@vesk/compiler 0.2.72 → 0.2.76

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAUjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAkGxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAgJlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAI5E;AAyCD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,EAAE,CAuB9F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAoFD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,SAAS,CAQtE;AA+nED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAmJD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAuED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAOpQ;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAyC5J;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/E;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAUjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAkGxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAiDD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAgJlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAI5E;AAyCD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,EAAE,CAuB9F;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAY5F;AAoFD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtC;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,SAAS,CAQtE;AAupED,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AAuKD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAuED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAOpQ;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAAC,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CAyC5J;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAG/E;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -857,8 +857,29 @@ function emitStatic(ctx, node, tracked, effectsVar, skipK = 0, regionBudget) {
857
857
  // (which would miss because SSR emits no marker for static children of dynamic parents).
858
858
  const isPureStaticChild = ctx.hydrate && child instanceof StaticNode && isStaticIR(child.children);
859
859
  if (isPureStaticChild) {
860
- const ssrEl = `${el}.__vsk_ssrEls[${residueBefore}]`;
861
- childVar = ssrEl;
860
+ // `__vsk_ssrEls` only exists on CLAIMED elements — the runtime captures it
861
+ // in captureSsrElementChildren. A FRESH parent (walker exhausted, or a
862
+ // tag-mismatch recovery) holds no SSR residue at all, so the unguarded
863
+ // retrieval crashed every post-hydration re-render that mounted new
864
+ // static content (opening a dropdown whose panel starts with a plain
865
+ // header: waterline "Cannot read properties of undefined (reading '0')").
866
+ // Fall back to building the subtree fresh — the non-hydrate emission —
867
+ // exactly when the residue is absent. The claimed path is unchanged and
868
+ // still retrieves, so SSR text is never duplicated.
869
+ const savedHydrate = ctx.hydrate;
870
+ ctx.hydrate = false;
871
+ const buildStart = ctx.lines.length;
872
+ const freshChild = emitStatic(ctx, child, tracked, effectsVar);
873
+ const buildLines = ctx.lines.splice(buildStart, ctx.lines.length - buildStart);
874
+ ctx.hydrate = savedHydrate;
875
+ const childSlot = ctx.n();
876
+ ctx.push(`const ${childSlot} = ${el}.__vsk_ssrEls ? ${el}.__vsk_ssrEls[${residueBefore}] : (() => {`);
877
+ for (const line of buildLines)
878
+ ctx.push(`\t${line}`);
879
+ ctx.push(`\treturn ${freshChild ?? "document.createElement('div')"};`);
880
+ ctx.push(`})();`);
881
+ childVar = childSlot;
882
+ const ssrEl = childSlot;
862
883
  // Process dynamic attributes on the retrieved SSR element
863
884
  const dynAttrs = [];
864
885
  const staticChildren = [];
@@ -1185,7 +1206,9 @@ function emitDynamicBinding(ctx, node, tracked, effectsVar, ssrTextExpr = null)
1185
1206
  const expr = transformTracked(node.expression, tracked);
1186
1207
  const v = ctx.n();
1187
1208
  if (!isReactiveExpression(node.expression, tracked)) {
1188
- ctx.push(`const ${v} = document.createTextNode(String(${expr}));`);
1209
+ // Parens around `expr`: `a || b ?? ''` is a SyntaxError, and the IR keeps
1210
+ // user precedence verbatim.
1211
+ ctx.push(`const ${v} = document.createTextNode(String((${expr}) ?? ''));`);
1189
1212
  return v;
1190
1213
  }
1191
1214
  // Hydrate-mode sole-dynamic-text snapshot (Hydrate-Todo A5): initialize from
@@ -1195,7 +1218,9 @@ function emitDynamicBinding(ctx, node, tracked, effectsVar, ssrTextExpr = null)
1195
1218
  // nothing and the `?? ''` keeps the old empty initial.
1196
1219
  const init = ssrTextExpr ? `String(${ssrTextExpr} ?? '')` : `''`;
1197
1220
  ctx.push(`const ${v} = document.createTextNode(${init});`);
1198
- const eff = `effect(() => { ${v}.data = String(${expr}); })`;
1221
+ // `null`/`undefined` render nothing (matching the SSR `raw()` helper), so a
1222
+ // dynamically absent value never paints the literal string "undefined".
1223
+ const eff = `effect(() => { const __v = ${expr}; ${v}.data = __v == null ? '' : String(__v); })`;
1199
1224
  if (effectsVar) {
1200
1225
  ctx.push(`${effectsVar}.push(${eff});`);
1201
1226
  }
@@ -2866,8 +2891,16 @@ function claimsWalkerNode(ctx, node) {
2866
2891
  return ctx.claimStatic || !isStaticIR(node.children);
2867
2892
  if (node instanceof ComponentCall)
2868
2893
  return true;
2869
- if (node instanceof OpaqueDynamicRegion)
2870
- return true;
2894
+ // A hydration-mode `if` emits comment fences even when neither branch
2895
+ // contains an element. Those fences are created client-side and do not move
2896
+ // the SSR walker, so the region must not clear an inherited first-claim
2897
+ // budget unless one of its branches actually claims. Treating every region
2898
+ // as claiming made a top-level statement-only `if` (a debug assignment, a
2899
+ // store write) before the first island element consume `takeSkipK()` and
2900
+ // claim the preceding server node.
2901
+ if (node instanceof OpaqueDynamicRegion) {
2902
+ return branchClaimsWalker(ctx, node.consequentNodes) || branchClaimsWalker(ctx, node.alternateNodes);
2903
+ }
2871
2904
  if (node instanceof MapRegion)
2872
2905
  return true;
2873
2906
  if (node instanceof ForLoop)
@@ -2880,6 +2913,16 @@ function claimsWalkerNode(ctx, node) {
2880
2913
  return true;
2881
2914
  return false;
2882
2915
  }
2916
+ // Opaque-region branches are emitted with `claimStatic = true`, so a static
2917
+ // element in a branch does consume a walker slot. Evaluate the branch under
2918
+ // that same flag without leaking it into the caller.
2919
+ function branchClaimsWalker(ctx, nodes) {
2920
+ const previous = ctx.claimStatic;
2921
+ ctx.claimStatic = true;
2922
+ const claims = nodes.some((node) => claimsWalkerNode(ctx, node));
2923
+ ctx.claimStatic = previous;
2924
+ return claims;
2925
+ }
2883
2926
  function isStaticComponent(comp) {
2884
2927
  if (comp.style)
2885
2928
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAuBP,MAAM,uBAAuB,CAAC;AA2T/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AAytDD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAqV9E"}
1
+ {"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAuBP,MAAM,uBAAuB,CAAC;AAkW/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AAsvDD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAsV9E"}
@@ -1,7 +1,7 @@
1
1
  import { IRRoot, ComponentIR, StaticNode, TextNode, DynamicBinding, OpaqueDynamicRegion, MapRegion, WhileLoop, SwitchBlock, TryCatch, RuntimeStatement, ForLoop, TrackDecl, ComponentRef, ComponentCall, ServerBlock, ClientBlock, HeadBlock, BreakSignal, Expression, SlotNode, PropSlot, PropSlotRender, } from '@vesk/compiler/src/ir';
2
2
  import { VeskError, codeFrame } from '@vesk/compiler/src/errors';
3
3
  import { createBaseParser } from '@vesk/compiler/src/parser';
4
- import { skipWhitespace, findBalancedEnd, splitTopLevel, startsWithIdentifier, stripDeclKeyword, isWhitespaceChar, collapseNewlineWhitespace } from '@vesk/compiler/src/scan';
4
+ import { skipWhitespace, findBalancedEnd, splitTopLevel, startsWithIdentifier, stripDeclKeyword, isWhitespaceChar, collapseNewlineWhitespace, skipString, skipComment } from '@vesk/compiler/src/scan';
5
5
  import { stripCodeTypes } from '@vesk/compiler/src/strip-ts';
6
6
  import { stripTypeImport } from '@vesk/compiler/src/vsk-imports';
7
7
  import { importBindingPairs } from '@vesk/compiler/src/module-imports';
@@ -15,6 +15,47 @@ let __vskAnnotations = [];
15
15
  * slot handed to it by a caller that wrote `name={<div/>}`.
16
16
  */
17
17
  let __slotProps = null;
18
+ /**
19
+ * Named type declarations (`interface SectionTitleProps { … }`,
20
+ * `type Foo = { … }`) in the file being compiled, keyed by name. A component
21
+ * that annotates its props with a named type must have that type resolved
22
+ * before slot-prop detection: `slotPropNamesFromType` only understands object
23
+ * literals, so `props: SectionTitleProps` with `action?: Component` used to
24
+ * degrade `{props.action}` into a stringified text binding.
25
+ */
26
+ let __typeTexts = null;
27
+ function resolveNamedTypeText(text) {
28
+ if (!text || !__typeTexts || __typeTexts.size === 0)
29
+ return text;
30
+ let t = text.trim();
31
+ for (let i = 0; i < 8; i++) {
32
+ if (!/^[A-Za-z_$][\w$]*$/.test(t))
33
+ return t;
34
+ const next = __typeTexts.get(t);
35
+ if (!next || next === t)
36
+ return t;
37
+ t = next.trim();
38
+ }
39
+ return t;
40
+ }
41
+ function collectTypeTexts(ast, source) {
42
+ const out = new Map();
43
+ for (const node of (ast?.body || [])) {
44
+ const decl = (node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration') && node.declaration
45
+ ? node.declaration
46
+ : node;
47
+ if (decl?.type !== 'TSInterfaceDeclaration' && decl?.type !== 'TSTypeAliasDeclaration')
48
+ continue;
49
+ const name = decl.id?.name;
50
+ if (!name)
51
+ continue;
52
+ const typeNode = decl.type === 'TSInterfaceDeclaration' ? decl.body : decl.typeAnnotation;
53
+ if (!typeNode || typeof typeNode.start !== 'number' || typeof typeNode.end !== 'number')
54
+ continue;
55
+ out.set(name, source.slice(typeNode.start, typeNode.end).trim());
56
+ }
57
+ return out;
58
+ }
18
59
  /**
19
60
  * The identifier a component binds its props to (`props` by convention, but
20
61
  * any first-parameter name is legal). Slot detection used to hardcode the
@@ -990,6 +1031,43 @@ function slotReadPropName(expr) {
990
1031
  }
991
1032
  return null;
992
1033
  }
1034
+ /**
1035
+ * Splits a type body into members on top-level `;` or newlines. Unlike
1036
+ * `splitTopLevel`, member separators are recognised even when flanked by
1037
+ * identifier characters (`string; action` — the common interface shape).
1038
+ */
1039
+ function splitTypeMembers(text) {
1040
+ const parts = [];
1041
+ let depth = 0;
1042
+ let last = 0;
1043
+ let i = 0;
1044
+ while (i < text.length) {
1045
+ const c = text[i];
1046
+ if (c === '"' || c === "'" || c === '`') {
1047
+ i = skipString(text, i);
1048
+ continue;
1049
+ }
1050
+ if (c === '/' && (text[i + 1] === '/' || text[i + 1] === '*')) {
1051
+ i = skipComment(text, i);
1052
+ continue;
1053
+ }
1054
+ if (c === '(' || c === '[' || c === '{' || c === '<')
1055
+ depth++;
1056
+ else if (c === ')' || c === ']' || c === '}' || c === '>') {
1057
+ if (depth > 0)
1058
+ depth--;
1059
+ }
1060
+ else if (depth === 0 && (c === ';' || c === '\n')) {
1061
+ parts.push(text.slice(last, i));
1062
+ last = i + 1;
1063
+ i++;
1064
+ continue;
1065
+ }
1066
+ i++;
1067
+ }
1068
+ parts.push(text.slice(last));
1069
+ return parts;
1070
+ }
993
1071
  /**
994
1072
  * Parses an inline component props type (`{ trigger: Component; ... }`) and
995
1073
  * returns the set of prop names declared as renderable content — any member
@@ -1005,13 +1083,14 @@ function slotPropNamesFromType(propsType) {
1005
1083
  const inner = findBalancedEnd(trimmed, 0) === trimmed.length - 1
1006
1084
  ? trimmed.slice(1, -1)
1007
1085
  : trimmed;
1008
- for (const part of splitTopLevel(inner, ';')) {
1086
+ const members = splitTypeMembers(inner);
1087
+ for (const part of members) {
1009
1088
  const colon = findTopLevelColon(part);
1010
1089
  if (colon === -1)
1011
1090
  continue;
1012
- const namePart = part.slice(0, colon).trim().replace(/^\$/, '').replace(/\?$/, '').trim();
1091
+ const namePart = part.slice(0, colon).trim().replace(/^readonly\s+/, '').replace(/^\$/, '').replace(/\?$/, '').trim();
1013
1092
  const typePart = part.slice(colon + 1).trim();
1014
- if (namePart && typePart.includes('Component'))
1093
+ if (namePart && /^[A-Za-z_$][\w$]*$/.test(namePart) && typePart.includes('Component'))
1015
1094
  out.add(namePart);
1016
1095
  }
1017
1096
  }
@@ -2249,6 +2328,7 @@ function collectIdentifiers(node, into) {
2249
2328
  export function generateIR(ast, source, filename) {
2250
2329
  __vskAnnotations = ast.__vskAnnotations ?? [];
2251
2330
  __slotProps = null;
2331
+ __typeTexts = collectTypeTexts(ast, source);
2252
2332
  const file = filename || '';
2253
2333
  const components = [];
2254
2334
  const imports = [];
@@ -2451,7 +2531,7 @@ export function generateIR(ast, source, filename) {
2451
2531
  // so content reads of `props.<name>` compile to slot renders instead of
2452
2532
  // value bindings for THIS component only.
2453
2533
  const prevSlotProps = __slotProps;
2454
- __slotProps = slotPropNamesFromType(propsType);
2534
+ __slotProps = slotPropNamesFromType(resolveNamedTypeText(propsType));
2455
2535
  __propsParam = propsAlias || null;
2456
2536
  if (isStatementMode(bodyStmts)) {
2457
2537
  const raw = processStatementModeBody(source, bodyStmts, file);
@@ -1 +1 @@
1
- {"version":3,"file":"vsk-imports.d.ts","sourceRoot":"","sources":["../src/vsk-imports.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AA0BD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/F;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAW/D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,aAAa,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GACxD,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB5C;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAKnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhE"}
1
+ {"version":3,"file":"vsk-imports.d.ts","sourceRoot":"","sources":["../src/vsk-imports.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AA0BD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/F;AAkBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAW/D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,aAAa,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GACxD,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB5C;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAKnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhE"}
@@ -3,7 +3,7 @@ import { existsSync } from 'node:fs';
3
3
  import { print } from 'esrap';
4
4
  import ts from 'esrap/languages/ts';
5
5
  import { parse } from '@vesk/compiler/src/parser';
6
- import { importBindingPairs, resolveImportPath } from '@vesk/compiler/src/module-imports';
6
+ import { importBindingPairs, resolveImportPath, resolveSsrModule } from '@vesk/compiler/src/module-imports';
7
7
  import { importModuleTarget, tokenizeCode } from '@vesk/compiler/src/tokens';
8
8
  /**
9
9
  * Resolve `import ... from './path.vsk'` statements so helper components can
@@ -115,8 +115,16 @@ function resolveVskTarget(target, sourcePath) {
115
115
  const full = resolve(dirname(sourcePath), target);
116
116
  return existsSync(full) ? full : null;
117
117
  }
118
+ // Bare specifiers (`vesk-paystack/components/PayButton.vsk`) are a package
119
+ // subpath, not a tsconfig alias. `resolveImportPath` only knows aliases and
120
+ // returns the specifier untouched, so a component library's `.vsk` import
121
+ // never resolved even though Node's `exports` map — and Vesk's own SSR
122
+ // resolver — handle it fine. Use the resolver that understands packages.
118
123
  const aliased = resolveImportPath(target, dirname(sourcePath));
119
- return aliased !== target && existsSync(aliased) ? aliased : null;
124
+ if (aliased !== target && existsSync(aliased))
125
+ return aliased;
126
+ const published = resolveSsrModule(target, dirname(sourcePath));
127
+ return published !== null && published.endsWith('.vsk') && existsSync(published) ? published : null;
120
128
  }
121
129
  /**
122
130
  * Local names bound by *named* value imports from a `.vsk` module.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/compiler",
3
- "version": "0.2.72",
3
+ "version": "0.2.76",
4
4
  "type": "module",
5
5
  "description": "Vesk compiler — lexer, parser, semantic analysis, IR, codegen",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@sveltejs/acorn-typescript": "^1.0.0",
23
- "@vesk/types": "^0.2.72",
23
+ "@vesk/types": "^0.2.76",
24
24
  "acorn": "^8.15.0",
25
25
  "esrap": "^2.3.0",
26
26
  "is-reference": "^3.0.0",