@statorjs/language-server 0.1.17 → 0.1.18

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 +99 -91
  2. package/package.json +2 -2
package/dist/server.cjs CHANGED
@@ -44177,50 +44177,14 @@ var import_volar_service_typescript = __toESM(require_volar_service_typescript()
44177
44177
  // ../stator/src/compiler/client-emit.ts
44178
44178
  var import_typescript = __toESM(require("typescript"), 1);
44179
44179
 
44180
- // ../stator/src/compiler/diagnostics.ts
44181
- var CompileError = class extends Error {
44182
- loc;
44183
- constructor(message, loc2) {
44184
- super(message);
44185
- this.name = "CompileError";
44186
- this.loc = loc2;
44187
- }
44188
- };
44189
- function offsetToLineCol(source, offset) {
44190
- const clamped = Math.max(0, Math.min(offset, source.length));
44191
- let line = 1;
44192
- let lastNewline = -1;
44193
- for (let i = 0; i < clamped; i++) {
44194
- if (source.charCodeAt(i) === 10) {
44195
- line++;
44196
- lastNewline = i;
44197
- }
44198
- }
44199
- return { line, column: clamped - lastNewline };
44200
- }
44201
- function codeFrame(source, line, column) {
44202
- const lines = source.split("\n");
44203
- const start = Math.max(1, line - 1);
44204
- const end = Math.min(lines.length, line + 1);
44205
- const gutterWidth = String(end).length;
44206
- const out = [];
44207
- for (let n = start; n <= end; n++) {
44208
- const gutter = String(n).padStart(gutterWidth);
44209
- const marker = n === line ? ">" : " ";
44210
- out.push(`${marker} ${gutter} | ${lines[n - 1] ?? ""}`);
44211
- if (n === line) {
44212
- out.push(` ${" ".repeat(gutterWidth)} | ${" ".repeat(Math.max(0, column - 1))}^`);
44213
- }
44214
- }
44215
- return out.join("\n");
44216
- }
44217
- function locAt(source, offset, file) {
44218
- const { line, column } = offsetToLineCol(source, offset);
44219
- return { file, line, column, frame: codeFrame(source, line, column) };
44220
- }
44180
+ // ../stator/src/wire/island-markers.ts
44181
+ var ISLAND_MARKER_ATTR = "data-b";
44182
+ var elementMarker = (i) => `b${i}`;
44183
+ var slotMarker = (i) => `s${i}`;
44184
+ var elementMarkerSelector = (marker) => `[${ISLAND_MARKER_ATTR}="${marker}"]`;
44221
44185
 
44222
44186
  // ../stator/src/compiler/client-emit.ts
44223
- var PRIMITIVES = "import { StatorElement, defineElement, use, machine, bind, bindSlot, effect, dispatch } from '@statorjs/stator/client'";
44187
+ var PRIMITIVES = "import { StatorElement, defineElement, use, machine, bind, bindSlot, effect, dispatch, attrValue, setAttr } from '@statorjs/stator/client'";
44224
44188
  function emitClientModule(input) {
44225
44189
  const { script, element, directives, members } = input;
44226
44190
  const impl = `__${element.className}Impl`;
@@ -44242,7 +44206,9 @@ function emitClientModule(input) {
44242
44206
  continue;
44243
44207
  }
44244
44208
  const node = `n${i++}`;
44245
- lines.push(` for (const ${node} of this.querySelectorAll('[data-b="${marker}"]')) {`);
44209
+ lines.push(
44210
+ ` for (const ${node} of this.querySelectorAll(${JSON.stringify(elementMarkerSelector(marker))})) {`
44211
+ );
44246
44212
  for (const d of group) lines.push(` ${wireDirective(node, d, members)}`);
44247
44213
  lines.push(" }");
44248
44214
  }
@@ -44268,27 +44234,9 @@ function wireDirective(node, d, members) {
44268
44234
  const target = d.target ?? "text";
44269
44235
  const thunk = `() => (${rewriteMembers(d.expr, members)})`;
44270
44236
  const deps = `[${d.deps.map((dep) => `this.${dep}`).join(", ")}]`;
44271
- if (target === "value" || target === "checked") {
44272
- const path = parseTwoWayPath(d.expr);
44273
- if (!path) {
44274
- throw new CompileError(
44275
- `stator: bind:${target}={${d.expr}} must bind to a settable context path like \`actor.key\` (a derived value can't be two-way bound).`
44276
- );
44277
- }
44278
- const writer2 = emitWriter(node, target);
44279
- const read = target === "checked" ? `${node}.checked` : `${node}.value`;
44280
- const guard = target === "value" ? `if (e.isComposing) return; ` : "";
44281
- const setter = `${node}.addEventListener(${JSON.stringify(target === "value" ? "input" : "change")}, (e) => { ${guard}this.${path.actor}.send({ type: '@set', key: ${JSON.stringify(path.key)}, value: ${read} }) })`;
44282
- return `this.track(bind(${deps}, ${thunk}, ${writer2}));
44283
- ${setter}`;
44284
- }
44285
44237
  const writer = emitWriter(node, target);
44286
44238
  return `this.track(bind(${deps}, ${thunk}, ${writer}))`;
44287
44239
  }
44288
- function parseTwoWayPath(expr) {
44289
- const m = expr.trim().match(/^([A-Za-z_$][\w$]*)\.([A-Za-z_$][\w$]*)$/);
44290
- return m ? { actor: m[1], key: m[2] } : null;
44291
- }
44292
44240
  function emitHandler(expr, members) {
44293
44241
  const t = expr.trim();
44294
44242
  if (/^[A-Za-z_$][\w$]*$/.test(t) && members.has(t)) {
@@ -44298,18 +44246,11 @@ function emitHandler(expr, members) {
44298
44246
  }
44299
44247
  function emitWriter(node, target) {
44300
44248
  switch (target) {
44301
- case "text":
44302
- return `(v) => { ${node}.textContent = v == null ? '' : String(v) }`;
44303
- case "html":
44304
- return `(v) => { ${node}.innerHTML = v == null ? '' : String(v) }`;
44305
- case "value":
44306
- return `(v) => { const s = v == null ? '' : String(v); if (${node}.value !== s) ${node}.value = s }`;
44307
44249
  case "disabled":
44308
44250
  case "hidden":
44309
- case "checked":
44310
44251
  return `(v) => { if (${node}.${target} !== !!v) ${node}.${target} = !!v }`;
44311
44252
  default:
44312
- return `(v) => { if (v == null || v === false) ${node}.removeAttribute(${JSON.stringify(target)}); else ${node}.setAttribute(${JSON.stringify(target)}, v === true ? '' : String(v)) }`;
44253
+ return `(v) => setAttr(${node}, ${JSON.stringify(target)}, attrValue(v))`;
44313
44254
  }
44314
44255
  }
44315
44256
  function stripClientPrimitiveImports(script) {
@@ -44348,6 +44289,50 @@ function rewriteMembers(expr, members) {
44348
44289
 
44349
44290
  // ../stator/src/compiler/client-script.ts
44350
44291
  var import_typescript2 = __toESM(require("typescript"), 1);
44292
+
44293
+ // ../stator/src/compiler/diagnostics.ts
44294
+ var CompileError = class extends Error {
44295
+ loc;
44296
+ constructor(message, loc2) {
44297
+ super(message);
44298
+ this.name = "CompileError";
44299
+ this.loc = loc2;
44300
+ }
44301
+ };
44302
+ function offsetToLineCol(source, offset) {
44303
+ const clamped = Math.max(0, Math.min(offset, source.length));
44304
+ let line = 1;
44305
+ let lastNewline = -1;
44306
+ for (let i = 0; i < clamped; i++) {
44307
+ if (source.charCodeAt(i) === 10) {
44308
+ line++;
44309
+ lastNewline = i;
44310
+ }
44311
+ }
44312
+ return { line, column: clamped - lastNewline };
44313
+ }
44314
+ function codeFrame(source, line, column) {
44315
+ const lines = source.split("\n");
44316
+ const start = Math.max(1, line - 1);
44317
+ const end = Math.min(lines.length, line + 1);
44318
+ const gutterWidth = String(end).length;
44319
+ const out = [];
44320
+ for (let n = start; n <= end; n++) {
44321
+ const gutter = String(n).padStart(gutterWidth);
44322
+ const marker = n === line ? ">" : " ";
44323
+ out.push(`${marker} ${gutter} | ${lines[n - 1] ?? ""}`);
44324
+ if (n === line) {
44325
+ out.push(` ${" ".repeat(gutterWidth)} | ${" ".repeat(Math.max(0, column - 1))}^`);
44326
+ }
44327
+ }
44328
+ return out.join("\n");
44329
+ }
44330
+ function locAt(source, offset, file) {
44331
+ const { line, column } = offsetToLineCol(source, offset);
44332
+ return { file, line, column, frame: codeFrame(source, line, column) };
44333
+ }
44334
+
44335
+ // ../stator/src/compiler/client-script.ts
44351
44336
  function kebabToPascal(tag) {
44352
44337
  return tag.split("-").map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("");
44353
44338
  }
@@ -44542,11 +44527,15 @@ function lowerTemplate(template, opts = {}) {
44542
44527
  const enableItemBind = !opts.client;
44543
44528
  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
44529
  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);
44530
+ const bindRemoved = (name, at) => new CompileError(
44531
+ `stator: bind:${name} was removed in 2.0. Display state with read() \u2014 \`{read(m, (s) => s.value)}\` in text position, \`attr={read(m, \u2026)}\` on an attribute \u2014 and capture input at a commit boundary with a typed event (ref:/FormData + send/dispatch). See the forms guide.`,
44532
+ at
44533
+ );
44545
44534
  const clientReadExpr = (call) => `(${call.arguments[1].getText(sf)})(${call.arguments[0].text})`;
44546
44535
  const allocSlotMarker = () => {
44547
44536
  const client = opts.client;
44548
44537
  if (!client) throw new CompileError("stator: internal \u2014 slot marker outside client mode");
44549
- return `s${client.directives.filter((d) => d.kind === "slot").length}`;
44538
+ return slotMarker(client.directives.filter((d) => d.kind === "slot").length);
44550
44539
  };
44551
44540
  const assertNoClientRead = (n) => {
44552
44541
  if (!opts.client) return;
@@ -44771,7 +44760,7 @@ function lowerTemplate(template, opts = {}) {
44771
44760
  const lowered = lowerAttribute(attr);
44772
44761
  if (lowered) out += ` ${lowered}`;
44773
44762
  }
44774
- if (collected?.marker) out += ` data-b="${collected.marker}"`;
44763
+ if (collected?.marker) out += ` ${ISLAND_MARKER_ATTR}="${collected.marker}"`;
44775
44764
  return out;
44776
44765
  };
44777
44766
  const collectClientDirectives = (attrs) => {
@@ -44784,22 +44773,13 @@ function lowerTemplate(template, opts = {}) {
44784
44773
  if (import_typescript3.default.isJsxNamespacedName(attr.name)) {
44785
44774
  const ns = attr.name.namespace.text;
44786
44775
  const name = attr.name.name.text;
44787
- if (ns !== "on" && ns !== "bind") continue;
44776
+ if (ns === "bind") throw bindRemoved(name, loc2(attr));
44777
+ if (ns !== "on") continue;
44788
44778
  const expr = attrExpr(attr);
44789
44779
  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
- });
44780
+ throw new CompileError(`stator: on:${name} requires a handler ({...})`, loc2(attr));
44802
44781
  }
44782
+ pending.push({ marker: "", kind: "on", event: name, expr, deps: [] });
44803
44783
  consumed.add(attr);
44804
44784
  continue;
44805
44785
  }
@@ -44824,7 +44804,9 @@ function lowerTemplate(template, opts = {}) {
44824
44804
  }
44825
44805
  }
44826
44806
  if (pending.length === 0) return { consumed };
44827
- const marker = `b${new Set(client.directives.filter((d) => d.kind !== "slot").map((d) => d.marker)).size}`;
44807
+ const marker = elementMarker(
44808
+ new Set(client.directives.filter((d) => d.kind !== "slot").map((d) => d.marker)).size
44809
+ );
44828
44810
  for (const d of pending) {
44829
44811
  d.marker = marker;
44830
44812
  client.directives.push(d);
@@ -44883,10 +44865,8 @@ function lowerTemplate(template, opts = {}) {
44883
44865
  if (meta) meta.refs.add(name2);
44884
44866
  return `data-ref=${JSON.stringify(name2)}`;
44885
44867
  }
44886
- throw new CompileError(
44887
- `stator: directive "${ns}:${name2}" is not supported yet (Phase 3b)`,
44888
- loc2(attr)
44889
- );
44868
+ if (ns === "bind") throw bindRemoved(name2, loc2(attr));
44869
+ throw new CompileError(`stator: directive "${ns}:${name2}" is not supported`, loc2(attr));
44890
44870
  }
44891
44871
  const name = attr.name.getText(sf);
44892
44872
  if (!attr.initializer) return name;
@@ -44913,9 +44893,10 @@ function lowerTemplate(template, opts = {}) {
44913
44893
  if (import_typescript3.default.isJsxNamespacedName(attr.name)) {
44914
44894
  const ns = attr.name.namespace.text;
44915
44895
  const dirName = attr.name.name.text;
44896
+ if (ns === "bind") throw bindRemoved(dirName, loc2(attr));
44916
44897
  if (ns !== "on") {
44917
44898
  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.`,
44899
+ `stator: forwarding "${ns}:${dirName}" to a component isn't supported yet \u2014 only on:* event directives forward. Apply ref: on an element directly.`,
44919
44900
  loc2(attr)
44920
44901
  );
44921
44902
  }
@@ -45539,6 +45520,26 @@ function isStatorMember(e, member) {
45539
45520
 
45540
45521
  // ../stator/src/compiler/dts.ts
45541
45522
  var import_typescript5 = __toESM(require("typescript"), 1);
45523
+ function statorPropsType(frontmatter, template, scripts) {
45524
+ const { propsType } = extractFrontmatterTypes(frontmatter);
45525
+ let propsT = componentPropsType(propsType, template);
45526
+ let needsReadResult = false;
45527
+ const classes = scripts.length > 0 ? analyzeScriptClasses(scripts.join("\n")) : [];
45528
+ if (!propsType && classes.length > 0) {
45529
+ const attrs = /* @__PURE__ */ new Map();
45530
+ for (const cls of classes) {
45531
+ for (const [key, kind] of cls.staticAttrs) attrs.set(key, kind);
45532
+ }
45533
+ if (attrs.size > 0) {
45534
+ needsReadResult = true;
45535
+ const fields = [...attrs].map(([key, kind]) => `${key}?: ${kind} | __SReadResult<${kind}>`).join("; ");
45536
+ propsT = `{ ${fields} } & { [prop: string]: unknown }`;
45537
+ } else {
45538
+ propsT = "{ [prop: string]: unknown }";
45539
+ }
45540
+ }
45541
+ return { propsT, needsReadResult };
45542
+ }
45542
45543
  function componentPropsType(propsType, template) {
45543
45544
  const usesChildren = /<children[\s/>]/.test(template);
45544
45545
  if (propsType) return usesChildren ? `${propsType} & { children?: any }` : propsType;
@@ -45644,7 +45645,14 @@ function buildServerTsx(regions) {
45644
45645
  tplOffset += doctype[0].length;
45645
45646
  tpl = tpl.slice(doctype[0].length);
45646
45647
  }
45647
- const propsT = componentPropsType(extractFrontmatterTypes(fm).propsType, regions.template.content);
45648
+ const { propsT, needsReadResult } = statorPropsType(
45649
+ fm,
45650
+ regions.template.content,
45651
+ regions.scripts.map((s) => s.content)
45652
+ );
45653
+ if (needsReadResult) {
45654
+ code += "type __SReadResult<T> = import('@statorjs/stator/template').ReadResult<T>\n";
45655
+ }
45648
45656
  code += `export default function (_props: ${propsT}) {
45649
45657
  `;
45650
45658
  for (const seg of body) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statorjs/language-server",
3
- "version": "0.1.17",
3
+ "version": "0.1.18",
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.9.0"
36
+ "@statorjs/stator": "2.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "typescript": "^5.6.0"