@ktjs/ts-plugin 0.1.8 → 0.1.10
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/README.md +7 -4
- package/dist/config.js +6 -4
- package/dist/kfor-highlighting.js +58 -4
- package/dist/scope-analysis.js +12 -23
- package/dist/types.d.ts +12 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ TypeScript language service plugin for KT.js `k-for` scope variables in TSX.
|
|
|
10
10
|
- Provides hover type info and member completions for inferred aliases.
|
|
11
11
|
- Supports hover type info inside `k-for` expression strings (`item in users`) for alias/source identifiers.
|
|
12
12
|
- Adds `k-for` inline semantic highlighting in string expressions (for example alias/keyword/source in `k-for="item in list"`).
|
|
13
|
+
- Highlights directive attribute names (`k-for`, `k-key`, `k-if`, `k-else`, `k-else-if`, `k-model`, `k-html`) with semantic token colors.
|
|
13
14
|
- Supports Vue-like syntax:
|
|
14
15
|
- `k-for="item in list"`
|
|
15
16
|
- `k-for="(item, i) in list"`
|
|
@@ -54,10 +55,12 @@ If VS Code still does not load the plugin, make sure it uses your workspace Type
|
|
|
54
55
|
{
|
|
55
56
|
"name": "@ktjs/ts-plugin",
|
|
56
57
|
"forAttr": "k-for",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
58
|
+
"keyAttr": "k-key",
|
|
59
|
+
"ifAttr": "k-if",
|
|
60
|
+
"elseAttr": "k-else",
|
|
61
|
+
"elseIfAttr": "k-else-if",
|
|
62
|
+
"modelAttr": "k-model",
|
|
63
|
+
"htmlAttr": "k-html",
|
|
61
64
|
"allowOfKeyword": true
|
|
62
65
|
}
|
|
63
66
|
]
|
package/dist/config.js
CHANGED
|
@@ -9,10 +9,12 @@ const node_path_1 = __importDefault(require("node:path"));
|
|
|
9
9
|
function resolveConfig(config) {
|
|
10
10
|
return {
|
|
11
11
|
forAttr: config?.forAttr || 'k-for',
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
keyAttr: config?.keyAttr || 'k-key',
|
|
13
|
+
ifAttr: config?.ifAttr || 'k-if',
|
|
14
|
+
elseAttr: config?.elseAttr || 'k-else',
|
|
15
|
+
elseIfAttr: config?.elseIfAttr || 'k-else-if',
|
|
16
|
+
modelAttr: config?.modelAttr || 'k-model',
|
|
17
|
+
htmlAttr: config?.htmlAttr || 'k-html',
|
|
16
18
|
allowOfKeyword: config?.allowOfKeyword !== false,
|
|
17
19
|
};
|
|
18
20
|
}
|
|
@@ -5,6 +5,7 @@ exports.addKForSyntacticClassifications = addKForSyntacticClassifications;
|
|
|
5
5
|
const jsx_attributes_1 = require("./jsx-attributes");
|
|
6
6
|
const kfor_parser_1 = require("./kfor-parser");
|
|
7
7
|
const identifiers_1 = require("./identifiers");
|
|
8
|
+
const TOKEN_TYPE_TYPE = 5;
|
|
8
9
|
const TOKEN_TYPE_VARIABLE = 7;
|
|
9
10
|
const TOKEN_MODIFIER_READONLY = 1 << 3;
|
|
10
11
|
const TOKEN_ENCODING_TYPE_OFFSET = 8;
|
|
@@ -45,6 +46,24 @@ function collectHighlightTokens(sourceFile, ts, config, span) {
|
|
|
45
46
|
opening = node;
|
|
46
47
|
}
|
|
47
48
|
if (opening) {
|
|
49
|
+
const directiveTokens = collectDirectiveAttributeTokens(opening, sourceFile, ts, config);
|
|
50
|
+
for (let i = 0; i < directiveTokens.length; i++) {
|
|
51
|
+
const token = directiveTokens[i];
|
|
52
|
+
const tokenStart = token.start;
|
|
53
|
+
const tokenEnd = token.start + token.length;
|
|
54
|
+
if (tokenEnd <= spanStart || tokenStart >= spanEnd) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const clippedStart = Math.max(tokenStart, spanStart);
|
|
58
|
+
const clippedEnd = Math.min(tokenEnd, spanEnd);
|
|
59
|
+
if (clippedEnd > clippedStart) {
|
|
60
|
+
tokens.push({
|
|
61
|
+
start: clippedStart,
|
|
62
|
+
length: clippedEnd - clippedStart,
|
|
63
|
+
kind: token.kind,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
48
67
|
const attr = (0, jsx_attributes_1.getJsxAttribute)(opening, config.forAttr, ts);
|
|
49
68
|
if (attr) {
|
|
50
69
|
const parsed = parseKForAttributeTokens(attr, sourceFile, ts, config.allowOfKeyword);
|
|
@@ -132,6 +151,35 @@ function parseKForAttributeTokens(attr, sourceFile, ts, allowOfKeyword) {
|
|
|
132
151
|
}
|
|
133
152
|
return tokens;
|
|
134
153
|
}
|
|
154
|
+
function collectDirectiveAttributeTokens(opening, sourceFile, ts, config) {
|
|
155
|
+
const directiveNames = new Set([
|
|
156
|
+
config.forAttr,
|
|
157
|
+
config.keyAttr,
|
|
158
|
+
config.ifAttr,
|
|
159
|
+
config.elseAttr,
|
|
160
|
+
config.elseIfAttr,
|
|
161
|
+
config.modelAttr,
|
|
162
|
+
config.htmlAttr,
|
|
163
|
+
]);
|
|
164
|
+
const tokens = [];
|
|
165
|
+
for (const directiveName of directiveNames) {
|
|
166
|
+
const attr = (0, jsx_attributes_1.getJsxAttribute)(opening, directiveName, ts);
|
|
167
|
+
if (!attr) {
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
const start = attr.name.getStart(sourceFile);
|
|
171
|
+
const length = attr.name.getWidth(sourceFile);
|
|
172
|
+
if (length <= 0) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
tokens.push({
|
|
176
|
+
start,
|
|
177
|
+
length,
|
|
178
|
+
kind: 'directive',
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
return tokens;
|
|
182
|
+
}
|
|
135
183
|
function collectAliasTokens(aliasText, baseStart, aliases) {
|
|
136
184
|
const result = [];
|
|
137
185
|
const allowed = new Set(aliases);
|
|
@@ -235,9 +283,11 @@ function buildSemanticSpans(tokens, format, ts) {
|
|
|
235
283
|
spans.push({
|
|
236
284
|
start: token.start,
|
|
237
285
|
length: token.length,
|
|
238
|
-
classification: token.kind === '
|
|
239
|
-
? encodeSemantic2020(
|
|
240
|
-
:
|
|
286
|
+
classification: token.kind === 'directive'
|
|
287
|
+
? encodeSemantic2020(TOKEN_TYPE_TYPE, 0)
|
|
288
|
+
: token.kind === 'keyword'
|
|
289
|
+
? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY)
|
|
290
|
+
: encodeSemantic2020(TOKEN_TYPE_VARIABLE, 0),
|
|
241
291
|
});
|
|
242
292
|
}
|
|
243
293
|
return spans;
|
|
@@ -247,7 +297,11 @@ function buildSemanticSpans(tokens, format, ts) {
|
|
|
247
297
|
spans.push({
|
|
248
298
|
start: token.start,
|
|
249
299
|
length: token.length,
|
|
250
|
-
classification: token.kind === '
|
|
300
|
+
classification: token.kind === 'directive'
|
|
301
|
+
? ts.ClassificationType.className
|
|
302
|
+
: token.kind === 'keyword'
|
|
303
|
+
? ts.ClassificationType.keyword
|
|
304
|
+
: ts.ClassificationType.identifier,
|
|
251
305
|
});
|
|
252
306
|
}
|
|
253
307
|
return spans;
|
package/dist/scope-analysis.js
CHANGED
|
@@ -6,7 +6,6 @@ exports.collectBindingsAtPosition = collectBindingsAtPosition;
|
|
|
6
6
|
exports.resolveBindingsForForAttribute = resolveBindingsForForAttribute;
|
|
7
7
|
const jsx_attributes_1 = require("./jsx-attributes");
|
|
8
8
|
const kfor_parser_1 = require("./kfor-parser");
|
|
9
|
-
const identifiers_1 = require("./identifiers");
|
|
10
9
|
const type_resolution_1 = require("./type-resolution");
|
|
11
10
|
function getFileAnalysis(fileName, languageService, ts, config) {
|
|
12
11
|
const program = languageService.getProgram();
|
|
@@ -78,22 +77,19 @@ function collectKForScopes(sourceFile, checker, ts, config) {
|
|
|
78
77
|
}
|
|
79
78
|
function resolveScopeBindings(opening, forAttr, checker, config, ts) {
|
|
80
79
|
const forExpression = (0, jsx_attributes_1.getAttributeText)(forAttr, ts);
|
|
81
|
-
if (forExpression
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
scopeNode: opening,
|
|
88
|
-
});
|
|
89
|
-
return createBindings(parsed.aliases, sourceTypes, checker, opening, ts);
|
|
90
|
-
}
|
|
80
|
+
if (forExpression === undefined) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
const parsed = (0, kfor_parser_1.parseKForExpression)(forExpression, config.allowOfKeyword);
|
|
84
|
+
if (!parsed) {
|
|
85
|
+
return [];
|
|
91
86
|
}
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
const sourceTypes = (0, type_resolution_1.resolveExpressionTypesFromText)(parsed.source, {
|
|
88
|
+
checker,
|
|
89
|
+
ts,
|
|
90
|
+
scopeNode: opening,
|
|
91
|
+
});
|
|
92
|
+
return createBindings(parsed.aliases, sourceTypes, checker, opening, ts);
|
|
97
93
|
}
|
|
98
94
|
function createBindings(names, sourceTypes, checker, scopeNode, ts) {
|
|
99
95
|
if (names.length === 0) {
|
|
@@ -146,10 +142,3 @@ function expandUnionTypes(types, ts) {
|
|
|
146
142
|
}
|
|
147
143
|
return result;
|
|
148
144
|
}
|
|
149
|
-
function getLegacyForSourceTypes(forAttr, checker, ts) {
|
|
150
|
-
const expression = (0, jsx_attributes_1.getAttributeExpression)(forAttr, ts);
|
|
151
|
-
if (!expression || ts.isStringLiteralLike(expression)) {
|
|
152
|
-
return [];
|
|
153
|
-
}
|
|
154
|
-
return [checker.getTypeAtLocation(expression)];
|
|
155
|
-
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import type tsModule from 'typescript/lib/tsserverlibrary';
|
|
2
2
|
export interface KForPluginConfig {
|
|
3
3
|
forAttr?: string;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
keyAttr?: string;
|
|
5
|
+
ifAttr?: string;
|
|
6
|
+
elseAttr?: string;
|
|
7
|
+
elseIfAttr?: string;
|
|
8
|
+
modelAttr?: string;
|
|
9
|
+
htmlAttr?: string;
|
|
8
10
|
allowOfKeyword?: boolean;
|
|
9
11
|
}
|
|
10
12
|
export interface ResolvedConfig {
|
|
11
13
|
forAttr: string;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
keyAttr: string;
|
|
15
|
+
ifAttr: string;
|
|
16
|
+
elseAttr: string;
|
|
17
|
+
elseIfAttr: string;
|
|
18
|
+
modelAttr: string;
|
|
19
|
+
htmlAttr: string;
|
|
16
20
|
allowOfKeyword: boolean;
|
|
17
21
|
}
|
|
18
22
|
export interface KForBinding {
|