@ktjs/ts-plugin 0.1.4 → 0.1.5
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/dist/ast.d.ts +4 -0
- package/dist/ast.js +41 -0
- package/dist/completion.d.ts +7 -0
- package/dist/completion.js +128 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +22 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +8 -0
- package/dist/identifiers.d.ts +3 -0
- package/dist/identifiers.js +29 -0
- package/dist/index.js +34 -637
- package/dist/jsx-attributes.d.ts +6 -0
- package/dist/jsx-attributes.js +59 -0
- package/dist/kfor-parser.d.ts +2 -0
- package/dist/kfor-parser.js +36 -0
- package/dist/scope-analysis.d.ts +5 -0
- package/dist/scope-analysis.js +151 -0
- package/dist/type-resolution.d.ts +5 -0
- package/dist/type-resolution.js +193 -0
- package/dist/types.d.ts +46 -0
- package/dist/types.js +2 -0
- package/package.json +2 -2
package/dist/ast.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type tsModule from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
export declare function findIdentifierAtPosition(sourceFile: tsModule.SourceFile, position: number, ts: typeof tsModule): tsModule.Identifier | undefined;
|
|
3
|
+
export declare function normalizePosition(position: number, sourceFile: tsModule.SourceFile): number;
|
|
4
|
+
export declare function findInnermostNode(node: tsModule.Node, position: number, ts: typeof tsModule): tsModule.Node | undefined;
|
package/dist/ast.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findIdentifierAtPosition = findIdentifierAtPosition;
|
|
4
|
+
exports.normalizePosition = normalizePosition;
|
|
5
|
+
exports.findInnermostNode = findInnermostNode;
|
|
6
|
+
function findIdentifierAtPosition(sourceFile, position, ts) {
|
|
7
|
+
const exact = findInnermostNode(sourceFile, normalizePosition(position, sourceFile), ts);
|
|
8
|
+
if (exact && ts.isIdentifier(exact)) {
|
|
9
|
+
return exact;
|
|
10
|
+
}
|
|
11
|
+
if (position > 0) {
|
|
12
|
+
const previous = findInnermostNode(sourceFile, normalizePosition(position - 1, sourceFile), ts);
|
|
13
|
+
if (previous && ts.isIdentifier(previous)) {
|
|
14
|
+
return previous;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
function normalizePosition(position, sourceFile) {
|
|
20
|
+
const max = Math.max(sourceFile.text.length - 1, 0);
|
|
21
|
+
if (position < 0) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
if (position > max) {
|
|
25
|
+
return max;
|
|
26
|
+
}
|
|
27
|
+
return position;
|
|
28
|
+
}
|
|
29
|
+
function findInnermostNode(node, position, ts) {
|
|
30
|
+
if (position < node.getFullStart() || position >= node.end) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
let match;
|
|
34
|
+
ts.forEachChild(node, (child) => {
|
|
35
|
+
const childMatch = findInnermostNode(child, position, ts);
|
|
36
|
+
if (childMatch) {
|
|
37
|
+
match = childMatch;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return match || node;
|
|
41
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type tsModule from 'typescript/lib/tsserverlibrary';
|
|
2
|
+
import type { KForBinding, MemberCompletionContext } from './types';
|
|
3
|
+
export declare function createMemberCompletionEntries(types: tsModule.Type[], prefix: string, checker: tsModule.TypeChecker, scopeNode: tsModule.Node, ts: typeof tsModule): tsModule.CompletionEntry[];
|
|
4
|
+
export declare function createAliasCompletionEntries(bindings: Map<string, KForBinding>, text: string, position: number, ts: typeof tsModule): tsModule.CompletionEntry[];
|
|
5
|
+
export declare function mergeCompletionInfo(completions: tsModule.CompletionInfo | undefined, extraEntries: tsModule.CompletionEntry[], forceMemberCompletion: boolean): tsModule.CompletionInfo;
|
|
6
|
+
export declare function createBindingTypeMap(bindings: Map<string, KForBinding>): Map<string, readonly tsModule.Type[]>;
|
|
7
|
+
export declare function getMemberCompletionContext(text: string, position: number): MemberCompletionContext | undefined;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMemberCompletionEntries = createMemberCompletionEntries;
|
|
4
|
+
exports.createAliasCompletionEntries = createAliasCompletionEntries;
|
|
5
|
+
exports.mergeCompletionInfo = mergeCompletionInfo;
|
|
6
|
+
exports.createBindingTypeMap = createBindingTypeMap;
|
|
7
|
+
exports.getMemberCompletionContext = getMemberCompletionContext;
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const identifiers_1 = require("./identifiers");
|
|
10
|
+
const type_resolution_1 = require("./type-resolution");
|
|
11
|
+
function createMemberCompletionEntries(types, prefix, checker, scopeNode, ts) {
|
|
12
|
+
if (types.length === 0) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
const entries = new Map();
|
|
16
|
+
const candidates = (0, type_resolution_1.uniqueTypes)(types, checker, scopeNode, ts);
|
|
17
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
18
|
+
const properties = checker.getPropertiesOfType(checker.getApparentType(candidates[i]));
|
|
19
|
+
for (let j = 0; j < properties.length; j++) {
|
|
20
|
+
const property = properties[j];
|
|
21
|
+
const name = property.getName();
|
|
22
|
+
if (!(0, identifiers_1.isValidIdentifier)(name) || name.startsWith('__@')) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (prefix && !name.startsWith(prefix)) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (entries.has(name)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
entries.set(name, {
|
|
32
|
+
name,
|
|
33
|
+
kind: getCompletionKind(property, ts),
|
|
34
|
+
kindModifiers: '',
|
|
35
|
+
sortText: '0',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return Array.from(entries.values()).sort((left, right) => left.name.localeCompare(right.name));
|
|
40
|
+
}
|
|
41
|
+
function createAliasCompletionEntries(bindings, text, position, ts) {
|
|
42
|
+
const prefix = getIdentifierPrefix(text, position);
|
|
43
|
+
if (prefix.isMemberAccess) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const entries = [];
|
|
47
|
+
for (const binding of bindings.values()) {
|
|
48
|
+
if (prefix.text && !binding.name.startsWith(prefix.text)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
entries.push({
|
|
52
|
+
name: binding.name,
|
|
53
|
+
kind: ts.ScriptElementKind.localVariableElement,
|
|
54
|
+
kindModifiers: '',
|
|
55
|
+
sortText: '0',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return entries;
|
|
59
|
+
}
|
|
60
|
+
function mergeCompletionInfo(completions, extraEntries, forceMemberCompletion) {
|
|
61
|
+
if (!completions) {
|
|
62
|
+
return {
|
|
63
|
+
isGlobalCompletion: !forceMemberCompletion,
|
|
64
|
+
isMemberCompletion: forceMemberCompletion,
|
|
65
|
+
isNewIdentifierLocation: !forceMemberCompletion,
|
|
66
|
+
entries: extraEntries,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const seen = new Set();
|
|
70
|
+
for (let i = 0; i < completions.entries.length; i++) {
|
|
71
|
+
seen.add(completions.entries[i].name);
|
|
72
|
+
}
|
|
73
|
+
const merged = completions.entries.slice();
|
|
74
|
+
for (let i = 0; i < extraEntries.length; i++) {
|
|
75
|
+
const entry = extraEntries[i];
|
|
76
|
+
if (seen.has(entry.name)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
seen.add(entry.name);
|
|
80
|
+
merged.push(entry);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
...completions,
|
|
84
|
+
isMemberCompletion: completions.isMemberCompletion || forceMemberCompletion,
|
|
85
|
+
entries: merged,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createBindingTypeMap(bindings) {
|
|
89
|
+
const map = new Map();
|
|
90
|
+
for (const binding of bindings.values()) {
|
|
91
|
+
map.set(binding.name, binding.types);
|
|
92
|
+
}
|
|
93
|
+
return map;
|
|
94
|
+
}
|
|
95
|
+
function getMemberCompletionContext(text, position) {
|
|
96
|
+
const sliceStart = Math.max(0, position - 200);
|
|
97
|
+
const snippet = text.slice(sliceStart, position);
|
|
98
|
+
const match = constants_1.MEMBER_COMPLETION_PATTERN.exec(snippet);
|
|
99
|
+
if (!match) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
receiver: match[1],
|
|
104
|
+
prefix: match[2] || '',
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function getCompletionKind(symbol, ts) {
|
|
108
|
+
const flags = symbol.flags;
|
|
109
|
+
if (flags & ts.SymbolFlags.Method) {
|
|
110
|
+
return ts.ScriptElementKind.memberFunctionElement;
|
|
111
|
+
}
|
|
112
|
+
if (flags & ts.SymbolFlags.Function) {
|
|
113
|
+
return ts.ScriptElementKind.functionElement;
|
|
114
|
+
}
|
|
115
|
+
if (flags & (ts.SymbolFlags.GetAccessor | ts.SymbolFlags.SetAccessor | ts.SymbolFlags.Property)) {
|
|
116
|
+
return ts.ScriptElementKind.memberVariableElement;
|
|
117
|
+
}
|
|
118
|
+
return ts.ScriptElementKind.memberVariableElement;
|
|
119
|
+
}
|
|
120
|
+
function getIdentifierPrefix(text, position) {
|
|
121
|
+
let start = position;
|
|
122
|
+
while (start > 0 && (0, identifiers_1.isIdentifierPart)(text.charCodeAt(start - 1))) {
|
|
123
|
+
start--;
|
|
124
|
+
}
|
|
125
|
+
const prefix = text.slice(start, position);
|
|
126
|
+
const isMemberAccess = start > 0 && text.charCodeAt(start - 1) === 46;
|
|
127
|
+
return { text: prefix, isMemberAccess };
|
|
128
|
+
}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveConfig = resolveConfig;
|
|
7
|
+
exports.isJsxLikeFile = isJsxLikeFile;
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
function resolveConfig(config) {
|
|
10
|
+
return {
|
|
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',
|
|
16
|
+
allowOfKeyword: config?.allowOfKeyword !== false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function isJsxLikeFile(fileName) {
|
|
20
|
+
const ext = node_path_1.default.extname(fileName).toLowerCase();
|
|
21
|
+
return ext === '.tsx' || ext === '.jsx';
|
|
22
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MEMBER_COMPLETION_PATTERN = exports.KFOR_TUPLE_PATTERN = exports.KFOR_SINGLE_PATTERN = exports.IDENTIFIER_RE = exports.DIAGNOSTIC_CANNOT_FIND_NAME = void 0;
|
|
4
|
+
exports.DIAGNOSTIC_CANNOT_FIND_NAME = 2304;
|
|
5
|
+
exports.IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
6
|
+
exports.KFOR_SINGLE_PATTERN = /^([A-Za-z_$][A-Za-z0-9_$]*)\s+(in|of)\s+([\s\S]+)$/;
|
|
7
|
+
exports.KFOR_TUPLE_PATTERN = /^\(\s*([A-Za-z_$][A-Za-z0-9_$]*)(?:\s*,\s*([A-Za-z_$][A-Za-z0-9_$]*))?(?:\s*,\s*([A-Za-z_$][A-Za-z0-9_$]*))?\s*\)\s+(in|of)\s+([\s\S]+)$/;
|
|
8
|
+
exports.MEMBER_COMPLETION_PATTERN = /([A-Za-z_$][A-Za-z0-9_$]*(?:\s*(?:\.\s*[A-Za-z_$][A-Za-z0-9_$]*|\[\s*(?:'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"|\d+)\s*\]))*)\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)?$/;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isValidIdentifier = isValidIdentifier;
|
|
4
|
+
exports.uniqueIdentifiers = uniqueIdentifiers;
|
|
5
|
+
exports.isIdentifierPart = isIdentifierPart;
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
function isValidIdentifier(name) {
|
|
8
|
+
return constants_1.IDENTIFIER_RE.test(name);
|
|
9
|
+
}
|
|
10
|
+
function uniqueIdentifiers(names) {
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
const result = [];
|
|
13
|
+
for (let i = 0; i < names.length; i++) {
|
|
14
|
+
const name = names[i];
|
|
15
|
+
if (!isValidIdentifier(name) || seen.has(name)) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
seen.add(name);
|
|
19
|
+
result.push(name);
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
function isIdentifierPart(code) {
|
|
24
|
+
return ((code >= 65 && code <= 90) ||
|
|
25
|
+
(code >= 97 && code <= 122) ||
|
|
26
|
+
(code >= 48 && code <= 57) ||
|
|
27
|
+
code === 95 ||
|
|
28
|
+
code === 36);
|
|
29
|
+
}
|