@signaltree/callable-syntax 4.0.6 → 4.0.9

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/LICENSE ADDED
@@ -0,0 +1,54 @@
1
+ BUSINESS SOURCE LICENSE 1.1
2
+
3
+ Copyright (c) 2025 Jonathan D Borgia
4
+
5
+ This Business Source License 1.1 ("License") governs the use of the software and associated documentation files (the "Software"). You are granted a limited license to use the Software under the terms of this License.
6
+
7
+ 1. Definitions
8
+
9
+ "Change Date" means the date on which the Change License set out in section 6 will apply to the Software. The Change Date for this release is 2028-09-05.
10
+
11
+ "Change License" means the open source license that will apply to the Software on and after the Change Date. The Change License for this release is the MIT License.
12
+
13
+ "Licensor" means the copyright owner granting rights under this License (Jonathan D Borgia).
14
+
15
+ "You" ("Licensee") means an individual or legal entity exercising rights under this License who has not violated the terms of this License or had their rights terminated.
16
+
17
+ 2. License Grant
18
+
19
+ Subject to the terms and conditions of this License, Licensor hereby grants You a non-exclusive, non-transferable, worldwide license to use, reproduce, display, perform, and distribute the Software, and to make modifications and derivative works for internal use, until the Change Date.
20
+
21
+ 3. Commercial Use
22
+
23
+ You may use the Software in commercial applications, including for providing services, selling products that include the Software, or otherwise exploiting the Software commercially, subject to the other terms of this License.
24
+
25
+ 4. Limitations and Conditions
26
+
27
+ a. You may not remove or alter this License, the copyright notice, or notices of the Change Date.
28
+
29
+ b. You may not publicly offer a modified version of the Software that would directly compete with Licensor's public offering of the Software if doing so would circumvent the intent of this License.
30
+
31
+ c. Except as expressly provided in this License, no rights are granted to You under any patent or trademark of Licensor.
32
+
33
+ 5. Disclaimer and Limitation of Liability
34
+
35
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. TO THE FULLEST EXTENT PERMITTED BY LAW, LICENSOR WILL NOT BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM OR RELATING TO THE SOFTWARE.
36
+
37
+ 6. Change License
38
+
39
+ On and after the Change Date specified above, the Software will be licensed under the Change License (MIT License) on the same terms and conditions as set forth by that Change License.
40
+
41
+ 7. Governing Law
42
+
43
+ This License will be governed by and construed in accordance with the laws of the State of New York, USA, without regard to conflict of law principles.
44
+
45
+ 8. Accepting this License
46
+
47
+ You accept this License by copying, modifying, or distributing the Software or any portion thereof.
48
+
49
+ ---
50
+
51
+ LICENSE NOTE
52
+
53
+ - Original license file replaced on 2025-09-05 to Business Source License 1.1. Change Date: 2028-09-05. Change License: MIT.
54
+ or standard modifications for your own applications.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaltree/callable-syntax",
3
- "version": "4.0.6",
3
+ "version": "4.0.9",
4
4
  "description": "Optional zero-runtime callable syntax transform for SignalTree unified leaf API.",
5
5
  "license": "BSL-1.1",
6
6
  "type": "commonjs",
@@ -47,12 +47,12 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@angular/core": "~20.3.0",
50
- "@signaltree/core": "4.0.2",
51
50
  "@types/babel__traverse": "^7.20.0",
52
51
  "@types/babel__generator": "^7.20.0",
53
52
  "@types/node": "^20.0.0",
54
53
  "vite": "^5.0.0",
55
54
  "webpack": "^5.90.0",
56
- "@types/webpack": "^5.28.0"
55
+ "@types/webpack": "^5.28.0",
56
+ "@signaltree/core": "4.0.9"
57
57
  }
58
58
  }
