@esportsplus/reactivity 0.29.0 → 0.29.2
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/accordion.js +45 -0
- package/accordion.ts +51 -0
- package/build/compiler/array.d.ts +1 -1
- package/build/compiler/array.js +2 -3
- package/build/compiler/index.js +22 -45
- package/build/compiler/object.d.ts +1 -1
- package/build/compiler/object.js +1 -2
- package/build/compiler/primitives.d.ts +1 -1
- package/build/compiler/primitives.js +3 -4
- package/package.json +2 -2
- package/src/compiler/array.ts +4 -13
- package/src/compiler/index.ts +37 -59
- package/src/compiler/object.ts +4 -6
- package/src/compiler/primitives.ts +3 -10
package/accordion.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as reactivity_1ihsmodgjbfar0 from '@esportsplus/reactivity';
|
|
2
|
+
import { omit } from '@esportsplus/utilities';
|
|
3
|
+
import template from '../../components/template/index.js';
|
|
4
|
+
import './scss/index.scss';
|
|
5
|
+
class ReactiveObject_xy8kflxy8kfl2 extends reactivity_1ihsmodgjbfar0.ReactiveObject {
|
|
6
|
+
#active = this[reactivity_1ihsmodgjbfar0.SIGNAL](0);
|
|
7
|
+
constructor() {
|
|
8
|
+
super(null);
|
|
9
|
+
}
|
|
10
|
+
get active() {
|
|
11
|
+
return reactivity_1ihsmodgjbfar0.read(this.#active);
|
|
12
|
+
}
|
|
13
|
+
set active(_v0) {
|
|
14
|
+
reactivity_1ihsmodgjbfar0.write(this.#active, _v0);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const OMIT = ['state'];
|
|
18
|
+
let key = Symbol();
|
|
19
|
+
export default template.factory(function (attributes, content) {
|
|
20
|
+
let ref, state = attributes.state || reactivity_1ihsmodgjbfar0.reactive({
|
|
21
|
+
active: 0
|
|
22
|
+
}), n, html;
|
|
23
|
+
`
|
|
24
|
+
<div
|
|
25
|
+
${omit(attributes, OMIT)}
|
|
26
|
+
${{
|
|
27
|
+
class: () => {
|
|
28
|
+
return state.active && '--active';
|
|
29
|
+
},
|
|
30
|
+
onrender: (element) => {
|
|
31
|
+
(ref = element)[key] = state;
|
|
32
|
+
},
|
|
33
|
+
style: () => {
|
|
34
|
+
let parent = ref.closest('accordion');
|
|
35
|
+
if (parent && key in parent) {
|
|
36
|
+
parent[key].active = (+parent[key].active) + 1;
|
|
37
|
+
}
|
|
38
|
+
return state.active && `--max-height: ${ref.scrollHeight}`;
|
|
39
|
+
}
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
${content}
|
|
43
|
+
</div>
|
|
44
|
+
`;
|
|
45
|
+
});
|
package/accordion.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { reactive } from '@esportsplus/reactivity';
|
|
2
|
+
import { html, Attributes } from '@esportsplus/template';
|
|
3
|
+
import { omit } from '@esportsplus/utilities';
|
|
4
|
+
import template from '~/components/template';
|
|
5
|
+
import './scss/index.scss';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
type A = Attributes & { state?: { active: boolean | number } };
|
|
9
|
+
|
|
10
|
+
type Accordion = HTMLElement & { [key: symbol]: { active: boolean | number } };
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const OMIT = ['state'];
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
let key = Symbol();
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export default template.factory(
|
|
20
|
+
function(attributes: A, content) {
|
|
21
|
+
let ref: Accordion,
|
|
22
|
+
state = attributes.state || reactive({
|
|
23
|
+
active: 0
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return html`
|
|
27
|
+
<div
|
|
28
|
+
${omit(attributes, OMIT)}
|
|
29
|
+
${{
|
|
30
|
+
class: () => {
|
|
31
|
+
return state.active && '--active';
|
|
32
|
+
},
|
|
33
|
+
onrender: (element) => {
|
|
34
|
+
( ref = element as Accordion )[key] = state;
|
|
35
|
+
},
|
|
36
|
+
style: () => {
|
|
37
|
+
let parent = ref.closest<Accordion>('accordion');
|
|
38
|
+
|
|
39
|
+
if (parent && key in parent) {
|
|
40
|
+
parent[key].active = (+parent[key].active) + 1;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return state.active && `--max-height: ${ref.scrollHeight}`;
|
|
44
|
+
}
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
${content}
|
|
48
|
+
</div>
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
3
|
import type { Bindings } from '../types.js';
|
|
4
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings
|
|
4
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings) => ReplacementIntent[];
|
|
5
5
|
export default _default;
|
package/build/compiler/array.js
CHANGED
|
@@ -45,7 +45,7 @@ function visit(ctx, node) {
|
|
|
45
45
|
ctx.bindings.set(node.name.text, COMPILER_TYPES.Array);
|
|
46
46
|
}
|
|
47
47
|
if (ts.isPropertyAccessExpression(node.initializer)) {
|
|
48
|
-
let path = ast.
|
|
48
|
+
let path = ast.getPropertyPath(node.initializer);
|
|
49
49
|
if (path && ctx.bindings.get(path) === COMPILER_TYPES.Array) {
|
|
50
50
|
ctx.bindings.set(node.name.text, COMPILER_TYPES.Array);
|
|
51
51
|
}
|
|
@@ -92,10 +92,9 @@ function visit(ctx, node) {
|
|
|
92
92
|
}
|
|
93
93
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
94
94
|
}
|
|
95
|
-
export default (sourceFile, bindings
|
|
95
|
+
export default (sourceFile, bindings) => {
|
|
96
96
|
let ctx = {
|
|
97
97
|
bindings,
|
|
98
|
-
checker,
|
|
99
98
|
replacements: [],
|
|
100
99
|
sourceFile
|
|
101
100
|
};
|
package/build/compiler/index.js
CHANGED
|
@@ -4,30 +4,10 @@ import { COMPILER_ENTRYPOINT, COMPILER_NAMESPACE, PACKAGE } from '../constants.j
|
|
|
4
4
|
import array from './array.js';
|
|
5
5
|
import object from './object.js';
|
|
6
6
|
import primitives from './primitives.js';
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
let symbol = checker.getSymbolAtLocation(node);
|
|
12
|
-
if (!symbol) {
|
|
13
|
-
return false;
|
|
14
|
-
}
|
|
15
|
-
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
16
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
17
|
-
}
|
|
18
|
-
let declarations = symbol.getDeclarations();
|
|
19
|
-
if (!declarations || declarations.length === 0) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
for (let i = 0, n = declarations.length; i < n; i++) {
|
|
23
|
-
let decl = declarations[i], sourceFile = decl.getSourceFile();
|
|
24
|
-
if (sourceFile.fileName.includes(PACKAGE) || sourceFile.fileName.includes('reactivity')) {
|
|
25
|
-
if (symbol.name === COMPILER_ENTRYPOINT) {
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return false;
|
|
7
|
+
function findRemainingCalls(checker, sourceFile, transformedNodes) {
|
|
8
|
+
let ctx = { checker, replacements: [], sourceFile, transformedNodes };
|
|
9
|
+
visit(ctx, sourceFile);
|
|
10
|
+
return ctx.replacements;
|
|
31
11
|
}
|
|
32
12
|
function isReactiveCallExpression(checker, node) {
|
|
33
13
|
if (!ts.isCallExpression(node)) {
|
|
@@ -39,39 +19,36 @@ function isReactiveCallExpression(checker, node) {
|
|
|
39
19
|
return true;
|
|
40
20
|
}
|
|
41
21
|
if (checker) {
|
|
42
|
-
return
|
|
22
|
+
return imports.inPackage(checker, expr, PACKAGE, COMPILER_ENTRYPOINT);
|
|
43
23
|
}
|
|
44
24
|
}
|
|
45
25
|
if (ts.isPropertyAccessExpression(expr) && expr.name.text === COMPILER_ENTRYPOINT && checker) {
|
|
46
|
-
return
|
|
26
|
+
return imports.inPackage(checker, expr, PACKAGE);
|
|
47
27
|
}
|
|
48
28
|
return false;
|
|
49
29
|
}
|
|
30
|
+
function visit(ctx, node) {
|
|
31
|
+
if (isReactiveCallExpression(ctx.checker, node) && !ctx.transformedNodes.has(node) && !ctx.transformedNodes.has(node.expression)) {
|
|
32
|
+
ctx.replacements.push({
|
|
33
|
+
generate: () => `${COMPILER_NAMESPACE}.reactive(${node.arguments.map(a => a.getText(ctx.sourceFile)).join(', ')})`,
|
|
34
|
+
node
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
ts.forEachChild(node, n => visit(ctx, n));
|
|
38
|
+
}
|
|
50
39
|
const plugin = {
|
|
51
40
|
patterns: ['reactive(', 'reactive<'],
|
|
52
41
|
transform: (ctx) => {
|
|
53
|
-
if (!
|
|
42
|
+
if (!imports.find(ctx.sourceFile, PACKAGE).some(i => i.specifiers.has(COMPILER_ENTRYPOINT))) {
|
|
54
43
|
return {};
|
|
55
44
|
}
|
|
56
|
-
let bindings = new Map(), importsIntent = [],
|
|
57
|
-
replacements.push(...primitives(ctx.sourceFile, bindings,
|
|
58
|
-
let objectResult = object(ctx.sourceFile, bindings
|
|
45
|
+
let bindings = new Map(), importsIntent = [], isReactive = (node) => isReactiveCallExpression(ctx.checker, node), prepend = [], replacements = [];
|
|
46
|
+
replacements.push(...primitives(ctx.sourceFile, bindings, isReactive));
|
|
47
|
+
let objectResult = object(ctx.sourceFile, bindings);
|
|
59
48
|
prepend.push(...objectResult.prepend);
|
|
60
|
-
replacements.push(...objectResult.replacements
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (isReactiveCall(node)) {
|
|
64
|
-
let call = node;
|
|
65
|
-
if (!transformedNodes.has(call) && !transformedNodes.has(call.expression)) {
|
|
66
|
-
replacements.push({
|
|
67
|
-
generate: () => `${COMPILER_NAMESPACE}.reactive(${call.arguments.map(a => a.getText(ctx.sourceFile)).join(', ')})`,
|
|
68
|
-
node: call
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
ts.forEachChild(node, findRemainingReactiveCalls);
|
|
73
|
-
}
|
|
74
|
-
findRemainingReactiveCalls(ctx.sourceFile);
|
|
49
|
+
replacements.push(...objectResult.replacements);
|
|
50
|
+
replacements.push(...array(ctx.sourceFile, bindings));
|
|
51
|
+
replacements.push(...findRemainingCalls(ctx.checker, ctx.sourceFile, new Set(replacements.map(r => r.node))));
|
|
75
52
|
if (replacements.length > 0 || prepend.length > 0) {
|
|
76
53
|
importsIntent.push({
|
|
77
54
|
namespace: COMPILER_NAMESPACE,
|
|
@@ -5,5 +5,5 @@ type ObjectTransformResult = {
|
|
|
5
5
|
prepend: string[];
|
|
6
6
|
replacements: ReplacementIntent[];
|
|
7
7
|
};
|
|
8
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings
|
|
8
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings) => ObjectTransformResult;
|
|
9
9
|
export default _default;
|
package/build/compiler/object.js
CHANGED
|
@@ -145,11 +145,10 @@ function visit(ctx, node) {
|
|
|
145
145
|
}
|
|
146
146
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
147
147
|
}
|
|
148
|
-
export default (sourceFile, bindings
|
|
148
|
+
export default (sourceFile, bindings) => {
|
|
149
149
|
let ctx = {
|
|
150
150
|
bindings,
|
|
151
151
|
calls: [],
|
|
152
|
-
checker,
|
|
153
152
|
sourceFile
|
|
154
153
|
};
|
|
155
154
|
visit(ctx, sourceFile);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReplacementIntent } from '@esportsplus/typescript/compiler';
|
|
2
2
|
import { ts } from '@esportsplus/typescript';
|
|
3
3
|
import type { Bindings } from '../types.js';
|
|
4
|
-
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: (node: ts.Node) => boolean
|
|
4
|
+
declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: (node: ts.Node) => boolean) => ReplacementIntent[];
|
|
5
5
|
export default _default;
|
|
@@ -17,7 +17,7 @@ const COMPOUND_OPERATORS = new Map([
|
|
|
17
17
|
[ts.SyntaxKind.QuestionQuestionEqualsToken, '??'],
|
|
18
18
|
[ts.SyntaxKind.SlashEqualsToken, '/']
|
|
19
19
|
]);
|
|
20
|
-
function
|
|
20
|
+
function inScope(reference, binding) {
|
|
21
21
|
let current = reference;
|
|
22
22
|
while (current) {
|
|
23
23
|
if (current === binding.scope) {
|
|
@@ -89,7 +89,7 @@ function visit(ctx, node) {
|
|
|
89
89
|
let bindings = ctx.scopedBindings, binding, name = node.text;
|
|
90
90
|
for (let i = 0, n = bindings.length; i < n; i++) {
|
|
91
91
|
let b = bindings[i];
|
|
92
|
-
if (b.name === name &&
|
|
92
|
+
if (b.name === name && inScope(node, b)) {
|
|
93
93
|
binding = b;
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -166,10 +166,9 @@ function visit(ctx, node) {
|
|
|
166
166
|
}
|
|
167
167
|
ts.forEachChild(node, n => visit(ctx, n));
|
|
168
168
|
}
|
|
169
|
-
export default (sourceFile, bindings, isReactiveCall
|
|
169
|
+
export default (sourceFile, bindings, isReactiveCall) => {
|
|
170
170
|
let ctx = {
|
|
171
171
|
bindings,
|
|
172
|
-
checker,
|
|
173
172
|
isReactiveCall,
|
|
174
173
|
replacements: [],
|
|
175
174
|
scopedBindings: [],
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"@esportsplus/utilities": "^0.27.2"
|
|
5
5
|
},
|
|
6
6
|
"devDependencies": {
|
|
7
|
-
"@esportsplus/typescript": "^0.
|
|
7
|
+
"@esportsplus/typescript": "^0.26.2",
|
|
8
8
|
"@types/node": "^25.0.3",
|
|
9
9
|
"vite": "^7.3.1"
|
|
10
10
|
},
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"type": "module",
|
|
33
33
|
"types": "build/index.d.ts",
|
|
34
|
-
"version": "0.29.
|
|
34
|
+
"version": "0.29.2",
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc",
|
|
37
37
|
"build:test": "pnpm build && vite build --config test/vite.config.ts",
|
package/src/compiler/array.ts
CHANGED
|
@@ -5,14 +5,6 @@ import { COMPILER_NAMESPACE, COMPILER_TYPES } from '~/constants';
|
|
|
5
5
|
import type { Bindings } from '~/types';
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
interface VisitContext {
|
|
9
|
-
bindings: Bindings;
|
|
10
|
-
checker?: ts.TypeChecker;
|
|
11
|
-
replacements: ReplacementIntent[];
|
|
12
|
-
sourceFile: ts.SourceFile;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
8
|
function getElementTypeText(typeNode: ts.TypeNode, sourceFile: ts.SourceFile): string | null {
|
|
17
9
|
if (ts.isArrayTypeNode(typeNode)) {
|
|
18
10
|
return typeNode.elementType.getText(sourceFile);
|
|
@@ -31,7 +23,7 @@ function getElementTypeText(typeNode: ts.TypeNode, sourceFile: ts.SourceFile): s
|
|
|
31
23
|
return null;
|
|
32
24
|
}
|
|
33
25
|
|
|
34
|
-
function visit(ctx:
|
|
26
|
+
function visit(ctx: { bindings: Bindings, replacements: ReplacementIntent[], sourceFile: ts.SourceFile }, node: ts.Node): void {
|
|
35
27
|
if (
|
|
36
28
|
ts.isCallExpression(node) &&
|
|
37
29
|
ts.isIdentifier(node.expression) &&
|
|
@@ -72,7 +64,7 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
72
64
|
}
|
|
73
65
|
|
|
74
66
|
if (ts.isPropertyAccessExpression(node.initializer)) {
|
|
75
|
-
let path = ast.
|
|
67
|
+
let path = ast.getPropertyPath(node.initializer);
|
|
76
68
|
|
|
77
69
|
if (path && ctx.bindings.get(path) === COMPILER_TYPES.Array) {
|
|
78
70
|
ctx.bindings.set(node.name.text, COMPILER_TYPES.Array);
|
|
@@ -140,10 +132,9 @@ function visit(ctx: VisitContext, node: ts.Node): void {
|
|
|
140
132
|
}
|
|
141
133
|
|
|
142
134
|
|
|
143
|
-
export default (sourceFile: ts.SourceFile, bindings: Bindings
|
|
144
|
-
let ctx
|
|
135
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings): ReplacementIntent[] => {
|
|
136
|
+
let ctx = {
|
|
145
137
|
bindings,
|
|
146
|
-
checker,
|
|
147
138
|
replacements: [],
|
|
148
139
|
sourceFile
|
|
149
140
|
};
|
package/src/compiler/index.ts
CHANGED
|
@@ -8,42 +8,23 @@ import object from './object';
|
|
|
8
8
|
import primitives from './primitives';
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (!symbol) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Follow aliases to original symbol
|
|
23
|
-
if (symbol.flags & ts.SymbolFlags.Alias) {
|
|
24
|
-
symbol = checker.getAliasedSymbol(symbol);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
let declarations = symbol.getDeclarations();
|
|
28
|
-
|
|
29
|
-
if (!declarations || declarations.length === 0) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
11
|
+
type FindRemainingContext = {
|
|
12
|
+
checker: ts.TypeChecker | undefined;
|
|
13
|
+
replacements: ReplacementIntent[];
|
|
14
|
+
sourceFile: ts.SourceFile;
|
|
15
|
+
transformedNodes: Set<ts.Node>;
|
|
16
|
+
};
|
|
32
17
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
18
|
+
function findRemainingCalls(
|
|
19
|
+
checker: ts.TypeChecker | undefined,
|
|
20
|
+
sourceFile: ts.SourceFile,
|
|
21
|
+
transformedNodes: Set<ts.Node>
|
|
22
|
+
): ReplacementIntent[] {
|
|
23
|
+
let ctx: FindRemainingContext = { checker, replacements: [], sourceFile, transformedNodes };
|
|
36
24
|
|
|
37
|
-
|
|
38
|
-
if (sourceFile.fileName.includes(PACKAGE) || sourceFile.fileName.includes('reactivity')) {
|
|
39
|
-
// Verify it's the reactive export
|
|
40
|
-
if (symbol.name === COMPILER_ENTRYPOINT) {
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
25
|
+
visit(ctx, sourceFile);
|
|
45
26
|
|
|
46
|
-
return
|
|
27
|
+
return ctx.replacements;
|
|
47
28
|
}
|
|
48
29
|
|
|
49
30
|
function isReactiveCallExpression(checker: ts.TypeChecker | undefined, node: ts.Node): node is ts.CallExpression {
|
|
@@ -62,62 +43,59 @@ function isReactiveCallExpression(checker: ts.TypeChecker | undefined, node: ts.
|
|
|
62
43
|
|
|
63
44
|
// Use checker to resolve aliases
|
|
64
45
|
if (checker) {
|
|
65
|
-
return
|
|
46
|
+
return imports.inPackage(checker, expr, PACKAGE, COMPILER_ENTRYPOINT);
|
|
66
47
|
}
|
|
67
48
|
}
|
|
68
49
|
|
|
69
50
|
// Property access: ns.reactive(...)
|
|
70
51
|
if (ts.isPropertyAccessExpression(expr) && expr.name.text === COMPILER_ENTRYPOINT && checker) {
|
|
71
|
-
return
|
|
52
|
+
return imports.inPackage(checker, expr, PACKAGE);
|
|
72
53
|
}
|
|
73
54
|
|
|
74
55
|
return false;
|
|
75
56
|
}
|
|
76
57
|
|
|
58
|
+
function visit(ctx: FindRemainingContext, node: ts.Node): void {
|
|
59
|
+
// Check if call or its expression has already been transformed
|
|
60
|
+
if (isReactiveCallExpression(ctx.checker, node) && !ctx.transformedNodes.has(node) && !ctx.transformedNodes.has(node.expression)) {
|
|
61
|
+
ctx.replacements.push({
|
|
62
|
+
generate: () => `${COMPILER_NAMESPACE}.reactive(${node.arguments.map(a => a.getText(ctx.sourceFile)).join(', ')})`,
|
|
63
|
+
node
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ts.forEachChild(node, n => visit(ctx, n));
|
|
68
|
+
}
|
|
69
|
+
|
|
77
70
|
|
|
78
71
|
const plugin: Plugin = {
|
|
79
72
|
patterns: ['reactive(', 'reactive<'],
|
|
80
73
|
|
|
81
74
|
transform: (ctx: TransformContext) => {
|
|
82
|
-
if (!
|
|
75
|
+
if (!imports.find(ctx.sourceFile, PACKAGE).some(i => i.specifiers.has(COMPILER_ENTRYPOINT))) {
|
|
83
76
|
return {};
|
|
84
77
|
}
|
|
85
78
|
|
|
86
79
|
let bindings: Bindings = new Map(),
|
|
87
80
|
importsIntent: ImportIntent[] = [],
|
|
88
|
-
|
|
81
|
+
isReactive = (node: ts.Node) => isReactiveCallExpression(ctx.checker, node),
|
|
89
82
|
prepend: string[] = [],
|
|
90
83
|
replacements: ReplacementIntent[] = [];
|
|
91
84
|
|
|
92
85
|
// Run primitives transform first (tracks bindings for signal/computed)
|
|
93
|
-
replacements.push(...primitives(ctx.sourceFile, bindings,
|
|
86
|
+
replacements.push(...primitives(ctx.sourceFile, bindings, isReactive));
|
|
94
87
|
|
|
95
88
|
// Run object transform
|
|
96
|
-
let objectResult = object(ctx.sourceFile, bindings
|
|
89
|
+
let objectResult = object(ctx.sourceFile, bindings);
|
|
97
90
|
|
|
98
91
|
prepend.push(...objectResult.prepend);
|
|
99
|
-
replacements.push(...objectResult.replacements
|
|
92
|
+
replacements.push(...objectResult.replacements);
|
|
100
93
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
function findRemainingReactiveCalls(node: ts.Node): void {
|
|
105
|
-
if (isReactiveCall(node)) {
|
|
106
|
-
let call = node as ts.CallExpression;
|
|
107
|
-
|
|
108
|
-
// Check if call or its expression has already been transformed
|
|
109
|
-
if (!transformedNodes.has(call) && !transformedNodes.has(call.expression)) {
|
|
110
|
-
replacements.push({
|
|
111
|
-
generate: () => `${COMPILER_NAMESPACE}.reactive(${call.arguments.map(a => a.getText(ctx.sourceFile)).join(', ')})`,
|
|
112
|
-
node: call
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
ts.forEachChild(node, findRemainingReactiveCalls);
|
|
118
|
-
}
|
|
94
|
+
// Run array transform separately ( avoid race conditions )
|
|
95
|
+
replacements.push(...array(ctx.sourceFile, bindings));
|
|
119
96
|
|
|
120
|
-
|
|
97
|
+
// Find remaining reactive() calls that weren't transformed and replace with namespace version
|
|
98
|
+
replacements.push(...findRemainingCalls(ctx.checker, ctx.sourceFile, new Set(replacements.map(r => r.node))));
|
|
121
99
|
|
|
122
100
|
// Build import intent
|
|
123
101
|
if (replacements.length > 0 || prepend.length > 0) {
|
package/src/compiler/object.ts
CHANGED
|
@@ -22,7 +22,6 @@ interface ReactiveObjectCall {
|
|
|
22
22
|
interface VisitContext {
|
|
23
23
|
bindings: Bindings;
|
|
24
24
|
calls: ReactiveObjectCall[];
|
|
25
|
-
checker?: ts.TypeChecker;
|
|
26
25
|
sourceFile: ts.SourceFile;
|
|
27
26
|
}
|
|
28
27
|
|
|
@@ -221,11 +220,10 @@ type ObjectTransformResult = {
|
|
|
221
220
|
};
|
|
222
221
|
|
|
223
222
|
|
|
224
|
-
export default (sourceFile: ts.SourceFile, bindings: Bindings
|
|
223
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings): ObjectTransformResult => {
|
|
225
224
|
let ctx: VisitContext = {
|
|
226
225
|
bindings,
|
|
227
226
|
calls: [],
|
|
228
|
-
checker,
|
|
229
227
|
sourceFile
|
|
230
228
|
};
|
|
231
229
|
|
|
@@ -245,9 +243,9 @@ export default (sourceFile: ts.SourceFile, bindings: Bindings, checker?: ts.Type
|
|
|
245
243
|
replacements.push({
|
|
246
244
|
generate: () => ` new ${call.className}(${
|
|
247
245
|
call.properties
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
.filter(({ isStatic, type }) => !isStatic || type === COMPILER_TYPES.Computed)
|
|
247
|
+
.map(p => p.valueText)
|
|
248
|
+
.join(', ')
|
|
251
249
|
})`,
|
|
252
250
|
node: call.node,
|
|
253
251
|
});
|
|
@@ -12,7 +12,6 @@ interface ScopeBinding {
|
|
|
12
12
|
|
|
13
13
|
interface TransformContext {
|
|
14
14
|
bindings: Bindings;
|
|
15
|
-
checker?: ts.TypeChecker;
|
|
16
15
|
isReactiveCall: (node: ts.Node) => boolean;
|
|
17
16
|
replacements: ReplacementIntent[];
|
|
18
17
|
scopedBindings: ScopeBinding[];
|
|
@@ -40,7 +39,7 @@ const COMPOUND_OPERATORS = new Map<ts.SyntaxKind, string>([
|
|
|
40
39
|
]);
|
|
41
40
|
|
|
42
41
|
|
|
43
|
-
function
|
|
42
|
+
function inScope(reference: ts.Node, binding: ScopeBinding): boolean {
|
|
44
43
|
let current: ts.Node | undefined = reference;
|
|
45
44
|
|
|
46
45
|
while (current) {
|
|
@@ -143,7 +142,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
143
142
|
for (let i = 0, n = bindings.length; i < n; i++) {
|
|
144
143
|
let b = bindings[i];
|
|
145
144
|
|
|
146
|
-
if (b.name === name &&
|
|
145
|
+
if (b.name === name && inScope(node, b)) {
|
|
147
146
|
binding = b;
|
|
148
147
|
}
|
|
149
148
|
}
|
|
@@ -239,15 +238,9 @@ function visit(ctx: TransformContext, node: ts.Node): void {
|
|
|
239
238
|
}
|
|
240
239
|
|
|
241
240
|
|
|
242
|
-
export default (
|
|
243
|
-
sourceFile: ts.SourceFile,
|
|
244
|
-
bindings: Bindings,
|
|
245
|
-
isReactiveCall: (node: ts.Node) => boolean,
|
|
246
|
-
checker?: ts.TypeChecker
|
|
247
|
-
) => {
|
|
241
|
+
export default (sourceFile: ts.SourceFile, bindings: Bindings, isReactiveCall: (node: ts.Node) => boolean) => {
|
|
248
242
|
let ctx: TransformContext = {
|
|
249
243
|
bindings,
|
|
250
|
-
checker,
|
|
251
244
|
isReactiveCall,
|
|
252
245
|
replacements: [],
|
|
253
246
|
scopedBindings: [],
|