@vesk/compiler 0.2.42 → 0.2.43

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.
@@ -400,6 +400,38 @@ function getJSXTagName(nameNode) {
400
400
  }
401
401
  return 'unknown';
402
402
  }
403
+ /** Root identifier of a dotted JSX tag: `NS.Icon` -> `NS`. */
404
+ function jsxTagRootName(nameNode) {
405
+ let node = nameNode;
406
+ while (node && node.type === 'JSXMemberExpression')
407
+ node = node.object;
408
+ return node && node.type === 'JSXIdentifier' ? node.name : '';
409
+ }
410
+ // Set for the duration of one `generateIR` call so `processJSXElement` — which
411
+ // is reached from eleven call sites and would otherwise need a context
412
+ // parameter threaded through all of them — can reject `<ns.Tag />` for a
413
+ // `import * as ns from './x.vsk'`.
414
+ let currentVskNamespaceLocals = null;
415
+ let currentSourceFile;
416
+ /**
417
+ * Local names bound by `import * as ns from './x.vsk'`. Only `.vsk` targets are
418
+ * collected — a namespace import from a real module (`./x.ts`, a package) is a
419
+ * genuine object and `<ns.Tag />` works there.
420
+ */
421
+ function collectVskNamespaceLocals(ast) {
422
+ const out = new Set();
423
+ for (const node of (ast.body || [])) {
424
+ if (node.type !== 'ImportDeclaration')
425
+ continue;
426
+ if (typeof node.source?.value !== 'string' || !node.source.value.endsWith('.vsk'))
427
+ continue;
428
+ for (const spec of node.specifiers || []) {
429
+ if (spec.type === 'ImportNamespaceSpecifier' && spec.local?.name)
430
+ out.add(spec.local.name);
431
+ }
432
+ }
433
+ return out;
434
+ }
403
435
  function isHTMLTag(name) {
404
436
  return name.length > 0 && name[0] === name[0].toLowerCase();
405
437
  }
