jq79 0.7.2 → 0.7.4
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/README.md +3 -2
- package/dev/vite.ts +152 -10
- package/dist/dom.d.ts +22 -4
- package/dist/html.d.ts +9 -0
- package/dist/jq79-sw.js +32 -0
- package/dist/jq79.cjs +18 -14
- package/dist/jq79.cjs.map +1 -1
- package/dist/jq79.d.ts +27 -13
- package/dist/jq79.global.js +18 -14
- package/dist/jq79.global.js.map +1 -1
- package/dist/jq79.js +18 -14
- package/dist/jq79.js.map +1 -1
- package/dist/precompile.cjs +24 -0
- package/dist/precompile.cjs.map +1 -0
- package/dist/precompile.d.ts +3 -0
- package/dist/precompile.js +24 -0
- package/dist/precompile.js.map +1 -0
- package/dist/reactive.d.ts +10 -0
- package/dist/source.d.ts +65 -0
- package/dist/vite.cjs +85 -4
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.d.ts +3 -0
- package/dist/vite.js +86 -5
- package/dist/vite.js.map +1 -1
- package/package.json +12 -2
- package/src/dom.ts +28 -4
- package/src/html.ts +289 -0
- package/src/jq79.ts +705 -363
- package/src/precompile.ts +238 -0
- package/src/reactive.ts +178 -9
- package/src/source.ts +389 -0
- package/src/sw.ts +87 -0
- package/src/transform.ts +1 -1
package/dist/vite.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../dev/vite.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\"\nimport { relative } from \"node:path\"\nimport { preprocessCSS, transformWithEsbuild } from \"vite\"\nimport type { Plugin, ResolvedConfig } from \"vite\"\n\n// Vite plugin: import .html single-file components as modules.\n//\n// import { jq79 } from \"jq79/vite\" // vite.config\n// import UserCard from \"./UserCard.html\" // app code\n//\n// The imported value is a Component79 built from the file's source - the same\n// thing `await Component79.fetch(url)` resolves to, but bundled at build time\n// instead of fetched at runtime. The component source is inlined verbatim, so\n// a file keeps working unchanged if it's ever served from public/ and loaded\n// with fetch instead - with one deliberate exception, a block that says it is\n// written in something else: <style lang=\"scss\"> (or less/stylus/sass) is\n// compiled to plain CSS here, and a TypeScript script - <script lang=\"ts\">, or\n// the <script type=\"text/typescript\"> editors read as one - to plain JS. Such a\n// component only works through the bundler; loaded with fetch() it would reach\n// the runtime uncompiled, which the runtime warns about.\n//\n// Only .html files imported from other modules are claimed; entry points\n// (index.html) have no importer and imports carrying an explicit query\n// (?raw, ?url) keep their built-in Vite meaning.\n\nexport interface Jq79PluginOptions {\n // which import specifiers are treated as components (default: any .html)\n include?: RegExp\n // resolved absolute paths to skip even when `include` matches\n exclude?: RegExp\n}\n\n// claimed modules get this suffix so their id no longer ends in \".html\" and\n// Vite's own html handling (entries, asset pipeline) leaves them alone\nconst COMPONENT_QUERY = \"?jq79\"\n\n// a <script> block with its attribute string, so `lang` can be read and the\n// body replaced - the same shape as STYLE_BLOCK_RE below, quote-aware so a\n// \">\" inside an attribute value (`:setup=\"{ n = a > 1 }\"`) doesn't end the tag\nconst SCRIPT_BLOCK_RE = /<script((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/script\\s*>/gi\n// import(\"...\") with a literal specifier, tried at word boundaries the\n// scanner below reaches (which is what skips $__import and foo.import(...))\nconst IMPORT_CALL_RE = /import\\s*\\(\\s*([\"'])([^\"'\\n]+?)\\1\\s*\\)/y\n// static import statements (factory scripts): optional clause + literal\n// specifier. The clause can't contain parens/quotes, so dynamic import()\n// and import.meta never match\nconst STATIC_IMPORT_RE = /import\\s*(?:[\\w$\\s,{}*]+?\\s*from\\s*)?([\"'])([^\"'\\n]+)\\1/y\n\nconst skipString = (src: string, start: number): number => {\n const quote = src[start]\n let i = start + 1\n while (i < src.length) {\n if (src[i] === \"\\\\\") { i += 2; continue }\n if (src[i] === quote) return i + 1\n i++\n }\n return src.length\n}\n\n// the literal import specifiers in one script body. A scanner rather than a\n// bare matchAll, because a specifier mentioned in a comment or a string is\n// not an import: hoisting a commented-out `import(\"./old.html\")` would pull\n// dead files into the bundle - or break the build once the file is gone\nconst importSpecifiers = (script: string): string[] => {\n const specs: string[] = []\n let i = 0\n while (i < script.length) {\n const ch = script[i]\n if (ch === \"'\" || ch === '\"' || ch === \"`\") { i = skipString(script, i); continue }\n if (ch === \"/\" && script[i + 1] === \"/\") {\n const end = script.indexOf(\"\\n\", i)\n i = end === -1 ? script.length : end + 1\n continue\n }\n if (ch === \"/\" && script[i + 1] === \"*\") {\n const end = script.indexOf(\"*/\", i + 2)\n i = end === -1 ? script.length : end + 2\n continue\n }\n if (ch === \"i\" && (i === 0 || !/[\\w$.]/.test(script[i - 1]))) {\n IMPORT_CALL_RE.lastIndex = i\n const call = IMPORT_CALL_RE.exec(script)\n if (call) { specs.push(call[2]); i = IMPORT_CALL_RE.lastIndex; continue }\n STATIC_IMPORT_RE.lastIndex = i\n const staticImport = STATIC_IMPORT_RE.exec(script)\n if (staticImport) { specs.push(staticImport[2]); i = STATIC_IMPORT_RE.lastIndex; continue }\n }\n i++\n }\n return specs\n}\n\nconst isHtmlUrl = (spec: string) => /\\.html?([?#]|$)/.test(spec)\nconst isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith(\"/\")\n\n// literal import specifiers in the component's script blocks - dynamic\n// `import(\"...\")` calls and static factory-script imports - that should\n// resolve from the bundle instead of at runtime. Absolute paths and full\n// URLs are left alone (they point at served files, e.g. public/), and so\n// are .html specifiers the plugin wouldn't claim as components\nconst hoistableImports = (source: string, include: RegExp): string[] => {\n const specifiers = new Set<string>()\n for (const [, , script] of source.matchAll(SCRIPT_BLOCK_RE)) {\n for (const spec of importSpecifiers(script)) {\n if (isExternalUrl(spec)) continue\n if (isHtmlUrl(spec) && !include.test(spec)) continue // html left to runtime fetch\n specifiers.add(spec) // a claimed component, a source file or an npm package\n }\n }\n return [...specifiers]\n}\n\n// any start or end tag, quote-aware so a \">\" inside an attribute value doesn't\n// end it early\nconst TAG_RE = /<(\\/?)([A-Za-z][\\w-]*)((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>/g\nconst NAME_ATTR_RE = /\\bname\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i\nconst COMPONENT_NAME_RE = /^[A-Z][A-Za-z0-9]*$/\nconst VOID_ELEMENTS = new Set([\n \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\",\n \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\",\n])\n\n// the components a file declares: its *top-level* <template name=\"…\"> blocks,\n// which the emitted module re-exports by name. Depth is tracked because only\n// the top level declares - a <template> nested in the markup is a plain inert\n// element the runtime leaves alone, and exporting it would name something that\n// never exists. Script and style bodies are cut out first, so a \"<\" in JS or a\n// selector can't be read as a tag\nconst declaredComponents = (source: string): string[] => {\n const markup = source.replace(SCRIPT_BLOCK_RE, \"\").replace(STYLE_BLOCK_RE, \"\")\n const names: string[] = []\n let depth = 0\n\n for (const [, closing, tag, attrs] of markup.matchAll(TAG_RE)) {\n if (closing) {\n depth = Math.max(0, depth - 1)\n continue\n }\n const selfClosing = /\\/\\s*$/.test(attrs) || VOID_ELEMENTS.has(tag.toLowerCase())\n if (depth === 0 && !selfClosing && tag.toLowerCase() === \"template\") {\n const declared = attrs.match(NAME_ATTR_RE)\n const name = declared?.[1] ?? declared?.[2]\n // the runtime warns about the ones this skips (nameless, not PascalCase)\n if (name && COMPONENT_NAME_RE.test(name)) names.push(name)\n }\n if (!selfClosing) depth++\n }\n return names\n}\n\n// a <style> block with its attribute string, so `lang` can be read and the\n// content replaced. Attribute values are matched as quoted chunks so a \">\"\n// inside one doesn't end the tag early\nconst STYLE_BLOCK_RE = /<style((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/style\\s*>/gi\nconst LANG_ATTR_RE = /\\blang\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\nconst TYPE_ATTR_RE = /\\btype\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\n\n// one attribute's value out of a tag's attribute string, whichever way it was\n// quoted - null when the attribute isn't there at all\nconst attrValue = (attrs: string, re: RegExp): string | null => {\n const found = attrs.match(re)\n return found ? found[1] ?? found[2] ?? found[3] : null\n}\n\n// compiles <style lang=\"scss|less|styl|sass\"> blocks to plain CSS with Vite's\n// own preprocessing (the same call @vitejs/plugin-vue makes), so the runtime\n// only ever sees CSS. The preprocessor picks its parser from the extension,\n// and resolving relative @use/@import against a filename in the component's\n// own directory is what makes `@use \"./vars\"` work. Files the preprocessor\n// pulls in are registered as watch deps, so editing a partial re-runs HMR for\n// every component that uses it. `lang` is dropped from the emitted tag: what\n// the runtime parses is a plain <style> (with `scoped` and the rest intact)\nconst compileStyleBlocks = async (\n source: string,\n file: string,\n config: ResolvedConfig,\n addWatchFile: (id: string) => void\n): Promise<string> => {\n const blocks = [...source.matchAll(STYLE_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const extension = attrValue(attrs, LANG_ATTR_RE)\n if (extension === null) return null\n const result = await preprocessCSS(content, `${file}.${extension}`, config)\n result.deps?.forEach(addWatchFile)\n return { attrs: attrs.replace(LANG_ATTR_RE, \"\").trimEnd(), css: result.code }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<style${done.attrs}>${done.css}</style>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// languages a <script lang> is compiled from. Anything else is left as written\n// for the runtime to warn about, rather than guessed at\nconst TS_LANGS = new Set([\"ts\", \"typescript\"])\n// the other spelling of the same mark, and the one editors read: a component is\n// a plain .html file, not an SFC, so nothing in an IDE knows what `lang` means\n// there - embedded-script tooling picks a language from `type`, and a typed\n// block without one is linted as JavaScript. The `x-` forms are the historical\n// spelling of the same two media types\nconst TS_TYPE_RE = /^(?:text|application)\\/(?:x-)?typescript$/\n\n// what marks a script block as TypeScript, given back as the attribute to drop\n// from the emitted tag - the block is compiled to JS, so the mark goes with the\n// types whichever one carried it. A `lang` answers on its own: `lang=\"coffee\"`\n// is a language this plugin doesn't compile, and reading `type` past it would\n// compile a block the author said was something else\nconst typescriptAttr = (attrs: string): RegExp | null => {\n const lang = attrValue(attrs, LANG_ATTR_RE)\n if (lang !== null) return TS_LANGS.has(lang.trim().toLowerCase()) ? LANG_ATTR_RE : null\n const type = attrValue(attrs, TYPE_ATTR_RE)\n return type !== null && TS_TYPE_RE.test(type.trim().toLowerCase()) ? TYPE_ATTR_RE : null\n}\n\ntype ViteTransform = (code: string, id: string, options?: unknown) => Promise<{ code: string }>\n\n// what strips the types: vite's own transform, so the plugin carries no\n// compiler of its own. *Which* transform is a version question, and neither\n// answer covers the peer range (vite >= 5) alone - transformWithOxc is the one\n// vite is moving to but only exists from vite 7, while transformWithEsbuild is\n// deprecated under vite 8 and throws there unless esbuild is installed\n// separately. So it is looked up at call time: oxc where it exists, esbuild on\n// the older versions that ship it.\n//\n// Both drop unused value imports by default, because a TS transform can't tell\n// a type-only import from an unused one. That would be silent damage here: a\n// factory script's `import Row from \"./row.html\"` would vanish, taking with it\n// the specifier hoistableImports needs to pull the child into the bundle. The\n// flags below are what keep it - only `import type` is erased\nconst stripTypes = async (ts: string, file: string): Promise<string> => {\n const vite = (await import(\"vite\")) as unknown as { transformWithOxc?: ViteTransform }\n const { code } = vite.transformWithOxc\n ? await vite.transformWithOxc(ts, file, { lang: \"ts\", typescript: { onlyRemoveTypeImports: true } })\n : await transformWithEsbuild(ts, file, {\n loader: \"ts\",\n tsconfigRaw: { compilerOptions: { verbatimModuleSyntax: true } },\n })\n // a script whose only imports were `import type` comes back marked as a\n // module. `export {}` exports nothing, and it is a SyntaxError inside the\n // Function body the runtime compiles a script into\n return code.replace(/^[ \\t]*export\\s*\\{\\s*\\}\\s*;?[ \\t]*$/m, \"\")\n}\n\n// the `:setup` attribute, when it carries a value (a bare `:setup` is the\n// closed signature and can't be typed)\nconst SETUP_ATTR_RE = /(:setup\\s*=\\s*)(?:\"([^\"]*)\"|'([^']*)')/i\n// the arrow body the signature is wrapped in, so the parameter list can be\n// found again in the output without matching brackets\nconst SIGNATURE_MARKER = \"__jq79_signature__\"\n\n// a component's props signature lives in the `:setup` *attribute*, not in the\n// script body, so the body's transform never sees it - and the TypeScript mark\n// has to mean the same thing on both halves of the block, or a typed signature\n// either survives into a component the plugin just promised was JS or, for\n// `_: Props`, stops reading as a signature at all.\n//\n// It goes through the same transform as everything else, wrapped as a\n// parameter list, rather than being cut with a scanner of its own: the\n// annotation can sit on the pattern (`{ a }: Props`), on the permissive `_`, or\n// inside a default (`{ step = 1 as number }`, which the runtime would evaluate\n// and silently drop), and telling those apart is a parser's job. Both transforms\n// hand back `(<params>) => <marker>` on one line, parens intact\nconst stripSignatureTypes = async (value: string, file: string): Promise<string> => {\n const compiled = await stripTypes(`(${value}) => ${SIGNATURE_MARKER}`, file)\n const marker = compiled.indexOf(SIGNATURE_MARKER)\n if (marker === -1) return value // not the shape expected: leave it as written\n const head = compiled.slice(0, marker).trimEnd()\n const params = (head.endsWith(\"=>\") ? head.slice(0, -2) : head).trim()\n return params.startsWith(\"(\") && params.endsWith(\")\") ? params.slice(1, -1).trim() : params\n}\n\n// the signature back into a double-quoted attribute. Only `\"` needs escaping:\n// the transforms normalize string literals to double quotes, so a default the\n// author wrote as `'x'` comes back as `\"x\"` and would end the attribute early.\n// `&` is deliberately left alone - `&&` in a default is not an entity and\n// survives the parse, while escaping it would double-encode a source that\n// already wrote `"`\nconst quoteAttrValue = (value: string) => value.replace(/\"/g, \""\")\n\n// compiles TypeScript script blocks to plain JS, so the runtime only ever sees\n// JS - the same deal <style lang=\"scss\"> gets, for a sharper reason. The setup\n// scanner is not a parser: `let count: number = 0` reaching it is not a syntax\n// error but a labeled statement that assigns to `number`, so it runs and leaves\n// `count` undeclared. Whichever attribute marked the block (`lang=\"ts\"` or\n// `type=\"text/typescript\"`) is dropped from the emitted tag and every other one\n// (`:setup`, `:mounted`) is left as written.\n//\n// This runs before hoistableImports reads the source, so an `import type`\n// specifier is already gone by the time the plugin decides what to bundle\nconst compileScriptBlocks = async (source: string, file: string): Promise<string> => {\n const blocks = [...source.matchAll(SCRIPT_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const marker = typescriptAttr(attrs)\n if (!marker) return null\n\n let rest = attrs.replace(marker, \"\").trimEnd()\n const setup = rest.match(SETUP_ATTR_RE)\n if (setup) {\n const signature = await stripSignatureTypes(setup[2] ?? setup[3], `${file}.signature.ts`)\n // a function replacement, not a string: `$&` and friends are live in a\n // replacement string and a default value is arbitrary source\n rest = rest.replace(SETUP_ATTR_RE, () => `${setup[1]}\"${quoteAttrValue(signature)}\"`)\n }\n\n return { attrs: rest, js: await stripTypes(content, `${file}.ts`) }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<script${done.attrs}>${done.js}</script>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// the emitted module. Literal import(\"...\") specifiers found in the\n// component's scripts become real module imports, handed to Component79 as a\n// resolution map: at runtime $__import checks the map before falling back to\n// fetch, so bundled components ship with their imports and nothing changes\n// for unbundled ones. Claimed components import as their default (a\n// Component79, matching what runtime fetch resolves to); everything else as\n// a namespace (matching native import()).\n//\n// A file's <template name=\"…\"> components are re-exported by name, so the\n// module shape is the one the file already has: default plus named. They read\n// off the instance, which is where the runtime hangs them - so in dev they are\n// bound to the *first* evaluation's definitions and a module that imports one\n// by name keeps the pre-edit child until the page reloads. The file's own\n// component patches in place, and its rendered children come from the reparse,\n// so this only shows in a component imported by name from another file.\n//\n// In dev, `hot.data` carries the exported instance across updates: importers\n// hold a reference to the *first* module evaluation's instance, so later\n// evaluations patch that same instance in place instead of exporting a new one\n// nobody sees. The patching itself is the runtime's `hotReplace` - the same\n// swap the jq79/dev server drives, from the one place that can reach a\n// component's markers. An instance only used as a definition has nothing to\n// re-render (nested clones can't be reached from this module), so it falls\n// back to a full reload.\nconst componentModule = (source: string, include: RegExp, filename: string): string => {\n const hoisted = hoistableImports(source, include)\n const imports = hoisted\n .map((spec, i) =>\n include.test(spec)\n ? `import __jq79_${i} from ${JSON.stringify(spec)}`\n : `import * as __jq79_${i} from ${JSON.stringify(spec)}`\n )\n .join(\"\\n\")\n const modulesMap = `{ ${hoisted.map((spec, i) => `${JSON.stringify(spec)}: __jq79_${i}`).join(\", \")} }`\n\n return `\nimport { Component79 } from \"jq79\"\n${imports}\n\nconst src = ${JSON.stringify(source)}\nconst modules = ${modulesMap}\nconst filename = ${JSON.stringify(filename)}\n\nlet component\n\nif (import.meta.hot && import.meta.hot.data.component) {\n const prior = import.meta.hot.data.component\n prior.modules = modules\n prior.filename = filename\n // re-renders it where it stands, keeping its data. false means it was never\n // rendered - a definition used only as a nested component - and a reload is\n // the only way to reach the clones made from it\n if (!prior.hotReplace(src) && !prior.data) import.meta.hot.invalidate()\n component = prior\n} else {\n component = new Component79(src, { modules, filename })\n}\n\nif (import.meta.hot) {\n import.meta.hot.data.component = component\n import.meta.hot.accept()\n}\n\nexport default component\n${declaredComponents(source).map(name => `export const ${name} = component.${name}`).join(\"\\n\")}\n`\n}\n\nexport function jq79(options: Jq79PluginOptions = {}): Plugin {\n const include = options.include ?? /\\.html$/\n const { exclude } = options\n\n let config: ResolvedConfig | null = null\n\n return {\n name: \"jq79\",\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved\n },\n\n async resolveId(source, importer) {\n if (!importer) return null // entry points are never components\n if (source.includes(\"?\")) return null // ?raw, ?url, ... keep their meaning\n if (!include.test(source)) return null\n\n const resolved = await this.resolve(source, importer, { skipSelf: true })\n if (!resolved || resolved.external) return null\n if (exclude?.test(resolved.id)) return null\n return resolved.id + COMPONENT_QUERY\n },\n\n async load(id) {\n if (!id.endsWith(COMPONENT_QUERY)) return null\n const file = id.slice(0, -COMPONENT_QUERY.length)\n\n let source = await readFile(file, \"utf8\")\n source = await compileScriptBlocks(source, file)\n if (config) source = await compileStyleBlocks(source, file, config, dep => this.addWatchFile(dep))\n\n // the runtime names the component's setup scripts after this, so devtools\n // shows a path the user recognizes instead of an anonymous VM script\n const filename = config ? relative(config.root, file) : file\n\n return { code: componentModule(source, include, filename), map: null }\n },\n }\n}\n\nexport default jq79\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AACzB,uBAAyB;AACzB,kBAAoD;AAgCpD,IAAM,kBAAkB;AAKxB,IAAM,kBAAkB;AAGxB,IAAM,iBAAiB;AAIvB,IAAM,mBAAmB;AAEzB,IAAM,aAAa,CAAC,KAAa,UAA0B;AACzD,QAAM,QAAQ,IAAI,KAAK;AACvB,MAAI,IAAI,QAAQ;AAChB,SAAO,IAAI,IAAI,QAAQ;AACrB,QAAI,IAAI,CAAC,MAAM,MAAM;AAAE,WAAK;AAAG;AAAA,IAAS;AACxC,QAAI,IAAI,CAAC,MAAM,MAAO,QAAO,IAAI;AACjC;AAAA,EACF;AACA,SAAO,IAAI;AACb;AAMA,IAAM,mBAAmB,CAAC,WAA6B;AACrD,QAAM,QAAkB,CAAC;AACzB,MAAI,IAAI;AACR,SAAO,IAAI,OAAO,QAAQ;AACxB,UAAM,KAAK,OAAO,CAAC;AACnB,QAAI,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAAE,UAAI,WAAW,QAAQ,CAAC;AAAG;AAAA,IAAS;AAClF,QAAI,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK;AACvC,YAAM,MAAM,OAAO,QAAQ,MAAM,CAAC;AAClC,UAAI,QAAQ,KAAK,OAAO,SAAS,MAAM;AACvC;AAAA,IACF;AACA,QAAI,OAAO,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK;AACvC,YAAM,MAAM,OAAO,QAAQ,MAAM,IAAI,CAAC;AACtC,UAAI,QAAQ,KAAK,OAAO,SAAS,MAAM;AACvC;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI;AAC5D,qBAAe,YAAY;AAC3B,YAAM,OAAO,eAAe,KAAK,MAAM;AACvC,UAAI,MAAM;AAAE,cAAM,KAAK,KAAK,CAAC,CAAC;AAAG,YAAI,eAAe;AAAW;AAAA,MAAS;AACxE,uBAAiB,YAAY;AAC7B,YAAM,eAAe,iBAAiB,KAAK,MAAM;AACjD,UAAI,cAAc;AAAE,cAAM,KAAK,aAAa,CAAC,CAAC;AAAG,YAAI,iBAAiB;AAAW;AAAA,MAAS;AAAA,IAC5F;AACA;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,YAAY,CAAC,SAAiB,kBAAkB,KAAK,IAAI;AAC/D,IAAM,gBAAgB,CAAC,SAAiB,uBAAuB,KAAK,IAAI,KAAK,KAAK,WAAW,GAAG;AAOhG,IAAM,mBAAmB,CAAC,QAAgB,YAA8B;AACtE,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,SAAS,eAAe,GAAG;AAC3D,eAAW,QAAQ,iBAAiB,MAAM,GAAG;AAC3C,UAAI,cAAc,IAAI,EAAG;AACzB,UAAI,UAAU,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAG;AAC5C,iBAAW,IAAI,IAAI;AAAA,IACrB;AAAA,EACF;AACA,SAAO,CAAC,GAAG,UAAU;AACvB;AAIA,IAAM,SAAS;AACf,IAAM,eAAe;AACrB,IAAM,oBAAoB;AAC1B,IAAM,gBAAgB,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAM;AAAA,EAAO;AAAA,EAAS;AAAA,EAAM;AAAA,EAAO;AAAA,EACnD;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAU;AAAA,EAAS;AAC9C,CAAC;AAQD,IAAM,qBAAqB,CAAC,WAA6B;AACvD,QAAM,SAAS,OAAO,QAAQ,iBAAiB,EAAE,EAAE,QAAQ,gBAAgB,EAAE;AAC7E,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAQ;AAEZ,aAAW,CAAC,EAAE,SAAS,KAAK,KAAK,KAAK,OAAO,SAAS,MAAM,GAAG;AAC7D,QAAI,SAAS;AACX,cAAQ,KAAK,IAAI,GAAG,QAAQ,CAAC;AAC7B;AAAA,IACF;AACA,UAAM,cAAc,SAAS,KAAK,KAAK,KAAK,cAAc,IAAI,IAAI,YAAY,CAAC;AAC/E,QAAI,UAAU,KAAK,CAAC,eAAe,IAAI,YAAY,MAAM,YAAY;AACnE,YAAM,WAAW,MAAM,MAAM,YAAY;AACzC,YAAM,OAAO,WAAW,CAAC,KAAK,WAAW,CAAC;AAE1C,UAAI,QAAQ,kBAAkB,KAAK,IAAI,EAAG,OAAM,KAAK,IAAI;AAAA,IAC3D;AACA,QAAI,CAAC,YAAa;AAAA,EACpB;AACA,SAAO;AACT;AAKA,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,eAAe;AAIrB,IAAM,YAAY,CAAC,OAAe,OAA8B;AAC9D,QAAM,QAAQ,MAAM,MAAM,EAAE;AAC5B,SAAO,QAAQ,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI;AACpD;AAUA,IAAM,qBAAqB,OACzB,QACA,MACA,QACA,iBACoB;AACpB,QAAM,SAAS,CAAC,GAAG,OAAO,SAAS,cAAc,CAAC;AAClD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,OAAO,IAAI,OAAO,CAAC,EAAE,OAAO,OAAO,MAAM;AACvC,YAAM,YAAY,UAAU,OAAO,YAAY;AAC/C,UAAI,cAAc,KAAM,QAAO;AAC/B,YAAM,SAAS,UAAM,2BAAc,SAAS,GAAG,IAAI,IAAI,SAAS,IAAI,MAAM;AAC1E,aAAO,MAAM,QAAQ,YAAY;AACjC,aAAO,EAAE,OAAO,MAAM,QAAQ,cAAc,EAAE,EAAE,QAAQ,GAAG,KAAK,OAAO,KAAK;AAAA,IAC9E,CAAC;AAAA,EACH;AAEA,MAAI,MAAM;AACV,MAAI,OAAO;AACX,SAAO,QAAQ,CAAC,OAAO,MAAM;AAC3B,UAAM,OAAO,SAAS,CAAC;AACvB,QAAI,CAAC,KAAM;AACX,WAAO,OAAO,MAAM,MAAM,MAAM,KAAK,IAAI,SAAS,KAAK,KAAK,IAAI,KAAK,GAAG;AACxE,WAAO,MAAM,QAAQ,MAAM,CAAC,EAAE;AAAA,EAChC,CAAC;AACD,SAAO,MAAM,OAAO,MAAM,IAAI;AAChC;AAIA,IAAM,WAAW,oBAAI,IAAI,CAAC,MAAM,YAAY,CAAC;AAM7C,IAAM,aAAa;AAOnB,IAAM,iBAAiB,CAAC,UAAiC;AACvD,QAAM,OAAO,UAAU,OAAO,YAAY;AAC1C,MAAI,SAAS,KAAM,QAAO,SAAS,IAAI,KAAK,KAAK,EAAE,YAAY,CAAC,IAAI,eAAe;AACnF,QAAM,OAAO,UAAU,OAAO,YAAY;AAC1C,SAAO,SAAS,QAAQ,WAAW,KAAK,KAAK,KAAK,EAAE,YAAY,CAAC,IAAI,eAAe;AACtF;AAiBA,IAAM,aAAa,OAAO,IAAY,SAAkC;AACtE,QAAM,OAAQ,MAAM,OAAO,MAAM;AACjC,QAAM,EAAE,KAAK,IAAI,KAAK,mBAClB,MAAM,KAAK,iBAAiB,IAAI,MAAM,EAAE,MAAM,MAAM,YAAY,EAAE,uBAAuB,KAAK,EAAE,CAAC,IACjG,UAAM,kCAAqB,IAAI,MAAM;AAAA,IACrC,QAAQ;AAAA,IACR,aAAa,EAAE,iBAAiB,EAAE,sBAAsB,KAAK,EAAE;AAAA,EACjE,CAAC;AAIH,SAAO,KAAK,QAAQ,wCAAwC,EAAE;AAChE;AAIA,IAAM,gBAAgB;AAGtB,IAAM,mBAAmB;AAczB,IAAM,sBAAsB,OAAO,OAAe,SAAkC;AAClF,QAAM,WAAW,MAAM,WAAW,IAAI,KAAK,QAAQ,gBAAgB,IAAI,IAAI;AAC3E,QAAM,SAAS,SAAS,QAAQ,gBAAgB;AAChD,MAAI,WAAW,GAAI,QAAO;AAC1B,QAAM,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,QAAQ;AAC/C,QAAM,UAAU,KAAK,SAAS,IAAI,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM,KAAK;AACrE,SAAO,OAAO,WAAW,GAAG,KAAK,OAAO,SAAS,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI;AACvF;AAQA,IAAM,iBAAiB,CAAC,UAAkB,MAAM,QAAQ,MAAM,QAAQ;AAYtE,IAAM,sBAAsB,OAAO,QAAgB,SAAkC;AACnF,QAAM,SAAS,CAAC,GAAG,OAAO,SAAS,eAAe,CAAC;AACnD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,OAAO,IAAI,OAAO,CAAC,EAAE,OAAO,OAAO,MAAM;AACvC,YAAM,SAAS,eAAe,KAAK;AACnC,UAAI,CAAC,OAAQ,QAAO;AAEpB,UAAI,OAAO,MAAM,QAAQ,QAAQ,EAAE,EAAE,QAAQ;AAC7C,YAAM,QAAQ,KAAK,MAAM,aAAa;AACtC,UAAI,OAAO;AACT,cAAM,YAAY,MAAM,oBAAoB,MAAM,CAAC,KAAK,MAAM,CAAC,GAAG,GAAG,IAAI,eAAe;AAGxF,eAAO,KAAK,QAAQ,eAAe,MAAM,GAAG,MAAM,CAAC,CAAC,IAAI,eAAe,SAAS,CAAC,GAAG;AAAA,MACtF;AAEA,aAAO,EAAE,OAAO,MAAM,IAAI,MAAM,WAAW,SAAS,GAAG,IAAI,KAAK,EAAE;AAAA,IACpE,CAAC;AAAA,EACH;AAEA,MAAI,MAAM;AACV,MAAI,OAAO;AACX,SAAO,QAAQ,CAAC,OAAO,MAAM;AAC3B,UAAM,OAAO,SAAS,CAAC;AACvB,QAAI,CAAC,KAAM;AACX,WAAO,OAAO,MAAM,MAAM,MAAM,KAAK,IAAI,UAAU,KAAK,KAAK,IAAI,KAAK,EAAE;AACxE,WAAO,MAAM,QAAQ,MAAM,CAAC,EAAE;AAAA,EAChC,CAAC;AACD,SAAO,MAAM,OAAO,MAAM,IAAI;AAChC;AA0BA,IAAM,kBAAkB,CAAC,QAAgB,SAAiB,aAA6B;AACrF,QAAM,UAAU,iBAAiB,QAAQ,OAAO;AAChD,QAAM,UAAU,QACb;AAAA,IAAI,CAAC,MAAM,MACV,QAAQ,KAAK,IAAI,IACb,iBAAiB,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC,KAC/C,sBAAsB,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC;AAAA,EAC1D,EACC,KAAK,IAAI;AACZ,QAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,MAAM,GAAG,KAAK,UAAU,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;AAEnG,SAAO;AAAA;AAAA,EAEP,OAAO;AAAA;AAAA,cAEK,KAAK,UAAU,MAAM,CAAC;AAAA,kBAClB,UAAU;AAAA,mBACT,KAAK,UAAU,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuBzC,mBAAmB,MAAM,EAAE,IAAI,UAAQ,gBAAgB,IAAI,gBAAgB,IAAI,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA;AAE/F;AAEO,SAAS,KAAK,UAA6B,CAAC,GAAW;AAC5D,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,EAAE,QAAQ,IAAI;AAEpB,MAAI,SAAgC;AAEpC,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IAET,eAAe,UAAU;AACvB,eAAS;AAAA,IACX;AAAA,IAEA,MAAM,UAAU,QAAQ,UAAU;AAChC,UAAI,CAAC,SAAU,QAAO;AACtB,UAAI,OAAO,SAAS,GAAG,EAAG,QAAO;AACjC,UAAI,CAAC,QAAQ,KAAK,MAAM,EAAG,QAAO;AAElC,YAAM,WAAW,MAAM,KAAK,QAAQ,QAAQ,UAAU,EAAE,UAAU,KAAK,CAAC;AACxE,UAAI,CAAC,YAAY,SAAS,SAAU,QAAO;AAC3C,UAAI,SAAS,KAAK,SAAS,EAAE,EAAG,QAAO;AACvC,aAAO,SAAS,KAAK;AAAA,IACvB;AAAA,IAEA,MAAM,KAAK,IAAI;AACb,UAAI,CAAC,GAAG,SAAS,eAAe,EAAG,QAAO;AAC1C,YAAM,OAAO,GAAG,MAAM,GAAG,CAAC,gBAAgB,MAAM;AAEhD,UAAI,SAAS,UAAM,0BAAS,MAAM,MAAM;AACxC,eAAS,MAAM,oBAAoB,QAAQ,IAAI;AAC/C,UAAI,OAAQ,UAAS,MAAM,mBAAmB,QAAQ,MAAM,QAAQ,SAAO,KAAK,aAAa,GAAG,CAAC;AAIjG,YAAM,WAAW,aAAS,2BAAS,OAAO,MAAM,IAAI,IAAI;AAExD,aAAO,EAAE,MAAM,gBAAgB,QAAQ,SAAS,QAAQ,GAAG,KAAK,KAAK;AAAA,IACvE;AAAA,EACF;AACF;AAEA,IAAO,eAAQ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../dev/vite.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\"\nimport { basename, relative } from \"node:path\"\nimport { preprocessCSS, transformWithEsbuild } from \"vite\"\nimport type { Plugin, ResolvedConfig } from \"vite\"\n// by package name rather than ../src: this file's types are emitted with dev/\n// as their root, and the generator is the runtime's own code - resolved through\n// the package's exports (external in the build, aliased to src in the tests)\nimport { precompile, precompiledScript } from \"jq79/precompile\"\n\n// Vite plugin: import .html single-file components as modules.\n//\n// import { jq79 } from \"jq79/vite\" // vite.config\n// import UserCard from \"./UserCard.html\" // app code\n//\n// The imported value is a Component79 built from the file's source - the same\n// thing `await Component79.fetch(url)` resolves to, but bundled at build time\n// instead of fetched at runtime. The component source is inlined verbatim, so\n// a file keeps working unchanged if it's ever served from public/ and loaded\n// with fetch instead - with one deliberate exception, a block that says it is\n// written in something else: <style lang=\"scss\"> (or less/stylus/sass) is\n// compiled to plain CSS here, and a TypeScript script - <script lang=\"ts\">, or\n// the same mark spelled <script type=\"text/typescript\"> - to plain JS. Such a\n// component only works through the bundler; loaded with fetch() it would reach\n// the runtime uncompiled, which the runtime warns about.\n//\n// Only .html files imported from other modules are claimed; entry points\n// (index.html) have no importer and imports carrying an explicit query\n// (?raw, ?url) keep their built-in Vite meaning.\n\nexport interface Jq79PluginOptions {\n // which import specifiers are treated as components (default: any .html)\n include?: RegExp\n // resolved absolute paths to skip even when `include` matches\n exclude?: RegExp\n // run the app without eval, for a CSP with no 'unsafe-eval' - the value\n // Component79.safeEval() takes, and meaning the same thing\n // (RECORD/2026-09-23.no-unsafe-eval.md). Every component is precompiled, and\n // its functions ship as a script of their own. `true`: those and nothing\n // else - whatever the build couldn't see is reported, never evaluated.\n // `{ nonce: true }`: whatever it couldn't see (a component built from a\n // string, an edit during HMR) is built as a <script> carrying the page's nonce\n safeEval?: boolean | { nonce?: boolean }\n}\n\n// claimed modules get this suffix so their id no longer ends in \".html\" and\n// Vite's own html handling (entries, asset pipeline) leaves them alone\nconst COMPONENT_QUERY = \"?jq79\"\n\n// safeEval. A component's precompiled functions travel as a classic script of\n// their own - Card.html.jq79.js - and not inside its module: they compile\n// under `with`, which is a SyntaxError in strict code, and every module is\n// strict. In a build the script is an asset beside the chunk; in dev the\n// server hands it out (PRECOMPILED_PATH). Either way it pushes its functions\n// onto the queue the runtime drains (see \"safe eval\" in src/jq79.ts).\n//\n// The component's module waits for it - a top-level await - before it builds\n// anything, through a module every component module imports. That module\n// evaluates once, so safe mode is turned on once per app, and a page with no\n// nonce is reported once rather than once per component; and it loads each\n// script once, however many modules ask. The <script> carries the page's\n// nonce when there is one, so a CSP that works by nonce admits it; under\n// `script-src 'self'` the URL is what admits it.\n//\n// Component79 is passed in rather than imported, so the module resolves\n// nothing: a bare \"jq79\" from a virtual importer is the one resolution that\n// would depend on how the app is laid out.\n//\n// A component built from a string *before* any .html module is imported runs\n// in the default mode; such an app calls Component79.safeEval itself. The\n// await needs a build target with top-level await in it - Vite 7 and later\n// have one by default; on Vite 5 or 6, raise build.target to es2022\nconst SAFE_EVAL_ID = \"virtual:jq79/safe-eval\"\nconst RESOLVED_SAFE_EVAL_ID = `\\0${SAFE_EVAL_ID}`\nconst safeEvalModule = (options: { nonce?: boolean; worker: false }) => `\nlet started = null\nconst loading = new Map()\nconst pageNonce = () => {\n for (const script of document.querySelectorAll(\"script[nonce]\")) {\n const nonce = script.nonce || script.getAttribute(\"nonce\")\n if (nonce) return nonce\n }\n}\nexport const safeEval = (Component79, url) => {\n if (!started) started = Component79.safeEval(${JSON.stringify(options)}).catch(error => console.error(error))\n let loaded = loading.get(url)\n if (!loaded) {\n loaded = new Promise((resolve, reject) => {\n const script = document.createElement(\"script\")\n const nonce = pageNonce()\n if (nonce) script.setAttribute(\"nonce\", nonce)\n script.src = url\n script.onload = () => { script.remove(); resolve() }\n script.onerror = () => {\n script.remove()\n reject(new Error(\"jq79: the precompiled functions at \" + url + \" did not load, and safeEval can't render without them\"))\n }\n document.head.append(script)\n })\n loading.set(url, loaded)\n }\n return loaded\n}\n`\n\n// where the dev server hands out a component's precompiled script\nconst PRECOMPILED_PATH = \"/@jq79/precompiled.js\"\n\n// the plugin's safeEval option, as what the modules pass the runtime: null\n// for off, or Component79.safeEval's own options\nconst safeEvalOptions = (option: Jq79PluginOptions[\"safeEval\"]): { nonce?: boolean } | null => {\n if (option === undefined || option === false) return null\n return typeof option === \"object\" && option !== null && option.nonce === true ? { nonce: true } : {}\n}\n\n// a scoped-form body: the runtime falls back to the `with` form when one\n// doesn't compile, so only the `with` form's failure is worth a word\nconst SCOPED_BODY_RE = /^(?:let \\$t;| return \\()/\n\n// a component's precompiled functions, as the classic script that registers\n// them (precompiledScript, in jq79/precompile). Each is compiled here first -\n// node can, where the page may not - so the script holds only functions that\n// parse; one that doesn't ships as null, and the build says so\nconst componentScript = (source: string, warn: (message: string) => void): string =>\n precompiledScript(precompile(source), (params, body) => {\n try {\n new Function(...params, body)\n return true\n } catch (error) {\n if (!SCOPED_BODY_RE.test(body)) warn(`${(error as Error).message}, in: ${body.length > 120 ? `${body.slice(0, 120)}…` : body}`)\n return false\n }\n })\n\n// a <script> block with its attribute string, so `lang` can be read and the\n// body replaced - the same shape as STYLE_BLOCK_RE below, quote-aware so a\n// \">\" inside an attribute value (`:setup=\"{ n = a > 1 }\"`) doesn't end the tag\nconst SCRIPT_BLOCK_RE = /<script((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/script\\s*>/gi\n// import(\"...\") with a literal specifier, tried at word boundaries the\n// scanner below reaches (which is what skips $__import and foo.import(...))\nconst IMPORT_CALL_RE = /import\\s*\\(\\s*([\"'])([^\"'\\n]+?)\\1\\s*\\)/y\n// static import statements (factory scripts): optional clause + literal\n// specifier. The clause can't contain parens/quotes, so dynamic import()\n// and import.meta never match\nconst STATIC_IMPORT_RE = /import\\s*(?:[\\w$\\s,{}*]+?\\s*from\\s*)?([\"'])([^\"'\\n]+)\\1/y\n\nconst skipString = (src: string, start: number): number => {\n const quote = src[start]\n let i = start + 1\n while (i < src.length) {\n if (src[i] === \"\\\\\") { i += 2; continue }\n if (src[i] === quote) return i + 1\n i++\n }\n return src.length\n}\n\n// the literal import specifiers in one script body. A scanner rather than a\n// bare matchAll, because a specifier mentioned in a comment or a string is\n// not an import: hoisting a commented-out `import(\"./old.html\")` would pull\n// dead files into the bundle - or break the build once the file is gone\nconst importSpecifiers = (script: string): string[] => {\n const specs: string[] = []\n let i = 0\n while (i < script.length) {\n const ch = script[i]\n if (ch === \"'\" || ch === '\"' || ch === \"`\") { i = skipString(script, i); continue }\n if (ch === \"/\" && script[i + 1] === \"/\") {\n const end = script.indexOf(\"\\n\", i)\n i = end === -1 ? script.length : end + 1\n continue\n }\n if (ch === \"/\" && script[i + 1] === \"*\") {\n const end = script.indexOf(\"*/\", i + 2)\n i = end === -1 ? script.length : end + 2\n continue\n }\n if (ch === \"i\" && (i === 0 || !/[\\w$.]/.test(script[i - 1]))) {\n IMPORT_CALL_RE.lastIndex = i\n const call = IMPORT_CALL_RE.exec(script)\n if (call) { specs.push(call[2]); i = IMPORT_CALL_RE.lastIndex; continue }\n STATIC_IMPORT_RE.lastIndex = i\n const staticImport = STATIC_IMPORT_RE.exec(script)\n if (staticImport) { specs.push(staticImport[2]); i = STATIC_IMPORT_RE.lastIndex; continue }\n }\n i++\n }\n return specs\n}\n\nconst isHtmlUrl = (spec: string) => /\\.html?([?#]|$)/.test(spec)\nconst isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith(\"/\")\n\n// literal import specifiers in the component's script blocks - dynamic\n// `import(\"...\")` calls and static factory-script imports - that should\n// resolve from the bundle instead of at runtime. Absolute paths and full\n// URLs are left alone (they point at served files, e.g. public/), and so\n// are .html specifiers the plugin wouldn't claim as components\nconst hoistableImports = (source: string, include: RegExp): string[] => {\n const specifiers = new Set<string>()\n for (const [, , script] of source.matchAll(SCRIPT_BLOCK_RE)) {\n for (const spec of importSpecifiers(script)) {\n if (isExternalUrl(spec)) continue\n if (isHtmlUrl(spec) && !include.test(spec)) continue // html left to runtime fetch\n specifiers.add(spec) // a claimed component, a source file or an npm package\n }\n }\n return [...specifiers]\n}\n\n// any start or end tag, quote-aware so a \">\" inside an attribute value doesn't\n// end it early\nconst TAG_RE = /<(\\/?)([A-Za-z][\\w-]*)((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>/g\nconst NAME_ATTR_RE = /\\bname\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i\nconst COMPONENT_NAME_RE = /^[A-Z][A-Za-z0-9]*$/\nconst VOID_ELEMENTS = new Set([\n \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\",\n \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\",\n])\n\n// the components a file declares: its *top-level* <template name=\"…\"> blocks,\n// which the emitted module re-exports by name. Depth is tracked because only\n// the top level declares - a <template> nested in the markup is a plain inert\n// element the runtime leaves alone, and exporting it would name something that\n// never exists. Script and style bodies are cut out first, so a \"<\" in JS or a\n// selector can't be read as a tag\nconst declaredComponents = (source: string): string[] => {\n const markup = source.replace(SCRIPT_BLOCK_RE, \"\").replace(STYLE_BLOCK_RE, \"\")\n const names: string[] = []\n let depth = 0\n\n for (const [, closing, tag, attrs] of markup.matchAll(TAG_RE)) {\n if (closing) {\n depth = Math.max(0, depth - 1)\n continue\n }\n const selfClosing = /\\/\\s*$/.test(attrs) || VOID_ELEMENTS.has(tag.toLowerCase())\n if (depth === 0 && !selfClosing && tag.toLowerCase() === \"template\") {\n const declared = attrs.match(NAME_ATTR_RE)\n const name = declared?.[1] ?? declared?.[2]\n // the runtime warns about the ones this skips (nameless, not PascalCase)\n if (name && COMPONENT_NAME_RE.test(name)) names.push(name)\n }\n if (!selfClosing) depth++\n }\n return names\n}\n\n// a <style> block with its attribute string, so `lang` can be read and the\n// content replaced. Attribute values are matched as quoted chunks so a \">\"\n// inside one doesn't end the tag early\nconst STYLE_BLOCK_RE = /<style((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/style\\s*>/gi\nconst LANG_ATTR_RE = /\\blang\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\nconst TYPE_ATTR_RE = /\\btype\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\n\n// one attribute's value out of a tag's attribute string, whichever way it was\n// quoted - null when the attribute isn't there at all\nconst attrValue = (attrs: string, re: RegExp): string | null => {\n const found = attrs.match(re)\n return found ? found[1] ?? found[2] ?? found[3] : null\n}\n\n// compiles <style lang=\"scss|less|styl|sass\"> blocks to plain CSS with Vite's\n// own preprocessing (the same call @vitejs/plugin-vue makes), so the runtime\n// only ever sees CSS. The preprocessor picks its parser from the extension,\n// and resolving relative @use/@import against a filename in the component's\n// own directory is what makes `@use \"./vars\"` work. Files the preprocessor\n// pulls in are registered as watch deps, so editing a partial re-runs HMR for\n// every component that uses it. `lang` is dropped from the emitted tag: what\n// the runtime parses is a plain <style> (with `scoped` and the rest intact)\nconst compileStyleBlocks = async (\n source: string,\n file: string,\n config: ResolvedConfig,\n addWatchFile: (id: string) => void\n): Promise<string> => {\n const blocks = [...source.matchAll(STYLE_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const extension = attrValue(attrs, LANG_ATTR_RE)\n if (extension === null) return null\n const result = await preprocessCSS(content, `${file}.${extension}`, config)\n result.deps?.forEach(addWatchFile)\n return { attrs: attrs.replace(LANG_ATTR_RE, \"\").trimEnd(), css: result.code }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<style${done.attrs}>${done.css}</style>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// languages a <script lang> is compiled from. Anything else is left as written\n// for the runtime to warn about, rather than guessed at\nconst TS_LANGS = new Set([\"ts\", \"typescript\"])\n// the other spelling of the same mark. A component is a plain .html file, not\n// an SFC, so nothing in an editor knows what `lang` means there, and each mark\n// gets half of one: VS Code's HTML language service checks a `type` of\n// text/typescript as TypeScript (and `lang=\"ts\"` as JavaScript), while its\n// grammar colors that `type` not at all (and `lang=\"ts\"` as JavaScript). See\n// docs/vite-plugin.md#which-mark-in-vs-code. The `x-` forms are the historical\n// spelling of the same two media types\nconst TS_TYPE_RE = /^(?:text|application)\\/(?:x-)?typescript$/\n\n// what marks a script block as TypeScript, given back as the attribute to drop\n// from the emitted tag - the block is compiled to JS, so the mark goes with the\n// types whichever one carried it. A `lang` answers on its own: `lang=\"coffee\"`\n// is a language this plugin doesn't compile, and reading `type` past it would\n// compile a block the author said was something else\nconst typescriptAttr = (attrs: string): RegExp | null => {\n const lang = attrValue(attrs, LANG_ATTR_RE)\n if (lang !== null) return TS_LANGS.has(lang.trim().toLowerCase()) ? LANG_ATTR_RE : null\n const type = attrValue(attrs, TYPE_ATTR_RE)\n return type !== null && TS_TYPE_RE.test(type.trim().toLowerCase()) ? TYPE_ATTR_RE : null\n}\n\ntype ViteTransform = (code: string, id: string, options?: unknown) => Promise<{ code: string }>\n\n// what strips the types: vite's own transform, so the plugin carries no\n// compiler of its own. *Which* transform is a version question, and neither\n// answer covers the peer range (vite >= 5) alone - transformWithOxc is the one\n// vite is moving to but only exists from vite 7, while transformWithEsbuild is\n// deprecated under vite 8 and throws there unless esbuild is installed\n// separately. So it is looked up at call time: oxc where it exists, esbuild on\n// the older versions that ship it.\n//\n// Both drop unused value imports by default, because a TS transform can't tell\n// a type-only import from an unused one. That would be silent damage here: a\n// factory script's `import Row from \"./row.html\"` would vanish, taking with it\n// the specifier hoistableImports needs to pull the child into the bundle. The\n// flags below are what keep it - only `import type` is erased\nconst stripTypes = async (ts: string, file: string): Promise<string> => {\n const vite = (await import(\"vite\")) as unknown as { transformWithOxc?: ViteTransform }\n const { code } = vite.transformWithOxc\n ? await vite.transformWithOxc(ts, file, { lang: \"ts\", typescript: { onlyRemoveTypeImports: true } })\n : await transformWithEsbuild(ts, file, {\n loader: \"ts\",\n tsconfigRaw: { compilerOptions: { verbatimModuleSyntax: true } },\n })\n // a script whose only imports were `import type` comes back marked as a\n // module. `export {}` exports nothing, and it is a SyntaxError inside the\n // Function body the runtime compiles a script into\n return code.replace(/^[ \\t]*export\\s*\\{\\s*\\}\\s*;?[ \\t]*$/m, \"\")\n}\n\n// the `:setup` attribute, when it carries a value (a bare `:setup` is the\n// closed signature and can't be typed)\nconst SETUP_ATTR_RE = /(:setup\\s*=\\s*)(?:\"([^\"]*)\"|'([^']*)')/i\n// the arrow body the signature is wrapped in, so the parameter list can be\n// found again in the output without matching brackets\nconst SIGNATURE_MARKER = \"__jq79_signature__\"\n\n// a component's props signature lives in the `:setup` *attribute*, not in the\n// script body, so the body's transform never sees it - and the TypeScript mark\n// has to mean the same thing on both halves of the block, or a typed signature\n// either survives into a component the plugin just promised was JS or, for\n// `_: Props`, stops reading as a signature at all.\n//\n// It goes through the same transform as everything else, wrapped as a\n// parameter list, rather than being cut with a scanner of its own: the\n// annotation can sit on the pattern (`{ a }: Props`), on the permissive `_`, or\n// inside a default (`{ step = 1 as number }`, which the runtime would evaluate\n// and silently drop), and telling those apart is a parser's job. Both transforms\n// hand back `(<params>) => <marker>` on one line, parens intact\nconst stripSignatureTypes = async (value: string, file: string): Promise<string> => {\n const compiled = await stripTypes(`(${value}) => ${SIGNATURE_MARKER}`, file)\n const marker = compiled.indexOf(SIGNATURE_MARKER)\n if (marker === -1) return value // not the shape expected: leave it as written\n const head = compiled.slice(0, marker).trimEnd()\n const params = (head.endsWith(\"=>\") ? head.slice(0, -2) : head).trim()\n return params.startsWith(\"(\") && params.endsWith(\")\") ? params.slice(1, -1).trim() : params\n}\n\n// the signature back into a double-quoted attribute. Only `\"` needs escaping:\n// the transforms normalize string literals to double quotes, so a default the\n// author wrote as `'x'` comes back as `\"x\"` and would end the attribute early.\n// `&` is deliberately left alone - `&&` in a default is not an entity and\n// survives the parse, while escaping it would double-encode a source that\n// already wrote `"`\nconst quoteAttrValue = (value: string) => value.replace(/\"/g, \""\")\n\n// compiles TypeScript script blocks to plain JS, so the runtime only ever sees\n// JS - the same deal <style lang=\"scss\"> gets, for a sharper reason. The setup\n// scanner is not a parser: `let count: number = 0` reaching it is not a syntax\n// error but a labeled statement that assigns to `number`, so it runs and leaves\n// `count` undeclared. Whichever attribute marked the block (`lang=\"ts\"` or\n// `type=\"text/typescript\"`) is dropped from the emitted tag and every other one\n// (`:setup`, `:mounted`) is left as written.\n//\n// This runs before hoistableImports reads the source, so an `import type`\n// specifier is already gone by the time the plugin decides what to bundle\nconst compileScriptBlocks = async (source: string, file: string): Promise<string> => {\n const blocks = [...source.matchAll(SCRIPT_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const marker = typescriptAttr(attrs)\n if (!marker) return null\n\n let rest = attrs.replace(marker, \"\").trimEnd()\n const setup = rest.match(SETUP_ATTR_RE)\n if (setup) {\n const signature = await stripSignatureTypes(setup[2] ?? setup[3], `${file}.signature.ts`)\n // a function replacement, not a string: `$&` and friends are live in a\n // replacement string and a default value is arbitrary source\n rest = rest.replace(SETUP_ATTR_RE, () => `${setup[1]}\"${quoteAttrValue(signature)}\"`)\n }\n\n return { attrs: rest, js: await stripTypes(content, `${file}.ts`) }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<script${done.attrs}>${done.js}</script>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// the emitted module. Literal import(\"...\") specifiers found in the\n// component's scripts become real module imports, handed to Component79 as a\n// resolution map: at runtime $__import checks the map before falling back to\n// fetch, so bundled components ship with their imports and nothing changes\n// for unbundled ones. Claimed components import as their default (a\n// Component79, matching what runtime fetch resolves to); everything else as\n// a namespace (matching native import()).\n//\n// A file's <template name=\"…\"> components are re-exported by name, so the\n// module shape is the one the file already has: default plus named. They read\n// off the instance, which is where the runtime hangs them - so in dev they are\n// bound to the *first* evaluation's definitions and a module that imports one\n// by name keeps the pre-edit child until the page reloads. The file's own\n// component patches in place, and its rendered children come from the reparse,\n// so this only shows in a component imported by name from another file.\n//\n// In dev, `hot.data` carries the exported instance across updates: importers\n// hold a reference to the *first* module evaluation's instance, so later\n// evaluations patch that same instance in place instead of exporting a new one\n// nobody sees. The patching itself is the runtime's `hotReplace` - the same\n// swap the jq79/dev server drives, from the one place that can reach a\n// component's markers. An instance only used as a definition has nothing to\n// re-render (nested clones can't be reached from this module), so it falls\n// back to a full reload.\n// `precompiled` is the precompiled script's URL, as a JS expression - present\n// only in safeEval mode\nconst componentModule = (source: string, include: RegExp, filename: string, precompiled?: string): string => {\n const hoisted = hoistableImports(source, include)\n const imports = hoisted\n .map((spec, i) =>\n include.test(spec)\n ? `import __jq79_${i} from ${JSON.stringify(spec)}`\n : `import * as __jq79_${i} from ${JSON.stringify(spec)}`\n )\n .join(\"\\n\")\n const modulesMap = `{ ${hoisted.map((spec, i) => `${JSON.stringify(spec)}: __jq79_${i}`).join(\", \")} }`\n\n // without safeEval, the module is exactly what it always was\n const safeEvalImport = precompiled ? `\\nimport { safeEval } from \"${SAFE_EVAL_ID}\"` : \"\"\n const safeEvalCall = precompiled ? `\\nawait safeEval(Component79, ${precompiled})` : \"\"\n\n return `\nimport { Component79 } from \"jq79\"${safeEvalImport}\n${imports}${safeEvalCall}\n\nconst src = ${JSON.stringify(source)}\nconst modules = ${modulesMap}\nconst filename = ${JSON.stringify(filename)}\n\nlet component\n\nif (import.meta.hot && import.meta.hot.data.component) {\n const prior = import.meta.hot.data.component\n prior.modules = modules\n prior.filename = filename\n // re-renders it where it stands, keeping its data. false means it was never\n // rendered - a definition used only as a nested component - and a reload is\n // the only way to reach the clones made from it\n if (!prior.hotReplace(src) && !prior.data) import.meta.hot.invalidate()\n component = prior\n} else {\n component = new Component79(src, { modules, filename })\n}\n\nif (import.meta.hot) {\n import.meta.hot.data.component = component\n import.meta.hot.accept()\n}\n\nexport default component\n${declaredComponents(source).map(name => `export const ${name} = component.${name}`).join(\"\\n\")}\n`\n}\n\nexport function jq79(options: Jq79PluginOptions = {}): Plugin {\n const include = options.include ?? /\\.html$/\n const { exclude } = options\n const safeEval = safeEvalOptions(options.safeEval)\n // dev only: each component's precompiled script, by the id its module asks\n // for - so the server hands out what the plugin compiled and nothing else\n const devScripts = new Map<string, string>()\n const devIds = new Map<string, number>()\n\n let config: ResolvedConfig | null = null\n\n return {\n name: \"jq79\",\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved\n },\n\n configureServer(server) {\n if (!safeEval) return\n server.middlewares.use((req, res, next) => {\n const url = new URL(req.url ?? \"/\", \"http://localhost\")\n if (!url.pathname.endsWith(PRECOMPILED_PATH)) return next()\n const script = devScripts.get(url.searchParams.get(\"id\") ?? \"\")\n if (script === undefined) return next()\n res.setHeader(\"Content-Type\", \"text/javascript\")\n res.setHeader(\"Cache-Control\", \"no-cache\")\n res.end(script)\n })\n },\n\n async resolveId(source, importer) {\n if (source === SAFE_EVAL_ID) return RESOLVED_SAFE_EVAL_ID\n if (!importer) return null // entry points are never components\n if (source.includes(\"?\")) return null // ?raw, ?url, ... keep their meaning\n if (!include.test(source)) return null\n\n const resolved = await this.resolve(source, importer, { skipSelf: true })\n if (!resolved || resolved.external) return null\n if (exclude?.test(resolved.id)) return null\n return resolved.id + COMPONENT_QUERY\n },\n\n async load(id) {\n // a Vite page's functions come from the build, so it never registers the worker\n if (id === RESOLVED_SAFE_EVAL_ID) return safeEvalModule({ ...safeEval, worker: false })\n if (!id.endsWith(COMPONENT_QUERY)) return null\n const file = id.slice(0, -COMPONENT_QUERY.length)\n\n let source = await readFile(file, \"utf8\")\n source = await compileScriptBlocks(source, file)\n if (config) source = await compileStyleBlocks(source, file, config, dep => this.addWatchFile(dep))\n\n // the runtime names the component's setup scripts after this, so devtools\n // shows a path the user recognizes instead of an anonymous VM script\n const filename = config ? relative(config.root, file) : file\n\n if (!safeEval) return { code: componentModule(source, include, filename), map: null }\n\n // the component's functions, compiled after its TypeScript and styles are:\n // the runtime compiles what reaches it, and this is what reaches it\n const script = componentScript(source, message => this.warn(`jq79: ${filename}: ${message}`))\n let url: string\n if (config?.command === \"serve\") {\n let devId = devIds.get(file)\n if (devId === undefined) devIds.set(file, devId = devIds.size)\n devScripts.set(String(devId), script)\n // versioned, so an edit loads the new functions rather than a cached copy\n url = JSON.stringify(`${config.base}${PRECOMPILED_PATH.slice(1)}?id=${devId}&v=${Date.now()}`)\n } else {\n const ref = this.emitFile({ type: \"asset\", name: `${basename(file)}.jq79.js`, source: script })\n url = `import.meta.ROLLUP_FILE_URL_${ref}`\n }\n return { code: componentModule(source, include, filename, url), map: null }\n },\n }\n}\n\nexport default jq79\n"],"mappings":"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","names":[]}
|
package/dist/vite.d.ts
CHANGED
package/dist/vite.js
CHANGED
|
@@ -1,8 +1,56 @@
|
|
|
1
1
|
// dev/vite.ts
|
|
2
2
|
import { readFile } from "fs/promises";
|
|
3
|
-
import { relative } from "path";
|
|
3
|
+
import { basename, relative } from "path";
|
|
4
4
|
import { preprocessCSS, transformWithEsbuild } from "vite";
|
|
5
|
+
import { precompile, precompiledScript } from "jq79/precompile";
|
|
5
6
|
var COMPONENT_QUERY = "?jq79";
|
|
7
|
+
var SAFE_EVAL_ID = "virtual:jq79/safe-eval";
|
|
8
|
+
var RESOLVED_SAFE_EVAL_ID = `\0${SAFE_EVAL_ID}`;
|
|
9
|
+
var safeEvalModule = (options) => `
|
|
10
|
+
let started = null
|
|
11
|
+
const loading = new Map()
|
|
12
|
+
const pageNonce = () => {
|
|
13
|
+
for (const script of document.querySelectorAll("script[nonce]")) {
|
|
14
|
+
const nonce = script.nonce || script.getAttribute("nonce")
|
|
15
|
+
if (nonce) return nonce
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export const safeEval = (Component79, url) => {
|
|
19
|
+
if (!started) started = Component79.safeEval(${JSON.stringify(options)}).catch(error => console.error(error))
|
|
20
|
+
let loaded = loading.get(url)
|
|
21
|
+
if (!loaded) {
|
|
22
|
+
loaded = new Promise((resolve, reject) => {
|
|
23
|
+
const script = document.createElement("script")
|
|
24
|
+
const nonce = pageNonce()
|
|
25
|
+
if (nonce) script.setAttribute("nonce", nonce)
|
|
26
|
+
script.src = url
|
|
27
|
+
script.onload = () => { script.remove(); resolve() }
|
|
28
|
+
script.onerror = () => {
|
|
29
|
+
script.remove()
|
|
30
|
+
reject(new Error("jq79: the precompiled functions at " + url + " did not load, and safeEval can't render without them"))
|
|
31
|
+
}
|
|
32
|
+
document.head.append(script)
|
|
33
|
+
})
|
|
34
|
+
loading.set(url, loaded)
|
|
35
|
+
}
|
|
36
|
+
return loaded
|
|
37
|
+
}
|
|
38
|
+
`;
|
|
39
|
+
var PRECOMPILED_PATH = "/@jq79/precompiled.js";
|
|
40
|
+
var safeEvalOptions = (option) => {
|
|
41
|
+
if (option === void 0 || option === false) return null;
|
|
42
|
+
return typeof option === "object" && option !== null && option.nonce === true ? { nonce: true } : {};
|
|
43
|
+
};
|
|
44
|
+
var SCOPED_BODY_RE = /^(?:let \$t;| return \()/;
|
|
45
|
+
var componentScript = (source, warn) => precompiledScript(precompile(source), (params, body) => {
|
|
46
|
+
try {
|
|
47
|
+
new Function(...params, body);
|
|
48
|
+
return true;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (!SCOPED_BODY_RE.test(body)) warn(`${error.message}, in: ${body.length > 120 ? `${body.slice(0, 120)}\u2026` : body}`);
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
6
54
|
var SCRIPT_BLOCK_RE = /<script((?:"[^"]*"|'[^']*'|[^>"'])*)>([\s\S]*?)<\/script\s*>/gi;
|
|
7
55
|
var IMPORT_CALL_RE = /import\s*\(\s*(["'])([^"'\n]+?)\1\s*\)/y;
|
|
8
56
|
var STATIC_IMPORT_RE = /import\s*(?:[\w$\s,{}*]+?\s*from\s*)?(["'])([^"'\n]+)\1/y;
|
|
@@ -189,15 +237,19 @@ var compileScriptBlocks = async (source, file) => {
|
|
|
189
237
|
});
|
|
190
238
|
return out + source.slice(last);
|
|
191
239
|
};
|
|
192
|
-
var componentModule = (source, include, filename) => {
|
|
240
|
+
var componentModule = (source, include, filename, precompiled) => {
|
|
193
241
|
const hoisted = hoistableImports(source, include);
|
|
194
242
|
const imports = hoisted.map(
|
|
195
243
|
(spec, i) => include.test(spec) ? `import __jq79_${i} from ${JSON.stringify(spec)}` : `import * as __jq79_${i} from ${JSON.stringify(spec)}`
|
|
196
244
|
).join("\n");
|
|
197
245
|
const modulesMap = `{ ${hoisted.map((spec, i) => `${JSON.stringify(spec)}: __jq79_${i}`).join(", ")} }`;
|
|
246
|
+
const safeEvalImport = precompiled ? `
|
|
247
|
+
import { safeEval } from "${SAFE_EVAL_ID}"` : "";
|
|
248
|
+
const safeEvalCall = precompiled ? `
|
|
249
|
+
await safeEval(Component79, ${precompiled})` : "";
|
|
198
250
|
return `
|
|
199
|
-
import { Component79 } from "jq79"
|
|
200
|
-
${imports}
|
|
251
|
+
import { Component79 } from "jq79"${safeEvalImport}
|
|
252
|
+
${imports}${safeEvalCall}
|
|
201
253
|
|
|
202
254
|
const src = ${JSON.stringify(source)}
|
|
203
255
|
const modules = ${modulesMap}
|
|
@@ -230,6 +282,9 @@ ${declaredComponents(source).map((name) => `export const ${name} = component.${n
|
|
|
230
282
|
function jq79(options = {}) {
|
|
231
283
|
const include = options.include ?? /\.html$/;
|
|
232
284
|
const { exclude } = options;
|
|
285
|
+
const safeEval = safeEvalOptions(options.safeEval);
|
|
286
|
+
const devScripts = /* @__PURE__ */ new Map();
|
|
287
|
+
const devIds = /* @__PURE__ */ new Map();
|
|
233
288
|
let config = null;
|
|
234
289
|
return {
|
|
235
290
|
name: "jq79",
|
|
@@ -237,7 +292,20 @@ function jq79(options = {}) {
|
|
|
237
292
|
configResolved(resolved) {
|
|
238
293
|
config = resolved;
|
|
239
294
|
},
|
|
295
|
+
configureServer(server) {
|
|
296
|
+
if (!safeEval) return;
|
|
297
|
+
server.middlewares.use((req, res, next) => {
|
|
298
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
299
|
+
if (!url.pathname.endsWith(PRECOMPILED_PATH)) return next();
|
|
300
|
+
const script = devScripts.get(url.searchParams.get("id") ?? "");
|
|
301
|
+
if (script === void 0) return next();
|
|
302
|
+
res.setHeader("Content-Type", "text/javascript");
|
|
303
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
304
|
+
res.end(script);
|
|
305
|
+
});
|
|
306
|
+
},
|
|
240
307
|
async resolveId(source, importer) {
|
|
308
|
+
if (source === SAFE_EVAL_ID) return RESOLVED_SAFE_EVAL_ID;
|
|
241
309
|
if (!importer) return null;
|
|
242
310
|
if (source.includes("?")) return null;
|
|
243
311
|
if (!include.test(source)) return null;
|
|
@@ -247,13 +315,26 @@ function jq79(options = {}) {
|
|
|
247
315
|
return resolved.id + COMPONENT_QUERY;
|
|
248
316
|
},
|
|
249
317
|
async load(id) {
|
|
318
|
+
if (id === RESOLVED_SAFE_EVAL_ID) return safeEvalModule({ ...safeEval, worker: false });
|
|
250
319
|
if (!id.endsWith(COMPONENT_QUERY)) return null;
|
|
251
320
|
const file = id.slice(0, -COMPONENT_QUERY.length);
|
|
252
321
|
let source = await readFile(file, "utf8");
|
|
253
322
|
source = await compileScriptBlocks(source, file);
|
|
254
323
|
if (config) source = await compileStyleBlocks(source, file, config, (dep) => this.addWatchFile(dep));
|
|
255
324
|
const filename = config ? relative(config.root, file) : file;
|
|
256
|
-
return { code: componentModule(source, include, filename), map: null };
|
|
325
|
+
if (!safeEval) return { code: componentModule(source, include, filename), map: null };
|
|
326
|
+
const script = componentScript(source, (message) => this.warn(`jq79: ${filename}: ${message}`));
|
|
327
|
+
let url;
|
|
328
|
+
if (config?.command === "serve") {
|
|
329
|
+
let devId = devIds.get(file);
|
|
330
|
+
if (devId === void 0) devIds.set(file, devId = devIds.size);
|
|
331
|
+
devScripts.set(String(devId), script);
|
|
332
|
+
url = JSON.stringify(`${config.base}${PRECOMPILED_PATH.slice(1)}?id=${devId}&v=${Date.now()}`);
|
|
333
|
+
} else {
|
|
334
|
+
const ref = this.emitFile({ type: "asset", name: `${basename(file)}.jq79.js`, source: script });
|
|
335
|
+
url = `import.meta.ROLLUP_FILE_URL_${ref}`;
|
|
336
|
+
}
|
|
337
|
+
return { code: componentModule(source, include, filename, url), map: null };
|
|
257
338
|
}
|
|
258
339
|
};
|
|
259
340
|
}
|
package/dist/vite.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../dev/vite.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\"\nimport { relative } from \"node:path\"\nimport { preprocessCSS, transformWithEsbuild } from \"vite\"\nimport type { Plugin, ResolvedConfig } from \"vite\"\n\n// Vite plugin: import .html single-file components as modules.\n//\n// import { jq79 } from \"jq79/vite\" // vite.config\n// import UserCard from \"./UserCard.html\" // app code\n//\n// The imported value is a Component79 built from the file's source - the same\n// thing `await Component79.fetch(url)` resolves to, but bundled at build time\n// instead of fetched at runtime. The component source is inlined verbatim, so\n// a file keeps working unchanged if it's ever served from public/ and loaded\n// with fetch instead - with one deliberate exception, a block that says it is\n// written in something else: <style lang=\"scss\"> (or less/stylus/sass) is\n// compiled to plain CSS here, and a TypeScript script - <script lang=\"ts\">, or\n// the <script type=\"text/typescript\"> editors read as one - to plain JS. Such a\n// component only works through the bundler; loaded with fetch() it would reach\n// the runtime uncompiled, which the runtime warns about.\n//\n// Only .html files imported from other modules are claimed; entry points\n// (index.html) have no importer and imports carrying an explicit query\n// (?raw, ?url) keep their built-in Vite meaning.\n\nexport interface Jq79PluginOptions {\n // which import specifiers are treated as components (default: any .html)\n include?: RegExp\n // resolved absolute paths to skip even when `include` matches\n exclude?: RegExp\n}\n\n// claimed modules get this suffix so their id no longer ends in \".html\" and\n// Vite's own html handling (entries, asset pipeline) leaves them alone\nconst COMPONENT_QUERY = \"?jq79\"\n\n// a <script> block with its attribute string, so `lang` can be read and the\n// body replaced - the same shape as STYLE_BLOCK_RE below, quote-aware so a\n// \">\" inside an attribute value (`:setup=\"{ n = a > 1 }\"`) doesn't end the tag\nconst SCRIPT_BLOCK_RE = /<script((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/script\\s*>/gi\n// import(\"...\") with a literal specifier, tried at word boundaries the\n// scanner below reaches (which is what skips $__import and foo.import(...))\nconst IMPORT_CALL_RE = /import\\s*\\(\\s*([\"'])([^\"'\\n]+?)\\1\\s*\\)/y\n// static import statements (factory scripts): optional clause + literal\n// specifier. The clause can't contain parens/quotes, so dynamic import()\n// and import.meta never match\nconst STATIC_IMPORT_RE = /import\\s*(?:[\\w$\\s,{}*]+?\\s*from\\s*)?([\"'])([^\"'\\n]+)\\1/y\n\nconst skipString = (src: string, start: number): number => {\n const quote = src[start]\n let i = start + 1\n while (i < src.length) {\n if (src[i] === \"\\\\\") { i += 2; continue }\n if (src[i] === quote) return i + 1\n i++\n }\n return src.length\n}\n\n// the literal import specifiers in one script body. A scanner rather than a\n// bare matchAll, because a specifier mentioned in a comment or a string is\n// not an import: hoisting a commented-out `import(\"./old.html\")` would pull\n// dead files into the bundle - or break the build once the file is gone\nconst importSpecifiers = (script: string): string[] => {\n const specs: string[] = []\n let i = 0\n while (i < script.length) {\n const ch = script[i]\n if (ch === \"'\" || ch === '\"' || ch === \"`\") { i = skipString(script, i); continue }\n if (ch === \"/\" && script[i + 1] === \"/\") {\n const end = script.indexOf(\"\\n\", i)\n i = end === -1 ? script.length : end + 1\n continue\n }\n if (ch === \"/\" && script[i + 1] === \"*\") {\n const end = script.indexOf(\"*/\", i + 2)\n i = end === -1 ? script.length : end + 2\n continue\n }\n if (ch === \"i\" && (i === 0 || !/[\\w$.]/.test(script[i - 1]))) {\n IMPORT_CALL_RE.lastIndex = i\n const call = IMPORT_CALL_RE.exec(script)\n if (call) { specs.push(call[2]); i = IMPORT_CALL_RE.lastIndex; continue }\n STATIC_IMPORT_RE.lastIndex = i\n const staticImport = STATIC_IMPORT_RE.exec(script)\n if (staticImport) { specs.push(staticImport[2]); i = STATIC_IMPORT_RE.lastIndex; continue }\n }\n i++\n }\n return specs\n}\n\nconst isHtmlUrl = (spec: string) => /\\.html?([?#]|$)/.test(spec)\nconst isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith(\"/\")\n\n// literal import specifiers in the component's script blocks - dynamic\n// `import(\"...\")` calls and static factory-script imports - that should\n// resolve from the bundle instead of at runtime. Absolute paths and full\n// URLs are left alone (they point at served files, e.g. public/), and so\n// are .html specifiers the plugin wouldn't claim as components\nconst hoistableImports = (source: string, include: RegExp): string[] => {\n const specifiers = new Set<string>()\n for (const [, , script] of source.matchAll(SCRIPT_BLOCK_RE)) {\n for (const spec of importSpecifiers(script)) {\n if (isExternalUrl(spec)) continue\n if (isHtmlUrl(spec) && !include.test(spec)) continue // html left to runtime fetch\n specifiers.add(spec) // a claimed component, a source file or an npm package\n }\n }\n return [...specifiers]\n}\n\n// any start or end tag, quote-aware so a \">\" inside an attribute value doesn't\n// end it early\nconst TAG_RE = /<(\\/?)([A-Za-z][\\w-]*)((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>/g\nconst NAME_ATTR_RE = /\\bname\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i\nconst COMPONENT_NAME_RE = /^[A-Z][A-Za-z0-9]*$/\nconst VOID_ELEMENTS = new Set([\n \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\",\n \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\",\n])\n\n// the components a file declares: its *top-level* <template name=\"…\"> blocks,\n// which the emitted module re-exports by name. Depth is tracked because only\n// the top level declares - a <template> nested in the markup is a plain inert\n// element the runtime leaves alone, and exporting it would name something that\n// never exists. Script and style bodies are cut out first, so a \"<\" in JS or a\n// selector can't be read as a tag\nconst declaredComponents = (source: string): string[] => {\n const markup = source.replace(SCRIPT_BLOCK_RE, \"\").replace(STYLE_BLOCK_RE, \"\")\n const names: string[] = []\n let depth = 0\n\n for (const [, closing, tag, attrs] of markup.matchAll(TAG_RE)) {\n if (closing) {\n depth = Math.max(0, depth - 1)\n continue\n }\n const selfClosing = /\\/\\s*$/.test(attrs) || VOID_ELEMENTS.has(tag.toLowerCase())\n if (depth === 0 && !selfClosing && tag.toLowerCase() === \"template\") {\n const declared = attrs.match(NAME_ATTR_RE)\n const name = declared?.[1] ?? declared?.[2]\n // the runtime warns about the ones this skips (nameless, not PascalCase)\n if (name && COMPONENT_NAME_RE.test(name)) names.push(name)\n }\n if (!selfClosing) depth++\n }\n return names\n}\n\n// a <style> block with its attribute string, so `lang` can be read and the\n// content replaced. Attribute values are matched as quoted chunks so a \">\"\n// inside one doesn't end the tag early\nconst STYLE_BLOCK_RE = /<style((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/style\\s*>/gi\nconst LANG_ATTR_RE = /\\blang\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\nconst TYPE_ATTR_RE = /\\btype\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\n\n// one attribute's value out of a tag's attribute string, whichever way it was\n// quoted - null when the attribute isn't there at all\nconst attrValue = (attrs: string, re: RegExp): string | null => {\n const found = attrs.match(re)\n return found ? found[1] ?? found[2] ?? found[3] : null\n}\n\n// compiles <style lang=\"scss|less|styl|sass\"> blocks to plain CSS with Vite's\n// own preprocessing (the same call @vitejs/plugin-vue makes), so the runtime\n// only ever sees CSS. The preprocessor picks its parser from the extension,\n// and resolving relative @use/@import against a filename in the component's\n// own directory is what makes `@use \"./vars\"` work. Files the preprocessor\n// pulls in are registered as watch deps, so editing a partial re-runs HMR for\n// every component that uses it. `lang` is dropped from the emitted tag: what\n// the runtime parses is a plain <style> (with `scoped` and the rest intact)\nconst compileStyleBlocks = async (\n source: string,\n file: string,\n config: ResolvedConfig,\n addWatchFile: (id: string) => void\n): Promise<string> => {\n const blocks = [...source.matchAll(STYLE_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const extension = attrValue(attrs, LANG_ATTR_RE)\n if (extension === null) return null\n const result = await preprocessCSS(content, `${file}.${extension}`, config)\n result.deps?.forEach(addWatchFile)\n return { attrs: attrs.replace(LANG_ATTR_RE, \"\").trimEnd(), css: result.code }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<style${done.attrs}>${done.css}</style>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// languages a <script lang> is compiled from. Anything else is left as written\n// for the runtime to warn about, rather than guessed at\nconst TS_LANGS = new Set([\"ts\", \"typescript\"])\n// the other spelling of the same mark, and the one editors read: a component is\n// a plain .html file, not an SFC, so nothing in an IDE knows what `lang` means\n// there - embedded-script tooling picks a language from `type`, and a typed\n// block without one is linted as JavaScript. The `x-` forms are the historical\n// spelling of the same two media types\nconst TS_TYPE_RE = /^(?:text|application)\\/(?:x-)?typescript$/\n\n// what marks a script block as TypeScript, given back as the attribute to drop\n// from the emitted tag - the block is compiled to JS, so the mark goes with the\n// types whichever one carried it. A `lang` answers on its own: `lang=\"coffee\"`\n// is a language this plugin doesn't compile, and reading `type` past it would\n// compile a block the author said was something else\nconst typescriptAttr = (attrs: string): RegExp | null => {\n const lang = attrValue(attrs, LANG_ATTR_RE)\n if (lang !== null) return TS_LANGS.has(lang.trim().toLowerCase()) ? LANG_ATTR_RE : null\n const type = attrValue(attrs, TYPE_ATTR_RE)\n return type !== null && TS_TYPE_RE.test(type.trim().toLowerCase()) ? TYPE_ATTR_RE : null\n}\n\ntype ViteTransform = (code: string, id: string, options?: unknown) => Promise<{ code: string }>\n\n// what strips the types: vite's own transform, so the plugin carries no\n// compiler of its own. *Which* transform is a version question, and neither\n// answer covers the peer range (vite >= 5) alone - transformWithOxc is the one\n// vite is moving to but only exists from vite 7, while transformWithEsbuild is\n// deprecated under vite 8 and throws there unless esbuild is installed\n// separately. So it is looked up at call time: oxc where it exists, esbuild on\n// the older versions that ship it.\n//\n// Both drop unused value imports by default, because a TS transform can't tell\n// a type-only import from an unused one. That would be silent damage here: a\n// factory script's `import Row from \"./row.html\"` would vanish, taking with it\n// the specifier hoistableImports needs to pull the child into the bundle. The\n// flags below are what keep it - only `import type` is erased\nconst stripTypes = async (ts: string, file: string): Promise<string> => {\n const vite = (await import(\"vite\")) as unknown as { transformWithOxc?: ViteTransform }\n const { code } = vite.transformWithOxc\n ? await vite.transformWithOxc(ts, file, { lang: \"ts\", typescript: { onlyRemoveTypeImports: true } })\n : await transformWithEsbuild(ts, file, {\n loader: \"ts\",\n tsconfigRaw: { compilerOptions: { verbatimModuleSyntax: true } },\n })\n // a script whose only imports were `import type` comes back marked as a\n // module. `export {}` exports nothing, and it is a SyntaxError inside the\n // Function body the runtime compiles a script into\n return code.replace(/^[ \\t]*export\\s*\\{\\s*\\}\\s*;?[ \\t]*$/m, \"\")\n}\n\n// the `:setup` attribute, when it carries a value (a bare `:setup` is the\n// closed signature and can't be typed)\nconst SETUP_ATTR_RE = /(:setup\\s*=\\s*)(?:\"([^\"]*)\"|'([^']*)')/i\n// the arrow body the signature is wrapped in, so the parameter list can be\n// found again in the output without matching brackets\nconst SIGNATURE_MARKER = \"__jq79_signature__\"\n\n// a component's props signature lives in the `:setup` *attribute*, not in the\n// script body, so the body's transform never sees it - and the TypeScript mark\n// has to mean the same thing on both halves of the block, or a typed signature\n// either survives into a component the plugin just promised was JS or, for\n// `_: Props`, stops reading as a signature at all.\n//\n// It goes through the same transform as everything else, wrapped as a\n// parameter list, rather than being cut with a scanner of its own: the\n// annotation can sit on the pattern (`{ a }: Props`), on the permissive `_`, or\n// inside a default (`{ step = 1 as number }`, which the runtime would evaluate\n// and silently drop), and telling those apart is a parser's job. Both transforms\n// hand back `(<params>) => <marker>` on one line, parens intact\nconst stripSignatureTypes = async (value: string, file: string): Promise<string> => {\n const compiled = await stripTypes(`(${value}) => ${SIGNATURE_MARKER}`, file)\n const marker = compiled.indexOf(SIGNATURE_MARKER)\n if (marker === -1) return value // not the shape expected: leave it as written\n const head = compiled.slice(0, marker).trimEnd()\n const params = (head.endsWith(\"=>\") ? head.slice(0, -2) : head).trim()\n return params.startsWith(\"(\") && params.endsWith(\")\") ? params.slice(1, -1).trim() : params\n}\n\n// the signature back into a double-quoted attribute. Only `\"` needs escaping:\n// the transforms normalize string literals to double quotes, so a default the\n// author wrote as `'x'` comes back as `\"x\"` and would end the attribute early.\n// `&` is deliberately left alone - `&&` in a default is not an entity and\n// survives the parse, while escaping it would double-encode a source that\n// already wrote `"`\nconst quoteAttrValue = (value: string) => value.replace(/\"/g, \""\")\n\n// compiles TypeScript script blocks to plain JS, so the runtime only ever sees\n// JS - the same deal <style lang=\"scss\"> gets, for a sharper reason. The setup\n// scanner is not a parser: `let count: number = 0` reaching it is not a syntax\n// error but a labeled statement that assigns to `number`, so it runs and leaves\n// `count` undeclared. Whichever attribute marked the block (`lang=\"ts\"` or\n// `type=\"text/typescript\"`) is dropped from the emitted tag and every other one\n// (`:setup`, `:mounted`) is left as written.\n//\n// This runs before hoistableImports reads the source, so an `import type`\n// specifier is already gone by the time the plugin decides what to bundle\nconst compileScriptBlocks = async (source: string, file: string): Promise<string> => {\n const blocks = [...source.matchAll(SCRIPT_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const marker = typescriptAttr(attrs)\n if (!marker) return null\n\n let rest = attrs.replace(marker, \"\").trimEnd()\n const setup = rest.match(SETUP_ATTR_RE)\n if (setup) {\n const signature = await stripSignatureTypes(setup[2] ?? setup[3], `${file}.signature.ts`)\n // a function replacement, not a string: `$&` and friends are live in a\n // replacement string and a default value is arbitrary source\n rest = rest.replace(SETUP_ATTR_RE, () => `${setup[1]}\"${quoteAttrValue(signature)}\"`)\n }\n\n return { attrs: rest, js: await stripTypes(content, `${file}.ts`) }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<script${done.attrs}>${done.js}</script>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// the emitted module. Literal import(\"...\") specifiers found in the\n// component's scripts become real module imports, handed to Component79 as a\n// resolution map: at runtime $__import checks the map before falling back to\n// fetch, so bundled components ship with their imports and nothing changes\n// for unbundled ones. Claimed components import as their default (a\n// Component79, matching what runtime fetch resolves to); everything else as\n// a namespace (matching native import()).\n//\n// A file's <template name=\"…\"> components are re-exported by name, so the\n// module shape is the one the file already has: default plus named. They read\n// off the instance, which is where the runtime hangs them - so in dev they are\n// bound to the *first* evaluation's definitions and a module that imports one\n// by name keeps the pre-edit child until the page reloads. The file's own\n// component patches in place, and its rendered children come from the reparse,\n// so this only shows in a component imported by name from another file.\n//\n// In dev, `hot.data` carries the exported instance across updates: importers\n// hold a reference to the *first* module evaluation's instance, so later\n// evaluations patch that same instance in place instead of exporting a new one\n// nobody sees. The patching itself is the runtime's `hotReplace` - the same\n// swap the jq79/dev server drives, from the one place that can reach a\n// component's markers. An instance only used as a definition has nothing to\n// re-render (nested clones can't be reached from this module), so it falls\n// back to a full reload.\nconst componentModule = (source: string, include: RegExp, filename: string): string => {\n const hoisted = hoistableImports(source, include)\n const imports = hoisted\n .map((spec, i) =>\n include.test(spec)\n ? `import __jq79_${i} from ${JSON.stringify(spec)}`\n : `import * as __jq79_${i} from ${JSON.stringify(spec)}`\n )\n .join(\"\\n\")\n const modulesMap = `{ ${hoisted.map((spec, i) => `${JSON.stringify(spec)}: __jq79_${i}`).join(\", \")} }`\n\n return `\nimport { Component79 } from \"jq79\"\n${imports}\n\nconst src = ${JSON.stringify(source)}\nconst modules = ${modulesMap}\nconst filename = ${JSON.stringify(filename)}\n\nlet component\n\nif (import.meta.hot && import.meta.hot.data.component) {\n const prior = import.meta.hot.data.component\n prior.modules = modules\n prior.filename = filename\n // re-renders it where it stands, keeping its data. false means it was never\n // rendered - a definition used only as a nested component - and a reload is\n // the only way to reach the clones made from it\n if (!prior.hotReplace(src) && !prior.data) import.meta.hot.invalidate()\n component = prior\n} else {\n component = new Component79(src, { modules, filename })\n}\n\nif (import.meta.hot) {\n import.meta.hot.data.component = component\n import.meta.hot.accept()\n}\n\nexport default component\n${declaredComponents(source).map(name => `export const ${name} = component.${name}`).join(\"\\n\")}\n`\n}\n\nexport function jq79(options: Jq79PluginOptions = {}): Plugin {\n const include = options.include ?? /\\.html$/\n const { exclude } = options\n\n let config: ResolvedConfig | null = null\n\n return {\n name: \"jq79\",\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved\n },\n\n async resolveId(source, importer) {\n if (!importer) return null // entry points are never components\n if (source.includes(\"?\")) return null // ?raw, ?url, ... keep their meaning\n if (!include.test(source)) return null\n\n const resolved = await this.resolve(source, importer, { skipSelf: true })\n if (!resolved || resolved.external) return null\n if (exclude?.test(resolved.id)) return null\n return resolved.id + COMPONENT_QUERY\n },\n\n async load(id) {\n if (!id.endsWith(COMPONENT_QUERY)) return null\n const file = id.slice(0, -COMPONENT_QUERY.length)\n\n let source = await readFile(file, \"utf8\")\n source = await compileScriptBlocks(source, file)\n if (config) source = await compileStyleBlocks(source, file, config, dep => this.addWatchFile(dep))\n\n // the runtime names the component's setup scripts after this, so devtools\n // shows a path the user recognizes instead of an anonymous VM script\n const filename = config ? relative(config.root, file) : file\n\n return { code: componentModule(source, include, filename), map: null }\n },\n }\n}\n\nexport default jq79\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../dev/vite.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\"\nimport { basename, relative } from \"node:path\"\nimport { preprocessCSS, transformWithEsbuild } from \"vite\"\nimport type { Plugin, ResolvedConfig } from \"vite\"\n// by package name rather than ../src: this file's types are emitted with dev/\n// as their root, and the generator is the runtime's own code - resolved through\n// the package's exports (external in the build, aliased to src in the tests)\nimport { precompile, precompiledScript } from \"jq79/precompile\"\n\n// Vite plugin: import .html single-file components as modules.\n//\n// import { jq79 } from \"jq79/vite\" // vite.config\n// import UserCard from \"./UserCard.html\" // app code\n//\n// The imported value is a Component79 built from the file's source - the same\n// thing `await Component79.fetch(url)` resolves to, but bundled at build time\n// instead of fetched at runtime. The component source is inlined verbatim, so\n// a file keeps working unchanged if it's ever served from public/ and loaded\n// with fetch instead - with one deliberate exception, a block that says it is\n// written in something else: <style lang=\"scss\"> (or less/stylus/sass) is\n// compiled to plain CSS here, and a TypeScript script - <script lang=\"ts\">, or\n// the same mark spelled <script type=\"text/typescript\"> - to plain JS. Such a\n// component only works through the bundler; loaded with fetch() it would reach\n// the runtime uncompiled, which the runtime warns about.\n//\n// Only .html files imported from other modules are claimed; entry points\n// (index.html) have no importer and imports carrying an explicit query\n// (?raw, ?url) keep their built-in Vite meaning.\n\nexport interface Jq79PluginOptions {\n // which import specifiers are treated as components (default: any .html)\n include?: RegExp\n // resolved absolute paths to skip even when `include` matches\n exclude?: RegExp\n // run the app without eval, for a CSP with no 'unsafe-eval' - the value\n // Component79.safeEval() takes, and meaning the same thing\n // (RECORD/2026-09-23.no-unsafe-eval.md). Every component is precompiled, and\n // its functions ship as a script of their own. `true`: those and nothing\n // else - whatever the build couldn't see is reported, never evaluated.\n // `{ nonce: true }`: whatever it couldn't see (a component built from a\n // string, an edit during HMR) is built as a <script> carrying the page's nonce\n safeEval?: boolean | { nonce?: boolean }\n}\n\n// claimed modules get this suffix so their id no longer ends in \".html\" and\n// Vite's own html handling (entries, asset pipeline) leaves them alone\nconst COMPONENT_QUERY = \"?jq79\"\n\n// safeEval. A component's precompiled functions travel as a classic script of\n// their own - Card.html.jq79.js - and not inside its module: they compile\n// under `with`, which is a SyntaxError in strict code, and every module is\n// strict. In a build the script is an asset beside the chunk; in dev the\n// server hands it out (PRECOMPILED_PATH). Either way it pushes its functions\n// onto the queue the runtime drains (see \"safe eval\" in src/jq79.ts).\n//\n// The component's module waits for it - a top-level await - before it builds\n// anything, through a module every component module imports. That module\n// evaluates once, so safe mode is turned on once per app, and a page with no\n// nonce is reported once rather than once per component; and it loads each\n// script once, however many modules ask. The <script> carries the page's\n// nonce when there is one, so a CSP that works by nonce admits it; under\n// `script-src 'self'` the URL is what admits it.\n//\n// Component79 is passed in rather than imported, so the module resolves\n// nothing: a bare \"jq79\" from a virtual importer is the one resolution that\n// would depend on how the app is laid out.\n//\n// A component built from a string *before* any .html module is imported runs\n// in the default mode; such an app calls Component79.safeEval itself. The\n// await needs a build target with top-level await in it - Vite 7 and later\n// have one by default; on Vite 5 or 6, raise build.target to es2022\nconst SAFE_EVAL_ID = \"virtual:jq79/safe-eval\"\nconst RESOLVED_SAFE_EVAL_ID = `\\0${SAFE_EVAL_ID}`\nconst safeEvalModule = (options: { nonce?: boolean; worker: false }) => `\nlet started = null\nconst loading = new Map()\nconst pageNonce = () => {\n for (const script of document.querySelectorAll(\"script[nonce]\")) {\n const nonce = script.nonce || script.getAttribute(\"nonce\")\n if (nonce) return nonce\n }\n}\nexport const safeEval = (Component79, url) => {\n if (!started) started = Component79.safeEval(${JSON.stringify(options)}).catch(error => console.error(error))\n let loaded = loading.get(url)\n if (!loaded) {\n loaded = new Promise((resolve, reject) => {\n const script = document.createElement(\"script\")\n const nonce = pageNonce()\n if (nonce) script.setAttribute(\"nonce\", nonce)\n script.src = url\n script.onload = () => { script.remove(); resolve() }\n script.onerror = () => {\n script.remove()\n reject(new Error(\"jq79: the precompiled functions at \" + url + \" did not load, and safeEval can't render without them\"))\n }\n document.head.append(script)\n })\n loading.set(url, loaded)\n }\n return loaded\n}\n`\n\n// where the dev server hands out a component's precompiled script\nconst PRECOMPILED_PATH = \"/@jq79/precompiled.js\"\n\n// the plugin's safeEval option, as what the modules pass the runtime: null\n// for off, or Component79.safeEval's own options\nconst safeEvalOptions = (option: Jq79PluginOptions[\"safeEval\"]): { nonce?: boolean } | null => {\n if (option === undefined || option === false) return null\n return typeof option === \"object\" && option !== null && option.nonce === true ? { nonce: true } : {}\n}\n\n// a scoped-form body: the runtime falls back to the `with` form when one\n// doesn't compile, so only the `with` form's failure is worth a word\nconst SCOPED_BODY_RE = /^(?:let \\$t;| return \\()/\n\n// a component's precompiled functions, as the classic script that registers\n// them (precompiledScript, in jq79/precompile). Each is compiled here first -\n// node can, where the page may not - so the script holds only functions that\n// parse; one that doesn't ships as null, and the build says so\nconst componentScript = (source: string, warn: (message: string) => void): string =>\n precompiledScript(precompile(source), (params, body) => {\n try {\n new Function(...params, body)\n return true\n } catch (error) {\n if (!SCOPED_BODY_RE.test(body)) warn(`${(error as Error).message}, in: ${body.length > 120 ? `${body.slice(0, 120)}…` : body}`)\n return false\n }\n })\n\n// a <script> block with its attribute string, so `lang` can be read and the\n// body replaced - the same shape as STYLE_BLOCK_RE below, quote-aware so a\n// \">\" inside an attribute value (`:setup=\"{ n = a > 1 }\"`) doesn't end the tag\nconst SCRIPT_BLOCK_RE = /<script((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/script\\s*>/gi\n// import(\"...\") with a literal specifier, tried at word boundaries the\n// scanner below reaches (which is what skips $__import and foo.import(...))\nconst IMPORT_CALL_RE = /import\\s*\\(\\s*([\"'])([^\"'\\n]+?)\\1\\s*\\)/y\n// static import statements (factory scripts): optional clause + literal\n// specifier. The clause can't contain parens/quotes, so dynamic import()\n// and import.meta never match\nconst STATIC_IMPORT_RE = /import\\s*(?:[\\w$\\s,{}*]+?\\s*from\\s*)?([\"'])([^\"'\\n]+)\\1/y\n\nconst skipString = (src: string, start: number): number => {\n const quote = src[start]\n let i = start + 1\n while (i < src.length) {\n if (src[i] === \"\\\\\") { i += 2; continue }\n if (src[i] === quote) return i + 1\n i++\n }\n return src.length\n}\n\n// the literal import specifiers in one script body. A scanner rather than a\n// bare matchAll, because a specifier mentioned in a comment or a string is\n// not an import: hoisting a commented-out `import(\"./old.html\")` would pull\n// dead files into the bundle - or break the build once the file is gone\nconst importSpecifiers = (script: string): string[] => {\n const specs: string[] = []\n let i = 0\n while (i < script.length) {\n const ch = script[i]\n if (ch === \"'\" || ch === '\"' || ch === \"`\") { i = skipString(script, i); continue }\n if (ch === \"/\" && script[i + 1] === \"/\") {\n const end = script.indexOf(\"\\n\", i)\n i = end === -1 ? script.length : end + 1\n continue\n }\n if (ch === \"/\" && script[i + 1] === \"*\") {\n const end = script.indexOf(\"*/\", i + 2)\n i = end === -1 ? script.length : end + 2\n continue\n }\n if (ch === \"i\" && (i === 0 || !/[\\w$.]/.test(script[i - 1]))) {\n IMPORT_CALL_RE.lastIndex = i\n const call = IMPORT_CALL_RE.exec(script)\n if (call) { specs.push(call[2]); i = IMPORT_CALL_RE.lastIndex; continue }\n STATIC_IMPORT_RE.lastIndex = i\n const staticImport = STATIC_IMPORT_RE.exec(script)\n if (staticImport) { specs.push(staticImport[2]); i = STATIC_IMPORT_RE.lastIndex; continue }\n }\n i++\n }\n return specs\n}\n\nconst isHtmlUrl = (spec: string) => /\\.html?([?#]|$)/.test(spec)\nconst isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith(\"/\")\n\n// literal import specifiers in the component's script blocks - dynamic\n// `import(\"...\")` calls and static factory-script imports - that should\n// resolve from the bundle instead of at runtime. Absolute paths and full\n// URLs are left alone (they point at served files, e.g. public/), and so\n// are .html specifiers the plugin wouldn't claim as components\nconst hoistableImports = (source: string, include: RegExp): string[] => {\n const specifiers = new Set<string>()\n for (const [, , script] of source.matchAll(SCRIPT_BLOCK_RE)) {\n for (const spec of importSpecifiers(script)) {\n if (isExternalUrl(spec)) continue\n if (isHtmlUrl(spec) && !include.test(spec)) continue // html left to runtime fetch\n specifiers.add(spec) // a claimed component, a source file or an npm package\n }\n }\n return [...specifiers]\n}\n\n// any start or end tag, quote-aware so a \">\" inside an attribute value doesn't\n// end it early\nconst TAG_RE = /<(\\/?)([A-Za-z][\\w-]*)((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>/g\nconst NAME_ATTR_RE = /\\bname\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/i\nconst COMPONENT_NAME_RE = /^[A-Z][A-Za-z0-9]*$/\nconst VOID_ELEMENTS = new Set([\n \"area\", \"base\", \"br\", \"col\", \"embed\", \"hr\", \"img\", \"input\",\n \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\",\n])\n\n// the components a file declares: its *top-level* <template name=\"…\"> blocks,\n// which the emitted module re-exports by name. Depth is tracked because only\n// the top level declares - a <template> nested in the markup is a plain inert\n// element the runtime leaves alone, and exporting it would name something that\n// never exists. Script and style bodies are cut out first, so a \"<\" in JS or a\n// selector can't be read as a tag\nconst declaredComponents = (source: string): string[] => {\n const markup = source.replace(SCRIPT_BLOCK_RE, \"\").replace(STYLE_BLOCK_RE, \"\")\n const names: string[] = []\n let depth = 0\n\n for (const [, closing, tag, attrs] of markup.matchAll(TAG_RE)) {\n if (closing) {\n depth = Math.max(0, depth - 1)\n continue\n }\n const selfClosing = /\\/\\s*$/.test(attrs) || VOID_ELEMENTS.has(tag.toLowerCase())\n if (depth === 0 && !selfClosing && tag.toLowerCase() === \"template\") {\n const declared = attrs.match(NAME_ATTR_RE)\n const name = declared?.[1] ?? declared?.[2]\n // the runtime warns about the ones this skips (nameless, not PascalCase)\n if (name && COMPONENT_NAME_RE.test(name)) names.push(name)\n }\n if (!selfClosing) depth++\n }\n return names\n}\n\n// a <style> block with its attribute string, so `lang` can be read and the\n// content replaced. Attribute values are matched as quoted chunks so a \">\"\n// inside one doesn't end the tag early\nconst STYLE_BLOCK_RE = /<style((?:\"[^\"]*\"|'[^']*'|[^>\"'])*)>([\\s\\S]*?)<\\/style\\s*>/gi\nconst LANG_ATTR_RE = /\\blang\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\nconst TYPE_ATTR_RE = /\\btype\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\s>]+))/i\n\n// one attribute's value out of a tag's attribute string, whichever way it was\n// quoted - null when the attribute isn't there at all\nconst attrValue = (attrs: string, re: RegExp): string | null => {\n const found = attrs.match(re)\n return found ? found[1] ?? found[2] ?? found[3] : null\n}\n\n// compiles <style lang=\"scss|less|styl|sass\"> blocks to plain CSS with Vite's\n// own preprocessing (the same call @vitejs/plugin-vue makes), so the runtime\n// only ever sees CSS. The preprocessor picks its parser from the extension,\n// and resolving relative @use/@import against a filename in the component's\n// own directory is what makes `@use \"./vars\"` work. Files the preprocessor\n// pulls in are registered as watch deps, so editing a partial re-runs HMR for\n// every component that uses it. `lang` is dropped from the emitted tag: what\n// the runtime parses is a plain <style> (with `scoped` and the rest intact)\nconst compileStyleBlocks = async (\n source: string,\n file: string,\n config: ResolvedConfig,\n addWatchFile: (id: string) => void\n): Promise<string> => {\n const blocks = [...source.matchAll(STYLE_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const extension = attrValue(attrs, LANG_ATTR_RE)\n if (extension === null) return null\n const result = await preprocessCSS(content, `${file}.${extension}`, config)\n result.deps?.forEach(addWatchFile)\n return { attrs: attrs.replace(LANG_ATTR_RE, \"\").trimEnd(), css: result.code }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<style${done.attrs}>${done.css}</style>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// languages a <script lang> is compiled from. Anything else is left as written\n// for the runtime to warn about, rather than guessed at\nconst TS_LANGS = new Set([\"ts\", \"typescript\"])\n// the other spelling of the same mark. A component is a plain .html file, not\n// an SFC, so nothing in an editor knows what `lang` means there, and each mark\n// gets half of one: VS Code's HTML language service checks a `type` of\n// text/typescript as TypeScript (and `lang=\"ts\"` as JavaScript), while its\n// grammar colors that `type` not at all (and `lang=\"ts\"` as JavaScript). See\n// docs/vite-plugin.md#which-mark-in-vs-code. The `x-` forms are the historical\n// spelling of the same two media types\nconst TS_TYPE_RE = /^(?:text|application)\\/(?:x-)?typescript$/\n\n// what marks a script block as TypeScript, given back as the attribute to drop\n// from the emitted tag - the block is compiled to JS, so the mark goes with the\n// types whichever one carried it. A `lang` answers on its own: `lang=\"coffee\"`\n// is a language this plugin doesn't compile, and reading `type` past it would\n// compile a block the author said was something else\nconst typescriptAttr = (attrs: string): RegExp | null => {\n const lang = attrValue(attrs, LANG_ATTR_RE)\n if (lang !== null) return TS_LANGS.has(lang.trim().toLowerCase()) ? LANG_ATTR_RE : null\n const type = attrValue(attrs, TYPE_ATTR_RE)\n return type !== null && TS_TYPE_RE.test(type.trim().toLowerCase()) ? TYPE_ATTR_RE : null\n}\n\ntype ViteTransform = (code: string, id: string, options?: unknown) => Promise<{ code: string }>\n\n// what strips the types: vite's own transform, so the plugin carries no\n// compiler of its own. *Which* transform is a version question, and neither\n// answer covers the peer range (vite >= 5) alone - transformWithOxc is the one\n// vite is moving to but only exists from vite 7, while transformWithEsbuild is\n// deprecated under vite 8 and throws there unless esbuild is installed\n// separately. So it is looked up at call time: oxc where it exists, esbuild on\n// the older versions that ship it.\n//\n// Both drop unused value imports by default, because a TS transform can't tell\n// a type-only import from an unused one. That would be silent damage here: a\n// factory script's `import Row from \"./row.html\"` would vanish, taking with it\n// the specifier hoistableImports needs to pull the child into the bundle. The\n// flags below are what keep it - only `import type` is erased\nconst stripTypes = async (ts: string, file: string): Promise<string> => {\n const vite = (await import(\"vite\")) as unknown as { transformWithOxc?: ViteTransform }\n const { code } = vite.transformWithOxc\n ? await vite.transformWithOxc(ts, file, { lang: \"ts\", typescript: { onlyRemoveTypeImports: true } })\n : await transformWithEsbuild(ts, file, {\n loader: \"ts\",\n tsconfigRaw: { compilerOptions: { verbatimModuleSyntax: true } },\n })\n // a script whose only imports were `import type` comes back marked as a\n // module. `export {}` exports nothing, and it is a SyntaxError inside the\n // Function body the runtime compiles a script into\n return code.replace(/^[ \\t]*export\\s*\\{\\s*\\}\\s*;?[ \\t]*$/m, \"\")\n}\n\n// the `:setup` attribute, when it carries a value (a bare `:setup` is the\n// closed signature and can't be typed)\nconst SETUP_ATTR_RE = /(:setup\\s*=\\s*)(?:\"([^\"]*)\"|'([^']*)')/i\n// the arrow body the signature is wrapped in, so the parameter list can be\n// found again in the output without matching brackets\nconst SIGNATURE_MARKER = \"__jq79_signature__\"\n\n// a component's props signature lives in the `:setup` *attribute*, not in the\n// script body, so the body's transform never sees it - and the TypeScript mark\n// has to mean the same thing on both halves of the block, or a typed signature\n// either survives into a component the plugin just promised was JS or, for\n// `_: Props`, stops reading as a signature at all.\n//\n// It goes through the same transform as everything else, wrapped as a\n// parameter list, rather than being cut with a scanner of its own: the\n// annotation can sit on the pattern (`{ a }: Props`), on the permissive `_`, or\n// inside a default (`{ step = 1 as number }`, which the runtime would evaluate\n// and silently drop), and telling those apart is a parser's job. Both transforms\n// hand back `(<params>) => <marker>` on one line, parens intact\nconst stripSignatureTypes = async (value: string, file: string): Promise<string> => {\n const compiled = await stripTypes(`(${value}) => ${SIGNATURE_MARKER}`, file)\n const marker = compiled.indexOf(SIGNATURE_MARKER)\n if (marker === -1) return value // not the shape expected: leave it as written\n const head = compiled.slice(0, marker).trimEnd()\n const params = (head.endsWith(\"=>\") ? head.slice(0, -2) : head).trim()\n return params.startsWith(\"(\") && params.endsWith(\")\") ? params.slice(1, -1).trim() : params\n}\n\n// the signature back into a double-quoted attribute. Only `\"` needs escaping:\n// the transforms normalize string literals to double quotes, so a default the\n// author wrote as `'x'` comes back as `\"x\"` and would end the attribute early.\n// `&` is deliberately left alone - `&&` in a default is not an entity and\n// survives the parse, while escaping it would double-encode a source that\n// already wrote `"`\nconst quoteAttrValue = (value: string) => value.replace(/\"/g, \""\")\n\n// compiles TypeScript script blocks to plain JS, so the runtime only ever sees\n// JS - the same deal <style lang=\"scss\"> gets, for a sharper reason. The setup\n// scanner is not a parser: `let count: number = 0` reaching it is not a syntax\n// error but a labeled statement that assigns to `number`, so it runs and leaves\n// `count` undeclared. Whichever attribute marked the block (`lang=\"ts\"` or\n// `type=\"text/typescript\"`) is dropped from the emitted tag and every other one\n// (`:setup`, `:mounted`) is left as written.\n//\n// This runs before hoistableImports reads the source, so an `import type`\n// specifier is already gone by the time the plugin decides what to bundle\nconst compileScriptBlocks = async (source: string, file: string): Promise<string> => {\n const blocks = [...source.matchAll(SCRIPT_BLOCK_RE)]\n const compiled = await Promise.all(\n blocks.map(async ([, attrs, content]) => {\n const marker = typescriptAttr(attrs)\n if (!marker) return null\n\n let rest = attrs.replace(marker, \"\").trimEnd()\n const setup = rest.match(SETUP_ATTR_RE)\n if (setup) {\n const signature = await stripSignatureTypes(setup[2] ?? setup[3], `${file}.signature.ts`)\n // a function replacement, not a string: `$&` and friends are live in a\n // replacement string and a default value is arbitrary source\n rest = rest.replace(SETUP_ATTR_RE, () => `${setup[1]}\"${quoteAttrValue(signature)}\"`)\n }\n\n return { attrs: rest, js: await stripTypes(content, `${file}.ts`) }\n })\n )\n\n let out = \"\"\n let last = 0\n blocks.forEach((block, i) => {\n const done = compiled[i]\n if (!done) return\n out += source.slice(last, block.index) + `<script${done.attrs}>${done.js}</script>`\n last = block.index + block[0].length\n })\n return out + source.slice(last)\n}\n\n// the emitted module. Literal import(\"...\") specifiers found in the\n// component's scripts become real module imports, handed to Component79 as a\n// resolution map: at runtime $__import checks the map before falling back to\n// fetch, so bundled components ship with their imports and nothing changes\n// for unbundled ones. Claimed components import as their default (a\n// Component79, matching what runtime fetch resolves to); everything else as\n// a namespace (matching native import()).\n//\n// A file's <template name=\"…\"> components are re-exported by name, so the\n// module shape is the one the file already has: default plus named. They read\n// off the instance, which is where the runtime hangs them - so in dev they are\n// bound to the *first* evaluation's definitions and a module that imports one\n// by name keeps the pre-edit child until the page reloads. The file's own\n// component patches in place, and its rendered children come from the reparse,\n// so this only shows in a component imported by name from another file.\n//\n// In dev, `hot.data` carries the exported instance across updates: importers\n// hold a reference to the *first* module evaluation's instance, so later\n// evaluations patch that same instance in place instead of exporting a new one\n// nobody sees. The patching itself is the runtime's `hotReplace` - the same\n// swap the jq79/dev server drives, from the one place that can reach a\n// component's markers. An instance only used as a definition has nothing to\n// re-render (nested clones can't be reached from this module), so it falls\n// back to a full reload.\n// `precompiled` is the precompiled script's URL, as a JS expression - present\n// only in safeEval mode\nconst componentModule = (source: string, include: RegExp, filename: string, precompiled?: string): string => {\n const hoisted = hoistableImports(source, include)\n const imports = hoisted\n .map((spec, i) =>\n include.test(spec)\n ? `import __jq79_${i} from ${JSON.stringify(spec)}`\n : `import * as __jq79_${i} from ${JSON.stringify(spec)}`\n )\n .join(\"\\n\")\n const modulesMap = `{ ${hoisted.map((spec, i) => `${JSON.stringify(spec)}: __jq79_${i}`).join(\", \")} }`\n\n // without safeEval, the module is exactly what it always was\n const safeEvalImport = precompiled ? `\\nimport { safeEval } from \"${SAFE_EVAL_ID}\"` : \"\"\n const safeEvalCall = precompiled ? `\\nawait safeEval(Component79, ${precompiled})` : \"\"\n\n return `\nimport { Component79 } from \"jq79\"${safeEvalImport}\n${imports}${safeEvalCall}\n\nconst src = ${JSON.stringify(source)}\nconst modules = ${modulesMap}\nconst filename = ${JSON.stringify(filename)}\n\nlet component\n\nif (import.meta.hot && import.meta.hot.data.component) {\n const prior = import.meta.hot.data.component\n prior.modules = modules\n prior.filename = filename\n // re-renders it where it stands, keeping its data. false means it was never\n // rendered - a definition used only as a nested component - and a reload is\n // the only way to reach the clones made from it\n if (!prior.hotReplace(src) && !prior.data) import.meta.hot.invalidate()\n component = prior\n} else {\n component = new Component79(src, { modules, filename })\n}\n\nif (import.meta.hot) {\n import.meta.hot.data.component = component\n import.meta.hot.accept()\n}\n\nexport default component\n${declaredComponents(source).map(name => `export const ${name} = component.${name}`).join(\"\\n\")}\n`\n}\n\nexport function jq79(options: Jq79PluginOptions = {}): Plugin {\n const include = options.include ?? /\\.html$/\n const { exclude } = options\n const safeEval = safeEvalOptions(options.safeEval)\n // dev only: each component's precompiled script, by the id its module asks\n // for - so the server hands out what the plugin compiled and nothing else\n const devScripts = new Map<string, string>()\n const devIds = new Map<string, number>()\n\n let config: ResolvedConfig | null = null\n\n return {\n name: \"jq79\",\n enforce: \"pre\",\n\n configResolved(resolved) {\n config = resolved\n },\n\n configureServer(server) {\n if (!safeEval) return\n server.middlewares.use((req, res, next) => {\n const url = new URL(req.url ?? \"/\", \"http://localhost\")\n if (!url.pathname.endsWith(PRECOMPILED_PATH)) return next()\n const script = devScripts.get(url.searchParams.get(\"id\") ?? \"\")\n if (script === undefined) return next()\n res.setHeader(\"Content-Type\", \"text/javascript\")\n res.setHeader(\"Cache-Control\", \"no-cache\")\n res.end(script)\n })\n },\n\n async resolveId(source, importer) {\n if (source === SAFE_EVAL_ID) return RESOLVED_SAFE_EVAL_ID\n if (!importer) return null // entry points are never components\n if (source.includes(\"?\")) return null // ?raw, ?url, ... keep their meaning\n if (!include.test(source)) return null\n\n const resolved = await this.resolve(source, importer, { skipSelf: true })\n if (!resolved || resolved.external) return null\n if (exclude?.test(resolved.id)) return null\n return resolved.id + COMPONENT_QUERY\n },\n\n async load(id) {\n // a Vite page's functions come from the build, so it never registers the worker\n if (id === RESOLVED_SAFE_EVAL_ID) return safeEvalModule({ ...safeEval, worker: false })\n if (!id.endsWith(COMPONENT_QUERY)) return null\n const file = id.slice(0, -COMPONENT_QUERY.length)\n\n let source = await readFile(file, \"utf8\")\n source = await compileScriptBlocks(source, file)\n if (config) source = await compileStyleBlocks(source, file, config, dep => this.addWatchFile(dep))\n\n // the runtime names the component's setup scripts after this, so devtools\n // shows a path the user recognizes instead of an anonymous VM script\n const filename = config ? relative(config.root, file) : file\n\n if (!safeEval) return { code: componentModule(source, include, filename), map: null }\n\n // the component's functions, compiled after its TypeScript and styles are:\n // the runtime compiles what reaches it, and this is what reaches it\n const script = componentScript(source, message => this.warn(`jq79: ${filename}: ${message}`))\n let url: string\n if (config?.command === \"serve\") {\n let devId = devIds.get(file)\n if (devId === undefined) devIds.set(file, devId = devIds.size)\n devScripts.set(String(devId), script)\n // versioned, so an edit loads the new functions rather than a cached copy\n url = JSON.stringify(`${config.base}${PRECOMPILED_PATH.slice(1)}?id=${devId}&v=${Date.now()}`)\n } else {\n const ref = this.emitFile({ type: \"asset\", name: `${basename(file)}.jq79.js`, source: script })\n url = `import.meta.ROLLUP_FILE_URL_${ref}`\n }\n return { code: componentModule(source, include, filename, url), map: null }\n },\n }\n}\n\nexport default jq79\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jq79",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"description": "Mini reactive component library: single-file .html components, Svelte-style setup scripts, fine-grained proxy reactivity. No compiler, no bundler, no dependencies — works from any static host.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -31,6 +31,13 @@
|
|
|
31
31
|
"require": "./dist/jq79.cjs",
|
|
32
32
|
"default": "./dist/jq79.js"
|
|
33
33
|
},
|
|
34
|
+
"./precompile": {
|
|
35
|
+
"types": "./dist/precompile.d.ts",
|
|
36
|
+
"import": "./dist/precompile.js",
|
|
37
|
+
"require": "./dist/precompile.cjs",
|
|
38
|
+
"default": "./dist/precompile.js"
|
|
39
|
+
},
|
|
40
|
+
"./jq79-sw.js": "./dist/jq79-sw.js",
|
|
34
41
|
"./vite": {
|
|
35
42
|
"types": "./dist/vite.d.ts",
|
|
36
43
|
"import": "./dist/vite.js",
|
|
@@ -58,7 +65,7 @@
|
|
|
58
65
|
"sideEffects": false,
|
|
59
66
|
"scripts": {
|
|
60
67
|
"build": "tsup && npm run types.lib && npm run types.dev",
|
|
61
|
-
"types.lib": "tsc src/jq79.ts --rootDir src --declaration --emitDeclarationOnly --strict --skipLibCheck --lib dom,es2021 --target es2020 --module es2020 --moduleResolution bundler --outDir dist",
|
|
68
|
+
"types.lib": "tsc src/jq79.ts src/precompile.ts --rootDir src --declaration --emitDeclarationOnly --strict --skipLibCheck --lib dom,es2021 --target es2020 --module es2020 --moduleResolution bundler --outDir dist",
|
|
62
69
|
"types.dev": "tsc dev/vite.ts dev/dev.ts --rootDir dev --declaration --emitDeclarationOnly --strict --skipLibCheck --lib dom,es2021 --target es2020 --module es2020 --moduleResolution bundler --outDir dist",
|
|
63
70
|
"test": "vitest run",
|
|
64
71
|
"test:coverage": "vitest run --coverage",
|
|
@@ -70,6 +77,8 @@
|
|
|
70
77
|
"benchmark:once": "node scripts/run-once-render.mjs",
|
|
71
78
|
"check:svg-names": "node scripts/check-svg-attribute-names.mjs",
|
|
72
79
|
"check:box": "node scripts/check-box-layout.mjs",
|
|
80
|
+
"check:csp": "node scripts/check-csp.mjs",
|
|
81
|
+
"check:precompile": "vitest run --config vitest.precompile.config.ts",
|
|
73
82
|
"prepublishOnly": "npm test && npm run build"
|
|
74
83
|
},
|
|
75
84
|
"peerDependencies": {
|
|
@@ -83,6 +92,7 @@
|
|
|
83
92
|
"devDependencies": {
|
|
84
93
|
"@types/node": "^26.1.1",
|
|
85
94
|
"@vitest/coverage-istanbul": "^4.1.10",
|
|
95
|
+
"acorn": "^8.18.0",
|
|
86
96
|
"chokidar": "^5.0.0",
|
|
87
97
|
"highlight.js": "^11.11.1",
|
|
88
98
|
"jsdom": "^29.1.1",
|
package/src/dom.ts
CHANGED
|
@@ -1,18 +1,42 @@
|
|
|
1
1
|
// DOM helpers: tiny query/create utilities, also injected into component
|
|
2
2
|
// scripts as $, $$ and $create
|
|
3
3
|
|
|
4
|
+
// what a query answers with (RECORD/2026-10-01.typed-queries.md): a tag name
|
|
5
|
+
// gives its own element, HTML first and then SVG, as querySelector's types
|
|
6
|
+
// do; any other selector an HTMLElement - not querySelector's Element, because
|
|
7
|
+
// what a component looks up is HTML almost every time - or whatever the type
|
|
8
|
+
// argument says. Exported for $self / $$self, typed the same way
|
|
9
|
+
export type QueryOne = {
|
|
10
|
+
<K extends keyof HTMLElementTagNameMap>(selector: K): HTMLElementTagNameMap[K] | null
|
|
11
|
+
<K extends keyof SVGElementTagNameMap>(selector: K): SVGElementTagNameMap[K] | null
|
|
12
|
+
<E extends Element = HTMLElement>(selector: string): E | null
|
|
13
|
+
}
|
|
14
|
+
export type QueryAll = {
|
|
15
|
+
<K extends keyof HTMLElementTagNameMap>(selector: K): HTMLElementTagNameMap[K][]
|
|
16
|
+
<K extends keyof SVGElementTagNameMap>(selector: K): SVGElementTagNameMap[K][]
|
|
17
|
+
<E extends Element = HTMLElement>(selector: string): E[]
|
|
18
|
+
}
|
|
19
|
+
|
|
4
20
|
// $(selector) queries the document; $(el, selector) queries within el. The
|
|
5
21
|
// selector is required in the element form - an empty one is a SyntaxError
|
|
6
|
-
export function
|
|
7
|
-
export function
|
|
22
|
+
export function $<K extends keyof HTMLElementTagNameMap>(selector: K): HTMLElementTagNameMap[K] | null
|
|
23
|
+
export function $<K extends keyof SVGElementTagNameMap>(selector: K): SVGElementTagNameMap[K] | null
|
|
24
|
+
export function $<E extends Element = HTMLElement>(selector: string): E | null
|
|
25
|
+
export function $<K extends keyof HTMLElementTagNameMap>(el: Element, selector: K): HTMLElementTagNameMap[K] | null
|
|
26
|
+
export function $<K extends keyof SVGElementTagNameMap>(el: Element, selector: K): SVGElementTagNameMap[K] | null
|
|
27
|
+
export function $<E extends Element = HTMLElement>(el: Element, selector: string): E | null
|
|
8
28
|
export function $(selectorOrEl: string | Element, selector?: string): Element | null {
|
|
9
29
|
return typeof selectorOrEl === "string"
|
|
10
30
|
? document.querySelector(selectorOrEl)
|
|
11
31
|
: selectorOrEl.querySelector(selector!)
|
|
12
32
|
}
|
|
13
33
|
|
|
14
|
-
export function
|
|
15
|
-
export function
|
|
34
|
+
export function $$<K extends keyof HTMLElementTagNameMap>(selector: K): HTMLElementTagNameMap[K][]
|
|
35
|
+
export function $$<K extends keyof SVGElementTagNameMap>(selector: K): SVGElementTagNameMap[K][]
|
|
36
|
+
export function $$<E extends Element = HTMLElement>(selector: string): E[]
|
|
37
|
+
export function $$<K extends keyof HTMLElementTagNameMap>(el: Element, selector: K): HTMLElementTagNameMap[K][]
|
|
38
|
+
export function $$<K extends keyof SVGElementTagNameMap>(el: Element, selector: K): SVGElementTagNameMap[K][]
|
|
39
|
+
export function $$<E extends Element = HTMLElement>(el: Element, selector: string): E[]
|
|
16
40
|
export function $$(selectorOrEl: string | Element, selector?: string): Element[] {
|
|
17
41
|
return Array.from(
|
|
18
42
|
typeof selectorOrEl === "string"
|