jq79 0.4.0 → 0.4.2

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 CHANGED
@@ -7,8 +7,8 @@
7
7
 
8
8
  [![npm](https://jgermade.github.io/jq79/badges/npm.svg)](https://www.npmjs.com/package/jq79)
9
9
  [![coverage](https://jgermade.github.io/jq79/badges/coverage.svg)](https://jgermade.github.io/jq79/coverage/)
10
- [![esm](https://jgermade.github.io/jq79/badges/esm-size.svg)](https://jgermade.github.io/jq79/)
11
- [![cjs](https://jgermade.github.io/jq79/badges/cjs-size.svg)](https://jgermade.github.io/jq79/)
10
+ [![esm](https://jgermade.github.io/jq79/badges/esm-size.svg)](#cdn)
11
+ [![cdn](https://jgermade.github.io/jq79/badges/cjs-size.svg)](#cdn)
12
12
 
13
13
  A independent reactive component library that ships as a single file. Svelte-style reactive scripts, fine-grained DOM updates via proxy-based dependency tracking
14
14
 
package/dev/dev.ts CHANGED
@@ -92,7 +92,8 @@ const isDocument = (req: IncomingMessage) => req.headers["sec-fetch-dest"] === "
92
92
  // fall back to the top of it rather than skipping the injection
93
93
  const injectClient = (html: string): string => {
94
94
  const tag = `<script src="${CLIENT_URL}"></script>`
95
- const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html)
95
+ // (\s[^>]*)? rather than [^>]*, or <header> would pass for <head>
96
+ const open = /<head(\s[^>]*)?>/i.exec(html) ?? /<body(\s[^>]*)?>/i.exec(html)
96
97
  if (!open) return tag + html
97
98
  const at = open.index + open[0].length
98
99
  return html.slice(0, at) + tag + html.slice(at)
@@ -130,7 +131,16 @@ export const devServer = async (options: DevServerOptions = {}): Promise<DevServ
130
131
  }
131
132
 
132
133
  try {
133
- if ((await stat(file)).isDirectory()) file = join(file, "index.html")
134
+ if ((await stat(file)).isDirectory()) {
135
+ // a directory is served through its trailing-slash URL, like every
136
+ // static host: /docs rendered as-is would resolve its relative links
137
+ // against the parent ("img.png" -> /img.png instead of /docs/img.png)
138
+ if (!pathname.endsWith("/")) {
139
+ res.writeHead(301, { location: pathname + "/" }).end()
140
+ return
141
+ }
142
+ file = join(file, "index.html")
143
+ }
134
144
  const body = await readFile(file)
135
145
  const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? "application/octet-stream"
136
146
 
package/dev/vite.ts CHANGED
@@ -33,13 +33,57 @@ export interface Jq79PluginOptions {
33
33
  const COMPONENT_QUERY = "?jq79"
34
34
 
35
35
  const SCRIPT_BLOCK_RE = /<script\b[^>]*>([\s\S]*?)<\/script\s*>/gi
36
- // import("...") with a literal specifier; the lookbehind skips $__import and
37
- // property accesses like foo.import(...)
38
- const IMPORT_LITERAL_RE = /(?<![\w$.])import\s*\(\s*(["'])([^"'\n]+?)\1\s*\)/g
36
+ // import("...") with a literal specifier, tried at word boundaries the
37
+ // scanner below reaches (which is what skips $__import and foo.import(...))
38
+ const IMPORT_CALL_RE = /import\s*\(\s*(["'])([^"'\n]+?)\1\s*\)/y
39
39
  // static import statements (factory scripts): optional clause + literal
40
40
  // specifier. The clause can't contain parens/quotes, so dynamic import()
41
41
  // and import.meta never match
42
- const STATIC_IMPORT_LITERAL_RE = /(?<![\w$.])import\s*(?:[\w$\s,{}*]+?\s*from\s*)?(["'])([^"'\n]+)\1/g
42
+ const STATIC_IMPORT_RE = /import\s*(?:[\w$\s,{}*]+?\s*from\s*)?(["'])([^"'\n]+)\1/y
43
+
44
+ const skipString = (src: string, start: number): number => {
45
+ const quote = src[start]
46
+ let i = start + 1
47
+ while (i < src.length) {
48
+ if (src[i] === "\\") { i += 2; continue }
49
+ if (src[i] === quote) return i + 1
50
+ i++
51
+ }
52
+ return src.length
53
+ }
54
+
55
+ // the literal import specifiers in one script body. A scanner rather than a
56
+ // bare matchAll, because a specifier mentioned in a comment or a string is
57
+ // not an import: hoisting a commented-out `import("./old.html")` would pull
58
+ // dead files into the bundle - or break the build once the file is gone
59
+ const importSpecifiers = (script: string): string[] => {
60
+ const specs: string[] = []
61
+ let i = 0
62
+ while (i < script.length) {
63
+ const ch = script[i]
64
+ if (ch === "'" || ch === '"' || ch === "`") { i = skipString(script, i); continue }
65
+ if (ch === "/" && script[i + 1] === "/") {
66
+ const end = script.indexOf("\n", i)
67
+ i = end === -1 ? script.length : end + 1
68
+ continue
69
+ }
70
+ if (ch === "/" && script[i + 1] === "*") {
71
+ const end = script.indexOf("*/", i + 2)
72
+ i = end === -1 ? script.length : end + 2
73
+ continue
74
+ }
75
+ if (ch === "i" && (i === 0 || !/[\w$.]/.test(script[i - 1]))) {
76
+ IMPORT_CALL_RE.lastIndex = i
77
+ const call = IMPORT_CALL_RE.exec(script)
78
+ if (call) { specs.push(call[2]); i = IMPORT_CALL_RE.lastIndex; continue }
79
+ STATIC_IMPORT_RE.lastIndex = i
80
+ const staticImport = STATIC_IMPORT_RE.exec(script)
81
+ if (staticImport) { specs.push(staticImport[2]); i = STATIC_IMPORT_RE.lastIndex; continue }
82
+ }
83
+ i++
84
+ }
85
+ return specs
86
+ }
43
87
 
44
88
  const isHtmlUrl = (spec: string) => /\.html?([?#]|$)/.test(spec)
45
89
  const isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spec.startsWith("/")
@@ -52,11 +96,7 @@ const isExternalUrl = (spec: string) => /^[a-z][a-z0-9+.-]*:/i.test(spec) || spe
52
96
  const hoistableImports = (source: string, include: RegExp): string[] => {
53
97
  const specifiers = new Set<string>()
54
98
  for (const [, script] of source.matchAll(SCRIPT_BLOCK_RE)) {
55
- const specs = [
56
- ...[...script.matchAll(IMPORT_LITERAL_RE)].map(match => match[2]),
57
- ...[...script.matchAll(STATIC_IMPORT_LITERAL_RE)].map(match => match[2]),
58
- ]
59
- for (const spec of specs) {
99
+ for (const spec of importSpecifiers(script)) {
60
100
  if (isExternalUrl(spec)) continue
61
101
  if (isHtmlUrl(spec) && !include.test(spec)) continue // html left to runtime fetch
62
102
  specifiers.add(spec) // a claimed component, a source file or an npm package
package/dist/cli.js CHANGED
@@ -46,7 +46,7 @@ var posix = (path) => path.split(sep).join("/");
46
46
  var isDocument = (req) => req.headers["sec-fetch-dest"] === "document";
47
47
  var injectClient = (html) => {
48
48
  const tag = `<script src="${CLIENT_URL}"></script>`;
49
- const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html);
49
+ const open = /<head(\s[^>]*)?>/i.exec(html) ?? /<body(\s[^>]*)?>/i.exec(html);
50
50
  if (!open) return tag + html;
51
51
  const at = open.index + open[0].length;
52
52
  return html.slice(0, at) + tag + html.slice(at);
@@ -75,7 +75,13 @@ data: ${JSON.stringify(data)}
75
75
  return;
76
76
  }
77
77
  try {
78
- if ((await stat(file)).isDirectory()) file = join(file, "index.html");
78
+ if ((await stat(file)).isDirectory()) {
79
+ if (!pathname.endsWith("/")) {
80
+ res.writeHead(301, { location: pathname + "/" }).end();
81
+ return;
82
+ }
83
+ file = join(file, "index.html");
84
+ }
79
85
  const body = await readFile(file);
80
86
  const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? "application/octet-stream";
81
87
  const html = type.startsWith("text/html") && isDocument(req);
package/dist/dev.cjs CHANGED
@@ -68,7 +68,7 @@ var posix = (path) => path.split(import_node_path.sep).join("/");
68
68
  var isDocument = (req) => req.headers["sec-fetch-dest"] === "document";
69
69
  var injectClient = (html) => {
70
70
  const tag = `<script src="${CLIENT_URL}"></script>`;
71
- const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html);
71
+ const open = /<head(\s[^>]*)?>/i.exec(html) ?? /<body(\s[^>]*)?>/i.exec(html);
72
72
  if (!open) return tag + html;
73
73
  const at = open.index + open[0].length;
74
74
  return html.slice(0, at) + tag + html.slice(at);
@@ -97,7 +97,13 @@ data: ${JSON.stringify(data)}
97
97
  return;
98
98
  }
99
99
  try {
100
- if ((await (0, import_promises.stat)(file)).isDirectory()) file = (0, import_node_path.join)(file, "index.html");
100
+ if ((await (0, import_promises.stat)(file)).isDirectory()) {
101
+ if (!pathname.endsWith("/")) {
102
+ res.writeHead(301, { location: pathname + "/" }).end();
103
+ return;
104
+ }
105
+ file = (0, import_node_path.join)(file, "index.html");
106
+ }
101
107
  const body = await (0, import_promises.readFile)(file);
102
108
  const type = CONTENT_TYPES[(0, import_node_path.extname)(file).toLowerCase()] ?? "application/octet-stream";
103
109
  const html = type.startsWith("text/html") && isDocument(req);
package/dist/dev.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../dev/dev.ts"],"sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport { readFile, realpath, stat } from \"node:fs/promises\"\nimport { watch, type FSWatcher } from \"node:fs\"\nimport { basename, extname, join, relative, resolve, sep } from \"node:path\"\n\n// A dev server for the no-bundle path: serve a directory of .html components\n// over HTTP, watch it, and hot-reload the components that changed.\n//\n// npx jq79 dev // the CLI\n// import { devServer } from \"jq79/dev\" // or from a script\n// await devServer({ rootDir: \".\" })\n//\n// It is a static file server and nothing else - no transforms, no bundling, no\n// module graph. Which is the point: the files it serves are the files you would\n// deploy, so what you develop against and what a static host serves are the same\n// bytes. The one thing it adds is the hot-reload channel, and it adds it to\n// *documents* only (a component fetched by the runtime is served verbatim).\n//\n// The reload is fine-grained. On a change the server pushes the new source down\n// an SSE channel and the runtime swaps it into every live instance of that file,\n// keeping its data - see hotUpdate in jq79.ts. Anything the runtime can't place\n// (a page, a stylesheet, a component nothing has mounted yet) falls back to a\n// full page reload.\n\nexport interface DevServerOptions {\n // the directory to serve, and to watch (default: the current directory)\n rootDir?: string\n // default: 4179, or the first free port after it\n port?: number\n // default: localhost\n host?: string\n}\n\nexport interface DevServer {\n url: string\n port: number\n close: () => Promise<void>\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json; charset=utf-8\",\n}\n\nconst CLIENT_URL = \"/__jq79/client.js\"\nconst EVENTS_URL = \"/__jq79/events\"\n\n// Served as a *classic* script, and injected into the <head>: classic scripts\n// run at parse time and module scripts are deferred, so the flag is set before\n// the page's `import ... from \"jq79\"` evaluates - which is what the runtime\n// waits for before it starts tracking instances. The client can't import the\n// runtime itself: the page's copy may come from a CDN or an import map, and a\n// second copy would have a second, empty registry.\nconst CLIENT = `(() => {\n window.__JQ79_HMR_ENABLED__ = true\n\n const events = new EventSource(${JSON.stringify(EVENTS_URL)})\n\n events.addEventListener(\"update\", event => {\n const { url, src } = JSON.parse(event.data)\n const runtime = window.__JQ79_HMR__\n // no runtime (the page doesn't use jq79), or no live instance from this\n // file (it isn't mounted, or it *is* the page) - nothing to swap into\n const patched = runtime ? runtime.update(url, src) : 0\n if (patched) console.log(\"[jq79] hot-updated \" + url + \" (\" + patched + (patched === 1 ? \" instance)\" : \" instances)\"))\n else location.reload()\n })\n\n events.addEventListener(\"reload\", () => location.reload())\n})()`\n\nconst posix = (path: string) => path.split(sep).join(\"/\")\n\nconst isDocument = (req: IncomingMessage) => req.headers[\"sec-fetch-dest\"] === \"document\"\n\n// the client goes in the <head> so it is the first thing the page runs. A file\n// with neither <head> nor <body> is still a document a browser will render, so\n// fall back to the top of it rather than skipping the injection\nconst injectClient = (html: string): string => {\n const tag = `<script src=\"${CLIENT_URL}\"></script>`\n const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html)\n if (!open) return tag + html\n const at = open.index + open[0].length\n return html.slice(0, at) + tag + html.slice(at)\n}\n\nexport const devServer = async (options: DevServerOptions = {}): Promise<DevServer> => {\n // the *real* path: the watcher reports what changed relative to the directory\n // it actually opened, so a root reached through a symlink (/tmp and /var are\n // symlinks on macOS) would hand back paths that don't line up with it\n const root = await realpath(resolve(options.rootDir ?? \".\"))\n const host = options.host ?? \"localhost\"\n\n const clients = new Set<ServerResponse>()\n\n const send = (event: string, data: unknown) => {\n const frame = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`\n clients.forEach(client => client.write(frame))\n }\n\n // --- serving ---------------------------------------------------------------\n\n const serveStatic = async (req: IncomingMessage, res: ServerResponse, pathname: string) => {\n // a URL path is not a file path: decode it, then keep the result inside the\n // root (\"..\" in a request must not walk out of the served directory)\n let file: string\n try {\n file = resolve(join(root, decodeURIComponent(pathname)))\n } catch {\n res.writeHead(400).end(\"bad request\")\n return\n }\n if (file !== root && !file.startsWith(root + sep)) {\n res.writeHead(403).end(\"forbidden\")\n return\n }\n\n try {\n if ((await stat(file)).isDirectory()) file = join(file, \"index.html\")\n const body = await readFile(file)\n const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\"\n\n // only a navigation gets the hot-reload client. A component is fetched by\n // the runtime (sec-fetch-dest: empty), and it must arrive as written -\n // injecting a <script> into it would make the runtime parse and run it\n const html = type.startsWith(\"text/html\") && isDocument(req)\n const payload = html ? Buffer.from(injectClient(body.toString(\"utf8\"))) : body\n\n res.writeHead(200, {\n \"content-type\": type,\n \"content-length\": payload.byteLength,\n \"cache-control\": \"no-store\", // the file on disk is always the truth here\n })\n res.end(payload)\n } catch {\n res.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(\"not found\")\n }\n }\n\n const server: Server = createServer((req, res) => {\n const pathname = (req.url ?? \"/\").split(/[?#]/)[0]\n\n if (pathname === CLIENT_URL) {\n res.writeHead(200, { \"content-type\": \"text/javascript; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(CLIENT)\n return\n }\n\n if (pathname === EVENTS_URL) {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store\",\n connection: \"keep-alive\",\n })\n res.write(\": jq79\\n\\n\") // opens the stream, so the browser fires onopen\n clients.add(res)\n req.on(\"close\", () => clients.delete(res))\n return\n }\n\n void serveStatic(req, res, pathname)\n })\n\n // --- watching --------------------------------------------------------------\n\n const ignored = (rel: string) =>\n rel.split(sep).some(part => part.startsWith(\".\") || part === \"node_modules\")\n\n // one save can arrive as several events (a rename plus a change, an editor's\n // atomic write); collapsing per file keeps that down to one push\n const pending = new Map<string, NodeJS.Timeout>()\n\n const changed = async (rel: string) => {\n const file = join(root, rel)\n\n let src: string | null = null\n try {\n // a directory changes whenever anything inside it does, and the event for\n // the file itself is already on its way - acting on both would reload the\n // page every time a component is saved\n if ((await stat(file)).isDirectory()) return\n if (rel.endsWith(\".html\")) src = await readFile(file, \"utf8\")\n } catch {\n // gone: deleted, or renamed away - and there is nothing to swap in, so the\n // page has to reload. Unless it was never there: macOS reports a change to\n // the watched directory *itself* under its own basename, which resolves to\n // a path inside it that does not exist\n if (rel === basename(root)) return\n }\n\n // the url is the one the component was served from, because that is what the\n // runtime resolves its instances' filenames against\n const url = \"/\" + posix(rel)\n if (src === null) send(\"reload\", { url })\n else send(\"update\", { url, src })\n }\n\n const watcher: FSWatcher = watch(root, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const rel = relative(root, resolve(root, filename.toString()))\n if (!rel || rel.startsWith(\"..\") || ignored(rel)) return\n\n clearTimeout(pending.get(rel))\n pending.set(rel, setTimeout(() => {\n pending.delete(rel)\n void changed(rel)\n }, 30))\n })\n\n // proxies and load balancers cut an idle stream; a comment every 30s is the\n // conventional way to keep it open. unref'd, so it never holds the process up\n const heartbeat = setInterval(() => clients.forEach(client => client.write(\": ping\\n\\n\")), 30_000)\n heartbeat.unref()\n\n // --- go --------------------------------------------------------------------\n\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail)\n server.listen(options.port ?? 4179, host, done)\n })\n const { port } = server.address() as { port: number }\n\n return {\n url: `http://${host}:${port}`,\n port,\n close: () =>\n new Promise(done => {\n clearInterval(heartbeat)\n watcher.close()\n pending.forEach(clearTimeout)\n clients.forEach(client => client.end())\n clients.clear()\n server.close(() => done())\n }),\n }\n}\n\nexport default devServer\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../dev/dev.ts"],"sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport { readFile, realpath, stat } from \"node:fs/promises\"\nimport { watch, type FSWatcher } from \"node:fs\"\nimport { basename, extname, join, relative, resolve, sep } from \"node:path\"\n\n// A dev server for the no-bundle path: serve a directory of .html components\n// over HTTP, watch it, and hot-reload the components that changed.\n//\n// npx jq79 dev // the CLI\n// import { devServer } from \"jq79/dev\" // or from a script\n// await devServer({ rootDir: \".\" })\n//\n// It is a static file server and nothing else - no transforms, no bundling, no\n// module graph. Which is the point: the files it serves are the files you would\n// deploy, so what you develop against and what a static host serves are the same\n// bytes. The one thing it adds is the hot-reload channel, and it adds it to\n// *documents* only (a component fetched by the runtime is served verbatim).\n//\n// The reload is fine-grained. On a change the server pushes the new source down\n// an SSE channel and the runtime swaps it into every live instance of that file,\n// keeping its data - see hotUpdate in jq79.ts. Anything the runtime can't place\n// (a page, a stylesheet, a component nothing has mounted yet) falls back to a\n// full page reload.\n\nexport interface DevServerOptions {\n // the directory to serve, and to watch (default: the current directory)\n rootDir?: string\n // default: 4179, or the first free port after it\n port?: number\n // default: localhost\n host?: string\n}\n\nexport interface DevServer {\n url: string\n port: number\n close: () => Promise<void>\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json; charset=utf-8\",\n}\n\nconst CLIENT_URL = \"/__jq79/client.js\"\nconst EVENTS_URL = \"/__jq79/events\"\n\n// Served as a *classic* script, and injected into the <head>: classic scripts\n// run at parse time and module scripts are deferred, so the flag is set before\n// the page's `import ... from \"jq79\"` evaluates - which is what the runtime\n// waits for before it starts tracking instances. The client can't import the\n// runtime itself: the page's copy may come from a CDN or an import map, and a\n// second copy would have a second, empty registry.\nconst CLIENT = `(() => {\n window.__JQ79_HMR_ENABLED__ = true\n\n const events = new EventSource(${JSON.stringify(EVENTS_URL)})\n\n events.addEventListener(\"update\", event => {\n const { url, src } = JSON.parse(event.data)\n const runtime = window.__JQ79_HMR__\n // no runtime (the page doesn't use jq79), or no live instance from this\n // file (it isn't mounted, or it *is* the page) - nothing to swap into\n const patched = runtime ? runtime.update(url, src) : 0\n if (patched) console.log(\"[jq79] hot-updated \" + url + \" (\" + patched + (patched === 1 ? \" instance)\" : \" instances)\"))\n else location.reload()\n })\n\n events.addEventListener(\"reload\", () => location.reload())\n})()`\n\nconst posix = (path: string) => path.split(sep).join(\"/\")\n\nconst isDocument = (req: IncomingMessage) => req.headers[\"sec-fetch-dest\"] === \"document\"\n\n// the client goes in the <head> so it is the first thing the page runs. A file\n// with neither <head> nor <body> is still a document a browser will render, so\n// fall back to the top of it rather than skipping the injection\nconst injectClient = (html: string): string => {\n const tag = `<script src=\"${CLIENT_URL}\"></script>`\n // (\\s[^>]*)? rather than [^>]*, or <header> would pass for <head>\n const open = /<head(\\s[^>]*)?>/i.exec(html) ?? /<body(\\s[^>]*)?>/i.exec(html)\n if (!open) return tag + html\n const at = open.index + open[0].length\n return html.slice(0, at) + tag + html.slice(at)\n}\n\nexport const devServer = async (options: DevServerOptions = {}): Promise<DevServer> => {\n // the *real* path: the watcher reports what changed relative to the directory\n // it actually opened, so a root reached through a symlink (/tmp and /var are\n // symlinks on macOS) would hand back paths that don't line up with it\n const root = await realpath(resolve(options.rootDir ?? \".\"))\n const host = options.host ?? \"localhost\"\n\n const clients = new Set<ServerResponse>()\n\n const send = (event: string, data: unknown) => {\n const frame = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`\n clients.forEach(client => client.write(frame))\n }\n\n // --- serving ---------------------------------------------------------------\n\n const serveStatic = async (req: IncomingMessage, res: ServerResponse, pathname: string) => {\n // a URL path is not a file path: decode it, then keep the result inside the\n // root (\"..\" in a request must not walk out of the served directory)\n let file: string\n try {\n file = resolve(join(root, decodeURIComponent(pathname)))\n } catch {\n res.writeHead(400).end(\"bad request\")\n return\n }\n if (file !== root && !file.startsWith(root + sep)) {\n res.writeHead(403).end(\"forbidden\")\n return\n }\n\n try {\n if ((await stat(file)).isDirectory()) {\n // a directory is served through its trailing-slash URL, like every\n // static host: /docs rendered as-is would resolve its relative links\n // against the parent (\"img.png\" -> /img.png instead of /docs/img.png)\n if (!pathname.endsWith(\"/\")) {\n res.writeHead(301, { location: pathname + \"/\" }).end()\n return\n }\n file = join(file, \"index.html\")\n }\n const body = await readFile(file)\n const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\"\n\n // only a navigation gets the hot-reload client. A component is fetched by\n // the runtime (sec-fetch-dest: empty), and it must arrive as written -\n // injecting a <script> into it would make the runtime parse and run it\n const html = type.startsWith(\"text/html\") && isDocument(req)\n const payload = html ? Buffer.from(injectClient(body.toString(\"utf8\"))) : body\n\n res.writeHead(200, {\n \"content-type\": type,\n \"content-length\": payload.byteLength,\n \"cache-control\": \"no-store\", // the file on disk is always the truth here\n })\n res.end(payload)\n } catch {\n res.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(\"not found\")\n }\n }\n\n const server: Server = createServer((req, res) => {\n const pathname = (req.url ?? \"/\").split(/[?#]/)[0]\n\n if (pathname === CLIENT_URL) {\n res.writeHead(200, { \"content-type\": \"text/javascript; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(CLIENT)\n return\n }\n\n if (pathname === EVENTS_URL) {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store\",\n connection: \"keep-alive\",\n })\n res.write(\": jq79\\n\\n\") // opens the stream, so the browser fires onopen\n clients.add(res)\n req.on(\"close\", () => clients.delete(res))\n return\n }\n\n void serveStatic(req, res, pathname)\n })\n\n // --- watching --------------------------------------------------------------\n\n const ignored = (rel: string) =>\n rel.split(sep).some(part => part.startsWith(\".\") || part === \"node_modules\")\n\n // one save can arrive as several events (a rename plus a change, an editor's\n // atomic write); collapsing per file keeps that down to one push\n const pending = new Map<string, NodeJS.Timeout>()\n\n const changed = async (rel: string) => {\n const file = join(root, rel)\n\n let src: string | null = null\n try {\n // a directory changes whenever anything inside it does, and the event for\n // the file itself is already on its way - acting on both would reload the\n // page every time a component is saved\n if ((await stat(file)).isDirectory()) return\n if (rel.endsWith(\".html\")) src = await readFile(file, \"utf8\")\n } catch {\n // gone: deleted, or renamed away - and there is nothing to swap in, so the\n // page has to reload. Unless it was never there: macOS reports a change to\n // the watched directory *itself* under its own basename, which resolves to\n // a path inside it that does not exist\n if (rel === basename(root)) return\n }\n\n // the url is the one the component was served from, because that is what the\n // runtime resolves its instances' filenames against\n const url = \"/\" + posix(rel)\n if (src === null) send(\"reload\", { url })\n else send(\"update\", { url, src })\n }\n\n const watcher: FSWatcher = watch(root, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const rel = relative(root, resolve(root, filename.toString()))\n if (!rel || rel.startsWith(\"..\") || ignored(rel)) return\n\n clearTimeout(pending.get(rel))\n pending.set(rel, setTimeout(() => {\n pending.delete(rel)\n void changed(rel)\n }, 30))\n })\n\n // proxies and load balancers cut an idle stream; a comment every 30s is the\n // conventional way to keep it open. unref'd, so it never holds the process up\n const heartbeat = setInterval(() => clients.forEach(client => client.write(\": ping\\n\\n\")), 30_000)\n heartbeat.unref()\n\n // --- go --------------------------------------------------------------------\n\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail)\n server.listen(options.port ?? 4179, host, done)\n })\n const { port } = server.address() as { port: number }\n\n return {\n url: `http://${host}:${port}`,\n port,\n close: () =>\n new Promise(done => {\n clearInterval(heartbeat)\n watcher.close()\n pending.forEach(clearTimeout)\n clients.forEach(client => client.end())\n clients.clear()\n server.close(() => done())\n }),\n }\n}\n\nexport default devServer\n"],"mappings":"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","names":[]}
package/dist/dev.js CHANGED
@@ -44,7 +44,7 @@ var posix = (path) => path.split(sep).join("/");
44
44
  var isDocument = (req) => req.headers["sec-fetch-dest"] === "document";
45
45
  var injectClient = (html) => {
46
46
  const tag = `<script src="${CLIENT_URL}"></script>`;
47
- const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html);
47
+ const open = /<head(\s[^>]*)?>/i.exec(html) ?? /<body(\s[^>]*)?>/i.exec(html);
48
48
  if (!open) return tag + html;
49
49
  const at = open.index + open[0].length;
50
50
  return html.slice(0, at) + tag + html.slice(at);
@@ -73,7 +73,13 @@ data: ${JSON.stringify(data)}
73
73
  return;
74
74
  }
75
75
  try {
76
- if ((await stat(file)).isDirectory()) file = join(file, "index.html");
76
+ if ((await stat(file)).isDirectory()) {
77
+ if (!pathname.endsWith("/")) {
78
+ res.writeHead(301, { location: pathname + "/" }).end();
79
+ return;
80
+ }
81
+ file = join(file, "index.html");
82
+ }
77
83
  const body = await readFile(file);
78
84
  const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? "application/octet-stream";
79
85
  const html = type.startsWith("text/html") && isDocument(req);
package/dist/dev.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../dev/dev.ts"],"sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport { readFile, realpath, stat } from \"node:fs/promises\"\nimport { watch, type FSWatcher } from \"node:fs\"\nimport { basename, extname, join, relative, resolve, sep } from \"node:path\"\n\n// A dev server for the no-bundle path: serve a directory of .html components\n// over HTTP, watch it, and hot-reload the components that changed.\n//\n// npx jq79 dev // the CLI\n// import { devServer } from \"jq79/dev\" // or from a script\n// await devServer({ rootDir: \".\" })\n//\n// It is a static file server and nothing else - no transforms, no bundling, no\n// module graph. Which is the point: the files it serves are the files you would\n// deploy, so what you develop against and what a static host serves are the same\n// bytes. The one thing it adds is the hot-reload channel, and it adds it to\n// *documents* only (a component fetched by the runtime is served verbatim).\n//\n// The reload is fine-grained. On a change the server pushes the new source down\n// an SSE channel and the runtime swaps it into every live instance of that file,\n// keeping its data - see hotUpdate in jq79.ts. Anything the runtime can't place\n// (a page, a stylesheet, a component nothing has mounted yet) falls back to a\n// full page reload.\n\nexport interface DevServerOptions {\n // the directory to serve, and to watch (default: the current directory)\n rootDir?: string\n // default: 4179, or the first free port after it\n port?: number\n // default: localhost\n host?: string\n}\n\nexport interface DevServer {\n url: string\n port: number\n close: () => Promise<void>\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json; charset=utf-8\",\n}\n\nconst CLIENT_URL = \"/__jq79/client.js\"\nconst EVENTS_URL = \"/__jq79/events\"\n\n// Served as a *classic* script, and injected into the <head>: classic scripts\n// run at parse time and module scripts are deferred, so the flag is set before\n// the page's `import ... from \"jq79\"` evaluates - which is what the runtime\n// waits for before it starts tracking instances. The client can't import the\n// runtime itself: the page's copy may come from a CDN or an import map, and a\n// second copy would have a second, empty registry.\nconst CLIENT = `(() => {\n window.__JQ79_HMR_ENABLED__ = true\n\n const events = new EventSource(${JSON.stringify(EVENTS_URL)})\n\n events.addEventListener(\"update\", event => {\n const { url, src } = JSON.parse(event.data)\n const runtime = window.__JQ79_HMR__\n // no runtime (the page doesn't use jq79), or no live instance from this\n // file (it isn't mounted, or it *is* the page) - nothing to swap into\n const patched = runtime ? runtime.update(url, src) : 0\n if (patched) console.log(\"[jq79] hot-updated \" + url + \" (\" + patched + (patched === 1 ? \" instance)\" : \" instances)\"))\n else location.reload()\n })\n\n events.addEventListener(\"reload\", () => location.reload())\n})()`\n\nconst posix = (path: string) => path.split(sep).join(\"/\")\n\nconst isDocument = (req: IncomingMessage) => req.headers[\"sec-fetch-dest\"] === \"document\"\n\n// the client goes in the <head> so it is the first thing the page runs. A file\n// with neither <head> nor <body> is still a document a browser will render, so\n// fall back to the top of it rather than skipping the injection\nconst injectClient = (html: string): string => {\n const tag = `<script src=\"${CLIENT_URL}\"></script>`\n const open = /<head[^>]*>/i.exec(html) ?? /<body[^>]*>/i.exec(html)\n if (!open) return tag + html\n const at = open.index + open[0].length\n return html.slice(0, at) + tag + html.slice(at)\n}\n\nexport const devServer = async (options: DevServerOptions = {}): Promise<DevServer> => {\n // the *real* path: the watcher reports what changed relative to the directory\n // it actually opened, so a root reached through a symlink (/tmp and /var are\n // symlinks on macOS) would hand back paths that don't line up with it\n const root = await realpath(resolve(options.rootDir ?? \".\"))\n const host = options.host ?? \"localhost\"\n\n const clients = new Set<ServerResponse>()\n\n const send = (event: string, data: unknown) => {\n const frame = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`\n clients.forEach(client => client.write(frame))\n }\n\n // --- serving ---------------------------------------------------------------\n\n const serveStatic = async (req: IncomingMessage, res: ServerResponse, pathname: string) => {\n // a URL path is not a file path: decode it, then keep the result inside the\n // root (\"..\" in a request must not walk out of the served directory)\n let file: string\n try {\n file = resolve(join(root, decodeURIComponent(pathname)))\n } catch {\n res.writeHead(400).end(\"bad request\")\n return\n }\n if (file !== root && !file.startsWith(root + sep)) {\n res.writeHead(403).end(\"forbidden\")\n return\n }\n\n try {\n if ((await stat(file)).isDirectory()) file = join(file, \"index.html\")\n const body = await readFile(file)\n const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\"\n\n // only a navigation gets the hot-reload client. A component is fetched by\n // the runtime (sec-fetch-dest: empty), and it must arrive as written -\n // injecting a <script> into it would make the runtime parse and run it\n const html = type.startsWith(\"text/html\") && isDocument(req)\n const payload = html ? Buffer.from(injectClient(body.toString(\"utf8\"))) : body\n\n res.writeHead(200, {\n \"content-type\": type,\n \"content-length\": payload.byteLength,\n \"cache-control\": \"no-store\", // the file on disk is always the truth here\n })\n res.end(payload)\n } catch {\n res.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(\"not found\")\n }\n }\n\n const server: Server = createServer((req, res) => {\n const pathname = (req.url ?? \"/\").split(/[?#]/)[0]\n\n if (pathname === CLIENT_URL) {\n res.writeHead(200, { \"content-type\": \"text/javascript; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(CLIENT)\n return\n }\n\n if (pathname === EVENTS_URL) {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store\",\n connection: \"keep-alive\",\n })\n res.write(\": jq79\\n\\n\") // opens the stream, so the browser fires onopen\n clients.add(res)\n req.on(\"close\", () => clients.delete(res))\n return\n }\n\n void serveStatic(req, res, pathname)\n })\n\n // --- watching --------------------------------------------------------------\n\n const ignored = (rel: string) =>\n rel.split(sep).some(part => part.startsWith(\".\") || part === \"node_modules\")\n\n // one save can arrive as several events (a rename plus a change, an editor's\n // atomic write); collapsing per file keeps that down to one push\n const pending = new Map<string, NodeJS.Timeout>()\n\n const changed = async (rel: string) => {\n const file = join(root, rel)\n\n let src: string | null = null\n try {\n // a directory changes whenever anything inside it does, and the event for\n // the file itself is already on its way - acting on both would reload the\n // page every time a component is saved\n if ((await stat(file)).isDirectory()) return\n if (rel.endsWith(\".html\")) src = await readFile(file, \"utf8\")\n } catch {\n // gone: deleted, or renamed away - and there is nothing to swap in, so the\n // page has to reload. Unless it was never there: macOS reports a change to\n // the watched directory *itself* under its own basename, which resolves to\n // a path inside it that does not exist\n if (rel === basename(root)) return\n }\n\n // the url is the one the component was served from, because that is what the\n // runtime resolves its instances' filenames against\n const url = \"/\" + posix(rel)\n if (src === null) send(\"reload\", { url })\n else send(\"update\", { url, src })\n }\n\n const watcher: FSWatcher = watch(root, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const rel = relative(root, resolve(root, filename.toString()))\n if (!rel || rel.startsWith(\"..\") || ignored(rel)) return\n\n clearTimeout(pending.get(rel))\n pending.set(rel, setTimeout(() => {\n pending.delete(rel)\n void changed(rel)\n }, 30))\n })\n\n // proxies and load balancers cut an idle stream; a comment every 30s is the\n // conventional way to keep it open. unref'd, so it never holds the process up\n const heartbeat = setInterval(() => clients.forEach(client => client.write(\": ping\\n\\n\")), 30_000)\n heartbeat.unref()\n\n // --- go --------------------------------------------------------------------\n\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail)\n server.listen(options.port ?? 4179, host, done)\n })\n const { port } = server.address() as { port: number }\n\n return {\n url: `http://${host}:${port}`,\n port,\n close: () =>\n new Promise(done => {\n clearInterval(heartbeat)\n watcher.close()\n pending.forEach(clearTimeout)\n clients.forEach(client => client.end())\n clients.clear()\n server.close(() => done())\n }),\n }\n}\n\nexport default devServer\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../dev/dev.ts"],"sourcesContent":["import { createServer, type Server, type IncomingMessage, type ServerResponse } from \"node:http\"\nimport { readFile, realpath, stat } from \"node:fs/promises\"\nimport { watch, type FSWatcher } from \"node:fs\"\nimport { basename, extname, join, relative, resolve, sep } from \"node:path\"\n\n// A dev server for the no-bundle path: serve a directory of .html components\n// over HTTP, watch it, and hot-reload the components that changed.\n//\n// npx jq79 dev // the CLI\n// import { devServer } from \"jq79/dev\" // or from a script\n// await devServer({ rootDir: \".\" })\n//\n// It is a static file server and nothing else - no transforms, no bundling, no\n// module graph. Which is the point: the files it serves are the files you would\n// deploy, so what you develop against and what a static host serves are the same\n// bytes. The one thing it adds is the hot-reload channel, and it adds it to\n// *documents* only (a component fetched by the runtime is served verbatim).\n//\n// The reload is fine-grained. On a change the server pushes the new source down\n// an SSE channel and the runtime swaps it into every live instance of that file,\n// keeping its data - see hotUpdate in jq79.ts. Anything the runtime can't place\n// (a page, a stylesheet, a component nothing has mounted yet) falls back to a\n// full page reload.\n\nexport interface DevServerOptions {\n // the directory to serve, and to watch (default: the current directory)\n rootDir?: string\n // default: 4179, or the first free port after it\n port?: number\n // default: localhost\n host?: string\n}\n\nexport interface DevServer {\n url: string\n port: number\n close: () => Promise<void>\n}\n\nconst CONTENT_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".map\": \"application/json; charset=utf-8\",\n}\n\nconst CLIENT_URL = \"/__jq79/client.js\"\nconst EVENTS_URL = \"/__jq79/events\"\n\n// Served as a *classic* script, and injected into the <head>: classic scripts\n// run at parse time and module scripts are deferred, so the flag is set before\n// the page's `import ... from \"jq79\"` evaluates - which is what the runtime\n// waits for before it starts tracking instances. The client can't import the\n// runtime itself: the page's copy may come from a CDN or an import map, and a\n// second copy would have a second, empty registry.\nconst CLIENT = `(() => {\n window.__JQ79_HMR_ENABLED__ = true\n\n const events = new EventSource(${JSON.stringify(EVENTS_URL)})\n\n events.addEventListener(\"update\", event => {\n const { url, src } = JSON.parse(event.data)\n const runtime = window.__JQ79_HMR__\n // no runtime (the page doesn't use jq79), or no live instance from this\n // file (it isn't mounted, or it *is* the page) - nothing to swap into\n const patched = runtime ? runtime.update(url, src) : 0\n if (patched) console.log(\"[jq79] hot-updated \" + url + \" (\" + patched + (patched === 1 ? \" instance)\" : \" instances)\"))\n else location.reload()\n })\n\n events.addEventListener(\"reload\", () => location.reload())\n})()`\n\nconst posix = (path: string) => path.split(sep).join(\"/\")\n\nconst isDocument = (req: IncomingMessage) => req.headers[\"sec-fetch-dest\"] === \"document\"\n\n// the client goes in the <head> so it is the first thing the page runs. A file\n// with neither <head> nor <body> is still a document a browser will render, so\n// fall back to the top of it rather than skipping the injection\nconst injectClient = (html: string): string => {\n const tag = `<script src=\"${CLIENT_URL}\"></script>`\n // (\\s[^>]*)? rather than [^>]*, or <header> would pass for <head>\n const open = /<head(\\s[^>]*)?>/i.exec(html) ?? /<body(\\s[^>]*)?>/i.exec(html)\n if (!open) return tag + html\n const at = open.index + open[0].length\n return html.slice(0, at) + tag + html.slice(at)\n}\n\nexport const devServer = async (options: DevServerOptions = {}): Promise<DevServer> => {\n // the *real* path: the watcher reports what changed relative to the directory\n // it actually opened, so a root reached through a symlink (/tmp and /var are\n // symlinks on macOS) would hand back paths that don't line up with it\n const root = await realpath(resolve(options.rootDir ?? \".\"))\n const host = options.host ?? \"localhost\"\n\n const clients = new Set<ServerResponse>()\n\n const send = (event: string, data: unknown) => {\n const frame = `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`\n clients.forEach(client => client.write(frame))\n }\n\n // --- serving ---------------------------------------------------------------\n\n const serveStatic = async (req: IncomingMessage, res: ServerResponse, pathname: string) => {\n // a URL path is not a file path: decode it, then keep the result inside the\n // root (\"..\" in a request must not walk out of the served directory)\n let file: string\n try {\n file = resolve(join(root, decodeURIComponent(pathname)))\n } catch {\n res.writeHead(400).end(\"bad request\")\n return\n }\n if (file !== root && !file.startsWith(root + sep)) {\n res.writeHead(403).end(\"forbidden\")\n return\n }\n\n try {\n if ((await stat(file)).isDirectory()) {\n // a directory is served through its trailing-slash URL, like every\n // static host: /docs rendered as-is would resolve its relative links\n // against the parent (\"img.png\" -> /img.png instead of /docs/img.png)\n if (!pathname.endsWith(\"/\")) {\n res.writeHead(301, { location: pathname + \"/\" }).end()\n return\n }\n file = join(file, \"index.html\")\n }\n const body = await readFile(file)\n const type = CONTENT_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\"\n\n // only a navigation gets the hot-reload client. A component is fetched by\n // the runtime (sec-fetch-dest: empty), and it must arrive as written -\n // injecting a <script> into it would make the runtime parse and run it\n const html = type.startsWith(\"text/html\") && isDocument(req)\n const payload = html ? Buffer.from(injectClient(body.toString(\"utf8\"))) : body\n\n res.writeHead(200, {\n \"content-type\": type,\n \"content-length\": payload.byteLength,\n \"cache-control\": \"no-store\", // the file on disk is always the truth here\n })\n res.end(payload)\n } catch {\n res.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(\"not found\")\n }\n }\n\n const server: Server = createServer((req, res) => {\n const pathname = (req.url ?? \"/\").split(/[?#]/)[0]\n\n if (pathname === CLIENT_URL) {\n res.writeHead(200, { \"content-type\": \"text/javascript; charset=utf-8\", \"cache-control\": \"no-store\" })\n res.end(CLIENT)\n return\n }\n\n if (pathname === EVENTS_URL) {\n res.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-store\",\n connection: \"keep-alive\",\n })\n res.write(\": jq79\\n\\n\") // opens the stream, so the browser fires onopen\n clients.add(res)\n req.on(\"close\", () => clients.delete(res))\n return\n }\n\n void serveStatic(req, res, pathname)\n })\n\n // --- watching --------------------------------------------------------------\n\n const ignored = (rel: string) =>\n rel.split(sep).some(part => part.startsWith(\".\") || part === \"node_modules\")\n\n // one save can arrive as several events (a rename plus a change, an editor's\n // atomic write); collapsing per file keeps that down to one push\n const pending = new Map<string, NodeJS.Timeout>()\n\n const changed = async (rel: string) => {\n const file = join(root, rel)\n\n let src: string | null = null\n try {\n // a directory changes whenever anything inside it does, and the event for\n // the file itself is already on its way - acting on both would reload the\n // page every time a component is saved\n if ((await stat(file)).isDirectory()) return\n if (rel.endsWith(\".html\")) src = await readFile(file, \"utf8\")\n } catch {\n // gone: deleted, or renamed away - and there is nothing to swap in, so the\n // page has to reload. Unless it was never there: macOS reports a change to\n // the watched directory *itself* under its own basename, which resolves to\n // a path inside it that does not exist\n if (rel === basename(root)) return\n }\n\n // the url is the one the component was served from, because that is what the\n // runtime resolves its instances' filenames against\n const url = \"/\" + posix(rel)\n if (src === null) send(\"reload\", { url })\n else send(\"update\", { url, src })\n }\n\n const watcher: FSWatcher = watch(root, { recursive: true }, (_event, filename) => {\n if (!filename) return\n const rel = relative(root, resolve(root, filename.toString()))\n if (!rel || rel.startsWith(\"..\") || ignored(rel)) return\n\n clearTimeout(pending.get(rel))\n pending.set(rel, setTimeout(() => {\n pending.delete(rel)\n void changed(rel)\n }, 30))\n })\n\n // proxies and load balancers cut an idle stream; a comment every 30s is the\n // conventional way to keep it open. unref'd, so it never holds the process up\n const heartbeat = setInterval(() => clients.forEach(client => client.write(\": ping\\n\\n\")), 30_000)\n heartbeat.unref()\n\n // --- go --------------------------------------------------------------------\n\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail)\n server.listen(options.port ?? 4179, host, done)\n })\n const { port } = server.address() as { port: number }\n\n return {\n url: `http://${host}:${port}`,\n port,\n close: () =>\n new Promise(done => {\n clearInterval(heartbeat)\n watcher.close()\n pending.forEach(clearTimeout)\n clients.forEach(client => client.end())\n clients.clear()\n server.close(() => done())\n }),\n }\n}\n\nexport default devServer\n"],"mappings":"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","names":[]}
package/dist/jq79.cjs CHANGED
@@ -1,11 +1,12 @@
1
- var I=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var Pe=Object.getOwnPropertyNames;var ke=Object.prototype.hasOwnProperty;var Fe=(e,t,n)=>t in e?I(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Ie=(e,t)=>{for(var n in t)I(e,n,{get:t[n],enumerable:!0})},We=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Pe(t))!ke.call(e,r)&&r!==n&&I(e,r,{get:()=>t[r],enumerable:!(s=De(t,r))||s.enumerable});return e};var Be=e=>We(I({},"__esModule",{value:!0}),e);var w=(e,t,n)=>Fe(e,typeof t!="symbol"?t+"":t,n);var Nt={};Ie(Nt,{$:()=>j,$$:()=>W,$create:()=>B,$reactive:()=>F,Component79:()=>M,enableHotReload:()=>Oe,hotUpdate:()=>Ae,parseComponent:()=>_t,renderComponent:()=>ut});module.exports=Be(Nt);function j(e,t){return typeof e=="string"?document.querySelector(e):e.querySelector(t)}function W(e,t){return Array.from(typeof e=="string"?document.querySelectorAll(e):e.querySelectorAll(t))}var B=(e,t={})=>{let n=document.createElement(e);for(let[s,r]of Object.entries(t))if(s==="className")n.className=Array.isArray(r)?r.join(" "):r;else if(s==="textContent")n.textContent=r;else if(s==="children")for(let o of r)n.appendChild(o);else n.setAttribute(s,r);return n},Ue=new Set(["a","b","i","em","strong","p","br","ul","ol","li","blockquote","code","pre","span","div","h1","h2","h3","h4","h5","h6","img"]),te={a:new Set(["href","title"]),img:new Set(["src","alt"]),"*":new Set(["class"])},qe=new Set(["http:","https:","mailto:"]);function He(e){try{let t=new URL(e,"https://example.com");return qe.has(t.protocol)}catch{return!1}}function ne(e,t){for(let n of Array.from(e.childNodes))if(n.nodeType===Node.ELEMENT_NODE){let s=ze(n);s&&t.appendChild(s)}else n.nodeType===Node.TEXT_NODE&&t.appendChild(n.cloneNode())}function ze(e){let t=e.tagName.toLowerCase();if(!Ue.has(t))return null;let n=document.createElement(t);for(let s of Array.from(e.attributes)){let r=s.name.toLowerCase(),o=te[t]?.has(r),c=te["*"]?.has(r);!o&&!c||(r==="href"||r==="src")&&!He(s.value)||n.setAttribute(r,s.value)}return t==="a"&&n.setAttribute("rel","noopener noreferrer"),ne(e,n),n}function se(e){let t=new DOMParser().parseFromString(e,"text/html"),n=document.createElement("div");return ne(t.body,n),n.innerHTML}var Ge=(e,t)=>t.split(".").reduce((n,s)=>n?.[s],e),re=e=>{if(Array.isArray(e))return!0;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},oe=(e,t,n)=>{Object.entries(e).forEach(([s,r])=>{let o=t?`${t}.${s}`:s;r&&typeof r=="object"&&re(r)?oe(r,o,n):n(o,r)})},Ke=(e,t)=>e===t||e.startsWith(`${t}.`)||t.startsWith(`${e}.`),K=Symbol("jq79.raw"),U=e=>{let t=e;for(;t!==null&&typeof t=="object"&&t[K];)t=t[K];return t},ie=Symbol("jq79.store"),k=e=>e!==null&&typeof e=="object"&&e[ie]===!0,D=[],ce=e=>{D.push(new Set);try{return e()}finally{D.pop()}},F=e=>{let t=new Map,n=new Set,s=new Set,r=new WeakMap,o=Object.create(null),c=(a,u,g=!1)=>{t.get(a)?.forEach(b=>b(u,a)),n.forEach(b=>b(a,u)),s.forEach(b=>{(g||Array.from(b.deps).some(m=>Ke(m,a)))&&b.run()})},i=a=>a!==null&&typeof a=="object"&&re(a),l=new Map,h=(a,u)=>{let g=l.get(u);g?.store!==a&&(g?.unsubscribe(),l.set(u,{store:a,unsubscribe:a.$onAny((b,m)=>c(`${u}.${b}`,m))}))},f=a=>{l.get(a)?.unsubscribe(),l.delete(a)},p=(a,u)=>{let g=r.get(a);if(g)return g;let b=new Proxy(a,{get(m,S,R){if(S===K)return m;if(S===ie)return u==="";if(typeof S!="string")return Reflect.get(m,S,R);if(u===""&&S in o)return o[S];let C=u?`${u}.${S}`:S;D[D.length-1]?.add(C);let $=Reflect.get(m,S,R);if(k($))return h($,C),$;let x=U($);return i(x)?p(x,C):x},set(m,S,R,C){if(C!==b&&!Object.prototype.hasOwnProperty.call(m,S))return Reflect.set(m,S,R,C);let $=u?`${u}.${S}`:S,x=k(R)?R:U(R),Me=!Object.prototype.hasOwnProperty.call(m,S);m[S]=x,k(x)?h(x,$):f($);let je=k(x)||!i(x)?x:p(x,$);return c($,je,Me),!0}});return r.set(a,b),b},d=p(U(e),"");Object.entries(U(e)).forEach(([a,u])=>{k(u)&&h(u,a)});let E=(a,u,{immediate:g=!1}={})=>(t.has(a)||t.set(a,new Set),t.get(a).add(u),g&&u(Ge(d,a),a),()=>t.get(a)?.delete(u)),y=(a,{immediate:u=!1}={})=>(n.add(a),u&&oe(d,"",(g,b)=>a(g,b)),()=>n.delete(a)),_=a=>{let u={deps:new Set,run:()=>{let g=new Set;D.push(g);try{a()}finally{D.pop(),u.deps=g}}};return s.add(u),u.run(),()=>{s.delete(u)}},N=()=>{l.forEach(({unsubscribe:a})=>a()),l.clear()};return o.$on=E,o.$onAny=y,o.$effect=_,o.$dispose=N,d},P=e=>{let t=[];return{effect:n=>{t.push(e.$effect(n))},onDispose:n=>{t.push(n)},dispose:()=>{t.splice(0).forEach(n=>n())}}};var ae=/(?:let|var|const)\s+([A-Za-z_$][\w$]*)/y,le=/\$:\s*/y,H=/import(?=\s*\()/y,fe=/\$:\s*([A-Za-z_$][\w$]*)\s*=(?!=)/y,L=(e,t)=>{let n=e[t],s=t+1;for(;s<e.length;){if(e[s]==="\\"){s+=2;continue}if(e[s]===n)return s+1;s++}return e.length},v=(e,t)=>{let n=e.indexOf(`
2
- `,t);return n===-1?e.length:n},A=(e,t)=>{let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2},q=(e,t)=>{let n=t;for(;n<e.length;){if(/\s/.test(e[n])){n++;continue}if(e[n]==="/"&&e[n+1]==="/"){n=v(e,n);continue}if(e[n]==="/"&&e[n+1]==="*"){n=A(e,n);continue}break}return n},Ze=/^(\?\.|\?\?|&&|\|\||\*\*|[.,+\-*/%&|^<>=?:([])/,Je=(e,t)=>{let n=0,s=t;for(;s<e.length;){let r=e[s];if(r==="'"||r==='"'||r==="`"){s=L(e,s);continue}if(r==="/"&&e[s+1]==="/"){s=v(e,s);continue}if(r==="/"&&e[s+1]==="*"){s=A(e,s);continue}if("([{".includes(r))n++;else if(")]}".includes(r))n--;else{if(n<=0&&r===";")return s;if(n<=0&&r===`
3
- `){let o=q(e,s+1);if(o>=e.length||!Ze.test(e.slice(o,o+2)))return s;s=o;continue}}s++}return e.length},de=e=>{let t=[],n="",s=0,r=0,o=!0;for(;s<e.length;){let c=e[s],i=e[s+1];if(c==="'"||c==='"'||c==="`"){let l=L(e,s);n+=e.slice(s,l),s=l,o=!1;continue}if(c==="/"&&(i==="/"||i==="*")){let l=i==="/"?v(e,s):A(e,s);n+=e.slice(s,l),s=l;continue}if(c==="i"&&(s===0||!/[\w$.]/.test(e[s-1]))&&(H.lastIndex=s,H.test(e))){n+="$__import",s+=6,o=!1;continue}if(r===0&&o){ae.lastIndex=s;let l=ae.exec(e);if(l){t.push(l[1]),n+=l[1],s+=l[0].length,o=!1;continue}le.lastIndex=s;let h=le.exec(e);if(h){fe.lastIndex=s;let f=fe.exec(e);f&&t.push(f[1]);let p=s+h[0].length,d=Je(e,p);n+=`$__effect(() => { ${e.slice(p,d)} });`,s=d;continue}}"([{".includes(c)?r++:")]}".includes(c)&&(r=Math.max(0,r-1)),c===`
4
- `||c===";"||c==="}"?o=!0:/\s/.test(c)||(o=!1),n+=c,s++}return{vars:t,code:n}},z=/export\s+default(?![\w$])/y,ue=/import\s*(?:([\w$\s,{}*]+?)\s*from\s*)?(["'])([^"'\n]+)\2/y,Ve=e=>{let t=[],n=0,s=0;for(let r=0;r<=e.length;r++){let o=e[r];if(o==="{")n++;else if(o==="}")n--;else if(r===e.length||o===","&&n===0){let c=e.slice(s,r).trim();c&&t.push(c),s=r+1}}return t},Xe=(e,t,n)=>{let s=`await $__import(${JSON.stringify(t)})`;if(e===void 0)return s;let r=Ve(e),o=[],c=s;if(r.length>1){let i=`$__mod${n}`;o.push(`${i} = ${s}`),c=i}for(let i of r)i.startsWith("{")?o.push(`${i.replace(/\s+as\s+/g,": ")} = ${c}`):i.startsWith("*")?o.push(`${i.replace(/^\*\s*as\s+/,"")} = ${c}`):o.push(`${i} = $__default(${c})`);return`const ${o.join(", ")}`},Qe=/^[A-Za-z_$][\w$]*$/,pe=(e,t)=>{let n=0,s=0;for(;s<e.length;){let r=e[s];if(r==="'"||r==='"'||r==="`"){s=L(e,s);continue}if(r==="/"&&e[s+1]==="/"){s=v(e,s);continue}if(r==="/"&&e[s+1]==="*"){s=A(e,s);continue}if("([{".includes(r))n++;else if(")]}".includes(r))n--;else if(n===0&&r===t)return s;s++}return-1},he=e=>{let t=[],n=0,s=0,r=0;for(;r<=e.length;){let o=e[r];if(o==="'"||o==='"'||o==="`"){r=L(e,r);continue}if(o==="/"&&e[r+1]==="/"){r=v(e,r);continue}if(o==="/"&&e[r+1]==="*"){r=A(e,r);continue}if(o!==void 0&&"([{".includes(o))n++;else if(o!==void 0&&")]}".includes(o))n--;else if(r===e.length||o===","&&n===0){let c=e.slice(s,r).trim();c&&t.push(c),s=r+1}r++}return t},Ye=e=>{let t=0;for(;t<e.length;){let n=pe(e.slice(t),"=");if(n===-1)return-1;let s=t+n;if(e[s+1]!=="="&&e[s+1]!==">"&&e[s-1]!=="="&&e[s-1]!=="!")return s;t=s+1}return-1},Z=e=>{let t=(e??"").trim();if(!t.startsWith("{"))return null;let n=0,s=0;for(;s<t.length;){let o=t[s];if(o==="'"||o==='"'||o==="`"){s=L(t,s);continue}if("([{".includes(o))n++;else if(")]}".includes(o)&&--n===0)break;s++}if(s>=t.length)return null;let r=[];for(let o of he(t.slice(1,s))){if(o.startsWith("..."))continue;let c=Ye(o),i=c===-1?o:o.slice(0,c),l=c===-1?void 0:o.slice(c+1).trim(),h=pe(i,":"),f=(h===-1?i:i.slice(0,h)).trim();Qe.test(f)&&r.push(l===void 0?{name:f}:{name:f,default:l})}return r},et=e=>{let t=0,n=0,s=!0;for(;t<e.length;){let r=e[t];if(r==="'"||r==='"'||r==="`"){t=L(e,t),s=!1;continue}if(r==="/"&&e[t+1]==="/"){t=v(e,t);continue}if(r==="/"&&e[t+1]==="*"){t=A(e,t);continue}if(r==="e"&&n===0&&s&&(t===0||!/[\w$.]/.test(e[t-1]))){z.lastIndex=t;let o=z.exec(e);if(o)return t+o[0].length}"([{".includes(r)?n++:")]}".includes(r)&&(n=Math.max(0,n-1)),r===`
5
- `||r===";"||r==="}"?s=!0:/\s/.test(r)||(s=!1),t++}return-1},tt=/^async(?![\w$])/,nt=/^function(?![\w$])\s*\*?\s*[A-Za-z_$][\w$]*|^function(?![\w$])\s*\*?/,st=e=>{let t=et(e);if(t===-1)return null;let n=q(e,t),s=e.slice(n);tt.test(s)&&(n=q(e,n+5));let r=nt.exec(e.slice(n));if(r&&(n=q(e,n+r[0].length)),e[n]!=="(")return null;let o=0,c=n;for(;c<e.length;){let i=e[c];if(i==="'"||i==='"'||i==="`"){c=L(e,c);continue}if("([{".includes(i))o++;else if(")]}".includes(i)&&--o===0)break;c++}return he(e.slice(n+1,c))[0]??""},me=e=>{let t=st(e);if(t===null)return null;let n=Z(t),s=n?.find(r=>r.name.startsWith("$"))?.name;if(s)throw new Error(`jq79: the factory signature is (props, ctx), so \`${s}\` can't be destructured from the first parameter. Write \`export default (props, { ${s} }) => \u2026\`, or \`_\` in place of props if the component takes none.`);return n},ge=e=>{let t="",n=0,s=0,r=!0,o=!1,c=0;for(;n<e.length;){let i=e[n],l=e[n+1],h=n===0||!/[\w$.]/.test(e[n-1]);if(i==="'"||i==='"'||i==="`"){let f=L(e,n);t+=e.slice(n,f),n=f,r=!1;continue}if(i==="/"&&(l==="/"||l==="*")){let f=l==="/"?v(e,n):A(e,n);t+=e.slice(n,f),n=f;continue}if(i==="i"&&h){if(H.lastIndex=n,H.test(e)){t+="$__import",n+=6,r=!1;continue}if(s===0&&r){ue.lastIndex=n;let f=ue.exec(e);if(f){t+=Xe(f[1],f[3],c++),n+=f[0].length,r=!1;continue}}}if(i==="e"&&h&&s===0&&r){z.lastIndex=n;let f=z.exec(e);if(f){o=!0,t+="$__exports.default =",n+=f[0].length,r=!1;continue}}"([{".includes(i)?s++:")]}".includes(i)&&(s=Math.max(0,s-1)),i===`
6
- `||i===";"||i==="}"?r=!0:/\s/.test(i)||(r=!1),t+=i,n++}return o?t:null};var xe=e=>Object.fromEntries(Array.from(e.attributes).map(t=>[t.name,t.value])),Te=e=>({tag:e.tagName.toLowerCase(),attrs:xe(e),children:Array.from(e.childNodes).flatMap(t=>{if(t.nodeType===Node.TEXT_NODE){let n=t.textContent??"";return n?[n]:[]}return t.nodeType===Node.ELEMENT_NODE?[Te(t)]:[]})}),ye=new Map,rt=(e,t)=>{let n=`${t.join(",")}|${e}`,s=ye.get(n);if(s===void 0){try{s=new Function("$scope",...t,`with ($scope) { return (${e}); }`)}catch{s=null}ye.set(n,s)}return s},T=(e,t,n)=>{let s=rt(e,n?Object.keys(n):[]);if(s)try{return s(t,...n?Object.values(n):[])}catch{return}},ot=(e,t)=>e.replace(/{{\s*([\s\S]+?)\s*}}/g,(n,s)=>T(s,t)??""),Ce=new Set([":attrs",":if",":elseif",":else",":each",":key",":with",":text",":html"]),it=/^\s*(\w+)\s+in\s+([\s\S]+)$/,ct=(e,t,n,s)=>{let[r,...o]=t.slice(1).split("."),c=new Set(o);e.addEventListener(r,i=>{if(c.has("self")&&i.target!==e)return;c.has("prevent")&&i.preventDefault(),c.has("stop")&&i.stopPropagation();let l=T(n,s,{$event:i});typeof l=="function"&&l.call(e,i)},{once:c.has("once"),capture:c.has("capture")})},Ee=e=>e.replace(/-(\w)/g,(t,n)=>n.toUpperCase()),be=(e,t)=>{let n=t.replace(/-/g,"").toLowerCase();for(let s=e;s&&s!==Object.prototype;s=Object.getPrototypeOf(s))for(let r of Object.keys(s))if(/^[A-Z]/.test(r)&&r.replace(/-/g,"").toLowerCase()===n)return r;return null},Se=(e,t,n,s,r)=>{let o=document.createComment(e),c=document.createDocumentFragment();c.appendChild(o);let i={};Object.entries(t.attrs).forEach(([p,d])=>{if(!(p===Y||Ce.has(p)||p.startsWith("@")))if(p.startsWith(":")){let E=Ee(p.slice(1));i[E]=d||E}else i[Ee(p)]=JSON.stringify(d)});let l=null,h=null,f=null;return s.effect(()=>{let p=T(e,n),d=p instanceof M?p:null;if(d===h||(f?.dispose(),f=null,l?.destroy(),l=null,h=d,!d))return;let E=new M({template:d.template,scripts:d.scripts,styles:d.styles,modules:d.modules,filename:d.filename}),y=ce(()=>Object.fromEntries(Object.entries(i).map(([a,u])=>[a,T(u,n)]))),_=document.createDocumentFragment();(r?E.renderShadow(y):E.render(y)).mount(_),o.parentNode.insertBefore(_,o.nextSibling);let N=P(n);Object.entries(i).forEach(([a,u])=>{N.effect(()=>{E.data[a]=T(u,n)})}),f=N,l=E}),s.onDispose(()=>{f?.dispose(),l?.destroy()}),c},at=(e,t)=>{let n=()=>{let s=T(e,t);return s!==null&&typeof s=="object"?s:null};return new Proxy(t,{has(s,r){let o=n();return o!==null&&Reflect.has(o,r)||Reflect.has(s,r)},get(s,r){let o=n();return o!==null&&Reflect.has(o,r)?o[r]:Reflect.get(s,r)},set(s,r,o){let c=n();return c!==null&&Reflect.has(c,r)?(c[r]=o,!0):Reflect.set(s,r,o)}})},X=(e,t,n,s)=>{let r=e.attrs[":with"],o=r!==void 0?at(r,t):t,c=be(o,e.tag);if(c)return Se(c,e,o,n,s);let i=document.createElement(e.tag);if(i instanceof HTMLUnknownElement||e.tag.includes("-")){let p=!1;n.effect(()=>{if(p)return;let d=be(o,e.tag);d&&(p=!0,i.replaceWith(Se(d,e,o,n,s)))})}Object.entries(e.attrs).forEach(([p,d])=>{p.startsWith("@")?ct(i,p,d,o):Ce.has(p)||i.setAttribute(p,d)});let l=e.attrs[":attrs"];if(l!==void 0){let p=[];n.effect(()=>{p.forEach(E=>i.removeAttribute(E));let d=T(l,o);p=d&&typeof d=="object"?Object.keys(d):[],p.forEach(E=>{let y=d[E];y!=null&&y!==!1&&i.setAttribute(E,String(y))})})}let h=e.attrs[":text"],f=e.attrs[":html"];return h!==void 0?n.effect(()=>{i.textContent=String(T(h,o)??"")}):f!==void 0?n.effect(()=>{i.innerHTML=se(String(T(f,o)??""))}):i.appendChild(Q(e.children,o,n,s)),i},lt=(e,t,n,s)=>{let r=document.createComment("if"),o=document.createDocumentFragment();o.appendChild(r);let c=null,i=null,l=null;return n.effect(()=>{let h=e.find(f=>f.expr===void 0||T(f.expr,t))??null;h!==i&&(l?.dispose(),c&&c.parentNode?.removeChild(c),c=null,i=h,h&&(l=P(t),c=X(h.node,t,l,s),r.parentNode.insertBefore(c,r.nextSibling)))}),o},J=(e,t,n)=>{Object.defineProperty(e,t,{value:n,writable:!0,enumerable:!0,configurable:!0})},ft=(e,t,n,s)=>{let r=e.attrs[":each"].match(it);if(!r)return document.createComment(`invalid :each expression "${e.attrs[":each"]}"`);let[,o,c]=r,i=e.attrs[":key"],{[":each"]:l,[":key"]:h,...f}=e.attrs,p={...e,attrs:f},d=document.createComment("each"),E=document.createDocumentFragment();E.appendChild(d);let y=[];return n.effect(()=>{let _=T(c,t),N=Array.isArray(_)?_:[],a=new Map(y.map(m=>[m.key,m])),u=N.map((m,S)=>{let R=Object.create(t);J(R,o,m),J(R,"$index",S);let C=i!==void 0?T(i,R):S,$=a.get(C);if($&&Object.is($.item,m))return J($.scope,"$index",S),$;$?.fx.dispose(),$?.node.parentNode?.removeChild($.node);let x=P(t);return{key:C,item:m,scope:R,fx:x,node:X(p,R,x,s)}}),g=new Set(u.map(m=>m.key));y.forEach(m=>{g.has(m.key)||(m.fx.dispose(),m.node.parentNode?.removeChild(m.node))});let b=d;u.forEach(m=>{b.nextSibling!==m.node&&d.parentNode.insertBefore(m.node,b.nextSibling),b=m.node}),y=u}),E},Q=(e,t,n,s=!1)=>{let r=document.createDocumentFragment(),o=0;for(;o<e.length;){let c=e[o];if(typeof c=="string"){let i=document.createTextNode(c);c.includes("{{")&&n.effect(()=>{i.textContent=ot(c,t)}),r.appendChild(i),o++;continue}if(":each"in c.attrs){r.appendChild(ft(c,t,n,s)),o++;continue}if(":if"in c.attrs){let i=[{expr:c.attrs[":if"],node:c}];o++;let l=f=>{let p=o;for(;p<e.length&&typeof e[p]=="string"&&!e[p].trim();)p++;let d=e[p];if(typeof d=="object"&&f in d.attrs)return o=p+1,d};for(let f=l(":elseif");f;f=l(":elseif"))i.push({expr:f.attrs[":elseif"],node:f});let h=l(":else");h&&i.push({node:h}),r.appendChild(lt(i,t,n,s));continue}r.appendChild(X(c,t,n,s)),o++}return r},ut=(e,t,n=!1)=>Q(e.template,t,P(t),n),dt=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),pt=/<([A-Za-z][\w-]*)((?:"[^"]*"|'[^']*'|[^>"'])*?)\/>/g,ht=/(<script[\s\S]*?<\/script\s*>|<style[\s\S]*?<\/style\s*>)/gi,mt=e=>e.split(ht).map((t,n)=>n%2===1?t:t.replace(pt,(s,r,o)=>dt.has(r.toLowerCase())?s:`<${r}${o}></${r}>`)).join(""),Y="data-jq79",gt=e=>{let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return(t>>>0).toString(36)},_e=(e,t)=>{e.forEach(n=>{typeof n!="string"&&(n.attrs[Y]=t,_e(n.children,t))})},yt=(e,t)=>e.split(",").map(n=>{let s=n.trim(),r=s.indexOf("::"),o=r===-1?s:s.slice(0,r),c=r===-1?"":s.slice(r);return`${o}[${Y}="${t}"]${c}`}).join(", "),Ne=(e,t)=>{Array.from(e).forEach(n=>{n instanceof CSSStyleRule?n.selectorText=yt(n.selectorText,t):n instanceof CSSGroupingRule&&Ne(n.cssRules,t)})},Et=(e,t)=>{/:deep\(|::v-deep|>>>/.test(e)&&console.warn("jq79: :deep()/::v-deep/>>> are not supported in <style scoped>; the rule will be dropped by the browser");let n=new CSSStyleSheet;return n.replaceSync(e),Ne(n.cssRules,t),Array.from(n.cssRules).map(s=>s.cssText).join(`
7
- `)},V=e=>{let n=new DOMParser().parseFromString(`<template>${mt(e)}</template>`,"text/html").querySelector("template"),s=[],r=[],o=[];Array.from(n.content.children).forEach(i=>{let l={attrs:xe(i),content:i.textContent??""};i.tagName==="SCRIPT"?s.push(l):i.tagName==="STYLE"?r.push(l):o.push(Te(i))}),r.forEach(i=>{"lang"in i.attrs&&console.warn(`jq79: <style lang="${i.attrs.lang}"> needs the jq79/vite plugin to compile it. This component didn't go through the bundler, so its styles were left uncompiled and the browser will ignore them.`)});let c=i=>"scoped"in i.attrs&&!("lang"in i.attrs);if(r.some(c)){let i=gt(e);_e(o,i),r.forEach(l=>{c(l)&&(l.scoped=Et(l.content,i))})}return{template:o,scripts:s,styles:r}},ee=e=>/\.html?([?#]|$)/.test(e)?M.fetch(e):import(e),Le=(e,t)=>e?`
8
- //# sourceURL=${e}?jq79-script=${t}`:"",$e=e=>e.scoped??e.content,G=new Map,bt=e=>{let t=G.get(e);if(!t){let n=document.createElement("style");n.textContent=e,document.head.appendChild(n),t={el:n,count:0},G.set(e,t)}t.count++},St=e=>{let t=G.get(e);t&&--t.count<=0&&(t.el.remove(),G.delete(e))},ve={$:j,$$:W,$create:B,$reactive:F},$t=(e,t,n,s={},r=ee,o={})=>{let c={...ve,...s},i=new Proxy(t,{has:(h,f)=>f!=="$__effect"&&f!=="$__import"&&(Reflect.has(h,f)||!(f in globalThis)&&!(f in c))});new Function("$scope","$__effect","$__import",...Object.keys(c),`return (async () => { with ($scope) { ${e} } })()${Le(o.filename,o.index??0)}`)(i,n,r,...Object.values(c)).catch(h=>console.error("jq79: error in :setup script",h))},we=(e,t)=>{t?.forEach(({name:n,default:s})=>{e[n]===void 0&&(e[n]=s===void 0?void 0:T(s,e))})},wt=e=>e&&e.default!==void 0?e.default:e,Rt=(e,t,n,s={},r=ee,o={})=>{let c={...ve,...s},i={},l=new Function("$__exports","$__default","$__import",...Object.keys(c),`return (async () => { "use strict";
1
+ var z=Object.defineProperty;var qe=Object.getOwnPropertyDescriptor;var He=Object.getOwnPropertyNames;var ze=Object.prototype.hasOwnProperty;var Ge=(e,t,n)=>t in e?z(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Ke=(e,t)=>{for(var n in t)z(e,n,{get:t[n],enumerable:!0})},Ze=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of He(t))!ze.call(e,r)&&r!==n&&z(e,r,{get:()=>t[r],enumerable:!(s=qe(t,r))||s.enumerable});return e};var Je=e=>Ze(z({},"__esModule",{value:!0}),e);var C=(e,t,n)=>Ge(e,typeof t!="symbol"?t+"":t,n);var It={};Ke(It,{$:()=>I,$$:()=>G,$create:()=>K,$reactive:()=>q,Component79:()=>F,enableHotReload:()=>Be,hotUpdate:()=>We,parseComponent:()=>Ft,renderComponent:()=>Rt});module.exports=Je(It);function I(e,t){return typeof e=="string"?document.querySelector(e):e.querySelector(t)}function G(e,t){return Array.from(typeof e=="string"?document.querySelectorAll(e):e.querySelectorAll(t))}var K=(e,t={})=>{let n=document.createElement(e);for(let[s,r]of Object.entries(t))if(s==="className")n.className=Array.isArray(r)?r.join(" "):r;else if(s==="textContent")n.textContent=r;else if(s==="children")for(let o of r)n.appendChild(o);else n.setAttribute(s,r);return n},Ve=new Set(["a","b","i","em","strong","p","br","ul","ol","li","blockquote","code","pre","span","div","h1","h2","h3","h4","h5","h6","img"]),de={a:new Set(["href","title"]),img:new Set(["src","alt"]),"*":new Set(["class"])},Xe=new Set(["http:","https:","mailto:"]);function Qe(e){try{let t=new URL(e,"https://example.com");return Xe.has(t.protocol)}catch{return!1}}function pe(e,t){for(let n of Array.from(e.childNodes))if(n.nodeType===Node.ELEMENT_NODE){let s=Ye(n);s&&t.appendChild(s)}else n.nodeType===Node.TEXT_NODE&&t.appendChild(n.cloneNode())}function Ye(e){let t=e.tagName.toLowerCase();if(!Ve.has(t))return null;let n=document.createElement(t);for(let s of Array.from(e.attributes)){let r=s.name.toLowerCase(),o=de[t]?.has(r),i=de["*"]?.has(r);!o&&!i||(r==="href"||r==="src")&&!Qe(s.value)||n.setAttribute(r,s.value)}return t==="a"&&n.setAttribute("rel","noopener noreferrer"),pe(e,n),n}function he(e){let t=new DOMParser().parseFromString(e,"text/html"),n=document.createElement("div");return pe(t.body,n),n.innerHTML}var et=(e,t)=>t.split(".").reduce((n,s)=>n?.[s],e),me=e=>{if(Array.isArray(e))return!0;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},ge=(e,t,n)=>{Object.entries(e).forEach(([s,r])=>{let o=t?`${t}.${s}`:s;r&&typeof r=="object"&&me(r)?ge(r,o,n):n(o,r)})},tt=(e,t)=>e===t||e.startsWith(`${t}.`)||t.startsWith(`${e}.`),te=Symbol("jq79.raw"),Z=e=>{let t=e;for(;t!==null&&typeof t=="object"&&t[te];)t=t[te];return t},ye=Symbol("jq79.store"),U=e=>e!==null&&typeof e=="object"&&e[ye]===!0,W=[],ne=e=>{W.push(new Set);try{return e()}finally{W.pop()}},q=e=>{let t=new Map,n=new Set,s=new Set,r=new WeakMap,o=Object.create(null),i=(a,u,h=!1)=>{t.get(a)?.forEach(S=>S(u,a)),n.forEach(S=>S(a,u)),s.forEach(S=>{(h||Array.from(S.deps).some(T=>tt(T,a)))&&S.run()})},c=a=>a!==null&&typeof a=="object"&&me(a),l=new Map,p=(a,u)=>{let h=l.get(u);h?.store!==a&&(h?.unsubscribe(),l.set(u,{store:a,unsubscribe:a.$onAny((S,T)=>i(`${u}.${S}`,T))}))},f=a=>{l.get(a)?.unsubscribe(),l.delete(a)},E=(a,u)=>{let h=r.get(a);if(h)return h;let S=null,T=new Proxy(a,{has(R,y){return Reflect.has(R,y)||typeof y=="string"&&S?.has(y)===!0},get(R,y,b){if(y===te)return R;if(y===ye)return u==="";if(typeof y!="string")return Reflect.get(R,y,b);if(u===""&&y in o)return o[y];let w=u?`${u}.${y}`:y;W[W.length-1]?.add(w);let N=Reflect.get(R,y,b);if(U(N))return p(N,w),N;let $=Z(N);return c($)?E($,w):$},set(R,y,b,w){if(w!==T&&!Object.prototype.hasOwnProperty.call(R,y))return Reflect.set(R,y,b,w);let N=u?`${u}.${y}`:y,$=U(b)?b:Z(b),P=!Object.prototype.hasOwnProperty.call(R,y);if(!P&&Object.is(R[y],$)&&($===null||typeof $!="object"))return!0;R[y]=$,S?.delete(y),U($)?p($,N):f(N);let L=U($)||!c($)?$:E($,N);return i(N,L,P),!0},deleteProperty(R,y){if(typeof y!="string")return Reflect.deleteProperty(R,y);let b=Object.prototype.hasOwnProperty.call(R,y),w=Reflect.deleteProperty(R,y);if(w&&b){let N=u?`${u}.${y}`:y;(S??(S=new Set)).add(y),f(N),i(N,void 0)}return w}});return r.set(a,T),T},d=E(Z(e),"");Object.entries(Z(e)).forEach(([a,u])=>{U(u)&&p(u,a)});let m=(a,u,{immediate:h=!1}={})=>(t.has(a)||t.set(a,new Set),t.get(a).add(u),h&&u(et(d,a),a),()=>t.get(a)?.delete(u)),g=(a,{immediate:u=!1}={})=>(n.add(a),u&&ge(d,"",(h,S)=>a(h,S)),()=>n.delete(a)),x=a=>{let u=!1,h=!1,S={deps:new Set,run:()=>{if(u){h=!0;return}u=!0;try{let T=0;do{h=!1;let R=new Set;W.push(R);try{a()}finally{W.pop(),S.deps=R}}while(h&&++T<100);h&&console.error("jq79: an effect re-woke itself 100 times in a row (it writes what it reads); giving up on it settling")}finally{u=!1}}};return s.add(S),S.run(),()=>{s.delete(S)}},O=()=>{l.forEach(({unsubscribe:a})=>a()),l.clear()};return o.$on=m,o.$onAny=g,o.$effect=x,o.$dispose=O,d},B=e=>{let t=[],n=[];return{effect:s=>{t.push(e.$effect(s)),n.push(s)},onDispose:s=>{t.push(s)},refresh:()=>{n.forEach(s=>s())},dispose:()=>{t.splice(0).forEach(s=>s()),n.length=0}}};var Ee=/(?:let|var|const)\s+([A-Za-z_$][\w$]*)/y,be=/\$:\s*/y,V=/import(?=\s*\()/y,Se=/\$:\s*([A-Za-z_$][\w$]*)\s*=(?!=)/y,j=(e,t)=>{let n=e[t],s=t+1;for(;s<e.length;){if(e[s]==="\\"){s+=2;continue}if(e[s]===n)return s+1;s++}return e.length},A=(e,t)=>{let n=e.indexOf(`
2
+ `,t);return n===-1?e.length:n},v=(e,t)=>{let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2},J=(e,t)=>{let n=t;for(;n<e.length;){if(/\s/.test(e[n])){n++;continue}if(e[n]==="/"&&e[n+1]==="/"){n=A(e,n);continue}if(e[n]==="/"&&e[n+1]==="*"){n=v(e,n);continue}break}return n},nt=new Set(["return","typeof","case","in","instanceof","new","delete","void","do","else","yield","await"]),M=(e,t)=>{let n=t-1;for(;n>=0;){let r=e[n];if(/\s/.test(r)){n--;continue}if(r==="/"&&e[n-1]==="*"){let o=e.lastIndexOf("/*",n-2);if(o===-1)return!0;n=o-1;continue}break}if(n<0)return!0;let s=e[n];if(/[\w$]/.test(s)){let r=n;for(;r>0&&/[\w$]/.test(e[r-1]);)r--;return nt.has(e.slice(r,n+1))}return(s==="+"||s==="-")&&e[n-1]===s?!1:!")]}\"'`.".includes(s)},D=(e,t)=>{let n=t+1,s=!1;for(;n<e.length;){let r=e[n];if(r==="\\"){n+=2;continue}if(r===`
3
+ `)return n;if(r==="[")s=!0;else if(r==="]")s=!1;else if(r==="/"&&!s){for(n++;n<e.length&&/[a-z]/i.test(e[n]);)n++;return n}n++}return e.length},st=/^(\?\.|\?\?|&&|\|\||\*\*|[.,+\-*/%&|^<>=?:([])/,rt=(e,t)=>{let n=0,s=t;for(;s<e.length;){let r=e[s];if(r==="'"||r==='"'||r==="`"){s=j(e,s);continue}if(r==="/"&&e[s+1]==="/"){s=A(e,s);continue}if(r==="/"&&e[s+1]==="*"){s=v(e,s);continue}if(r==="/"&&M(e,s)){s=D(e,s);continue}if("([{".includes(r))n++;else if(")]}".includes(r))n--;else{if(n<=0&&r===";")return s;if(n<=0&&r===`
4
+ `){let o=J(e,s+1);if(o>=e.length||!st.test(e.slice(o,o+2)))return s;s=o;continue}}s++}return e.length},se=e=>{let t=[],n="",s=0,r=0,o=!0;for(;s<e.length;){let i=e[s],c=e[s+1];if(i==="'"||i==='"'||i==="`"){let l=j(e,s);n+=e.slice(s,l),s=l,o=!1;continue}if(i==="/"&&(c==="/"||c==="*")){let l=c==="/"?A(e,s):v(e,s);n+=e.slice(s,l),s=l;continue}if(i==="/"&&M(e,s)){let l=D(e,s);n+=e.slice(s,l),s=l,o=!1;continue}if(i==="i"&&(s===0||!/[\w$.]/.test(e[s-1]))&&(V.lastIndex=s,V.test(e))){n+="$__import",s+=6,o=!1;continue}if(r===0&&o){Ee.lastIndex=s;let l=Ee.exec(e);if(l){t.push(l[1]),n+=l[1],s+=l[0].length,o=!1;continue}be.lastIndex=s;let p=be.exec(e);if(p){Se.lastIndex=s;let f=Se.exec(e);f&&t.push(f[1]);let E=s+p[0].length,d=rt(e,E);n+=`$__effect(() => { ${se(e.slice(E,d)).code} });`,s=d;continue}}"([{".includes(i)?r++:")]}".includes(i)&&(r=Math.max(0,r-1)),i===`
5
+ `||i===";"||i==="}"?o=!0:/\s/.test(i)||(o=!1),n+=i,s++}return{vars:t,code:n}},X=/export\s+default(?![\w$])/y,we=/import\s*(?:([\w$\s,{}*]+?)\s*from\s*)?(["'])([^"'\n]+)\2/y,ot=e=>{let t=[],n=0,s=0;for(let r=0;r<=e.length;r++){let o=e[r];if(o==="{")n++;else if(o==="}")n--;else if(r===e.length||o===","&&n===0){let i=e.slice(s,r).trim();i&&t.push(i),s=r+1}}return t},it=(e,t,n)=>{let s=`await $__import(${JSON.stringify(t)})`;if(e===void 0)return s;let r=ot(e),o=[],i=s;if(r.length>1){let c=`$__mod${n}`;o.push(`${c} = ${s}`),i=c}for(let c of r)c.startsWith("{")?o.push(`${c.replace(/\s+as\s+/g,": ")} = ${i}`):c.startsWith("*")?o.push(`${c.replace(/^\*\s*as\s+/,"")} = ${i}`):o.push(`${c} = $__default(${i})`);return`const ${o.join(", ")}`},ct=/^[A-Za-z_$][\w$]*$/,Re=(e,t)=>{let n=0,s=0;for(;s<e.length;){let r=e[s];if(r==="'"||r==='"'||r==="`"){s=j(e,s);continue}if(r==="/"&&e[s+1]==="/"){s=A(e,s);continue}if(r==="/"&&e[s+1]==="*"){s=v(e,s);continue}if(r==="/"&&r!==t&&M(e,s)){s=D(e,s);continue}if("([{".includes(r))n++;else if(")]}".includes(r))n--;else if(n===0&&r===t)return s;s++}return-1},$e=e=>{let t=[],n=0,s=0,r=0;for(;r<=e.length;){let o=e[r];if(o==="'"||o==='"'||o==="`"){r=j(e,r);continue}if(o==="/"&&e[r+1]==="/"){r=A(e,r);continue}if(o==="/"&&e[r+1]==="*"){r=v(e,r);continue}if(o==="/"&&M(e,r)){r=D(e,r);continue}if(o!==void 0&&"([{".includes(o))n++;else if(o!==void 0&&")]}".includes(o))n--;else if(r===e.length||o===","&&n===0){let i=e.slice(s,r).trim();i&&t.push(i),s=r+1}r++}return t},at=e=>{let t=0;for(;t<e.length;){let n=Re(e.slice(t),"=");if(n===-1)return-1;let s=t+n;if(e[s+1]!=="="&&e[s+1]!==">"&&e[s-1]!=="="&&e[s-1]!=="!")return s;t=s+1}return-1},re=e=>{let t=(e??"").trim();if(!t.startsWith("{"))return null;let n=0,s=0;for(;s<t.length;){let o=t[s];if(o==="'"||o==='"'||o==="`"){s=j(t,s);continue}if(o==="/"&&t[s+1]==="/"){s=A(t,s);continue}if(o==="/"&&t[s+1]==="*"){s=v(t,s);continue}if(o==="/"&&M(t,s)){s=D(t,s);continue}if("([{".includes(o))n++;else if(")]}".includes(o)&&--n===0)break;s++}if(s>=t.length)return null;let r=[];for(let o of $e(t.slice(1,s))){if(o.startsWith("..."))continue;let i=at(o),c=i===-1?o:o.slice(0,i),l=i===-1?void 0:o.slice(i+1).trim(),p=Re(c,":"),f=(p===-1?c:c.slice(0,p)).trim();ct.test(f)&&r.push(l===void 0?{name:f}:{name:f,default:l})}return r},lt=e=>{let t=0,n=0,s=!0;for(;t<e.length;){let r=e[t];if(r==="'"||r==='"'||r==="`"){t=j(e,t),s=!1;continue}if(r==="/"&&e[t+1]==="/"){t=A(e,t);continue}if(r==="/"&&e[t+1]==="*"){t=v(e,t);continue}if(r==="/"&&M(e,t)){t=D(e,t),s=!1;continue}if(r==="e"&&n===0&&s&&(t===0||!/[\w$.]/.test(e[t-1]))){X.lastIndex=t;let o=X.exec(e);if(o)return t+o[0].length}"([{".includes(r)?n++:")]}".includes(r)&&(n=Math.max(0,n-1)),r===`
6
+ `||r===";"||r==="}"?s=!0:/\s/.test(r)||(s=!1),t++}return-1},ft=/^async(?![\w$])/,ut=/^function(?![\w$])\s*\*?\s*[A-Za-z_$][\w$]*|^function(?![\w$])\s*\*?/,dt=e=>{let t=lt(e);if(t===-1)return null;let n=J(e,t),s=e.slice(n);ft.test(s)&&(n=J(e,n+5));let r=ut.exec(e.slice(n));if(r&&(n=J(e,n+r[0].length)),e[n]!=="(")return null;let o=0,i=n;for(;i<e.length;){let c=e[i];if(c==="'"||c==='"'||c==="`"){i=j(e,i);continue}if(c==="/"&&e[i+1]==="/"){i=A(e,i);continue}if(c==="/"&&e[i+1]==="*"){i=v(e,i);continue}if(c==="/"&&M(e,i)){i=D(e,i);continue}if("([{".includes(c))o++;else if(")]}".includes(c)&&--o===0)break;i++}return $e(e.slice(n+1,i))[0]??""},xe=e=>{let t=dt(e);if(t===null)return null;let n=re(t),s=n?.find(r=>r.name.startsWith("$"))?.name;if(s)throw new Error(`jq79: the factory signature is (props, ctx), so \`${s}\` can't be destructured from the first parameter. Write \`export default (props, { ${s} }) => \u2026\`, or \`_\` in place of props if the component takes none.`);return n},Te=e=>{let t="",n=0,s=0,r=!0,o=!1,i=0;for(;n<e.length;){let c=e[n],l=e[n+1],p=n===0||!/[\w$.]/.test(e[n-1]);if(c==="'"||c==='"'||c==="`"){let f=j(e,n);t+=e.slice(n,f),n=f,r=!1;continue}if(c==="/"&&(l==="/"||l==="*")){let f=l==="/"?A(e,n):v(e,n);t+=e.slice(n,f),n=f;continue}if(c==="/"&&M(e,n)){let f=D(e,n);t+=e.slice(n,f),n=f,r=!1;continue}if(c==="i"&&p){if(V.lastIndex=n,V.test(e)){t+="$__import",n+=6,r=!1;continue}if(s===0&&r){we.lastIndex=n;let f=we.exec(e);if(f){t+=it(f[1],f[3],i++),n+=f[0].length,r=!1;continue}}}if(c==="e"&&p&&s===0&&r){X.lastIndex=n;let f=X.exec(e);if(f){o=!0,t+="$__exports.default =",n+=f[0].length,r=!1;continue}}"([{".includes(c)?s++:")]}".includes(c)&&(s=Math.max(0,s-1)),c===`
7
+ `||c===";"||c==="}"?r=!0:/\s/.test(c)||(r=!1),t+=c,n++}return o?t:null};var je=e=>Object.fromEntries(Array.from(e.attributes).map(t=>[t.name,t.value])),Me=e=>({tag:e.tagName.toLowerCase(),attrs:je(e),children:Array.from(e.childNodes).flatMap(t=>{if(t.nodeType===Node.TEXT_NODE){let n=t.textContent??"";return n?[n]:[]}return t.nodeType===Node.ELEMENT_NODE?[Me(t)]:[]})}),Ce=new Map,pt=(e,t)=>{let n=`${t.join(",")}|${e}`,s=Ce.get(n);if(s===void 0){try{s=new Function("$scope",...t,`with ($scope) { return (${e}); }`)}catch{s=null}Ce.set(n,s)}return s},_=(e,t,n)=>{let s=pt(e,n?Object.keys(n):[]);if(s)try{return s(t,...n?Object.values(n):[])}catch{return}},ht=(e,t)=>e.replace(/{{\s*([\s\S]+?)\s*}}/g,(n,s)=>_(s,t)??""),De=new Set([":attrs",":class",":if",":elseif",":else",":each",":key",":with",":text",":html"]),mt=/^\s*\(?\s*(\w+)\s*(?:,\s*(\w+))?\s*\)?\s+in\s+([\s\S]+)$/,gt=(e,t,n,s)=>{let[r,...o]=t.slice(1).split("."),i=new Set(o);e.addEventListener(r,c=>{if(i.has("self")&&c.target!==e)return;i.has("prevent")&&c.preventDefault(),i.has("stop")&&c.stopPropagation();let l=_(n,s,{$event:c});typeof l=="function"&&l.call(e,c)},{once:i.has("once"),capture:i.has("capture")})},Ne=e=>e.replace(/-(\w)/g,(t,n)=>n.toUpperCase()),ie=e=>e instanceof DocumentFragment?{first:e.firstChild,last:e.lastChild}:{first:e,last:e},Q=({first:e,last:t})=>{for(let n=e;n;){let s=n===t?null:n.nextSibling;n.parentNode?.removeChild(n),n=s}},yt=({first:e,last:t},n)=>{let s=n.nextSibling;for(let r=e;r;){let o=r===t?null:r.nextSibling;n.parentNode.insertBefore(r,s),r=o}},_e=(e,t)=>{let n=t.replace(/-/g,"").toLowerCase();for(let s=e;s&&s!==Object.prototype;s=Object.getPrototypeOf(s))for(let r of Object.keys(s))if(/^[A-Z]/.test(r)&&r.replace(/-/g,"").toLowerCase()===n)return r;return null},Le=(e,t,n,s,r)=>{let o=document.createComment(e),i=document.createComment(`/${e}`),c=document.createDocumentFragment();c.append(o,i);let l={};Object.entries(t.attrs).forEach(([d,m])=>{if(!(d===le||De.has(d)||d.startsWith("@")))if(d.startsWith(":")){let g=Ne(d.slice(1));l[g]=m||g}else l[Ne(d)]=JSON.stringify(m)});let p=null,f=null,E=null;return s.effect(()=>{let d=_(e,n),m=d instanceof F?d:null;if(m===f||(E?.dispose(),E=null,p?.destroy(),p=null,f=m,!m))return;let g=new F({template:m.template,scripts:m.scripts,styles:m.styles,modules:m.modules,filename:m.filename}),x=ne(()=>Object.fromEntries(Object.entries(l).map(([u,h])=>[u,_(h,n)]))),O=document.createDocumentFragment();(r?g.renderShadow(x):g.render(x)).mount(O),i.parentNode.insertBefore(O,i);let a=B(n);Object.entries(l).forEach(([u,h])=>{a.effect(()=>{g.data[u]=_(h,n)})}),E=a,p=g}),s.onDispose(()=>{E?.dispose(),p?.destroy()}),c},Et=(e,t)=>{let n=()=>{let s=_(e,t);return s!==null&&typeof s=="object"?s:null};return new Proxy(t,{has(s,r){let o=n();return o!==null&&Reflect.has(o,r)||Reflect.has(s,r)},get(s,r){let o=n();return o!==null&&Reflect.has(o,r)?o[r]:Reflect.get(s,r)},set(s,r,o){let i=n();return i!==null&&Reflect.has(i,r)?(i[r]=o,!0):Reflect.set(s,r,o)}})},Y=e=>typeof e=="string"?e.split(/\s+/).filter(Boolean):Array.isArray(e)?e.flatMap(Y):e!==null&&typeof e=="object"?Object.entries(e).flatMap(([t,n])=>n?Y(t):[]):[],ce=(e,t,n,s)=>{let r=e.attrs[":with"],o=r!==void 0?Et(r,t):t,i=_e(o,e.tag);if(i)return Le(i,e,o,n,s);let c=document.createElement(e.tag);if(c instanceof HTMLUnknownElement||e.tag.includes("-")){let d=!1;n.effect(()=>{if(d)return;let m=_e(o,e.tag);if(!m)return;d=!0;let g=Le(m,e,o,n,s),x=ie(g);n.onDispose(()=>Q(x)),c.replaceWith(g)})}Object.entries(e.attrs).forEach(([d,m])=>{d.startsWith("@")?gt(c,d,m,o):De.has(d)||c.setAttribute(d,m)});let l=e.attrs[":attrs"];if(l!==void 0){let d=[];n.effect(()=>{d.forEach(g=>c.removeAttribute(g));let m=_(l,o);d=m&&typeof m=="object"?Object.keys(m):[],d.forEach(g=>{let x=m[g];x!=null&&x!==!1&&c.setAttribute(g,String(x))})})}let p=e.attrs[":class"];if(p!==void 0){let d=new Set(Y(e.attrs.class??"")),m=[];n.effect(()=>{let g=Y(_(p,o));m.forEach(x=>{!g.includes(x)&&!d.has(x)&&c.classList.remove(x)}),c.classList.add(...g),m=g})}let f=e.attrs[":text"],E=e.attrs[":html"];return f!==void 0?n.effect(()=>{c.textContent=String(_(f,o)??"")}):E!==void 0?n.effect(()=>{c.innerHTML=he(String(_(E,o)??""))}):c.appendChild(ae(e.children,o,n,s)),c},bt=(e,t,n,s)=>{let r=document.createComment("if"),o=document.createDocumentFragment();o.appendChild(r);let i=null,c=null,l=null;return n.effect(()=>{let p=e.find(E=>E.expr===void 0||_(E.expr,t))??null;if(p===c||(l?.dispose(),i&&Q(i),i=null,c=p,!p))return;l=B(t);let f=ce(p.node,t,l,s);i=ie(f),r.parentNode.insertBefore(f,r.nextSibling)}),o},H=(e,t,n)=>{Object.defineProperty(e,t,{value:n,writable:!0,enumerable:!0,configurable:!0})},St=e=>{if(e===null||typeof e!="object"||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},wt=(e,t,n,s)=>{let r=e.attrs[":each"].match(mt);if(!r)return document.createComment(`invalid :each expression "${e.attrs[":each"]}"`);let[,o,i,c]=r,l=e.attrs[":key"],{[":each"]:p,[":key"]:f,...E}=e.attrs,d={...e,attrs:E},m=document.createComment("each"),g=document.createDocumentFragment();g.appendChild(m),(":if"in e.attrs||":elseif"in e.attrs||":else"in e.attrs)&&console.warn("jq79: :if/:elseif/:else on a :each element is ignored; filter the list expression instead");let x=[],O=!1;return n.effect(()=>{let a=_(c,t),u=Array.isArray(a)?a.map((b,w)=>[w,b]):St(a)?Object.entries(a):[],h=new Map;x.forEach(b=>{let w=h.get(b.key);w?w.push(b):h.set(b.key,[b])});let S=new Set,T=[],R=u.map(([b,w],N)=>{let $=Object.create(t);H($,o,w),i&&H($,i,b),H($,"$index",N);let P=l!==void 0?_(l,$):b;S.has(P)&&!O&&(O=!0,console.warn(`jq79: duplicate :key in :each "${e.attrs[":each"]}"; duplicates pair up by position`)),S.add(P);let L=h.get(P)?.shift();if(L&&Object.is(L.item,w))return L.scope.$index!==N&&T.push(L),H(L.scope,"$index",N),i&&H(L.scope,i,b),L;L&&(L.fx.dispose(),Q(L.range));let ue=B(t),Ue=ie(ce(d,$,ue,s));return{key:P,item:w,scope:$,fx:ue,range:Ue}});h.forEach(b=>b.forEach(w=>{w.fx.dispose(),Q(w.range)}));let y=m;R.forEach(b=>{y.nextSibling!==b.range.first&&yt(b.range,y),y=b.range.last}),T.forEach(b=>ne(()=>b.fx.refresh())),x=R}),g},ae=(e,t,n,s=!1)=>{let r=document.createDocumentFragment(),o=0;for(;o<e.length;){let i=e[o];if(typeof i=="string"){let c=document.createTextNode(i);i.includes("{{")&&n.effect(()=>{c.textContent=ht(i,t)}),r.appendChild(c),o++;continue}if(":each"in i.attrs){r.appendChild(wt(i,t,n,s)),o++;continue}if(":if"in i.attrs){let c=[{expr:i.attrs[":if"],node:i}];o++;let l=f=>{let E=o;for(;E<e.length&&typeof e[E]=="string"&&!e[E].trim();)E++;let d=e[E];if(typeof d=="object"&&f in d.attrs)return o=E+1,d};for(let f=l(":elseif");f;f=l(":elseif"))c.push({expr:f.attrs[":elseif"],node:f});let p=l(":else");p&&c.push({node:p}),r.appendChild(bt(c,t,n,s));continue}r.appendChild(ce(i,t,n,s)),o++}return r},Rt=(e,t,n=!1)=>ae(e.template,t,B(t),n),$t=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]),xt=/<([A-Za-z][\w-]*)((?:"[^"]*"|'[^']*'|[^>"'])*?)\/>/g,Tt=/(<script[\s\S]*?<\/script\s*>|<style[\s\S]*?<\/style\s*>)/gi,Ct=e=>e.split(Tt).map((t,n)=>n%2===1?t:t.replace(xt,(s,r,o)=>$t.has(r.toLowerCase())?s:`<${r}${o}></${r}>`)).join(""),le="data-jq79",Nt=e=>{let t=2166136261;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),16777619);return(t>>>0).toString(36)},Pe=(e,t)=>{e.forEach(n=>{typeof n!="string"&&(n.attrs[le]=t,Pe(n.children,t))})},_t=(e,t)=>e.split(",").map(n=>{let s=n.trim(),r=s.indexOf("::"),o=r===-1?s:s.slice(0,r),i=r===-1?"":s.slice(r);return`${o}[${le}="${t}"]${i}`}).join(", "),ke=(e,t)=>{Array.from(e).forEach(n=>{n instanceof CSSStyleRule?n.selectorText=_t(n.selectorText,t):n instanceof CSSGroupingRule&&ke(n.cssRules,t)})},Lt=(e,t)=>{/:deep\(|::v-deep|>>>/.test(e)&&console.warn("jq79: :deep()/::v-deep/>>> are not supported in <style scoped>; the rule will be dropped by the browser");let n=new CSSStyleSheet;return n.replaceSync(e),ke(n.cssRules,t),Array.from(n.cssRules).map(s=>s.cssText).join(`
8
+ `)},oe=e=>{let n=new DOMParser().parseFromString(`<template>${Ct(e)}</template>`,"text/html").querySelector("template"),s=[],r=[],o=[];Array.from(n.content.children).forEach(c=>{let l={attrs:je(c),content:c.textContent??""};c.tagName==="SCRIPT"?s.push(l):c.tagName==="STYLE"?r.push(l):o.push(Me(c))}),r.forEach(c=>{"lang"in c.attrs&&console.warn(`jq79: <style lang="${c.attrs.lang}"> needs the jq79/vite plugin to compile it. This component didn't go through the bundler, so its styles were left uncompiled and the browser will ignore them.`)});let i=c=>"scoped"in c.attrs&&!("lang"in c.attrs);if(r.some(i)){let c=Nt(e);Pe(o,c),r.forEach(l=>{i(l)&&(l.scoped=Lt(l.content,c))})}return{template:o,scripts:s,styles:r}},fe=e=>/\.html?([?#]|$)/.test(e)?F.fetch(e):import(e),Fe=(e,t)=>e?`
9
+ //# sourceURL=${e}?jq79-script=${t}`:"",Oe=e=>e.scoped??e.content,ee=new Map,Ot=e=>{let t=ee.get(e);if(!t){let n=document.createElement("style");n.textContent=e,document.head.appendChild(n),t={el:n,count:0},ee.set(e,t)}t.count++},At=e=>{let t=ee.get(e);t&&--t.count<=0&&(t.el.remove(),ee.delete(e))},Ie={$:I,$$:G,$create:K,$reactive:q},vt=(e,t,n,s={},r=fe,o={})=>{let i={...Ie,...s},c=new Proxy(t,{has:(p,f)=>f!=="$__effect"&&f!=="$__import"&&(Reflect.has(p,f)||!(f in globalThis)&&!(f in i))});new Function("$scope","$__effect","$__import",...Object.keys(i),`return (async () => { with ($scope) { ${e} } })()${Fe(o.filename,o.index??0)}`)(c,n,r,...Object.values(i)).catch(p=>console.error("jq79: error in :setup script",p))},Ae=(e,t)=>{t?.forEach(({name:n,default:s})=>{e[n]===void 0&&(e[n]=s===void 0?void 0:_(s,e))})},jt=e=>e&&e.default!==void 0?e.default:e,Mt=(e,t,n,s={},r=fe,o={})=>{let i={...Ie,...s},c={},l=new Function("$__exports","$__default","$__import",...Object.keys(i),`return (async () => { "use strict";
9
10
  ${e}
10
- ;$__exports.done = true })()${Le(o.filename,o.index??0)}`)(i,wt,r,...Object.values(c)),h=d=>console.error("jq79: error in factory script",d),f=!1,p=()=>{if(f)return;f=!0;let d=i.default;if(typeof d!="function")return;let E=y=>{y&&typeof y=="object"&&Object.assign(t,y)};try{let y=d(t,{$data:t,$props:t,$effect:n,...s});y instanceof Promise?y.then(E).catch(h):E(y)}catch(y){h(y)}};l.then(p,h),i.done&&p()},xt="__JQ79_HMR_ENABLED__",Tt="__JQ79_HMR__",O=null,Ct=e=>{if(!O||!e.filename)return;let t=O.get(e.filename);t||O.set(e.filename,t=new Set),t.add(new WeakRef(e))},Re=e=>{try{return new URL(e,document.baseURI).pathname}catch{return e}},Ae=(e,t)=>{if(!O)return 0;let n=Re(e),s=V(t),r=0;for(let[o,c]of O)if(Re(o)===n){for(let i of c){let l=i.deref();if(!l){c.delete(i);continue}l.hotReplace(s)&&r++}c.size||O.delete(o)}return r},Oe=()=>{O??(O=new Map),globalThis[Tt]={update:Ae}},M=class e{constructor(t,n={}){w(this,"template");w(this,"scripts");w(this,"styles");w(this,"modules");w(this,"filename");w(this,"data",null);w(this,"fx",null);w(this,"content",null);w(this,"startMarker",null);w(this,"endMarker",null);w(this,"styleEls",[]);w(this,"ownsSharedStyles",!1);w(this,"useShadow",!1);w(this,"mountRoot",null);w(this,"resolveMounted",null);w(this,"emitListeners",new Map);let s=typeof t=="string"?V(t):t;this.template=s.template,this.scripts=s.scripts,this.styles=s.styles,this.modules=n.modules??(typeof t=="string"?void 0:t.modules),this.filename=n.filename??(typeof t=="string"?void 0:t.filename),Ct(this)}hotReplace(t){let n=typeof t=="string"?V(t):t,s=this.startMarker,r=!!(s&&this.content),o=r&&s.isConnected,c=o?s.parentNode:null,i=o?this.endMarker.nextSibling:null,l={...this.data},h=this.useShadow;return r&&this.destroy(),this.template=n.template,this.scripts=n.scripts,this.styles=n.styles,!r||(this.renderWith(l,h),!c)?!1:(h&&this.styleEls.forEach(f=>c.insertBefore(f,i)),c.insertBefore(this.content,i),this.mountRoot=c,this.resolveMounted?.(),!0)}static async fetch(t){let n=await fetch(t);if(!n.ok)throw new Error(`failed to fetch component from ${t}: ${n.status}`);return new e(await n.text(),{filename:t})}on(t,n){return this.emitListeners.has(t)||this.emitListeners.set(t,new Set),this.emitListeners.get(t).add(n),this}off(t,n){return this.emitListeners.get(t)?.delete(n),this}render(t={}){return this.renderWith(t,!1)}renderShadow(t={}){return this.renderWith(t,!0)}renderWith(t,n){this.destroy();let s=F({...t}),r=P(s);this.data=s,this.fx=r,this.useShadow=n,this.startMarker=document.createComment("jq79"),this.endMarker=document.createComment("/jq79");let o=this.startMarker,c=(a,u)=>{let g=new CustomEvent(a,{detail:u,bubbles:!0,composed:!0}),b=o.dispatchEvent(g);return o===this.startMarker&&this.emitListeners.get(a)?.forEach(m=>m(g,u)),b},i,l=new Promise(a=>{i=a});this.resolveMounted=i;let h=()=>l,f=this.endMarker,p=a=>{let u=[];for(let g=o.nextSibling;g&&g!==f;g=g.nextSibling)g instanceof Element&&(g.matches(a)&&u.push(g),u.push(...Array.from(g.querySelectorAll(a))));return u},d=a=>p(a)[0]??null,E=this.modules,y=a=>E&&a in E?Promise.resolve(E[a]):ee(a),_=a=>`await $mounted();${a}`;this.scripts.forEach((a,u)=>{let g={$emit:c,$mounted:h,$self:d,$$self:p},b={filename:this.filename,index:u},m=ge(a.content);if(m!==null){we(s,me(a.content));let $=":mounted"in a.attrs?_(m):m;Rt($,s,r.effect,g,y,b);return}let{vars:S,code:R}=de(a.content);we(s,Z(a.attrs[":setup"])),S.forEach($=>{$ in s||(s[$]=void 0)});let C=":mounted"in a.attrs?_(R):R;$t(C,s,r.effect,g,y,b)});let N=document.createDocumentFragment();return N.append(this.startMarker,Q(this.template,s,r,n),this.endMarker),this.content=N,n?this.styleEls=this.styles.map(a=>{let u=document.createElement("style");return u.textContent=a.content,u}):(this.styles.forEach(a=>bt($e(a))),this.ownsSharedStyles=!0),this}mount(t,n){let s=typeof t=="string"?j(t):t;if(!s)throw new Error(`mount target not found: ${t}`);return(!this.content||n!==void 0)&&this.renderWith(n??{},this.useShadow),this.attach(s)}mountShadow(t,n){let s=typeof t=="string"?j(t):t;if(!s)throw new Error(`mount target not found: ${t}`);return(!this.content||n!==void 0||!this.useShadow)&&this.renderWith(n??{},!0),this.attach(s)}attach(t){this.mountRoot&&this.detach();let n=this.useShadow&&t instanceof Element?t.shadowRoot??t.attachShadow({mode:"open"}):t;return this.useShadow&&this.styleEls.forEach(s=>n.appendChild(s)),n.appendChild(this.content),this.mountRoot=n,this.resolveMounted?.(),this}detach(){if(!this.mountRoot||!this.content||!this.startMarker||!this.endMarker)return this;let t=this.startMarker;for(;t;){let n=t.nextSibling;if(this.content.appendChild(t),t===this.endMarker)break;t=n}return this.mountRoot=null,this}destroy(){return this.detach(),this.fx?.dispose(),this.fx=null,this.data?.$dispose(),this.styleEls.forEach(t=>t.parentNode?.removeChild(t)),this.styleEls=[],this.ownsSharedStyles&&(this.styles.forEach(t=>St($e(t))),this.ownsSharedStyles=!1),this.content=null,this.startMarker=null,this.endMarker=null,this.data=null,this.resolveMounted=null,this}},_t=e=>new M(e);typeof globalThis<"u"&&globalThis[xt]&&Oe();0&&(module.exports={$,$$,$create,$reactive,Component79,enableHotReload,hotUpdate,parseComponent,renderComponent});
11
+ ;$__exports.done = true })()${Fe(o.filename,o.index??0)}`)(c,jt,r,...Object.values(i)),p=d=>console.error("jq79: error in factory script",d),f=!1,E=()=>{if(f)return;f=!0;let d=c.default;if(typeof d!="function")return;let m=g=>{g&&typeof g=="object"&&Object.assign(t,g)};try{let g=d(t,{$data:t,$props:t,$effect:n,...s});g instanceof Promise?g.then(m).catch(p):m(g)}catch(g){p(g)}};l.then(E,p),c.done&&E()},Dt="__JQ79_HMR_ENABLED__",Pt="__JQ79_HMR__",k=null,kt=e=>{if(!k||!e.filename)return;let t=k.get(e.filename);t||k.set(e.filename,t=new Set),t.add(new WeakRef(e))},ve=e=>{try{return new URL(e,document.baseURI).pathname}catch{return e}},We=(e,t)=>{if(!k)return 0;let n=ve(e),s=oe(t),r=0;for(let[o,i]of k)if(ve(o)===n){for(let c of i){let l=c.deref();if(!l){i.delete(c);continue}l.hotReplace(s)&&r++}i.size||k.delete(o)}return r},Be=()=>{k??(k=new Map),globalThis[Pt]={update:We}},F=class e{constructor(t,n={}){C(this,"template");C(this,"scripts");C(this,"styles");C(this,"modules");C(this,"filename");C(this,"data",null);C(this,"fx",null);C(this,"content",null);C(this,"startMarker",null);C(this,"endMarker",null);C(this,"styleEls",[]);C(this,"ownsSharedStyles",!1);C(this,"useShadow",!1);C(this,"mountRoot",null);C(this,"resolveMounted",null);C(this,"emitListeners",new Map);let s=typeof t=="string"?oe(t):t;this.template=s.template,this.scripts=s.scripts,this.styles=s.styles,this.modules=n.modules??(typeof t=="string"?void 0:t.modules),this.filename=n.filename??(typeof t=="string"?void 0:t.filename),kt(this)}hotReplace(t){let n=typeof t=="string"?oe(t):t,s=this.startMarker,r=!!(s&&this.content),o=r&&s.isConnected,i=o?s.parentNode:null,c=o?this.endMarker.nextSibling:null,l={...this.data},p=this.useShadow;return r&&this.destroy(),this.template=n.template,this.scripts=n.scripts,this.styles=n.styles,!r||(this.renderWith(l,p),!i)?!1:(p&&this.styleEls.forEach(f=>i.insertBefore(f,c)),i.insertBefore(this.content,c),this.mountRoot=i,this.resolveMounted?.(),!0)}static async fetch(t){let n=await fetch(t);if(!n.ok)throw new Error(`failed to fetch component from ${t}: ${n.status}`);return new e(await n.text(),{filename:t})}on(t,n){return this.emitListeners.has(t)||this.emitListeners.set(t,new Set),this.emitListeners.get(t).add(n),this}off(t,n){return this.emitListeners.get(t)?.delete(n),this}render(t={}){return this.renderWith(t,!1)}renderShadow(t={}){return this.renderWith(t,!0)}renderWith(t,n){this.destroy();let s=q({...t}),r=B(s);this.data=s,this.fx=r,this.useShadow=n,this.startMarker=document.createComment("jq79"),this.endMarker=document.createComment("/jq79");let o=this.startMarker,i=(a,u)=>{let h=new CustomEvent(a,{detail:u,bubbles:!0,composed:!0}),S=o.dispatchEvent(h);return o===this.startMarker&&this.emitListeners.get(a)?.forEach(T=>T(h,u)),S},c,l=new Promise(a=>{c=a});this.resolveMounted=c;let p=()=>l,f=this.endMarker,E=a=>{let u=[];for(let h=o.nextSibling;h&&h!==f;h=h.nextSibling)h instanceof Element&&(h.matches(a)&&u.push(h),u.push(...Array.from(h.querySelectorAll(a))));return u},d=a=>E(a)[0]??null,m=this.modules,g=a=>m&&a in m?Promise.resolve(m[a]):fe(a),x=a=>`await $mounted();${a}`;this.scripts.forEach((a,u)=>{let h={$emit:i,$mounted:p,$self:d,$$self:E},S={filename:this.filename,index:u},T=Te(a.content);if(T!==null){Ae(s,xe(a.content));let w=":mounted"in a.attrs?x(T):T;Mt(w,s,r.effect,h,g,S);return}let{vars:R,code:y}=se(a.content);Ae(s,re(a.attrs[":setup"])),R.forEach(w=>{w in s||(s[w]=void 0)});let b=":mounted"in a.attrs?x(y):y;vt(b,s,r.effect,h,g,S)});let O=document.createDocumentFragment();return O.append(this.startMarker,ae(this.template,s,r,n),this.endMarker),this.content=O,n?this.styleEls=this.styles.map(a=>{let u=document.createElement("style");return u.textContent=a.content,u}):(this.styles.forEach(a=>Ot(Oe(a))),this.ownsSharedStyles=!0),this}mount(t,n){let s=typeof t=="string"?I(t):t;if(!s)throw new Error(`mount target not found: ${t}`);return(!this.content||n!==void 0)&&this.renderWith(n??{},this.useShadow),this.attach(s)}mountShadow(t,n){let s=typeof t=="string"?I(t):t;if(!s)throw new Error(`mount target not found: ${t}`);return(!this.content||n!==void 0||!this.useShadow)&&this.renderWith(n??{},!0),this.attach(s)}attach(t){this.mountRoot&&this.detach();let n=this.useShadow&&t instanceof Element?t.shadowRoot??t.attachShadow({mode:"open"}):t;return this.useShadow&&this.styleEls.forEach(s=>n.appendChild(s)),n.appendChild(this.content),this.mountRoot=n,this.resolveMounted?.(),this}detach(){if(!this.mountRoot||!this.content||!this.startMarker||!this.endMarker)return this;let t=this.startMarker;for(;t;){let n=t.nextSibling;if(this.content.appendChild(t),t===this.endMarker)break;t=n}return this.mountRoot=null,this}destroy(){return this.detach(),this.fx?.dispose(),this.fx=null,this.data?.$dispose(),this.styleEls.forEach(t=>t.parentNode?.removeChild(t)),this.styleEls=[],this.ownsSharedStyles&&(this.styles.forEach(t=>At(Oe(t))),this.ownsSharedStyles=!1),this.content=null,this.startMarker=null,this.endMarker=null,this.data=null,this.resolveMounted=null,this}},Ft=e=>new F(e);typeof globalThis<"u"&&globalThis[Dt]&&Be();0&&(module.exports={$,$$,$create,$reactive,Component79,enableHotReload,hotUpdate,parseComponent,renderComponent});
11
12
  //# sourceMappingURL=jq79.cjs.map