@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 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
- "itemAttr": "k-for-item",
58
- "indexAttr": "k-for-index",
59
- "itemName": "item",
60
- "indexName": "index",
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
- itemAttr: config?.itemAttr || 'k-for-item',
13
- indexAttr: config?.indexAttr || 'k-for-index',
14
- itemName: config?.itemName || 'item',
15
- indexName: config?.indexName || 'index',
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 === 'keyword'
239
- ? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY)
240
- : encodeSemantic2020(TOKEN_TYPE_VARIABLE, 0),
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 === 'keyword' ? ts.ClassificationType.keyword : ts.ClassificationType.identifier,
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;
@@ -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 !== undefined) {
82
- const parsed = (0, kfor_parser_1.parseKForExpression)(forExpression, config.allowOfKeyword);
83
- if (parsed) {
84
- const sourceTypes = (0, type_resolution_1.resolveExpressionTypesFromText)(parsed.source, {
85
- checker,
86
- ts,
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 itemName = (0, jsx_attributes_1.getScopeName)(opening, config.itemAttr, config.itemName, ts);
93
- const indexName = (0, jsx_attributes_1.getScopeName)(opening, config.indexAttr, config.indexName, ts);
94
- const aliases = (0, identifiers_1.uniqueIdentifiers)([itemName, indexName]);
95
- const sourceTypes = getLegacyForSourceTypes(forAttr, checker, ts);
96
- return createBindings(aliases, sourceTypes, checker, opening, ts);
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
- itemAttr?: string;
5
- indexAttr?: string;
6
- itemName?: string;
7
- indexName?: string;
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
- itemAttr: string;
13
- indexAttr: string;
14
- itemName: string;
15
- indexName: string;
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 {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/ts-plugin",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "TypeScript language service plugin for kt.js k-for scope names in TSX.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",