All files / commands convert-file-format.ts

92.85% Statements 52/56
88.88% Branches 16/18
83.33% Functions 10/12
92.72% Lines 51/55

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                1x     6x       1x     1x       1x             1x     1x       1x               8x   8x 1x 1x     7x 7x   7x 1x 1x     6x 6x 6x   6x 1x 1x     5x       3x 2x     3x 3x 3x   3x 3x 3x 2x   2x   1x         3x 3x 3x           3x 6x 6x           3x         3x       2x 2x   2x 1x 1x     1x                   3x               3x      
import * as vscode from 'vscode';
import { VocabularyRepository } from '@faubulous/mentor-rdf';
import { container } from 'tsyringe';
import { ServiceToken } from '@src/services/tokens';
import { IDocumentContextService } from '@src/services/document';
import { IDocumentFactory, ILanguageInfo } from '@src/services/document/document-factory.interface';
import { WorkspaceUri } from '@src/providers/workspace-uri';
 
export const convertFileFormat = {
	id: 'mentor.command.convertFileFormat',
	handler: async () => {
		await convertFileFormatHandler();
	}
};
 
export const convertFileFormatToNTriplesSubmenu = {
	id: 'mentor.command.convertFileFormatToNTriplesSubmenu',
	handler: async () => {
		await convertFileFormatHandler('ntriples');
	}
};
 
export const convertFileFormatToNQuadsSubmenu = {
	id: 'mentor.command.convertFileFormatToNQuadsSubmenu',
	handler: async () => {
		await convertFileFormatHandler('nquads');
	}
};
 
export const convertFileFormatToTurtleSubmenu = {
	id: 'mentor.command.convertFileFormatToTurtleSubmenu',
	handler: async () => {
		await convertFileFormatHandler('turtle');
	}
};
 
export const convertFileFormatToXmlSubmenu = {
	id: 'mentor.command.convertFileFormatToXmlSubmenu',
	handler: async () => {
		await convertFileFormatHandler('xml');
	}
};
 
async function convertFileFormatHandler(targetLanguageId?: string) {
	const document = vscode.window.activeTextEditor?.document;
 
	if (!document) {
		vscode.window.showErrorMessage('No document selected.');
		return;
	}
 
	const diagnostics = vscode.languages.getDiagnostics(document.uri);
	const hasErrors = diagnostics.some((d) => d.severity === vscode.DiagnosticSeverity.Error);
 
	if (hasErrors) {
		await vscode.window.showErrorMessage('This document has syntax errors and cannot be converted.');
		return;
	}
 
	const documentIri = document.uri.toString();
	const contextService = container.resolve<IDocumentContextService>(ServiceToken.DocumentContextService);
	const context = contextService.contexts[documentIri];
 
	if (!context) {
		vscode.window.showErrorMessage('The document graph could not be retrieved.');
		return;
	}
 
	const selectedLanguage = targetLanguageId
		? await selectConfiguredTargetLanguage(document.languageId, targetLanguageId)
		: await selectTargetLanguage(document.languageId);
 
	if (!selectedLanguage) {
		return;
	}
 
	const sourceGraphIri = WorkspaceUri.toCanonicalString(context.graphIri);
	const targetGraphIri = await selectTargetGraphIri(sourceGraphIri, selectedLanguage.id);
	const targetLanguage = selectedLanguage.mimetypes[0];
 
	try {
		const vocabulary = container.resolve<VocabularyRepository>(ServiceToken.VocabularyRepository);
		const data = await vocabulary.store.serializeGraph(sourceGraphIri, targetLanguage, targetGraphIri, context.namespaces);
		const result = await vscode.workspace.openTextDocument({ content: data, language: selectedLanguage.id });
 
		vscode.window.showTextDocument(result);
	} catch (error) {
		vscode.window.showErrorMessage(`Error converting file format: ${error}`);
	}
}
 
async function selectTargetLanguage(sourceLanguageId: string) {
	const documentFactory = container.resolve<IDocumentFactory>(ServiceToken.DocumentFactory);
	const languages = await documentFactory.getSupportedLanguagesInfo();
	const targetLanguageIds = new Set(documentFactory.getConvertibleTargetLanguageIds(sourceLanguageId));
 
	type LanguagePickItem = vscode.QuickPickItem & {
		language: ILanguageInfo;
	};
 
	const items: LanguagePickItem[] = languages
		.filter(lang => targetLanguageIds.has(lang.id))
		.map((lang) => ({
			label: lang.name,
			description: (lang.extensions ?? []).join(", "),
			language: lang,
		}));
 
	const selected = await vscode.window.showQuickPick(items, {
		placeHolder: 'Select the target format:',
		matchOnDescription: true
	});
 
	return selected?.language;
}
 
async function selectConfiguredTargetLanguage(sourceLanguageId: string, targetLanguageId: string) {
	const documentFactory = container.resolve<IDocumentFactory>(ServiceToken.DocumentFactory);
	const targetLanguageIds = new Set(documentFactory.getConvertibleTargetLanguageIds(sourceLanguageId));
 
	if (!targetLanguageIds.has(targetLanguageId)) {
		vscode.window.showErrorMessage('The selected target format is not supported for this document.');
		return undefined;
	}
 
	return documentFactory.getLanguageInfo(targetLanguageId);
}
 
/**
 * Select the target graph IRI for the conversion if supported by the target language.
 * @param graphUri The source graph URI.
 * @param targetLanguageId The target language ID.
 * @returns The selected target graph IRI.
 */
async function selectTargetGraphIri(graphUri: string, targetLanguageId: string): Promise<string | undefined> {
	Iif (targetLanguageId === 'nquads' || targetLanguageId === 'trig') {
		const result = await vscode.window.showInputBox({
			prompt: 'Enter the target graph URI',
			value: graphUri
		});
 
		return result;
	} else {
		return undefined;
	}
}