zero-com 1.6.4 → 1.6.5
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/lib/common.d.ts +19 -5
- package/lib/common.js +83 -39
- package/lib/rollup.js +4 -3
- package/lib/runtime.d.ts +2 -2
- package/lib/runtime.js +22 -11
- package/lib/webpack-loader.d.ts +2 -1
- package/lib/webpack-loader.js +6 -3
- package/lib/webpack.js +1 -1
- package/package.json +2 -1
package/lib/common.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import type { SourceMap } from 'magic-string';
|
|
1
2
|
import { CallExpression, Project, SourceFile } from 'ts-morph';
|
|
3
|
+
export type Replacement = {
|
|
4
|
+
start: number;
|
|
5
|
+
end: number;
|
|
6
|
+
content: string;
|
|
7
|
+
};
|
|
2
8
|
export type Options = {
|
|
3
9
|
development?: boolean;
|
|
4
10
|
};
|
|
@@ -28,15 +34,23 @@ export declare const resolveFilePath: (basePath: string) => string;
|
|
|
28
34
|
export declare const createProject: () => Project;
|
|
29
35
|
export declare const buildRegistry: (contextDir: string, registry: ServerFuncRegistry) => void;
|
|
30
36
|
export declare const getImportedServerFunctions: (sourceFile: SourceFile, registry: ServerFuncRegistry) => Map<string, ServerFuncInfo>;
|
|
31
|
-
export declare const
|
|
32
|
-
export declare const
|
|
33
|
-
export declare const
|
|
34
|
-
export declare const
|
|
37
|
+
export declare const collectCallSiteReplacements: (sourceFile: SourceFile, importedFuncs: Map<string, ServerFuncInfo>) => Replacement[];
|
|
38
|
+
export declare const collectHandleCallReplacements: (sourceFile: SourceFile) => Replacement[];
|
|
39
|
+
export declare const collectSendCallReplacements: (sourceFile: SourceFile) => Replacement[];
|
|
40
|
+
export declare const collectFuncCallReplacements: (sourceFile: SourceFile) => Replacement[];
|
|
41
|
+
export declare const applyReplacementsWithMap: (source: string, replacements: Replacement[], filePath: string) => {
|
|
42
|
+
code: string;
|
|
43
|
+
map: SourceMap;
|
|
44
|
+
};
|
|
35
45
|
export declare const appendRegistryCode: (sourceFile: SourceFile, fileRegistry: Map<string, ServerFuncInfo>) => string;
|
|
36
46
|
export type TransformResult = {
|
|
37
47
|
content: string;
|
|
38
48
|
transformed: boolean;
|
|
49
|
+
map?: SourceMap;
|
|
50
|
+
};
|
|
51
|
+
export type TransformOptions = {
|
|
52
|
+
development?: boolean;
|
|
39
53
|
};
|
|
40
|
-
export declare const transformSourceFile: (filePath: string, content: string, registry: ServerFuncRegistry) => TransformResult;
|
|
54
|
+
export declare const transformSourceFile: (filePath: string, content: string, registry: ServerFuncRegistry, options?: TransformOptions) => TransformResult;
|
|
41
55
|
export declare const emitToJs: (filePath: string, content: string) => string;
|
|
42
56
|
export declare const applyReplacements: (code: string, compilationId: string) => string;
|
package/lib/common.js
CHANGED
|
@@ -3,9 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.applyReplacements = exports.emitToJs = exports.transformSourceFile = exports.appendRegistryCode = exports.
|
|
6
|
+
exports.applyReplacements = exports.emitToJs = exports.transformSourceFile = exports.appendRegistryCode = exports.applyReplacementsWithMap = exports.collectFuncCallReplacements = exports.collectSendCallReplacements = exports.collectHandleCallReplacements = exports.collectCallSiteReplacements = exports.getImportedServerFunctions = exports.buildRegistry = exports.createProject = exports.resolveFilePath = exports.isFromLibrary = exports.getReplacements = exports.generateCompilationId = exports.formatFuncIdName = exports.FILE_EXTENSIONS = exports.LIBRARY_NAME = exports.CONTEXT_TYPE_NAME = exports.CALL_NAME = exports.HANDLE_NAME = exports.SERVER_FUNCTION_WRAPPER_NAME = exports.ZERO_COM_SERVER_REGISTRY = exports.ZERO_COM_CLIENT_CALL = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const magic_string_1 = __importDefault(require("magic-string"));
|
|
9
10
|
const ts_morph_1 = require("ts-morph");
|
|
10
11
|
// Constants
|
|
11
12
|
exports.ZERO_COM_CLIENT_CALL = 'ZERO_COM_CLIENT_CALL';
|
|
@@ -153,11 +154,11 @@ const getImportedServerFunctions = (sourceFile, registry) => {
|
|
|
153
154
|
return importedFuncs;
|
|
154
155
|
};
|
|
155
156
|
exports.getImportedServerFunctions = getImportedServerFunctions;
|
|
156
|
-
// Transformations
|
|
157
|
-
const
|
|
157
|
+
// Transformations - collect replacements instead of modifying AST
|
|
158
|
+
const collectCallSiteReplacements = (sourceFile, importedFuncs) => {
|
|
158
159
|
if (importedFuncs.size === 0)
|
|
159
|
-
return
|
|
160
|
-
|
|
160
|
+
return [];
|
|
161
|
+
const replacements = [];
|
|
161
162
|
sourceFile.forEachDescendant((node) => {
|
|
162
163
|
if (node.getKind() !== ts_morph_1.SyntaxKind.CallExpression)
|
|
163
164
|
return;
|
|
@@ -167,14 +168,17 @@ const transformCallSites = (sourceFile, importedFuncs) => {
|
|
|
167
168
|
if (!funcInfo)
|
|
168
169
|
return;
|
|
169
170
|
const args = callExpr.getArguments().map(a => a.getText()).join(', ');
|
|
170
|
-
|
|
171
|
-
|
|
171
|
+
replacements.push({
|
|
172
|
+
start: callExpr.getStart(),
|
|
173
|
+
end: callExpr.getEnd(),
|
|
174
|
+
content: `globalThis.${exports.ZERO_COM_CLIENT_CALL}('${funcInfo.funcId}', [${args}])`
|
|
175
|
+
});
|
|
172
176
|
});
|
|
173
|
-
return
|
|
177
|
+
return replacements;
|
|
174
178
|
};
|
|
175
|
-
exports.
|
|
176
|
-
const
|
|
177
|
-
|
|
179
|
+
exports.collectCallSiteReplacements = collectCallSiteReplacements;
|
|
180
|
+
const collectHandleCallReplacements = (sourceFile) => {
|
|
181
|
+
const replacements = [];
|
|
178
182
|
sourceFile.forEachDescendant((node) => {
|
|
179
183
|
if (node.getKind() !== ts_morph_1.SyntaxKind.CallExpression)
|
|
180
184
|
return;
|
|
@@ -184,18 +188,20 @@ const transformHandleCalls = (sourceFile) => {
|
|
|
184
188
|
const args = callExpr.getArguments();
|
|
185
189
|
if (args.length < 3)
|
|
186
190
|
return;
|
|
187
|
-
// Inline the logic directly using a named function for better stack traces.
|
|
188
191
|
const funcId = args[0].getText();
|
|
189
192
|
const ctx = args[1].getText();
|
|
190
193
|
const argsArray = args[2].getText();
|
|
191
|
-
|
|
192
|
-
|
|
194
|
+
replacements.push({
|
|
195
|
+
start: callExpr.getStart(),
|
|
196
|
+
end: callExpr.getEnd(),
|
|
197
|
+
content: `((__fn) => __fn.requireContext ? __fn(${ctx}, ...${argsArray}) : __fn(...${argsArray}))(globalThis.${exports.ZERO_COM_SERVER_REGISTRY}[${funcId}])`
|
|
198
|
+
});
|
|
193
199
|
});
|
|
194
|
-
return
|
|
200
|
+
return replacements;
|
|
195
201
|
};
|
|
196
|
-
exports.
|
|
197
|
-
const
|
|
198
|
-
|
|
202
|
+
exports.collectHandleCallReplacements = collectHandleCallReplacements;
|
|
203
|
+
const collectSendCallReplacements = (sourceFile) => {
|
|
204
|
+
const replacements = [];
|
|
199
205
|
sourceFile.forEachDescendant((node) => {
|
|
200
206
|
if (node.getKind() !== ts_morph_1.SyntaxKind.CallExpression)
|
|
201
207
|
return;
|
|
@@ -205,18 +211,21 @@ const transformSendCalls = (sourceFile) => {
|
|
|
205
211
|
const args = callExpr.getArguments();
|
|
206
212
|
if (args.length < 1)
|
|
207
213
|
return;
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
replacements.push({
|
|
215
|
+
start: callExpr.getStart(),
|
|
216
|
+
end: callExpr.getEnd(),
|
|
217
|
+
content: `globalThis.${exports.ZERO_COM_CLIENT_CALL} = ${args[0].getText()}`
|
|
218
|
+
});
|
|
210
219
|
});
|
|
211
|
-
return
|
|
220
|
+
return replacements;
|
|
212
221
|
};
|
|
213
|
-
exports.
|
|
214
|
-
//
|
|
222
|
+
exports.collectSendCallReplacements = collectSendCallReplacements;
|
|
223
|
+
// Collect func(fn) replacements to just fn.
|
|
215
224
|
// The func() wrapper is only needed for type-level transformation (RemoveContextParam).
|
|
216
225
|
// At runtime, we just need the raw function. The registration code (appendRegistryCode)
|
|
217
226
|
// will set requireContext on the function based on compile-time analysis.
|
|
218
|
-
const
|
|
219
|
-
|
|
227
|
+
const collectFuncCallReplacements = (sourceFile) => {
|
|
228
|
+
const replacements = [];
|
|
220
229
|
sourceFile.forEachDescendant((node) => {
|
|
221
230
|
if (node.getKind() !== ts_morph_1.SyntaxKind.CallExpression)
|
|
222
231
|
return;
|
|
@@ -227,17 +236,34 @@ const transformFuncCalls = (sourceFile) => {
|
|
|
227
236
|
if (args.length !== 1)
|
|
228
237
|
return;
|
|
229
238
|
// Replace func(fn) with just fn
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
replacements.push({
|
|
240
|
+
start: callExpr.getStart(),
|
|
241
|
+
end: callExpr.getEnd(),
|
|
242
|
+
content: args[0].getText()
|
|
243
|
+
});
|
|
232
244
|
});
|
|
233
|
-
return
|
|
245
|
+
return replacements;
|
|
234
246
|
};
|
|
235
|
-
exports.
|
|
247
|
+
exports.collectFuncCallReplacements = collectFuncCallReplacements;
|
|
248
|
+
// Apply collected replacements using MagicString for sourcemap support
|
|
249
|
+
const applyReplacementsWithMap = (source, replacements, filePath) => {
|
|
250
|
+
const s = new magic_string_1.default(source);
|
|
251
|
+
// Sort replacements by start position descending to preserve positions
|
|
252
|
+
const sorted = [...replacements].sort((a, b) => b.start - a.start);
|
|
253
|
+
for (const { start, end, content } of sorted) {
|
|
254
|
+
s.overwrite(start, end, content);
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
code: s.toString(),
|
|
258
|
+
map: s.generateMap({ source: filePath, includeContent: true, hires: true })
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
exports.applyReplacementsWithMap = applyReplacementsWithMap;
|
|
236
262
|
const appendRegistryCode = (sourceFile, fileRegistry) => {
|
|
237
263
|
// Generate registration code for each server function.
|
|
238
264
|
// We set requireContext based on compile-time analysis of the function's first parameter type.
|
|
239
265
|
// If the first param is context<T>, requireContext = true, otherwise false.
|
|
240
|
-
// This allows
|
|
266
|
+
// This allows handle() at runtime to know whether to inject the context as the first argument.
|
|
241
267
|
const registrations = Array.from(fileRegistry.values())
|
|
242
268
|
.map(info => `globalThis.${exports.ZERO_COM_SERVER_REGISTRY}['${info.funcId}'] = ${info.exportName};\n` +
|
|
243
269
|
`${info.exportName}.requireContext = ${info.requireContext};`)
|
|
@@ -247,7 +273,8 @@ if (!globalThis.${exports.ZERO_COM_SERVER_REGISTRY}) globalThis.${exports.ZERO_C
|
|
|
247
273
|
${registrations}`;
|
|
248
274
|
};
|
|
249
275
|
exports.appendRegistryCode = appendRegistryCode;
|
|
250
|
-
const transformSourceFile = (filePath, content, registry) => {
|
|
276
|
+
const transformSourceFile = (filePath, content, registry, options = {}) => {
|
|
277
|
+
const { development = true } = options;
|
|
251
278
|
const project = (0, exports.createProject)();
|
|
252
279
|
const sourceFile = project.createSourceFile(filePath, content, { overwrite: true });
|
|
253
280
|
const fileRegistry = registry.get(filePath);
|
|
@@ -257,17 +284,34 @@ const transformSourceFile = (filePath, content, registry) => {
|
|
|
257
284
|
if (isServerFunctionFile) {
|
|
258
285
|
fileRegistry.forEach((_, name) => importedFuncs.delete(name));
|
|
259
286
|
}
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
//
|
|
287
|
+
// Collect all replacements
|
|
288
|
+
const replacements = [];
|
|
289
|
+
// Always collect client call site replacements (needed in both dev and prod)
|
|
290
|
+
replacements.push(...(0, exports.collectCallSiteReplacements)(sourceFile, importedFuncs));
|
|
291
|
+
// In production mode, collect handle(), call(), and func() replacements.
|
|
292
|
+
// In development mode, these work at runtime via ZERO_COM_DEV_MODE flag.
|
|
293
|
+
if (!development) {
|
|
294
|
+
replacements.push(...(0, exports.collectHandleCallReplacements)(sourceFile));
|
|
295
|
+
replacements.push(...(0, exports.collectSendCallReplacements)(sourceFile));
|
|
296
|
+
}
|
|
297
|
+
// Handle server function files
|
|
265
298
|
if (isServerFunctionFile) {
|
|
266
|
-
|
|
299
|
+
// In production mode, strip func() wrappers
|
|
300
|
+
if (!development) {
|
|
301
|
+
replacements.push(...(0, exports.collectFuncCallReplacements)(sourceFile));
|
|
302
|
+
}
|
|
303
|
+
// Apply replacements and append registry code
|
|
304
|
+
if (replacements.length > 0) {
|
|
305
|
+
const { code, map } = (0, exports.applyReplacementsWithMap)(content, replacements, filePath);
|
|
306
|
+
// Create a new source file from the transformed code to append registry
|
|
307
|
+
const transformedSourceFile = project.createSourceFile(filePath + '.transformed', code, { overwrite: true });
|
|
308
|
+
return { content: (0, exports.appendRegistryCode)(transformedSourceFile, fileRegistry), transformed: true, map };
|
|
309
|
+
}
|
|
267
310
|
return { content: (0, exports.appendRegistryCode)(sourceFile, fileRegistry), transformed: true };
|
|
268
311
|
}
|
|
269
|
-
if (
|
|
270
|
-
|
|
312
|
+
if (replacements.length > 0) {
|
|
313
|
+
const { code, map } = (0, exports.applyReplacementsWithMap)(content, replacements, filePath);
|
|
314
|
+
return { content: code, transformed: true, map };
|
|
271
315
|
}
|
|
272
316
|
return { content, transformed: false };
|
|
273
317
|
};
|
package/lib/rollup.js
CHANGED
|
@@ -42,15 +42,16 @@ function zeroComRollupPlugin(options = {}) {
|
|
|
42
42
|
});
|
|
43
43
|
},
|
|
44
44
|
load(id) {
|
|
45
|
-
var _a, _b;
|
|
45
|
+
var _a, _b, _c;
|
|
46
46
|
if (!((_b = (_a = this.getModuleInfo(id)) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.needsTransform) || !fs_1.default.existsSync(id))
|
|
47
47
|
return null;
|
|
48
48
|
const content = fs_1.default.readFileSync(id, 'utf8');
|
|
49
|
-
const result = (0, common_1.transformSourceFile)(id, content, registry);
|
|
49
|
+
const result = (0, common_1.transformSourceFile)(id, content, registry, { development });
|
|
50
50
|
if (!result.transformed)
|
|
51
51
|
return null;
|
|
52
52
|
console.log(`[ZeroComRollupPlugin] Transformed: ${path_1.default.relative(process.cwd(), id)}`);
|
|
53
|
-
|
|
53
|
+
const code = (0, common_1.emitToJs)(id, result.content);
|
|
54
|
+
return { code, map: (_c = result.map) !== null && _c !== void 0 ? _c : null };
|
|
54
55
|
},
|
|
55
56
|
renderChunk(code) {
|
|
56
57
|
if (development)
|
package/lib/runtime.d.ts
CHANGED
|
@@ -10,6 +10,6 @@ export type context<T = unknown> = T & {
|
|
|
10
10
|
};
|
|
11
11
|
type RemoveContextParam<F> = F extends (ctx: infer C, ...args: infer A) => infer R ? C extends context<unknown> ? (...args: A) => R : F : F;
|
|
12
12
|
export declare function func<F extends (...args: any[]) => any>(fn: F): RemoveContextParam<F>;
|
|
13
|
-
export declare const handle: (
|
|
14
|
-
export declare const call: (
|
|
13
|
+
export declare const handle: (funcId: string, ctx: any, args: any[]) => any;
|
|
14
|
+
export declare const call: (fn: (funcId: string, args: any[]) => Promise<any>) => void;
|
|
15
15
|
export {};
|
package/lib/runtime.js
CHANGED
|
@@ -3,19 +3,30 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.call = exports.handle = void 0;
|
|
4
4
|
exports.func = func;
|
|
5
5
|
// Implementation
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
function func(
|
|
10
|
-
|
|
6
|
+
// In development mode: works at runtime, returns the function as-is.
|
|
7
|
+
// In production mode: transformed by plugin to just the inner function.
|
|
8
|
+
// The plugin appends code to register the function and set requireContext.
|
|
9
|
+
function func(fn) {
|
|
10
|
+
return fn;
|
|
11
11
|
}
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
// In development mode: works at runtime, looks up function and calls it.
|
|
13
|
+
// In production mode: transformed by plugin to inline code.
|
|
14
|
+
const handle = (funcId, ctx, args) => {
|
|
15
|
+
const fn = globalThis.ZERO_COM_SERVER_REGISTRY[funcId];
|
|
16
|
+
if (!fn) {
|
|
17
|
+
throw new Error(`Function not found in registry: ${funcId}`);
|
|
18
|
+
}
|
|
19
|
+
if (fn.requireContext) {
|
|
20
|
+
return fn(ctx, ...args);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
return fn(...args);
|
|
24
|
+
}
|
|
15
25
|
};
|
|
16
26
|
exports.handle = handle;
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
// In development mode: works at runtime, sets the client call handler.
|
|
28
|
+
// In production mode: transformed by plugin to assignment.
|
|
29
|
+
const call = (fn) => {
|
|
30
|
+
globalThis.ZERO_COM_CLIENT_CALL = fn;
|
|
20
31
|
};
|
|
21
32
|
exports.call = call;
|
package/lib/webpack-loader.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import type { LoaderContext } from 'webpack';
|
|
|
2
2
|
import { ServerFuncRegistry } from './common';
|
|
3
3
|
export interface ZeroComLoaderOptions {
|
|
4
4
|
registry: ServerFuncRegistry;
|
|
5
|
+
development: boolean;
|
|
5
6
|
}
|
|
6
|
-
export default function zeroComLoader(this: LoaderContext<ZeroComLoaderOptions>, source: string):
|
|
7
|
+
export default function zeroComLoader(this: LoaderContext<ZeroComLoaderOptions>, source: string): void;
|
package/lib/webpack-loader.js
CHANGED
|
@@ -9,10 +9,13 @@ const common_1 = require("./common");
|
|
|
9
9
|
function zeroComLoader(source) {
|
|
10
10
|
const options = this.getOptions();
|
|
11
11
|
const filePath = this.resourcePath;
|
|
12
|
-
const result = (0, common_1.transformSourceFile)(filePath, source, options.registry
|
|
12
|
+
const result = (0, common_1.transformSourceFile)(filePath, source, options.registry, {
|
|
13
|
+
development: options.development
|
|
14
|
+
});
|
|
13
15
|
if (!result.transformed) {
|
|
14
|
-
|
|
16
|
+
this.callback(null, source);
|
|
17
|
+
return;
|
|
15
18
|
}
|
|
16
19
|
console.log(`[ZeroComWebpackPlugin] Transformed: ${path_1.default.basename(filePath)}`);
|
|
17
|
-
|
|
20
|
+
this.callback(null, result.content, result.map);
|
|
18
21
|
}
|
package/lib/webpack.js
CHANGED
|
@@ -24,7 +24,7 @@ class ZeroComWebpackPlugin {
|
|
|
24
24
|
enforce: 'pre',
|
|
25
25
|
use: [{
|
|
26
26
|
loader: loaderPath,
|
|
27
|
-
options: { registry: this.registry }
|
|
27
|
+
options: { registry: this.registry, development: this.options.development }
|
|
28
28
|
}]
|
|
29
29
|
};
|
|
30
30
|
compiler.options.module.rules.unshift(loaderRule);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zero-com",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.5",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": "https://github.com/yosbelms/zero-com",
|
|
6
6
|
"keywords": [
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"description": "",
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"magic-string": "^0.30.21",
|
|
25
26
|
"minimatch": "^10.0.1",
|
|
26
27
|
"ts-morph": "^26.0.0"
|
|
27
28
|
},
|