@statorjs/language-server 0.1.33 → 0.1.34
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/dist/server.cjs +105 -35
- package/package.json +2 -2
package/dist/server.cjs
CHANGED
|
@@ -44814,6 +44814,10 @@ function codeFrame(source, line, column) {
|
|
|
44814
44814
|
}
|
|
44815
44815
|
return out.join("\n");
|
|
44816
44816
|
}
|
|
44817
|
+
function parseDiagnosticsOf(sf) {
|
|
44818
|
+
const { parseDiagnostics } = sf;
|
|
44819
|
+
return parseDiagnostics ?? [];
|
|
44820
|
+
}
|
|
44817
44821
|
function locAt(source, offset, file) {
|
|
44818
44822
|
const { line, column } = offsetToLineCol(source, offset);
|
|
44819
44823
|
return { file, line, column, frame: codeFrame(source, line, column) };
|
|
@@ -45112,6 +45116,39 @@ function lowerTemplate(template, opts = {}) {
|
|
|
45112
45116
|
import_typescript3.default.forEachChild(node, (child) => checkNoBindingInRcdata(child, rcdataTag));
|
|
45113
45117
|
};
|
|
45114
45118
|
checkNoBindingInRcdata(fragment, null);
|
|
45119
|
+
const childMarkerOf = (attrs) => attrs.properties.find(
|
|
45120
|
+
(a) => import_typescript3.default.isJsxAttribute(a) && !import_typescript3.default.isJsxNamespacedName(a.name) && a.name.getText(sf) === "child"
|
|
45121
|
+
);
|
|
45122
|
+
const checkChildMarkers = (node, underComponent) => {
|
|
45123
|
+
if (import_typescript3.default.isJsxElement(node) || import_typescript3.default.isJsxSelfClosingElement(node)) {
|
|
45124
|
+
const opening = import_typescript3.default.isJsxElement(node) ? node.openingElement : node;
|
|
45125
|
+
const tag = opening.tagName.getText(sf);
|
|
45126
|
+
const marker = childMarkerOf(opening.attributes);
|
|
45127
|
+
if (marker) {
|
|
45128
|
+
const region = marker.initializer && import_typescript3.default.isStringLiteral(marker.initializer) ? marker.initializer.text : "x";
|
|
45129
|
+
if (isComponentTag(tag)) {
|
|
45130
|
+
throw new CompileError(
|
|
45131
|
+
`stator: child="${region}" on <${tag}/> has no effect \u2014 a child="x" marker is only read on a direct element child of a component tag; on a component it is an ignored prop. Wrap it: <div child="${region}"><${tag}/></div>`,
|
|
45132
|
+
loc2(marker)
|
|
45133
|
+
);
|
|
45134
|
+
}
|
|
45135
|
+
if (!underComponent) {
|
|
45136
|
+
throw new CompileError(
|
|
45137
|
+
`stator: child="${region}" has no effect here \u2014 a child="x" marker is only read on a direct element child of a component tag. Move the condition inside the slotted element: <div child="${region}">{cond ? \u2026 : null}</div>`,
|
|
45138
|
+
loc2(marker)
|
|
45139
|
+
);
|
|
45140
|
+
}
|
|
45141
|
+
}
|
|
45142
|
+
checkChildMarkers(opening.attributes, false);
|
|
45143
|
+
if (import_typescript3.default.isJsxElement(node)) {
|
|
45144
|
+
const inner = isComponentTag(tag);
|
|
45145
|
+
for (const child of node.children) checkChildMarkers(child, inner);
|
|
45146
|
+
}
|
|
45147
|
+
return;
|
|
45148
|
+
}
|
|
45149
|
+
import_typescript3.default.forEachChild(node, (child) => checkChildMarkers(child, false));
|
|
45150
|
+
};
|
|
45151
|
+
checkChildMarkers(fragment, false);
|
|
45115
45152
|
const checkItemReadPlacement = (node, frames) => {
|
|
45116
45153
|
if (import_typescript3.default.isCallExpression(node) && import_typescript3.default.isIdentifier(node.expression)) {
|
|
45117
45154
|
const callee = node.expression.text;
|
|
@@ -45775,7 +45812,8 @@ function compile(source, opts = {}) {
|
|
|
45775
45812
|
styles,
|
|
45776
45813
|
file: opts.id,
|
|
45777
45814
|
fm: fm2,
|
|
45778
|
-
source
|
|
45815
|
+
source,
|
|
45816
|
+
templateOffset
|
|
45779
45817
|
});
|
|
45780
45818
|
}
|
|
45781
45819
|
throw new CompileError(
|
|
@@ -45812,7 +45850,7 @@ function compile(source, opts = {}) {
|
|
|
45812
45850
|
}
|
|
45813
45851
|
function compileClient(template, script, ctx) {
|
|
45814
45852
|
const classes = analyzeScriptClasses(script);
|
|
45815
|
-
const root2 = extractClientRoot(template, ctx
|
|
45853
|
+
const root2 = extractClientRoot(template, ctx);
|
|
45816
45854
|
const tags = /* @__PURE__ */ new Set([root2.tag]);
|
|
45817
45855
|
analyzeClient(script, tags, { file: ctx.file });
|
|
45818
45856
|
const cls = classes.find((c) => pascalToKebab(c.name) === root2.tag);
|
|
@@ -45878,23 +45916,27 @@ function compileClient(template, script, ctx) {
|
|
|
45878
45916
|
clientTag: root2.tag
|
|
45879
45917
|
};
|
|
45880
45918
|
}
|
|
45881
|
-
function staticRootAttrs(attrs, sf) {
|
|
45919
|
+
function staticRootAttrs(tag, attrs, sf, at) {
|
|
45882
45920
|
const out = {};
|
|
45883
45921
|
for (const attr of attrs.properties) {
|
|
45884
|
-
|
|
45885
|
-
|
|
45886
|
-
|
|
45887
|
-
|
|
45888
|
-
|
|
45889
|
-
|
|
45890
|
-
out[name] = init.text;
|
|
45922
|
+
const isStatic = import_typescript4.default.isJsxAttribute(attr) && !import_typescript4.default.isJsxNamespacedName(attr.name) && (attr.initializer === void 0 || import_typescript4.default.isStringLiteral(attr.initializer));
|
|
45923
|
+
if (!isStatic) {
|
|
45924
|
+
throw new CompileError(
|
|
45925
|
+
`stator: <${tag} ${attr.getText(sf)}> \u2014 attributes on an island's root must be static (a string literal or a bare boolean). The root is rendered by the shell from the use site's props; a dynamic value belongs on an inner element, or declare it with \`static attrs\` and pass it from the use site.`,
|
|
45926
|
+
at(attr)
|
|
45927
|
+
);
|
|
45891
45928
|
}
|
|
45929
|
+
const name = attr.name.getText(sf);
|
|
45930
|
+
out[name] = attr.initializer === void 0 ? true : attr.initializer.text;
|
|
45892
45931
|
}
|
|
45893
45932
|
return out;
|
|
45894
45933
|
}
|
|
45895
|
-
function extractClientRoot(template,
|
|
45896
|
-
const
|
|
45934
|
+
function extractClientRoot(template, ctx) {
|
|
45935
|
+
const { file } = ctx;
|
|
45936
|
+
const prefix = "const __t = (<>";
|
|
45937
|
+
const wrapped = `${prefix}${template}</>);`;
|
|
45897
45938
|
const sf = import_typescript4.default.createSourceFile("t.tsx", wrapped, import_typescript4.default.ScriptTarget.Latest, true, import_typescript4.default.ScriptKind.TSX);
|
|
45939
|
+
const at = (node) => ctx.source != null && ctx.templateOffset != null ? locAt(ctx.source, ctx.templateOffset + (node.getStart(sf) - prefix.length), file) : void 0;
|
|
45898
45940
|
let fragment;
|
|
45899
45941
|
const find = (n) => {
|
|
45900
45942
|
if (import_typescript4.default.isJsxFragment(n)) {
|
|
@@ -45917,13 +45959,13 @@ function extractClientRoot(template, file) {
|
|
|
45917
45959
|
if (import_typescript4.default.isJsxSelfClosingElement(rootEl)) {
|
|
45918
45960
|
const tag2 = rootEl.tagName.getText(sf);
|
|
45919
45961
|
requireCustomRoot(tag2, file);
|
|
45920
|
-
return { tag: tag2, inner: "", rootAttrs: staticRootAttrs(rootEl.attributes, sf) };
|
|
45962
|
+
return { tag: tag2, inner: "", rootAttrs: staticRootAttrs(tag2, rootEl.attributes, sf, at) };
|
|
45921
45963
|
}
|
|
45922
45964
|
const el = rootEl;
|
|
45923
45965
|
const tag = el.openingElement.tagName.getText(sf);
|
|
45924
45966
|
requireCustomRoot(tag, file);
|
|
45925
45967
|
const inner = wrapped.slice(el.openingElement.getEnd(), el.closingElement.getStart());
|
|
45926
|
-
return { tag, inner, rootAttrs: staticRootAttrs(el.openingElement.attributes, sf) };
|
|
45968
|
+
return { tag, inner, rootAttrs: staticRootAttrs(tag, el.openingElement.attributes, sf, at) };
|
|
45927
45969
|
}
|
|
45928
45970
|
function requireCustomRoot(tag, file) {
|
|
45929
45971
|
if (!isCustomElementTag(tag)) {
|
|
@@ -45943,6 +45985,21 @@ function processFrontmatter(fm, kind, source, file) {
|
|
|
45943
45985
|
let propsType;
|
|
45944
45986
|
const reads = [];
|
|
45945
45987
|
const locInFm = (node) => locAt(source, fmOffset(source) + node.getStart(sf), file);
|
|
45988
|
+
const syntax = parseDiagnosticsOf(sf);
|
|
45989
|
+
if (syntax.length > 0) {
|
|
45990
|
+
const jsx = findJsxLikeAssertion(sf);
|
|
45991
|
+
if (jsx) {
|
|
45992
|
+
throw new CompileError(
|
|
45993
|
+
"stator: JSX isn't allowed in frontmatter \u2014 it's plain TypeScript. Markup belongs in the template (use when()/match() for conditional content); a different page for a not-found case cascades to routes/404.stator.",
|
|
45994
|
+
locInFm(jsx)
|
|
45995
|
+
);
|
|
45996
|
+
}
|
|
45997
|
+
const d = syntax[0];
|
|
45998
|
+
throw new CompileError(
|
|
45999
|
+
`stator: frontmatter syntax error \u2014 ${import_typescript4.default.flattenDiagnosticMessageText(d.messageText, "\n")}`,
|
|
46000
|
+
locAt(source, fmOffset(source) + d.start, file)
|
|
46001
|
+
);
|
|
46002
|
+
}
|
|
45946
46003
|
for (const stmt of sf.statements) {
|
|
45947
46004
|
if (import_typescript4.default.isImportDeclaration(stmt) || import_typescript4.default.isTypeAliasDeclaration(stmt) || import_typescript4.default.isInterfaceDeclaration(stmt)) {
|
|
45948
46005
|
hoisted.push(stmt.getText(sf));
|
|
@@ -46129,6 +46186,19 @@ function requireRoute(what, kind, loc2) {
|
|
|
46129
46186
|
);
|
|
46130
46187
|
}
|
|
46131
46188
|
}
|
|
46189
|
+
function findJsxLikeAssertion(sf) {
|
|
46190
|
+
let found;
|
|
46191
|
+
const visit = (n) => {
|
|
46192
|
+
if (found) return;
|
|
46193
|
+
if (import_typescript4.default.isTypeAssertionExpression(n) && import_typescript4.default.isTypeReferenceNode(n.type) && import_typescript4.default.isIdentifier(n.type.typeName) && !n.type.typeArguments) {
|
|
46194
|
+
found = n;
|
|
46195
|
+
return;
|
|
46196
|
+
}
|
|
46197
|
+
import_typescript4.default.forEachChild(n, visit);
|
|
46198
|
+
};
|
|
46199
|
+
visit(sf);
|
|
46200
|
+
return found;
|
|
46201
|
+
}
|
|
46132
46202
|
function fmOffset(source) {
|
|
46133
46203
|
return source.startsWith("---") ? source.indexOf("\n") + 1 : 0;
|
|
46134
46204
|
}
|
|
@@ -46246,11 +46316,7 @@ function buildServerTsx(regions) {
|
|
|
46246
46316
|
const userCode = fm + regions.template.content;
|
|
46247
46317
|
let code = injectImports(TEMPLATE_GLOBALS, "@statorjs/stator/template", userCode) + AMBIENT_TYPE_IMPORTS + STATOR_AMBIENT;
|
|
46248
46318
|
const { hoisted, body } = splitFrontmatter(fm, fmOffset2);
|
|
46249
|
-
for (const seg of hoisted)
|
|
46250
|
-
push(mappings, seg.sourceOffset, code.length, seg.text.length);
|
|
46251
|
-
code += `${seg.text}
|
|
46252
|
-
`;
|
|
46253
|
-
}
|
|
46319
|
+
for (const seg of hoisted) code = emitSegment(mappings, code, seg);
|
|
46254
46320
|
let tplOffset = regions.template.contentOffset;
|
|
46255
46321
|
let tpl = regions.template.content;
|
|
46256
46322
|
const doctype = DOCTYPE_RE.exec(tpl);
|
|
@@ -46268,12 +46334,7 @@ function buildServerTsx(regions) {
|
|
|
46268
46334
|
}
|
|
46269
46335
|
code += `export default function (_props: ${propsT}) {
|
|
46270
46336
|
`;
|
|
46271
|
-
for (const seg of body) {
|
|
46272
|
-
code += " ";
|
|
46273
|
-
push(mappings, seg.sourceOffset, code.length, seg.text.length);
|
|
46274
|
-
code += `${seg.text}
|
|
46275
|
-
`;
|
|
46276
|
-
}
|
|
46337
|
+
for (const seg of body) code = emitSegment(mappings, `${code} `, seg);
|
|
46277
46338
|
code += " return (<>";
|
|
46278
46339
|
code = appendTemplateTsx(code, mappings, tpl, tplOffset);
|
|
46279
46340
|
code += "</>);\n}\n";
|
|
@@ -46362,13 +46423,29 @@ function expressionEnd(tpl, start) {
|
|
|
46362
46423
|
}
|
|
46363
46424
|
return tpl.length;
|
|
46364
46425
|
}
|
|
46426
|
+
function emitSegment(mappings, code, seg) {
|
|
46427
|
+
if (seg.opaque) return `${code}${JSON.stringify(seg.text)};
|
|
46428
|
+
`;
|
|
46429
|
+
push(mappings, seg.sourceOffset, code.length, seg.text.length);
|
|
46430
|
+
return `${code}${seg.text}
|
|
46431
|
+
`;
|
|
46432
|
+
}
|
|
46365
46433
|
function splitFrontmatter(fm, fmOffset2) {
|
|
46366
46434
|
const hoisted = [];
|
|
46367
46435
|
const body = [];
|
|
46368
46436
|
if (!fm.trim()) return { hoisted, body };
|
|
46369
46437
|
const sf = import_typescript7.default.createSourceFile("fm.ts", fm, import_typescript7.default.ScriptTarget.Latest, true, import_typescript7.default.ScriptKind.TS);
|
|
46438
|
+
const brokenLines = new Set(
|
|
46439
|
+
parseDiagnosticsOf(sf).map((d) => sf.getLineAndCharacterOfPosition(d.start).line)
|
|
46440
|
+
);
|
|
46370
46441
|
for (const stmt of sf.statements) {
|
|
46371
|
-
const
|
|
46442
|
+
const start = stmt.getStart(sf);
|
|
46443
|
+
const seg = { sourceOffset: fmOffset2 + start, text: stmt.getText(sf) };
|
|
46444
|
+
const first = sf.getLineAndCharacterOfPosition(start).line;
|
|
46445
|
+
const last = sf.getLineAndCharacterOfPosition(stmt.getEnd()).line;
|
|
46446
|
+
for (let line = first; line <= last; line++) {
|
|
46447
|
+
if (brokenLines.has(line)) seg.opaque = true;
|
|
46448
|
+
}
|
|
46372
46449
|
if (import_typescript7.default.isImportDeclaration(stmt) || import_typescript7.default.isTypeAliasDeclaration(stmt) || import_typescript7.default.isInterfaceDeclaration(stmt)) {
|
|
46373
46450
|
hoisted.push(seg);
|
|
46374
46451
|
} else {
|
|
@@ -46387,17 +46464,10 @@ function buildClientTsx(regions) {
|
|
|
46387
46464
|
const { hoisted, body } = splitFrontmatter(fm, fmOffset2);
|
|
46388
46465
|
for (const seg of hoisted) {
|
|
46389
46466
|
if (userScript.includes(seg.text.trim())) continue;
|
|
46390
|
-
|
|
46391
|
-
code += `${seg.text}
|
|
46392
|
-
`;
|
|
46467
|
+
code = emitSegment(mappings, code, seg);
|
|
46393
46468
|
}
|
|
46394
46469
|
code += "function __statorFence(props: Record<string, unknown>) {\n";
|
|
46395
|
-
for (const seg of body) {
|
|
46396
|
-
code += " ";
|
|
46397
|
-
push(mappings, seg.sourceOffset, code.length, seg.text.length);
|
|
46398
|
-
code += `${seg.text}
|
|
46399
|
-
`;
|
|
46400
|
-
}
|
|
46470
|
+
for (const seg of body) code = emitSegment(mappings, `${code} `, seg);
|
|
46401
46471
|
code += "}\nvoid __statorFence\n";
|
|
46402
46472
|
}
|
|
46403
46473
|
for (const script of regions.scripts) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statorjs/language-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.34",
|
|
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": "2.
|
|
36
|
+
"@statorjs/stator": "2.12.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"typescript": "^5.6.0"
|