@css-modules-kit/ts-plugin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +95 -0
- package/dist/applicable-refactor.d.ts +3 -0
- package/dist/applicable-refactor.d.ts.map +1 -0
- package/dist/applicable-refactor.js +9 -0
- package/dist/applicable-refactor.js.map +1 -0
- package/dist/ast.d.ts +6 -0
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +27 -0
- package/dist/ast.js.map +1 -0
- package/dist/file-text-change.d.ts +4 -0
- package/dist/file-text-change.d.ts.map +1 -0
- package/dist/file-text-change.js +29 -0
- package/dist/file-text-change.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/language-plugin.d.ts +19 -0
- package/dist/language-plugin.d.ts.map +1 -0
- package/dist/language-plugin.js +72 -0
- package/dist/language-plugin.js.map +1 -0
- package/dist/language-service/feature/code-fix.d.ts +5 -0
- package/dist/language-service/feature/code-fix.d.ts.map +1 -0
- package/dist/language-service/feature/code-fix.js +83 -0
- package/dist/language-service/feature/code-fix.js.map +1 -0
- package/dist/language-service/feature/completion.d.ts +3 -0
- package/dist/language-service/feature/completion.d.ts.map +1 -0
- package/dist/language-service/feature/completion.js +46 -0
- package/dist/language-service/feature/completion.js.map +1 -0
- package/dist/language-service/feature/refactor.d.ts +12 -0
- package/dist/language-service/feature/refactor.d.ts.map +1 -0
- package/dist/language-service/feature/refactor.js +43 -0
- package/dist/language-service/feature/refactor.js.map +1 -0
- package/dist/language-service/feature/semantic-diagnostic.d.ts +5 -0
- package/dist/language-service/feature/semantic-diagnostic.d.ts.map +1 -0
- package/dist/language-service/feature/semantic-diagnostic.js +43 -0
- package/dist/language-service/feature/semantic-diagnostic.js.map +1 -0
- package/dist/language-service/feature/syntactic-diagnostic.d.ts +4 -0
- package/dist/language-service/feature/syntactic-diagnostic.d.ts.map +1 -0
- package/dist/language-service/feature/syntactic-diagnostic.js +38 -0
- package/dist/language-service/feature/syntactic-diagnostic.js.map +1 -0
- package/dist/language-service/proxy.d.ts +5 -0
- package/dist/language-service/proxy.d.ts.map +1 -0
- package/dist/language-service/proxy.js +35 -0
- package/dist/language-service/proxy.js.map +1 -0
- package/dist/language-service.d.ts +4 -0
- package/dist/language-service.d.ts.map +1 -0
- package/dist/language-service.js +125 -0
- package/dist/language-service.js.map +1 -0
- package/dist/util.d.ts +5 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/util.js +25 -0
- package/dist/util.js.map +1 -0
- package/package.json +47 -0
- package/src/index.ts +53 -0
- package/src/language-plugin.ts +88 -0
- package/src/language-service/feature/code-fix.ts +109 -0
- package/src/language-service/feature/completion.ts +48 -0
- package/src/language-service/feature/refactor.ts +52 -0
- package/src/language-service/feature/semantic-diagnostic.ts +49 -0
- package/src/language-service/feature/syntactic-diagnostic.ts +39 -0
- package/src/language-service/proxy.ts +51 -0
- package/src/util.ts +19 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-diagnostic.d.ts","sourceRoot":"","sources":["../../../src/language-service/feature/semantic-diagnostic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAsB,MAAM,uBAAuB,CAAC;AAEpH,OAAO,EAAE,MAAM,YAAY,CAAC;AAK5B,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,aAAa,EAAE,aAAa,EAC5B,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,cAAc,EAC9B,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,SAAS,GACpD,EAAE,CAAC,eAAe,CAAC,wBAAwB,CAAC,CAc9C"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getSemanticDiagnostics = getSemanticDiagnostics;
|
|
7
|
+
const core_1 = require("@css-modules-kit/core");
|
|
8
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
9
|
+
const language_plugin_js_1 = require("../../language-plugin.js");
|
|
10
|
+
const util_js_1 = require("../../util.js");
|
|
11
|
+
// eslint-disable-next-line max-params
|
|
12
|
+
function getSemanticDiagnostics(language, languageService, exportBuilder, resolver, matchesPattern, getCSSModule) {
|
|
13
|
+
return (fileName) => {
|
|
14
|
+
const prior = languageService.getSemanticDiagnostics(fileName);
|
|
15
|
+
const script = language.scripts.get(fileName);
|
|
16
|
+
if ((0, language_plugin_js_1.isCSSModuleScript)(script)) {
|
|
17
|
+
const virtualCode = script.generated.root;
|
|
18
|
+
const cssModule = virtualCode[language_plugin_js_1.CMK_DATA_KEY].cssModule;
|
|
19
|
+
const diagnostics = (0, core_1.checkCSSModule)(cssModule, exportBuilder, matchesPattern, resolver, getCSSModule);
|
|
20
|
+
const sourceFile = languageService.getProgram().getSourceFile(fileName);
|
|
21
|
+
const tsDiagnostics = diagnostics.map((diagnostic) => convertDiagnostic(diagnostic, sourceFile));
|
|
22
|
+
prior.push(...tsDiagnostics);
|
|
23
|
+
}
|
|
24
|
+
return prior;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function convertDiagnostic(diagnostic, sourceFile) {
|
|
28
|
+
const start = diagnostic.start ?
|
|
29
|
+
typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.start.line - 1, diagnostic.start.column - 1)
|
|
30
|
+
: undefined;
|
|
31
|
+
const length = start !== undefined && diagnostic.end ?
|
|
32
|
+
typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.end.line - 1, diagnostic.end.column - 1) - start
|
|
33
|
+
: undefined;
|
|
34
|
+
return {
|
|
35
|
+
file: sourceFile,
|
|
36
|
+
start,
|
|
37
|
+
category: (0, util_js_1.convertErrorCategory)(diagnostic.category),
|
|
38
|
+
length,
|
|
39
|
+
messageText: diagnostic.text,
|
|
40
|
+
code: util_js_1.TS_ERROR_CODE_FOR_CMK_ERROR,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=semantic-diagnostic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-diagnostic.js","sourceRoot":"","sources":["../../../src/language-service/feature/semantic-diagnostic.ts"],"names":[],"mappings":";;;;;AAQA,wDAqBC;AA3BD,gDAAuD;AACvD,4DAA4B;AAC5B,iEAA2E;AAC3E,2CAAkF;AAElF,sCAAsC;AACtC,SAAgB,sBAAsB,CACpC,QAA0B,EAC1B,eAAmC,EACnC,aAA4B,EAC5B,QAAkB,EAClB,cAA8B,EAC9B,YAAqD;IAErD,OAAO,CAAC,QAAgB,EAAE,EAAE;QAC1B,MAAM,KAAK,GAAG,eAAe,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,IAAA,sCAAiB,EAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1C,MAAM,SAAS,GAAG,WAAW,CAAC,iCAAY,CAAC,CAAC,SAAS,CAAC;YACtD,MAAM,WAAW,GAAG,IAAA,qBAAc,EAAC,SAAS,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;YACrG,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,EAAG,CAAC,aAAa,CAAC,QAAQ,CAAE,CAAC;YAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;YACjG,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,UAA8B,EAAE,UAAyB;IAClF,MAAM,KAAK,GACT,UAAU,CAAC,KAAK,CAAC,CAAC;QAChB,oBAAE,CAAC,6BAA6B,CAAC,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtG,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,MAAM,GACV,KAAK,KAAK,SAAS,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;QACrC,oBAAE,CAAC,6BAA6B,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK;QAC1G,CAAC,CAAC,SAAS,CAAC;IACd,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK;QACL,QAAQ,EAAE,IAAA,8BAAoB,EAAC,UAAU,CAAC,QAAQ,CAAC;QACnD,MAAM;QACN,WAAW,EAAE,UAAU,CAAC,IAAI;QAC5B,IAAI,EAAE,qCAA2B;KAClC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Language } from '@volar/language-core';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
export declare function getSyntacticDiagnostics(language: Language<string>, languageService: ts.LanguageService): ts.LanguageService['getSyntacticDiagnostics'];
|
|
4
|
+
//# sourceMappingURL=syntactic-diagnostic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syntactic-diagnostic.d.ts","sourceRoot":"","sources":["../../../src/language-service/feature/syntactic-diagnostic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,MAAM,YAAY,CAAC;AAI5B,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,eAAe,EAAE,EAAE,CAAC,eAAe,GAClC,EAAE,CAAC,eAAe,CAAC,yBAAyB,CAAC,CAa/C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getSyntacticDiagnostics = getSyntacticDiagnostics;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const language_plugin_js_1 = require("../../language-plugin.js");
|
|
9
|
+
const util_js_1 = require("../../util.js");
|
|
10
|
+
function getSyntacticDiagnostics(language, languageService) {
|
|
11
|
+
return (fileName) => {
|
|
12
|
+
const prior = languageService.getSyntacticDiagnostics(fileName);
|
|
13
|
+
const script = language.scripts.get(fileName);
|
|
14
|
+
if ((0, language_plugin_js_1.isCSSModuleScript)(script)) {
|
|
15
|
+
const virtualCode = script.generated.root;
|
|
16
|
+
const diagnostics = virtualCode[language_plugin_js_1.CMK_DATA_KEY].diagnostics;
|
|
17
|
+
const sourceFile = languageService.getProgram().getSourceFile(fileName);
|
|
18
|
+
const tsDiagnostics = diagnostics.map((diagnostic) => convertDiagnostic(diagnostic, sourceFile));
|
|
19
|
+
prior.push(...tsDiagnostics);
|
|
20
|
+
}
|
|
21
|
+
return prior;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function convertDiagnostic(diagnostic, sourceFile) {
|
|
25
|
+
const start = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.start.line - 1, diagnostic.start.column - 1);
|
|
26
|
+
const length = diagnostic.end ?
|
|
27
|
+
typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.end.line - 1, diagnostic.end.column - 1) - start
|
|
28
|
+
: 1;
|
|
29
|
+
return {
|
|
30
|
+
file: sourceFile,
|
|
31
|
+
start,
|
|
32
|
+
category: (0, util_js_1.convertErrorCategory)(diagnostic.category),
|
|
33
|
+
length,
|
|
34
|
+
messageText: diagnostic.text,
|
|
35
|
+
code: util_js_1.TS_ERROR_CODE_FOR_CMK_ERROR,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=syntactic-diagnostic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"syntactic-diagnostic.js","sourceRoot":"","sources":["../../../src/language-service/feature/syntactic-diagnostic.ts"],"names":[],"mappings":";;;;;AAMA,0DAgBC;AApBD,4DAA4B;AAC5B,iEAA2E;AAC3E,2CAAkF;AAElF,SAAgB,uBAAuB,CACrC,QAA0B,EAC1B,eAAmC;IAEnC,OAAO,CAAC,QAAgB,EAAE,EAAE;QAC1B,MAAM,KAAK,GAAG,eAAe,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,IAAA,sCAAiB,EAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1C,MAAM,WAAW,GAAG,WAAW,CAAC,iCAAY,CAAC,CAAC,WAAW,CAAC;YAC1D,MAAM,UAAU,GAAG,eAAe,CAAC,UAAU,EAAG,CAAC,aAAa,CAAC,QAAQ,CAAE,CAAC;YAC1E,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC;YACjG,KAAK,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;QAC/B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,UAA+B,EAAE,UAAyB;IACnF,MAAM,KAAK,GAAG,oBAAE,CAAC,6BAA6B,CAAC,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACnH,MAAM,MAAM,GACV,UAAU,CAAC,GAAG,CAAC,CAAC;QACd,oBAAE,CAAC,6BAA6B,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK;QAC1G,CAAC,CAAC,CAAC,CAAC;IACN,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK;QACL,QAAQ,EAAE,IAAA,8BAAoB,EAAC,UAAU,CAAC,QAAQ,CAAC;QACnD,MAAM;QACN,WAAW,EAAE,UAAU,CAAC,IAAI;QAC5B,IAAI,EAAE,qCAA2B;KAClC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Language } from '@volar/language-core';
|
|
2
|
+
import { type MatchesPattern, type Resolver } from '@css-modules-kit/core';
|
|
3
|
+
import type ts from 'typescript';
|
|
4
|
+
export declare function proxyLanguageService(language: Language<string>, languageService: ts.LanguageService, project: ts.server.Project, resolver: Resolver, matchesPattern: MatchesPattern): ts.LanguageService;
|
|
5
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/language-service/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAuB,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAChG,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAQjC,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAC1B,QAAQ,EAAE,QAAQ,EAClB,cAAc,EAAE,cAAc,GAC7B,EAAE,CAAC,eAAe,CAkCpB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.proxyLanguageService = proxyLanguageService;
|
|
4
|
+
const core_1 = require("@css-modules-kit/core");
|
|
5
|
+
const language_plugin_js_1 = require("../language-plugin.js");
|
|
6
|
+
const code_fix_js_1 = require("./feature/code-fix.js");
|
|
7
|
+
const completion_js_1 = require("./feature/completion.js");
|
|
8
|
+
const refactor_js_1 = require("./feature/refactor.js");
|
|
9
|
+
const semantic_diagnostic_js_1 = require("./feature/semantic-diagnostic.js");
|
|
10
|
+
const syntactic_diagnostic_js_1 = require("./feature/syntactic-diagnostic.js");
|
|
11
|
+
function proxyLanguageService(language, languageService, project, resolver, matchesPattern) {
|
|
12
|
+
const proxy = Object.create(null);
|
|
13
|
+
for (const k of Object.keys(languageService)) {
|
|
14
|
+
const x = languageService[k];
|
|
15
|
+
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
17
|
+
proxy[k] = (...args) => x.apply(languageService, args);
|
|
18
|
+
}
|
|
19
|
+
const getCSSModule = (path) => {
|
|
20
|
+
const script = language.scripts.get(path);
|
|
21
|
+
if ((0, language_plugin_js_1.isCSSModuleScript)(script)) {
|
|
22
|
+
return script.generated.root[language_plugin_js_1.CMK_DATA_KEY].cssModule;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
};
|
|
26
|
+
const exportBuilder = (0, core_1.createExportBuilder)({ getCSSModule, resolver, matchesPattern });
|
|
27
|
+
proxy.getSyntacticDiagnostics = (0, syntactic_diagnostic_js_1.getSyntacticDiagnostics)(language, languageService);
|
|
28
|
+
proxy.getSemanticDiagnostics = (0, semantic_diagnostic_js_1.getSemanticDiagnostics)(language, languageService, exportBuilder, resolver, matchesPattern, getCSSModule);
|
|
29
|
+
proxy.getApplicableRefactors = (0, refactor_js_1.getApplicableRefactors)(languageService, project);
|
|
30
|
+
proxy.getEditsForRefactor = (0, refactor_js_1.getEditsForRefactor)(languageService);
|
|
31
|
+
proxy.getCompletionsAtPosition = (0, completion_js_1.getCompletionsAtPosition)(languageService);
|
|
32
|
+
proxy.getCodeFixesAtPosition = (0, code_fix_js_1.getCodeFixesAtPosition)(language, languageService, project);
|
|
33
|
+
return proxy;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/language-service/proxy.ts"],"names":[],"mappings":";;AAUA,oDAwCC;AAjDD,gDAAgG;AAEhG,8DAAwE;AACxE,uDAA+D;AAC/D,2DAAmE;AACnE,uDAAoF;AACpF,6EAA0E;AAC1E,+EAA4E;AAE5E,SAAgB,oBAAoB,CAClC,QAA0B,EAC1B,eAAmC,EACnC,OAA0B,EAC1B,QAAkB,EAClB,cAA8B;IAE9B,MAAM,KAAK,GAAuB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEtD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,eAAe,CAAiC,EAAE,CAAC;QAC7E,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAE,CAAC;QAC9B,yEAAyE;QACzE,mEAAmE;QACnE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,IAAU,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE;QACpC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,IAAA,sCAAiB,EAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,iCAAY,CAAC,CAAC,SAAS,CAAC;QACvD,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,aAAa,GAAG,IAAA,0BAAmB,EAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;IAEtF,KAAK,CAAC,uBAAuB,GAAG,IAAA,iDAAuB,EAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IACnF,KAAK,CAAC,sBAAsB,GAAG,IAAA,+CAAsB,EACnD,QAAQ,EACR,eAAe,EACf,aAAa,EACb,QAAQ,EACR,cAAc,EACd,YAAY,CACb,CAAC;IACF,KAAK,CAAC,sBAAsB,GAAG,IAAA,oCAAsB,EAAC,eAAe,EAAE,OAAO,CAAC,CAAC;IAChF,KAAK,CAAC,mBAAmB,GAAG,IAAA,iCAAmB,EAAC,eAAe,CAAC,CAAC;IACjE,KAAK,CAAC,wBAAwB,GAAG,IAAA,wCAAwB,EAAC,eAAe,CAAC,CAAC;IAC3E,KAAK,CAAC,sBAAsB,GAAG,IAAA,oCAAsB,EAAC,QAAQ,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;IAE1F,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Language } from '@volar/language-core';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
export declare function proxyLanguageService(language: Language<string>, languageService: ts.LanguageService, project: ts.server.Project): ts.LanguageService;
|
|
4
|
+
//# sourceMappingURL=language-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-service.d.ts","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAAE,MAAM,YAAY,CAAC;AAY5B,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC1B,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,GACzB,EAAE,CAAC,eAAe,CAmGpB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.proxyLanguageService = proxyLanguageService;
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
8
|
+
const applicable_refactor_js_1 = require("./applicable-refactor.js");
|
|
9
|
+
const ast_js_1 = require("./ast.js");
|
|
10
|
+
const file_text_change_js_1 = require("./file-text-change.js");
|
|
11
|
+
const language_plugin_js_1 = require("./language-plugin.js");
|
|
12
|
+
const util_js_1 = require("./util.js");
|
|
13
|
+
const ERROR_CODE = 0;
|
|
14
|
+
const STYLES_IMPORT_NAME = 'styles';
|
|
15
|
+
// ref: https://github.com/microsoft/TypeScript/blob/220706eb0320ff46fad8bf80a5e99db624ee7dfb/src/compiler/diagnosticMessages.json#L2051-L2054
|
|
16
|
+
const PROPERTY_DOES_NOT_EXIST_ERROR_CODE = 2339;
|
|
17
|
+
function proxyLanguageService(language, languageService, project) {
|
|
18
|
+
const proxy = Object.create(null);
|
|
19
|
+
for (const k of Object.keys(languageService)) {
|
|
20
|
+
const x = languageService[k];
|
|
21
|
+
// @ts-expect-error - JS runtime trickery which is tricky to type tersely
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
23
|
+
proxy[k] = (...args) => x.apply(languageService, args);
|
|
24
|
+
}
|
|
25
|
+
proxy.getSyntacticDiagnostics = (fileName) => {
|
|
26
|
+
const prior = languageService.getSyntacticDiagnostics(fileName);
|
|
27
|
+
const script = language.scripts.get(fileName);
|
|
28
|
+
if (!(0, language_plugin_js_1.isCSSModuleScript)(script))
|
|
29
|
+
return prior;
|
|
30
|
+
const virtualCode = script.generated.root;
|
|
31
|
+
const diagnostics = virtualCode[language_plugin_js_1.HCM_DATA_KEY].diagnostics;
|
|
32
|
+
const sourceFile = languageService.getProgram().getSourceFile(fileName);
|
|
33
|
+
const tsDiagnostics = diagnostics.map((diagnostic) => convertDiagnostic(diagnostic, sourceFile));
|
|
34
|
+
return [...prior, ...tsDiagnostics];
|
|
35
|
+
};
|
|
36
|
+
proxy.getApplicableRefactors = (fileName, positionOrRange, preferences) => {
|
|
37
|
+
const prior = languageService.getApplicableRefactors(fileName, positionOrRange, preferences) ?? [];
|
|
38
|
+
const sourceFile = project.getSourceFile(project.projectService.toPath(fileName));
|
|
39
|
+
if (!sourceFile)
|
|
40
|
+
return prior;
|
|
41
|
+
const result = languageService.getMoveToRefactoringFileSuggestions(fileName, 0, preferences);
|
|
42
|
+
const cssFileName = (0, util_js_1.getCssFileName)(fileName);
|
|
43
|
+
if (!project.fileExists(cssFileName)) {
|
|
44
|
+
prior.push(applicable_refactor_js_1.createCssModuleFileRefactor);
|
|
45
|
+
}
|
|
46
|
+
return prior;
|
|
47
|
+
};
|
|
48
|
+
// eslint-disable-next-line max-params
|
|
49
|
+
proxy.getEditsForRefactor = (fileName, formatOptions, positionOrRange, refactorName, actionName, preferences) => {
|
|
50
|
+
const prior = languageService.getEditsForRefactor(fileName, formatOptions, positionOrRange, refactorName, actionName, preferences) ?? { edits: [] };
|
|
51
|
+
const sourceFile = project.getSourceFile(project.projectService.toPath(fileName));
|
|
52
|
+
if (!sourceFile)
|
|
53
|
+
return prior;
|
|
54
|
+
const cssFileName = (0, util_js_1.getCssFileName)(fileName);
|
|
55
|
+
if (refactorName === applicable_refactor_js_1.createCssModuleFileRefactor.name) {
|
|
56
|
+
prior.edits.push((0, file_text_change_js_1.createNewCssModuleFileTextChange)(cssFileName));
|
|
57
|
+
}
|
|
58
|
+
return prior;
|
|
59
|
+
};
|
|
60
|
+
proxy.getCompletionsAtPosition = (fileName, position, options, formattingSettings) => {
|
|
61
|
+
const prior = languageService.getCompletionsAtPosition(fileName, position, options, formattingSettings);
|
|
62
|
+
if (!(0, util_js_1.isTypeScriptFile)(fileName) || !prior?.entries)
|
|
63
|
+
return prior;
|
|
64
|
+
const cssFileName = (0, util_js_1.getCssFileName)(fileName);
|
|
65
|
+
for (const entry of prior.entries) {
|
|
66
|
+
if (entry.name === STYLES_IMPORT_NAME &&
|
|
67
|
+
entry.data &&
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
|
|
69
|
+
entry.data.exportName === typescript_1.default.InternalSymbolName.Default &&
|
|
70
|
+
entry.data.fileName === cssFileName) {
|
|
71
|
+
// NOTE: This is a hack to make the completion item appear at the top
|
|
72
|
+
entry.sortText = '0';
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return prior;
|
|
76
|
+
};
|
|
77
|
+
// eslint-disable-next-line max-params
|
|
78
|
+
proxy.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => {
|
|
79
|
+
const prior = languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences);
|
|
80
|
+
if (!(0, util_js_1.isTypeScriptFile)(fileName))
|
|
81
|
+
return prior;
|
|
82
|
+
const sourceFile = project.getSourceFile(project.projectService.toPath(fileName));
|
|
83
|
+
if (!sourceFile)
|
|
84
|
+
return prior;
|
|
85
|
+
const result = [...prior];
|
|
86
|
+
const stylesPropertyNode = (0, ast_js_1.getStylesPropertyAccessExpression)(sourceFile, start, STYLES_IMPORT_NAME);
|
|
87
|
+
if (stylesPropertyNode && errorCodes.includes(PROPERTY_DOES_NOT_EXIST_ERROR_CODE)) {
|
|
88
|
+
const className = stylesPropertyNode.name.getText();
|
|
89
|
+
result.push({
|
|
90
|
+
fixName: 'fixMissingProperties',
|
|
91
|
+
description: `Add missing CSS rule '.${className}'`,
|
|
92
|
+
changes: [(0, file_text_change_js_1.createInsertRuleFileTextChange)((0, util_js_1.getCssFileName)(fileName), className, project)],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
};
|
|
97
|
+
return proxy;
|
|
98
|
+
}
|
|
99
|
+
function convertDiagnostic(diagnostic, sourceFile) {
|
|
100
|
+
const start = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.start.line - 1, diagnostic.start.column - 1);
|
|
101
|
+
const length = diagnostic.end ?
|
|
102
|
+
typescript_1.default.getPositionOfLineAndCharacter(sourceFile, diagnostic.end.line - 1, diagnostic.end.column - 1) - start
|
|
103
|
+
: 1;
|
|
104
|
+
return {
|
|
105
|
+
file: sourceFile,
|
|
106
|
+
start,
|
|
107
|
+
category: convertErrorCategory(diagnostic.category),
|
|
108
|
+
length,
|
|
109
|
+
messageText: diagnostic.text,
|
|
110
|
+
code: ERROR_CODE,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function convertErrorCategory(category) {
|
|
114
|
+
switch (category) {
|
|
115
|
+
case 'error':
|
|
116
|
+
return typescript_1.default.DiagnosticCategory.Error;
|
|
117
|
+
case 'warning':
|
|
118
|
+
return typescript_1.default.DiagnosticCategory.Warning;
|
|
119
|
+
case 'suggestion':
|
|
120
|
+
return typescript_1.default.DiagnosticCategory.Suggestion;
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`Unknown category: ${String(category)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=language-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-service.js","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"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"}
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
/** The error code used by tsserver to display the css-modules-kit error in the editor. */
|
|
3
|
+
export declare const TS_ERROR_CODE_FOR_CMK_ERROR = 0;
|
|
4
|
+
export declare function convertErrorCategory(category: 'error' | 'warning' | 'suggestion'): ts.DiagnosticCategory;
|
|
5
|
+
//# sourceMappingURL=util.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,0FAA0F;AAG1F,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,YAAY,GAAG,EAAE,CAAC,kBAAkB,CAWxG"}
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TS_ERROR_CODE_FOR_CMK_ERROR = void 0;
|
|
7
|
+
exports.convertErrorCategory = convertErrorCategory;
|
|
8
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
9
|
+
/** The error code used by tsserver to display the css-modules-kit error in the editor. */
|
|
10
|
+
// NOTE: Use any other number than 1002 or later, as they are reserved by TypeScript's built-in errors.
|
|
11
|
+
// ref: https://github.com/microsoft/TypeScript/blob/220706eb0320ff46fad8bf80a5e99db624ee7dfb/src/compiler/diagnosticMessages.json
|
|
12
|
+
exports.TS_ERROR_CODE_FOR_CMK_ERROR = 0;
|
|
13
|
+
function convertErrorCategory(category) {
|
|
14
|
+
switch (category) {
|
|
15
|
+
case 'error':
|
|
16
|
+
return typescript_1.default.DiagnosticCategory.Error;
|
|
17
|
+
case 'warning':
|
|
18
|
+
return typescript_1.default.DiagnosticCategory.Warning;
|
|
19
|
+
case 'suggestion':
|
|
20
|
+
return typescript_1.default.DiagnosticCategory.Suggestion;
|
|
21
|
+
default:
|
|
22
|
+
throw new Error(`Unknown category: ${String(category)}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;;;;AAOA,oDAWC;AAlBD,4DAA4B;AAE5B,0FAA0F;AAC1F,uGAAuG;AACvG,kIAAkI;AACrH,QAAA,2BAA2B,GAAG,CAAC,CAAC;AAE7C,SAAgB,oBAAoB,CAAC,QAA4C;IAC/E,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,OAAO;YACV,OAAO,oBAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC;QACrC,KAAK,SAAS;YACZ,OAAO,oBAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC;QACvC,KAAK,YAAY;YACf,OAAO,oBAAE,CAAC,kBAAkB,CAAC,UAAU,CAAC;QAC1C;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@css-modules-kit/ts-plugin",
|
|
3
|
+
"description": "A TypeScript Language Service Plugin for CSS Modules",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"type": "commonjs",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/mizdra/css-modules-kit.git",
|
|
10
|
+
"directory": "packages/ts-plugin"
|
|
11
|
+
},
|
|
12
|
+
"author": "mizdra <pp.mizdra@gmail.com>",
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"private": false,
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -b tsconfig.build.json"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=22.0.0"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public",
|
|
24
|
+
"registry": "https://registry.npmjs.org/"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"css-modules",
|
|
28
|
+
"typescript",
|
|
29
|
+
"language service"
|
|
30
|
+
],
|
|
31
|
+
"files": [
|
|
32
|
+
"bin",
|
|
33
|
+
"src",
|
|
34
|
+
"!src/**/*.test.ts",
|
|
35
|
+
"!src/**/__snapshots__",
|
|
36
|
+
"!src/test",
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@volar/language-core": "^2.4.11",
|
|
41
|
+
"@volar/typescript": "^2.4.11",
|
|
42
|
+
"@css-modules-kit/core": "^0.0.1"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"typescript": ">=5.6.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { CMKConfig } from '@css-modules-kit/core';
|
|
2
|
+
import { createMatchesPattern, createResolver, readConfigFile } from '@css-modules-kit/core';
|
|
3
|
+
import { TsConfigFileNotFoundError } from '@css-modules-kit/core';
|
|
4
|
+
import { createLanguageServicePlugin } from '@volar/typescript/lib/quickstart/createLanguageServicePlugin.js';
|
|
5
|
+
import { createCSSModuleLanguagePlugin } from './language-plugin.js';
|
|
6
|
+
import { proxyLanguageService } from './language-service/proxy.js';
|
|
7
|
+
|
|
8
|
+
const plugin = createLanguageServicePlugin((ts, info) => {
|
|
9
|
+
if (info.project.projectKind !== ts.server.ProjectKind.Configured) {
|
|
10
|
+
info.project.projectService.logger.info(`[@css-modules-kit/ts-plugin] info: Project is not configured`);
|
|
11
|
+
return { languagePlugins: [] };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let config: CMKConfig;
|
|
15
|
+
try {
|
|
16
|
+
config = readConfigFile(info.project.getProjectName());
|
|
17
|
+
// TODO: Report diagnostics
|
|
18
|
+
info.project.projectService.logger.info(
|
|
19
|
+
`[@css-modules-kit/ts-plugin] info: Config file is found '${config.configFileName}'`,
|
|
20
|
+
);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
// If the config file is not found, disable the plugin.
|
|
23
|
+
if (error instanceof TsConfigFileNotFoundError) {
|
|
24
|
+
return { languagePlugins: [] };
|
|
25
|
+
} else {
|
|
26
|
+
let msg = `[@css-modules-kit/ts-plugin] error: Fail to read config file`;
|
|
27
|
+
if (error instanceof Error) {
|
|
28
|
+
msg += `\n: ${error.message}`;
|
|
29
|
+
msg += `\n${error.stack}`;
|
|
30
|
+
}
|
|
31
|
+
info.project.projectService.logger.info(msg);
|
|
32
|
+
return { languagePlugins: [] };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const resolver = createResolver(config.paths);
|
|
37
|
+
const matchesPattern = createMatchesPattern(config);
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
languagePlugins: [createCSSModuleLanguagePlugin(config, resolver, matchesPattern)],
|
|
41
|
+
setup: (language) => {
|
|
42
|
+
info.languageService = proxyLanguageService(
|
|
43
|
+
language,
|
|
44
|
+
info.languageService,
|
|
45
|
+
info.project,
|
|
46
|
+
resolver,
|
|
47
|
+
matchesPattern,
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export = plugin;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { CMKConfig, CSSModule, MatchesPattern, Resolver, SyntacticDiagnostic } from '@css-modules-kit/core';
|
|
2
|
+
import { createDts, parseCSSModule } from '@css-modules-kit/core';
|
|
3
|
+
import type { LanguagePlugin, SourceScript, VirtualCode } from '@volar/language-core';
|
|
4
|
+
import type {} from '@volar/typescript';
|
|
5
|
+
import ts from 'typescript';
|
|
6
|
+
|
|
7
|
+
export const LANGUAGE_ID = 'css-module';
|
|
8
|
+
|
|
9
|
+
export const CMK_DATA_KEY = Symbol('css-modules-kit-data');
|
|
10
|
+
|
|
11
|
+
interface CSSModuleVirtualCode extends VirtualCode {
|
|
12
|
+
[CMK_DATA_KEY]: {
|
|
13
|
+
cssModule: CSSModule;
|
|
14
|
+
diagnostics: SyntacticDiagnostic[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CSSModuleScript extends SourceScript<string> {
|
|
19
|
+
generated: SourceScript<string>['generated'] & {
|
|
20
|
+
root: CSSModuleVirtualCode;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createCSSModuleLanguagePlugin(
|
|
25
|
+
config: CMKConfig,
|
|
26
|
+
resolver: Resolver,
|
|
27
|
+
matchesPattern: MatchesPattern,
|
|
28
|
+
): LanguagePlugin<string, VirtualCode> {
|
|
29
|
+
return {
|
|
30
|
+
getLanguageId(scriptId) {
|
|
31
|
+
if (!matchesPattern(scriptId)) return undefined;
|
|
32
|
+
return LANGUAGE_ID;
|
|
33
|
+
},
|
|
34
|
+
createVirtualCode(scriptId, languageId, snapshot): CSSModuleVirtualCode | undefined {
|
|
35
|
+
if (languageId !== LANGUAGE_ID) return undefined;
|
|
36
|
+
|
|
37
|
+
const length = snapshot.getLength();
|
|
38
|
+
const cssModuleCode = snapshot.getText(0, length);
|
|
39
|
+
const { cssModule, diagnostics } = parseCSSModule(cssModuleCode, {
|
|
40
|
+
fileName: scriptId,
|
|
41
|
+
dashedIdents: config.dashedIdents,
|
|
42
|
+
// The CSS in the process of being written in an editor often contains invalid syntax.
|
|
43
|
+
// So, ts-plugin uses a fault-tolerant Parser to parse CSS.
|
|
44
|
+
safe: true,
|
|
45
|
+
});
|
|
46
|
+
const { text, mapping, linkedCodeMapping } = createDts(cssModule, { resolver, matchesPattern });
|
|
47
|
+
return {
|
|
48
|
+
id: 'main',
|
|
49
|
+
languageId: LANGUAGE_ID,
|
|
50
|
+
snapshot: {
|
|
51
|
+
getText: (start, end) => text.slice(start, end),
|
|
52
|
+
getLength: () => text.length,
|
|
53
|
+
getChangeRange: () => undefined,
|
|
54
|
+
},
|
|
55
|
+
// `mappings` are required to support "Go to Definition" and renaming
|
|
56
|
+
mappings: [{ ...mapping, data: { navigation: true } }],
|
|
57
|
+
// `linkedCodeMappings` are required to support "Go to Definition" and renaming for the imported tokens
|
|
58
|
+
linkedCodeMappings: [{ ...linkedCodeMapping, data: undefined }],
|
|
59
|
+
[CMK_DATA_KEY]: {
|
|
60
|
+
cssModule,
|
|
61
|
+
diagnostics,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
typescript: {
|
|
66
|
+
extraFileExtensions: [
|
|
67
|
+
{
|
|
68
|
+
extension: 'css',
|
|
69
|
+
isMixedContent: true,
|
|
70
|
+
scriptKind: ts.ScriptKind.TS,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
getServiceScript(root) {
|
|
74
|
+
return {
|
|
75
|
+
code: root,
|
|
76
|
+
extension: ts.Extension.Ts,
|
|
77
|
+
scriptKind: ts.ScriptKind.TS,
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function isCSSModuleScript(script: SourceScript<string> | undefined): script is CSSModuleScript {
|
|
85
|
+
return (
|
|
86
|
+
!!script && script.languageId === LANGUAGE_ID && !!script.generated?.root && CMK_DATA_KEY in script.generated.root
|
|
87
|
+
);
|
|
88
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { isComponentFileName } from '@css-modules-kit/core';
|
|
2
|
+
import type { Language } from '@volar/language-core';
|
|
3
|
+
import ts from 'typescript';
|
|
4
|
+
import { isCSSModuleScript } from '../../language-plugin.js';
|
|
5
|
+
|
|
6
|
+
// ref: https://github.com/microsoft/TypeScript/blob/220706eb0320ff46fad8bf80a5e99db624ee7dfb/src/compiler/diagnosticMessages.json#L2051-L2054
|
|
7
|
+
export const PROPERTY_DOES_NOT_EXIST_ERROR_CODE = 2339;
|
|
8
|
+
|
|
9
|
+
export function getCodeFixesAtPosition(
|
|
10
|
+
language: Language<string>,
|
|
11
|
+
languageService: ts.LanguageService,
|
|
12
|
+
project: ts.server.Project,
|
|
13
|
+
): ts.LanguageService['getCodeFixesAtPosition'] {
|
|
14
|
+
// eslint-disable-next-line max-params
|
|
15
|
+
return (fileName, start, end, errorCodes, formatOptions, preferences) => {
|
|
16
|
+
const prior = Array.from(
|
|
17
|
+
languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences) ?? [],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (isComponentFileName(fileName)) {
|
|
21
|
+
// If a user is trying to use a non-existent token (e.g. `styles.nonExistToken`), provide a code fix to add the token.
|
|
22
|
+
if (errorCodes.includes(PROPERTY_DOES_NOT_EXIST_ERROR_CODE)) {
|
|
23
|
+
const tokenConsumer = getTokenConsumerAtPosition(fileName, start, language, languageService, project);
|
|
24
|
+
if (tokenConsumer) {
|
|
25
|
+
prior.push({
|
|
26
|
+
fixName: 'fixMissingCSSRule',
|
|
27
|
+
description: `Add missing CSS rule '.${tokenConsumer.tokenName}'`,
|
|
28
|
+
changes: [createInsertRuleFileChange(tokenConsumer.from, tokenConsumer.tokenName, language)],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return prior;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface TokenConsumer {
|
|
39
|
+
/** The token name (e.g. `foo` in `styles.foo`) */
|
|
40
|
+
tokenName: string;
|
|
41
|
+
/** The file path of the CSS module that defines the token */
|
|
42
|
+
from: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the token consumer at the specified position.
|
|
47
|
+
* If the position is at `styles.foo`, it returns `{ tokenName: 'foo', from: '/path/to/a.module.css' }`.
|
|
48
|
+
*/
|
|
49
|
+
function getTokenConsumerAtPosition(
|
|
50
|
+
fileName: string,
|
|
51
|
+
position: number,
|
|
52
|
+
language: Language<string>,
|
|
53
|
+
languageService: ts.LanguageService,
|
|
54
|
+
project: ts.server.Project,
|
|
55
|
+
): TokenConsumer | undefined {
|
|
56
|
+
const sourceFile = project.getSourceFile(project.projectService.toPath(fileName));
|
|
57
|
+
if (!sourceFile) return undefined;
|
|
58
|
+
const propertyAccessExpression = getPropertyAccessExpressionAtPosition(sourceFile, position);
|
|
59
|
+
if (!propertyAccessExpression) return undefined;
|
|
60
|
+
|
|
61
|
+
// Check if the expression of property access expression (e.g. `styles` in `styles.foo`) is imported from a CSS module.
|
|
62
|
+
|
|
63
|
+
// `expression` is the expression of the property access expression (e.g. `styles` in `styles.foo`).
|
|
64
|
+
const expression = propertyAccessExpression.expression;
|
|
65
|
+
|
|
66
|
+
const definitions = languageService.getDefinitionAtPosition(fileName, expression.getStart());
|
|
67
|
+
if (definitions && definitions[0]) {
|
|
68
|
+
const script = language.scripts.get(definitions[0].fileName);
|
|
69
|
+
if (isCSSModuleScript(script)) {
|
|
70
|
+
return { tokenName: propertyAccessExpression.name.text, from: definitions[0].fileName };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Get the property access expression at the specified position. (e.g. `obj.foo`, `styles.foo`) */
|
|
77
|
+
function getPropertyAccessExpressionAtPosition(
|
|
78
|
+
sourceFile: ts.SourceFile,
|
|
79
|
+
position: number,
|
|
80
|
+
): ts.PropertyAccessExpression | undefined {
|
|
81
|
+
function getPropertyAccessExpressionImpl(node: ts.Node): ts.PropertyAccessExpression | undefined {
|
|
82
|
+
if (node.pos <= position && position <= node.end && ts.isPropertyAccessExpression(node)) {
|
|
83
|
+
return node;
|
|
84
|
+
}
|
|
85
|
+
return ts.forEachChild(node, getPropertyAccessExpressionImpl);
|
|
86
|
+
}
|
|
87
|
+
return getPropertyAccessExpressionImpl(sourceFile);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function createInsertRuleFileChange(
|
|
91
|
+
cssModuleFileName: string,
|
|
92
|
+
className: string,
|
|
93
|
+
language: Language<string>,
|
|
94
|
+
): ts.FileTextChanges {
|
|
95
|
+
const script = language.scripts.get(cssModuleFileName);
|
|
96
|
+
if (script) {
|
|
97
|
+
return {
|
|
98
|
+
fileName: cssModuleFileName,
|
|
99
|
+
textChanges: [{ span: { start: script.snapshot.getLength(), length: 0 }, newText: `\n.${className} {\n \n}` }],
|
|
100
|
+
isNewFile: false,
|
|
101
|
+
};
|
|
102
|
+
} else {
|
|
103
|
+
return {
|
|
104
|
+
fileName: cssModuleFileName,
|
|
105
|
+
textChanges: [{ span: { start: 0, length: 0 }, newText: `.${className} {\n \n}\n\n` }],
|
|
106
|
+
isNewFile: true,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|