Skip to content

Commit 93d2abc

Browse files
committed
Add injectionSelector diagnostics
1 parent dd5f6ec commit 93d2abc

File tree

3 files changed

+86
-32
lines changed

3 files changed

+86
-32
lines changed

src/DiagnosticCollection.ts

Lines changed: 77 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ async function Diagnostics(document: vscode.TextDocument) {
203203
const diagnostics: vscode.Diagnostic[] = [];
204204

205205
await Promise.allSettled([
206-
tryCatch(diagnosticsMismatchingRootScopeName(diagnostics, rootNode, document), "Diagnostics error:", "MismatchingPackageJSONInfo"),
206+
tryCatch(diagnosticsMismatchingPackageJSONInfo(diagnostics, rootNode, document), "Diagnostics error:", "MismatchingPackageJSONInfo"),
207207
tryCatch(diagnosticsTreeSitterJSONErrors(diagnostics, rootNode), "Diagnostics error:", "TreeSitterJSONErrors"),
208208
tryCatch(diagnosticsTreeSitterRegexErrors(diagnostics, trees), "Diagnostics error:", "TreeSitterRegexErrors"),
209209
tryCatch(diagnosticsRegularExpressionErrors(diagnostics, trees), "Diagnostics error:", "OnigurumaRegexErrors"),
@@ -947,49 +947,99 @@ async function diagnosticsDeadTextMateCode(diagnostics: vscode.Diagnostic[], roo
947947
// vscode.window.showInformationMessage(`dead ${(performance.now() - start).toFixed(3)}ms\n${JSON.stringify(diagnostics, stringify)}`);
948948
}
949949

950-
async function diagnosticsMismatchingRootScopeName(diagnostics: vscode.Diagnostic[], rootNode: webTreeSitter.Node, document: vscode.TextDocument) {
951-
// vscode.window.showInformationMessage(JSON.stringify("diagnostics scopeName"));
950+
async function diagnosticsMismatchingPackageJSONInfo(diagnostics: vscode.Diagnostic[], rootNode: webTreeSitter.Node, document: vscode.TextDocument) {
952951
// const start = performance.now();
953952

954-
const scopeNameQuery = `;scm
955-
(scopeName (value) @scopeName)
956-
`;
957-
const scopeNameCapture = queryNode(rootNode, scopeNameQuery).pop();
958-
if (!scopeNameCapture) {
959-
return;
960-
}
961-
962953
const { packageJSON, packageUri } = await getPackageJSON(document);
963954
if (!packageJSON) {
964955
return;
965956
}
966-
const grammars = packageJSON?.contributes?.grammars;
957+
const grammars = packageJSON.contributes?.grammars;
967958
if (!Array.isArray(grammars)) {
968959
return;
969960
}
970961

971-
const node = scopeNameCapture.node;
972-
const scopeName = node.text;
962+
const query = `;scm
963+
(json (scopeName (value) @scopeName))
964+
(json (injectionSelector) @injectionSelector)
965+
`;
966+
const queryCaptures = queryNode(rootNode, query);
973967

968+
let injectToPresent = false;
969+
let injectionSelectorPresent = false;
974970
for (const grammar of grammars) {
975-
const uri = vscode.Uri.joinPath(packageUri, '..', grammar.path);
971+
const path = grammar.path;
972+
if (!path) {
973+
continue;
974+
}
975+
const uri = vscode.Uri.joinPath(packageUri, '..', path);
976976
if (document.uri.path == uri.path) {
977-
if (grammar.scopeName == scopeName) {
978-
continue;
977+
for (const queryCapture of queryCaptures) {
978+
switch (queryCapture.name) {
979+
case 'injectionSelector':
980+
injectionSelectorPresent = true;
981+
break;
982+
case 'scopeName':
983+
const scopeName = queryCapture.node.text;
984+
if (grammar.scopeName == scopeName) {
985+
break;
986+
}
987+
988+
const range = toRange(queryCapture);
989+
const diagnostic: vscode.Diagnostic = {
990+
range: range,
991+
message: `scopeName '${scopeName}' does not match scopeName '${grammar.scopeName}' inside '${packageUri.path}'`,
992+
severity: vscode.DiagnosticSeverity.Error,
993+
source: 'TextMate',
994+
code: 'scopeName',
995+
};
996+
diagnostics.push(diagnostic);
997+
break;
998+
}
979999
}
9801000

981-
const range = toRange(node);
982-
const diagnostic: vscode.Diagnostic = {
983-
range: range,
984-
message: `scopeName '${scopeName}' does not match scopeName '${grammar.scopeName}' inside '${packageUri.path}'`,
985-
severity: vscode.DiagnosticSeverity.Error,
986-
source: 'TextMate',
987-
code: 'scopeName',
988-
};
989-
diagnostics.push(diagnostic);
1001+
if (grammar.injectTo?.length) {
1002+
injectToPresent = true;
1003+
if (!injectionSelectorPresent) {
1004+
const rootObjectQuery = `;scm
1005+
(json . "{" @rootObject)
1006+
`;
1007+
const rootObjectCaptures = queryNode(rootNode, rootObjectQuery);
1008+
for (const rootObjectCapture of rootObjectCaptures) {
1009+
const range = toRange(rootObjectCapture);
1010+
const diagnostic: vscode.Diagnostic = {
1011+
range: range,
1012+
message: `Missing property "injectionSelector".`,
1013+
severity: vscode.DiagnosticSeverity.Warning,
1014+
source: 'TextMate',
1015+
code: 'injectionSelector',
1016+
};
1017+
diagnostics.push(diagnostic);
1018+
}
1019+
}
1020+
}
1021+
}
1022+
}
1023+
1024+
if (injectionSelectorPresent && !injectToPresent) {
1025+
for (const queryCapture of queryCaptures) {
1026+
switch (queryCapture.name) {
1027+
case 'injectionSelector':
1028+
const range = toRange(queryCapture);
1029+
const diagnostic: vscode.Diagnostic = {
1030+
range: range,
1031+
message: '"injectionSelector" requires "injectTo" to be present under "grammars" inside `package.json`.',
1032+
severity: vscode.DiagnosticSeverity.Hint,
1033+
source: 'TextMate',
1034+
code: 'dead',
1035+
tags: [vscode.DiagnosticTag.Unnecessary],
1036+
};
1037+
diagnostics.push(diagnostic);
1038+
break;
1039+
}
9901040
}
9911041
}
992-
// vscode.window.showInformationMessage(`scopeName ${(performance.now() - start).toFixed(3)}ms`);
1042+
// vscode.window.showInformationMessage(`packageJSON ${(performance.now() - start).toFixed(3)}ms`);
9931043
}
9941044

9951045
async function diagnosticsLinguistCaptures(diagnostics: vscode.Diagnostic[], rootNode: webTreeSitter.Node) {

src/TreeSitter.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,15 @@ export function queryNode(node: webTreeSitter.Node, queryString: string, startPo
162162
}
163163

164164
export function toRange(node: webTreeSitter.Node): vscode.Range;
165-
export function toRange(points: webTreeSitter.Point): vscode.Range;
165+
export function toRange(node: webTreeSitter.QueryCapture): vscode.Range;
166+
export function toRange(point: webTreeSitter.Point): vscode.Range;
166167
export function toRange(start: webTreeSitter.Point, end: webTreeSitter.Point): vscode.Range;
167-
export function toRange(nodePoint: webTreeSitter.Node | webTreeSitter.Point, end?: webTreeSitter.Point): vscode.Range {
168+
export function toRange(nodePoint: webTreeSitter.Node | webTreeSitter.QueryCapture | webTreeSitter.Point, endPoint?: webTreeSitter.Point): vscode.Range {
169+
if ('node' in nodePoint) {
170+
nodePoint = nodePoint.node;
171+
}
168172
const startPosition = (<webTreeSitter.Node>nodePoint)?.startPosition || nodePoint;
169-
const endPosition = (<webTreeSitter.Node>nodePoint)?.endPosition || end || startPosition;
173+
const endPosition = (<webTreeSitter.Node>nodePoint)?.endPosition || endPoint || startPosition;
170174
const range = new vscode.Range(
171175
startPosition.row,
172176
startPosition.column,

src/extensions.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ export interface IExtensionContributions {
314314
configuration?: IConfiguration | IConfiguration[];
315315
configurationDefaults?: IConfigurationDefaults;
316316
debuggers?: IDebugger[];
317-
grammars?: IGrammar[];
317+
grammars?: Partial<IGrammar>[];
318318
jsonValidation?: IJSONValidation[];
319319
keybindings?: IKeyBinding[];
320320
languages?: ILanguage[];
@@ -381,7 +381,7 @@ export interface IRelaxedExtensionManifest {
381381
extensionDependencies?: string[];
382382
extensionPack?: string[];
383383
extensionKind?: vscode.ExtensionKind | vscode.ExtensionKind[];
384-
contributes?: IExtensionContributions;
384+
contributes?: Partial<IExtensionContributions>;
385385
repository?: { url: string; };
386386
bugs?: { url: string; };
387387
enabledApiProposals?: readonly string[];

0 commit comments

Comments
 (0)