@@ -887,6 +919,11 @@ function processJSXElement(source, element) {
887
919
  // actual in-scope value instead of `document.createElement("it.icon")` or a
888
920
  // registry lookup by dotted string.
889
921
  if (nameNode && nameNode.type === 'JSXMemberExpression') {
922
+ const root = jsxTagRootName(nameNode);
923
+ if (currentVskNamespaceLocals && currentVskNamespaceLocals.has(root)) {
924
+ const { line, column } = offsetToLineCol(source, nameNode.start ?? 0);
925
+ throw VeskError.vskNamespaceTag({ file: currentSourceFile, line, column, code: codeFrame(source, line, column) });
926
+ }
890
927
  const { props, spreadProps, slots } = extractProps(source, element);
891
928
  const children = selfClosing ? [] : processJSXChildren(source, element.children || []);
892
929
  return [new ComponentCall(tagName, props, [...children, ...slots.map((s) => new PropSlot(s.name, s.nodes))], spreadProps, element.start, getSource(source, nameNode))];
@@ -1411,222 +1448,289 @@ export function generateIR(ast, source, filename) {
1411
1448
  let staticProps = null;
1412
1449
  let loadFn = null;
1413
1450
  const topLevelCode = [];
1414
- for (const node of ast.body) {
1415
- if (node.type === 'ImportDeclaration') {
1416
- const raw = getSource(source, node);
1417
- let cleaned = stripTypeImport(raw);
1418
- if (cleaned === null)
1419
- continue;
1420
- cleaned = normalizeRuntimeSpecifier(cleaned);
1421
- imports.push(cleaned);
1422
- for (const spec of node.specifiers) {
1423
- if (spec.importKind === 'type')
1451
+ const exportAliases = [];
1452
+ const reexportSources = [];
1453
+ // `export { A }` / `export { A as B }` are stripped by the parser (acorn
1454
+ // rejects a module export that names no top-level binding, and a `.vsk`
1455
+ // component is a registry entry, not a binding). The pairs ride along on the
1456
+ // AST and become registry aliases below.
1457
+ for (const pair of (ast
1458
+ .__vskSpecifierExports) || []) {
1459
+ exportAliases.push({ local: pair.local, exported: pair.exported });
1460
+ }
1461
+ // `import * as ns from './x.vsk'` has no runtime binding: a `.vsk` component
1462
+ // is a registry entry, not a module namespace object. Pre-scan the import
1463
+ // declarations so a `<ns.Tag />` can be reported clearly instead of failing
1464
+ // later as an opaque "ns is not defined".
1465
+ const vskNamespaceLocals = collectVskNamespaceLocals(ast);
1466
+ const prevNamespaceLocals = currentVskNamespaceLocals;
1467
+ const prevSourceFile = currentSourceFile;
1468
+ currentVskNamespaceLocals = vskNamespaceLocals;
1469
+ currentSourceFile = file;
1470
+ try {
1471
+ for (const node of ast.body) {
1472
+ if (node.type === 'ImportDeclaration') {
1473
+ const raw = getSource(source, node);
1474
+ let cleaned = stripTypeImport(raw);
1475
+ if (cleaned === null)
1424
1476
  continue;
1425
- if (spec.type === 'ImportSpecifier') {
1426
- importedNames.add(spec.local.name);
1477
+ cleaned = normalizeRuntimeSpecifier(cleaned);
1478
+ imports.push(cleaned);
1479
+ for (const spec of node.specifiers) {
1480
+ if (spec.importKind === 'type')
1481
+ continue;
1482
+ if (spec.type === 'ImportSpecifier') {
1483
+ importedNames.add(spec.local.name);
1484
+ }
1427
1485
  }
1428
- }
1429
- continue;
1430
- }
1431
- if (node.type === 'ExportNamedDeclaration' && node.declaration && !staticProps) {
1432
- const decl = node.declaration;
1433
- const fnName = decl.type === 'FunctionDeclaration'
1434
- ? decl.id?.name
1435
- : decl.type === 'VariableDeclaration'
1436
- ? decl.declarations[0]?.id?.name
1437
- : null;
1438
- if (fnName === 'getStaticProps') {
1439
- staticProps = stripCodeTypes(getSource(source, decl));
1440
1486
  continue;
1441
1487
  }
1442
- }
1443
- if (node.type === 'ExportNamedDeclaration' && node.declaration && !loadFn) {
1444
- const decl = node.declaration;
1445
- const fnName = decl.type === 'FunctionDeclaration'
1446
- ? decl.id?.name
1447
- : decl.type === 'VariableDeclaration'
1448
- ? decl.declarations[0]?.id?.name
1449
- : null;
1450
- if (fnName === 'load') {
1451
- loadFn = stripCodeTypes(getSource(source, decl));
1452
- continue;
1488
+ if (node.type === 'ExportNamedDeclaration' && node.declaration && !staticProps) {
1489
+ const decl = node.declaration;
1490
+ const fnName = decl.type === 'FunctionDeclaration'
1491
+ ? decl.id?.name
1492
+ : decl.type === 'VariableDeclaration'
1493
+ ? decl.declarations[0]?.id?.name
1494
+ : null;
1495
+ if (fnName === 'getStaticProps') {
1496
+ staticProps = stripCodeTypes(getSource(source, decl));
1497
+ continue;
1498
+ }
1453
1499
  }
1454
- }
1455
- // `export const standalone = true` / `export let standalone = true` is a
1456
- // compile-time routing directive (isStandaloneLayoutFile), not runtime
1457
- // code — drop it so it never reaches emitted JS (client chunks are
1458
- // IIFE-wrapped where a bare `export` is a syntax error).
1459
- if (node.type === 'ExportNamedDeclaration' && node.declaration) {
1460
- const decl = node.declaration;
1461
- if (decl.type === 'VariableDeclaration') {
1462
- const declName = decl.declarations[0]?.id?.name;
1463
- if (declName === 'standalone') {
1500
+ if (node.type === 'ExportNamedDeclaration' && node.declaration && !loadFn) {
1501
+ const decl = node.declaration;
1502
+ const fnName = decl.type === 'FunctionDeclaration'
1503
+ ? decl.id?.name
1504
+ : decl.type === 'VariableDeclaration'
1505
+ ? decl.declarations[0]?.id?.name
1506
+ : null;
1507
+ if (fnName === 'load') {
1508
+ loadFn = stripCodeTypes(getSource(source, decl));
1464
1509
  continue;
1465
1510
  }
1466
1511
  }
1467
- }
1468
- let inner = node;
1469
- let exported = false;
1470
- let defaultExport = false;
1471
- if (node.type === 'ExportNamedDeclaration' && node.declaration) {
1472
- inner = node.declaration;
1473
- exported = true;
1474
- }
1475
- else if (node.type === 'ExportDefaultDeclaration' && node.declaration) {
1476
- inner = node.declaration;
1477
- exported = true;
1478
- defaultExport = true;
1479
- }
1480
- if (inner.type === 'ComponentDeclaration') {
1481
- // handled below
1482
- }
1483
- else if (inner.type === 'ClassDeclaration') {
1484
- const { line, column } = offsetToLineCol(source, inner.start ?? 0);
1485
- throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
1486
- }
1487
- else if (inner.type === 'TSEnumDeclaration') {
1488
- const code = processEnum(inner, source, exported);
1489
- topLevelCode.push(code);
1490
- continue;
1491
- }
1492
- else {
1493
- topLevelCode.push(getSource(source, node));
1494
- continue;
1495
- }
1496
- const name = inner.id.name;
1497
- const paramNames = getParamNames(inner.params, source);
1498
- // A plain-identifier first parameter receives the whole props object under
1499
- // its own name (React-style); a destructuring pattern receives the fields.
1500
- const firstParam = inner.params?.[0];
1501
- const propsAlias = firstParam && firstParam.type === 'Identifier' ? firstParam.name : null;
1502
- const propsType = getPropsType(inner.params, source);
1503
- const bodyStmts = inner.body.body;
1504
- const isClientComp = !!inner.client;
1505
- // Slot props are declared at the component boundary (`trigger: Component`),
1506
- // so content reads of `props.<name>` compile to slot renders instead of
1507
- // value bindings for THIS component only.
1508
- const prevSlotProps = __slotProps;
1509
- __slotProps = slotPropNamesFromType(propsType);
1510
- __propsParam = propsAlias || null;
1511
- if (isStatementMode(bodyStmts)) {
1512
- const raw = processStatementModeBody(source, bodyStmts, file);
1513
- const { body, css } = extractStyle(raw);
1514
- validateBlocks(name, isClientComp, body, file, source);
1515
- const comp = new ComponentIR(name, paramNames, body, { mode: 'statement', exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
1516
- comp.style = css;
1517
- components.push(comp);
1518
- __slotProps = prevSlotProps;
1519
- }
1520
- else {
1521
- const guardClauses = [];
1522
- let mainReturn = null;
1523
- const preamble = [];
1524
- for (const stmt of bodyStmts) {
1525
- if (stmt.type === 'VeskBlock') {
1526
- const innerBody = processStatementModeBody(source, stmt.body, file);
1527
- if (stmt.tag === 'server') {
1528
- preamble.push(new ServerBlock(innerBody));
1529
- }
1530
- else if (stmt.tag === 'client') {
1531
- preamble.push(new ClientBlock(innerBody));
1512
+ // `export const standalone = true` / `export let standalone = true` is a
1513
+ // compile-time routing directive (isStandaloneLayoutFile), not runtime
1514
+ // code — drop it so it never reaches emitted JS (client chunks are
1515
+ // IIFE-wrapped where a bare `export` is a syntax error).
1516
+ if (node.type === 'ExportNamedDeclaration' && node.declaration) {
1517
+ const decl = node.declaration;
1518
+ if (decl.type === 'VariableDeclaration') {
1519
+ const declName = decl.declarations[0]?.id?.name;
1520
+ if (declName === 'standalone') {
1521
+ continue;
1532
1522
  }
1533
1523
  }
1534
- else if (stmt.type === 'ReturnStatement') {
1535
- mainReturn = stmt;
1536
- }
1537
- else if (isTrackDeclaration(stmt)) {
1538
- const elements = stmt.declarations[0].id.elements;
1539
- const trackName = elements[0]?.name;
1540
- const rawName = elements.length > 1 ? elements[1]?.name : null;
1541
- const init = getSource(source, stmt.declarations[0].init);
1542
- if (trackName)
1543
- preamble.push(new TrackDecl(trackName, init, rawName));
1544
- const refName = getComponentRefName(stmt);
1545
- if (refName)
1546
- preamble.push(new ComponentRef(refName));
1547
- }
1548
- else if (stmt.type === 'IfStatement' && !mainReturn && stmt.consequent.type !== 'ThrowStatement') {
1549
- guardClauses.push(stmt);
1550
- }
1551
- else if (stmt.type === 'ClassDeclaration') {
1552
- const { line, column } = offsetToLineCol(source, stmt.start ?? 0);
1553
- throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
1524
+ }
1525
+ if (node.type === 'ExportNamedDeclaration' && !node.declaration) {
1526
+ // A specifier-only export (`export { A }`, `export { A as B }`) or a
1527
+ // re-export (`export { A } from './x.vsk'`, `export { default as A } from …`).
1528
+ // Never emit the raw statement: components are registry entries, not
1529
+ // top-level bindings, so emitting it yields `Export 'A' is not defined`.
1530
+ if (node.source) {
1531
+ if (typeof node.source.value === 'string')
1532
+ reexportSources.push(node.source.value);
1533
+ // `export { A as B } from './x.vsk'`: the target's components merge into
1534
+ // this file's registry under their own names, so the specifier is the
1535
+ // same canonical -> alias mapping a same-file export would produce.
1536
+ for (const spec of node.specifiers || []) {
1537
+ if (spec.type === 'ExportSpecifier') {
1538
+ const localName = spec.local && spec.local.name;
1539
+ const exportedName = spec.exported && spec.exported.name;
1540
+ if (typeof localName === 'string' && typeof exportedName === 'string') {
1541
+ exportAliases.push({ local: localName, exported: exportedName });
1542
+ }
1543
+ }
1544
+ }
1545
+ continue;
1554
1546
  }
1555
- else {
1556
- const raw = getSource(source, stmt);
1557
- if (raw)
1558
- preamble.push(new RuntimeStatement(raw, stmt, source));
1547
+ for (const spec of node.specifiers || []) {
1548
+ if (spec.type === 'ExportSpecifier') {
1549
+ const localName = spec.local && spec.local.name;
1550
+ const exportedName = spec.exported && spec.exported.name;
1551
+ if (typeof localName === 'string' && typeof exportedName === 'string') {
1552
+ exportAliases.push({ local: localName, exported: exportedName });
1553
+ }
1554
+ }
1559
1555
  }
1556
+ continue;
1560
1557
  }
1561
- const guardBody = buildGuardChain(source, guardClauses, mainReturn);
1562
- const { body, css } = extractStyle([...preamble, ...guardBody]);
1563
- validateBlocks(name, isClientComp, body, file, source);
1564
- const comp = new ComponentIR(name, paramNames, body, { exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
1565
- comp.style = css;
1566
- components.push(comp);
1567
- __slotProps = prevSlotProps;
1568
- }
1569
- }
1570
- const asyncNames = new Set(components.filter((c) => c.isAsync || c.ssrAwait).map((c) => c.name));
1571
- for (const comp of components) {
1572
- if (asyncNames.has(comp.name))
1573
- continue;
1574
- const called = new Map();
1575
- collectComponentCalls(comp.body, called);
1576
- for (const [childName, start] of called) {
1577
- if (!asyncNames.has(childName))
1558
+ if (node.type === 'ExportAllDeclaration') {
1559
+ // `export * from './x.vsk'` / `export * as ns from './x.vsk'`: resolve the
1560
+ // target into this file's component registry instead of emitting a bare
1561
+ // re-export that no bundler can satisfy for `.vsk` modules.
1562
+ if (node.source && typeof node.source.value === 'string')
1563
+ reexportSources.push(node.source.value);
1578
1564
  continue;
1579
- const { line, column } = offsetToLineCol(source, start >= 0 ? start : 0);
1580
- throw VeskError.asyncChildInSyncParent(comp.name, childName, { file, line, column, code: codeFrame(source, line, column) });
1581
- }
1582
- }
1583
- const autoImportable = [
1584
- 'useFetch', 'useRouter', 'useParams', 'usePathname', 'useSearchParams', 'useNavigate',
1585
- 'defineAction',
1586
- 'Form', 'Field', 'required', 'email', 'minLength', 'maxLength', 'pattern', 'custom',
1587
- 'Link', 'NavLink', 'Outlet', 'Redirect',
1588
- 'Image', 'Portal',
1589
- 'Experiment',
1590
- 'LoadingIndicator', 'useLoadingIndicator',
1591
- 'JsonLd', 'ArticleSchema', 'ProductSchema', 'FAQPageSchema', 'BreadcrumbListSchema',
1592
- 'OrganizationSchema', 'LocalBusinessSchema', 'VideoSchema',
1593
- 'effect', 'derived', 'untrack', 'peek', 'tick', 'flushSync', 'on_destroy',
1594
- 'createContext',
1595
- 'redirect', 'permanentRedirect', 'notFound', 'NotFoundError',
1596
- 'createResource', 'getAction', 'validateActionInput', 'issuesToFieldMap', 'isFormAction',
1597
- 'Show', 'For', 'Switch', 'Match',
1598
- ];
1599
- // One walk of the already-parsed tree finds every auto-importable call
1600
- // target and JSX element name. Every IR raw the old per-fragment scan
1601
- // re-tokenized ("addUsedFrom" over ~15 text slices) is a subtree of this
1602
- // very same `ast` — nothing is lost, but the acorn tokenizer is invoked once
1603
- // per file instead of once per fragment.
1604
- const called = collectCallAndJsxTargets(ast);
1605
- const usedFunctions = new Set();
1606
- for (const fn of autoImportable) {
1607
- if (called.has(fn))
1608
- usedFunctions.add(fn);
1609
- }
1610
- if (usedFunctions.size > 0) {
1611
- const existing = new Set();
1612
- for (const imp of imports) {
1613
- if (importModuleTarget(imp) !== '@vesk/runtime')
1565
+ }
1566
+ let inner = node;
1567
+ let exported = false;
1568
+ let defaultExport = false;
1569
+ if (node.type === 'ExportNamedDeclaration' && node.declaration) {
1570
+ inner = node.declaration;
1571
+ exported = true;
1572
+ }
1573
+ else if (node.type === 'ExportDefaultDeclaration' && node.declaration) {
1574
+ inner = node.declaration;
1575
+ exported = true;
1576
+ defaultExport = true;
1577
+ }
1578
+ if (inner.type === 'ComponentDeclaration') {
1579
+ // handled below
1580
+ }
1581
+ else if (inner.type === 'ClassDeclaration') {
1582
+ const { line, column } = offsetToLineCol(source, inner.start ?? 0);
1583
+ throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
1584
+ }
1585
+ else if (inner.type === 'TSEnumDeclaration') {
1586
+ const code = processEnum(inner, source, exported);
1587
+ topLevelCode.push(code);
1614
1588
  continue;
1615
- for (const n of extractImportNames(imp))
1616
- existing.add(n);
1589
+ }
1590
+ else {
1591
+ topLevelCode.push(getSource(source, node));
1592
+ continue;
1593
+ }
1594
+ const name = inner.id.name;
1595
+ const paramNames = getParamNames(inner.params, source);
1596
+ // A plain-identifier first parameter receives the whole props object under
1597
+ // its own name (React-style); a destructuring pattern receives the fields.
1598
+ const firstParam = inner.params?.[0];
1599
+ const propsAlias = firstParam && firstParam.type === 'Identifier' ? firstParam.name : null;
1600
+ const propsType = getPropsType(inner.params, source);
1601
+ const bodyStmts = inner.body.body;
1602
+ const isClientComp = !!inner.client;
1603
+ // Slot props are declared at the component boundary (`trigger: Component`),
1604
+ // so content reads of `props.<name>` compile to slot renders instead of
1605
+ // value bindings for THIS component only.
1606
+ const prevSlotProps = __slotProps;
1607
+ __slotProps = slotPropNamesFromType(propsType);
1608
+ __propsParam = propsAlias || null;
1609
+ if (isStatementMode(bodyStmts)) {
1610
+ const raw = processStatementModeBody(source, bodyStmts, file);
1611
+ const { body, css } = extractStyle(raw);
1612
+ validateBlocks(name, isClientComp, body, file, source);
1613
+ const comp = new ComponentIR(name, paramNames, body, { mode: 'statement', exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
1614
+ comp.style = css;
1615
+ components.push(comp);
1616
+ __slotProps = prevSlotProps;
1617
+ }
1618
+ else {
1619
+ const guardClauses = [];
1620
+ let mainReturn = null;
1621
+ const preamble = [];
1622
+ for (const stmt of bodyStmts) {
1623
+ if (stmt.type === 'VeskBlock') {
1624
+ const innerBody = processStatementModeBody(source, stmt.body, file);
1625
+ if (stmt.tag === 'server') {
1626
+ preamble.push(new ServerBlock(innerBody));
1627
+ }
1628
+ else if (stmt.tag === 'client') {
1629
+ preamble.push(new ClientBlock(innerBody));
1630
+ }
1631
+ }
1632
+ else if (stmt.type === 'ReturnStatement') {
1633
+ mainReturn = stmt;
1634
+ }
1635
+ else if (isTrackDeclaration(stmt)) {
1636
+ const elements = stmt.declarations[0].id.elements;
1637
+ const trackName = elements[0]?.name;
1638
+ const rawName = elements.length > 1 ? elements[1]?.name : null;
1639
+ const init = getSource(source, stmt.declarations[0].init);
1640
+ if (trackName)
1641
+ preamble.push(new TrackDecl(trackName, init, rawName));
1642
+ const refName = getComponentRefName(stmt);
1643
+ if (refName)
1644
+ preamble.push(new ComponentRef(refName));
1645
+ }
1646
+ else if (stmt.type === 'IfStatement' && !mainReturn && stmt.consequent.type !== 'ThrowStatement') {
1647
+ guardClauses.push(stmt);
1648
+ }
1649
+ else if (stmt.type === 'ClassDeclaration') {
1650
+ const { line, column } = offsetToLineCol(source, stmt.start ?? 0);
1651
+ throw VeskError.classDecl({ file, line, column, code: codeFrame(source, line, column) });
1652
+ }
1653
+ else {
1654
+ const raw = getSource(source, stmt);
1655
+ if (raw)
1656
+ preamble.push(new RuntimeStatement(raw, stmt, source));
1657
+ }
1658
+ }
1659
+ const guardBody = buildGuardChain(source, guardClauses, mainReturn);
1660
+ const { body, css } = extractStyle([...preamble, ...guardBody]);
1661
+ validateBlocks(name, isClientComp, body, file, source);
1662
+ const comp = new ComponentIR(name, paramNames, body, { exported, defaultExport, isClient: inner.client, isAsync: inner.async, ssrAwait: componentUsesFetch(body), propsType, propsAlias });
1663
+ comp.style = css;
1664
+ components.push(comp);
1665
+ __slotProps = prevSlotProps;
1666
+ }
1617
1667
  }
1618
- // A name already bound by the file's own imports (any target — including a
1619
- // local module with the same export) wins; never auto-import a duplicate
1620
- // binding. Mirrors client shadowing so SSR and client agree.
1621
- const boundLocally = new Set();
1622
- for (const imp of imports) {
1623
- for (const pair of importBindingPairs(imp))
1624
- boundLocally.add(pair.local);
1668
+ const asyncNames = new Set(components.filter((c) => c.isAsync || c.ssrAwait).map((c) => c.name));
1669
+ for (const comp of components) {
1670
+ if (asyncNames.has(comp.name))
1671
+ continue;
1672
+ const called = new Map();
1673
+ collectComponentCalls(comp.body, called);
1674
+ for (const [childName, start] of called) {
1675
+ if (!asyncNames.has(childName))
1676
+ continue;
1677
+ const { line, column } = offsetToLineCol(source, start >= 0 ? start : 0);
1678
+ throw VeskError.asyncChildInSyncParent(comp.name, childName, { file, line, column, code: codeFrame(source, line, column) });
1679
+ }
1625
1680
  }
1626
- const missing = [...usedFunctions].filter(f => !existing.has(f) && !boundLocally.has(f));
1627
- if (missing.length > 0) {
1628
- imports.push(`import { ${missing.join(', ')} } from '@vesk/runtime';`);
1681
+ const autoImportable = [
1682
+ 'useFetch', 'useRouter', 'useParams', 'usePathname', 'useSearchParams', 'useNavigate',
1683
+ 'defineAction',
1684
+ 'Form', 'Field', 'required', 'email', 'minLength', 'maxLength', 'pattern', 'custom',
1685
+ 'Link', 'NavLink', 'Outlet', 'Redirect',
1686
+ 'Image', 'Portal',
1687
+ 'Experiment',
1688
+ 'LoadingIndicator', 'useLoadingIndicator',
1689
+ 'JsonLd', 'ArticleSchema', 'ProductSchema', 'FAQPageSchema', 'BreadcrumbListSchema',
1690
+ 'OrganizationSchema', 'LocalBusinessSchema', 'VideoSchema',
1691
+ 'effect', 'derived', 'untrack', 'peek', 'tick', 'flushSync', 'on_destroy',
1692
+ 'createContext',
1693
+ 'redirect', 'permanentRedirect', 'notFound', 'NotFoundError',
1694
+ 'createResource', 'getAction', 'validateActionInput', 'issuesToFieldMap', 'isFormAction',
1695
+ 'Show', 'For', 'Switch', 'Match',
1696
+ 'primitive', 'leaf',
1697
+ ];
1698
+ // One walk of the already-parsed tree finds every auto-importable call
1699
+ // target and JSX element name. Every IR raw the old per-fragment scan
1700
+ // re-tokenized ("addUsedFrom" over ~15 text slices) is a subtree of this
1701
+ // very same `ast` — nothing is lost, but the acorn tokenizer is invoked once
1702
+ // per file instead of once per fragment.
1703
+ const called = collectCallAndJsxTargets(ast);
1704
+ const usedFunctions = new Set();
1705
+ for (const fn of autoImportable) {
1706
+ if (called.has(fn))
1707
+ usedFunctions.add(fn);
1708
+ }
1709
+ if (usedFunctions.size > 0) {
1710
+ const existing = new Set();
1711
+ for (const imp of imports) {
1712
+ if (importModuleTarget(imp) !== '@vesk/runtime')
1713
+ continue;
1714
+ for (const n of extractImportNames(imp))
1715
+ existing.add(n);
1716
+ }
1717
+ // A name already bound by the file's own imports (any target — including a
1718
+ // local module with the same export) wins; never auto-import a duplicate
1719
+ // binding. Mirrors client shadowing so SSR and client agree.
1720
+ const boundLocally = new Set();
1721
+ for (const imp of imports) {
1722
+ for (const pair of importBindingPairs(imp))
1723
+ boundLocally.add(pair.local);
1724
+ }
1725
+ const missing = [...usedFunctions].filter(f => !existing.has(f) && !boundLocally.has(f));
1726
+ if (missing.length > 0) {
1727
+ imports.push(`import { ${missing.join(', ')} } from '@vesk/runtime';`);
1728
+ }
1629
1729
  }
1730
+ return new IRRoot(components, imports, importedNames, staticProps, loadFn, topLevelCode, exportAliases, reexportSources);
1731
+ }
1732
+ finally {
1733
+ currentVskNamespaceLocals = prevNamespaceLocals;
1734
+ currentSourceFile = prevSourceFile;
1630
1735
  }
1631
- return new IRRoot(components, imports, importedNames, staticProps, loadFn, topLevelCode);
1632
1736
  }
package/dist/ir.d.ts CHANGED
@@ -13,7 +13,28 @@ export declare class IRRoot {
13
13
  staticProps: string | null;
14
14
  loadFn: string | null;
15
15
  topLevelCode: string[];
16
- constructor(components: ComponentIR[], imports?: string[], importedNames?: Set<string>, staticProps?: string | null, loadFn?: string | null, topLevelCode?: string[]);
16
+ /**
17
+ * Same-file specifier exports (`export { A }`, `export { A as B }`) as
18
+ * `{ local, exported }` pairs. These are NOT emitted as JS: components live
19
+ * in the component registry rather than as top-level bindings, so a raw
20
+ * `export { A }` would reference an undefined identifier. The pairs become
21
+ * registry alias entries so the exported name is importable.
22
+ */
23
+ exportAliases: Array<{
24
+ local: string;
25
+ exported: string;
26
+ }>;
27
+ /**
28
+ * Module specifiers re-exported from this file (`export * from './x.vsk'`,
29
+ * `export { A } from './x.vsk'`, `export * as ns from './x.vsk'`). The
30
+ * statements themselves are dropped — the target file is compiled and
31
+ * merged into this one's component registry instead.
32
+ */
33
+ reexportSources: string[];
34
+ constructor(components: ComponentIR[], imports?: string[], importedNames?: Set<string>, staticProps?: string | null, loadFn?: string | null, topLevelCode?: string[], exportAliases?: Array<{
35
+ local: string;
36
+ exported: string;
37
+ }>, reexportSources?: string[]);
17
38
  }
18
39
  export declare class ComponentIR {
19
40
  name: string;
package/dist/ir.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ir.d.ts","sourceRoot":"","sources":["../src/ir.ts"],"names":[],"mappings":"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"}
package/dist/ir.js CHANGED
@@ -17,13 +17,30 @@ export class IRRoot {
17
17
  staticProps;
18
18
  loadFn;
19
19
  topLevelCode;
20
- constructor(components, imports = [], importedNames = new Set(), staticProps = null, loadFn = null, topLevelCode = []) {
20
+ /**
21
+ * Same-file specifier exports (`export { A }`, `export { A as B }`) as
22
+ * `{ local, exported }` pairs. These are NOT emitted as JS: components live
23
+ * in the component registry rather than as top-level bindings, so a raw
24
+ * `export { A }` would reference an undefined identifier. The pairs become
25
+ * registry alias entries so the exported name is importable.
26
+ */
27
+ exportAliases;
28
+ /**
29
+ * Module specifiers re-exported from this file (`export * from './x.vsk'`,
30
+ * `export { A } from './x.vsk'`, `export * as ns from './x.vsk'`). The
31
+ * statements themselves are dropped — the target file is compiled and
32
+ * merged into this one's component registry instead.
33
+ */
34
+ reexportSources;
35
+ constructor(components, imports = [], importedNames = new Set(), staticProps = null, loadFn = null, topLevelCode = [], exportAliases = [], reexportSources = []) {
21
36
  this.components = components;
22
37
  this.imports = imports;
23
38
  this.importedNames = importedNames;
24
39
  this.staticProps = staticProps;
25
40
  this.loadFn = loadFn;
26
41
  this.topLevelCode = topLevelCode;
42
+ this.exportAliases = exportAliases;
43
+ this.reexportSources = reexportSources;
27
44
  }
28
45
  }
29
46
  export class ComponentIR {