@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,11 +1,6 @@
1
- import { uid } from '@esportsplus/typescript/transformer';
2
- import { addMissingImports, applyReplacements } from './utilities.js';
3
1
  import { ts } from '@esportsplus/typescript';
4
- const CLASS_NAME_REGEX = /class (\w+)/;
5
- const EXTRA_IMPORTS = [
6
- { module: '@esportsplus/reactivity/constants', specifier: 'REACTIVE_OBJECT' },
7
- { module: '@esportsplus/reactivity/reactive/array', specifier: 'ReactiveArray' }
8
- ];
2
+ import { code as c } from '@esportsplus/typescript/transformer';
3
+ import { COMPILATION_TYPE_ARRAY, COMPILATION_TYPE_COMPUTED, COMPILATION_TYPE_SIGNAL, PACKAGE } from '../../constants.js';
9
4
  function analyzeProperty(prop, sourceFile) {
10
5
  if (!ts.isPropertyAssignment(prop)) {
11
6
  return null;
@@ -19,33 +14,39 @@ function analyzeProperty(prop, sourceFile) {
19
14
  }
20
15
  let value = prop.initializer, valueText = value.getText(sourceFile);
21
16
  if (ts.isArrowFunction(value) || ts.isFunctionExpression(value)) {
22
- return { key, type: 'computed', valueText };
17
+ return { key, type: COMPILATION_TYPE_COMPUTED, valueText };
23
18
  }
24
19
  if (ts.isArrayLiteralExpression(value)) {
25
- return { key, type: 'array', valueText };
20
+ let elements = value.elements, elementsText = '';
21
+ for (let i = 0, n = elements.length; i < n; i++) {
22
+ if (i > 0) {
23
+ elementsText += ', ';
24
+ }
25
+ elementsText += elements[i].getText(sourceFile);
26
+ }
27
+ return { key, type: COMPILATION_TYPE_ARRAY, valueText: elementsText };
26
28
  }
27
- return { key, type: 'signal', valueText };
29
+ return { key, type: COMPILATION_TYPE_SIGNAL, valueText };
28
30
  }
29
- function buildClassCode(className, properties) {
30
- let accessors = [], disposeStatements = [], fields = [];
31
- fields.push(`[REACTIVE_OBJECT] = true;`);
31
+ function buildClassCode(className, properties, ns) {
32
+ let accessors = [], disposeStatements = [], fields = [], paramCounter = 0;
33
+ fields.push(`[${ns}.REACTIVE_OBJECT] = true;`);
32
34
  for (let i = 0, n = properties.length; i < n; i++) {
33
35
  let { key, type, valueText } = properties[i];
34
- if (type === 'signal') {
35
- let param = uid('v');
36
- fields.push(`#${key} = signal(${valueText});`);
37
- accessors.push(`get ${key}() { return read(this.#${key}); }`);
38
- accessors.push(`set ${key}(${param}) { set(this.#${key}, ${param}); }`);
36
+ if (type === COMPILATION_TYPE_SIGNAL) {
37
+ let param = `_v${paramCounter++}`;
38
+ fields.push(`#${key} = ${ns}.signal(${valueText});`);
39
+ accessors.push(`get ${key}() { return ${ns}.read(this.#${key}); }`);
40
+ accessors.push(`set ${key}(${param}) { ${ns}.write(this.#${key}, ${param}); }`);
39
41
  }
40
- else if (type === 'array') {
41
- let elements = valueText.slice(1, -1);
42
- fields.push(`${key} = new ReactiveArray(${elements});`);
42
+ else if (type === COMPILATION_TYPE_ARRAY) {
43
+ fields.push(`${key} = new ${ns}.ReactiveArray(${valueText});`);
43
44
  disposeStatements.push(`this.${key}.dispose();`);
44
45
  }
45
- else if (type === 'computed') {
46
- fields.push(`#${key}: Computed<unknown> | null = null;`);
47
- accessors.push(`get ${key}() { return read(this.#${key} ??= computed(${valueText})); }`);
48
- disposeStatements.push(`if (this.#${key}) dispose(this.#${key});`);
46
+ else if (type === COMPILATION_TYPE_COMPUTED) {
47
+ fields.push(`#${key} = null;`);
48
+ accessors.push(`get ${key}() { return ${ns}.read(this.#${key} ??= ${ns}.computed(${valueText})); }`);
49
+ disposeStatements.push(`if (this.#${key}) ${ns}.dispose(this.#${key});`);
49
50
  }
50
51
  }
51
52
  return `
@@ -63,7 +64,7 @@ function visit(ctx, node) {
63
64
  if (ts.isImportDeclaration(node)) {
64
65
  ctx.lastImportEnd = node.end;
65
66
  if (ts.isStringLiteral(node.moduleSpecifier) &&
66
- node.moduleSpecifier.text.includes('@esportsplus/reactivity')) {
67
+ node.moduleSpecifier.text.includes(PACKAGE)) {
67
68
  let clause = node.importClause;
68
69
  if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
69
70
  let elements = clause.namedBindings.elements;
@@ -82,14 +83,11 @@ function visit(ctx, node) {
82
83
  node.expression.text === 'reactive') {
83
84
  let arg = node.arguments[0];
84
85
  if (arg && ts.isObjectLiteralExpression(arg)) {
85
- let varName = null;
86
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
86
+ let properties = [], props = arg.properties, varName = null;
87
+ if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
87
88
  varName = node.parent.name.text;
88
89
  ctx.bindings.set(varName, 'object');
89
90
  }
90
- let needsImports = new Set(), properties = [];
91
- needsImports.add('REACTIVE_OBJECT');
92
- let props = arg.properties;
93
91
  for (let i = 0, n = props.length; i < n; i++) {
94
92
  let prop = props[i];
95
93
  if (ts.isSpreadAssignment(prop)) {
@@ -102,28 +100,14 @@ function visit(ctx, node) {
102
100
  return;
103
101
  }
104
102
  properties.push(analyzed);
105
- if (analyzed.type === 'signal') {
106
- needsImports.add('read');
107
- needsImports.add('set');
108
- needsImports.add('signal');
109
- }
110
- else if (analyzed.type === 'array') {
111
- needsImports.add('ReactiveArray');
112
- if (varName) {
113
- ctx.bindings.set(`${varName}.${analyzed.key}`, 'array');
114
- }
115
- }
116
- else if (analyzed.type === 'computed') {
117
- needsImports.add('computed');
118
- needsImports.add('dispose');
119
- needsImports.add('read');
103
+ if (analyzed.type === COMPILATION_TYPE_ARRAY && varName) {
104
+ ctx.bindings.set(`${varName}.${analyzed.key}`, COMPILATION_TYPE_ARRAY);
120
105
  }
121
106
  }
122
- needsImports.forEach(imp => ctx.allNeededImports.add(imp));
123
107
  ctx.calls.push({
108
+ className: `_RO${ctx.classCounter++}`,
124
109
  end: node.end,
125
- generatedClass: buildClassCode(uid('ReactiveObject'), properties),
126
- needsImports,
110
+ properties,
127
111
  start: node.pos,
128
112
  varName
129
113
  });
@@ -131,33 +115,33 @@ function visit(ctx, node) {
131
115
  }
132
116
  ts.forEachChild(node, n => visit(ctx, n));
133
117
  }
134
- const transformReactiveObjects = (sourceFile, bindings) => {
118
+ export default (sourceFile, bindings, ns) => {
135
119
  let code = sourceFile.getFullText(), ctx = {
136
- allNeededImports: new Set(),
137
120
  bindings,
138
121
  calls: [],
122
+ classCounter: 0,
139
123
  hasReactiveImport: false,
140
124
  lastImportEnd: 0,
125
+ ns,
141
126
  sourceFile
142
127
  };
143
128
  visit(ctx, sourceFile);
144
129
  if (ctx.calls.length === 0) {
145
130
  return code;
146
131
  }
147
- let replacements = [];
132
+ let classes = ctx.calls.map(c => buildClassCode(c.className, c.properties, ns)).join('\n'), replacements = [];
148
133
  replacements.push({
149
134
  end: ctx.lastImportEnd,
150
- newText: code.substring(0, ctx.lastImportEnd) + '\n' + ctx.calls.map(c => c.generatedClass).join('\n') + '\n',
135
+ newText: code.substring(0, ctx.lastImportEnd) + '\n' + classes + '\n',
151
136
  start: 0
152
137
  });
153
138
  for (let i = 0, n = ctx.calls.length; i < n; i++) {
154
- let call = ctx.calls[i], classMatch = call.generatedClass.match(CLASS_NAME_REGEX);
139
+ let call = ctx.calls[i];
155
140
  replacements.push({
156
141
  end: call.end,
157
- newText: ` new ${classMatch ? classMatch[1] : 'ReactiveObject'}()`,
142
+ newText: ` new ${call.className}()`,
158
143
  start: call.start
159
144
  });
160
145
  }
161
- return addMissingImports(applyReplacements(code, replacements), ctx.allNeededImports, EXTRA_IMPORTS);
146
+ return c.replace(code, replacements);
162
147
  };
163
- export { transformReactiveObjects };
@@ -1,4 +1,4 @@
1
- import type { Bindings } from '../../types.js';
2
1
  import { ts } from '@esportsplus/typescript';
3
- declare const transformReactivePrimitives: (sourceFile: ts.SourceFile, bindings: Bindings) => string;
4
- export { transformReactivePrimitives };
2
+ import type { Bindings } from '../../types.js';
3
+ declare const _default: (sourceFile: ts.SourceFile, bindings: Bindings, ns: string) => string;
4
+ export default _default;
@@ -1,14 +1,31 @@
1
- import { uid } from '@esportsplus/typescript/transformer';
2
- import { addMissingImports, applyReplacements } from './utilities.js';
3
1
  import { ts } from '@esportsplus/typescript';
2
+ import { code as c } from '@esportsplus/typescript/transformer';
3
+ import { COMPILATION_TYPE_COMPUTED, COMPILATION_ENTRYPOINT, COMPILATION_TYPE_SIGNAL, PACKAGE } from '../../constants.js';
4
+ let COMPOUND_OPERATORS = new Map([
5
+ [ts.SyntaxKind.AmpersandAmpersandEqualsToken, '&&'],
6
+ [ts.SyntaxKind.AmpersandEqualsToken, '&'],
7
+ [ts.SyntaxKind.AsteriskAsteriskEqualsToken, '**'],
8
+ [ts.SyntaxKind.AsteriskEqualsToken, '*'],
9
+ [ts.SyntaxKind.BarBarEqualsToken, '||'],
10
+ [ts.SyntaxKind.BarEqualsToken, '|'],
11
+ [ts.SyntaxKind.CaretEqualsToken, '^'],
12
+ [ts.SyntaxKind.GreaterThanGreaterThanEqualsToken, '>>'],
13
+ [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, '>>>'],
14
+ [ts.SyntaxKind.LessThanLessThanEqualsToken, '<<'],
15
+ [ts.SyntaxKind.MinusEqualsToken, '-'],
16
+ [ts.SyntaxKind.PercentEqualsToken, '%'],
17
+ [ts.SyntaxKind.PlusEqualsToken, '+'],
18
+ [ts.SyntaxKind.QuestionQuestionEqualsToken, '??'],
19
+ [ts.SyntaxKind.SlashEqualsToken, '/']
20
+ ]);
4
21
  function classifyReactiveArg(arg) {
5
22
  if (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) {
6
- return 'computed';
23
+ return COMPILATION_TYPE_COMPUTED;
7
24
  }
8
25
  if (ts.isObjectLiteralExpression(arg) || ts.isArrayLiteralExpression(arg)) {
9
26
  return null;
10
27
  }
11
- return 'signal';
28
+ return COMPILATION_TYPE_SIGNAL;
12
29
  }
13
30
  function findBinding(bindings, name, node) {
14
31
  for (let i = 0, n = bindings.length; i < n; i++) {
@@ -36,56 +53,6 @@ function findEnclosingScope(node) {
36
53
  }
37
54
  return node.getSourceFile();
38
55
  }
39
- function getCompoundOperator(kind) {
40
- if (kind === ts.SyntaxKind.PlusEqualsToken) {
41
- return '+';
42
- }
43
- else if (kind === ts.SyntaxKind.MinusEqualsToken) {
44
- return '-';
45
- }
46
- else if (kind === ts.SyntaxKind.AsteriskEqualsToken) {
47
- return '*';
48
- }
49
- else if (kind === ts.SyntaxKind.SlashEqualsToken) {
50
- return '/';
51
- }
52
- else if (kind === ts.SyntaxKind.PercentEqualsToken) {
53
- return '%';
54
- }
55
- else if (kind === ts.SyntaxKind.AsteriskAsteriskEqualsToken) {
56
- return '**';
57
- }
58
- else if (kind === ts.SyntaxKind.AmpersandEqualsToken) {
59
- return '&';
60
- }
61
- else if (kind === ts.SyntaxKind.BarEqualsToken) {
62
- return '|';
63
- }
64
- else if (kind === ts.SyntaxKind.CaretEqualsToken) {
65
- return '^';
66
- }
67
- else if (kind === ts.SyntaxKind.LessThanLessThanEqualsToken) {
68
- return '<<';
69
- }
70
- else if (kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken) {
71
- return '>>';
72
- }
73
- else if (kind === ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken) {
74
- return '>>>';
75
- }
76
- else if (kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) {
77
- return '&&';
78
- }
79
- else if (kind === ts.SyntaxKind.BarBarEqualsToken) {
80
- return '||';
81
- }
82
- else if (kind === ts.SyntaxKind.QuestionQuestionEqualsToken) {
83
- return '??';
84
- }
85
- else {
86
- return '+';
87
- }
88
- }
89
56
  function isInComputedRange(ranges, start, end) {
90
57
  for (let i = 0, n = ranges.length; i < n; i++) {
91
58
  let r = ranges[i];
@@ -97,10 +64,7 @@ function isInComputedRange(ranges, start, end) {
97
64
  }
98
65
  function isInDeclarationInit(node) {
99
66
  let parent = node.parent;
100
- if (ts.isVariableDeclaration(parent) && parent.initializer === node) {
101
- return true;
102
- }
103
- return false;
67
+ return ts.isVariableDeclaration(parent) && parent.initializer === node;
104
68
  }
105
69
  function isInScope(reference, binding) {
106
70
  let current = reference;
@@ -119,7 +83,7 @@ function isReactiveReassignment(node) {
119
83
  parent.right === node &&
120
84
  ts.isCallExpression(node) &&
121
85
  ts.isIdentifier(node.expression) &&
122
- node.expression.text === 'reactive') {
86
+ node.expression.text === COMPILATION_ENTRYPOINT) {
123
87
  return true;
124
88
  }
125
89
  return false;
@@ -131,12 +95,7 @@ function isWriteContext(node) {
131
95
  if (op === ts.SyntaxKind.EqualsToken) {
132
96
  return 'simple';
133
97
  }
134
- if (op >= ts.SyntaxKind.PlusEqualsToken && op <= ts.SyntaxKind.CaretEqualsToken) {
135
- return 'compound';
136
- }
137
- if (op === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
138
- op === ts.SyntaxKind.BarBarEqualsToken ||
139
- op === ts.SyntaxKind.QuestionQuestionEqualsToken) {
98
+ if (COMPOUND_OPERATORS.has(op)) {
140
99
  return 'compound';
141
100
  }
142
101
  }
@@ -151,11 +110,11 @@ function isWriteContext(node) {
151
110
  function visit(ctx, node) {
152
111
  if (ts.isImportDeclaration(node) &&
153
112
  ts.isStringLiteral(node.moduleSpecifier) &&
154
- node.moduleSpecifier.text.includes('@esportsplus/reactivity')) {
113
+ node.moduleSpecifier.text.includes(PACKAGE)) {
155
114
  let clause = node.importClause;
156
115
  if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings)) {
157
116
  for (let i = 0, n = clause.namedBindings.elements.length; i < n; i++) {
158
- if (clause.namedBindings.elements[i].name.text === 'reactive') {
117
+ if (clause.namedBindings.elements[i].name.text === COMPILATION_ENTRYPOINT) {
159
118
  ctx.hasReactiveImport = true;
160
119
  break;
161
120
  }
@@ -165,15 +124,16 @@ function visit(ctx, node) {
165
124
  if (ctx.hasReactiveImport &&
166
125
  ts.isCallExpression(node) &&
167
126
  ts.isIdentifier(node.expression) &&
168
- node.expression.text === 'reactive' &&
127
+ node.expression.text === COMPILATION_ENTRYPOINT &&
169
128
  node.arguments.length > 0) {
170
129
  let arg = node.arguments[0], classification = classifyReactiveArg(arg);
171
130
  if (classification) {
172
131
  let varName = null;
173
- if (ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
132
+ if (node.parent && ts.isVariableDeclaration(node.parent) && ts.isIdentifier(node.parent.name)) {
174
133
  varName = node.parent.name.text;
175
134
  }
176
- else if (ts.isBinaryExpression(node.parent) &&
135
+ else if (node.parent &&
136
+ ts.isBinaryExpression(node.parent) &&
177
137
  node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
178
138
  ts.isIdentifier(node.parent.left)) {
179
139
  varName = node.parent.left.text;
@@ -183,39 +143,34 @@ function visit(ctx, node) {
183
143
  ctx.scopedBindings.push({ name: varName, scope, type: classification });
184
144
  ctx.bindings.set(varName, classification);
185
145
  }
186
- if (classification === 'computed') {
187
- ctx.computedArgRanges.push({
188
- end: arg.end,
189
- start: arg.getStart(ctx.sourceFile)
190
- });
146
+ if (classification === COMPILATION_TYPE_COMPUTED) {
147
+ let argStart = arg.getStart(ctx.sourceFile);
148
+ ctx.computedArgRanges.push({ end: arg.end, start: argStart });
191
149
  let argCtx = {
192
- argStart: arg.getStart(ctx.sourceFile),
150
+ argStart,
193
151
  innerReplacements: [],
194
- neededImports: ctx.neededImports,
152
+ ns: ctx.ns,
195
153
  scopedBindings: ctx.scopedBindings,
196
154
  sourceFile: ctx.sourceFile
197
155
  };
198
156
  visitArg(argCtx, arg);
199
- let argText = applyReplacements(arg.getText(ctx.sourceFile), argCtx.innerReplacements);
157
+ let argText = c.replace(arg.getText(ctx.sourceFile), argCtx.innerReplacements);
200
158
  ctx.replacements.push({
201
159
  end: node.end,
202
- newText: `computed(${argText})`,
160
+ newText: `${ctx.ns}.computed(${argText})`,
203
161
  start: node.pos
204
162
  });
205
- ctx.neededImports.add('computed');
206
163
  }
207
164
  else {
208
- let argText = arg.getText(ctx.sourceFile);
209
165
  ctx.replacements.push({
210
166
  end: node.end,
211
- newText: `signal(${argText})`,
167
+ newText: `${ctx.ns}.signal(${arg.getText(ctx.sourceFile)})`,
212
168
  start: node.pos
213
169
  });
214
- ctx.neededImports.add('signal');
215
170
  }
216
171
  }
217
172
  }
218
- if (ts.isIdentifier(node) && !isInDeclarationInit(node.parent)) {
173
+ if (ts.isIdentifier(node) && node.parent && !isInDeclarationInit(node.parent)) {
219
174
  if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
220
175
  ts.forEachChild(node, n => visit(ctx, n));
221
176
  return;
@@ -226,51 +181,49 @@ function visit(ctx, node) {
226
181
  return;
227
182
  }
228
183
  let binding = findBinding(ctx.scopedBindings, node.text, node), name = node.text;
229
- if (binding) {
184
+ if (binding && node.parent) {
230
185
  if (!isReactiveReassignment(node.parent) &&
231
186
  !(ts.isTypeOfExpression(node.parent) && node.parent.expression === node)) {
232
187
  let writeCtx = isWriteContext(node);
233
188
  if (writeCtx) {
234
- if (binding.type !== 'computed') {
235
- ctx.neededImports.add('set');
189
+ if (binding.type !== COMPILATION_TYPE_COMPUTED) {
236
190
  let parent = node.parent;
237
191
  if (writeCtx === 'simple' && ts.isBinaryExpression(parent)) {
238
- let valueText = parent.right.getText(ctx.sourceFile);
239
192
  ctx.replacements.push({
240
193
  end: parent.end,
241
- newText: `set(${name}, ${valueText})`,
194
+ newText: `${ctx.ns}.write(${name}, ${parent.right.getText(ctx.sourceFile)})`,
242
195
  start: parent.pos
243
196
  });
244
197
  }
245
198
  else if (writeCtx === 'compound' && ts.isBinaryExpression(parent)) {
246
- let op = getCompoundOperator(parent.operatorToken.kind), valueText = parent.right.getText(ctx.sourceFile);
199
+ let op = COMPOUND_OPERATORS.get(parent.operatorToken.kind) ?? '+';
247
200
  ctx.replacements.push({
248
201
  end: parent.end,
249
- newText: `set(${name}, ${name}.value ${op} ${valueText})`,
202
+ newText: `${ctx.ns}.write(${name}, ${name}.value ${op} ${parent.right.getText(ctx.sourceFile)})`,
250
203
  start: parent.pos
251
204
  });
252
205
  }
253
206
  else if (writeCtx === 'increment') {
254
- let isPrefix = ts.isPrefixUnaryExpression(parent), op = parent.operator, delta = op === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1';
207
+ let delta = parent.operator === ts.SyntaxKind.PlusPlusToken ? '+ 1' : '- 1', isPrefix = ts.isPrefixUnaryExpression(parent);
255
208
  if (ts.isExpressionStatement(parent.parent)) {
256
209
  ctx.replacements.push({
257
210
  end: parent.end,
258
- newText: `set(${name}, ${name}.value ${delta})`,
211
+ newText: `${ctx.ns}.write(${name}, ${name}.value ${delta})`,
259
212
  start: parent.pos
260
213
  });
261
214
  }
262
215
  else if (isPrefix) {
263
216
  ctx.replacements.push({
264
217
  end: parent.end,
265
- newText: `(set(${name}, ${name}.value ${delta}), ${name}.value)`,
218
+ newText: `(${ctx.ns}.write(${name}, ${name}.value ${delta}), ${name}.value)`,
266
219
  start: parent.pos
267
220
  });
268
221
  }
269
222
  else {
270
- let tmp = uid('tmp');
223
+ let tmp = `_t${ctx.tmpCounter++}`;
271
224
  ctx.replacements.push({
272
225
  end: parent.end,
273
- newText: `((${tmp}) => (set(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
226
+ newText: `((${tmp}) => (${ctx.ns}.write(${name}, ${tmp} ${delta}), ${tmp}))(${name}.value)`,
274
227
  start: parent.pos
275
228
  });
276
229
  }
@@ -278,10 +231,9 @@ function visit(ctx, node) {
278
231
  }
279
232
  }
280
233
  else {
281
- ctx.neededImports.add('read');
282
234
  ctx.replacements.push({
283
235
  end: node.end,
284
- newText: `read(${name})`,
236
+ newText: `${ctx.ns}.read(${name})`,
285
237
  start: node.pos
286
238
  });
287
239
  }
@@ -291,45 +243,36 @@ function visit(ctx, node) {
291
243
  ts.forEachChild(node, n => visit(ctx, n));
292
244
  }
293
245
  function visitArg(ctx, node) {
294
- if (ts.isIdentifier(node)) {
295
- if (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) {
246
+ if (ts.isIdentifier(node) && node.parent) {
247
+ if ((ts.isPropertyAccessExpression(node.parent) && node.parent.name === node) ||
248
+ (ts.isCallExpression(node.parent) && node.parent.expression === node)) {
296
249
  ts.forEachChild(node, n => visitArg(ctx, n));
297
250
  return;
298
251
  }
299
- if (ts.isCallExpression(node.parent) && node.parent.expression === node) {
300
- ts.forEachChild(node, n => visitArg(ctx, n));
301
- return;
302
- }
303
- let binding = findBinding(ctx.scopedBindings, node.text, node);
304
- if (binding) {
305
- ctx.neededImports.add('read');
252
+ if (findBinding(ctx.scopedBindings, node.text, node)) {
306
253
  ctx.innerReplacements.push({
307
254
  end: node.end - ctx.argStart,
308
- newText: `read(${node.text})`,
255
+ newText: `${ctx.ns}.read(${node.text})`,
309
256
  start: node.getStart(ctx.sourceFile) - ctx.argStart
310
257
  });
311
258
  }
312
259
  }
313
260
  ts.forEachChild(node, n => visitArg(ctx, n));
314
261
  }
315
- const transformReactivePrimitives = (sourceFile, bindings) => {
262
+ export default (sourceFile, bindings, ns) => {
316
263
  let code = sourceFile.getFullText(), ctx = {
317
264
  bindings,
318
265
  computedArgRanges: [],
319
266
  hasReactiveImport: false,
320
- neededImports: new Set(),
267
+ ns,
321
268
  replacements: [],
322
269
  scopedBindings: [],
323
- sourceFile
270
+ sourceFile,
271
+ tmpCounter: 0
324
272
  };
325
273
  visit(ctx, sourceFile);
326
274
  if (ctx.replacements.length === 0) {
327
275
  return code;
328
276
  }
329
- let result = applyReplacements(code, ctx.replacements);
330
- if (ctx.neededImports.size > 0) {
331
- result = addMissingImports(result, ctx.neededImports);
332
- }
333
- return result;
277
+ return c.replace(code, ctx.replacements);
334
278
  };
335
- export { transformReactivePrimitives };
package/build/types.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
2
- import { ReactiveArray, ReactiveObject } from './reactive/index.js';
3
2
  import { ts } from '@esportsplus/typescript';
4
3
  type BindingType = 'array' | 'computed' | 'object' | 'signal';
5
4
  type Bindings = Map<string, BindingType>;
@@ -25,6 +24,7 @@ interface Link {
25
24
  sub: Computed<unknown>;
26
25
  version: number;
27
26
  }
27
+ type Reactive<T> = T;
28
28
  type Signal<T> = {
29
29
  subs: Link | null;
30
30
  subsTail: Link | null;
@@ -36,4 +36,4 @@ interface TransformResult {
36
36
  sourceFile: ts.SourceFile;
37
37
  transformed: boolean;
38
38
  }
39
- export type { BindingType, Bindings, Computed, Link, ReactiveArray, ReactiveObject, Signal, TransformResult };
39
+ export type { BindingType, Bindings, Computed, Link, Reactive, Signal, TransformResult };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "@esportsplus/utilities": "^0.27.2"
5
5
  },
6
6
  "devDependencies": {
7
- "@esportsplus/typescript": "^0.17.3",
7
+ "@esportsplus/typescript": "^0.17.5",
8
8
  "@types/node": "^25.0.3",
9
9
  "vite": "^7.3.0"
10
10
  },
@@ -18,13 +18,13 @@
18
18
  "types": "./build/constants.d.ts"
19
19
  },
20
20
  "./plugins/tsc": {
21
+ "types": "./build/transformer/plugins/tsc.d.ts",
21
22
  "import": "./build/transformer/plugins/tsc.js",
22
- "require": "./build/transformer/plugins/tsc.js",
23
- "types": "./build/transformer/plugins/tsc.d.ts"
23
+ "require": "./build/transformer/plugins/tsc.js"
24
24
  },
25
25
  "./plugins/vite": {
26
- "import": "./build/transformer/plugins/vite.js",
27
- "types": "./build/transformer/plugins/vite.d.ts"
26
+ "types": "./build/transformer/plugins/vite.d.ts",
27
+ "import": "./build/transformer/plugins/vite.js"
28
28
  }
29
29
  },
30
30
  "main": "build/index.js",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "type": "module",
38
38
  "types": "build/index.d.ts",
39
- "version": "0.25.2",
39
+ "version": "0.25.4",
40
40
  "scripts": {
41
41
  "build": "tsc",
42
42
  "build:test": "pnpm build && vite build --config test/vite.config.ts",
package/readme.md CHANGED
@@ -107,7 +107,7 @@ The library requires a build-time transformer to convert `reactive()` calls into
107
107
  ```typescript
108
108
  // vite.config.ts
109
109
  import { defineConfig } from 'vite';
110
- import { plugin as reactivity } from '@esportsplus/reactivity/plugins/vite';
110
+ import reactivity from '@esportsplus/reactivity/plugins/vite';
111
111
 
112
112
  export default defineConfig({
113
113
  plugins: [
@@ -146,12 +146,12 @@ console.log(doubled);
146
146
 
147
147
  **Output:**
148
148
  ```typescript
149
- import { computed, read, set, signal } from '@esportsplus/reactivity';
149
+ import { computed, read, signal, write } from '@esportsplus/reactivity';
150
150
 
151
151
  let count = signal(0);
152
152
  let doubled = computed(() => read(count) * 2);
153
153
 
154
- set(count, 5);
154
+ write(count, 5);
155
155
  console.log(read(doubled));
156
156
  ```
157
157
 
@@ -172,7 +172,7 @@ class ReactiveObject_1 {
172
172
  #greeting = null;
173
173
 
174
174
  get name() { return read(this.#name); }
175
- set name(v) { set(this.#name, v); }
175
+ set name(v) { write(this.#name, v); }
176
176
  get greeting() { return read(this.#greeting ??= computed(() => `Hello, ${this.name}`)); }
177
177
 
178
178
  dispose() {
@@ -206,7 +206,7 @@ These are typically only used by the transformer output:
206
206
  | `signal(value)` | Creates a raw signal |
207
207
  | `computed(fn)` | Creates a raw computed |
208
208
  | `read(node)` | Reads a signal or computed value |
209
- | `set(signal, value)` | Sets a signal value |
209
+ | `write(signal, value)` | Sets a signal value |
210
210
  | `dispose(computed)` | Disposes a computed and its dependencies |
211
211
 
212
212
  ### Type Guards
package/src/constants.ts CHANGED
@@ -1,5 +1,20 @@
1
+ const COMPILATION_ENTRYPOINT = 'reactive';
2
+
3
+ const COMPILATION_ENTRYPOINT_REGEX = /\breactive\b/;
4
+
5
+ const COMPILATION_NAMESPACE = 'reactive';
6
+
7
+ const COMPILATION_TYPE_ARRAY = 'array';
8
+
9
+ const COMPILATION_TYPE_COMPUTED = 'computed';
10
+
11
+ const COMPILATION_TYPE_SIGNAL = 'signal';
12
+
13
+
1
14
  const COMPUTED = Symbol('reactivity.computed');
2
15
 
16
+ const PACKAGE = '@esportsplus/reactivity';
17
+
3
18
  const REACTIVE_ARRAY = Symbol('reactivity.reactive.array');
4
19
 
5
20
  const REACTIVE_OBJECT = Symbol('reactivity.reactive.object');
@@ -30,18 +45,10 @@ const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
30
45
 
31
46
 
32
47
  export {
33
- COMPUTED,
34
- REACTIVE_ARRAY,
35
- REACTIVE_OBJECT,
48
+ COMPILATION_TYPE_ARRAY, COMPILATION_TYPE_COMPUTED, COMPILATION_ENTRYPOINT, COMPILATION_ENTRYPOINT_REGEX, COMPILATION_NAMESPACE, COMPILATION_TYPE_SIGNAL, COMPUTED,
49
+ PACKAGE,
50
+ REACTIVE_ARRAY, REACTIVE_OBJECT,
36
51
  SIGNAL,
37
- STABILIZER_IDLE,
38
- STATE_NOTIFY_MASK,
39
- STABILIZER_RESCHEDULE,
40
- STABILIZER_RUNNING,
41
- STABILIZER_SCHEDULED,
42
- STATE_CHECK,
43
- STATE_DIRTY,
44
- STATE_IN_HEAP,
45
- STATE_NONE,
46
- STATE_RECOMPUTING
52
+ STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED,
53
+ STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING
47
54
  };