@ktjs/ts-plugin 0.1.8 → 0.1.9

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-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,11 @@ 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
+ "ifAttr": "k-if",
59
+ "elseAttr": "k-else",
60
+ "elseIfAttr": "k-else-if",
61
+ "modelAttr": "k-model",
62
+ "htmlAttr": "k-html",
61
63
  "allowOfKeyword": true
62
64
  }
63
65
  ]
package/dist/config.js CHANGED
@@ -9,10 +9,11 @@ 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
+ ifAttr: config?.ifAttr || 'k-if',
13
+ elseAttr: config?.elseAttr || 'k-else',
14
+ elseIfAttr: config?.elseIfAttr || 'k-else-if',
15
+ modelAttr: config?.modelAttr || 'k-model',
16
+ htmlAttr: config?.htmlAttr || 'k-html',
16
17
  allowOfKeyword: config?.allowOfKeyword !== false,
17
18
  };
18
19
  }
@@ -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,34 @@ 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.ifAttr,
158
+ config.elseAttr,
159
+ config.elseIfAttr,
160
+ config.modelAttr,
161
+ config.htmlAttr,
162
+ ]);
163
+ const tokens = [];
164
+ for (const directiveName of directiveNames) {
165
+ const attr = (0, jsx_attributes_1.getJsxAttribute)(opening, directiveName, ts);
166
+ if (!attr) {
167
+ continue;
168
+ }
169
+ const start = attr.name.getStart(sourceFile);
170
+ const length = attr.name.getWidth(sourceFile);
171
+ if (length <= 0) {
172
+ continue;
173
+ }
174
+ tokens.push({
175
+ start,
176
+ length,
177
+ kind: 'directive',
178
+ });
179
+ }
180
+ return tokens;
181
+ }
135
182
  function collectAliasTokens(aliasText, baseStart, aliases) {
136
183
  const result = [];
137
184
  const allowed = new Set(aliases);
@@ -235,9 +282,11 @@ function buildSemanticSpans(tokens, format, ts) {
235
282
  spans.push({
236
283
  start: token.start,
237
284
  length: token.length,
238
- classification: token.kind === 'keyword'
239
- ? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY)
240
- : encodeSemantic2020(TOKEN_TYPE_VARIABLE, 0),
285
+ classification: token.kind === 'directive'
286
+ ? encodeSemantic2020(TOKEN_TYPE_TYPE, 0)
287
+ : token.kind === 'keyword'
288
+ ? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY)
289
+ : encodeSemantic2020(TOKEN_TYPE_VARIABLE, 0),
241
290
  });
242
291
  }
243
292
  return spans;
@@ -247,7 +296,11 @@ function buildSemanticSpans(tokens, format, ts) {
247
296
  spans.push({
248
297
  start: token.start,
249
298
  length: token.length,
250
- classification: token.kind === 'keyword' ? ts.ClassificationType.keyword : ts.ClassificationType.identifier,
299
+ classification: token.kind === 'directive'
300
+ ? ts.ClassificationType.className
301
+ : token.kind === 'keyword'
302
+ ? ts.ClassificationType.keyword
303
+ : ts.ClassificationType.identifier,
251
304
  });
252
305
  }
253
306
  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,20 @@
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
+ ifAttr?: string;
5
+ elseAttr?: string;
6
+ elseIfAttr?: string;
7
+ modelAttr?: string;
8
+ htmlAttr?: string;
8
9
  allowOfKeyword?: boolean;
9
10
  }
10
11
  export interface ResolvedConfig {
11
12
  forAttr: string;
12
- itemAttr: string;
13
- indexAttr: string;
14
- itemName: string;
15
- indexName: string;
13
+ ifAttr: string;
14
+ elseAttr: string;
15
+ elseIfAttr: string;
16
+ modelAttr: string;
17
+ htmlAttr: string;
16
18
  allowOfKeyword: boolean;
17
19
  }
18
20
  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.9",
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",