fix(tooling): reconcile framework fixes in canonical WireJS checkout
This commit is contained in:
1 parent
a077515336
commit
65d63dfbe7
19 files changed
+312
-156
No files matched your search
@@ -668,7 +668,7 @@
|
|||||||
},
|
},
|
||||||
"packages/syntax": {
|
"packages/syntax": {
|
||||||
"name": "@wrnexus/syntax",
|
"name": "@wrnexus/syntax",
|
||||||
"version": "0.8.18",
|
"version": "0.8.19",
|
||||||
},
|
},
|
||||||
"packages/test": {
|
"packages/test": {
|
||||||
"name": "@wrnexus/test",
|
"name": "@wrnexus/test",
|
||||||
@@ -680,7 +680,7 @@
|
|||||||
},
|
},
|
||||||
"packages/typecheck": {
|
"packages/typecheck": {
|
||||||
"name": "@wrnexus/typecheck",
|
"name": "@wrnexus/typecheck",
|
||||||
"version": "0.8.16",
|
"version": "0.8.17",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/syntax": "workspace:*",
|
"@wrnexus/syntax": "workspace:*",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^6.0.3",
|
||||||
@@ -688,7 +688,7 @@
|
|||||||
},
|
},
|
||||||
"packages/ui": {
|
"packages/ui": {
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.61",
|
"version": "0.8.62",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wrnexus/core": "workspace:*",
|
"@wrnexus/core": "workspace:*",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.8.12
|
||||||
|
|
||||||
|
- Fixed false TypeScript diagnostics for `{t:key}` translations in component props and native HTML attributes. Mixed translated/dynamic attributes still validate ordinary expressions.
|
||||||
|
- Fixed inline event handlers containing multiple statements, and infer `event.currentTarget` from the bound HTML/SVG element.
|
||||||
|
- Rebuilt the bundled language server from the shared framework typechecker; real unknown-name, invalid-property and nullable DOM diagnostics remain enabled.
|
||||||
|
|
||||||
## 0.8.9
|
## 0.8.9
|
||||||
|
|
||||||
- Added highlighting for the page-level `apis { }` block and its `<name> <METHOD> <path>` entries,
|
- Added highlighting for the page-level `apis { }` block and its `<name> <METHOD> <path>` entries,
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"": {
|
"": {
|
||||||
"name": "wrnexus",
|
"name": "wrnexus",
|
||||||
|
"dependencies": {
|
||||||
|
"vscode-html-languageservice": "^5.6.2",
|
||||||
|
"vscode-languageclient": "^10.1.0",
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vscode/vsce": "^3.9.2",
|
"@vscode/vsce": "^3.9.2",
|
||||||
},
|
},
|
||||||
@@ -88,6 +92,8 @@
|
|||||||
|
|
||||||
"@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.6", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og=="],
|
"@typespec/ts-http-runtime": ["@typespec/ts-http-runtime@0.3.6", "", { "dependencies": { "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "tslib": "^2.6.2" } }, "sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og=="],
|
||||||
|
|
||||||
|
"@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="],
|
||||||
|
|
||||||
"@vscode/vsce": ["@vscode/vsce@3.9.2", "", { "dependencies": { "@azure/identity": "^4.1.0", "@secretlint/node": "^10.1.2", "@secretlint/secretlint-formatter-sarif": "^10.1.2", "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", "@vscode/vsce-sign": "^2.0.0", "azure-devops-node-api": "^12.5.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", "cockatiel": "^3.1.2", "commander": "^12.1.0", "form-data": "^4.0.0", "glob": "^13.0.6", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "leven": "^3.1.0", "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^10.2.2", "parse-semver": "^1.1.1", "read": "^1.0.7", "secretlint": "^10.1.2", "semver": "^7.5.2", "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", "yauzl": "^3.2.1", "yazl": "^2.2.2" }, "optionalDependencies": { "keytar": "^7.7.0" }, "bin": { "vsce": "vsce" } }, "sha512-XSxMosEEDO6vLxELAHVkwmhC0qe0ijZni2jB9Rcs8kQsW4lhTDQ/wMzmwFs/buotAWSnpmUp/dRWD2ufG3UYKA=="],
|
"@vscode/vsce": ["@vscode/vsce@3.9.2", "", { "dependencies": { "@azure/identity": "^4.1.0", "@secretlint/node": "^10.1.2", "@secretlint/secretlint-formatter-sarif": "^10.1.2", "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", "@vscode/vsce-sign": "^2.0.0", "azure-devops-node-api": "^12.5.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", "cockatiel": "^3.1.2", "commander": "^12.1.0", "form-data": "^4.0.0", "glob": "^13.0.6", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "leven": "^3.1.0", "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^10.2.2", "parse-semver": "^1.1.1", "read": "^1.0.7", "secretlint": "^10.1.2", "semver": "^7.5.2", "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", "yauzl": "^3.2.1", "yazl": "^2.2.2" }, "optionalDependencies": { "keytar": "^7.7.0" }, "bin": { "vsce": "vsce" } }, "sha512-XSxMosEEDO6vLxELAHVkwmhC0qe0ijZni2jB9Rcs8kQsW4lhTDQ/wMzmwFs/buotAWSnpmUp/dRWD2ufG3UYKA=="],
|
||||||
|
|
||||||
"@vscode/vsce-sign": ["@vscode/vsce-sign@2.0.9", "", { "optionalDependencies": { "@vscode/vsce-sign-alpine-arm64": "2.0.6", "@vscode/vsce-sign-alpine-x64": "2.0.6", "@vscode/vsce-sign-darwin-arm64": "2.0.6", "@vscode/vsce-sign-darwin-x64": "2.0.6", "@vscode/vsce-sign-linux-arm": "2.0.6", "@vscode/vsce-sign-linux-arm64": "2.0.6", "@vscode/vsce-sign-linux-x64": "2.0.6", "@vscode/vsce-sign-win32-arm64": "2.0.6", "@vscode/vsce-sign-win32-x64": "2.0.6" } }, "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g=="],
|
"@vscode/vsce-sign": ["@vscode/vsce-sign@2.0.9", "", { "optionalDependencies": { "@vscode/vsce-sign-alpine-arm64": "2.0.6", "@vscode/vsce-sign-alpine-x64": "2.0.6", "@vscode/vsce-sign-darwin-arm64": "2.0.6", "@vscode/vsce-sign-darwin-x64": "2.0.6", "@vscode/vsce-sign-linux-arm": "2.0.6", "@vscode/vsce-sign-linux-arm64": "2.0.6", "@vscode/vsce-sign-linux-x64": "2.0.6", "@vscode/vsce-sign-win32-arm64": "2.0.6", "@vscode/vsce-sign-win32-x64": "2.0.6" } }, "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g=="],
|
||||||
@@ -542,6 +548,20 @@
|
|||||||
|
|
||||||
"version-range": ["version-range@4.15.0", "", {}, "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg=="],
|
"version-range": ["version-range@4.15.0", "", {}, "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg=="],
|
||||||
|
|
||||||
|
"vscode-html-languageservice": ["vscode-html-languageservice@5.6.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="],
|
||||||
|
|
||||||
|
"vscode-jsonrpc": ["vscode-jsonrpc@9.0.1", "", {}, "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw=="],
|
||||||
|
|
||||||
|
"vscode-languageclient": ["vscode-languageclient@10.1.0", "", { "dependencies": { "minimatch": "^10.2.5", "semver": "^7.8.1", "vscode-languageserver-protocol": "3.18.2", "vscode-languageserver-textdocument": "1.0.13" } }, "sha512-XXRx6lqVitQy/oOLr9MfNYRG+MbQkhXkDaxbQMiKxEm8zZNfheRFUKNb8UYNh2stn9btl2wQM5wZFJjJvoc+jA=="],
|
||||||
|
|
||||||
|
"vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.18.2", "", { "dependencies": { "vscode-jsonrpc": "9.0.1", "vscode-languageserver-types": "3.18.0" } }, "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg=="],
|
||||||
|
|
||||||
|
"vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.12", "", {}, "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA=="],
|
||||||
|
|
||||||
|
"vscode-languageserver-types": ["vscode-languageserver-types@3.18.0", "", {}, "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g=="],
|
||||||
|
|
||||||
|
"vscode-uri": ["vscode-uri@3.2.0", "", {}, "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg=="],
|
||||||
|
|
||||||
"whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
|
"whatwg-encoding": ["whatwg-encoding@3.1.1", "", { "dependencies": { "iconv-lite": "0.6.3" } }, "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ=="],
|
||||||
|
|
||||||
"whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
|
"whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="],
|
||||||
@@ -582,6 +602,8 @@
|
|||||||
|
|
||||||
"table/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"table/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"vscode-languageclient/vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.13", "", {}, "sha512-nx0ZHwMGIsVkzFG3/VLeJYBLTaFBRuNdGDvevvjuoayU5EOS2fEYazOhtCM3PI9ClMMg5igc0uwXtAq4tJj+Dw=="],
|
||||||
|
|
||||||
"@textlint/linter-formatter/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"@textlint/linter-formatter/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
"normalize-package-data/hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "wrnexus",
|
"name": "wrnexus",
|
||||||
"displayName": "WRNexus Language Support",
|
"displayName": "WRNexus Language Support",
|
||||||
"description": "Complete WRNexus v0.8.3 language support for typed imports, props, state, outputs, runtime functions, stores, diagnostics, formatting, navigation, and migration assistance.",
|
"description": "Complete WRNexus v0.8.3 language support for typed imports, props, state, outputs, runtime functions, stores, diagnostics, formatting, navigation, and migration assistance.",
|
||||||
"version": "0.8.11",
|
"version": "0.8.12",
|
||||||
"publisher": "wrnexus",
|
"publisher": "wrnexus",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "SEE LICENSE IN LICENSE",
|
"license": "SEE LICENSE IN LICENSE",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
// Generated by scripts/build-editor-compiler.mjs. Do not edit directly.
|
// Generated by scripts/build-editor-compiler.mjs. Do not edit directly.
|
||||||
// WRN editor compiler source hash: 3d346a264807ba7b107584dc9a7b505b1d14057b2ad1aa85c5ea890f9b09c272
|
// WRN editor compiler source hash: 89199942be0196a3d06ea3d30dff80d361253192108bd978b5b80d921195c59f
|
||||||
// WRN editor compiler generator hash: f8c1094b47e695151205899de28cd63d574356d26ac49219c4a43db0f2391ef5
|
// WRN editor compiler generator hash: f8c1094b47e695151205899de28cd63d574356d26ac49219c4a43db0f2391ef5
|
||||||
// Generated with TypeScript: 6.0.3
|
// Generated with TypeScript: 6.0.3
|
||||||
const __nodeRequire = require;
|
const __nodeRequire = require;
|
||||||
@@ -1202,10 +1202,16 @@ function renderAttrs(attrs, csrId, reactive = null, dynamicExpressions) {
|
|||||||
if (expression &&
|
if (expression &&
|
||||||
exprRefsState(expression, reactive.runtimeStateNames) &&
|
exprRefsState(expression, reactive.runtimeStateNames) &&
|
||||||
dynamicExpressions) {
|
dynamicExpressions) {
|
||||||
|
const marker = exprRefsState(expression, reactive.stateNames)
|
||||||
|
? ` data-wrn-bind-${bindIndex++}="${attrEscape(JSON.stringify([attr.name, attr.value]))}"`
|
||||||
|
: "";
|
||||||
|
if (isHtmlBooleanAttribute(attr.name)) {
|
||||||
|
dynamicExpressions.push(`\${(${expression}) ? ${JSON.stringify(` ${attr.name}`)} : ""}`);
|
||||||
|
return `\x00WRNEACH${dynamicExpressions.length - 1}\x00${marker}`;
|
||||||
|
}
|
||||||
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
||||||
const sentinel = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
const sentinel = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
||||||
const marker = JSON.stringify([attr.name, attr.value]);
|
return ` ${attr.name}="${sentinel}"${marker}`;
|
||||||
return ` ${attr.name}="${sentinel}" data-wrn-bind-${bindIndex++}="${attrEscape(marker)}"`;
|
|
||||||
}
|
}
|
||||||
const initial = reactiveAttrValue(attr.value, reactive);
|
const initial = reactiveAttrValue(attr.value, reactive);
|
||||||
if (initial === null)
|
if (initial === null)
|
||||||
@@ -1253,17 +1259,20 @@ function evalStateSeeds(states) {
|
|||||||
*/
|
*/
|
||||||
function substituteReactiveText(raw, reactive, dynamicExpressions) {
|
function substituteReactiveText(raw, reactive, dynamicExpressions) {
|
||||||
const text = substituteTMarkers(raw);
|
const text = substituteTMarkers(raw);
|
||||||
if (!reactive || reactive.stateNames.size === 0)
|
if (!reactive)
|
||||||
return text;
|
return text;
|
||||||
return text.replace(/\{([^{}]+)\}/g, (whole, inner) => {
|
return text.replace(/\{([^{}]+)\}/g, (whole, inner) => {
|
||||||
const expr = inner.trim();
|
const expr = inner.trim();
|
||||||
if (expr.startsWith("t:") || !exprRefsState(expr, reactive.stateNames))
|
const clientReactive = exprRefsState(expr, reactive.stateNames);
|
||||||
|
if (expr.startsWith("t:"))
|
||||||
return whole;
|
return whole;
|
||||||
if (exprRefsState(expr, reactive.runtimeStateNames) && dynamicExpressions) {
|
if (exprRefsState(expr, reactive.runtimeStateNames) && dynamicExpressions) {
|
||||||
dynamicExpressions.push(`\${__wrnexusEscapeHtml(${expr})}`);
|
dynamicExpressions.push(`\${__wrnexusEscapeHtml(${expr})}`);
|
||||||
const sentinel = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
const sentinel = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
||||||
return `<span data-text="${attrEscape(expr)}">${sentinel}</span>`;
|
return clientReactive ? `<span data-text="${attrEscape(expr)}">${sentinel}</span>` : sentinel;
|
||||||
}
|
}
|
||||||
|
if (!clientReactive)
|
||||||
|
return whole;
|
||||||
let value;
|
let value;
|
||||||
try {
|
try {
|
||||||
value = new Function("with(this){return (" + expr + ");}").call(reactive.scope);
|
value = new Function("with(this){return (" + expr + ");}").call(reactive.scope);
|
||||||
@@ -1339,6 +1348,18 @@ function renderLoopBody(node, locals = []) {
|
|||||||
if (attr.boolean) {
|
if (attr.boolean) {
|
||||||
return escLit(` ${name}`);
|
return escLit(` ${name}`);
|
||||||
}
|
}
|
||||||
|
// Native boolean attributes inside #if/#each must use presence semantics,
|
||||||
|
// just like attributes on the page root. disabled="false" still disables
|
||||||
|
// an HTML input. Component props retain their serialized boolean value.
|
||||||
|
if (!componentTag &&
|
||||||
|
!node.attrs.some((a) => a.name === "data-component") &&
|
||||||
|
isHtmlBooleanAttribute(name)) {
|
||||||
|
const expression = wholeAttributeExpression(attr.value);
|
||||||
|
if (expression)
|
||||||
|
return "${(" + expression + ") ? " + JSON.stringify(` ${name}`) + ' : ""}';
|
||||||
|
if (attr.value === "false")
|
||||||
|
return "";
|
||||||
|
}
|
||||||
return escLit(` ${name}="`) + bakeLoopAttr(attr.value, componentTag) + escLit(`"`);
|
return escLit(` ${name}="`) + bakeLoopAttr(attr.value, componentTag) + escLit(`"`);
|
||||||
})
|
})
|
||||||
.join("");
|
.join("");
|
||||||
@@ -1458,6 +1479,16 @@ function renderNode(node, ssrBindings, csrBindings, apiBindings, loops, reactive
|
|||||||
// templateEscape, swapped for its real `${…}` code after escaping.
|
// templateEscape, swapped for its real `${…}` code after escaping.
|
||||||
if (node.type === "each" || node.type === "if") {
|
if (node.type === "each" || node.type === "if") {
|
||||||
loops.push(node.type === "each" ? compileEachExpr(node) : compileIfExpr(node));
|
loops.push(node.type === "each" ? compileEachExpr(node) : compileIfExpr(node));
|
||||||
|
const conditions = node.type === "each"
|
||||||
|
? [node.list]
|
||||||
|
: node.branches.flatMap((branch) => (branch.cond ? [branch.cond] : []));
|
||||||
|
// Server-only loader values are not serialized into browser state. Their
|
||||||
|
// controls must not be re-evaluated by a surrounding component's hydration.
|
||||||
|
if (reactive &&
|
||||||
|
conditions.some((condition) => exprRefsState(condition, reactive.runtimeStateNames)) &&
|
||||||
|
!conditions.some((condition) => exprRefsState(condition, reactive.stateNames))) {
|
||||||
|
return `\x00WRNEACH${loops.length - 1}\x00`;
|
||||||
|
}
|
||||||
const definition = node.type === "each"
|
const definition = node.type === "each"
|
||||||
? {
|
? {
|
||||||
list: node.list,
|
list: node.list,
|
||||||
@@ -1621,7 +1652,7 @@ function renderNestedComponentInvocation(node, ctx) {
|
|||||||
const wholeExpression = wholeAttributeExpression(attr.value);
|
const wholeExpression = wholeAttributeExpression(attr.value);
|
||||||
const compiledValue = wholeExpression
|
const compiledValue = wholeExpression
|
||||||
? `\${__wrnProp(${ctx.resolveExpr(wholeExpression)})}`
|
? `\${__wrnProp(${ctx.resolveExpr(wholeExpression)})}`
|
||||||
: compileAttrValue(attr.value, ctx);
|
: compileAttrValue(attr.value, ctx, attr.name === "pattern");
|
||||||
const rendered = ` ${attr.name}="${compiledValue}"`;
|
const rendered = ` ${attr.name}="${compiledValue}"`;
|
||||||
if (!attr.value.includes("{") ||
|
if (!attr.value.includes("{") ||
|
||||||
(!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))) {
|
(!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))) {
|
||||||
@@ -2250,7 +2281,7 @@ function generateInner(ast) {
|
|||||||
.map((load) => load.name),
|
.map((load) => load.name),
|
||||||
];
|
];
|
||||||
const runtimeStateNames = runtimeComputedNames(orderedStates, orderedComputed, runtimeRoots);
|
const runtimeStateNames = runtimeComputedNames(orderedStates, orderedComputed, runtimeRoots);
|
||||||
const reactive = reactiveNames.length > 0
|
const reactive = reactiveNames.length > 0 || runtimeStateNames.size > 0
|
||||||
? { stateNames: new Set(reactiveNames), runtimeStateNames, scope: seedScope }
|
? { stateNames: new Set(reactiveNames), runtimeStateNames, scope: seedScope }
|
||||||
: null;
|
: null;
|
||||||
const loops = [];
|
const loops = [];
|
||||||
@@ -2739,7 +2770,7 @@ function compileText(raw, ctx) {
|
|||||||
return out + escLit(raw.slice(last));
|
return out + escLit(raw.slice(last));
|
||||||
}
|
}
|
||||||
/** Compile an attribute value; `{expr}` is baked server-side (loop vars stay literal). */
|
/** Compile an attribute value; `{expr}` is baked server-side (loop vars stay literal). */
|
||||||
function compileAttrValue(raw, ctx) {
|
function compileAttrValue(raw, ctx, regexPattern = false) {
|
||||||
if (!raw.includes("{"))
|
if (!raw.includes("{"))
|
||||||
return escLit(attrEscape(raw));
|
return escLit(attrEscape(raw));
|
||||||
let out = "";
|
let out = "";
|
||||||
@@ -2749,7 +2780,10 @@ function compileAttrValue(raw, ctx) {
|
|||||||
while ((m = INTERP_RE.exec(raw))) {
|
while ((m = INTERP_RE.exec(raw))) {
|
||||||
out += escLit(attrEscape(raw.slice(last, m.index)));
|
out += escLit(attrEscape(raw.slice(last, m.index)));
|
||||||
const expr = m[1].trim();
|
const expr = m[1].trim();
|
||||||
if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
|
if (regexPattern && /^\d+(?:,\d*)?$/.test(expr)) {
|
||||||
|
out += escLit(attrEscape(m[0])); // Regex quantifiers are not template expressions.
|
||||||
|
}
|
||||||
|
else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
|
||||||
out += escLit(`{${expr}}`); // hydrated per-item by the list renderer
|
out += escLit(`{${expr}}`); // hydrated per-item by the list renderer
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -3047,7 +3081,7 @@ function renderComponentNode(node, ctx) {
|
|||||||
}
|
}
|
||||||
const compiledValue = isExplicitComponentMount && wholeExpression
|
const compiledValue = isExplicitComponentMount && wholeExpression
|
||||||
? `\${__wrnProp(${elementContext.resolveExpr(wholeExpression)})}`
|
? `\${__wrnProp(${elementContext.resolveExpr(wholeExpression)})}`
|
||||||
: compileAttrValue(a.value, elementContext);
|
: compileAttrValue(a.value, elementContext, a.name === "pattern");
|
||||||
/*
|
/*
|
||||||
* A constraint attribute whose value is only known at render time (a
|
* A constraint attribute whose value is only known at render time (a
|
||||||
* component prop defaulting to "") must be decided at render time, so
|
* component prop defaulting to "") must be decided at render time, so
|
||||||
@@ -3528,7 +3562,7 @@ function __wrnProp(v) {
|
|||||||
const value = v !== null && typeof v === "object" ? JSON.stringify(v) : String(v == null ? "" : v);
|
const value = v !== null && typeof v === "object" ? JSON.stringify(v) : String(v == null ? "" : v);
|
||||||
return __wrnAttr(value);
|
return __wrnAttr(value);
|
||||||
}
|
}
|
||||||
function renderPageComponentAttr(attr, dynamicExpressions, _reactive) {
|
function renderPageComponentAttr(attr, dynamicExpressions, reactive) {
|
||||||
if (attr.event) {
|
if (attr.event) {
|
||||||
return ` ${componentEventAttribute(attr.name)}="${attrEscape(attr.value)}"`;
|
return ` ${componentEventAttribute(attr.name)}="${attrEscape(attr.value)}"`;
|
||||||
}
|
}
|
||||||
@@ -3541,6 +3575,11 @@ function renderPageComponentAttr(attr, dynamicExpressions, _reactive) {
|
|||||||
}
|
}
|
||||||
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
dynamicExpressions.push(`\${__wrnexusPropAttr(${expression})}`);
|
||||||
const marker = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
const marker = `\x00WRNEACH${dynamicExpressions.length - 1}\x00`;
|
||||||
|
if (reactive &&
|
||||||
|
exprRefsState(expression, reactive.runtimeStateNames) &&
|
||||||
|
!exprRefsState(expression, reactive.stateNames)) {
|
||||||
|
return ` ${attr.name}="${marker}"`;
|
||||||
|
}
|
||||||
// The mount disappears during SSR. Preserve every dynamic component prop
|
// The mount disappears during SSR. Preserve every dynamic component prop
|
||||||
// as a parent-owned binding; server-only expressions simply fail closed in
|
// as a parent-owned binding; server-only expressions simply fail closed in
|
||||||
// the browser, while page state can continue driving the mounted child.
|
// the browser, while page state can continue driving the mounted child.
|
||||||
@@ -6229,7 +6268,7 @@ function expandStructuredStateDeclarations(lines, unit) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
||||||
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([\[{][\s\S]*)$/.exec(value);
|
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([[{][\s\S]*)$/.exec(value);
|
||||||
if (!match)
|
if (!match)
|
||||||
return null;
|
return null;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// WRN editor extension source hash: d07c535bd69332e90f207cbc254aae06982b40dd863fbc8de63fb386ecf31f50
|
// WRN editor extension source hash: fd585db47099c8b781bf49e4ce7c86146bad583f781d0aa93196eb200a95b20f
|
||||||
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
|
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
|
||||||
"use strict";
|
"use strict";
|
||||||
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
||||||
@@ -10089,7 +10089,7 @@ var require_commonjs = __commonJS(function(exports2) {
|
|||||||
// editors/vscode/node_modules/brace-expansion/dist/commonjs/index.js
|
// editors/vscode/node_modules/brace-expansion/dist/commonjs/index.js
|
||||||
var require_commonjs2 = __commonJS(function(exports2) {
|
var require_commonjs2 = __commonJS(function(exports2) {
|
||||||
Object.defineProperty(exports2, "__esModule", { value: true });
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
||||||
exports2.EXPANSION_MAX_LENGTH = exports2.EXPANSION_MAX = undefined;
|
exports2.EXPANSION_MAX = undefined;
|
||||||
exports2.expand = expand;
|
exports2.expand = expand;
|
||||||
var balanced_match_1 = require_commonjs();
|
var balanced_match_1 = require_commonjs();
|
||||||
var escSlash = "\x00SLASH" + Math.random() + "\x00";
|
var escSlash = "\x00SLASH" + Math.random() + "\x00";
|
||||||
@@ -10108,7 +10108,6 @@ var require_commonjs2 = __commonJS(function(exports2) {
|
|||||||
var commaPattern = /\\,/g;
|
var commaPattern = /\\,/g;
|
||||||
var periodPattern = /\\\./g;
|
var periodPattern = /\\\./g;
|
||||||
exports2.EXPANSION_MAX = 1e5;
|
exports2.EXPANSION_MAX = 1e5;
|
||||||
exports2.EXPANSION_MAX_LENGTH = 4000000;
|
|
||||||
function numeric(str) {
|
function numeric(str) {
|
||||||
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0);
|
||||||
}
|
}
|
||||||
@@ -10142,11 +10141,11 @@ var require_commonjs2 = __commonJS(function(exports2) {
|
|||||||
if (!str) {
|
if (!str) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const { max = exports2.EXPANSION_MAX, maxLength = exports2.EXPANSION_MAX_LENGTH } = options;
|
const { max = exports2.EXPANSION_MAX } = options;
|
||||||
if (str.slice(0, 2) === "{}") {
|
if (str.slice(0, 2) === "{}") {
|
||||||
str = "\\{\\}" + str.slice(2);
|
str = "\\{\\}" + str.slice(2);
|
||||||
}
|
}
|
||||||
return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces);
|
return expand_(escapeBraces(str), max, true).map(unescapeBraces);
|
||||||
}
|
}
|
||||||
function embrace(str) {
|
function embrace(str) {
|
||||||
return "{" + str + "}";
|
return "{" + str + "}";
|
||||||
@@ -10160,87 +10159,20 @@ var require_commonjs2 = __commonJS(function(exports2) {
|
|||||||
function gte(i, y) {
|
function gte(i, y) {
|
||||||
return i >= y;
|
return i >= y;
|
||||||
}
|
}
|
||||||
function combine(acc, pre, values, max, maxLength, dropEmpties) {
|
function expand_(str, max, isTop) {
|
||||||
const out = [];
|
const expansions = [];
|
||||||
let length = 0;
|
|
||||||
for (let a = 0;a < acc.length; a++) {
|
|
||||||
for (let v = 0;v < values.length; v++) {
|
|
||||||
if (out.length >= max)
|
|
||||||
return out;
|
|
||||||
const expansion = acc[a] + pre + values[v];
|
|
||||||
if (dropEmpties && !expansion)
|
|
||||||
continue;
|
|
||||||
if (length + expansion.length > maxLength)
|
|
||||||
return out;
|
|
||||||
out.push(expansion);
|
|
||||||
length += expansion.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
function expandSequence(body, isAlphaSequence, max, maxLength) {
|
|
||||||
const n = body.split(/\.\./);
|
|
||||||
const N = [];
|
|
||||||
if (n[0] === undefined || n[1] === undefined) {
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
const x = numeric(n[0]);
|
|
||||||
const y = numeric(n[1]);
|
|
||||||
const width = Math.max(n[0].length, n[1].length);
|
|
||||||
let incr = n.length === 3 && n[2] !== undefined ? Math.max(Math.abs(numeric(n[2])), 1) : 1;
|
|
||||||
let test = lte;
|
|
||||||
const reverse = y < x;
|
|
||||||
if (reverse) {
|
|
||||||
incr *= -1;
|
|
||||||
test = gte;
|
|
||||||
}
|
|
||||||
const pad = n.some(isPadded);
|
|
||||||
let length = 0;
|
|
||||||
for (let i = x;test(i, y) && N.length < max; i += incr) {
|
|
||||||
let c;
|
|
||||||
if (isAlphaSequence) {
|
|
||||||
c = String.fromCharCode(i);
|
|
||||||
if (c === "\\") {
|
|
||||||
c = "";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c = String(i);
|
|
||||||
if (pad) {
|
|
||||||
const need = width - c.length;
|
|
||||||
if (need > 0) {
|
|
||||||
const z = new Array(need + 1).join("0");
|
|
||||||
if (i < 0) {
|
|
||||||
c = "-" + z + c.slice(1);
|
|
||||||
} else {
|
|
||||||
c = z + c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (length + c.length > maxLength)
|
|
||||||
break;
|
|
||||||
N.push(c);
|
|
||||||
length += c.length;
|
|
||||||
}
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
function expand_(str, max, maxLength, isTop) {
|
|
||||||
let acc = [""];
|
|
||||||
let dropEmpties = false;
|
|
||||||
let firstGroup = true;
|
|
||||||
for (;; ) {
|
for (;; ) {
|
||||||
const m = (0, balanced_match_1.balanced)("{", "}", str);
|
const m = (0, balanced_match_1.balanced)("{", "}", str);
|
||||||
if (!m) {
|
if (!m)
|
||||||
return combine(acc, str, [""], max, maxLength, dropEmpties);
|
return [str];
|
||||||
}
|
|
||||||
const pre = m.pre;
|
const pre = m.pre;
|
||||||
if (/\$$/.test(pre)) {
|
if (/\$$/.test(m.pre)) {
|
||||||
acc = combine(acc, pre + "{" + m.body + "}", [""], max, maxLength, dropEmpties && !m.post.length);
|
const post2 = m.post.length ? expand_(m.post, max, false) : [""];
|
||||||
firstGroup = false;
|
for (let k = 0;k < post2.length && k < max; k++) {
|
||||||
if (!m.post.length)
|
const expansion = pre + "{" + m.body + "}" + post2[k];
|
||||||
break;
|
expansions.push(expansion);
|
||||||
str = m.post;
|
}
|
||||||
continue;
|
return expansions;
|
||||||
}
|
}
|
||||||
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
||||||
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
||||||
@@ -10252,56 +10184,74 @@ var require_commonjs2 = __commonJS(function(exports2) {
|
|||||||
isTop = true;
|
isTop = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return combine(acc, pre + "{" + m.body + "}" + m.post, [""], max, maxLength, dropEmpties);
|
return [str];
|
||||||
}
|
}
|
||||||
if (firstGroup) {
|
const post = m.post.length ? expand_(m.post, max, false) : [""];
|
||||||
dropEmpties = isTop && !isSequence;
|
let n;
|
||||||
firstGroup = false;
|
|
||||||
}
|
|
||||||
let values;
|
|
||||||
if (isSequence) {
|
if (isSequence) {
|
||||||
values = expandSequence(m.body, isAlphaSequence, max, maxLength);
|
n = m.body.split(/\.\./);
|
||||||
} else {
|
} else {
|
||||||
let n = parseCommaParts(m.body);
|
n = parseCommaParts(m.body);
|
||||||
if (n.length === 1 && n[0] !== undefined) {
|
if (n.length === 1 && n[0] !== undefined) {
|
||||||
n = expand_(n[0], max, maxLength, false).map(embrace);
|
n = expand_(n[0], max, false).map(embrace);
|
||||||
if (n.length === 1) {
|
if (n.length === 1) {
|
||||||
acc = combine(acc, pre + n[0], [""], max, maxLength, dropEmpties && !m.post.length);
|
return post.map((p) => m.pre + n[0] + p);
|
||||||
if (!m.post.length)
|
|
||||||
break;
|
|
||||||
str = m.post;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let dropsEmpties = dropEmpties && !m.post.length && !pre;
|
}
|
||||||
for (let d = 0;dropsEmpties && d < acc.length; d++) {
|
let N;
|
||||||
if (acc[d]) {
|
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
||||||
dropsEmpties = false;
|
const x = numeric(n[0]);
|
||||||
}
|
const y = numeric(n[1]);
|
||||||
|
const width = Math.max(n[0].length, n[1].length);
|
||||||
|
let incr = n.length === 3 && n[2] !== undefined ? Math.max(Math.abs(numeric(n[2])), 1) : 1;
|
||||||
|
let test = lte;
|
||||||
|
const reverse = y < x;
|
||||||
|
if (reverse) {
|
||||||
|
incr *= -1;
|
||||||
|
test = gte;
|
||||||
}
|
}
|
||||||
values = [];
|
const pad = n.some(isPadded);
|
||||||
let valuesLength = 0;
|
N = [];
|
||||||
outer:
|
for (let i = x;test(i, y) && N.length < max; i += incr) {
|
||||||
for (let j = 0;j < n.length; j++) {
|
let c;
|
||||||
const expanded = expand_(n[j], max, maxLength, false);
|
if (isAlphaSequence) {
|
||||||
for (let k = 0;k < expanded.length; k++) {
|
c = String.fromCharCode(i);
|
||||||
const v = expanded[k];
|
if (c === "\\") {
|
||||||
if (dropsEmpties && !v)
|
c = "";
|
||||||
continue;
|
}
|
||||||
if (values.length >= max || valuesLength + v.length > maxLength) {
|
} else {
|
||||||
break outer;
|
c = String(i);
|
||||||
|
if (pad) {
|
||||||
|
const need = width - c.length;
|
||||||
|
if (need > 0) {
|
||||||
|
const z = new Array(need + 1).join("0");
|
||||||
|
if (i < 0) {
|
||||||
|
c = "-" + z + c.slice(1);
|
||||||
|
} else {
|
||||||
|
c = z + c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
values.push(v);
|
|
||||||
valuesLength += v.length;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
N.push(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
N = [];
|
||||||
|
for (let j = 0;j < n.length; j++) {
|
||||||
|
N.push.apply(N, expand_(n[j], max, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length);
|
for (let j = 0;j < N.length; j++) {
|
||||||
if (!m.post.length)
|
for (let k = 0;k < post.length && expansions.length < max; k++) {
|
||||||
break;
|
const expansion = pre + N[j] + post[k];
|
||||||
str = m.post;
|
if (!isTop || isSequence || expansion) {
|
||||||
|
expansions.push(expansion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return expansions;
|
||||||
}
|
}
|
||||||
return acc;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -13933,7 +13883,7 @@ var require_configuration = __commonJS(function(exports2) {
|
|||||||
exports2.SyncConfigurationFeature = SyncConfigurationFeature;
|
exports2.SyncConfigurationFeature = SyncConfigurationFeature;
|
||||||
});
|
});
|
||||||
|
|
||||||
// editors/vscode/node_modules/vscode-languageserver-textdocument/lib/umd/main.js
|
// editors/vscode/node_modules/vscode-languageclient/node_modules/vscode-languageserver-textdocument/lib/umd/main.js
|
||||||
var require_main2 = __commonJS(function(exports2, module2) {
|
var require_main2 = __commonJS(function(exports2, module2) {
|
||||||
var __spreadArray = exports2 && exports2.__spreadArray || function(to, from, pack) {
|
var __spreadArray = exports2 && exports2.__spreadArray || function(to, from, pack) {
|
||||||
if (pack || arguments.length === 2)
|
if (pack || arguments.length === 2)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
// WRN editor language server source hash: 5258b3e76cec47df752d4bb886fbd57a3f3c4af9ca9b6b2bf6742c8d78025ff1
|
// WRN editor language server source hash: d192eefe86b41eaa54eb48a69202842dbeb8ec4ee4e962c912b288820a65b162
|
||||||
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
|
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
|
||||||
// @bun @bun-cjs
|
// @bun @bun-cjs
|
||||||
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
|
(function(exports, require, module, __filename, __dirname) {var __create = Object.create;
|
||||||
@@ -170723,7 +170723,7 @@ function expandStructuredStateDeclarations(lines, unit) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
||||||
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([\[{][\s\S]*)$/.exec(value);
|
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([[{][\s\S]*)$/.exec(value);
|
||||||
if (!match)
|
if (!match)
|
||||||
return null;
|
return null;
|
||||||
try {
|
try {
|
||||||
@@ -173217,12 +173217,13 @@ ${sharedAliases}`);
|
|||||||
append(`declare const ${name}: typeof ${runtimeNamespace(runtime)}.${name};`);
|
append(`declare const ${name}: typeof ${runtimeNamespace(runtime)}.${name};`);
|
||||||
}
|
}
|
||||||
let bindingIndex = 0;
|
let bindingIndex = 0;
|
||||||
|
append("type __WrnEventElement<Tag extends string> = Tag extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[Tag] : Tag extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[Tag] : HTMLElement;");
|
||||||
const reservedProps = new Set(ast.props.map((prop) => prop.name).filter((name) => !safeBindingName(name)));
|
const reservedProps = new Set(ast.props.map((prop) => prop.name).filter((name) => !safeBindingName(name)));
|
||||||
const appendViewBindings = (nodes, locals) => {
|
const appendViewBindings = (nodes, locals) => {
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
if (node.type === "element") {
|
if (node.type === "element") {
|
||||||
for (const attr of node.attrs) {
|
for (const attr of node.attrs) {
|
||||||
const expressions = attr.event ? [attr.value] : extractInterpolations(attr.value).map((segment) => segment.expression);
|
const expressions = attr.event ? [attr.value] : extractInterpolations(attr.value).filter((segment) => !/^t:[^{}]+$/.test(segment.expression)).map((segment) => segment.expression);
|
||||||
for (const expression of expressions) {
|
for (const expression of expressions) {
|
||||||
if (!expression.trim())
|
if (!expression.trim())
|
||||||
continue;
|
continue;
|
||||||
@@ -173230,10 +173231,10 @@ ${sharedAliases}`);
|
|||||||
...[...locals].map((name) => `declare const ${name}: any;`),
|
...[...locals].map((name) => `declare const ${name}: any;`),
|
||||||
...attr.event ? [
|
...attr.event ? [
|
||||||
"declare const payload: any;",
|
"declare const payload: any;",
|
||||||
"declare const event: Event & { target: HTMLElement };"
|
`declare const event: Event & { target: HTMLElement; currentTarget: __WrnEventElement<${JSON.stringify(node.tag)}> };`
|
||||||
] : []
|
] : []
|
||||||
].join(" ");
|
].join(" ");
|
||||||
append(`namespace __wrn_view_${bindingIndex++} { ${declarations} void (${safeViewExpression(expression, reservedProps)}); }`, attr.value);
|
append(`namespace __wrn_view_${bindingIndex++} { ${declarations} ${attr.event ? `void (() => { ${safeViewExpression(expression, reservedProps)} });` : `void (${safeViewExpression(expression, reservedProps)});`} }`, attr.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendViewBindings(node.children, locals);
|
appendViewBindings(node.children, locals);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ test("formats large typed JSON prop defaults with the bundled formatter", () =>
|
|||||||
}`;
|
}`;
|
||||||
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2, printWidth: 70 });
|
const formatted = formatWrn(source, { insertSpaces: true, tabSize: 2, printWidth: 70 });
|
||||||
|
|
||||||
assert.match(formatted, /categories: unknown\[\] = \[\n \{/);
|
assert.match(formatted, /categories: unknown\[\] = \[\n {6}\{/);
|
||||||
assert.match(formatted, /"apps": \[\n \{/);
|
assert.match(formatted, /"apps": \[\n {10}\{/);
|
||||||
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2, printWidth: 70 }), formatted);
|
assert.equal(formatWrn(formatted, { insertSpaces: true, tabSize: 2, printWidth: 70 }), formatted);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,51 @@ function run(messages) {
|
|||||||
return parseResponses(result.stdout || Buffer.alloc(0));
|
return parseResponses(result.stdout || Buffer.alloc(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("bundled language server accepts translated attributes and form statement handlers", () => {
|
||||||
|
const uri = "file:///tmp/wrnexus-translated-contact.wrn";
|
||||||
|
const valid = `page Contact {
|
||||||
|
view {
|
||||||
|
<div data-component="PageHeader" eyebrow="{t:contact.eyebrow}" title="{t:contact.title}" description="{t:contact.description}"></div>
|
||||||
|
<form @wrn:success="event.currentTarget.reset(); toast.success('Sent')"></form>
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
const responses = run([
|
||||||
|
{ jsonrpc: "2.0", id: 1, method: "initialize", params: { rootPath: root } },
|
||||||
|
{ jsonrpc: "2.0", method: "initialized", params: {} },
|
||||||
|
{
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "textDocument/didOpen",
|
||||||
|
params: { textDocument: { uri, languageId: "wrn", version: 1, text: valid } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "textDocument/didChange",
|
||||||
|
params: {
|
||||||
|
textDocument: { uri, version: 2 },
|
||||||
|
contentChanges: [
|
||||||
|
{ text: valid.replace("{t:contact.title}", "{t:contact.title} {missingValue}") },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ jsonrpc: "2.0", method: "textDocument/didSave", params: { textDocument: { uri } } },
|
||||||
|
{ jsonrpc: "2.0", id: 2, method: "shutdown", params: {} },
|
||||||
|
{ jsonrpc: "2.0", method: "exit", params: {} },
|
||||||
|
]);
|
||||||
|
const publications = responses.filter(
|
||||||
|
(item) => item.method === "textDocument/publishDiagnostics",
|
||||||
|
);
|
||||||
|
assert.equal(publications.length, 2);
|
||||||
|
assert.deepEqual(
|
||||||
|
publications[0].params.diagnostics.filter((item) => item.source === "wrnexus-types"),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const errors = publications[1].params.diagnostics.filter(
|
||||||
|
(item) => item.source === "wrnexus-types",
|
||||||
|
);
|
||||||
|
assert.equal(errors.length, 1);
|
||||||
|
assert.match(errors[0].message, /missingValue/);
|
||||||
|
});
|
||||||
|
|
||||||
test("language server starts under Node and keeps official typed components clean", () => {
|
test("language server starts under Node and keeps official typed components clean", () => {
|
||||||
const files = [
|
const files = [
|
||||||
path.join(root, "packages", "ui", "components", "AuthForm.wrn"),
|
path.join(root, "packages", "ui", "components", "AuthForm.wrn"),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { expect, test } from "bun:test";
|
import { expect, test } from "bun:test";
|
||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { Window } from "happy-dom";
|
import { Window, type HTMLInputElement, type HTMLOptionElement, type HTMLElement } from "happy-dom";
|
||||||
|
|
||||||
test("MFA uses the nested Select and restores continuation after hydration without reviving expired challenges", async () => {
|
test("MFA uses the nested Select and restores continuation after hydration without reviving expired challenges", async () => {
|
||||||
const window = new Window({ url: "https://sso.example.test/mfa" });
|
const window = new Window({ url: "https://sso.example.test/mfa" });
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { documentDiagnostics, virtualTypeScriptDocument } from "../src/index.ts";
|
||||||
|
|
||||||
|
test("editor diagnostics accept translated PageHeader attributes without hiding real errors", () => {
|
||||||
|
const document = {
|
||||||
|
uri: "file:///contact.wrn",
|
||||||
|
text: `page Contact {
|
||||||
|
view {
|
||||||
|
<div data-component="PageHeader" eyebrow="{t:contact.eyebrow}" title="{t:contact.title}" description="{t:contact.description}"></div>
|
||||||
|
<p title="{t:contact.title} {missingValue}"></p>
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
const diagnostics = documentDiagnostics(document).filter(
|
||||||
|
(item) => item.source === "wrnexus-types",
|
||||||
|
);
|
||||||
|
expect(diagnostics).toHaveLength(1);
|
||||||
|
expect(diagnostics[0]?.message).toContain("missingValue");
|
||||||
|
expect(diagnostics[0]?.range.start.line).toBe(3);
|
||||||
|
expect(virtualTypeScriptDocument(document).text).not.toContain("void (t:");
|
||||||
|
expect(
|
||||||
|
documentDiagnostics({ ...document, text: document.text.replace("{missingValue}", "") }).filter(
|
||||||
|
(item) => item.source === "wrnexus-types",
|
||||||
|
),
|
||||||
|
).toEqual([]);
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/syntax",
|
"name": "@wrnexus/syntax",
|
||||||
"version": "0.8.18",
|
"version": "0.8.19",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -768,9 +768,7 @@ function expandStructuredStateDeclarations(lines, unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
function formatStructuredPropDeclaration(value, unit, depth, printWidth) {
|
||||||
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([\[{][\s\S]*)$/.exec(
|
const match = /^([A-Za-z_$][\w$]*\??\s*(?::\s*[^=]+?)?\s*=\s*)([[{][\s\S]*)$/.exec(value);
|
||||||
value,
|
|
||||||
);
|
|
||||||
if (!match) return null;
|
if (!match) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,3 +3,5 @@
|
|||||||
Static type checking for `.wrn` declarations, props, state, outputs, functions, stores, and generated virtual TypeScript files.
|
Static type checking for `.wrn` declarations, props, state, outputs, functions, stores, and generated virtual TypeScript files.
|
||||||
|
|
||||||
The package is compiler tooling rather than a browser UI package, so its public kit consists of programmatic typecheck helpers and diagnostics.
|
The package is compiler tooling rather than a browser UI package, so its public kit consists of programmatic typecheck helpers and diagnostics.
|
||||||
|
|
||||||
|
View attribute `{t:key}` segments are translation markers, not TypeScript expressions. Ordinary expressions in the same attribute remain typechecked. Inline event bindings accept statement lists, with `event.currentTarget` typed as the bound HTML/SVG element. Nullable DOM queries still require normal guards.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/typecheck",
|
"name": "@wrnexus/typecheck",
|
||||||
"version": "0.8.16",
|
"version": "0.8.17",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -377,6 +377,9 @@ export function virtualTypeScriptModule(
|
|||||||
// misspelled state/function name cannot silently become `undefined` at
|
// misspelled state/function name cannot silently become `undefined` at
|
||||||
// runtime. Each/handler locals mirror the browser evaluator's bindings.
|
// runtime. Each/handler locals mirror the browser evaluator's bindings.
|
||||||
let bindingIndex = 0;
|
let bindingIndex = 0;
|
||||||
|
append(
|
||||||
|
"type __WrnEventElement<Tag extends string> = Tag extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[Tag] : Tag extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[Tag] : HTMLElement;",
|
||||||
|
);
|
||||||
const reservedProps = new Set(
|
const reservedProps = new Set(
|
||||||
ast.props.map((prop) => prop.name).filter((name) => !safeBindingName(name)),
|
ast.props.map((prop) => prop.name).filter((name) => !safeBindingName(name)),
|
||||||
);
|
);
|
||||||
@@ -386,7 +389,12 @@ export function virtualTypeScriptModule(
|
|||||||
for (const attr of node.attrs) {
|
for (const attr of node.attrs) {
|
||||||
const expressions = attr.event
|
const expressions = attr.event
|
||||||
? [attr.value]
|
? [attr.value]
|
||||||
: extractInterpolations(attr.value).map((segment) => segment.expression);
|
: extractInterpolations(attr.value)
|
||||||
|
// Translation markers are resolved by i18n, not evaluated as JavaScript.
|
||||||
|
// Filter individual segments so mixed translated/dynamic attributes
|
||||||
|
// still typecheck their ordinary expressions.
|
||||||
|
.filter((segment) => !/^t:[^{}]+$/.test(segment.expression))
|
||||||
|
.map((segment) => segment.expression);
|
||||||
for (const expression of expressions) {
|
for (const expression of expressions) {
|
||||||
if (!expression.trim()) continue;
|
if (!expression.trim()) continue;
|
||||||
const declarations = [
|
const declarations = [
|
||||||
@@ -394,12 +402,12 @@ export function virtualTypeScriptModule(
|
|||||||
...(attr.event
|
...(attr.event
|
||||||
? [
|
? [
|
||||||
"declare const payload: any;",
|
"declare const payload: any;",
|
||||||
"declare const event: Event & { target: HTMLElement };",
|
`declare const event: Event & { target: HTMLElement; currentTarget: __WrnEventElement<${JSON.stringify(node.tag)}> };`,
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
].join(" ");
|
].join(" ");
|
||||||
append(
|
append(
|
||||||
`namespace __wrn_view_${bindingIndex++} { ${declarations} void (${safeViewExpression(expression, reservedProps)}); }`,
|
`namespace __wrn_view_${bindingIndex++} { ${declarations} ${attr.event ? `void (() => { ${safeViewExpression(expression, reservedProps)} });` : `void (${safeViewExpression(expression, reservedProps)});`} }`,
|
||||||
attr.value,
|
attr.value,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
import { checkWrnSource, virtualTypeScriptModule } from "../src/index.ts";
|
||||||
|
|
||||||
|
test("translation markers in native and component attributes are not TypeScript expressions", () => {
|
||||||
|
const source = `page Contact {
|
||||||
|
state count = 1
|
||||||
|
view {
|
||||||
|
<div data-component="PageHeader" eyebrow="{t:contact.eyebrow}" title="{t:contact.title}" description="{t:contact.description}"></div>
|
||||||
|
<input aria-label="{t:contact.form.name}" placeholder='{t:contact.form.namePlaceholder}' />
|
||||||
|
<div data-success-message="{t:contact.form.successMessage}" title="{t:contact.title} — {count}">{t:contact.title}</div>
|
||||||
|
<span t:aria-label="contact.form.label"></span>
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
expect(checkWrnSource(source)).toEqual([]);
|
||||||
|
const virtual = virtualTypeScriptModule(source).code;
|
||||||
|
expect(virtual).not.toContain("void (t:");
|
||||||
|
expect(virtual).toContain("void (count)");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("mixed translation bindings retain genuine expression diagnostics", () => {
|
||||||
|
const source = `page Contact {
|
||||||
|
view {
|
||||||
|
<div title="{t:contact.title} — {missingValue}"></div>
|
||||||
|
<div title="{true ? missingBranch : 'fallback'}"></div>
|
||||||
|
<div data-value="{{ t: missingProperty }}"></div>
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
const diagnostics = checkWrnSource(source);
|
||||||
|
for (const name of ["missingValue", "missingBranch", "missingProperty"]) {
|
||||||
|
expect(
|
||||||
|
diagnostics.some((item) => item.code === "WRN-TYPE-2304" && item.message.includes(name)),
|
||||||
|
).toBe(true);
|
||||||
|
}
|
||||||
|
expect(diagnostics.some((item) => item.message.includes("name 't'"))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("the translation exemption does not apply to event handlers", () => {
|
||||||
|
const diagnostics = checkWrnSource(
|
||||||
|
`page Contact { view { <button @click="t:contact.title"></button> } }`,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
diagnostics.some((item) => item.code === "WRN-TYPE-2304" && item.message.includes("contact")),
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("form event statement lists have the correct currentTarget type", () => {
|
||||||
|
const source = `page Contact {
|
||||||
|
view {
|
||||||
|
<form @wrn:success="event.currentTarget.reset(); toast.success('Sent')"></form>
|
||||||
|
<input @input="toast.info(event.currentTarget.value)" />
|
||||||
|
<button @click="event.currentTarget.disabled = true; toast.info('Working')"></button>
|
||||||
|
}
|
||||||
|
}`;
|
||||||
|
expect(checkWrnSource(source)).toEqual([]);
|
||||||
|
const invalid = checkWrnSource(
|
||||||
|
source.replace("event.currentTarget.disabled", "event.currentTarget.notARealProperty"),
|
||||||
|
);
|
||||||
|
expect(invalid.some((item) => item.code === "WRN-TYPE-2339")).toBe(true);
|
||||||
|
});
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@wrnexus/ui",
|
"name": "@wrnexus/ui",
|
||||||
"version": "0.8.61",
|
"version": "0.8.62",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export interface MegaMenuColumn {
|
|||||||
actionHref?: string;
|
actionHref?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MegaMenuRailItem extends NavigationLink {}
|
export type MegaMenuRailItem = NavigationLink;
|
||||||
|
|
||||||
export interface MegaMenuFeatured {
|
export interface MegaMenuFeatured {
|
||||||
eyebrow?: string;
|
eyebrow?: string;
|
||||||
|
|||||||
Reference in new issue
Block a user