@cmj/juice 0.0.1
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 +21 -0
- package/README.md +88 -0
- package/dist/cli/commands.d.ts +29 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/commands.js +102 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/create.d.ts +35 -0
- package/dist/cli/create.d.ts.map +1 -0
- package/dist/cli/create.js +108 -0
- package/dist/cli/create.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +97 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/templates.d.ts +14 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +154 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/compiler/errors.d.ts +91 -0
- package/dist/compiler/errors.d.ts.map +1 -0
- package/dist/compiler/errors.js +110 -0
- package/dist/compiler/errors.js.map +1 -0
- package/dist/compiler/manifest.d.ts +39 -0
- package/dist/compiler/manifest.d.ts.map +1 -0
- package/dist/compiler/manifest.js +78 -0
- package/dist/compiler/manifest.js.map +1 -0
- package/dist/compiler/parse.d.ts +126 -0
- package/dist/compiler/parse.d.ts.map +1 -0
- package/dist/compiler/parse.js +246 -0
- package/dist/compiler/parse.js.map +1 -0
- package/dist/compiler/plugin.d.ts +43 -0
- package/dist/compiler/plugin.d.ts.map +1 -0
- package/dist/compiler/plugin.js +281 -0
- package/dist/compiler/plugin.js.map +1 -0
- package/dist/compiler/proxy.d.ts +42 -0
- package/dist/compiler/proxy.d.ts.map +1 -0
- package/dist/compiler/proxy.js +80 -0
- package/dist/compiler/proxy.js.map +1 -0
- package/dist/compiler/registry.d.ts +58 -0
- package/dist/compiler/registry.d.ts.map +1 -0
- package/dist/compiler/registry.js +79 -0
- package/dist/compiler/registry.js.map +1 -0
- package/dist/compiler/server-action-registry.d.ts +57 -0
- package/dist/compiler/server-action-registry.d.ts.map +1 -0
- package/dist/compiler/server-action-registry.js +76 -0
- package/dist/compiler/server-action-registry.js.map +1 -0
- package/dist/compiler/server-actions.d.ts +49 -0
- package/dist/compiler/server-actions.d.ts.map +1 -0
- package/dist/compiler/server-actions.js +89 -0
- package/dist/compiler/server-actions.js.map +1 -0
- package/dist/compiler/types.d.ts +188 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/compiler/types.js +9 -0
- package/dist/compiler/types.js.map +1 -0
- package/dist/runtime/actions.d.ts +37 -0
- package/dist/runtime/actions.d.ts.map +1 -0
- package/dist/runtime/actions.js +167 -0
- package/dist/runtime/actions.js.map +1 -0
- package/dist/runtime/dev.d.ts +43 -0
- package/dist/runtime/dev.d.ts.map +1 -0
- package/dist/runtime/dev.js +260 -0
- package/dist/runtime/dev.js.map +1 -0
- package/dist/runtime/errors.d.ts +98 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +124 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +5 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/matcher.d.ts +44 -0
- package/dist/runtime/matcher.d.ts.map +1 -0
- package/dist/runtime/matcher.js +83 -0
- package/dist/runtime/matcher.js.map +1 -0
- package/dist/runtime/render.d.ts +25 -0
- package/dist/runtime/render.d.ts.map +1 -0
- package/dist/runtime/render.js +141 -0
- package/dist/runtime/render.js.map +1 -0
- package/dist/runtime/resolve.d.ts +24 -0
- package/dist/runtime/resolve.d.ts.map +1 -0
- package/dist/runtime/resolve.js +41 -0
- package/dist/runtime/resolve.js.map +1 -0
- package/dist/runtime/router.d.ts +74 -0
- package/dist/runtime/router.d.ts.map +1 -0
- package/dist/runtime/router.js +367 -0
- package/dist/runtime/router.js.map +1 -0
- package/dist/runtime/types.d.ts +245 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +5 -0
- package/dist/runtime/types.js.map +1 -0
- package/package.json +92 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// ─────────────────────────────────────────────────────────────────
|
|
2
|
+
// @cmj/juice — CLI Template Files
|
|
3
|
+
// Pure functions that return file content strings for scaffolding.
|
|
4
|
+
// ─────────────────────────────────────────────────────────────────
|
|
5
|
+
export const DEPLOY_TARGETS = ['bun', 'node', 'cloudflare', 'deno'];
|
|
6
|
+
export const TARGET_LABELS = {
|
|
7
|
+
bun: 'Bun',
|
|
8
|
+
node: 'Node.js',
|
|
9
|
+
cloudflare: 'Cloudflare Workers',
|
|
10
|
+
deno: 'Deno',
|
|
11
|
+
};
|
|
12
|
+
export function packageJson({ name, target }) {
|
|
13
|
+
const startScript = {
|
|
14
|
+
bun: 'bun server.ts',
|
|
15
|
+
node: 'node dist/server.js',
|
|
16
|
+
cloudflare: 'wrangler dev',
|
|
17
|
+
deno: 'deno run --allow-net --allow-read server.ts',
|
|
18
|
+
};
|
|
19
|
+
const pkg = {
|
|
20
|
+
name,
|
|
21
|
+
private: true,
|
|
22
|
+
type: 'module',
|
|
23
|
+
scripts: {
|
|
24
|
+
dev: 'vite dev',
|
|
25
|
+
build: 'vite build',
|
|
26
|
+
start: startScript[target],
|
|
27
|
+
typecheck: 'tsc --noEmit',
|
|
28
|
+
},
|
|
29
|
+
dependencies: {
|
|
30
|
+
'@cmj/juice': '^0.0.1',
|
|
31
|
+
react: '^19.0.0',
|
|
32
|
+
'react-dom': '^19.0.0',
|
|
33
|
+
},
|
|
34
|
+
devDependencies: {
|
|
35
|
+
'@types/react': '^19.0.0',
|
|
36
|
+
'@types/react-dom': '^19.0.0',
|
|
37
|
+
typescript: '^5.7.0',
|
|
38
|
+
vite: '^6.0.0',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
// Bun and Deno have built-in types; Node needs @types/node
|
|
42
|
+
if (target === 'node') {
|
|
43
|
+
pkg.devDependencies['@types/node'] = '^22.0.0';
|
|
44
|
+
}
|
|
45
|
+
return JSON.stringify(pkg, null, 2) + '\n';
|
|
46
|
+
}
|
|
47
|
+
export function tsconfig() {
|
|
48
|
+
const config = {
|
|
49
|
+
compilerOptions: {
|
|
50
|
+
target: 'ES2022',
|
|
51
|
+
module: 'ESNext',
|
|
52
|
+
moduleResolution: 'bundler',
|
|
53
|
+
jsx: 'react-jsx',
|
|
54
|
+
strict: true,
|
|
55
|
+
noEmit: true,
|
|
56
|
+
esModuleInterop: true,
|
|
57
|
+
skipLibCheck: true,
|
|
58
|
+
isolatedModules: true,
|
|
59
|
+
verbatimModuleSyntax: true,
|
|
60
|
+
},
|
|
61
|
+
include: ['**/*.ts', '**/*.tsx'],
|
|
62
|
+
};
|
|
63
|
+
return JSON.stringify(config, null, 2) + '\n';
|
|
64
|
+
}
|
|
65
|
+
export function viteConfig() {
|
|
66
|
+
return `import { defineConfig } from 'vite';
|
|
67
|
+
import juice from '@cmj/juice/plugin';
|
|
68
|
+
|
|
69
|
+
export default defineConfig({
|
|
70
|
+
plugins: [juice()],
|
|
71
|
+
});
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
// ── Server entry per target ─────────────────────────────────────
|
|
75
|
+
const SERVER_PREAMBLE = `import { createRouter } from '@cmj/juice/runtime';
|
|
76
|
+
import type { FlightManifest } from '@cmj/juice/runtime';
|
|
77
|
+
|
|
78
|
+
const manifest: FlightManifest = {
|
|
79
|
+
routes: {
|
|
80
|
+
'/': { moduleId: './app/routes/home.tsx' },
|
|
81
|
+
},
|
|
82
|
+
clientModules: {},
|
|
83
|
+
serverActions: {},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const handler = createRouter(manifest, {
|
|
87
|
+
root: import.meta.url,
|
|
88
|
+
});
|
|
89
|
+
`;
|
|
90
|
+
const SERVER_ADAPTERS = {
|
|
91
|
+
bun: `
|
|
92
|
+
Bun.serve({
|
|
93
|
+
port: 3000,
|
|
94
|
+
fetch: handler,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
console.log('🧃 Listening on http://localhost:3000');
|
|
98
|
+
`,
|
|
99
|
+
node: `
|
|
100
|
+
import { createServer } from 'node:http';
|
|
101
|
+
|
|
102
|
+
createServer(async (req, res) => {
|
|
103
|
+
const url = new URL(req.url ?? '/', \`http://\${req.headers.host}\`);
|
|
104
|
+
const body = await new Promise<Buffer>((resolve) => {
|
|
105
|
+
const chunks: Buffer[] = [];
|
|
106
|
+
req.on('data', (c: Buffer) => chunks.push(c));
|
|
107
|
+
req.on('end', () => resolve(Buffer.concat(chunks)));
|
|
108
|
+
});
|
|
109
|
+
const request = new Request(url.href, {
|
|
110
|
+
method: req.method,
|
|
111
|
+
headers: req.headers as Record<string, string>,
|
|
112
|
+
body: req.method !== 'GET' && req.method !== 'HEAD' ? body : undefined,
|
|
113
|
+
});
|
|
114
|
+
const response = await handler(request);
|
|
115
|
+
res.writeHead(response.status, Object.fromEntries(response.headers));
|
|
116
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
117
|
+
res.end(buffer);
|
|
118
|
+
}).listen(3000, () => {
|
|
119
|
+
console.log('🧃 Listening on http://localhost:3000');
|
|
120
|
+
});
|
|
121
|
+
`,
|
|
122
|
+
cloudflare: `
|
|
123
|
+
export default { fetch: handler };
|
|
124
|
+
`,
|
|
125
|
+
deno: `
|
|
126
|
+
Deno.serve({ port: 3000 }, handler);
|
|
127
|
+
|
|
128
|
+
console.log('🧃 Listening on http://localhost:3000');
|
|
129
|
+
`,
|
|
130
|
+
};
|
|
131
|
+
export function serverEntry(target) {
|
|
132
|
+
return SERVER_PREAMBLE + SERVER_ADAPTERS[target];
|
|
133
|
+
}
|
|
134
|
+
export function homeRoute() {
|
|
135
|
+
return `import React from 'react';
|
|
136
|
+
|
|
137
|
+
export default function HomePage() {
|
|
138
|
+
const timestamp = new Date().toISOString();
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<html>
|
|
142
|
+
<head>
|
|
143
|
+
<title>Juice App</title>
|
|
144
|
+
</head>
|
|
145
|
+
<body>
|
|
146
|
+
<h1>🧃 Juice</h1>
|
|
147
|
+
<p>Server-rendered at {timestamp}</p>
|
|
148
|
+
</body>
|
|
149
|
+
</html>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,kCAAkC;AAClC,mEAAmE;AACnE,oEAAoE;AAIpE,MAAM,CAAC,MAAM,cAAc,GAA4B,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAU,CAAC;AAEtG,MAAM,CAAC,MAAM,aAAa,GAAiC;IACzD,GAAG,EAAE,KAAK;IACV,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,oBAAoB;IAChC,IAAI,EAAE,MAAM;CACb,CAAC;AAOF,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,EAAE,MAAM,EAAmB;IAC3D,MAAM,WAAW,GAAiC;QAChD,GAAG,EAAE,eAAe;QACpB,IAAI,EAAE,qBAAqB;QAC3B,UAAU,EAAE,cAAc;QAC1B,IAAI,EAAE,6CAA6C;KACpD,CAAC;IAEF,MAAM,GAAG,GAA4B;QACnC,IAAI;QACJ,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE;YACP,GAAG,EAAE,UAAU;YACf,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;YAC1B,SAAS,EAAE,cAAc;SAC1B;QACD,YAAY,EAAE;YACZ,YAAY,EAAE,QAAQ;YACtB,KAAK,EAAE,SAAS;YAChB,WAAW,EAAE,SAAS;SACvB;QACD,eAAe,EAAE;YACf,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,SAAS;YAC7B,UAAU,EAAE,QAAQ;YACpB,IAAI,EAAE,QAAQ;SACf;KACF,CAAC;IAEF,2DAA2D;IAC3D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACrB,GAAG,CAAC,eAA0C,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC;IAC7E,CAAC;IAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,MAAM,MAAM,GAAG;QACb,eAAe,EAAE;YACf,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,QAAQ;YAChB,gBAAgB,EAAE,SAAS;YAC3B,GAAG,EAAE,WAAW;YAChB,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,IAAI;YACZ,eAAe,EAAE,IAAI;YACrB,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,IAAI;YACrB,oBAAoB,EAAE,IAAI;SAC3B;QACD,OAAO,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;KACjC,CAAC;IACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;;;;;;CAMR,CAAC;AACF,CAAC;AAED,mEAAmE;AAEnE,MAAM,eAAe,GAAG;;;;;;;;;;;;;;CAcvB,CAAC;AAEF,MAAM,eAAe,GAAiC;IACpD,GAAG,EAAE;;;;;;;CAON;IACC,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;CAsBP;IACC,UAAU,EAAE;;CAEb;IACC,IAAI,EAAE;;;;CAIP;CACA,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,MAAoB;IAC9C,OAAO,eAAe,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO;;;;;;;;;;;;;;;;;CAiBR,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for the Juice compiler.
|
|
3
|
+
*
|
|
4
|
+
* Every error provides:
|
|
5
|
+
* 1. **What** went wrong.
|
|
6
|
+
* 2. **Why** it went wrong.
|
|
7
|
+
* 3. **Exactly how to fix it.**
|
|
8
|
+
*
|
|
9
|
+
* @module errors
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The two directive types supported by the Juice compiler.
|
|
13
|
+
*/
|
|
14
|
+
export type DirectiveType = 'use client' | 'use server';
|
|
15
|
+
/**
|
|
16
|
+
* Thrown when a `'use client'` directive is found in an invalid position.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```
|
|
20
|
+
* JuiceDirectiveError: 'use client' must be the first statement in
|
|
21
|
+
* components/Counter.tsx. Found 'ImportDeclaration' at line 1 instead.
|
|
22
|
+
* Move the directive to the very first line of the file.
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class JuiceDirectiveError extends Error {
|
|
26
|
+
readonly name = "JuiceDirectiveError";
|
|
27
|
+
constructor(file: string, actualNodeType: string, line: number);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when a directive module exports nothing.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```
|
|
34
|
+
* JuiceExportError: components/Counter.tsx has a 'use client' directive
|
|
35
|
+
* but exports nothing. Directive modules must export at least one binding.
|
|
36
|
+
* Did you forget to add 'export default'?
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare class JuiceExportError extends Error {
|
|
40
|
+
readonly name = "JuiceExportError";
|
|
41
|
+
constructor(file: string, directive?: DirectiveType);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Thrown when a module contains BOTH `'use client'` and `'use server'` directives.
|
|
45
|
+
*
|
|
46
|
+
* A module cannot be both a client component and a server action — they have
|
|
47
|
+
* fundamentally incompatible execution semantics. Split the code into two files.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```
|
|
51
|
+
* JuiceMutualExclusionError: components/Mixed.tsx contains both 'use client'
|
|
52
|
+
* and 'use server' directives. A module cannot be both. Split the client
|
|
53
|
+
* component and server action into separate files.
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare class JuiceMutualExclusionError extends Error {
|
|
57
|
+
readonly name = "JuiceMutualExclusionError";
|
|
58
|
+
constructor(file: string);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Thrown when a directive module uses `export * from '...'` which is unsupported.
|
|
62
|
+
*
|
|
63
|
+
* React requires explicit exports for client/server boundary modules because
|
|
64
|
+
* each export becomes a separately addressable reference in the Flight protocol.
|
|
65
|
+
* Barrel re-exports (`export *`) lose the explicit mapping.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```
|
|
69
|
+
* JuiceBarrelExportError: components/index.tsx uses 'export * from' with
|
|
70
|
+
* a 'use client' directive. Only explicit named exports are allowed in
|
|
71
|
+
* directive modules. Replace with: export { Counter, Badge } from './Counter';
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare class JuiceBarrelExportError extends Error {
|
|
75
|
+
readonly name = "JuiceBarrelExportError";
|
|
76
|
+
constructor(file: string, directive: DirectiveType, source: string);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Thrown when the Flight manifest cannot be written to disk.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```
|
|
83
|
+
* JuiceManifestError: Failed to write flight-manifest.json to dist/.
|
|
84
|
+
* Ensure the output directory exists and is writable. Path: /abs/dist/flight-manifest.json
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare class JuiceManifestError extends Error {
|
|
88
|
+
readonly name = "JuiceManifestError";
|
|
89
|
+
constructor(outDir: string, fullPath: string, cause?: unknown);
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/compiler/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,YAAY,CAAC;AAExD;;;;;;;;;GASG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,SAAkB,IAAI,yBAAyB;gBAEnC,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAO/D;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,SAAkB,IAAI,sBAAsB;gBAEhC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,aAA4B;CAOlE;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;IAClD,SAAkB,IAAI,+BAA+B;gBAEzC,IAAI,EAAE,MAAM;CAOzB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAkB,IAAI,4BAA4B;gBAEtC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM;CASnE;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAkB,IAAI,wBAAwB;gBAElC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAQ9D"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for the Juice compiler.
|
|
3
|
+
*
|
|
4
|
+
* Every error provides:
|
|
5
|
+
* 1. **What** went wrong.
|
|
6
|
+
* 2. **Why** it went wrong.
|
|
7
|
+
* 3. **Exactly how to fix it.**
|
|
8
|
+
*
|
|
9
|
+
* @module errors
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Thrown when a `'use client'` directive is found in an invalid position.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```
|
|
16
|
+
* JuiceDirectiveError: 'use client' must be the first statement in
|
|
17
|
+
* components/Counter.tsx. Found 'ImportDeclaration' at line 1 instead.
|
|
18
|
+
* Move the directive to the very first line of the file.
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export class JuiceDirectiveError extends Error {
|
|
22
|
+
name = 'JuiceDirectiveError';
|
|
23
|
+
constructor(file, actualNodeType, line) {
|
|
24
|
+
super(`'use client' must be the first statement in ${file}. ` +
|
|
25
|
+
`Found '${actualNodeType}' at line ${line} instead. ` +
|
|
26
|
+
`Move the directive to the very first line of the file.`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Thrown when a directive module exports nothing.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```
|
|
34
|
+
* JuiceExportError: components/Counter.tsx has a 'use client' directive
|
|
35
|
+
* but exports nothing. Directive modules must export at least one binding.
|
|
36
|
+
* Did you forget to add 'export default'?
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class JuiceExportError extends Error {
|
|
40
|
+
name = 'JuiceExportError';
|
|
41
|
+
constructor(file, directive = 'use client') {
|
|
42
|
+
super(`${file} has a '${directive}' directive but exports nothing. ` +
|
|
43
|
+
`Directive modules must export at least one binding. ` +
|
|
44
|
+
`Did you forget to add 'export default' or 'export function'?`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Thrown when a module contains BOTH `'use client'` and `'use server'` directives.
|
|
49
|
+
*
|
|
50
|
+
* A module cannot be both a client component and a server action — they have
|
|
51
|
+
* fundamentally incompatible execution semantics. Split the code into two files.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```
|
|
55
|
+
* JuiceMutualExclusionError: components/Mixed.tsx contains both 'use client'
|
|
56
|
+
* and 'use server' directives. A module cannot be both. Split the client
|
|
57
|
+
* component and server action into separate files.
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export class JuiceMutualExclusionError extends Error {
|
|
61
|
+
name = 'JuiceMutualExclusionError';
|
|
62
|
+
constructor(file) {
|
|
63
|
+
super(`${file} contains both 'use client' and 'use server' directives. ` +
|
|
64
|
+
`A module cannot be both a client component and a server action. ` +
|
|
65
|
+
`Split the client component and server action into separate files.`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Thrown when a directive module uses `export * from '...'` which is unsupported.
|
|
70
|
+
*
|
|
71
|
+
* React requires explicit exports for client/server boundary modules because
|
|
72
|
+
* each export becomes a separately addressable reference in the Flight protocol.
|
|
73
|
+
* Barrel re-exports (`export *`) lose the explicit mapping.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```
|
|
77
|
+
* JuiceBarrelExportError: components/index.tsx uses 'export * from' with
|
|
78
|
+
* a 'use client' directive. Only explicit named exports are allowed in
|
|
79
|
+
* directive modules. Replace with: export { Counter, Badge } from './Counter';
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export class JuiceBarrelExportError extends Error {
|
|
83
|
+
name = 'JuiceBarrelExportError';
|
|
84
|
+
constructor(file, directive, source) {
|
|
85
|
+
super(`${file} uses 'export * from ${JSON.stringify(source)}' with a ` +
|
|
86
|
+
`'${directive}' directive. Only explicit named exports are allowed ` +
|
|
87
|
+
`in directive modules because each export must be individually ` +
|
|
88
|
+
`addressable in the Flight protocol. ` +
|
|
89
|
+
`Replace with: export { SpecificExport } from ${JSON.stringify(source)};`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Thrown when the Flight manifest cannot be written to disk.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```
|
|
97
|
+
* JuiceManifestError: Failed to write flight-manifest.json to dist/.
|
|
98
|
+
* Ensure the output directory exists and is writable. Path: /abs/dist/flight-manifest.json
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
export class JuiceManifestError extends Error {
|
|
102
|
+
name = 'JuiceManifestError';
|
|
103
|
+
constructor(outDir, fullPath, cause) {
|
|
104
|
+
super(`Failed to write flight-manifest.json to ${outDir}. ` +
|
|
105
|
+
`Ensure the output directory exists and is writable. ` +
|
|
106
|
+
`Path: ${fullPath}`);
|
|
107
|
+
this.cause = cause;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/compiler/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH;;;;;;;;;GASG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC1B,IAAI,GAAG,qBAAqB,CAAC;IAE/C,YAAY,IAAY,EAAE,cAAsB,EAAE,IAAY;QAC5D,KAAK,CACH,+CAA+C,IAAI,IAAI;YACvD,UAAU,cAAc,aAAa,IAAI,YAAY;YACrD,wDAAwD,CACzD,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IACvB,IAAI,GAAG,kBAAkB,CAAC;IAE5C,YAAY,IAAY,EAAE,YAA2B,YAAY;QAC/D,KAAK,CACH,GAAG,IAAI,WAAW,SAAS,mCAAmC;YAC9D,sDAAsD;YACtD,8DAA8D,CAC/D,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAChC,IAAI,GAAG,2BAA2B,CAAC;IAErD,YAAY,IAAY;QACtB,KAAK,CACH,GAAG,IAAI,2DAA2D;YAClE,kEAAkE;YAClE,mEAAmE,CACpE,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC7B,IAAI,GAAG,wBAAwB,CAAC;IAElD,YAAY,IAAY,EAAE,SAAwB,EAAE,MAAc;QAChE,KAAK,CACH,GAAG,IAAI,wBAAwB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW;YAChE,IAAI,SAAS,uDAAuD;YACpE,gEAAgE;YAChE,sCAAsC;YACtC,gDAAgD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,CAC1E,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACzB,IAAI,GAAG,oBAAoB,CAAC;IAE9C,YAAY,MAAc,EAAE,QAAgB,EAAE,KAAe;QAC3D,KAAK,CACH,2CAA2C,MAAM,IAAI;YACrD,sDAAsD;YACtD,SAAS,QAAQ,EAAE,CACpB,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits the `flight-manifest.json` file that maps server component references
|
|
3
|
+
* to client-side chunks.
|
|
4
|
+
*
|
|
5
|
+
* @module manifest
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
import type { FlightManifest, ManifestRouteEntry } from './types.js';
|
|
9
|
+
import type { ClientModuleRegistry } from './registry.js';
|
|
10
|
+
import type { ServerActionRegistry } from './server-action-registry.js';
|
|
11
|
+
/**
|
|
12
|
+
* Build the {@link FlightManifest} object from the registries and resolved
|
|
13
|
+
* chunk file names.
|
|
14
|
+
*
|
|
15
|
+
* @param clientRegistry - The populated client module registry.
|
|
16
|
+
* @param chunkMap - Maps module specifiers to their emitted chunk file paths
|
|
17
|
+
* (e.g., `'components/Counter.tsx' → ['client/Counter.CxK3d.js']`).
|
|
18
|
+
* @param serverRegistry - Optional server action registry.
|
|
19
|
+
* @param routes - Optional route map (pattern → module info).
|
|
20
|
+
* @returns The complete manifest ready for JSON serialization.
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function _buildManifest(clientRegistry: ClientModuleRegistry, chunkMap: ReadonlyMap<string, readonly string[]>, serverRegistry?: ServerActionRegistry, routes?: Readonly<Record<string, ManifestRouteEntry>>, meta?: FlightManifest['_meta']): FlightManifest;
|
|
25
|
+
/**
|
|
26
|
+
* Serialize the manifest to a human-readable JSON string.
|
|
27
|
+
*
|
|
28
|
+
* The output is intentionally pretty-printed (2-space indent) because the
|
|
29
|
+
* manifest is a build artifact consumed by the server runtime — human
|
|
30
|
+
* readability aids debugging and diffs. Size is irrelevant as it is never
|
|
31
|
+
* sent to clients.
|
|
32
|
+
*
|
|
33
|
+
* @param manifest - The manifest to serialize.
|
|
34
|
+
* @returns A JSON string with 2-space indentation.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export declare function _serializeManifest(manifest: FlightManifest): string;
|
|
39
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/compiler/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,cAAc,EAGd,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,cAAc,EAAE,oBAAoB,EACpC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAChD,cAAc,CAAC,EAAE,oBAAoB,EACrC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,EACrD,IAAI,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,GAC7B,cAAc,CA6ChB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAEnE"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits the `flight-manifest.json` file that maps server component references
|
|
3
|
+
* to client-side chunks.
|
|
4
|
+
*
|
|
5
|
+
* @module manifest
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Build the {@link FlightManifest} object from the registries and resolved
|
|
10
|
+
* chunk file names.
|
|
11
|
+
*
|
|
12
|
+
* @param clientRegistry - The populated client module registry.
|
|
13
|
+
* @param chunkMap - Maps module specifiers to their emitted chunk file paths
|
|
14
|
+
* (e.g., `'components/Counter.tsx' → ['client/Counter.CxK3d.js']`).
|
|
15
|
+
* @param serverRegistry - Optional server action registry.
|
|
16
|
+
* @param routes - Optional route map (pattern → module info).
|
|
17
|
+
* @returns The complete manifest ready for JSON serialization.
|
|
18
|
+
*
|
|
19
|
+
* @internal
|
|
20
|
+
*/
|
|
21
|
+
export function _buildManifest(clientRegistry, chunkMap, serverRegistry, routes, meta) {
|
|
22
|
+
const clientModules = {};
|
|
23
|
+
for (const [specifier, info] of clientRegistry.entries()) {
|
|
24
|
+
const chunks = chunkMap.get(specifier) ?? [];
|
|
25
|
+
const exports = {};
|
|
26
|
+
for (const exp of info.exports) {
|
|
27
|
+
exports[exp.exportedName] = {
|
|
28
|
+
id: `${specifier}#${exp.exportedName}`,
|
|
29
|
+
name: exp.exportedName,
|
|
30
|
+
chunks: [...chunks],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
clientModules[specifier] = {
|
|
34
|
+
chunks: [...chunks],
|
|
35
|
+
exports,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Build server actions map — field names aligned with runtime ServerActionRef
|
|
39
|
+
const serverActions = {};
|
|
40
|
+
if (serverRegistry) {
|
|
41
|
+
for (const [specifier, info] of serverRegistry.entries()) {
|
|
42
|
+
for (const exp of info.exports) {
|
|
43
|
+
const actionId = `${specifier}#${exp.exportedName}`;
|
|
44
|
+
serverActions[actionId] = {
|
|
45
|
+
id: actionId,
|
|
46
|
+
exportName: exp.exportedName,
|
|
47
|
+
moduleId: specifier,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
$schema: 'https://juice.dev/schemas/flight-manifest.v1.json',
|
|
54
|
+
version: 1,
|
|
55
|
+
routes: routes ?? {},
|
|
56
|
+
clientModules,
|
|
57
|
+
ssrModules: {},
|
|
58
|
+
serverActions,
|
|
59
|
+
...(meta ? { _meta: meta } : {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Serialize the manifest to a human-readable JSON string.
|
|
64
|
+
*
|
|
65
|
+
* The output is intentionally pretty-printed (2-space indent) because the
|
|
66
|
+
* manifest is a build artifact consumed by the server runtime — human
|
|
67
|
+
* readability aids debugging and diffs. Size is irrelevant as it is never
|
|
68
|
+
* sent to clients.
|
|
69
|
+
*
|
|
70
|
+
* @param manifest - The manifest to serialize.
|
|
71
|
+
* @returns A JSON string with 2-space indentation.
|
|
72
|
+
*
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
export function _serializeManifest(manifest) {
|
|
76
|
+
return JSON.stringify(manifest, null, 2) + '\n';
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/compiler/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,cAAoC,EACpC,QAAgD,EAChD,cAAqC,EACrC,MAAqD,EACrD,IAA8B;IAE9B,MAAM,aAAa,GAAwC,EAAE,CAAC;IAE9D,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAE7C,MAAM,OAAO,GAAwC,EAAE,CAAC;QACxD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG;gBAC1B,EAAE,EAAE,GAAG,SAAS,IAAI,GAAG,CAAC,YAAY,EAAE;gBACtC,IAAI,EAAE,GAAG,CAAC,YAAY;gBACtB,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;aACpB,CAAC;QACJ,CAAC;QAED,aAAa,CAAC,SAAS,CAAC,GAAG;YACzB,MAAM,EAAE,CAAC,GAAG,MAAM,CAAC;YACnB,OAAO;SACR,CAAC;IACJ,CAAC;IAED,8EAA8E;IAC9E,MAAM,aAAa,GAA8C,EAAE,CAAC;IACpE,IAAI,cAAc,EAAE,CAAC;QACnB,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC;YACzD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,GAAG,SAAS,IAAI,GAAG,CAAC,YAAY,EAAE,CAAC;gBACpD,aAAa,CAAC,QAAQ,CAAC,GAAG;oBACxB,EAAE,EAAE,QAAQ;oBACZ,UAAU,EAAE,GAAG,CAAC,YAAY;oBAC5B,QAAQ,EAAE,SAAS;iBACpB,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,EAAE,mDAAmD;QAC5D,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,MAAM,IAAI,EAAE;QACpB,aAAa;QACb,UAAU,EAAE,EAAE;QACd,aAAa;QACb,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAwB;IACzD,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-based detection of `'use client'` and `'use server'` directives
|
|
3
|
+
* and export extraction.
|
|
4
|
+
*
|
|
5
|
+
* Uses Vite's built-in acorn parser via the Rollup plugin context — zero
|
|
6
|
+
* additional dependencies.
|
|
7
|
+
*
|
|
8
|
+
* @module parse
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
import type { ExportRecord } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Quick check for the `'use client'` substring before doing a full AST parse.
|
|
14
|
+
* Returns `false` if the directive cannot possibly be present.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
export declare function _mayContainClientDirective(source: string): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Quick check for the `'use server'` substring before doing a full AST parse.
|
|
21
|
+
* Returns `false` if the directive cannot possibly be present.
|
|
22
|
+
*
|
|
23
|
+
* @internal
|
|
24
|
+
*/
|
|
25
|
+
export declare function _mayContainServerDirective(source: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Quick check for either `'use client'` or `'use server'` substrings.
|
|
28
|
+
* Returns `false` if neither directive can possibly be present.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export declare function _mayContainDirective(source: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Result of analyzing a module's AST for the `'use client'` directive.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export type DirectiveResult = {
|
|
39
|
+
readonly hasDirective: false;
|
|
40
|
+
} | {
|
|
41
|
+
readonly hasDirective: true;
|
|
42
|
+
readonly exports: readonly ExportRecord[];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Analyze a parsed AST `Program` node for a `'use client'` directive and
|
|
46
|
+
* extract all exports if found.
|
|
47
|
+
*
|
|
48
|
+
* The directive MUST be the first statement in the module body (after optional
|
|
49
|
+
* comments). If `'use client'` appears anywhere other than position 0, this
|
|
50
|
+
* function returns `{ hasDirective: false }` — no false positives.
|
|
51
|
+
*
|
|
52
|
+
* @param ast - The acorn `Program` AST node (from `this.parse()` in Rollup context).
|
|
53
|
+
* @returns A {@link DirectiveResult} indicating whether the directive was found
|
|
54
|
+
* and, if so, all exports extracted from the module.
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export declare function _analyzeAST(ast: unknown): DirectiveResult;
|
|
59
|
+
/**
|
|
60
|
+
* Result of analyzing a module's AST for the `'use server'` directive.
|
|
61
|
+
*
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
export type ServerDirectiveResult = {
|
|
65
|
+
readonly hasDirective: false;
|
|
66
|
+
} | {
|
|
67
|
+
readonly hasDirective: true;
|
|
68
|
+
readonly exports: readonly ExportRecord[];
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Analyze a parsed AST `Program` node for a `'use server'` directive and
|
|
72
|
+
* extract all exports if found.
|
|
73
|
+
*
|
|
74
|
+
* The directive MUST be the first statement in the module body (after optional
|
|
75
|
+
* comments). If `'use server'` appears anywhere other than position 0, this
|
|
76
|
+
* function returns `{ hasDirective: false }` — no false positives.
|
|
77
|
+
*
|
|
78
|
+
* @param ast - The acorn `Program` AST node (from `this.parse()` in Rollup context).
|
|
79
|
+
* @returns A {@link ServerDirectiveResult} indicating whether the directive was found
|
|
80
|
+
* and, if so, all exports extracted from the module.
|
|
81
|
+
*
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export declare function _analyzeServerAST(ast: unknown): ServerDirectiveResult;
|
|
85
|
+
/**
|
|
86
|
+
* Detected directive type from a module's AST.
|
|
87
|
+
*
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
export type DetectedDirective = 'use client' | 'use server' | null;
|
|
91
|
+
/**
|
|
92
|
+
* Unified result from `_detectDirective` — detects which directive (if any)
|
|
93
|
+
* is present and extracts exports, barrel re-export sources, and flags for
|
|
94
|
+
* mutual exclusion validation.
|
|
95
|
+
*
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
export interface UnifiedDirectiveResult {
|
|
99
|
+
/** Which directive was detected, or `null` if none. */
|
|
100
|
+
readonly directive: DetectedDirective;
|
|
101
|
+
/** All explicit exports found in the module. */
|
|
102
|
+
readonly exports: readonly ExportRecord[];
|
|
103
|
+
/** Sources of any `export * from '...'` barrel re-exports. */
|
|
104
|
+
readonly barrelReExports: readonly string[];
|
|
105
|
+
/**
|
|
106
|
+
* Whether both `'use client'` and `'use server'` appear as directives
|
|
107
|
+
* in the AST. This is a fatal error condition.
|
|
108
|
+
*/
|
|
109
|
+
readonly hasMutualExclusion: boolean;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Detect the directive (if any), extract exports, and perform validation
|
|
113
|
+
* checks in a single AST pass for the hardened pipeline.
|
|
114
|
+
*
|
|
115
|
+
* Advantages over calling `_analyzeAST` + `_analyzeServerAST` separately:
|
|
116
|
+
* - Single AST walk (not two)
|
|
117
|
+
* - Catches mutual exclusion (`'use client'` + `'use server'` simultaneously)
|
|
118
|
+
* - Detects barrel re-exports (`export *`) for a clear error
|
|
119
|
+
*
|
|
120
|
+
* @param ast - The acorn `Program` AST node.
|
|
121
|
+
* @returns A {@link UnifiedDirectiveResult} with all extracted information.
|
|
122
|
+
*
|
|
123
|
+
* @internal
|
|
124
|
+
*/
|
|
125
|
+
export declare function _detectDirective(ast: unknown): UnifiedDirectiveResult;
|
|
126
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/compiler/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAkE/C;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE5D;AAMD;;;;GAIG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAiBzD;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAC7B;IAAE,QAAQ,CAAC,YAAY,EAAE,KAAK,CAAA;CAAE,GAChC;IAAE,QAAQ,CAAC,YAAY,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAA;CAAE,CAAC;AAE/E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,qBAAqB,CAiBrE;AAMD;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,YAAY,GAAG,IAAI,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IAEtC,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,CAAC;IAE1C,8DAA8D;IAC9D,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAE5C;;;OAGG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,sBAAsB,CAiDrE"}
|