@esportsplus/reactivity 0.25.2 → 0.25.4

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.
Files changed (41) hide show
  1. package/build/constants.d.ts +8 -1
  2. package/build/constants.js +8 -1
  3. package/build/index.d.ts +2 -2
  4. package/build/index.js +2 -2
  5. package/build/reactive/array.js +18 -27
  6. package/build/reactive/index.d.ts +14 -15
  7. package/build/reactive/index.js +2 -2
  8. package/build/system.d.ts +2 -2
  9. package/build/system.js +10 -10
  10. package/build/transformer/detector.d.ts +2 -2
  11. package/build/transformer/detector.js +14 -14
  12. package/build/transformer/index.d.ts +3 -7
  13. package/build/transformer/index.js +21 -39
  14. package/build/transformer/plugins/tsc.js +7 -2
  15. package/build/transformer/plugins/vite.js +7 -9
  16. package/build/transformer/transforms/array.d.ts +3 -3
  17. package/build/transformer/transforms/array.js +16 -19
  18. package/build/transformer/transforms/object.d.ts +3 -3
  19. package/build/transformer/transforms/object.js +41 -57
  20. package/build/transformer/transforms/primitives.d.ts +3 -3
  21. package/build/transformer/transforms/primitives.js +60 -117
  22. package/build/types.d.ts +2 -2
  23. package/package.json +6 -6
  24. package/readme.md +5 -5
  25. package/src/constants.ts +20 -13
  26. package/src/index.ts +2 -2
  27. package/src/reactive/array.ts +18 -32
  28. package/src/reactive/index.ts +18 -19
  29. package/src/system.ts +14 -21
  30. package/src/transformer/detector.ts +16 -25
  31. package/src/transformer/index.ts +24 -46
  32. package/src/transformer/plugins/tsc.ts +8 -2
  33. package/src/transformer/plugins/vite.ts +9 -12
  34. package/src/transformer/transforms/array.ts +20 -33
  35. package/src/transformer/transforms/object.ts +55 -79
  36. package/src/transformer/transforms/primitives.ts +70 -144
  37. package/src/types.ts +5 -3
  38. package/test/vite.config.ts +1 -1
  39. package/build/transformer/transforms/utilities.d.ts +0 -8
  40. package/build/transformer/transforms/utilities.js +0 -27
  41. package/src/transformer/transforms/utilities.ts +0 -45
@@ -1,15 +1,7 @@
1
- import { uid } from '@esportsplus/typescript/transformer';
2
- import type { Bindings } from '~/types';
3
- import { addMissingImports, applyReplacements, ExtraImport, Replacement } from './utilities';
4
1
  import { ts } from '@esportsplus/typescript';
5
-
6
-
7
- const CLASS_NAME_REGEX = /class (\w+)/;
8
-
9
- const EXTRA_IMPORTS: ExtraImport[] = [
10
- { module: '@esportsplus/reactivity/constants', specifier: 'REACTIVE_OBJECT' },
11
- { module: '@esportsplus/reactivity/reactive/array', specifier: 'ReactiveArray' }
12
- ];
2
+ import { code as c, type Replacement } from '@esportsplus/typescript/transformer';
3
+ import { COMPILATION_TYPE_ARRAY, COMPILATION_TYPE_COMPUTED, COMPILATION_TYPE_SIGNAL, PACKAGE } from '~/constants';
4
+ import type { Bindings } from '~/types';
13
5
 
14
6
 
