// Sanity checks for the VS Code extension assets. Run with `node test/validate.mjs`. // Verifies the JSON contribution files parse and that the bundled compiler both // accepts valid .wrn and reports an offset for invalid .wrn (what diagnostics need). import { readFileSync } from "node:fs"; import { fileURLToPath } from "node:url"; import { dirname, join } from "node:path"; import { createRequire } from "node:module"; const here = dirname(fileURLToPath(import.meta.url)); const root = join(here, ".."); const require = createRequire(import.meta.url); let failures = 0; const ok = (name) => console.log(` ok ${name}`); const bad = (name, detail) => { failures++; console.error(` FAIL ${name}${detail ? " — " + detail : ""}`); }; // 1. All JSON contribution files parse. for (const rel of [ "package.json", "language-configuration.json", "syntaxes/wrn.tmLanguage.json", "syntaxes/wrn.injection.tmLanguage.json", "snippets/wrn.json", ]) { try { JSON.parse(readFileSync(join(root, rel), "utf8")); ok(`json parses: ${rel}`); } catch (e) { bad(`json parses: ${rel}`, e.message); } } // 2. Grammar wires up the right scope + embedded languages. const grammar = JSON.parse(readFileSync(join(root, "syntaxes/wrn.tmLanguage.json"), "utf8")); grammar.scopeName === "source.wrn" ? ok("grammar scopeName") : bad("grammar scopeName"); const localIncludes = []; const visitGrammarNode = (value) => { if (Array.isArray(value)) { value.forEach(visitGrammarNode); return; } if (!value || typeof value !== "object") return; if (typeof value.include === "string" && value.include.startsWith("#")) { localIncludes.push(value.include.slice(1)); } Object.values(value).forEach(visitGrammarNode); }; visitGrammarNode(grammar.patterns); visitGrammarNode(grammar.repository); const missingIncludes = [...new Set(localIncludes)].filter((name) => !grammar.repository?.[name]); missingIncludes.length === 0 ? ok("all local grammar includes resolve") : bad("all local grammar includes resolve", missingIncludes.join(", ")); grammar.repository?.["conditional-class-single"] ? ok("single-quoted class directives are registered") : bad("single-quoted class directives are registered"); grammar.repository?.["style-block"]?.applyEndPatternLast === true ? ok("style blocks keep nested CSS braces embedded") : bad("style blocks keep nested CSS braces embedded"); grammar.repository?.["view-block"]?.applyEndPatternLast === true ? ok("view blocks keep template directive braces embedded") : bad("view blocks keep template directive braces embedded"); grammar.repository?.interpolation?.patterns?.some( (pattern) => pattern.name === "meta.block.directive.wrn", ) ? ok("template block directives have dedicated grammar scopes") : bad("template block directives have dedicated grammar scopes"); // 3. Marketplace metadata and the gallery icon meet vsce requirements. try { const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); manifest.publisher === "wrnexus" ? ok("publisher id") : bad("publisher id"); const language = manifest.contributes?.languages?.find((entry) => entry.id === "wrn"); language?.extensions?.includes(".wrn") ? ok(".wrn extension maps to the wrn language") : bad(".wrn extension maps to the wrn language"); manifest.contributes?.configurationDefaults?.["files.associations"]?.["*.wrn"] === "wrn" ? ok("default file association uses the wrn language id") : bad("default file association uses the wrn language id"); manifest.activationEvents?.includes("onLanguage:wrn") ? ok("extension activates for the wrn language") : bad("extension activates for the wrn language"); manifest.activationEvents?.length === 1 && manifest.activationEvents[0] === "onLanguage:wrn" ? ok("extension activates only when a WRN document is used") : bad("extension avoids workspace-wide startup activation"); const extensionSource = readFileSync(join(root, "src/extension.js"), "utf8"); !extensionSource.includes('createFileSystemWatcher("**/*.wrn")') ? ok("language client avoids an unrestricted workspace watcher") : bad("language client avoids an unrestricted workspace watcher"); manifest.contributes?.configuration?.properties?.["wrnexus.languageServer.enable"]?.default === true ? ok("shared language server is enabled by default") : bad("shared language server is enabled by default"); readFileSync(join(root, "src/language-server.cjs"), "utf8").includes("WRNexus Language Server") ? ok("bundled language server exists") : bad("bundled language server exists"); language?.firstLine ? ok("first-line language detection is configured") : bad("first-line language detection is configured"); manifest.icon?.endsWith(".png") ? ok("Marketplace icon is PNG") : bad("Marketplace icon is PNG"); const icon = readFileSync(join(root, manifest.icon)); const isPng = icon.subarray(1, 4).toString("ascii") === "PNG"; const width = isPng ? icon.readUInt32BE(16) : 0; const height = isPng ? icon.readUInt32BE(20) : 0; isPng && width >= 128 && height >= 128 ? ok(`Marketplace icon dimensions (${width}x${height})`) : bad("Marketplace icon is at least 128x128 PNG"); for (const rel of ["README.md", "CHANGELOG.md", "SUPPORT.md", "LICENSE"]) { readFileSync(join(root, rel), "utf8"); ok(`Marketplace document exists: ${rel}`); } } catch (e) { bad("Marketplace metadata", e.message); } // 4. Bundled compiler: valid source compiles, invalid source throws with an offset. try { const compiler = require(join(root, "src/compiler.cjs")); const good = `page Home {\n view {

Hi

}\n}`; compiler.compileWireFile(good); ok("compiler accepts valid .wrn"); const structuredProps = `page FooterExample { state footerItems = [ { "label": "Accessibility", "href": "/accessibility", "value": "accessibility" } ] view {