@ktjs/ts-plugin 0.1.4 → 0.1.6

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.
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveExpressionTypesFromText = resolveExpressionTypesFromText;
4
+ exports.formatTypeList = formatTypeList;
5
+ exports.uniqueTypes = uniqueTypes;
6
+ function resolveExpressionTypesFromText(raw, context) {
7
+ const value = raw.trim();
8
+ if (!value) {
9
+ return [];
10
+ }
11
+ const sourceFile = context.ts.createSourceFile('__k_for_expression.ts', `(${value});`, context.ts.ScriptTarget.Latest, true, context.ts.ScriptKind.TS);
12
+ if (sourceFile.statements.length === 0) {
13
+ return [];
14
+ }
15
+ const statement = sourceFile.statements[0];
16
+ if (!context.ts.isExpressionStatement(statement)) {
17
+ return [];
18
+ }
19
+ const types = resolveExpressionTypes(statement.expression, context);
20
+ return uniqueTypes(types, context.checker, context.scopeNode, context.ts);
21
+ }
22
+ function formatTypeList(types, checker, scopeNode, ts) {
23
+ if (types.length === 0) {
24
+ return 'any';
25
+ }
26
+ const texts = new Set();
27
+ for (let i = 0; i < types.length; i++) {
28
+ texts.add(checker.typeToString(types[i], scopeNode, ts.TypeFormatFlags.NoTruncation));
29
+ }
30
+ return Array.from(texts).join(' | ');
31
+ }
32
+ function uniqueTypes(types, checker, scopeNode, ts) {
33
+ const seen = new Set();
34
+ const result = [];
35
+ for (let i = 0; i < types.length; i++) {
36
+ const type = types[i];
37
+ const text = checker.typeToString(type, scopeNode, ts.TypeFormatFlags.NoTruncation);
38
+ if (seen.has(text)) {
39
+ continue;
40
+ }
41
+ seen.add(text);
42
+ result.push(type);
43
+ }
44
+ return result;
45
+ }
46
+ function resolveExpressionTypes(expr, context) {
47
+ const ts = context.ts;
48
+ const target = unwrapExpression(expr, ts);
49
+ if (ts.isIdentifier(target)) {
50
+ return resolveIdentifierTypes(target.text, context);
51
+ }
52
+ if (ts.isPropertyAccessExpression(target)) {
53
+ const objectTypes = resolveExpressionTypes(target.expression, context);
54
+ return resolvePropertyTypes(objectTypes, target.name.text, context, false);
55
+ }
56
+ if (ts.isElementAccessExpression(target)) {
57
+ const objectTypes = resolveExpressionTypes(target.expression, context);
58
+ const argument = target.argumentExpression;
59
+ if (!argument) {
60
+ return [];
61
+ }
62
+ if (ts.isStringLiteralLike(argument)) {
63
+ return resolvePropertyTypes(objectTypes, argument.text, context, true);
64
+ }
65
+ if (ts.isNumericLiteral(argument)) {
66
+ return resolveNumericElementTypes(objectTypes, Number(argument.text), context);
67
+ }
68
+ return resolveIndexedTypes(objectTypes, context);
69
+ }
70
+ if (ts.isCallExpression(target)) {
71
+ const calleeTypes = resolveExpressionTypes(target.expression, context);
72
+ const result = [];
73
+ for (let i = 0; i < calleeTypes.length; i++) {
74
+ const signatures = context.checker.getSignaturesOfType(calleeTypes[i], ts.SignatureKind.Call);
75
+ for (let j = 0; j < signatures.length; j++) {
76
+ result.push(context.checker.getReturnTypeOfSignature(signatures[j]));
77
+ }
78
+ }
79
+ return uniqueTypes(result, context.checker, context.scopeNode, ts);
80
+ }
81
+ if (ts.isConditionalExpression(target)) {
82
+ const whenTrue = resolveExpressionTypes(target.whenTrue, context);
83
+ const whenFalse = resolveExpressionTypes(target.whenFalse, context);
84
+ return uniqueTypes([...whenTrue, ...whenFalse], context.checker, context.scopeNode, ts);
85
+ }
86
+ if (ts.isBinaryExpression(target) &&
87
+ (target.operatorToken.kind === ts.SyntaxKind.BarBarToken ||
88
+ target.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
89
+ target.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken)) {
90
+ const left = resolveExpressionTypes(target.left, context);
91
+ const right = resolveExpressionTypes(target.right, context);
92
+ return uniqueTypes([...left, ...right], context.checker, context.scopeNode, ts);
93
+ }
94
+ return [];
95
+ }
96
+ function unwrapExpression(expr, ts) {
97
+ let current = expr;
98
+ while (true) {
99
+ if (ts.isParenthesizedExpression(current)) {
100
+ current = current.expression;
101
+ continue;
102
+ }
103
+ if (ts.isAsExpression(current) || ts.isTypeAssertionExpression(current) || ts.isSatisfiesExpression(current)) {
104
+ current = current.expression;
105
+ continue;
106
+ }
107
+ if (ts.isNonNullExpression(current)) {
108
+ current = current.expression;
109
+ continue;
110
+ }
111
+ return current;
112
+ }
113
+ }
114
+ function resolveIdentifierTypes(name, context) {
115
+ const localTypes = context.localBindings?.get(name);
116
+ if (localTypes && localTypes.length > 0) {
117
+ return [...localTypes];
118
+ }
119
+ const symbol = resolveSymbolInScope(name, context);
120
+ if (!symbol) {
121
+ return [];
122
+ }
123
+ return [context.checker.getTypeOfSymbolAtLocation(symbol, context.scopeNode)];
124
+ }
125
+ function resolveSymbolInScope(name, context) {
126
+ const symbols = context.checker.getSymbolsInScope(context.scopeNode, context.ts.SymbolFlags.Value | context.ts.SymbolFlags.Alias);
127
+ for (let i = 0; i < symbols.length; i++) {
128
+ const symbol = symbols[i];
129
+ if (symbol.getName() !== name) {
130
+ continue;
131
+ }
132
+ if (symbol.flags & context.ts.SymbolFlags.Alias) {
133
+ const aliased = context.checker.getAliasedSymbol(symbol);
134
+ if (aliased.flags & context.ts.SymbolFlags.Value) {
135
+ return aliased;
136
+ }
137
+ continue;
138
+ }
139
+ if (symbol.flags & context.ts.SymbolFlags.Value) {
140
+ return symbol;
141
+ }
142
+ }
143
+ return undefined;
144
+ }
145
+ function resolvePropertyTypes(objectTypes, propertyName, context, allowStringIndexFallback) {
146
+ const result = [];
147
+ for (let i = 0; i < objectTypes.length; i++) {
148
+ const targetType = context.checker.getApparentType(objectTypes[i]);
149
+ const property = context.checker.getPropertyOfType(targetType, propertyName);
150
+ if (property) {
151
+ result.push(context.checker.getTypeOfSymbolAtLocation(property, context.scopeNode));
152
+ continue;
153
+ }
154
+ if (allowStringIndexFallback) {
155
+ const stringIndexType = context.checker.getIndexTypeOfType(targetType, context.ts.IndexKind.String);
156
+ if (stringIndexType) {
157
+ result.push(stringIndexType);
158
+ }
159
+ }
160
+ }
161
+ return uniqueTypes(result, context.checker, context.scopeNode, context.ts);
162
+ }
163
+ function resolveNumericElementTypes(objectTypes, index, context) {
164
+ const result = [];
165
+ const indexName = String(index);
166
+ for (let i = 0; i < objectTypes.length; i++) {
167
+ const targetType = context.checker.getApparentType(objectTypes[i]);
168
+ const property = context.checker.getPropertyOfType(targetType, indexName);
169
+ if (property) {
170
+ result.push(context.checker.getTypeOfSymbolAtLocation(property, context.scopeNode));
171
+ }
172
+ const numericIndexType = context.checker.getIndexTypeOfType(targetType, context.ts.IndexKind.Number);
173
+ if (numericIndexType) {
174
+ result.push(numericIndexType);
175
+ }
176
+ }
177
+ return uniqueTypes(result, context.checker, context.scopeNode, context.ts);
178
+ }
179
+ function resolveIndexedTypes(objectTypes, context) {
180
+ const result = [];
181
+ for (let i = 0; i < objectTypes.length; i++) {
182
+ const targetType = context.checker.getApparentType(objectTypes[i]);
183
+ const stringIndexType = context.checker.getIndexTypeOfType(targetType, context.ts.IndexKind.String);
184
+ if (stringIndexType) {
185
+ result.push(stringIndexType);
186
+ }
187
+ const numericIndexType = context.checker.getIndexTypeOfType(targetType, context.ts.IndexKind.Number);
188
+ if (numericIndexType) {
189
+ result.push(numericIndexType);
190
+ }
191
+ }
192
+ return uniqueTypes(result, context.checker, context.scopeNode, context.ts);
193
+ }
@@ -0,0 +1,46 @@
1
+ import type tsModule from 'typescript/lib/tsserverlibrary';
2
+ export interface KForPluginConfig {
3
+ forAttr?: string;
4
+ itemAttr?: string;
5
+ indexAttr?: string;
6
+ itemName?: string;
7
+ indexName?: string;
8
+ allowOfKeyword?: boolean;
9
+ }
10
+ export interface ResolvedConfig {
11
+ forAttr: string;
12
+ itemAttr: string;
13
+ indexAttr: string;
14
+ itemName: string;
15
+ indexName: string;
16
+ allowOfKeyword: boolean;
17
+ }
18
+ export interface KForBinding {
19
+ name: string;
20
+ types: tsModule.Type[];
21
+ }
22
+ export interface KForScope {
23
+ start: number;
24
+ end: number;
25
+ bindings: KForBinding[];
26
+ }
27
+ export interface ParsedKForExpression {
28
+ aliases: string[];
29
+ source: string;
30
+ }
31
+ export interface TypeResolutionContext {
32
+ checker: tsModule.TypeChecker;
33
+ ts: typeof tsModule;
34
+ scopeNode: tsModule.Node;
35
+ localBindings?: ReadonlyMap<string, readonly tsModule.Type[]>;
36
+ }
37
+ export interface MemberCompletionContext {
38
+ receiver: string;
39
+ prefix: string;
40
+ }
41
+ export interface FileAnalysis {
42
+ sourceFile: tsModule.SourceFile;
43
+ checker: tsModule.TypeChecker;
44
+ scopes: KForScope[];
45
+ }
46
+ export type JsxOpeningLikeElement = tsModule.JsxOpeningElement | tsModule.JsxSelfClosingElement;
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ktjs/ts-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",
@@ -39,4 +39,4 @@
39
39
  "scripts": {
40
40
  "build": "tsc -p tsconfig.json"
41
41
  }
42
- }
42
+ }