@ktjs/ts-plugin 0.1.7 → 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,10 +5,9 @@ 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_VARIABLE = 7;
9
8
  const TOKEN_TYPE_TYPE = 5;
9
+ const TOKEN_TYPE_VARIABLE = 7;
10
10
  const TOKEN_MODIFIER_READONLY = 1 << 3;
11
- const TOKEN_MODIFIER_LOCAL = 1 << 5;
12
11
  const TOKEN_ENCODING_TYPE_OFFSET = 8;
13
12
  const IDENTIFIER_PATTERN = /[A-Za-z_$][A-Za-z0-9_$]*/g;
14
13
  const KEYWORD_DELIMITER_PATTERN = /\s+(in|of)\s+/;
@@ -47,6 +46,24 @@ function collectHighlightTokens(sourceFile, ts, config, span) {
47
46
  opening = node;
48
47
  }
49
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
+ }
50
67
  const attr = (0, jsx_attributes_1.getJsxAttribute)(opening, config.forAttr, ts);
51
68
  if (attr) {
52
69
  const parsed = parseKForAttributeTokens(attr, sourceFile, ts, config.allowOfKeyword);
@@ -134,6 +151,34 @@ function parseKForAttributeTokens(attr, sourceFile, ts, allowOfKeyword) {
134
151
  }
135
152
  return tokens;
136
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
+ }
137
182
  function collectAliasTokens(aliasText, baseStart, aliases) {
138
183
  const result = [];
139
184
  const allowed = new Set(aliases);
@@ -237,10 +282,10 @@ function buildSemanticSpans(tokens, format, ts) {
237
282
  spans.push({
238
283
  start: token.start,
239
284
  length: token.length,
240
- classification: token.kind === 'alias'
241
- ? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY | TOKEN_MODIFIER_LOCAL)
285
+ classification: token.kind === 'directive'
286
+ ? encodeSemantic2020(TOKEN_TYPE_TYPE, 0)
242
287
  : token.kind === 'keyword'
243
- ? encodeSemantic2020(TOKEN_TYPE_TYPE, 0)
288
+ ? encodeSemantic2020(TOKEN_TYPE_VARIABLE, TOKEN_MODIFIER_READONLY)
244
289
  : encodeSemantic2020(TOKEN_TYPE_VARIABLE, 0),
245
290
  });
246
291
  }
@@ -251,7 +296,11 @@ function buildSemanticSpans(tokens, format, ts) {
251
296
  spans.push({
252
297
  start: token.start,
253
298
  length: token.length,
254
- 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,
255
304
  });
256
305
  }
257
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.7",
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",