@@ -1 +1,10 @@
1
- export {};
1
+ import '@angular/core';
2
+
3
+ // Augment Angular WritableSignal so leaves support callable set/update like NodeAccessor.
4
+ // Getter signature already exists on WritableSignal.
5
+ declare module '@angular/core' {
6
+ interface WritableSignal<T> {
7
+ (value: T extends (...args: unknown[]) => unknown ? never : T): void;
8
+ (updater: (current: T) => T): void;
9
+ }
10
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TypeScript module augmentation for callable syntax support
3
+ * Since NodeAccessor already has callable signatures, we just need to ensure
4
+ * the types are properly imported and available.
5
+ *
6
+ * Note: The actual type import is commented out during build to avoid
7
+ * resolution issues. Users will import '@signaltree/core' in their own code.
8
+ */
9
+ // import type {} from '@signaltree/core';
10
+
11
+ // The existing NodeAccessor<T> interface in @signaltree/core already supports:
12
+ // - (): T // getter
13
+ // - (value: T): void // set
14
+ // - (updater: (current: T) => T): void // update
15
+
16
+ // This file ensures the types are available when imported
17
+ // The build-time transformer will handle the actual transformation
18
+
19
+ export {};
@@ -2,3 +2,4 @@ export * from './lib/ast-transform';
2
2
  export * from './lib/vite-plugin';
3
3
  export * from './lib/webpack-plugin';
4
4
  export * from './augmentation';
5
+ // Augmentation is exported behind a path; users can `import '@signaltree/callable-syntax/augmentation'` if desired.
@@ -0,0 +1,160 @@
1
+ import generate from '@babel/generator';
2
+ import { parse } from '@babel/parser';
3
+ import traverse from '@babel/traverse';
4
+ import * as t from '@babel/types';
5
+
6
+ export interface TransformOptions {
7
+ /** Root variable names that contain SignalTree instances (default: ['tree']) */
8
+ readonly rootIdentifiers?: string[];
9
+ /** Enable debug logging for transformed calls */
10
+ readonly debug?: boolean;
11
+ }
12
+
13
+ export interface TransformResult {
14
+ /** The transformed code */
15
+ code: string;
16
+ /** Number of calls that were transformed */
17
+ transformed: number;
18
+ }
19
+
20
+ export const DEFAULT_ROOT_IDENTIFIERS = ['tree'];
21
+
22
+ /**
23
+ * Transforms SignalTree callable syntax to explicit .set/.update method calls
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // Input:
28
+ * tree.$.user.name('John');
29
+ * tree.$.count(n => n + 1);
30
+ *
31
+ * // Output:
32
+ * tree.$.user.name.set('John');
33
+ * tree.$.count.update(n => n + 1);
34
+ * ```
35
+ */
36
+ export function transformCode(
37
+ source: string,
38
+ options: TransformOptions = {}
39
+ ): TransformResult {
40
+ const rootIds = options.rootIdentifiers?.length
41
+ ? options.rootIdentifiers
42
+ : DEFAULT_ROOT_IDENTIFIERS;
43
+ const ast = parseSourceCode(source);
44
+ let transformCount = 0;
45
+
46
+ traverse(ast, {
47
+ CallExpression(path) {
48
+ const { node } = path;
49
+ if (!t.isCallExpression(node)) return;
50
+
51
+ if (shouldTransformCallExpression(node, rootIds)) {
52
+ const transformedCall = createTransformedCall(node);
53
+ path.replaceWith(transformedCall);
54
+ transformCount++;
55
+ }
56
+ },
57
+ });
58
+
59
+ const output = generate(ast, { retainLines: false, comments: true }, source);
60
+
61
+ if (options.debug && transformCount > 0) {
62
+ console.log(
63
+ `[signaltree callable-syntax] transformed ${transformCount} calls`
64
+ );
65
+ }
66
+
67
+ return { code: output.code, transformed: transformCount };
68
+ }
69
+
70
+ /**
71
+ * Parses TypeScript/JSX source code into an AST
72
+ */
73
+ function parseSourceCode(source: string): t.File {
74
+ return parse(source, {
75
+ sourceType: 'module',
76
+ plugins: ['typescript', 'jsx'],
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Determines if a call expression should be transformed
82
+ */
83
+ function shouldTransformCallExpression(
84
+ node: t.CallExpression,
85
+ rootIds: string[]
86
+ ): boolean {
87
+ // Must be a member expression call (e.g., obj.prop())
88
+ if (!t.isMemberExpression(node.callee)) return false;
89
+
90
+ // Skip getter calls (no arguments)
91
+ if (node.arguments.length === 0) return false;
92
+
93
+ // Skip if already calling .set or .update
94
+ if (isAlreadyTransformed(node.callee)) return false;
95
+
96
+ // Must be accessing a signal from one of the root identifiers
97
+ return isRootedSignalAccess(node.callee, rootIds);
98
+ }
99
+
100
+ /**
101
+ * Checks if the call is already transformed (.set or .update)
102
+ */
103
+ function isAlreadyTransformed(callee: t.MemberExpression): boolean {
104
+ return (
105
+ t.isIdentifier(callee.property) &&
106
+ (callee.property.name === 'set' || callee.property.name === 'update')
107
+ );
108
+ }
109
+
110
+ /**
111
+ * Creates the transformed call expression with .set or .update
112
+ */
113
+ function createTransformedCall(node: t.CallExpression): t.CallExpression {
114
+ const callee = node.callee as t.MemberExpression;
115
+ const method = determineMethod(node.arguments[0]);
116
+
117
+ return t.callExpression(
118
+ t.memberExpression(callee, t.identifier(method)),
119
+ node.arguments as t.Expression[]
120
+ );
121
+ }
122
+
123
+ /**
124
+ * Determines whether to use 'set' or 'update' based on the argument type
125
+ */
126
+ function determineMethod(
127
+ firstArg:
128
+ | t.Expression
129
+ | t.SpreadElement
130
+ | t.JSXNamespacedName
131
+ | t.ArgumentPlaceholder
132
+ ): 'set' | 'update' {
133
+ if (
134
+ t.isFunctionExpression(firstArg) ||
135
+ t.isArrowFunctionExpression(firstArg)
136
+ ) {
137
+ return 'update';
138
+ }
139
+ return 'set';
140
+ }
141
+
142
+ /**
143
+ * Checks if the member expression ultimately accesses a signal from a root identifier
144
+ */
145
+ function isRootedSignalAccess(
146
+ expr: t.MemberExpression,
147
+ roots: string[]
148
+ ): boolean {
149
+ let current: t.MemberExpression | t.Expression = expr;
150
+
151
+ // Traverse up the member expression chain to find the root identifier
152
+ while (t.isMemberExpression(current)) {
153
+ if (t.isIdentifier(current.object)) {
154
+ return roots.includes(current.object.name);
155
+ }
156
+ current = current.object as t.Expression;
157
+ }
158
+
159
+ return false;
160
+ }
@@ -0,0 +1,65 @@
1
+ import { transformCode } from './ast-transform';
2
+
3
+ describe('ast transform', () => {
4
+ it('transforms set calls', () => {
5
+ const src = `tree.$.user.name('John');`;
6
+ const { code, transformed } = transformCode(src, {
7
+ rootIdentifiers: ['tree'],
8
+ });
9
+ expect(code).toContain("tree.$.user.name.set('John')");
10
+ expect(transformed).toBe(1);
11
+ });
12
+ it('transforms update calls', () => {
13
+ const src = `tree.$.count(n => n + 1);`;
14
+ const { code, transformed } = transformCode(src, {
15
+ rootIdentifiers: ['tree'],
16
+ });
17
+ expect(code).toContain('tree.$.count.update');
18
+ expect(transformed).toBe(1);
19
+ });
20
+ it('leaves getters untouched', () => {
21
+ const src = `const v = tree.$.count();`;
22
+ const { code, transformed } = transformCode(src, {
23
+ rootIdentifiers: ['tree'],
24
+ });
25
+ expect(code).toContain('tree.$.count()');
26
+ expect(transformed).toBe(0);
27
+ });
28
+
29
+ it('transforms calls on additional root identifiers (e.g., store)', () => {
30
+ const src = `store.$.todos([{ id: 1 }]);
31
+ store.$.todos(items => items);
32
+ const x = store.$.todos();`;
33
+ const { code, transformed } = transformCode(src, {
34
+ rootIdentifiers: ['tree', 'store'],
35
+ });
36
+ // pretty-printer may add whitespace/newlines inside arrays/objects
37
+ expect(code).toMatch(/store\.\$\.todos\.set\(\[\{\s*id:\s*1\s*\}\]\)/);
38
+ expect(code).toContain('store.$.todos.update');
39
+ expect(code).toContain('store.$.todos()');
40
+ expect(transformed).toBe(2);
41
+ });
42
+
43
+ it('does not double-transform already .set/.update calls', () => {
44
+ const src = `tree.$.count.set(1);
45
+ tree.$.count.update(n => n + 1);`;
46
+ const { code, transformed } = transformCode(src, {
47
+ rootIdentifiers: ['tree'],
48
+ });
49
+ expect(code).toContain('tree.$.count.set(1)');
50
+ expect(code).toContain('tree.$.count.update');
51
+ expect(transformed).toBe(0);
52
+ });
53
+
54
+ it('does not transform optional-chaining calls (documented limitation)', () => {
55
+ const src = `tree?.$.user?.name('Alice');
56
+ const v = tree?.$.user?.name();`;
57
+ const { code, transformed } = transformCode(src, {
58
+ rootIdentifiers: ['tree'],
59
+ });
60
+ // Current algorithm only matches CallExpression with MemberExpression callee (no optional chain)
61
+ expect(code).toContain("tree?.$.user?.name('Alice')");
62
+ expect(code).toContain('tree?.$.user?.name()');
63
+ expect(transformed).toBe(0);
64
+ });
65
+ });
@@ -0,0 +1,2 @@
1
+ // Deprecated placeholder kept to avoid breaking the initial test; actual exports moved.
2
+ export const syntaxTransform = () => 'callable-syntax';
@@ -0,0 +1,36 @@
1
+ import { transformCode } from './ast-transform';
2
+
3
+ // Vite types are optional; fall back to minimal shape if not installed.
4
+ // Declare a lightweight Plugin interface to avoid hard dependency if types unavailable.
5
+ type Plugin = {
6
+ name: string;
7
+ enforce?: 'pre' | 'post';
8
+ transform?: (code: string, id: string) => { code: string; map: null } | null;
9
+ };
10
+ export interface SignalTreeVitePluginOptions {
11
+ include?: RegExp;
12
+ exclude?: RegExp;
13
+ rootIdentifiers?: string[];
14
+ debug?: boolean;
15
+ }
16
+
17
+ export function signalTreeSyntaxTransform(
18
+ options: SignalTreeVitePluginOptions = {}
19
+ ): Plugin {
20
+ const include = options.include ?? /src\/.*\.(t|j)sx?$/;
21
+ const exclude = options.exclude ?? /node_modules|\.spec\.|\.test\./;
22
+
23
+ return {
24
+ name: 'signaltree-callable-syntax',
25
+ enforce: 'pre',
26
+ transform(code: string, id: string) {
27
+ if (!include.test(id) || exclude.test(id)) return null;
28
+ const result = transformCode(code, {
29
+ rootIdentifiers: options.rootIdentifiers,
30
+ debug: options.debug,
31
+ });
32
+ if (result.transformed === 0) return null;
33
+ return { code: result.code, map: null };
34
+ },
35
+ };
36
+ }
@@ -0,0 +1,67 @@
1
+ import { transformCode } from './ast-transform';
2
+
3
+ // Lightweight fallbacks so users without webpack types still compile.
4
+ interface CompilationLike {
5
+ assets: Record<string, { source(): unknown; size(): number }>;
6
+ }
7
+ interface CompilerLike {
8
+ hooks: {
9
+ emit: {
10
+ tapAsync(
11
+ name: string,
12
+ cb: (compilation: CompilationLike, done: (err?: Error) => void) => void
13
+ ): void;
14
+ };
15
+ };
16
+ }
17
+
18
+ export interface SignalTreeWebpackPluginOptions {
19
+ test?: RegExp;
20
+ exclude?: RegExp;
21
+ rootIdentifiers?: string[];
22
+ debug?: boolean;
23
+ }
24
+
25
+ export class SignalTreeSyntaxWebpackPlugin {
26
+ constructor(private readonly options: SignalTreeWebpackPluginOptions = {}) {}
27
+
28
+ apply(compiler: CompilerLike) {
29
+ const test = this.options.test ?? /src\/.*\.(t|j)sx?$/;
30
+ const exclude = this.options.exclude ?? /node_modules|\.spec\.|\.test\./;
31
+
32
+ compiler.hooks.emit.tapAsync(
33
+ 'SignalTreeSyntaxWebpackPlugin',
34
+ (compilation: CompilationLike, cb: (err?: Error) => void) => {
35
+ for (const filename of Object.keys(compilation.assets)) {
36
+ if (!test.test(filename) || exclude.test(filename)) continue;
37
+ const asset = compilation.assets[filename];
38
+ const raw = asset.source();
39
+
40
+ // Handle different source types from webpack assets
41
+ let source: string;
42
+ if (typeof raw === 'string') {
43
+ source = raw;
44
+ } else if (Buffer.isBuffer(raw)) {
45
+ source = raw.toString('utf8');
46
+ } else {
47
+ source = String(raw);
48
+ }
49
+
50
+ const { code, transformed } = transformCode(source, {
51
+ rootIdentifiers: this.options.rootIdentifiers,
52
+ debug: this.options.debug,
53
+ });
54
+ if (transformed > 0) {
55
+ const updated = code;
56
+ // Webpack 5 source compatibility minimal implementation
57
+ compilation.assets[filename] = {
58
+ source: () => updated,
59
+ size: () => Buffer.byteLength(updated, 'utf8'),
60
+ };
61
+ }
62
+ }
63
+ cb();
64
+ }
65
+ );
66
+ }
67
+ }
@@ -0,0 +1,31 @@
1
+ // Fallback declarations for Babel modules in case @types packages are missing.
2
+ // These are minimal and only to satisfy TypeScript when types cannot be resolved.
3
+ // They will be ignored if proper @types are installed.
4
+
5
+ declare module '@babel/generator' {
6
+ import type { Node } from '@babel/types';
7
+ interface GeneratorOptions {
8
+ retainLines?: boolean;
9
+ comments?: boolean;
10
+ }
11
+ interface GeneratorResult {
12
+ code: string;
13
+ map?: unknown;
14
+ }
15
+ export default function generate(
16
+ ast: Node,
17
+ options?: GeneratorOptions,
18
+ code?: string
19
+ ): GeneratorResult;
20
+ }
21
+
22
+ declare module '@babel/traverse' {
23
+ import type { Node } from '@babel/types';
24
+ export interface NodePath<T = Node> {
25
+ node: T;
26
+ replaceWith(node: Node): void;
27
+ }
28
+ export type VisitorFn<T = Node> = (path: NodePath<T>) => void;
29
+ export type Visitor = Record<string, VisitorFn>;
30
+ export default function traverse(ast: Node, options: Visitor): void;
31
+ }
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=augmentation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"augmentation.js","sourceRoot":"","sources":["../../../../packages/callable-syntax/src/augmentation.ts"],"names":[],"mappings":""}
package/src/index.js DELETED
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./lib/ast-transform"), exports);
5
- tslib_1.__exportStar(require("./lib/vite-plugin"), exports);
6
- tslib_1.__exportStar(require("./lib/webpack-plugin"), exports);
7
- tslib_1.__exportStar(require("./augmentation"), exports);
8
- // Augmentation is exported behind a path; users can `import '@signaltree/callable-syntax/augmentation'` if desired.
9
- //# sourceMappingURL=index.js.map
package/src/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/callable-syntax/src/index.ts"],"names":[],"mappings":";;;AAAA,8DAAoC;AACpC,4DAAkC;AAClC,+DAAqC;AACrC,yDAA+B;AAC/B,oHAAoH"}
@@ -1,28 +0,0 @@
1
- export interface TransformOptions {
2
- /** Root variable names that contain SignalTree instances (default: ['tree']) */
3
- readonly rootIdentifiers?: string[];
4
- /** Enable debug logging for transformed calls */
5
- readonly debug?: boolean;
6
- }
7
- export interface TransformResult {
8
- /** The transformed code */
9
- code: string;
10
- /** Number of calls that were transformed */
11
- transformed: number;
12
- }
13
- export declare const DEFAULT_ROOT_IDENTIFIERS: string[];
14
- /**
15
- * Transforms SignalTree callable syntax to explicit .set/.update method calls
16
- *
17
- * @example
18
- * ```typescript
19
- * // Input:
20
- * tree.$.user.name('John');
21
- * tree.$.count(n => n + 1);
22
- *
23
- * // Output:
24
- * tree.$.user.name.set('John');
25
- * tree.$.count.update(n => n + 1);
26
- * ```
27
- */
28
- export declare function transformCode(source: string, options?: TransformOptions): TransformResult;
@@ -1,114 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_ROOT_IDENTIFIERS = void 0;
4
- exports.transformCode = transformCode;
5
- const tslib_1 = require("tslib");
6
- const generator_1 = tslib_1.__importDefault(require("@babel/generator"));
7
- const parser_1 = require("@babel/parser");
8
- const traverse_1 = tslib_1.__importDefault(require("@babel/traverse"));
9
- const t = tslib_1.__importStar(require("@babel/types"));
10
- exports.DEFAULT_ROOT_IDENTIFIERS = ['tree'];
11
- /**
12
- * Transforms SignalTree callable syntax to explicit .set/.update method calls
13
- *
14
- * @example
15
- * ```typescript
16
- * // Input:
17
- * tree.$.user.name('John');
18
- * tree.$.count(n => n + 1);
19
- *
20
- * // Output:
21
- * tree.$.user.name.set('John');
22
- * tree.$.count.update(n => n + 1);
23
- * ```
24
- */
25
- function transformCode(source, options = {}) {
26
- var _a;
27
- const rootIds = ((_a = options.rootIdentifiers) === null || _a === void 0 ? void 0 : _a.length)
28
- ? options.rootIdentifiers
29
- : exports.DEFAULT_ROOT_IDENTIFIERS;
30
- const ast = parseSourceCode(source);
31
- let transformCount = 0;
32
- (0, traverse_1.default)(ast, {
33
- CallExpression(path) {
34
- const { node } = path;
35
- if (!t.isCallExpression(node))
36
- return;
37
- if (shouldTransformCallExpression(node, rootIds)) {
38
- const transformedCall = createTransformedCall(node);
39
- path.replaceWith(transformedCall);
40
- transformCount++;
41
- }
42
- },
43
- });
44
- const output = (0, generator_1.default)(ast, { retainLines: false, comments: true }, source);
45
- if (options.debug && transformCount > 0) {
46
- console.log(`[signaltree callable-syntax] transformed ${transformCount} calls`);
47
- }
48
- return { code: output.code, transformed: transformCount };
49
- }
50
- /**
51
- * Parses TypeScript/JSX source code into an AST
52
- */
53
- function parseSourceCode(source) {
54
- return (0, parser_1.parse)(source, {
55
- sourceType: 'module',
56
- plugins: ['typescript', 'jsx'],
57
- });
58
- }
59
- /**
60
- * Determines if a call expression should be transformed
61
- */
62
- function shouldTransformCallExpression(node, rootIds) {
63
- // Must be a member expression call (e.g., obj.prop())
64
- if (!t.isMemberExpression(node.callee))
65
- return false;
66
- // Skip getter calls (no arguments)
67
- if (node.arguments.length === 0)
68
- return false;
69
- // Skip if already calling .set or .update
70
- if (isAlreadyTransformed(node.callee))
71
- return false;
72
- // Must be accessing a signal from one of the root identifiers
73
- return isRootedSignalAccess(node.callee, rootIds);
74
- }
75
- /**
76
- * Checks if the call is already transformed (.set or .update)
77
- */
78
- function isAlreadyTransformed(callee) {
79
- return (t.isIdentifier(callee.property) &&
80
- (callee.property.name === 'set' || callee.property.name === 'update'));
81
- }
82
- /**
83
- * Creates the transformed call expression with .set or .update
84
- */
85
- function createTransformedCall(node) {
86
- const callee = node.callee;
87
- const method = determineMethod(node.arguments[0]);
88
- return t.callExpression(t.memberExpression(callee, t.identifier(method)), node.arguments);
89
- }
90
- /**
91
- * Determines whether to use 'set' or 'update' based on the argument type
92
- */
93
- function determineMethod(firstArg) {
94
- if (t.isFunctionExpression(firstArg) ||
95
- t.isArrowFunctionExpression(firstArg)) {
96
- return 'update';
97
- }
98
- return 'set';
99
- }
100
- /**
101
- * Checks if the member expression ultimately accesses a signal from a root identifier
102
- */
103
- function isRootedSignalAccess(expr, roots) {
104
- let current = expr;
105
- // Traverse up the member expression chain to find the root identifier
106
- while (t.isMemberExpression(current)) {
107
- if (t.isIdentifier(current.object)) {
108
- return roots.includes(current.object.name);
109
- }
110
- current = current.object;
111
- }
112
- return false;
113
- }
114
- //# sourceMappingURL=ast-transform.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ast-transform.js","sourceRoot":"","sources":["../../../../../packages/callable-syntax/src/lib/ast-transform.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- export declare const syntaxTransform: () => string;
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.syntaxTransform = void 0;
4
- // Deprecated placeholder kept to avoid breaking the initial test; actual exports moved.
5
- const syntaxTransform = () => 'callable-syntax';
6
- exports.syntaxTransform = syntaxTransform;
7
- //# sourceMappingURL=syntax-transform.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"syntax-transform.js","sourceRoot":"","sources":["../../../../../packages/callable-syntax/src/lib/syntax-transform.ts"],"names":[],"mappings":";;;AAAA,wFAAwF;AACjF,MAAM,eAAe,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC;AAA1C,QAAA,eAAe,mBAA2B"}
@@ -1,16 +0,0 @@
1
- type Plugin = {
2
- name: string;
3
- enforce?: 'pre' | 'post';
4
- transform?: (code: string, id: string) => {
5
- code: string;
6
- map: null;
7
- } | null;
8
- };
9
- export interface SignalTreeVitePluginOptions {
10
- include?: RegExp;
11
- exclude?: RegExp;
12
- rootIdentifiers?: string[];
13
- debug?: boolean;
14
- }
15
- export declare function signalTreeSyntaxTransform(options?: SignalTreeVitePluginOptions): Plugin;
16
- export {};
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.signalTreeSyntaxTransform = signalTreeSyntaxTransform;
4
- const ast_transform_1 = require("./ast-transform");
5
- function signalTreeSyntaxTransform(options = {}) {
6
- var _a, _b;
7
- const include = (_a = options.include) !== null && _a !== void 0 ? _a : /src\/.*\.(t|j)sx?$/;
8
- const exclude = (_b = options.exclude) !== null && _b !== void 0 ? _b : /node_modules|\.spec\.|\.test\./;
9
- return {
10
- name: 'signaltree-callable-syntax',
11
- enforce: 'pre',
12
- transform(code, id) {
13
- if (!include.test(id) || exclude.test(id))
14
- return null;
15
- const result = (0, ast_transform_1.transformCode)(code, {
16
- rootIdentifiers: options.rootIdentifiers,
17
- debug: options.debug,
18
- });
19
- if (result.transformed === 0)
20
- return null;
21
- return { code: result.code, map: null };
22
- },
23
- };
24
- }
25
- //# sourceMappingURL=vite-plugin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite-plugin.js","sourceRoot":"","sources":["../../../../../packages/callable-syntax/src/lib/vite-plugin.ts"],"names":[],"mappings":";;AAgBA,8DAmBC;AAnCD,mDAAgD;AAgBhD,SAAgB,yBAAyB,CACvC,UAAuC,EAAE;;IAEzC,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,OAAO,mCAAI,oBAAoB,CAAC;IACxD,MAAM,OAAO,GAAG,MAAA,OAAO,CAAC,OAAO,mCAAI,gCAAgC,CAAC;IAEpE,OAAO;QACL,IAAI,EAAE,4BAA4B;QAClC,OAAO,EAAE,KAAK;QACd,SAAS,CAAC,IAAY,EAAE,EAAU;YAChC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,OAAO,IAAI,CAAC;YACvD,MAAM,MAAM,GAAG,IAAA,6BAAa,EAAC,IAAI,EAAE;gBACjC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,KAAK,EAAE,OAAO,CAAC,KAAK;aACrB,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -1,25 +0,0 @@
1
- interface CompilationLike {
2
- assets: Record<string, {
3
- source(): unknown;
4
- size(): number;
5
- }>;
6
- }
7
- interface CompilerLike {
8
- hooks: {
9
- emit: {
10
- tapAsync(name: string, cb: (compilation: CompilationLike, done: (err?: Error) => void) => void): void;
11
- };
12
- };
13
- }
14
- export interface SignalTreeWebpackPluginOptions {
15
- test?: RegExp;
16
- exclude?: RegExp;
17
- rootIdentifiers?: string[];
18
- debug?: boolean;
19
- }
20
- export declare class SignalTreeSyntaxWebpackPlugin {
21
- private readonly options;
22
- constructor(options?: SignalTreeWebpackPluginOptions);
23
- apply(compiler: CompilerLike): void;
24
- }
25
- export {};
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SignalTreeSyntaxWebpackPlugin = void 0;
4
- const ast_transform_1 = require("./ast-transform");
5
- class SignalTreeSyntaxWebpackPlugin {
6
- constructor(options = {}) {
7
- this.options = options;
8
- }
9
- apply(compiler) {
10
- var _a, _b;
11
- const test = (_a = this.options.test) !== null && _a !== void 0 ? _a : /src\/.*\.(t|j)sx?$/;
12
- const exclude = (_b = this.options.exclude) !== null && _b !== void 0 ? _b : /node_modules|\.spec\.|\.test\./;
13
- compiler.hooks.emit.tapAsync('SignalTreeSyntaxWebpackPlugin', (compilation, cb) => {
14
- for (const filename of Object.keys(compilation.assets)) {
15
- if (!test.test(filename) || exclude.test(filename))
16
- continue;
17
- const asset = compilation.assets[filename];
18
- const raw = asset.source();
19
- // Handle different source types from webpack assets
20
- let source;
21
- if (typeof raw === 'string') {
22
- source = raw;
23
- }
24
- else if (Buffer.isBuffer(raw)) {
25
- source = raw.toString('utf8');
26
- }
27
- else {
28
- source = String(raw);
29
- }
30
- const { code, transformed } = (0, ast_transform_1.transformCode)(source, {
31
- rootIdentifiers: this.options.rootIdentifiers,
32
- debug: this.options.debug,
33
- });
34
- if (transformed > 0) {
35
- const updated = code;
36
- // Webpack 5 source compatibility minimal implementation
37
- compilation.assets[filename] = {
38
- source: () => updated,
39
- size: () => Buffer.byteLength(updated, 'utf8'),
40
- };
41
- }
42
- }
43
- cb();
44
- });
45
- }
46
- }
47
- exports.SignalTreeSyntaxWebpackPlugin = SignalTreeSyntaxWebpackPlugin;
48
- //# sourceMappingURL=webpack-plugin.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webpack-plugin.js","sourceRoot":"","sources":["../../../../../packages/callable-syntax/src/lib/webpack-plugin.ts"],"names":[],"mappings":";;;AAAA,mDAAgD;AAwBhD,MAAa,6BAA6B;IACxC,YAA6B,UAA0C,EAAE;QAA5C,YAAO,GAAP,OAAO,CAAqC;IAAG,CAAC;IAE7E,KAAK,CAAC,QAAsB;;QAC1B,MAAM,IAAI,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,IAAI,mCAAI,oBAAoB,CAAC;QACvD,MAAM,OAAO,GAAG,MAAA,IAAI,CAAC,OAAO,CAAC,OAAO,mCAAI,gCAAgC,CAAC;QAEzE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAC1B,+BAA+B,EAC/B,CAAC,WAA4B,EAAE,EAAyB,EAAE,EAAE;YAC1D,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC;oBAAE,SAAS;gBAC7D,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAC3C,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBAE3B,oDAAoD;gBACpD,IAAI,MAAc,CAAC;gBACnB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;oBAC5B,MAAM,GAAG,GAAG,CAAC;gBACf,CAAC;qBAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBAChC,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;gBAED,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAA,6BAAa,EAAC,MAAM,EAAE;oBAClD,eAAe,EAAE,IAAI,CAAC,OAAO,CAAC,eAAe;oBAC7C,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK;iBAC1B,CAAC,CAAC;gBACH,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;oBACpB,MAAM,OAAO,GAAG,IAAI,CAAC;oBACrB,wDAAwD;oBACxD,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG;wBAC7B,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO;wBACrB,IAAI,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;qBAC/C,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,EAAE,EAAE,CAAC;QACP,CAAC,CACF,CAAC;IACJ,CAAC;CACF;AA1CD,sEA0CC"}