@evjs/build-tools 0.0.0
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/README.md +99 -0
- package/esm/codegen.d.ts +6 -0
- package/esm/codegen.d.ts.map +1 -0
- package/esm/codegen.js +10 -0
- package/esm/codegen.js.map +1 -0
- package/esm/entry.d.ts +18 -0
- package/esm/entry.d.ts.map +1 -0
- package/esm/entry.js +33 -0
- package/esm/entry.js.map +1 -0
- package/esm/index.d.ts +9 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +7 -0
- package/esm/index.js.map +1 -0
- package/esm/transforms/client/index.d.ts +5 -0
- package/esm/transforms/client/index.d.ts.map +1 -0
- package/esm/transforms/client/index.js +21 -0
- package/esm/transforms/client/index.js.map +1 -0
- package/esm/transforms/index.d.ts +14 -0
- package/esm/transforms/index.d.ts.map +1 -0
- package/esm/transforms/index.js +40 -0
- package/esm/transforms/index.js.map +1 -0
- package/esm/transforms/server/index.d.ts +5 -0
- package/esm/transforms/server/index.d.ts.map +1 -0
- package/esm/transforms/server/index.js +36 -0
- package/esm/transforms/server/index.js.map +1 -0
- package/esm/transforms/utils.d.ts +4 -0
- package/esm/transforms/utils.d.ts.map +1 -0
- package/esm/transforms/utils.js +32 -0
- package/esm/transforms/utils.js.map +1 -0
- package/esm/types.d.ts +46 -0
- package/esm/types.d.ts.map +1 -0
- package/esm/types.js +25 -0
- package/esm/types.js.map +1 -0
- package/esm/utils.d.ts +14 -0
- package/esm/utils.d.ts.map +1 -0
- package/esm/utils.js +47 -0
- package/esm/utils.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @evjs/build-tools
|
|
2
|
+
|
|
3
|
+
Bundler-agnostic build utilities for the **ev** framework. Contains all core logic for server function handling, decoupled from any specific bundler.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @evjs/build-tools
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Exports
|
|
12
|
+
|
|
13
|
+
| Export | Description |
|
|
14
|
+
|--------|-------------|
|
|
15
|
+
| `generateServerEntry(config, modules)` | Generate server entry source from discovered modules |
|
|
16
|
+
| `transformServerFile(source, options)` | SWC-based transform for `"use server"` files |
|
|
17
|
+
| `detectUseServer(source)` | Check if a file starts with the `"use server"` directive |
|
|
18
|
+
| `makeFnId(root, path, name)` | Derive a stable SHA-256 function ID |
|
|
19
|
+
| `parseModuleRef(ref)` | Parse `"module#export"` reference strings |
|
|
20
|
+
| `ServerEntryConfig` | Config type for server entry generation |
|
|
21
|
+
| `TransformOptions` | Options type for file transformation |
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
This package is consumed by bundler adapters (e.g., `@evjs/webpack-plugin`), not directly by application code.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import {
|
|
29
|
+
generateServerEntry,
|
|
30
|
+
transformServerFile,
|
|
31
|
+
detectUseServer,
|
|
32
|
+
} from "@evjs/build-tools";
|
|
33
|
+
|
|
34
|
+
// Generate server entry source
|
|
35
|
+
const entrySource = generateServerEntry(
|
|
36
|
+
{ appFactory: "@evjs/runtime/server#createApp" },
|
|
37
|
+
["/path/to/api/users.server.ts"],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
// Transform a "use server" file for client build
|
|
41
|
+
const clientStub = await transformServerFile(source, {
|
|
42
|
+
resourcePath: "/path/to/api/users.server.ts",
|
|
43
|
+
rootContext: "/path/to/project",
|
|
44
|
+
isServer: false,
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Architecture
|
|
49
|
+
|
|
50
|
+
### Transform Pipeline
|
|
51
|
+
|
|
52
|
+
`transformServerFile()` parses the source with SWC, extracts exported function names via AST traversal, then delegates to the appropriate transform:
|
|
53
|
+
|
|
54
|
+
- **Client transform** — replaces function bodies with `__fn_call(fnId, args)` transport stubs and registers them via `__fn_register()` for query cache keys.
|
|
55
|
+
- **Server transform** — keeps original source, prepends the `registerServerFn` import, and appends registration calls for each export.
|
|
56
|
+
|
|
57
|
+
### Entry Generation
|
|
58
|
+
|
|
59
|
+
`generateServerEntry()` produces a self-contained server entry that imports all discovered `"use server"` modules, creates a Hono app via `createApp()`, and optionally invokes a backend (e.g., `serve`) for self-starting bundles.
|
|
60
|
+
|
|
61
|
+
### Code Emitter
|
|
62
|
+
|
|
63
|
+
All generated code passes through `emitCode()` — a SWC `parseSync → printSync` roundtrip that validates syntax at build time and produces consistently formatted output.
|
|
64
|
+
|
|
65
|
+
### RUNTIME Constants
|
|
66
|
+
|
|
67
|
+
All runtime identifiers (module paths, function names, property names) are centralized in a single `RUNTIME` constant — no hardcoded strings in templates:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
RUNTIME.serverModule // "@evjs/runtime/server/register"
|
|
71
|
+
RUNTIME.appModule // "@evjs/runtime/server"
|
|
72
|
+
RUNTIME.clientTransportModule // "@evjs/runtime/client/transport"
|
|
73
|
+
RUNTIME.registerServerFn // "registerServerFn"
|
|
74
|
+
RUNTIME.clientCall // "__fn_call"
|
|
75
|
+
RUNTIME.clientRegister // "__fn_register"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Bundler Adapter Pattern
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
@evjs/build-tools (pure functions) Bundler Adapters
|
|
82
|
+
──────────────────────────────── ─────────────────
|
|
83
|
+
• generateServerEntry() @evjs/webpack-plugin
|
|
84
|
+
• transformServerFile() → EvWebpackPlugin
|
|
85
|
+
• detectUseServer() → server-fn-loader
|
|
86
|
+
• makeFnId()
|
|
87
|
+
• parseModuleRef() (future: @evjs/vite-plugin)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Key Files
|
|
91
|
+
|
|
92
|
+
| File | Purpose |
|
|
93
|
+
|------|---------|
|
|
94
|
+
| `src/transforms/index.ts` | `transformServerFile` — main transform |
|
|
95
|
+
| `src/transforms/client/` | Client-side SWC transform (stub generation) |
|
|
96
|
+
| `src/transforms/server/` | Server-side SWC transform (registration) |
|
|
97
|
+
| `src/entry.ts` | `generateServerEntry` |
|
|
98
|
+
| `src/utils.ts` | `makeFnId`, `parseModuleRef`, `detectUseServer` |
|
|
99
|
+
| `src/types.ts` | Type definitions |
|
package/esm/codegen.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAG/C"}
|
package/esm/codegen.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { parseSync, printSync } from "@swc/core";
|
|
2
|
+
/**
|
|
3
|
+
* Parse source code and re-emit via SWC for consistent formatting.
|
|
4
|
+
* Validates the code is syntactically correct at build time.
|
|
5
|
+
*/
|
|
6
|
+
export function emitCode(source) {
|
|
7
|
+
const ast = parseSync(source, { syntax: "ecmascript" });
|
|
8
|
+
return printSync(ast, { jsc: { target: "esnext" } }).code;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=codegen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEjD;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAc;IACrC,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACxD,OAAO,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC"}
|
package/esm/entry.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type ServerEntryConfig } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate the server entry source code from discovered server modules.
|
|
4
|
+
*
|
|
5
|
+
* The generated entry:
|
|
6
|
+
* 1. Imports user's "use server" modules (registering functions as side effects)
|
|
7
|
+
* 2. Re-exports them as named exports (_fns_0, _fns_1, ...)
|
|
8
|
+
* 3. Re-exports `createApp` so the adapter can create a Hono app that
|
|
9
|
+
* shares the same function registry
|
|
10
|
+
*
|
|
11
|
+
* The adapter layer (node/ecma) handles server startup.
|
|
12
|
+
*
|
|
13
|
+
* @param config - Server entry configuration (setup imports)
|
|
14
|
+
* @param serverModulePaths - Absolute paths to discovered "use server" modules
|
|
15
|
+
* @returns The generated server entry source code string
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateServerEntry(config: ServerEntryConfig | undefined, serverModulePaths: string[]): string;
|
|
18
|
+
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAW,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,iBAAiB,GAAG,SAAS,EACrC,iBAAiB,EAAE,MAAM,EAAE,GAC1B,MAAM,CAkBR"}
|
package/esm/entry.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { emitCode } from "./codegen.js";
|
|
2
|
+
import { RUNTIME } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Generate the server entry source code from discovered server modules.
|
|
5
|
+
*
|
|
6
|
+
* The generated entry:
|
|
7
|
+
* 1. Imports user's "use server" modules (registering functions as side effects)
|
|
8
|
+
* 2. Re-exports them as named exports (_fns_0, _fns_1, ...)
|
|
9
|
+
* 3. Re-exports `createApp` so the adapter can create a Hono app that
|
|
10
|
+
* shares the same function registry
|
|
11
|
+
*
|
|
12
|
+
* The adapter layer (node/ecma) handles server startup.
|
|
13
|
+
*
|
|
14
|
+
* @param config - Server entry configuration (setup imports)
|
|
15
|
+
* @param serverModulePaths - Absolute paths to discovered "use server" modules
|
|
16
|
+
* @returns The generated server entry source code string
|
|
17
|
+
*/
|
|
18
|
+
export function generateServerEntry(config, serverModulePaths) {
|
|
19
|
+
const moduleImports = serverModulePaths
|
|
20
|
+
.map((p, i) => `import * as _fns_${i} from ${JSON.stringify(p)};`)
|
|
21
|
+
.join("\n");
|
|
22
|
+
const fnsExports = serverModulePaths.map((_p, i) => `_fns_${i}`);
|
|
23
|
+
const allExports = [...fnsExports];
|
|
24
|
+
return emitCode([
|
|
25
|
+
`export { createApp } from "${RUNTIME.appModule}";`,
|
|
26
|
+
...(config?.middleware ?? []),
|
|
27
|
+
moduleImports,
|
|
28
|
+
allExports.length ? `export { ${allExports.join(", ")} };` : "",
|
|
29
|
+
]
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.join("\n"));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=entry.js.map
|
package/esm/entry.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAA0B,MAAM,YAAY,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAAqC,EACrC,iBAA2B;IAE3B,MAAM,aAAa,GAAG,iBAAiB;SACpC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;SACjE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjE,MAAM,UAAU,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC;IAEnC,OAAO,QAAQ,CACb;QACE,8BAA8B,OAAO,CAAC,SAAS,IAAI;QACnD,GAAG,CAAC,MAAM,EAAE,UAAU,IAAI,EAAE,CAAC;QAC7B,aAAa;QACb,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;KAChE;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;AACJ,CAAC"}
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundler-agnostic build utilities for the ev framework.
|
|
3
|
+
*/
|
|
4
|
+
export { generateServerEntry } from "./entry.js";
|
|
5
|
+
export type { TransformResult } from "./transforms/index.js";
|
|
6
|
+
export { transformServerFile } from "./transforms/index.js";
|
|
7
|
+
export type { ServerEntryConfig, TransformOptions } from "./types.js";
|
|
8
|
+
export { detectUseServer, hashString, makeFnId, makeModuleId, parseModuleRef, } from "./utils.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACtE,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundler-agnostic build utilities for the ev framework.
|
|
3
|
+
*/
|
|
4
|
+
export { generateServerEntry } from "./entry.js";
|
|
5
|
+
export { transformServerFile } from "./transforms/index.js";
|
|
6
|
+
export { detectUseServer, hashString, makeFnId, makeModuleId, parseModuleRef, } from "./utils.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,GACf,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Module } from "@swc/core";
|
|
2
|
+
import { type TransformOptions } from "../../types.js";
|
|
3
|
+
/** Client build: replace function bodies with __fn_call transport stubs via AST replacement. */
|
|
4
|
+
export declare function buildClientOutput(program: Module, exportNames: string[], options: TransformOptions): Module;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,WAAW,CAAC;AACnD,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGhE,gGAAgG;AAChG,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAoBR"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parseSync } from "@swc/core";
|
|
2
|
+
import { RUNTIME } from "../../types.js";
|
|
3
|
+
import { makeFnId } from "../../utils.js";
|
|
4
|
+
/** Client build: replace function bodies with __fn_call transport stubs via AST replacement. */
|
|
5
|
+
export function buildClientOutput(program, exportNames, options) {
|
|
6
|
+
const stubs = exportNames.map((name) => {
|
|
7
|
+
const fnId = JSON.stringify(makeFnId(options.rootContext, options.resourcePath, name));
|
|
8
|
+
return [
|
|
9
|
+
`export function ${name}(...args) { return ${RUNTIME.clientCall}(${fnId}, args); }`,
|
|
10
|
+
`${RUNTIME.clientRegister}(${name}, ${fnId}, ${JSON.stringify(name)});`,
|
|
11
|
+
].join("\n");
|
|
12
|
+
});
|
|
13
|
+
const injectCode = [
|
|
14
|
+
`import { ${RUNTIME.clientCall}, ${RUNTIME.clientRegister} } from "${RUNTIME.clientTransportModule}";`,
|
|
15
|
+
...stubs,
|
|
16
|
+
].join("\n");
|
|
17
|
+
const injectAst = parseSync(injectCode, { syntax: "ecmascript" });
|
|
18
|
+
program.body = injectAst.body;
|
|
19
|
+
return program;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transforms/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,SAAS,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,OAAO,EAAyB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,gGAAgG;AAChG,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,WAAqB,EACrB,OAAyB;IAEzB,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAC1D,CAAC;QACF,OAAO;YACL,mBAAmB,IAAI,sBAAsB,OAAO,CAAC,UAAU,IAAI,IAAI,YAAY;YACnF,GAAG,OAAO,CAAC,cAAc,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI;SACxE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG;QACjB,YAAY,OAAO,CAAC,UAAU,KAAK,OAAO,CAAC,cAAc,YAAY,OAAO,CAAC,qBAAqB,IAAI;QACtG,GAAG,KAAK;KACT,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,SAAS,GAAG,SAAS,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC;IAE9B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TransformOptions } from "../types.js";
|
|
2
|
+
export interface TransformResult {
|
|
3
|
+
code: string;
|
|
4
|
+
map?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Transform a "use server" file for either client or server builds.
|
|
8
|
+
* This is a pure function with no bundler dependency.
|
|
9
|
+
*
|
|
10
|
+
* - **Server**: keeps original source + appends `registerServerFn()` calls
|
|
11
|
+
* - **Client**: replaces function bodies with `__fn_call()` transport stubs
|
|
12
|
+
*/
|
|
13
|
+
export declare function transformServerFile(source: string, options: TransformOptions): Promise<TransformResult>;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { parse, printSync } from "@swc/core";
|
|
2
|
+
import { detectUseServer } from "../utils.js";
|
|
3
|
+
import { buildClientOutput } from "./client/index.js";
|
|
4
|
+
import { buildServerOutput } from "./server/index.js";
|
|
5
|
+
import { extractExportNames } from "./utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* Transform a "use server" file for either client or server builds.
|
|
8
|
+
* This is a pure function with no bundler dependency.
|
|
9
|
+
*
|
|
10
|
+
* - **Server**: keeps original source + appends `registerServerFn()` calls
|
|
11
|
+
* - **Client**: replaces function bodies with `__fn_call()` transport stubs
|
|
12
|
+
*/
|
|
13
|
+
export async function transformServerFile(source, options) {
|
|
14
|
+
if (!detectUseServer(source)) {
|
|
15
|
+
return { code: source };
|
|
16
|
+
}
|
|
17
|
+
const program = await parse(source, {
|
|
18
|
+
syntax: "typescript",
|
|
19
|
+
tsx: true,
|
|
20
|
+
comments: false,
|
|
21
|
+
script: false,
|
|
22
|
+
target: "esnext",
|
|
23
|
+
});
|
|
24
|
+
const exportNames = extractExportNames(program.body);
|
|
25
|
+
if (exportNames.length === 0) {
|
|
26
|
+
return { code: source };
|
|
27
|
+
}
|
|
28
|
+
const modifiedAst = options.isServer
|
|
29
|
+
? buildServerOutput(program, exportNames, options)
|
|
30
|
+
: buildClientOutput(program, exportNames, options);
|
|
31
|
+
const { code, map } = printSync(modifiedAst, {
|
|
32
|
+
sourceMaps: true,
|
|
33
|
+
inlineSourcesContent: true,
|
|
34
|
+
filename: options.resourcePath,
|
|
35
|
+
sourceFileName: options.resourcePath,
|
|
36
|
+
jsc: { target: "esnext" },
|
|
37
|
+
});
|
|
38
|
+
return { code, map };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAOhD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,MAAc,EACd,OAAyB;IAEzB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;QAClC,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,IAAI;QACT,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ;QAClC,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC;QAClD,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAErD,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,WAAW,EAAE;QAC3C,UAAU,EAAE,IAAI;QAChB,oBAAoB,EAAE,IAAI;QAC1B,QAAQ,EAAE,OAAO,CAAC,YAAY;QAC9B,cAAc,EAAE,OAAO,CAAC,YAAY;QACpC,GAAG,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;KAC1B,CAAC,CAAC;IAEH,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Module } from "@swc/core";
|
|
2
|
+
import { type TransformOptions } from "../../types.js";
|
|
3
|
+
/** Server build: inject import and appends registrations as AST nodes. */
|
|
4
|
+
export declare function buildServerOutput(program: Module, exportNames: string[], options: TransformOptions): Module;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transforms/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,WAAW,CAAC;AACnD,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAgBhE,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EAAE,EACrB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CA4BR"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { parseSync } from "@swc/core";
|
|
2
|
+
import { RUNTIME } from "../../types.js";
|
|
3
|
+
import { makeFnId, makeModuleId } from "../../utils.js";
|
|
4
|
+
/** Notify the manifest collector about each server function. */
|
|
5
|
+
function reportToManifest(exportNames, options) {
|
|
6
|
+
if (!options.onServerFn)
|
|
7
|
+
return;
|
|
8
|
+
const moduleId = makeModuleId(options.rootContext, options.resourcePath);
|
|
9
|
+
for (const name of exportNames) {
|
|
10
|
+
const fnId = makeFnId(options.rootContext, options.resourcePath, name);
|
|
11
|
+
options.onServerFn(fnId, { moduleId, export: name });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Server build: inject import and appends registrations as AST nodes. */
|
|
15
|
+
export function buildServerOutput(program, exportNames, options) {
|
|
16
|
+
reportToManifest(exportNames, options);
|
|
17
|
+
const registrations = exportNames.map((name) => {
|
|
18
|
+
const fnId = JSON.stringify(makeFnId(options.rootContext, options.resourcePath, name));
|
|
19
|
+
return `${RUNTIME.registerServerFn}(${fnId}, ${name});`;
|
|
20
|
+
});
|
|
21
|
+
const injectCode = [
|
|
22
|
+
`import { ${RUNTIME.registerServerFn} } from "${RUNTIME.serverModule}";`,
|
|
23
|
+
...registrations,
|
|
24
|
+
].join("\n");
|
|
25
|
+
const injectAst = parseSync(injectCode, { syntax: "ecmascript" });
|
|
26
|
+
// Prepend import
|
|
27
|
+
if (injectAst.body.length > 0) {
|
|
28
|
+
program.body.unshift(injectAst.body[0]);
|
|
29
|
+
}
|
|
30
|
+
// Append registrations
|
|
31
|
+
for (let i = 1; i < injectAst.body.length; i++) {
|
|
32
|
+
program.body.push(injectAst.body[i]);
|
|
33
|
+
}
|
|
34
|
+
return program;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transforms/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,SAAS,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,OAAO,EAAyB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAExD,gEAAgE;AAChE,SAAS,gBAAgB,CACvB,WAAqB,EACrB,OAAyB;IAEzB,IAAI,CAAC,OAAO,CAAC,UAAU;QAAE,OAAO;IAChC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACzE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACvE,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,WAAqB,EACrB,OAAyB;IAEzB,gBAAgB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAEvC,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAC1D,CAAC;QACF,OAAO,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG;QACjB,YAAY,OAAO,CAAC,gBAAgB,YAAY,OAAO,CAAC,YAAY,IAAI;QACxE,GAAG,aAAa;KACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,MAAM,SAAS,GAAG,SAAS,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IAElE,iBAAiB;IACjB,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC;IAED,uBAAuB;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/transforms/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CA4B/D"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Extract exported function/variable names from a parsed SWC module. */
|
|
2
|
+
export function extractExportNames(body) {
|
|
3
|
+
const names = [];
|
|
4
|
+
for (const item of body) {
|
|
5
|
+
if (item.type === "ExportDeclaration") {
|
|
6
|
+
const decl = item.declaration;
|
|
7
|
+
if (decl.type === "FunctionDeclaration") {
|
|
8
|
+
if (decl.identifier.value)
|
|
9
|
+
names.push(decl.identifier.value);
|
|
10
|
+
}
|
|
11
|
+
else if (decl.type === "VariableDeclaration") {
|
|
12
|
+
for (const v of decl.declarations) {
|
|
13
|
+
if (v.id.type === "Identifier") {
|
|
14
|
+
names.push(v.id.value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else if (item.type === "ExportNamedDeclaration") {
|
|
20
|
+
for (const specifier of item.specifiers) {
|
|
21
|
+
if (specifier.type === "ExportSpecifier") {
|
|
22
|
+
const exported = specifier.exported ?? specifier.orig;
|
|
23
|
+
if (exported.type === "Identifier") {
|
|
24
|
+
names.push(exported.value);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return names;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/transforms/utils.ts"],"names":[],"mappings":"AAEA,yEAAyE;AACzE,MAAM,UAAU,kBAAkB,CAAC,IAAkB;IACnD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC;YAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBACxC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK;oBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YAC/D,CAAC;iBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;gBAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBAClC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBAC/B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,KAAK,wBAAwB,EAAE,CAAC;YAClD,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACxC,IAAI,SAAS,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBACzC,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,IAAI,SAAS,CAAC,IAAI,CAAC;oBACtD,IAAI,QAAQ,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;wBACnC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/esm/types.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Configuration for the generated server entry. */
|
|
2
|
+
export interface ServerEntryConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Middleware module paths to auto-register in the server entry.
|
|
5
|
+
*/
|
|
6
|
+
middleware?: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Options for transforming a "use server" file. */
|
|
9
|
+
export interface TransformOptions {
|
|
10
|
+
/** Absolute path to the source file. */
|
|
11
|
+
resourcePath: string;
|
|
12
|
+
/** Root directory of the project. */
|
|
13
|
+
rootContext: string;
|
|
14
|
+
/** Whether this is a server-side build. */
|
|
15
|
+
isServer: boolean;
|
|
16
|
+
/** Callback to register a server function in the manifest. */
|
|
17
|
+
onServerFn?: (fnId: string, meta: {
|
|
18
|
+
moduleId: string;
|
|
19
|
+
export: string;
|
|
20
|
+
}) => void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Runtime identifiers used in generated code.
|
|
24
|
+
*
|
|
25
|
+
* These are build-time constants — the actual module paths and function names
|
|
26
|
+
* that appear in codegen output. They must stay in sync with the `@evjs/runtime`
|
|
27
|
+
* package exports.
|
|
28
|
+
*
|
|
29
|
+
* Note: `DEFAULT_ENDPOINT` (the default HTTP path for server functions) is a runtime
|
|
30
|
+
* concern and lives in `@evjs/runtime/src/constants.ts`, not here.
|
|
31
|
+
*/
|
|
32
|
+
export declare const RUNTIME: {
|
|
33
|
+
/** Module path for server-side function registration (no Hono dependency). */
|
|
34
|
+
readonly serverModule: "@evjs/runtime/server/register";
|
|
35
|
+
/** Module path for the server app factory (Hono app + server function handler). */
|
|
36
|
+
readonly appModule: "@evjs/runtime/server";
|
|
37
|
+
/** Module path for client-side transport stubs. */
|
|
38
|
+
readonly clientTransportModule: "@evjs/runtime/client/transport";
|
|
39
|
+
/** Server function registration call name. */
|
|
40
|
+
readonly registerServerFn: "registerServerFn";
|
|
41
|
+
/** Client-side server function call name. */
|
|
42
|
+
readonly clientCall: "__fn_call";
|
|
43
|
+
/** Client-side function registration call name. */
|
|
44
|
+
readonly clientRegister: "__fn_register";
|
|
45
|
+
};
|
|
46
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,QAAQ,EAAE,OAAO,CAAC;IAClB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KACvC,IAAI,CAAC;CACX;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO;IAClB,8EAA8E;;IAE9E,mFAAmF;;IAEnF,mDAAmD;;IAEnD,8CAA8C;;IAE9C,6CAA6C;;IAE7C,mDAAmD;;CAE3C,CAAC"}
|
package/esm/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime identifiers used in generated code.
|
|
3
|
+
*
|
|
4
|
+
* These are build-time constants — the actual module paths and function names
|
|
5
|
+
* that appear in codegen output. They must stay in sync with the `@evjs/runtime`
|
|
6
|
+
* package exports.
|
|
7
|
+
*
|
|
8
|
+
* Note: `DEFAULT_ENDPOINT` (the default HTTP path for server functions) is a runtime
|
|
9
|
+
* concern and lives in `@evjs/runtime/src/constants.ts`, not here.
|
|
10
|
+
*/
|
|
11
|
+
export const RUNTIME = {
|
|
12
|
+
/** Module path for server-side function registration (no Hono dependency). */
|
|
13
|
+
serverModule: "@evjs/runtime/server/register",
|
|
14
|
+
/** Module path for the server app factory (Hono app + server function handler). */
|
|
15
|
+
appModule: "@evjs/runtime/server",
|
|
16
|
+
/** Module path for client-side transport stubs. */
|
|
17
|
+
clientTransportModule: "@evjs/runtime/client/transport",
|
|
18
|
+
/** Server function registration call name. */
|
|
19
|
+
registerServerFn: "registerServerFn",
|
|
20
|
+
/** Client-side server function call name. */
|
|
21
|
+
clientCall: "__fn_call",
|
|
22
|
+
/** Client-side function registration call name. */
|
|
23
|
+
clientRegister: "__fn_register",
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=types.js.map
|
package/esm/types.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,8EAA8E;IAC9E,YAAY,EAAE,+BAA+B;IAC7C,mFAAmF;IACnF,SAAS,EAAE,sBAAsB;IACjC,mDAAmD;IACnD,qBAAqB,EAAE,gCAAgC;IACvD,8CAA8C;IAC9C,gBAAgB,EAAE,kBAAkB;IACpC,6CAA6C;IAC7C,UAAU,EAAE,WAAW;IACvB,mDAAmD;IACnD,cAAc,EAAE,eAAe;CACvB,CAAC"}
|
package/esm/utils.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Parse a "module#export" reference string. */
|
|
2
|
+
export declare function parseModuleRef(ref: string): {
|
|
3
|
+
module: string;
|
|
4
|
+
exportName: string;
|
|
5
|
+
};
|
|
6
|
+
/** Hash a string to a 16-character hex digest (SHA-256, truncated). */
|
|
7
|
+
export declare function hashString(input: string): string;
|
|
8
|
+
/** Derive a stable module ID from a file path relative to root. */
|
|
9
|
+
export declare function makeModuleId(rootContext: string, resourcePath: string): string;
|
|
10
|
+
/** Derive a stable function ID from the file path and export name. */
|
|
11
|
+
export declare function makeFnId(rootContext: string, resourcePath: string, exportName: string): string;
|
|
12
|
+
/** Check whether the source starts with the "use server" directive. */
|
|
13
|
+
export declare function detectUseServer(source: string): boolean;
|
|
14
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAQA;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACnB,MAAM,CAER;AAED,sEAAsE;AACtE,wBAAgB,QAAQ,CACtB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAsBvD"}
|
package/esm/utils.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseSync } from "@swc/core";
|
|
4
|
+
/** Parse a "module#export" reference string. */
|
|
5
|
+
export function parseModuleRef(ref) {
|
|
6
|
+
const idx = ref.indexOf("#");
|
|
7
|
+
if (idx === -1) {
|
|
8
|
+
throw new Error(`Invalid module reference "${ref}". Expected format: "module#exportName".`);
|
|
9
|
+
}
|
|
10
|
+
return { module: ref.slice(0, idx), exportName: ref.slice(idx + 1) };
|
|
11
|
+
}
|
|
12
|
+
/** Hash a string to a 16-character hex digest (SHA-256, truncated). */
|
|
13
|
+
export function hashString(input) {
|
|
14
|
+
return createHash("sha256").update(input).digest("hex").slice(0, 16);
|
|
15
|
+
}
|
|
16
|
+
/** Derive a stable module ID from a file path relative to root. */
|
|
17
|
+
export function makeModuleId(rootContext, resourcePath) {
|
|
18
|
+
return hashString(path.relative(rootContext, resourcePath));
|
|
19
|
+
}
|
|
20
|
+
/** Derive a stable function ID from the file path and export name. */
|
|
21
|
+
export function makeFnId(rootContext, resourcePath, exportName) {
|
|
22
|
+
const relativePath = path.relative(rootContext, resourcePath);
|
|
23
|
+
return hashString(`${relativePath}:${exportName}`);
|
|
24
|
+
}
|
|
25
|
+
/** Check whether the source starts with the "use server" directive. */
|
|
26
|
+
export function detectUseServer(source) {
|
|
27
|
+
try {
|
|
28
|
+
const ast = parseSync(source, {
|
|
29
|
+
syntax: "typescript",
|
|
30
|
+
tsx: true,
|
|
31
|
+
target: "esnext",
|
|
32
|
+
});
|
|
33
|
+
if (ast.body && ast.body.length > 0) {
|
|
34
|
+
const firstNode = ast.body[0];
|
|
35
|
+
if (firstNode.type === "ExpressionStatement" &&
|
|
36
|
+
firstNode.expression.type === "StringLiteral" &&
|
|
37
|
+
firstNode.expression.value === "use server") {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (_e) {
|
|
43
|
+
// Fallback if parsing completely fails for some reason
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=utils.js.map
|
package/esm/utils.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,gDAAgD;AAChD,MAAM,UAAU,cAAc,CAAC,GAAW;IAIxC,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,6BAA6B,GAAG,0CAA0C,CAC3E,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvE,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAC1B,WAAmB,EACnB,YAAoB;IAEpB,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;AAC9D,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CACtB,WAAmB,EACnB,YAAoB,EACpB,UAAkB;IAElB,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC9D,OAAO,UAAU,CAAC,GAAG,YAAY,IAAI,UAAU,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE;YAC5B,MAAM,EAAE,YAAY;YACpB,GAAG,EAAE,IAAI;YACT,MAAM,EAAE,QAAQ;SACjB,CAAC,CAAC;QAEH,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,SAAS,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,IACE,SAAS,CAAC,IAAI,KAAK,qBAAqB;gBACxC,SAAS,CAAC,UAAU,CAAC,IAAI,KAAK,eAAe;gBAC7C,SAAS,CAAC,UAAU,CAAC,KAAK,KAAK,YAAY,EAC3C,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,EAAE,EAAE,CAAC;QACZ,uDAAuD;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evjs/build-tools",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Bundler-agnostic build utilities for the ev framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"main": "./esm/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./esm/index.d.ts",
|
|
13
|
+
"import": "./esm/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"check-types": "tsc --noEmit"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"esm"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"evjs",
|
|
26
|
+
"build-tools",
|
|
27
|
+
"server-functions",
|
|
28
|
+
"code-transform",
|
|
29
|
+
"typescript"
|
|
30
|
+
],
|
|
31
|
+
"author": "xusd320",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@swc/core": "^1.15.18"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@swc/types": "^0.1.25",
|
|
38
|
+
"typescript": "^5.7.3"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/evaijs/evjs#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/evaijs/evjs/issues"
|
|
43
|
+
},
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/evaijs/evjs.git"
|
|
47
|
+
}
|
|
48
|
+
}
|