15
7
  interface AnalyzedProperty {
@@ -19,19 +11,20 @@ interface AnalyzedProperty {
19
11
  }
20
12
 
21
13
  interface ReactiveObjectCall {
14
+ className: string;
22
15
  end: number;
23
- generatedClass: string;
24
- needsImports: Set<string>;
16
+ properties: AnalyzedProperty[];
25
17
  start: number;
26
18
  varName: string | null;
27
19
  }
28
20
 
29
21
  interface TransformContext {
30
- allNeededImports: Set<string>;
31
22
  bindings: Bindings;
32
23
  calls: ReactiveObjectCall[];
24
+ classCounter: number;
33
25
  hasReactiveImport: boolean;
34
26
  lastImportEnd: number;
27
+ ns: string;
35
28
  sourceFile: ts.SourceFile;
36
29
  }
37
30
 
@@ -54,43 +47,53 @@ function analyzeProperty(prop: ts.ObjectLiteralElementLike, sourceFile: ts.Sourc
54
47
  valueText = value.getText(sourceFile);
55
48
 
56
49
  if (ts.isArrowFunction(value) || ts.isFunctionExpression(value)) {
57
- return { key, type: 'computed', valueText };
50
+ return { key, type: COMPILATION_TYPE_COMPUTED, valueText };
58
51
  }
59
52
 
60
53
  if (ts.isArrayLiteralExpression(value)) {
61
- return { key, type: 'array', valueText };
54
+ let elements = value.elements,
55
+ elementsText = '';
56
+
57
+ for (let i = 0, n = elements.length; i < n; i++) {
58
+ if (i > 0) {
59
+ elementsText += ', ';
60
+ }
61
+
62
+ elementsText += elements[i].getText(sourceFile);
63
+ }
64
+
65
+ return { key, type: COMPILATION_TYPE_ARRAY, valueText: elementsText };
62
66
  }
63
67
 
64
- return { key, type: 'signal', valueText };
68
+ return { key, type: COMPILATION_TYPE_SIGNAL, valueText };
65
69
  }
66
70
 
67
- function buildClassCode(className: string, properties: AnalyzedProperty[]): string {
71
+ function buildClassCode(className: string, properties: AnalyzedProperty[], ns: string): string {
68
72
  let accessors: string[] = [],
69
73
  disposeStatements: string[] = [],
70
- fields: string[] = [];
74
+ fields: string[] = [],
75
+ paramCounter = 0;
71
76
 
72
- fields.push(`[REACTIVE_OBJECT] = true;`);
77
+ fields.push(`[${ns}.REACTIVE_OBJECT] = true;`);
73
78
 
74
79
  for (let i = 0, n = properties.length; i < n; i++) {
75
80
  let { key, type, valueText } = properties[i];
76
81
 
77
- if (type === 'signal') {
78
- let param = uid('v');
82
+ if (type === COMPILATION_TYPE_SIGNAL) {
83
+ let param = `_v${paramCounter++}`;
79
84
 
80
- fields.push(`#${key} = signal(${valueText});`);
81
- accessors.push(`get ${key}() { return read(this.#${key}); }`);
82
- accessors.push(`set ${key}(${param}) { set(this.#${key}, ${param}); }`);
85
+ fields.push(`#${key} = ${ns}.signal(${valueText});`);
86
+ accessors.push(`get ${key}() { return ${ns}.read(this.#${key}); }`);
87
+ accessors.push(`set ${key}(${param}) { ${ns}.write(this.#${key}, ${param}); }`);
83
88
  }
84
- else if (type === 'array') {
85
- let elements = valueText.slice(1, -1);
86
-
87
- fields.push(`${key} = new ReactiveArray(${elements});`);
89
+ else if (type === COMPILATION_TYPE_ARRAY) {
90
+ fields.push(`${key} = new ${ns}.ReactiveArray(${valueText});`);
88
91
  disposeStatements.push(`this.${key}.dispose();`);
89
92
  }
90
- else if (type === 'computed') {
91
- fields.push(`#${key}: Computed<unknown> | null = null;`);
92
- accessors.push(`get ${key}() { return read(this.#${key} ??= computed(${valueText})); }`);
93
- disposeStatements.push(`if (this.#${key}) dispose(this.#${key});`);
93
+ else if (type === COMPILATION_TYPE_COMPUTED) {
94
+ fields.push(`#${key} = null;`);
95
+ accessors.push(`get ${key}() { return ${ns}.read(this.#${key} ??= ${ns}.computed(${valueText})); }`);
96
+ disposeStatements.push(`if (this.#${key}) ${ns}.dispose(this.#${key});`);
94
97
  }
95
98
  }
96
99
 
@@ -112,7 +115,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
112
115
 
113
116
  if (
114
117
  ts.isStringLiteral(node.moduleSpecifier) &&
115
- node.moduleSpecifier.text.includes('@esportsplus/reactivity')
118
+ node.moduleSpecifier.text.includes(PACKAGE)
116
119
  ) {
117
120
  let clause = node.importClause;
118
121
 
@@ -138,20 +141,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
138
141
  let arg = node.arguments[0];
139
142
 
140
143
  if (arg && ts.isObjectLiteralExpression(arg)) {
141
- let varName: string | null = null;
144
+ let properties: AnalyzedProperty[] = [],
145
+ props = arg.properties,
146
+ varName: string | null = null;
142
147
 
143
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
148
+ if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
144
149
  varName = node.parent.name.text;
145
150
  ctx.bindings.set(varName, 'object');
146
151
  }
147
152
 
148
- let needsImports = new Set<string>(),
149
- properties: AnalyzedProperty[] = [];
150
-
151
- needsImports.add('REACTIVE_OBJECT');
152
-
153
- let props = arg.properties;
154
-
155
153
  for (let i = 0, n = props.length; i < n; i++) {
156
154
  let prop = props[i];
157
155
 
@@ -169,31 +167,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
169
167
 
170
168
  properties.push(analyzed);
171
169
 
172
- if (analyzed.type === 'signal') {
173
- needsImports.add('read');
174
- needsImports.add('set');
175
- needsImports.add('signal');
176
- }
177
- else if (analyzed.type === 'array') {
178
- needsImports.add('ReactiveArray');
179
-
180
- if (varName) {
181
- ctx.bindings.set(`${varName}.${analyzed.key}`, 'array');
182
- }
183
- }
184
- else if (analyzed.type === 'computed') {
185
- needsImports.add('computed');
186
- needsImports.add('dispose');
187
- needsImports.add('read');
170
+ if (analyzed.type === COMPILATION_TYPE_ARRAY && varName) {
171
+ ctx.bindings.set(`${varName}.${analyzed.key}`, COMPILATION_TYPE_ARRAY);
188
172
  }
189
173
  }
190
174
 
191
- needsImports.forEach(imp => ctx.allNeededImports.add(imp));
192
-
193
175
  ctx.calls.push({
176
+ className: `_RO${ctx.classCounter++}`,
194
177
  end: node.end,
195
- generatedClass: buildClassCode(uid('ReactiveObject'), properties),
196
- needsImports,
178
+ properties,
197
179
  start: node.pos,
198
180
  varName
199
181
  });
@@ -204,14 +186,15 @@ function visit(ctx: TransformContext, node: ts.Node): void {
204
186
  }
205
187
 
206
188
 
207
- const transformReactiveObjects = (sourceFile: ts.SourceFile, bindings: Bindings): string => {
189
+ export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
208
190
  let code = sourceFile.getFullText(),
209
191
  ctx: TransformContext = {
210
- allNeededImports: new Set<string>(),
211
192
  bindings,
212
193
  calls: [],
194
+ classCounter: 0,
213
195
  hasReactiveImport: false,
214
196
  lastImportEnd: 0,
197
+ ns,
215
198
  sourceFile
216
199
  };
217
200
 
@@ -221,31 +204,24 @@ const transformReactiveObjects = (sourceFile: ts.SourceFile, bindings: Bindings)
221
204
  return code;
222
205
  }
223
206
 
224
- let replacements: Replacement[] = [];
207
+ let classes = ctx.calls.map(c => buildClassCode(c.className, c.properties, ns)).join('\n'),
208
+ replacements: Replacement[] = [];
225
209
 
226
210
  replacements.push({
227
211
  end: ctx.lastImportEnd,
228
- newText: code.substring(0, ctx.lastImportEnd) + '\n' + ctx.calls.map(c => c.generatedClass).join('\n') + '\n',
212
+ newText: code.substring(0, ctx.lastImportEnd) + '\n' + classes + '\n',
229
213
  start: 0
230
214
  });
231
215
 
232
216
  for (let i = 0, n = ctx.calls.length; i < n; i++) {
233
- let call = ctx.calls[i],
234
- classMatch = call.generatedClass.match(CLASS_NAME_REGEX);
217
+ let call = ctx.calls[i];
235
218
 
236
219
  replacements.push({
237
220
  end: call.end,
238
- newText: ` new ${classMatch ? classMatch[1] : 'ReactiveObject'}()`,
221
+ newText: ` new ${call.className}()`,
239
222
  start: call.start
240
223
  });
241
224
  }
242
225
 
243
- return addMissingImports(
244
- applyReplacements(code, replacements),
245
- ctx.allNeededImports,
246
- EXTRA_IMPORTS
247
- );
248
- };
249
-
250
-
251
- export { transformReactiveObjects };
226
+ return c.replace(code, replacements);
227
+ };
@@ -1,13 +1,13 @@
1
- import { uid, type Range } from '@esportsplus/typescript/transformer';
2
- import type { BindingType, Bindings } from '~/types';
3
- import { addMissingImports, applyReplacements, Replacement } from './utilities';
4
1
  import { ts } from '@esportsplus/typescript';
2
+ import { code as c, type Range, type Replacement } from '@esportsplus/typescript/transformer';
3
+ import type { BindingType, Bindings } from '~/types';
4
+ import { COMPILATION_TYPE_COMPUTED, COMPILATION_ENTRYPOINT, COMPILATION_TYPE_SIGNAL, PACKAGE } from '~/constants';
5
5
 
6
6
 
7
7
  interface ArgContext {
8
8
  argStart: number;
9
9
  innerReplacements: Replacement[];
10
- neededImports: Set<string>;
10
+ ns: string;
11
11
  scopedBindings: ScopeBinding[];
12
12
  sourceFile: ts.SourceFile;
13
13
  }
@@ -22,23 +22,43 @@ interface TransformContext {
22
22
  bindings: Bindings;
23
23
  computedArgRanges: Range[];
24
24
  hasReactiveImport: boolean;
25
- neededImports: Set<string>;
25
+ ns: string;
26
26
  replacements: Replacement[];
27
27
  scopedBindings: ScopeBinding[];
28
28
  sourceFile: ts.SourceFile;
29
+ tmpCounter: number;
29
30
  }
30
31
 
31
32
 
32
- function classifyReactiveArg(arg: ts.Expression): 'computed' | 'signal' | null {
33
+ let COMPOUND_OPERATORS = new Map<ts.SyntaxKind, string>([
34
+ [ts.SyntaxKind.AmpersandAmpersandEqualsToken, '&&'],
35
+ [ts.SyntaxKind.AmpersandEqualsToken, '&'],
36
+ [ts.SyntaxKind.AsteriskAsteriskEqualsToken, '**'],
37
+ [ts.SyntaxKind.AsteriskEqualsToken, '*'],
38
+ [ts.SyntaxKind.BarBarEqualsToken, '||'],
39
+ [ts.SyntaxKind.BarEqualsToken, '|'],
40
+ [ts.SyntaxKind.CaretEqualsToken, '^'],
41
+ [ts.SyntaxKind.GreaterThanGreaterThanEqualsToken, '>>'],
42
+ [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, '>>>'],
43
+ [ts.SyntaxKind.LessThanLessThanEqualsToken, '<<'],
44
+ [ts.SyntaxKind.MinusEqualsToken, '-'],
45
+ [ts.SyntaxKind.PercentEqualsToken, '%'],
46
+ [ts.SyntaxKind.PlusEqualsToken, '+'],
47
+ [ts.SyntaxKind.QuestionQuestionEqualsToken, '??'],
48
+ [ts.SyntaxKind.SlashEqualsToken, '/']
49
+ ]);
50
+
51
+
52
+ function classifyReactiveArg(arg: ts.Expression): BindingType | null {
33
53
  if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
34
- return 'computed';
54
+ return COMPILATION_TYPE_COMPUTED;
35
55
  }
36
56
 
37
57
  if (ts.isObjectLiteralExpression(arg) || ts.isArrayLiteralExpression(arg)) {
38
58
  return null;
39
59
  }
40
60
 
41
- return 'signal';
61
+ return COMPILATION_TYPE_SIGNAL;
42
62
  }
43
63
 
44
64
  function findBinding(bindings: ScopeBinding[], name: string, node: ts.Node): ScopeBinding | undefined {
@@ -76,57 +96,6 @@ function findEnclosingScope(node: ts.Node): ts.Node {
76
96
  return node.getSourceFile();
77
97
  }
78
98
 
79
- function getCompoundOperator(kind: ts.SyntaxKind): string {
80
- if (kind === ts.SyntaxKind.PlusEqualsToken) {
81
- return '+';
82
- }
83
- else if (kind === ts.SyntaxKind.MinusEqualsToken) {
84
- return '-';
85
- }
86
- else if (kind === ts.SyntaxKind.AsteriskEqualsToken) {
87
- return '*';
88
- }
89
- else if (kind === ts.SyntaxKind.SlashEqualsToken) {
90
- return '/';
91
- }
92
- else if (kind === ts.SyntaxKind.PercentEqualsToken) {
93
- return '%';
94
- }
95
- else if (kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
96
- return '**';
97
- }
98
- else if (kind === ts.SyntaxKind.AmpersandEqualsToken) {
99
- return '&';
100
- }
101
- else if (kind === ts.SyntaxKind.BarEqualsToken) {
102
- return '|';
103
- }
104
- else if (kind === ts.SyntaxKind.CaretEqualsToken) {
105
- return '^';
106
- }
107
- else if (kind === ts.SyntaxKind.LessThanLessThanEqualsToken) {
108
- return '<<';
109
- }
110
- else if (kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken) {
111
- return '>>';
112
- }
113
- else if (kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
114
- return '>>>';
115
- }
116
- else if (kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
117
- return '&&';
118
- }
119
- else if (kind === ts.SyntaxKind.BarBarEqualsToken) {
120
- return '||';
121
- }
122
- else if (kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
123
- return '??';
124
- }
125
- else {
126
- return '+';
127
- }
128
- }
129
-
130
99
  function isInComputedRange(ranges: Range[], start: number, end: number): boolean {
131
100
  for (let i = 0, n = ranges.length; i < n; i++) {
132
101
  let r = ranges[i];
@@ -142,11 +111,7 @@ function isInComputedRange(ranges: Range[], start: number, end: number): boolean
142
111
  function isInDeclarationInit(node: ts.Node): boolean {
143
112
  let parent = node.parent;
144
113
 
145
- if (ts.isVariableDeclaration(parent) && parent.initializer === node) {
146
- return true;
147
- }
148
-
149
- return false;
114
+ return ts.isVariableDeclaration(parent) && parent.initializer === node;
150
115
  }
151
116
 
152
117
  function isInScope(reference: ts.Node, binding: ScopeBinding): boolean {
@@ -172,7 +137,7 @@ function isReactiveReassignment(node: ts.Node): boolean {
172
137
  parent.right === node &&
173
138
  ts.isCallExpression(node) &&
174
139
  ts.isIdentifier((node as ts.CallExpression).expression) &&
175
- ((node as ts.CallExpression).expression as ts.Identifier).text === 'reactive'
140
+ ((node as ts.CallExpression).expression as ts.Identifier).text === COMPILATION_ENTRYPOINT
176
141
  ) {
177
142
  return true;
178
143
  }
@@ -190,15 +155,7 @@ function isWriteContext(node: ts.Identifier): 'simple' | 'compound' | 'increment
190
155
  return 'simple';
191
156
  }
192
157
 
193
- if (op >= ts.SyntaxKind.PlusEqualsToken && op <= ts.SyntaxKind.CaretEqualsToken) {
194
- return 'compound';
195
- }
196
-
197
- if (
198
- op === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
199
- op === ts.SyntaxKind.BarBarEqualsToken ||
200
- op === ts.SyntaxKind.QuestionQuestionEqualsToken
201
- ) {
158
+ if (COMPOUND_OPERATORS.has(op)) {
202
159
  return 'compound';
203
160
  }
204
161
  }
@@ -218,13 +175,13 @@ function visit(ctx: TransformContext, node: ts.Node): void {
218
175
  if (
219
176
  ts.isImportDeclaration(node) &&
220
177
  ts.isStringLiteral(node.moduleSpecifier) &&
221
- node.moduleSpecifier.text.includes('@esportsplus/reactivity')
178
+ node.moduleSpecifier.text.includes(PACKAGE)
222
179
  ) {
223
180
  let clause = node.importClause;
224
181
 
225
182
  if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
226
183
  for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
227
- if (clause.namedBindings.elements[i].name.text === 'reactive') {
184
+ if (clause.namedBindings.elements[i].name.text === COMPILATION_ENTRYPOINT) {
228
185
  ctx.hasReactiveImport = true;
229
186
  break;
230
187
  }
@@ -236,7 +193,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
236
193
  ctx.hasReactiveImport &&
237
194
  ts.isCallExpression(node) &&
238
195
  ts.isIdentifier(node.expression) &&
239
- node.expression.text === 'reactive' &&
196
+ node.expression.text === COMPILATION_ENTRYPOINT &&
240
197
  node.arguments.length > 0
241
198
  ) {
242
199
  let arg = node.arguments[0],
@@ -245,10 +202,11 @@ function visit(ctx: TransformContext, node: ts.Node): void {
245
202
  if (classification) {
246
203
  let varName: string | null = null;
247
204
 
248
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
205
+ if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
249
206
  varName = node.parent.name.text;
250
207
  }
251
208
  else if (
209
+ node.parent &&
252
210
  ts.isBinaryExpression(node.parent) &&
253
211
  node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
254
212
  ts.isIdentifier(node.parent.left)
@@ -263,47 +221,40 @@ function visit(ctx: TransformContext, node: ts.Node): void {
263
221
  ctx.bindings.set(varName, classification);
264
222
  }
265
223
 
266
- if (classification === 'computed') {
267
- ctx.computedArgRanges.push({
268
- end: arg.end,
269
- start: arg.getStart(ctx.sourceFile)
270
- });
224
+ if (classification === COMPILATION_TYPE_COMPUTED) {
225
+ let argStart = arg.getStart(ctx.sourceFile);
226
+
227
+ ctx.computedArgRanges.push({ end: arg.end, start: argStart });
271
228
 
272
229
  let argCtx: ArgContext = {
273
- argStart: arg.getStart(ctx.sourceFile),
230
+ argStart,
274
231
  innerReplacements: [],
275
- neededImports: ctx.neededImports,
232
+ ns: ctx.ns,
276
233
  scopedBindings: ctx.scopedBindings,
277
234
  sourceFile: ctx.sourceFile
278
235
  };
279
236
 
280
237
  visitArg(argCtx, arg);
281
238
 
282
- let argText = applyReplacements(arg.getText(ctx.sourceFile), argCtx.innerReplacements);
239
+ let argText = c.replace(arg.getText(ctx.sourceFile), argCtx.innerReplacements);
283
240
 
284
241
  ctx.replacements.push({
285
242
  end: node.end,
286
- newText: `computed(${argText})`,
243
+ newText: `${ctx.ns}.computed(${argText})`,
287
244
  start: node.pos
288
245
  });
289
-
290
- ctx.neededImports.add('computed');
291
246
  }
292
247
  else {
293
- let argText = arg.getText(ctx.sourceFile);
294
-
295
248
  ctx.replacements.push({
296
249
  end: node.end,
297
- newText: `signal(${argText})`,
250
+ newText: `${ctx.ns}.signal(${arg.getText(ctx.sourceFile)})`,
298
251
  start: node.pos
299
252
  });
300
-
301
- ctx.neededImports.add('signal');
302
253
  }
303
254
  }
304
255
  }
305
256
 
306
- if (ts.isIdentifier(node) && !isInDeclarationInit(node.parent)) {
257
+ if (ts.isIdentifier(node) && node.parent && !isInDeclarationInit(node.parent)) {
307
258
  if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
308
259
  ts.forEachChild(node, n => visit(ctx, n));
309
260
  return;
@@ -319,7 +270,7 @@ function visit(ctx: TransformContext, node: ts.Node): void {
319
270
  let binding = findBinding(ctx.scopedBindings, node.text, node),
320
271
  name = node.text;
321
272
 
322
- if (binding) {
273
+ if (binding && node.parent) {
323
274
  if (
324
275
  !isReactiveReassignment(node.parent) &&
325
276
  !(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)
@@ -327,55 +278,49 @@ function visit(ctx: TransformContext, node: ts.Node): void {
327
278
  let writeCtx = isWriteContext(node);
328
279
 
329
280
  if (writeCtx) {
330
- if (binding.type !== 'computed') {
331
- ctx.neededImports.add('set');
332
-
281
+ if (binding.type !== COMPILATION_TYPE_COMPUTED) {
333
282
  let parent = node.parent;
334
283
 
335
284
  if (writeCtx === 'simple' && ts.isBinaryExpression(parent)) {
336
- let valueText = parent.right.getText(ctx.sourceFile);
337
-
338
285
  ctx.replacements.push({
339
286
  end: parent.end,
340
- newText: `set(${name}, ${valueText})`,
287
+ newText: `${ctx.ns}.write(${name}, ${parent.right.getText(ctx.sourceFile)})`,
341
288
  start: parent.pos
342
289
  });
343
290
  }
344
291
  else if (writeCtx === 'compound' && ts.isBinaryExpression(parent)) {
345
- let op = getCompoundOperator(parent.operatorToken.kind),
346
- valueText = parent.right.getText(ctx.sourceFile);
292
+ let op = COMPOUND_OPERATORS.get(parent.operatorToken.kind) ?? '+';
347
293
 
348
294
  ctx.replacements.push({
349
295
  end: parent.end,
350
- newText: `set(${name}, ${name}.value ${op} ${valueText})`,
296
+ newText: `${ctx.ns}.write(${name}, ${name}.value ${op} ${parent.right.getText(ctx.sourceFile)})`,
351
297
  start: parent.pos
352
298
  });
353
299
  }
354
300
  else if (writeCtx === 'increment') {
355
- let isPrefix = ts.isPrefixUnaryExpression(parent),
356
- op = (parent as ts.PrefixUnaryExpression | ts.PostfixUnaryExpression).operator,
357
- delta = op === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1';
301
+ let delta = (parent as ts.PrefixUnaryExpression | ts.PostfixUnaryExpression).operator === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1',
302
+ isPrefix = ts.isPrefixUnaryExpression(parent);
358
303
 
359
304
  if (ts.isExpressionStatement(parent.parent)) {
360
305
  ctx.replacements.push({
361
306
  end: parent.end,
362
- newText: `set(${name}, ${name}.value ${delta})`,
307
+ newText: `${ctx.ns}.write(${name}, ${name}.value ${delta})`,
363
308
  start: parent.pos
364
309
  });
365
310
  }
366
311
  else if (isPrefix) {
367
312
  ctx.replacements.push({
368
313
  end: parent.end,
369
- newText: `(set(${name}, ${name}.value ${delta}), ${name}.value)`,
314
+ newText: `(${ctx.ns}.write(${name}, ${name}.value ${delta}), ${name}.value)`,
370
315
  start: parent.pos
371
316
  });
372
317
  }
373
318
  else {
374
- let tmp = uid('tmp');
319
+ let tmp = `_t${ctx.tmpCounter++}`;
375
320
 
376
321
  ctx.replacements.push({
377
322
  end: parent.end,
378
- newText: `((${tmp}) => (set(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
323
+ newText: `((${tmp}) => (${ctx.ns}.write(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
379
324
  start: parent.pos
380
325
  });
381
326
  }
@@ -383,11 +328,9 @@ function visit(ctx: TransformContext, node: ts.Node): void {
383
328
  }
384
329
  }
385
330
  else {
386
- ctx.neededImports.add('read');
387
-
388
331
  ctx.replacements.push({
389
332
  end: node.end,
390
- newText: `read(${name})`,
333
+ newText: `${ctx.ns}.read(${name})`,
391
334
  start: node.pos
392
335
  });
393
336
  }
@@ -399,25 +342,19 @@ function visit(ctx: TransformContext, node: ts.Node): void {
399
342
  }
400
343
 
401
344
  function visitArg(ctx: ArgContext, node: ts.Node): void {
402
- if (ts.isIdentifier(node)) {
403
- if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
404
- ts.forEachChild(node, n => visitArg(ctx, n));
405
- return;
406
- }
407
-
408
- if (ts.isCallExpression(node.parent) && node.parent.expression === node) {
345
+ if (ts.isIdentifier(node) && node.parent) {
346
+ if (
347
+ (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) ||
348
+ (ts.isCallExpression(node.parent) && node.parent.expression === node)
349
+ ) {
409
350
  ts.forEachChild(node, n => visitArg(ctx, n));
410
351
  return;
411
352
  }
412
353
 
413
- let binding = findBinding(ctx.scopedBindings, node.text, node);
414
-
415
- if (binding) {
416
- ctx.neededImports.add('read');
417
-
354
+ if (findBinding(ctx.scopedBindings, node.text, node)) {
418
355
  ctx.innerReplacements.push({
419
356
  end: node.end - ctx.argStart,
420
- newText: `read(${node.text})`,
357
+ newText: `${ctx.ns}.read(${node.text})`,
421
358
  start: node.getStart(ctx.sourceFile) - ctx.argStart
422
359
  });
423
360
  }
@@ -427,19 +364,17 @@ function visitArg(ctx: ArgContext, node: ts.Node): void {
427
364
  }
428
365
 
429
366
 
430
- const transformReactivePrimitives = (
431
- sourceFile: ts.SourceFile,
432
- bindings: Bindings
433
- ): string => {
367
+ export default (sourceFile: ts.SourceFile, bindings: Bindings, ns: string): string => {
434
368
  let code = sourceFile.getFullText(),
435
369
  ctx: TransformContext = {
436
370
  bindings,
437
371
  computedArgRanges: [],
438
372
  hasReactiveImport: false,
439
- neededImports: new Set<string>(),
373
+ ns,
440
374
  replacements: [],
441
375
  scopedBindings: [],
442
- sourceFile
376
+ sourceFile,
377
+ tmpCounter: 0
443
378
  };
444
379
 
445
380
  visit(ctx, sourceFile);
@@ -448,14 +383,5 @@ const transformReactivePrimitives = (
448
383
  return code;
449
384
  }
450
385
 
451
- let result = applyReplacements(code, ctx.replacements);
452
-
453
- if (ctx.neededImports.size > 0) {
454
- result = addMissingImports(result, ctx.neededImports);
455
- }
456
-
457
- return result;
386
+ return c.replace(code, ctx.replacements);
458
387
  };
459
-
460
-
461
- export { transformReactivePrimitives };
package/src/types.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
2
- import { ReactiveArray, ReactiveObject } from './reactive';
3
2
  import { ts } from '@esportsplus/typescript';
4
3
 
5
4
 
@@ -36,6 +35,10 @@ interface Link {
36
35
  version: number;
37
36
  }
38
37
 
38
+ // If we expose internals optimizing compiler may break api.
39
+ // Instead we will use this as a shim.
40
+ type Reactive<T> = T;
41
+
39
42
  type Signal<T> = {
40
43
  subs: Link | null;
41
44
  subsTail: Link | null;
@@ -55,8 +58,7 @@ export type {
55
58
  Bindings,
56
59
  Computed,
57
60
  Link,
58
- ReactiveArray,
59
- ReactiveObject,
61
+ Reactive,
60
62
  Signal,
61
63
  TransformResult
62
64
  };