@statorjs/language-server 0.1.16 → 0.1.17

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.
Files changed (2) hide show
  1. package/dist/server.cjs +128 -37
  2. package/package.json +2 -2
package/dist/server.cjs CHANGED
@@ -44220,7 +44220,7 @@ function locAt(source, offset, file) {
44220
44220
  }
44221
44221
 
44222
44222
  // ../stator/src/compiler/client-emit.ts
44223
- var PRIMITIVES = "import { StatorElement, defineElement, use, machine, bind, effect, dispatch } from '@statorjs/stator/client'";
44223
+ var PRIMITIVES = "import { StatorElement, defineElement, use, machine, bind, bindSlot, effect, dispatch } from '@statorjs/stator/client'";
44224
44224
  function emitClientModule(input) {
44225
44225
  const { script, element, directives, members } = input;
44226
44226
  const impl = `__${element.className}Impl`;
@@ -44233,9 +44233,16 @@ function emitClientModule(input) {
44233
44233
  const lines = [];
44234
44234
  let i = 0;
44235
44235
  for (const [marker, group] of byMarker) {
44236
+ if (group[0]?.kind === "slot") {
44237
+ for (const d of group) {
44238
+ const thunk = `() => (${rewriteMembers(d.expr, members)})`;
44239
+ const deps = `[${d.deps.map((dep) => `this.${dep}`).join(", ")}]`;
44240
+ lines.push(` this.track(bindSlot(this, ${JSON.stringify(marker)}, ${deps}, ${thunk}))`);
44241
+ }
44242
+ continue;
44243
+ }
44236
44244
  const node = `n${i++}`;
44237
- lines.push(` const ${node} = this.querySelector('[data-b="${marker}"]')`);
44238
- lines.push(` if (${node}) {`);
44245
+ lines.push(` for (const ${node} of this.querySelectorAll('[data-b="${marker}"]')) {`);
44239
44246
  for (const d of group) lines.push(` ${wireDirective(node, d, members)}`);
44240
44247
  lines.push(" }");
44241
44248
  }
@@ -44492,7 +44499,7 @@ function cleanJsxText(raw) {
44492
44499
  var WRAP_PREFIX_LEN = "const __t = (<>".length;
44493
44500
  var INLINE_SCRIPT_RE = /<script\b([^>]*\bis:inline\b[^>]*)>([\s\S]*?)<\/script>/gi;
44494
44501
  var inlineMarker = (i) => `\0statorInlineScript${i}\0`;
44495
- var INLINE_MARKER_RE = /statorInlineScript(\d+)/g;
44502
+ var INLINE_MARKER_RE = /\0statorInlineScript(\d+)\0/g;
44496
44503
  function eachItemParamsFor(jsx) {
44497
44504
  let node = jsx.parent;
44498
44505
  while (node && import_typescript3.default.isParenthesizedExpression(node)) node = node.parent;
@@ -44534,6 +44541,24 @@ function lowerTemplate(template, opts = {}) {
44534
44541
  let eachParams = null;
44535
44542
  const enableItemBind = !opts.client;
44536
44543
  const isItemRead = (n) => enableItemBind && eachParams !== null && import_typescript3.default.isCallExpression(n) && import_typescript3.default.isIdentifier(n.expression) && n.expression.text === "read" && n.arguments.length >= 2 && n.arguments[0] !== void 0 && import_typescript3.default.isIdentifier(n.arguments[0]) && n.arguments[0].text === eachParams.item;
44544
+ const isClientRead = (n) => opts.client !== void 0 && import_typescript3.default.isCallExpression(n) && import_typescript3.default.isIdentifier(n.expression) && n.expression.text === "read" && n.arguments.length >= 2 && n.arguments[0] !== void 0 && import_typescript3.default.isIdentifier(n.arguments[0]) && opts.client.useFields.has(n.arguments[0].text);
44545
+ const clientReadExpr = (call) => `(${call.arguments[1].getText(sf)})(${call.arguments[0].text})`;
44546
+ const allocSlotMarker = () => {
44547
+ const client = opts.client;
44548
+ if (!client) throw new CompileError("stator: internal \u2014 slot marker outside client mode");
44549
+ return `s${client.directives.filter((d) => d.kind === "slot").length}`;
44550
+ };
44551
+ const assertNoClientRead = (n) => {
44552
+ if (!opts.client) return;
44553
+ if (import_typescript3.default.isJsxElement(n) || import_typescript3.default.isJsxSelfClosingElement(n) || import_typescript3.default.isJsxFragment(n)) return;
44554
+ if (isClientRead(n)) {
44555
+ throw new CompileError(
44556
+ `stator: read(${n.arguments[0].text}, \u2026) on a client machine must be the entire expression \u2014 text position (\`{read(m, s => \u2026)}\`) or attribute position (\`attr={read(m, s => \u2026)}\`). Compose derived values inside the selector.`,
44557
+ loc2(n)
44558
+ );
44559
+ }
44560
+ import_typescript3.default.forEachChild(n, assertNoClientRead);
44561
+ };
44537
44562
  const loc2 = (node) => {
44538
44563
  if (opts.source == null || opts.templateOffset == null) return void 0;
44539
44564
  const orig = opts.templateOffset + doctypeLen + (node.getStart(sf) - WRAP_PREFIX_LEN);
@@ -44642,6 +44667,17 @@ function lowerTemplate(template, opts = {}) {
44642
44667
  if (import_typescript3.default.isJsxText(node)) return escapeText(cleanJsxText(node.getFullText(sf)));
44643
44668
  if (import_typescript3.default.isJsxExpression(node)) {
44644
44669
  if (!node.expression) return "";
44670
+ if (opts.client && isClientRead(node.expression)) {
44671
+ const marker = allocSlotMarker();
44672
+ const expr = clientReadExpr(node.expression);
44673
+ opts.client.directives.push({
44674
+ marker,
44675
+ kind: "slot",
44676
+ expr,
44677
+ deps: inferDeps(expr, opts.client.useFields)
44678
+ });
44679
+ return `<!--${marker}-->`;
44680
+ }
44645
44681
  return `\${${lowerExprText(node.expression)}}`;
44646
44682
  }
44647
44683
  if (import_typescript3.default.isJsxElement(node)) {
@@ -44675,6 +44711,7 @@ function lowerTemplate(template, opts = {}) {
44675
44711
  if (import_typescript3.default.isJsxElement(expr) || import_typescript3.default.isJsxSelfClosingElement(expr) || import_typescript3.default.isJsxFragment(expr)) {
44676
44712
  return `html\`${contentOfChild(expr)}\``;
44677
44713
  }
44714
+ assertNoClientRead(expr);
44678
44715
  if (isItemRead(expr)) {
44679
44716
  return `itemBind(${lowerExprText(expr.arguments[1])})`;
44680
44717
  }
@@ -44720,56 +44757,79 @@ function lowerTemplate(template, opts = {}) {
44720
44757
  );
44721
44758
  }
44722
44759
  }
44723
- const clientMarker = opts.client ? collectClientDirectives(attrs) : void 0;
44760
+ const collected = opts.client ? collectClientDirectives(attrs) : void 0;
44724
44761
  let out = "";
44725
44762
  for (const attr of attrs.properties) {
44726
44763
  if (import_typescript3.default.isJsxSpreadAttribute(attr)) {
44727
- throw new CompileError("stator: spread attributes ({...x}) are not supported", loc2(attr));
44728
- }
44729
- if (import_typescript3.default.isJsxAttribute(attr) && !import_typescript3.default.isJsxNamespacedName(attr.name) && attr.name.getText(sf) === "child") {
44764
+ out += ` \${spreadAttrs(${lowerExprText(attr.expression)})}`;
44730
44765
  continue;
44731
44766
  }
44732
- if (opts.client && import_typescript3.default.isJsxAttribute(attr) && import_typescript3.default.isJsxNamespacedName(attr.name) && (attr.name.namespace.text === "on" || attr.name.namespace.text === "bind")) {
44767
+ if (import_typescript3.default.isJsxAttribute(attr) && !import_typescript3.default.isJsxNamespacedName(attr.name) && attr.name.getText(sf) === "child") {
44733
44768
  continue;
44734
44769
  }
44770
+ if (collected?.consumed.has(attr)) continue;
44735
44771
  const lowered = lowerAttribute(attr);
44736
44772
  if (lowered) out += ` ${lowered}`;
44737
44773
  }
44738
- if (clientMarker) out += ` data-b="${clientMarker}"`;
44774
+ if (collected?.marker) out += ` data-b="${collected.marker}"`;
44739
44775
  return out;
44740
44776
  };
44741
44777
  const collectClientDirectives = (attrs) => {
44778
+ const consumed = /* @__PURE__ */ new Set();
44742
44779
  const client = opts.client;
44743
- if (!client) return void 0;
44780
+ if (!client) return { consumed };
44744
44781
  const pending = [];
44745
44782
  for (const attr of attrs.properties) {
44746
- if (!import_typescript3.default.isJsxAttribute(attr) || !import_typescript3.default.isJsxNamespacedName(attr.name)) continue;
44747
- const ns = attr.name.namespace.text;
44748
- const name = attr.name.name.text;
44749
- if (ns !== "on" && ns !== "bind") continue;
44750
- const expr = attrExpr(attr);
44751
- if (!expr) {
44752
- throw new CompileError(`stator: ${ns}:${name} requires a value ({...})`, loc2(attr));
44783
+ if (!import_typescript3.default.isJsxAttribute(attr)) continue;
44784
+ if (import_typescript3.default.isJsxNamespacedName(attr.name)) {
44785
+ const ns = attr.name.namespace.text;
44786
+ const name = attr.name.name.text;
44787
+ if (ns !== "on" && ns !== "bind") continue;
44788
+ const expr = attrExpr(attr);
44789
+ if (!expr) {
44790
+ throw new CompileError(`stator: ${ns}:${name} requires a value ({...})`, loc2(attr));
44791
+ }
44792
+ if (ns === "on") {
44793
+ pending.push({ marker: "", kind: "on", event: name, expr, deps: [] });
44794
+ } else {
44795
+ pending.push({
44796
+ marker: "",
44797
+ kind: "bind",
44798
+ target: name,
44799
+ expr,
44800
+ deps: inferDeps(expr, client.useFields)
44801
+ });
44802
+ }
44803
+ consumed.add(attr);
44804
+ continue;
44753
44805
  }
44754
- if (ns === "on") {
44755
- pending.push({ marker: "", kind: "on", event: name, expr, deps: [] });
44756
- } else {
44806
+ const init = attr.initializer;
44807
+ if (init && import_typescript3.default.isJsxExpression(init) && init.expression && isClientRead(init.expression)) {
44808
+ const target = attr.name.getText(sf);
44809
+ if (target === "value" || target === "checked") {
44810
+ throw new CompileError(
44811
+ `stator: read() can't live-drive ${target}= from a client machine \u2014 the control owns its draft. Pre-fill with a server-rendered ${target} attribute, populate/reset via ref: at safe moments, and capture input with a typed commit event. See the forms guide.`,
44812
+ loc2(attr)
44813
+ );
44814
+ }
44815
+ const expr = clientReadExpr(init.expression);
44757
44816
  pending.push({
44758
44817
  marker: "",
44759
44818
  kind: "bind",
44760
- target: name,
44819
+ target,
44761
44820
  expr,
44762
44821
  deps: inferDeps(expr, client.useFields)
44763
44822
  });
44823
+ consumed.add(attr);
44764
44824
  }
44765
44825
  }
44766
- if (pending.length === 0) return void 0;
44767
- const marker = `b${new Set(client.directives.map((d) => d.marker)).size}`;
44826
+ if (pending.length === 0) return { consumed };
44827
+ const marker = `b${new Set(client.directives.filter((d) => d.kind !== "slot").map((d) => d.marker)).size}`;
44768
44828
  for (const d of pending) {
44769
44829
  d.marker = marker;
44770
44830
  client.directives.push(d);
44771
44831
  }
44772
- return marker;
44832
+ return { marker, consumed };
44773
44833
  };
44774
44834
  const lowerChildrenPlaceholder = (attrs) => {
44775
44835
  if (meta) meta.usesChildren = true;
@@ -44844,18 +44904,30 @@ function lowerTemplate(template, opts = {}) {
44844
44904
  };
44845
44905
  const lowerComponent = (tag, attrs, children) => {
44846
44906
  const entries = [];
44907
+ const forwarded = [];
44847
44908
  for (const attr of attrs.properties) {
44848
44909
  if (import_typescript3.default.isJsxSpreadAttribute(attr)) {
44849
- throw new CompileError(
44850
- `stator: spread props ({...x}) on <${tag}/> are not supported`,
44851
- loc2(attr)
44852
- );
44910
+ entries.push(`...${lowerExprText(attr.expression)}`);
44911
+ continue;
44853
44912
  }
44854
44913
  if (import_typescript3.default.isJsxNamespacedName(attr.name)) {
44855
- throw new CompileError(
44856
- `stator: directive "${attr.name.namespace.text}:${attr.name.name.text}" is not valid on component <${tag}/> \u2014 directives apply to HTML elements, not components`,
44857
- loc2(attr)
44858
- );
44914
+ const ns = attr.name.namespace.text;
44915
+ const dirName = attr.name.name.text;
44916
+ if (ns !== "on") {
44917
+ throw new CompileError(
44918
+ `stator: forwarding "${ns}:${dirName}" to a component isn't supported yet \u2014 only on:* event directives forward. Apply bind:/ref: on an element directly.`,
44919
+ loc2(attr)
44920
+ );
44921
+ }
44922
+ const value = attrExpr(attr);
44923
+ if (!value) {
44924
+ throw new CompileError(
44925
+ `stator: on:${dirName} on <${tag}/> requires a handler ({...})`,
44926
+ loc2(attr)
44927
+ );
44928
+ }
44929
+ forwarded.push(`${JSON.stringify(`on:${dirName}`)}: ${value}`);
44930
+ continue;
44859
44931
  }
44860
44932
  const name = attr.name.getText(sf);
44861
44933
  if (!attr.initializer) {
@@ -44892,6 +44964,7 @@ function lowerTemplate(template, opts = {}) {
44892
44964
  }
44893
44965
  if (bag.length > 0) entries.push(`children: { ${bag.join(", ")} }`);
44894
44966
  }
44967
+ if (forwarded.length > 0) entries.push(`$directives: { ${forwarded.join(", ")} }`);
44895
44968
  return `${tag}({ ${entries.join(", ")} })`;
44896
44969
  };
44897
44970
  const body = `html\`${doctype}${contentOfChildren(fragment.children)}\``;
@@ -45145,7 +45218,7 @@ function isSubjectGlobal(sel) {
45145
45218
  }
45146
45219
 
45147
45220
  // ../stator/src/compiler/compile.ts
45148
- var PRIMITIVES_IMPORT = "import { html, read, each, itemBind, when, match, defer, on, classList, styleList } from '@statorjs/stator/template'";
45221
+ var PRIMITIVES_IMPORT = "import { html, read, each, itemBind, when, match, defer, on, classList, styleList, spreadAttrs } from '@statorjs/stator/template'";
45149
45222
  function compile(source, opts = {}) {
45150
45223
  const { frontmatter, template, styles, scripts, scriptOffsets, templateOffset } = splitStator(source);
45151
45224
  const kind = opts.kind ?? "component";
@@ -45222,7 +45295,7 @@ function compileClient(template, script, ctx) {
45222
45295
  const attrDecl = `{ ${[...cls.staticAttrs].map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join(", ")} }`;
45223
45296
  const rootScope = ctx.scopeAttr ? ` data-s-${ctx.hash}` : "";
45224
45297
  const serverCode = [
45225
- "import { html, read, each, when, match, defer, on, classList, styleList, createHtmlFragment, clientShellAttrs } from '@statorjs/stator/template'",
45298
+ "import { html, read, each, when, match, defer, on, classList, styleList, spreadAttrs, createHtmlFragment, clientShellAttrs } from '@statorjs/stator/template'",
45226
45299
  "",
45227
45300
  `export default function (props = {}) {`,
45228
45301
  ` const __inner = ${innerExpr}`,
@@ -45351,6 +45424,23 @@ function processFrontmatter(fm, kind, source, file) {
45351
45424
  repls.push([n.getStart(sf), n.getEnd(), bound]);
45352
45425
  return;
45353
45426
  }
45427
+ if (import_typescript4.default.isCallExpression(n) && isStatorCall(n, "forwarded")) {
45428
+ if (kind === "route") {
45429
+ throw new CompileError(
45430
+ "stator: Stator.forwarded() is only available in a component \u2014 it reads a directive forwarded from a parent (`<Child on:click={h}/>`), and a route has no parent.",
45431
+ locInFm(n)
45432
+ );
45433
+ }
45434
+ const arg = n.arguments[0];
45435
+ if (!arg) {
45436
+ throw new CompileError(
45437
+ "stator: Stator.forwarded(name) takes a directive name, e.g. Stator.forwarded('on:click')",
45438
+ locInFm(n)
45439
+ );
45440
+ }
45441
+ repls.push([n.getStart(sf), n.getEnd(), `props.$directives?.[${arg.getText(sf)}]`]);
45442
+ return;
45443
+ }
45354
45444
  if (import_typescript4.default.isPropertyAccessExpression(n) && isStatorMember(n, "request")) {
45355
45445
  requireRoute("Stator.request", kind, locInFm(n));
45356
45446
  repls.push([n.getStart(sf), n.getEnd(), "__req"]);
@@ -45512,16 +45602,17 @@ function injectImports(globals, modulePath, userCode) {
45512
45602
  return missing.length > 0 ? `import { ${missing.join(", ")} } from '${modulePath}';
45513
45603
  ` : "";
45514
45604
  }
45515
- var AMBIENT_TYPE_IMPORTS = "import type { AnyMachineDef as __SMachineDef } from '@statorjs/stator/machine';\nimport type { InstanceOf as __SInstanceOf } from '@statorjs/stator/template';\n";
45605
+ var AMBIENT_TYPE_IMPORTS = "import type { AnyMachineDef as __SMachineDef } from '@statorjs/stator/machine';\nimport type { InstanceOf as __SInstanceOf } from '@statorjs/stator/template';\nimport type { StatorIntrinsicElements as __SIntrinsics } from '@statorjs/stator/template';\n";
45516
45606
  var STATOR_AMBIENT = `declare const Stator: {
45517
45607
  props<P>(): P;
45518
45608
  reads<const T extends readonly __SMachineDef[]>(defs: T): { -readonly [K in keyof T]: __SInstanceOf<T[K]> };
45609
+ forwarded(name: \`on:\${string}\`): (() => unknown) | undefined;
45519
45610
  request: any;
45520
45611
  response: { status: number; headers: Record<string, string>; cookies: any };
45521
45612
  };
45522
45613
  declare global {
45523
45614
  namespace JSX {
45524
- interface IntrinsicElements extends Record<string, any> {}
45615
+ interface IntrinsicElements extends __SIntrinsics {}
45525
45616
  }
45526
45617
  }
45527
45618
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statorjs/language-server",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Volar-based language server for .stator files.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -33,7 +33,7 @@
33
33
  "volar-service-typescript": "0.0.71",
34
34
  "vscode-css-languageservice": "^6.3.0",
35
35
  "vscode-uri": "^3.0.8",
36
- "@statorjs/stator": "1.8.0"
36
+ "@statorjs/stator": "1.9.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "typescript": "^5.6.0"