@esportsplus/reactivity 0.26.0 → 0.27.0
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/build/compiler/array.d.ts +1 -1
- package/build/compiler/array.js +1 -1
- package/build/compiler/index.d.ts +1 -1
- package/build/compiler/index.js +30 -34
- package/build/compiler/object.d.ts +1 -1
- package/build/compiler/object.js +15 -21
- package/build/compiler/primitives.d.ts +1 -1
- package/build/compiler/primitives.js +19 -27
- package/package.json +6 -7
- package/src/compiler/array.ts +1 -1
- package/src/compiler/index.ts +35 -39
- package/src/compiler/object.ts +20 -27
- package/src/compiler/primitives.ts +28 -34
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
2
|
import type { Bindings } from '../types.js';
|
|
3
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, _ns: string) => string;
|
|
3
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, _ns: string, _checker?: ts.TypeChecker) => string;
|
|
4
4
|
export default _default;
|
package/build/compiler/array.js
CHANGED
|
@@ -54,7 +54,7 @@ function visit(ctx, node) {
|
|
|
54
54
|
}
|
|
55
55
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
56
56
|
}
|
|
57
|
-
export default (sourceFile, bindings, _ns) => {
|
|
57
|
+
export default (sourceFile, bindings, _ns, _checker) => {
|
|
58
58
|
let code = sourceFile.getFullText(), ctx = {
|
|
59
59
|
bindings,
|
|
60
60
|
replacements: [],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
2
|
import type { TransformResult } from '../types.js';
|
|
3
|
-
declare const transform: (sourceFile: ts.SourceFile) => TransformResult;
|
|
3
|
+
declare const transform: (sourceFile: ts.SourceFile, program: ts.Program) => TransformResult;
|
|
4
4
|
export { transform };
|
package/build/compiler/index.js
CHANGED
|
@@ -1,51 +1,46 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { code as c } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REGEX, COMPILER_NAMESPACE } from '../constants.js';
|
|
2
|
+
import { code as c, imports } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REGEX, COMPILER_NAMESPACE, PACKAGE } from '../constants.js';
|
|
4
4
|
import array from './array.js';
|
|
5
5
|
import object from './object.js';
|
|
6
6
|
import primitives from './primitives.js';
|
|
7
7
|
let transforms = [object, array, primitives];
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
function hasReactiveImport(sourceFile) {
|
|
9
|
+
let found = imports.find(sourceFile, PACKAGE);
|
|
10
|
+
for (let i = 0, n = found.length; i < n; i++) {
|
|
11
|
+
if (found[i].specifiers.has(COMPILER_ENTRYPOINT)) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
|
-
|
|
13
|
-
imported: false,
|
|
14
|
-
used: false
|
|
15
|
-
};
|
|
16
|
-
visit(ctx, ts.createSourceFile('detect.ts', code, ts.ScriptTarget.Latest, false));
|
|
17
|
-
return ctx.imported && ctx.used;
|
|
15
|
+
return false;
|
|
18
16
|
}
|
|
19
|
-
function
|
|
20
|
-
if (
|
|
21
|
-
return;
|
|
17
|
+
function hasReactiveUsage(code) {
|
|
18
|
+
if (!c.contains(code, { regex: COMPILER_ENTRYPOINT_REGEX })) {
|
|
19
|
+
return false;
|
|
22
20
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (let i = 0, n = elements.length; i < n; i++) {
|
|
28
|
-
let element = elements[i];
|
|
29
|
-
if ((element.propertyName?.text ?? element.name.text) === COMPILER_ENTRYPOINT) {
|
|
30
|
-
ctx.imported = true;
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
21
|
+
let sourceFile = ts.createSourceFile('detect.ts', code, ts.ScriptTarget.Latest, false), used = false;
|
|
22
|
+
function visit(node) {
|
|
23
|
+
if (used) {
|
|
24
|
+
return;
|
|
33
25
|
}
|
|
26
|
+
if (ts.isCallExpression(node) &&
|
|
27
|
+
ts.isIdentifier(node.expression) &&
|
|
28
|
+
node.expression.text === COMPILER_ENTRYPOINT) {
|
|
29
|
+
used = true;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
ts.forEachChild(node, visit);
|
|
34
33
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
node.expression.text === COMPILER_ENTRYPOINT) {
|
|
38
|
-
ctx.used = true;
|
|
39
|
-
}
|
|
40
|
-
ts.forEachChild(node, n => visit(ctx, n));
|
|
34
|
+
visit(sourceFile);
|
|
35
|
+
return used;
|
|
41
36
|
}
|
|
42
|
-
const transform = (sourceFile) => {
|
|
43
|
-
let bindings = new Map(), changed = false, code = sourceFile.getFullText(), current = sourceFile, result;
|
|
44
|
-
if (!
|
|
37
|
+
const transform = (sourceFile, program) => {
|
|
38
|
+
let bindings = new Map(), changed = false, checker = program.getTypeChecker(), code = sourceFile.getFullText(), current = sourceFile, result;
|
|
39
|
+
if (!hasReactiveImport(sourceFile) || !hasReactiveUsage(code)) {
|
|
45
40
|
return { changed: false, code, sourceFile };
|
|
46
41
|
}
|
|
47
42
|
for (let i = 0, n = transforms.length; i < n; i++) {
|
|
48
|
-
result = transforms[i](current, bindings, COMPILER_NAMESPACE);
|
|
43
|
+
result = transforms[i](current, bindings, COMPILER_NAMESPACE, checker);
|
|
49
44
|
if (result !== code) {
|
|
50
45
|
current = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
51
46
|
code = result;
|
|
@@ -53,6 +48,7 @@ const transform = (sourceFile) => {
|
|
|
53
48
|
}
|
|
54
49
|
}
|
|
55
50
|
if (changed) {
|
|
51
|
+
code = imports.modify(code, current, PACKAGE, { remove: [COMPILER_ENTRYPOINT] });
|
|
56
52
|
code = `import * as ${COMPILER_NAMESPACE} from '@esportsplus/reactivity';\n` + code;
|
|
57
53
|
sourceFile = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
|
|
58
54
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
2
|
import type { Bindings } from '../types.js';
|
|
3
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, ns: string) => string;
|
|
3
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, ns: string, checker?: ts.TypeChecker) => string;
|
|
4
4
|
export default _default;
|
package/build/compiler/object.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { code as c } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import { COMPILER_TYPES, PACKAGE } from '../constants.js';
|
|
2
|
+
import { code as c, imports } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '../constants.js';
|
|
4
4
|
function analyzeProperty(prop, sourceFile) {
|
|
5
5
|
if (!ts.isPropertyAssignment(prop)) {
|
|
6
6
|
return null;
|
|
@@ -60,27 +60,21 @@ function buildClassCode(className, properties, ns) {
|
|
|
60
60
|
}
|
|
61
61
|
`;
|
|
62
62
|
}
|
|
63
|
+
function isReactiveCall(node, checker) {
|
|
64
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (node.expression.text !== COMPILER_ENTRYPOINT) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return imports.isFromPackage(node.expression, PACKAGE, checker);
|
|
71
|
+
}
|
|
63
72
|
function visit(ctx, node) {
|
|
64
73
|
if (ts.isImportDeclaration(node)) {
|
|
65
74
|
ctx.lastImportEnd = node.end;
|
|
66
|
-
if (ts.isStringLiteral(node.moduleSpecifier) &&
|
|
67
|
-
node.moduleSpecifier.text.includes(PACKAGE)) {
|
|
68
|
-
let clause = node.importClause;
|
|
69
|
-
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
70
|
-
let elements = clause.namedBindings.elements;
|
|
71
|
-
for (let i = 0, n = elements.length; i < n; i++) {
|
|
72
|
-
if (elements[i].name.text === 'reactive') {
|
|
73
|
-
ctx.hasReactiveImport = true;
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
75
|
}
|
|
80
|
-
if (
|
|
81
|
-
|
|
82
|
-
ts.isIdentifier(node.expression) &&
|
|
83
|
-
node.expression.text === 'reactive') {
|
|
76
|
+
if (ts.isCallExpression(node) &&
|
|
77
|
+
isReactiveCall(node, ctx.checker)) {
|
|
84
78
|
let arg = node.arguments[0];
|
|
85
79
|
if (arg && ts.isObjectLiteralExpression(arg)) {
|
|
86
80
|
let properties = [], props = arg.properties, varName = null;
|
|
@@ -115,12 +109,12 @@ function visit(ctx, node) {
|
|
|
115
109
|
}
|
|
116
110
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
117
111
|
}
|
|
118
|
-
export default (sourceFile, bindings, ns) => {
|
|
112
|
+
export default (sourceFile, bindings, ns, checker) => {
|
|
119
113
|
let code = sourceFile.getFullText(), ctx = {
|
|
120
114
|
bindings,
|
|
121
115
|
calls: [],
|
|
116
|
+
checker,
|
|
122
117
|
classCounter: 0,
|
|
123
|
-
hasReactiveImport: false,
|
|
124
118
|
lastImportEnd: 0,
|
|
125
119
|
ns,
|
|
126
120
|
sourceFile
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
2
|
import type { Bindings } from '../types.js';
|
|
3
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, ns: string) => string;
|
|
3
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, ns: string, checker?: ts.TypeChecker) => string;
|
|
4
4
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { ast, code as c } from '@esportsplus/typescript/compiler';
|
|
2
|
+
import { ast, code as c, imports } from '@esportsplus/typescript/compiler';
|
|
3
3
|
import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '../constants.js';
|
|
4
4
|
const COMPOUND_OPERATORS = new Map([
|
|
5
5
|
[ts.SyntaxKind.AmpersandAmpersandEqualsToken, '&&'],
|
|
@@ -58,15 +58,22 @@ function isInScope(reference, binding) {
|
|
|
58
58
|
}
|
|
59
59
|
return false;
|
|
60
60
|
}
|
|
61
|
-
function
|
|
61
|
+
function isReactiveCall(node, checker) {
|
|
62
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (node.expression.text !== COMPILER_ENTRYPOINT) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return imports.isFromPackage(node.expression, PACKAGE, checker);
|
|
69
|
+
}
|
|
70
|
+
function isReactiveReassignment(node, checker) {
|
|
62
71
|
let parent = node.parent;
|
|
63
72
|
if (ts.isBinaryExpression(parent) &&
|
|
64
73
|
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
65
74
|
parent.right === node &&
|
|
66
|
-
ts.isCallExpression(node)
|
|
67
|
-
|
|
68
|
-
node.expression.text === COMPILER_ENTRYPOINT) {
|
|
69
|
-
return true;
|
|
75
|
+
ts.isCallExpression(node)) {
|
|
76
|
+
return isReactiveCall(node, checker);
|
|
70
77
|
}
|
|
71
78
|
return false;
|
|
72
79
|
}
|
|
@@ -90,24 +97,9 @@ function isWriteContext(node) {
|
|
|
90
97
|
return false;
|
|
91
98
|
}
|
|
92
99
|
function visit(ctx, node) {
|
|
93
|
-
if (ts.
|
|
94
|
-
|
|
95
|
-
node.
|
|
96
|
-
let clause = node.importClause;
|
|
97
|
-
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
98
|
-
for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
|
|
99
|
-
if (clause.namedBindings.elements[i].name.text === COMPILER_ENTRYPOINT) {
|
|
100
|
-
ctx.hasReactiveImport = true;
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (ctx.hasReactiveImport &&
|
|
107
|
-
ts.isCallExpression(node) &&
|
|
108
|
-
ts.isIdentifier(node.expression) &&
|
|
109
|
-
node.expression.text === COMPILER_ENTRYPOINT &&
|
|
110
|
-
node.arguments.length > 0) {
|
|
100
|
+
if (ts.isCallExpression(node) &&
|
|
101
|
+
node.arguments.length > 0 &&
|
|
102
|
+
isReactiveCall(node, ctx.checker)) {
|
|
111
103
|
let arg = node.arguments[0], classification = COMPILER_TYPES.Signal;
|
|
112
104
|
if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
|
|
113
105
|
classification = COMPILER_TYPES.Computed;
|
|
@@ -170,7 +162,7 @@ function visit(ctx, node) {
|
|
|
170
162
|
}
|
|
171
163
|
let binding = findBinding(ctx.scopedBindings, node.text, node), name = node.text;
|
|
172
164
|
if (binding && node.parent) {
|
|
173
|
-
if (!isReactiveReassignment(node.parent) &&
|
|
165
|
+
if (!isReactiveReassignment(node.parent, ctx.checker) &&
|
|
174
166
|
!(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)) {
|
|
175
167
|
let writeCtx = isWriteContext(node);
|
|
176
168
|
if (writeCtx) {
|
|
@@ -247,11 +239,11 @@ function visitArg(ctx, node) {
|
|
|
247
239
|
}
|
|
248
240
|
ts.forEachChild(node, n => visitArg(ctx, n));
|
|
249
241
|
}
|
|
250
|
-
export default (sourceFile, bindings, ns) => {
|
|
242
|
+
export default (sourceFile, bindings, ns, checker) => {
|
|
251
243
|
let code = sourceFile.getFullText(), ctx = {
|
|
252
244
|
bindings,
|
|
245
|
+
checker,
|
|
253
246
|
computedArgRanges: [],
|
|
254
|
-
hasReactiveImport: false,
|
|
255
247
|
ns,
|
|
256
248
|
replacements: [],
|
|
257
249
|
scopedBindings: [],
|
package/package.json
CHANGED
|
@@ -4,23 +4,22 @@
|
|
|
4
4
|
"@esportsplus/utilities": "^0.27.2"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"@esportsplus/typescript": "^0.
|
|
7
|
+
"@esportsplus/typescript": "^0.22.0",
|
|
8
8
|
"@types/node": "^25.0.3",
|
|
9
9
|
"vite": "^7.3.0"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"types": "./build/index.d.ts",
|
|
14
|
+
"default": "./build/index.js"
|
|
15
15
|
},
|
|
16
16
|
"./compiler/tsc": {
|
|
17
17
|
"types": "./build/compiler/plugins/tsc.d.ts",
|
|
18
|
-
"
|
|
19
|
-
"require": "./build/compiler/plugins/tsc.js"
|
|
18
|
+
"default": "./build/compiler/plugins/tsc.js"
|
|
20
19
|
},
|
|
21
20
|
"./compiler/vite": {
|
|
22
21
|
"types": "./build/compiler/plugins/vite.d.ts",
|
|
23
|
-
"
|
|
22
|
+
"default": "./build/compiler/plugins/vite.js"
|
|
24
23
|
}
|
|
25
24
|
},
|
|
26
25
|
"main": "build/index.js",
|
|
@@ -32,7 +31,7 @@
|
|
|
32
31
|
},
|
|
33
32
|
"type": "module",
|
|
34
33
|
"types": "build/index.d.ts",
|
|
35
|
-
"version": "0.
|
|
34
|
+
"version": "0.27.0",
|
|
36
35
|
"scripts": {
|
|
37
36
|
"build": "tsc",
|
|
38
37
|
"build:test": "pnpm build && vite build --config test/vite.config.ts",
|
package/src/compiler/array.ts
CHANGED
|
@@ -81,7 +81,7 @@ function visit(ctx: { bindings: Bindings, replacements: Replacement[], sourceFil
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
export default (sourceFile: ts.SourceFile, bindings: Bindings, _ns: string): string => {
|
|
84
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, _ns: string, _checker?: ts.TypeChecker): string => {
|
|
85
85
|
let code = sourceFile.getFullText(),
|
|
86
86
|
ctx = {
|
|
87
87
|
bindings,
|
package/src/compiler/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { code as c } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REGEX, COMPILER_NAMESPACE } from '~/constants';
|
|
2
|
+
import { code as c, imports } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import { COMPILER_ENTRYPOINT, COMPILER_ENTRYPOINT_REGEX, COMPILER_NAMESPACE, PACKAGE } from '~/constants';
|
|
4
4
|
import type { Bindings, TransformResult } from '~/types';
|
|
5
5
|
import array from './array';
|
|
6
6
|
import object from './object';
|
|
@@ -10,68 +10,63 @@ import primitives from './primitives';
|
|
|
10
10
|
let transforms = [object, array, primitives];
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
13
|
+
function hasReactiveImport(sourceFile: ts.SourceFile): boolean {
|
|
14
|
+
let found = imports.find(sourceFile, PACKAGE);
|
|
17
15
|
|
|
18
|
-
let
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
visit(ctx, ts.createSourceFile('detect.ts', code, ts.ScriptTarget.Latest, false));
|
|
16
|
+
for (let i = 0, n = found.length; i < n; i++) {
|
|
17
|
+
if (found[i].specifiers.has(COMPILER_ENTRYPOINT)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
24
21
|
|
|
25
|
-
return
|
|
22
|
+
return false;
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
function
|
|
29
|
-
if (
|
|
30
|
-
return;
|
|
25
|
+
function hasReactiveUsage(code: string): boolean {
|
|
26
|
+
if (!c.contains(code, { regex: COMPILER_ENTRYPOINT_REGEX })) {
|
|
27
|
+
return false;
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
node.importClause?.namedBindings &&
|
|
36
|
-
ts.isNamedImports(node.importClause.namedBindings)
|
|
37
|
-
) {
|
|
38
|
-
let elements = node.importClause.namedBindings.elements;
|
|
30
|
+
let sourceFile = ts.createSourceFile('detect.ts', code, ts.ScriptTarget.Latest, false),
|
|
31
|
+
used = false;
|
|
39
32
|
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
function visit(node: ts.Node): void {
|
|
34
|
+
if (used) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
if (
|
|
39
|
+
ts.isCallExpression(node) &&
|
|
40
|
+
ts.isIdentifier(node.expression) &&
|
|
41
|
+
node.expression.text === COMPILER_ENTRYPOINT
|
|
42
|
+
) {
|
|
43
|
+
used = true;
|
|
44
|
+
return;
|
|
47
45
|
}
|
|
48
|
-
}
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
ts.isCallExpression(node) &&
|
|
52
|
-
ts.isIdentifier(node.expression) &&
|
|
53
|
-
node.expression.text === COMPILER_ENTRYPOINT
|
|
54
|
-
) {
|
|
55
|
-
ctx.used = true;
|
|
47
|
+
ts.forEachChild(node, visit);
|
|
56
48
|
}
|
|
57
49
|
|
|
58
|
-
|
|
50
|
+
visit(sourceFile);
|
|
51
|
+
|
|
52
|
+
return used;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
|
|
62
|
-
const transform = (sourceFile: ts.SourceFile): TransformResult => {
|
|
56
|
+
const transform = (sourceFile: ts.SourceFile, program: ts.Program): TransformResult => {
|
|
63
57
|
let bindings: Bindings = new Map(),
|
|
64
58
|
changed = false,
|
|
59
|
+
checker = program.getTypeChecker(),
|
|
65
60
|
code = sourceFile.getFullText(),
|
|
66
61
|
current = sourceFile,
|
|
67
62
|
result: string;
|
|
68
63
|
|
|
69
|
-
if (!
|
|
64
|
+
if (!hasReactiveImport(sourceFile) || !hasReactiveUsage(code)) {
|
|
70
65
|
return { changed: false, code, sourceFile };
|
|
71
66
|
}
|
|
72
67
|
|
|
73
68
|
for (let i = 0, n = transforms.length; i < n; i++) {
|
|
74
|
-
result = transforms[i](current, bindings, COMPILER_NAMESPACE);
|
|
69
|
+
result = transforms[i](current, bindings, COMPILER_NAMESPACE, checker);
|
|
75
70
|
|
|
76
71
|
if (result !== code) {
|
|
77
72
|
current = ts.createSourceFile(sourceFile.fileName, result, sourceFile.languageVersion, true);
|
|
@@ -81,6 +76,7 @@ const transform = (sourceFile: ts.SourceFile): TransformResult => {
|
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
if (changed) {
|
|
79
|
+
code = imports.modify(code, current, PACKAGE, { remove: [COMPILER_ENTRYPOINT] });
|
|
84
80
|
code = `import * as ${COMPILER_NAMESPACE} from '@esportsplus/reactivity';\n` + code;
|
|
85
81
|
sourceFile = ts.createSourceFile(sourceFile.fileName, code, sourceFile.languageVersion, true);
|
|
86
82
|
}
|
package/src/compiler/object.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { code as c, type Replacement } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import { COMPILER_TYPES, PACKAGE } from '~/constants';
|
|
2
|
+
import { code as c, imports, type Replacement } from '@esportsplus/typescript/compiler';
|
|
3
|
+
import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '~/constants';
|
|
4
4
|
import type { Bindings } from '~/types';
|
|
5
5
|
|
|
6
6
|
|
|
@@ -21,8 +21,8 @@ interface ReactiveObjectCall {
|
|
|
21
21
|
interface TransformContext {
|
|
22
22
|
bindings: Bindings;
|
|
23
23
|
calls: ReactiveObjectCall[];
|
|
24
|
+
checker?: ts.TypeChecker;
|
|
24
25
|
classCounter: number;
|
|
25
|
-
hasReactiveImport: boolean;
|
|
26
26
|
lastImportEnd: number;
|
|
27
27
|
ns: string;
|
|
28
28
|
sourceFile: ts.SourceFile;
|
|
@@ -109,34 +109,26 @@ function buildClassCode(className: string, properties: AnalyzedProperty[], ns: s
|
|
|
109
109
|
`;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
function
|
|
113
|
-
if (ts.
|
|
114
|
-
|
|
112
|
+
function isReactiveCall(node: ts.CallExpression, checker?: ts.TypeChecker): boolean {
|
|
113
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
) {
|
|
120
|
-
let clause = node.importClause;
|
|
117
|
+
if (node.expression.text !== COMPILER_ENTRYPOINT) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
return imports.isFromPackage(node.expression, PACKAGE, checker);
|
|
122
|
+
}
|
|
124
123
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
124
|
+
function visit(ctx: TransformContext, node: ts.Node): void {
|
|
125
|
+
if (ts.isImportDeclaration(node)) {
|
|
126
|
+
ctx.lastImportEnd = node.end;
|
|
133
127
|
}
|
|
134
128
|
|
|
135
129
|
if (
|
|
136
|
-
ctx.hasReactiveImport &&
|
|
137
130
|
ts.isCallExpression(node) &&
|
|
138
|
-
|
|
139
|
-
node.expression.text === 'reactive'
|
|
131
|
+
isReactiveCall(node, ctx.checker)
|
|
140
132
|
) {
|
|
141
133
|
let arg = node.arguments[0];
|
|
142
134
|
|
|
@@ -186,13 +178,13 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
186
178
|
}
|
|
187
179
|
|
|
188
180
|
|
|
189
|
-
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
|
|
181
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string, checker?: ts.TypeChecker): string => {
|
|
190
182
|
let code = sourceFile.getFullText(),
|
|
191
183
|
ctx: TransformContext = {
|
|
192
184
|
bindings,
|
|
193
185
|
calls: [],
|
|
186
|
+
checker,
|
|
194
187
|
classCounter: 0,
|
|
195
|
-
hasReactiveImport: false,
|
|
196
188
|
lastImportEnd: 0,
|
|
197
189
|
ns,
|
|
198
190
|
sourceFile
|
|
@@ -224,4 +216,5 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): stri
|
|
|
224
216
|
}
|
|
225
217
|
|
|
226
218
|
return c.replace(code, replacements);
|
|
227
|
-
};
|
|
219
|
+
};
|
|
220
|
+
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ts } from '@esportsplus/typescript';
|
|
2
|
-
import { ast, code as c, type Range, type Replacement } from '@esportsplus/typescript/compiler';
|
|
3
|
-
import type { Bindings } from '~/types';
|
|
2
|
+
import { ast, code as c, imports, type Range, type Replacement } from '@esportsplus/typescript/compiler';
|
|
4
3
|
import { COMPILER_ENTRYPOINT, COMPILER_TYPES, PACKAGE } from '~/constants';
|
|
4
|
+
import type { Bindings } from '~/types';
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
interface ArgContext {
|
|
@@ -20,8 +20,8 @@ interface ScopeBinding {
|
|
|
20
20
|
|
|
21
21
|
interface TransformContext {
|
|
22
22
|
bindings: Bindings;
|
|
23
|
+
checker?: ts.TypeChecker;
|
|
23
24
|
computedArgRanges: Range[];
|
|
24
|
-
hasReactiveImport: boolean;
|
|
25
25
|
ns: string;
|
|
26
26
|
replacements: Replacement[];
|
|
27
27
|
scopedBindings: ScopeBinding[];
|
|
@@ -104,18 +104,28 @@ function isInScope(reference: ts.Node, binding: ScopeBinding): boolean {
|
|
|
104
104
|
return false;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
function
|
|
107
|
+
function isReactiveCall(node: ts.CallExpression, checker?: ts.TypeChecker): boolean {
|
|
108
|
+
if (!ts.isIdentifier(node.expression)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (node.expression.text !== COMPILER_ENTRYPOINT) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return imports.isFromPackage(node.expression, PACKAGE, checker);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function isReactiveReassignment(node: ts.Node, checker?: ts.TypeChecker): boolean {
|
|
108
120
|
let parent = node.parent;
|
|
109
121
|
|
|
110
122
|
if (
|
|
111
123
|
ts.isBinaryExpression(parent) &&
|
|
112
124
|
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
113
125
|
parent.right === node &&
|
|
114
|
-
ts.isCallExpression(node)
|
|
115
|
-
ts.isIdentifier((node as ts.CallExpression).expression) &&
|
|
116
|
-
((node as ts.CallExpression).expression as ts.Identifier).text === COMPILER_ENTRYPOINT
|
|
126
|
+
ts.isCallExpression(node)
|
|
117
127
|
) {
|
|
118
|
-
return
|
|
128
|
+
return isReactiveCall(node as ts.CallExpression, checker);
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
return false;
|
|
@@ -149,28 +159,9 @@ function isWriteContext(node: ts.Identifier): 'simple' | 'compound' | 'increment
|
|
|
149
159
|
|
|
150
160
|
function visit(ctx: TransformContext, node: ts.Node): void {
|
|
151
161
|
if (
|
|
152
|
-
ts.isImportDeclaration(node) &&
|
|
153
|
-
ts.isStringLiteral(node.moduleSpecifier) &&
|
|
154
|
-
node.moduleSpecifier.text.includes(PACKAGE)
|
|
155
|
-
) {
|
|
156
|
-
let clause = node.importClause;
|
|
157
|
-
|
|
158
|
-
if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
159
|
-
for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
|
|
160
|
-
if (clause.namedBindings.elements[i].name.text === COMPILER_ENTRYPOINT) {
|
|
161
|
-
ctx.hasReactiveImport = true;
|
|
162
|
-
break;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (
|
|
169
|
-
ctx.hasReactiveImport &&
|
|
170
162
|
ts.isCallExpression(node) &&
|
|
171
|
-
|
|
172
|
-
node.
|
|
173
|
-
node.arguments.length > 0
|
|
163
|
+
node.arguments.length > 0 &&
|
|
164
|
+
isReactiveCall(node, ctx.checker)
|
|
174
165
|
) {
|
|
175
166
|
let arg = node.arguments[0],
|
|
176
167
|
classification: COMPILER_TYPES | null = COMPILER_TYPES.Signal;
|
|
@@ -237,6 +228,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
237
228
|
}
|
|
238
229
|
}
|
|
239
230
|
|
|
231
|
+
|
|
240
232
|
if (ts.isIdentifier(node) && node.parent && !isInDeclarationInit(node.parent)) {
|
|
241
233
|
if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
|
|
242
234
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
@@ -255,7 +247,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
255
247
|
|
|
256
248
|
if (binding && node.parent) {
|
|
257
249
|
if (
|
|
258
|
-
!isReactiveReassignment(node.parent) &&
|
|
250
|
+
!isReactiveReassignment(node.parent, ctx.checker) &&
|
|
259
251
|
!(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)
|
|
260
252
|
) {
|
|
261
253
|
let writeCtx = isWriteContext(node);
|
|
@@ -272,7 +264,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
272
264
|
});
|
|
273
265
|
}
|
|
274
266
|
else if (writeCtx === 'compound' && ts.isBinaryExpression(parent)) {
|
|
275
|
-
let op = COMPOUND_OPERATORS.get(parent.operatorToken.kind) ?? '+'
|
|
267
|
+
let op = COMPOUND_OPERATORS.get(parent.operatorToken.kind) ?? '+'
|
|
276
268
|
|
|
277
269
|
ctx.replacements.push({
|
|
278
270
|
end: parent.end,
|
|
@@ -324,6 +316,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
324
316
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
325
317
|
}
|
|
326
318
|
|
|
319
|
+
|
|
327
320
|
function visitArg(ctx: ArgContext, node: ts.Node): void {
|
|
328
321
|
if (ts.isIdentifier(node) && node.parent) {
|
|
329
322
|
if (
|
|
@@ -347,12 +340,12 @@ function visitArg(ctx: ArgContext, node: ts.Node): void {
|
|
|
347
340
|
}
|
|
348
341
|
|
|
349
342
|
|
|
350
|
-
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
|
|
343
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string, checker?: ts.TypeChecker): string => {
|
|
351
344
|
let code = sourceFile.getFullText(),
|
|
352
345
|
ctx: TransformContext = {
|
|
353
346
|
bindings,
|
|
347
|
+
checker,
|
|
354
348
|
computedArgRanges: [],
|
|
355
|
-
hasReactiveImport: false,
|
|
356
349
|
ns,
|
|
357
350
|
replacements: [],
|
|
358
351
|
scopedBindings: [],
|
|
@@ -367,4 +360,5 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): stri
|
|
|
367
360
|
}
|
|
368
361
|
|
|
369
362
|
return c.replace(code, ctx.replacements);
|
|
370
|
-
};
|
|
363
|
+
};
|
|
364
|
+
|