@nexus_js/compiler 0.6.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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/codegen.d.ts +4 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +308 -0
- package/dist/codegen.js.map +1 -0
- package/dist/css-scope.d.ts +76 -0
- package/dist/css-scope.d.ts.map +1 -0
- package/dist/css-scope.js +327 -0
- package/dist/css-scope.js.map +1 -0
- package/dist/guard.d.ts +59 -0
- package/dist/guard.d.ts.map +1 -0
- package/dist/guard.js +212 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/island-ssr-stubs.d.ts +25 -0
- package/dist/island-ssr-stubs.d.ts.map +1 -0
- package/dist/island-ssr-stubs.js +107 -0
- package/dist/island-ssr-stubs.js.map +1 -0
- package/dist/island-wrap.d.ts +19 -0
- package/dist/island-wrap.d.ts.map +1 -0
- package/dist/island-wrap.js +108 -0
- package/dist/island-wrap.js.map +1 -0
- package/dist/parser.d.ts +28 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +128 -0
- package/dist/parser.js.map +1 -0
- package/dist/preload-scanner.d.ts +60 -0
- package/dist/preload-scanner.d.ts.map +1 -0
- package/dist/preload-scanner.js +156 -0
- package/dist/preload-scanner.js.map +1 -0
- package/dist/server-actions-extract.d.ts +9 -0
- package/dist/server-actions-extract.d.ts.map +1 -0
- package/dist/server-actions-extract.js +89 -0
- package/dist/server-actions-extract.js.map +1 -0
- package/dist/types.d.ts +98 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,8BAA8B,EAAE,MAAM,6BAA6B,CAAC;AAgB7E,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,6DAA6D;AAC7D,MAAM,UAAU,OAAO,CACrB,MAAc,EACd,QAAgB,EAChB,OAAgC,EAAE;IAElC,MAAM,OAAO,GAAmB;QAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,QAAQ;QAC3B,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,KAAK;QACtB,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,IAAI;QACrB,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,IAAI,IAAI;QACnD,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,MAAM;QAC7B,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,OAAO,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the template is wrapped in <nexus-island>, SSR still stringifies the inner HTML.
|
|
3
|
+
* Runes ($state/$derived) and client handlers are not available on the server — emit safe stubs.
|
|
4
|
+
*/
|
|
5
|
+
/** Pull `name` from `let name = $state(` / `$derived(` / `$effect(` (best-effort). */
|
|
6
|
+
export declare function listRuneBindingNames(script: string): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Extract `let x = $state( INITIAL );` initializers (handles generic `$state<T>(` and nested parens).
|
|
9
|
+
*/
|
|
10
|
+
export declare function extractDollarStateInitializers(script: string): Map<string, string>;
|
|
11
|
+
export declare function extractDollarDerivedBodies(script: string): Map<string, string>;
|
|
12
|
+
/**
|
|
13
|
+
* `function foo` / `async function foo` anywhere in the script (best-effort).
|
|
14
|
+
* Previously only the slice before the first `$effect` was scanned, which missed handlers
|
|
15
|
+
* declared after reactive blocks (e.g. `onSearchInput` after several `$effect`s).
|
|
16
|
+
*/
|
|
17
|
+
export declare function listTopLevelFunctions(script: string): {
|
|
18
|
+
name: string;
|
|
19
|
+
async: boolean;
|
|
20
|
+
}[];
|
|
21
|
+
/**
|
|
22
|
+
* Lines to prepend inside `async function renderTemplate(ctx)` before `return \`...\``.
|
|
23
|
+
*/
|
|
24
|
+
export declare function islandSsrStubLines(script: string): string[];
|
|
25
|
+
//# sourceMappingURL=island-ssr-stubs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-ssr-stubs.d.ts","sourceRoot":"","sources":["../src/island-ssr-stubs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAS7D;AAeD;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAalF;AAED,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAY9E;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EAAE,CAQxF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CA4B3D"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* When the template is wrapped in <nexus-island>, SSR still stringifies the inner HTML.
|
|
3
|
+
* Runes ($state/$derived) and client handlers are not available on the server — emit safe stubs.
|
|
4
|
+
*/
|
|
5
|
+
/** Pull `name` from `let name = $state(` / `$derived(` / `$effect(` (best-effort). */
|
|
6
|
+
export function listRuneBindingNames(script) {
|
|
7
|
+
const names = [];
|
|
8
|
+
const re = /(?:let|const)\s+(\w+)\s*=\s*\$(?:state|derived|effect)\s*\(/g;
|
|
9
|
+
let m;
|
|
10
|
+
while ((m = re.exec(script)) !== null) {
|
|
11
|
+
const n = m[1];
|
|
12
|
+
if (n)
|
|
13
|
+
names.push(n);
|
|
14
|
+
}
|
|
15
|
+
return names;
|
|
16
|
+
}
|
|
17
|
+
function balancedFrom(openParenIdx, s) {
|
|
18
|
+
let depth = 1;
|
|
19
|
+
for (let i = openParenIdx + 1; i < s.length; i++) {
|
|
20
|
+
const c = s[i];
|
|
21
|
+
if (c === '(')
|
|
22
|
+
depth++;
|
|
23
|
+
else if (c === ')') {
|
|
24
|
+
depth--;
|
|
25
|
+
if (depth === 0)
|
|
26
|
+
return i;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Extract `let x = $state( INITIAL );` initializers (handles generic `$state<T>(` and nested parens).
|
|
33
|
+
*/
|
|
34
|
+
export function extractDollarStateInitializers(script) {
|
|
35
|
+
const map = new Map();
|
|
36
|
+
const re = /\b(?:let|const)\s+(\w+)\s*=\s*\$state(?:<[^>]+>)?\s*\(/g;
|
|
37
|
+
let m;
|
|
38
|
+
while ((m = re.exec(script)) !== null) {
|
|
39
|
+
const name = m[1];
|
|
40
|
+
const open = (m.index ?? 0) + m[0].length - 1;
|
|
41
|
+
const close = balancedFrom(open, script);
|
|
42
|
+
if (!name || close === null)
|
|
43
|
+
continue;
|
|
44
|
+
const inner = script.slice(open + 1, close).trim();
|
|
45
|
+
map.set(name, inner);
|
|
46
|
+
}
|
|
47
|
+
return map;
|
|
48
|
+
}
|
|
49
|
+
export function extractDollarDerivedBodies(script) {
|
|
50
|
+
const map = new Map();
|
|
51
|
+
const re = /\b(?:let|const)\s+(\w+)\s*=\s*\$derived\s*\(/g;
|
|
52
|
+
let m;
|
|
53
|
+
while ((m = re.exec(script)) !== null) {
|
|
54
|
+
const name = m[1];
|
|
55
|
+
const open = (m.index ?? 0) + m[0].length - 1;
|
|
56
|
+
const close = balancedFrom(open, script);
|
|
57
|
+
if (!name || close === null)
|
|
58
|
+
continue;
|
|
59
|
+
map.set(name, script.slice(open + 1, close).trim());
|
|
60
|
+
}
|
|
61
|
+
return map;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* `function foo` / `async function foo` anywhere in the script (best-effort).
|
|
65
|
+
* Previously only the slice before the first `$effect` was scanned, which missed handlers
|
|
66
|
+
* declared after reactive blocks (e.g. `onSearchInput` after several `$effect`s).
|
|
67
|
+
*/
|
|
68
|
+
export function listTopLevelFunctions(script) {
|
|
69
|
+
const out = [];
|
|
70
|
+
const re = /\b(async\s+)?function\s+(\w+)\s*\(/g;
|
|
71
|
+
let m;
|
|
72
|
+
while ((m = re.exec(script)) !== null) {
|
|
73
|
+
out.push({ name: m[2] ?? 'fn', async: Boolean(m[1]) });
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Lines to prepend inside `async function renderTemplate(ctx)` before `return \`...\``.
|
|
79
|
+
*/
|
|
80
|
+
export function islandSsrStubLines(script) {
|
|
81
|
+
const lines = [];
|
|
82
|
+
const stateInits = extractDollarStateInitializers(script);
|
|
83
|
+
const derivedBodies = extractDollarDerivedBodies(script);
|
|
84
|
+
const runeNames = new Set(listRuneBindingNames(script));
|
|
85
|
+
for (const fn of listTopLevelFunctions(script)) {
|
|
86
|
+
const rhs = fn.async ? 'async () => {}' : '() => {}';
|
|
87
|
+
lines.push(` const ${fn.name} = ${rhs};`);
|
|
88
|
+
}
|
|
89
|
+
for (const [name, init] of stateInits) {
|
|
90
|
+
lines.push(` const ${name} = (${init});`);
|
|
91
|
+
}
|
|
92
|
+
for (const [name, body] of derivedBodies) {
|
|
93
|
+
const expr = body.replace(/,\s*$/u, '').trim();
|
|
94
|
+
lines.push(` const ${name} = (${expr});`);
|
|
95
|
+
}
|
|
96
|
+
for (const name of runeNames) {
|
|
97
|
+
if (stateInits.has(name))
|
|
98
|
+
continue;
|
|
99
|
+
if (derivedBodies.has(name))
|
|
100
|
+
continue;
|
|
101
|
+
if (lines.some((l) => l.includes(` const ${name} = `)))
|
|
102
|
+
continue;
|
|
103
|
+
lines.push(` const ${name} = [];`);
|
|
104
|
+
}
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=island-ssr-stubs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-ssr-stubs.js","sourceRoot":"","sources":["../src/island-ssr-stubs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps every element that uses a client:* hydration directive in <nexus-island>,
|
|
3
|
+
* so the Node dev server can serve a real ESM bundle at /_nexus/islands/client.mjs.
|
|
4
|
+
* Multiple islands per page share one client module; each wrapper gets data-nexus-island-index.
|
|
5
|
+
*/
|
|
6
|
+
export interface IslandWrapResult {
|
|
7
|
+
template: string;
|
|
8
|
+
/** First island inner root (backward compat for single-island callers) */
|
|
9
|
+
clientTemplate: string | null;
|
|
10
|
+
/** One HTML fragment per island (same order as data-nexus-island-index) */
|
|
11
|
+
clientFragments: string[];
|
|
12
|
+
didWrap: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Finds every tag with a `client:*` directive and wraps each (balanced subtree)
|
|
16
|
+
* in <nexus-island> pointing at /_nexus/islands/client.mjs.
|
|
17
|
+
*/
|
|
18
|
+
export declare function wrapSelfClientIslandMarkers(template: string, absFilePath: string, appRoot?: string): IslandWrapResult;
|
|
19
|
+
//# sourceMappingURL=island-wrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-wrap.d.ts","sourceRoot":"","sources":["../src/island-wrap.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAuDH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2EAA2E;IAC3E,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,gBAAgB,CA4DlB"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps every element that uses a client:* hydration directive in <nexus-island>,
|
|
3
|
+
* so the Node dev server can serve a real ESM bundle at /_nexus/islands/client.mjs.
|
|
4
|
+
* Multiple islands per page share one client module; each wrapper gets data-nexus-island-index.
|
|
5
|
+
*/
|
|
6
|
+
import { relative } from 'node:path';
|
|
7
|
+
const CLIENT_DIR_RE = /\sclient:(load|idle|visible|media)(?:=["']([^"']*)["'])?/;
|
|
8
|
+
/** Opening tag that contains client:(load|idle|visible|media). */
|
|
9
|
+
const OPEN_WITH_CLIENT_RE = /<([a-zA-Z][\w-]*)(\s[^>]*\sclient:(?:load|idle|visible|media)(?:=["'][^"']*["'])?[^>]*)\s*>/;
|
|
10
|
+
function extractBalanced(html, openEnd, tag) {
|
|
11
|
+
const reOpen = new RegExp(`<${tag}(\\s[^>]*)?>`, 'gi');
|
|
12
|
+
const reClose = new RegExp(`</${tag}\\s*>`, 'gi');
|
|
13
|
+
let depth = 1;
|
|
14
|
+
let i = openEnd;
|
|
15
|
+
while (i < html.length && depth > 0) {
|
|
16
|
+
reOpen.lastIndex = i;
|
|
17
|
+
reClose.lastIndex = i;
|
|
18
|
+
const mo = reOpen.exec(html);
|
|
19
|
+
const mc = reClose.exec(html);
|
|
20
|
+
const iOpen = mo?.index ?? Number.POSITIVE_INFINITY;
|
|
21
|
+
const iClose = mc?.index ?? Number.POSITIVE_INFINITY;
|
|
22
|
+
if (iClose === Number.POSITIVE_INFINITY)
|
|
23
|
+
return null;
|
|
24
|
+
if (mo && iOpen < iClose) {
|
|
25
|
+
depth++;
|
|
26
|
+
i = iOpen + mo[0].length;
|
|
27
|
+
}
|
|
28
|
+
else if (mc) {
|
|
29
|
+
depth--;
|
|
30
|
+
if (depth === 0) {
|
|
31
|
+
return { inner: html.slice(openEnd, iClose), closeEnd: iClose + mc[0].length };
|
|
32
|
+
}
|
|
33
|
+
i = iClose + mc[0].length;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function stripClientDirective(attrs) {
|
|
42
|
+
return attrs.replace(CLIENT_DIR_RE, ' ').replace(/\s+/g, ' ').trim();
|
|
43
|
+
}
|
|
44
|
+
function islandQueryParam(absFilePath, appRoot) {
|
|
45
|
+
if (appRoot && absFilePath.startsWith(appRoot)) {
|
|
46
|
+
const rel = relative(appRoot, absFilePath).replace(/\\/g, '/');
|
|
47
|
+
return `path=${encodeURIComponent(rel)}`;
|
|
48
|
+
}
|
|
49
|
+
return `abs=${encodeURIComponent(absFilePath)}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Finds every tag with a `client:*` directive and wraps each (balanced subtree)
|
|
53
|
+
* in <nexus-island> pointing at /_nexus/islands/client.mjs.
|
|
54
|
+
*/
|
|
55
|
+
export function wrapSelfClientIslandMarkers(template, absFilePath, appRoot) {
|
|
56
|
+
let t = template;
|
|
57
|
+
const fragments = [];
|
|
58
|
+
const idBase = absFilePath.replace(/[^a-zA-Z0-9]/g, '_');
|
|
59
|
+
const q = islandQueryParam(absFilePath, appRoot);
|
|
60
|
+
const islandUrl = `/_nexus/islands/client.mjs?${q}`;
|
|
61
|
+
while (true) {
|
|
62
|
+
OPEN_WITH_CLIENT_RE.lastIndex = 0;
|
|
63
|
+
const m = OPEN_WITH_CLIENT_RE.exec(t);
|
|
64
|
+
if (!m) {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
const tag = m[1] ?? 'div';
|
|
68
|
+
const fullAttrs = m[2] ?? '';
|
|
69
|
+
const openMatchStart = m.index ?? 0;
|
|
70
|
+
const openTagEnd = openMatchStart + m[0].length;
|
|
71
|
+
const strat = fullAttrs.match(CLIENT_DIR_RE);
|
|
72
|
+
const strategy = (strat?.[1] ?? 'load');
|
|
73
|
+
const mediaQuery = strat?.[2];
|
|
74
|
+
const cleanAttrs = stripClientDirective(fullAttrs);
|
|
75
|
+
const balanced = extractBalanced(t, openTagEnd, tag);
|
|
76
|
+
if (!balanced) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
const innerRootOpen = `<${tag}${cleanAttrs ? ' ' + cleanAttrs : ''}>`;
|
|
80
|
+
const innerRootClose = `</${tag}>`;
|
|
81
|
+
const clientTemplate = innerRootOpen + balanced.inner + innerRootClose;
|
|
82
|
+
fragments.push(clientTemplate);
|
|
83
|
+
const islandIdx = fragments.length - 1;
|
|
84
|
+
const islandId = `island_${idBase}_${islandIdx}`.toLowerCase();
|
|
85
|
+
const dataStrategy = strategy === 'media' && mediaQuery
|
|
86
|
+
? `data-nexus-strategy="client:media" data-nexus-media="${escapeAttr(mediaQuery)}"`
|
|
87
|
+
: `data-nexus-strategy="client:${strategy}"`;
|
|
88
|
+
const wrapped = t.slice(0, openMatchStart) +
|
|
89
|
+
`<nexus-island
|
|
90
|
+
data-nexus-island="${islandId}"
|
|
91
|
+
data-nexus-island-index="${islandIdx}"
|
|
92
|
+
data-nexus-component="${islandUrl}"
|
|
93
|
+
${dataStrategy}
|
|
94
|
+
>${clientTemplate}</nexus-island>` +
|
|
95
|
+
t.slice(balanced.closeEnd);
|
|
96
|
+
t = wrapped;
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
template: t,
|
|
100
|
+
clientTemplate: fragments[0] ?? null,
|
|
101
|
+
clientFragments: fragments,
|
|
102
|
+
didWrap: fragments.length > 0,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function escapeAttr(s) {
|
|
106
|
+
return s.replace(/&/g, '&').replace(/"/g, '"');
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=island-wrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-wrap.js","sourceRoot":"","sources":["../src/island-wrap.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ParsedComponent } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses a .nx source file into its constituent blocks.
|
|
4
|
+
* A .nx file has the structure:
|
|
5
|
+
*
|
|
6
|
+
* ```
|
|
7
|
+
* ---
|
|
8
|
+
* // Server-only frontmatter (Astro-style)
|
|
9
|
+
* import { db } from '$lib/db';
|
|
10
|
+
* const user = await db.user.findFirst();
|
|
11
|
+
* ---
|
|
12
|
+
*
|
|
13
|
+
* <script>
|
|
14
|
+
* // Svelte 5 Runes-style reactive script
|
|
15
|
+
* let count = $state(0);
|
|
16
|
+
* let doubled = $derived(count * 2);
|
|
17
|
+
* </script>
|
|
18
|
+
*
|
|
19
|
+
* <h1>Hello {user.name}</h1>
|
|
20
|
+
* <button onclick={() => count++}>Clicked {count}</button>
|
|
21
|
+
*
|
|
22
|
+
* <style>
|
|
23
|
+
* h1 { color: red; }
|
|
24
|
+
* </style>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function parse(source: string, filepath: string): ParsedComponent;
|
|
28
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAIhB,MAAM,YAAY,CAAC;AAgBpB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CAiFvE"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { extractServerActionsFromSource } from './server-actions-extract.js';
|
|
2
|
+
/** Regex patterns for parsing .nx files */
|
|
3
|
+
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
4
|
+
const SCRIPT_BLOCK_RE = /<script(?:\s[^>]*)?>(\n[\s\S]*?)<\/script>/;
|
|
5
|
+
const STYLE_BLOCK_RE = /<style(?:\s[^>]*)?>(\n[\s\S]*?)<\/style>/;
|
|
6
|
+
const ISLAND_DIRECTIVES = [
|
|
7
|
+
'client:load',
|
|
8
|
+
'client:idle',
|
|
9
|
+
'client:visible',
|
|
10
|
+
'client:media',
|
|
11
|
+
'server:only',
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Parses a .nx source file into its constituent blocks.
|
|
15
|
+
* A .nx file has the structure:
|
|
16
|
+
*
|
|
17
|
+
* ```
|
|
18
|
+
* ---
|
|
19
|
+
* // Server-only frontmatter (Astro-style)
|
|
20
|
+
* import { db } from '$lib/db';
|
|
21
|
+
* const user = await db.user.findFirst();
|
|
22
|
+
* ---
|
|
23
|
+
*
|
|
24
|
+
* <script>
|
|
25
|
+
* // Svelte 5 Runes-style reactive script
|
|
26
|
+
* let count = $state(0);
|
|
27
|
+
* let doubled = $derived(count * 2);
|
|
28
|
+
* </script>
|
|
29
|
+
*
|
|
30
|
+
* <h1>Hello {user.name}</h1>
|
|
31
|
+
* <button onclick={() => count++}>Clicked {count}</button>
|
|
32
|
+
*
|
|
33
|
+
* <style>
|
|
34
|
+
* h1 { color: red; }
|
|
35
|
+
* </style>
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function parse(source, filepath) {
|
|
39
|
+
const warnings = [];
|
|
40
|
+
// --- Frontmatter ---
|
|
41
|
+
const fmMatch = FRONTMATTER_RE.exec(source);
|
|
42
|
+
let frontmatter = null;
|
|
43
|
+
let remaining = source;
|
|
44
|
+
if (fmMatch && fmMatch.index === 0) {
|
|
45
|
+
frontmatter = {
|
|
46
|
+
type: 'server',
|
|
47
|
+
content: fmMatch[1] ?? '',
|
|
48
|
+
start: 0,
|
|
49
|
+
end: fmMatch[0].length,
|
|
50
|
+
};
|
|
51
|
+
remaining = source.slice(fmMatch[0].length);
|
|
52
|
+
}
|
|
53
|
+
// --- Script block ---
|
|
54
|
+
const scriptMatch = SCRIPT_BLOCK_RE.exec(remaining);
|
|
55
|
+
let script = null;
|
|
56
|
+
if (scriptMatch) {
|
|
57
|
+
const absStart = (frontmatter?.end ?? 0) + (scriptMatch.index ?? 0);
|
|
58
|
+
script = {
|
|
59
|
+
type: 'script',
|
|
60
|
+
content: scriptMatch[1] ?? '',
|
|
61
|
+
start: absStart,
|
|
62
|
+
end: absStart + scriptMatch[0].length,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// --- Style block ---
|
|
66
|
+
const styleMatch = STYLE_BLOCK_RE.exec(remaining);
|
|
67
|
+
let style = null;
|
|
68
|
+
if (styleMatch) {
|
|
69
|
+
const absStart = (frontmatter?.end ?? 0) + (styleMatch.index ?? 0);
|
|
70
|
+
style = {
|
|
71
|
+
type: 'style',
|
|
72
|
+
content: styleMatch[1] ?? '',
|
|
73
|
+
start: absStart,
|
|
74
|
+
end: absStart + styleMatch[0].length,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// --- Template: everything except frontmatter, script, style ---
|
|
78
|
+
let templateContent = remaining;
|
|
79
|
+
if (scriptMatch)
|
|
80
|
+
templateContent = templateContent.replace(scriptMatch[0], '');
|
|
81
|
+
if (styleMatch)
|
|
82
|
+
templateContent = templateContent.replace(styleMatch[0], '');
|
|
83
|
+
templateContent = templateContent.trim();
|
|
84
|
+
const template = {
|
|
85
|
+
type: 'template',
|
|
86
|
+
content: templateContent,
|
|
87
|
+
start: frontmatter?.end ?? 0,
|
|
88
|
+
end: source.length,
|
|
89
|
+
};
|
|
90
|
+
// --- Island directives ---
|
|
91
|
+
const islandDirectives = extractIslandDirectives(templateContent);
|
|
92
|
+
// --- Server Actions ---
|
|
93
|
+
const scriptContent = script?.content ?? '';
|
|
94
|
+
const frontmatterContent = frontmatter?.content ?? '';
|
|
95
|
+
const serverActions = extractServerActionsFromSource(scriptContent + '\n' + frontmatterContent);
|
|
96
|
+
if (serverActions.length > 0 && !source.includes('use server')) {
|
|
97
|
+
warnings.push(`Found server action patterns without "use server" directive in ${filepath}`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
source,
|
|
101
|
+
filepath,
|
|
102
|
+
frontmatter,
|
|
103
|
+
script,
|
|
104
|
+
template,
|
|
105
|
+
style,
|
|
106
|
+
islandDirectives,
|
|
107
|
+
serverActions,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function extractIslandDirectives(template) {
|
|
111
|
+
const directives = [];
|
|
112
|
+
for (const directive of ISLAND_DIRECTIVES) {
|
|
113
|
+
const re = new RegExp(`<(\\w+)[^>]*\\s${directive}(?:=["']([^"']*)["'])?[^>]*>`, 'g');
|
|
114
|
+
let match;
|
|
115
|
+
while ((match = re.exec(template)) !== null) {
|
|
116
|
+
const entry = {
|
|
117
|
+
directive,
|
|
118
|
+
componentName: match[1] ?? 'Unknown',
|
|
119
|
+
};
|
|
120
|
+
if (directive === 'client:media' && match[2] !== undefined) {
|
|
121
|
+
entry.mediaQuery = match[2];
|
|
122
|
+
}
|
|
123
|
+
directives.push(entry);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return directives;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nexus Preload Scanner — Eliminates island waterfall loading.
|
|
3
|
+
*
|
|
4
|
+
* The waterfall problem:
|
|
5
|
+
* <Page> → loads Island A JS
|
|
6
|
+
* <IslandA> → renders, then discovers Island B
|
|
7
|
+
* <IslandB> → ONLY NOW starts loading Island B JS ← waterfall!
|
|
8
|
+
*
|
|
9
|
+
* The fix:
|
|
10
|
+
* At SSR time, the scanner walks the entire component tree and collects
|
|
11
|
+
* ALL island component paths (including deeply nested ones).
|
|
12
|
+
* It then emits <link rel="modulepreload"> for each, so the browser
|
|
13
|
+
* fetches them in parallel while parsing the initial HTML.
|
|
14
|
+
*
|
|
15
|
+
* Result: Island A and Island B both start loading immediately,
|
|
16
|
+
* even if B is nested inside A.
|
|
17
|
+
*
|
|
18
|
+
* Algorithm:
|
|
19
|
+
* 1. Parse the template for component references (<ComponentName ...>)
|
|
20
|
+
* 2. For each component that resolves to a .nx file, compile it
|
|
21
|
+
* 3. If it has islands, record their client bundle paths
|
|
22
|
+
* 4. Recurse into imported components
|
|
23
|
+
* 5. Deduplicate and emit modulepreload links
|
|
24
|
+
*/
|
|
25
|
+
export interface PreloadEntry {
|
|
26
|
+
/** Absolute path to the island's client bundle */
|
|
27
|
+
modulePath: string;
|
|
28
|
+
/** Relative URL path (for <link rel="modulepreload" href="..."> */
|
|
29
|
+
href: string;
|
|
30
|
+
/** Hydration strategy (determines fetch priority) */
|
|
31
|
+
strategy: string;
|
|
32
|
+
/** Component name for debugging */
|
|
33
|
+
component: string;
|
|
34
|
+
}
|
|
35
|
+
export interface PreloadScanResult {
|
|
36
|
+
/** All preload entries, deduplicated and sorted by priority */
|
|
37
|
+
entries: PreloadEntry[];
|
|
38
|
+
/** HTML string of <link> tags ready to inject into <head> */
|
|
39
|
+
linkTags: string;
|
|
40
|
+
/** Total number of islands discovered */
|
|
41
|
+
islandCount: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Scans a route file and all its imported components recursively.
|
|
45
|
+
* Returns modulepreload entries for every island in the tree.
|
|
46
|
+
*/
|
|
47
|
+
export declare function scanPreloads(filepath: string, opts: {
|
|
48
|
+
root: string;
|
|
49
|
+
publicBase?: string;
|
|
50
|
+
maxDepth?: number;
|
|
51
|
+
}): Promise<PreloadScanResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Quick synchronous scan — for use inside the compiler during codegen.
|
|
54
|
+
* Returns preload hrefs from already-parsed island directives.
|
|
55
|
+
*/
|
|
56
|
+
export declare function buildPreloadTagsFromManifest(islands: Array<{
|
|
57
|
+
componentPath: string;
|
|
58
|
+
directive: string;
|
|
59
|
+
}>, root: string, publicBase?: string): string;
|
|
60
|
+
//# sourceMappingURL=preload-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preload-scanner.d.ts","sourceRoot":"","sources":["../src/preload-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAAC,iBAAiB,CAAC,CAgB5B;AA2GD;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,KAAK,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,EAC5D,IAAI,EAAE,MAAM,EACZ,UAAU,SAAoB,GAC7B,MAAM,CAcR"}
|