@loadbare/app 0.24.0 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/assemble.d.ts +1 -2
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +61 -53
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.d.ts +4 -10
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +11 -33
- package/dist/build/cli.js.map +1 -1
- package/dist/build/declared.js +1 -1
- package/dist/build/declared.js.map +1 -1
- package/dist/core/lb-constants.d.ts +8 -18
- package/dist/core/lb-constants.d.ts.map +1 -1
- package/dist/core/lb-constants.js +32 -72
- package/dist/core/lb-constants.js.map +1 -1
- package/dist/core/lb-types.d.ts +12 -11
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +7 -0
- package/dist/core/lb-types.js.map +1 -1
- package/dist/hub/lb-apply.d.ts +23 -37
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +205 -518
- package/dist/hub/lb-apply.js.map +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +159 -132
- package/dist/hub/lb-hub.browser.js.map +1 -1
- package/dist/hub/lb-lifecycle.d.ts +2 -2
- package/dist/hub/lb-lifecycle.d.ts.map +1 -1
- package/dist/hub/lb-lifecycle.js +9 -17
- package/dist/hub/lb-lifecycle.js.map +1 -1
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +3 -3
- package/dist/server/lb-express.js.map +1 -1
- package/dist/server/lb-server.d.ts +35 -19
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +141 -88
- package/dist/server/lb-server.js.map +1 -1
- package/docs/binding-cases.md +150 -0
- package/docs/comparison.md +20 -29
- package/docs/miswarts.md +2 -2
- package/docs/reference/css.md +2 -15
- package/docs/reference/custom-elements.md +6 -8
- package/docs/reference/data-binding.md +100 -185
- package/docs/reference/names.md +11 -27
- package/docs/reference/page-files.md +4 -14
- package/docs/reference/server.md +0 -1
- package/docs/testing.md +2 -5
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +66 -56
- package/skills/loadbare-app/references/css.md +2 -15
- package/skills/loadbare-app/references/custom-elements.md +6 -8
- package/skills/loadbare-app/references/data-binding.md +100 -185
- package/skills/loadbare-app/references/miswarts.md +2 -2
- package/skills/loadbare-app/references/names.md +11 -27
- package/skills/loadbare-app/references/page-files.md +4 -14
- package/skills/loadbare-app/references/server.md +0 -1
- package/docs/temp-proposals.md +0 -251
package/dist/build/assemble.d.ts
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* expanded host is wrapped in `<template lb-page="<name>">` and, together
|
|
10
10
|
* with the chrome's own expanded body content, spliced back into the
|
|
11
11
|
* chrome's `<body>`. The result is the one document a server has to serve
|
|
12
|
-
* for every route — see docs/tutorials/000-getting-started.md
|
|
13
|
-
* docs/reference/builder.md.
|
|
12
|
+
* for every route — see docs/tutorials/000-getting-started.md.
|
|
14
13
|
*
|
|
15
14
|
* Every path here is a parameter, resolved once by build/locations.ts — this
|
|
16
15
|
* module never reconstructs one of its own, and never reads a directory
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../build/assemble.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../build/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAyCH,OAAO,KAAK,EAAY,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAmgB/C,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8EAA8E;IAC9E,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACvB;AAED,wBAAsB,QAAQ,CAAC,EAC7B,UAAU,EACV,KAAK,EACL,KAAK,EACL,QAAQ,GACT,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC,CAgEtC"}
|
package/dist/build/assemble.js
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* expanded host is wrapped in `<template lb-page="<name>">` and, together
|
|
10
10
|
* with the chrome's own expanded body content, spliced back into the
|
|
11
11
|
* chrome's `<body>`. The result is the one document a server has to serve
|
|
12
|
-
* for every route — see docs/tutorials/000-getting-started.md
|
|
13
|
-
* docs/reference/builder.md.
|
|
12
|
+
* for every route — see docs/tutorials/000-getting-started.md.
|
|
14
13
|
*
|
|
15
14
|
* Every path here is a parameter, resolved once by build/locations.ts — this
|
|
16
15
|
* module never reconstructs one of its own, and never reads a directory
|
|
@@ -19,7 +18,7 @@
|
|
|
19
18
|
import { readFile } from "node:fs/promises";
|
|
20
19
|
import { addDefinitions, customElementTags, expandTree, } from "./expand.js";
|
|
21
20
|
import { formatHtml } from "./format.js";
|
|
22
|
-
import {
|
|
21
|
+
import { ATTR_FILTER, ATTR_MANUAL, MANUAL_FILTER, MANUAL_ORDER, ATTR_COLUMN, ATTR_PAGE, ATTR_PAGE_TITLE, ATTR_QUERY, ATTR_REQUEST, ATTR_SHOW, ATTR_URL_LINK, ATTR_URL_PUSH, ATTR_URL_PARM, ATTR_URL_UNKNOWN, FILTERS_QUERY, SORT_QUERY, HUB_QUERY, DEVELOPER_ATTRIBUTES, HUB_TAG_NAME, LB_COMMAND_PREFIX, COMMAND_NEW, LB_COMMANDS, LB_RESERVED_PREFIX, REQUEST_ROW_DELETE, REQUEST_ROW_INSERT, REQUEST_ROW_UPDATE, SHOW_NOT, URL_QUERY, } from "../core/lb-constants.js";
|
|
23
22
|
import { isRowRequest } from "../core/lb-types.js";
|
|
24
23
|
/**
|
|
25
24
|
* The hub is one element, and it swaps each page into the one `<main>`
|
|
@@ -70,7 +69,7 @@ function checkUnknownPageDialog(chromeFile, body) {
|
|
|
70
69
|
}
|
|
71
70
|
}
|
|
72
71
|
/** The queries the hub serves, which every page and the chrome may name. */
|
|
73
|
-
const HUB_QUERIES = [URL_QUERY,
|
|
72
|
+
const HUB_QUERIES = [URL_QUERY, SORT_QUERY, FILTERS_QUERY, HUB_QUERY];
|
|
74
73
|
/** The `Crud` key each request Loadbare provides runs. */
|
|
75
74
|
const CRUD_KEYS = {
|
|
76
75
|
[REQUEST_ROW_INSERT]: "rowInsert",
|
|
@@ -147,7 +146,7 @@ function checkNames(el, scope, names, problems) {
|
|
|
147
146
|
*
|
|
148
147
|
* Every rule here is a fact the markup states about itself. The developer
|
|
149
148
|
* writes `lb-*` attributes in markup, and script never assigns them, which is
|
|
150
|
-
* what makes checking the markup sound.
|
|
149
|
+
* what makes checking the markup sound.
|
|
151
150
|
*
|
|
152
151
|
* A `<template>`'s children are walked in the scope that encloses the
|
|
153
152
|
* template, because a row template's clones land in the element around it.
|
|
@@ -221,24 +220,6 @@ function walkMarkup(node, scope, names, problems) {
|
|
|
221
220
|
`column of ${URL_QUERY} holds several, so it goes inside ` +
|
|
222
221
|
`${ATTR_QUERY}="${URL_QUERY}"`);
|
|
223
222
|
}
|
|
224
|
-
// A selector is a checkbox in a live row, and selects that row. It is no
|
|
225
|
-
// column, and commits nothing of its own.
|
|
226
|
-
if (el.hasAttribute(ATTR_SELECT)) {
|
|
227
|
-
if (tag !== "input" || el.getAttribute("type") !== "checkbox") {
|
|
228
|
-
problems.push(`<${tag}> carries ${ATTR_SELECT}; it goes on an ` +
|
|
229
|
-
`<input type="checkbox">`);
|
|
230
|
-
}
|
|
231
|
-
else if (scope?.row !== true) {
|
|
232
|
-
problems.push(`<input> carries ${ATTR_SELECT} outside a row template; it ` +
|
|
233
|
-
`selects the row it sits in`);
|
|
234
|
-
}
|
|
235
|
-
for (const name of [ATTR_COLUMN, ATTR_REQUEST]) {
|
|
236
|
-
if (el.hasAttribute(name)) {
|
|
237
|
-
problems.push(`<${tag}> carries ${ATTR_SELECT} and ${name}; a selector is no ` +
|
|
238
|
-
`column and sends nothing`);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
223
|
// HTML's own command attribute, whose `--lb-` values are Loadbare's.
|
|
243
224
|
const command = el.getAttribute("command");
|
|
244
225
|
if (command !== null && command.startsWith(LB_COMMAND_PREFIX)) {
|
|
@@ -254,39 +235,16 @@ function walkMarkup(node, scope, names, problems) {
|
|
|
254
235
|
if (el.hasAttribute(ATTR_URL_UNKNOWN) && tag !== "dialog") {
|
|
255
236
|
problems.push(`<${tag}> carries ${ATTR_URL_UNKNOWN}; it goes on a <dialog>`);
|
|
256
237
|
}
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
if (
|
|
261
|
-
if (tag !== "template") {
|
|
262
|
-
problems.push(`<${tag}> carries ${ATTR_GROUP}; it goes on a <template>`);
|
|
263
|
-
}
|
|
264
|
-
else if (!el.content.querySelector(`template:not([${ATTR_SHOW}])`)) {
|
|
265
|
-
problems.push(`a <template ${ATTR_GROUP}> holds no <template> for its contents`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
for (const name of AGGREGATES) {
|
|
269
|
-
if (!el.hasAttribute(name))
|
|
270
|
-
continue;
|
|
271
|
-
if (tag === "template") {
|
|
272
|
-
problems.push(`a <template> carries ${name}; it goes on an element`);
|
|
273
|
-
}
|
|
274
|
-
else if (name !== ATTR_COUNT && !el.getAttribute(name)) {
|
|
275
|
-
problems.push(`<${tag}> carries ${name} naming no column`);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
// The user's order and filter for the rows an element holds, each read
|
|
279
|
-
// from a column of lb-choices it names.
|
|
280
|
-
for (const name of [ATTR_ORDER, ATTR_FILTER]) {
|
|
281
|
-
const value = el.getAttribute(name);
|
|
282
|
-
if (value === null)
|
|
283
|
-
continue;
|
|
238
|
+
// The columns of its rows an element lets the user filter, read from its
|
|
239
|
+
// row of lb-filters.
|
|
240
|
+
const filterValue = el.getAttribute(ATTR_FILTER);
|
|
241
|
+
if (filterValue !== null) {
|
|
284
242
|
if (!el.hasAttribute(ATTR_QUERY)) {
|
|
285
|
-
problems.push(`<${tag}> carries ${
|
|
243
|
+
problems.push(`<${tag}> carries ${ATTR_FILTER}; it goes on the element carrying ` +
|
|
286
244
|
`${ATTR_QUERY}`);
|
|
287
245
|
}
|
|
288
|
-
else if (
|
|
289
|
-
problems.push(`<${tag}> carries ${
|
|
246
|
+
else if (filterValue.trim() === "") {
|
|
247
|
+
problems.push(`<${tag}> carries ${ATTR_FILTER} naming no column`);
|
|
290
248
|
}
|
|
291
249
|
}
|
|
292
250
|
const manual = el.getAttribute(ATTR_MANUAL);
|
|
@@ -388,10 +346,60 @@ function expandFile(file, source, defs) {
|
|
|
388
346
|
function checkMarkup(file, root, names) {
|
|
389
347
|
const problems = [];
|
|
390
348
|
walkMarkup(root, null, names, problems);
|
|
349
|
+
checkNewTargets(root, problems);
|
|
391
350
|
if (problems.length > 0) {
|
|
392
351
|
throw new Error(`assemble: '${file}' markup:\n ` + problems.join(`\n `));
|
|
393
352
|
}
|
|
394
353
|
}
|
|
354
|
+
/** Every element under root, template content included. */
|
|
355
|
+
function everyElement(root) {
|
|
356
|
+
const found = [];
|
|
357
|
+
for (const el of root.querySelectorAll("*")) {
|
|
358
|
+
found.push(el);
|
|
359
|
+
if (el.localName === "template") {
|
|
360
|
+
found.push(...everyElement(el.content));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return found;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* `--lb-new` aimed at a list rather than a form puts a row not yet entered
|
|
367
|
+
* in it, which only the submit of the form around it carries: the list is a
|
|
368
|
+
* query nested directly in a form's own query. A target the markup does not
|
|
369
|
+
* hold, as a page's own element named from the chrome, is not judged.
|
|
370
|
+
*/
|
|
371
|
+
function checkNewTargets(root, problems) {
|
|
372
|
+
const all = everyElement(root);
|
|
373
|
+
const byId = new Map();
|
|
374
|
+
for (const el of all) {
|
|
375
|
+
const id = el.getAttribute("id");
|
|
376
|
+
if (id !== null && !byId.has(id))
|
|
377
|
+
byId.set(id, el);
|
|
378
|
+
}
|
|
379
|
+
for (const button of all) {
|
|
380
|
+
if (button.getAttribute("command") !== COMMAND_NEW)
|
|
381
|
+
continue;
|
|
382
|
+
const target = byId.get(button.getAttribute("commandfor") ?? "");
|
|
383
|
+
if (!target || target.localName === "form")
|
|
384
|
+
continue;
|
|
385
|
+
const tag = target.localName;
|
|
386
|
+
if (!target.hasAttribute(ATTR_QUERY)) {
|
|
387
|
+
problems.push(`<${tag} id="${target.id}"> is aimed at by ${COMMAND_NEW}, and is ` +
|
|
388
|
+
`neither a <form> nor a list carrying ${ATTR_QUERY}`);
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const form = target.closest("form");
|
|
392
|
+
const own = form?.hasAttribute(ATTR_QUERY)
|
|
393
|
+
? form
|
|
394
|
+
: form?.parentElement?.closest(`[${ATTR_QUERY}]`);
|
|
395
|
+
const around = target.parentElement?.closest(`[${ATTR_QUERY}]`);
|
|
396
|
+
if (!form || !own || around !== own) {
|
|
397
|
+
problems.push(`<${tag} id="${target.id}"> is aimed at by ${COMMAND_NEW}, and is ` +
|
|
398
|
+
`not a query nested directly in a form's own; a row not yet ` +
|
|
399
|
+
`entered goes with the submit of the form around it`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
395
403
|
/**
|
|
396
404
|
* A page file's `<title>` names the page. It is lifted out, since a page is
|
|
397
405
|
* a fragment inside `<main>` and a `<title>` belongs in a document's head,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../build/assemble.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Assembling one document out of a chrome file and a set of pages.\n *\n * Every `.html` file in play — the chrome and each page — goes through the\n * same `expand()` (see build/expand.ts) against the same definitions: the\n * built-in widgets and whatever definitions were found in the caller's own\n * source tree. `expand()` only ever sees a fragment, so the chrome's own is\n * the text between its `<body>` tags; a page's is the whole file. A page's\n * expanded host is wrapped in `<template lb-page=\"<name>\">` and, together\n * with the chrome's own expanded body content, spliced back into the\n * chrome's `<body>`. The result is the one document a server has to serve\n * for every route — see docs/tutorials/000-getting-started.md and\n * docs/reference/builder.md.\n *\n * Every path here is a parameter, resolved once by build/locations.ts — this\n * module never reconstructs one of its own, and never reads a directory\n * looking for pages or widgets; it is handed exactly which files those are.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport {\n addDefinitions,\n customElementTags,\n expandTree,\n type Definitions,\n} from \"./expand.js\";\nimport { formatHtml } from \"./format.js\";\nimport {\n AGGREGATES,\n ATTR_FILTER,\n ATTR_MANUAL,\n ATTR_ORDER,\n MANUAL_FILTER,\n MANUAL_ORDER,\n ATTR_COLUMN,\n ATTR_COUNT,\n ATTR_GROUP,\n ATTR_PAGE,\n ATTR_PAGE_TITLE,\n ATTR_QUERY,\n ATTR_REQUEST,\n ATTR_SELECT,\n ATTR_SHOW,\n ATTR_URL_LINK,\n ATTR_URL_PUSH,\n ATTR_URL_PARM,\n ATTR_URL_UNKNOWN,\n CHOICES_QUERY,\n HUB_QUERY,\n DEVELOPER_ATTRIBUTES,\n HUB_TAG_NAME,\n LB_COMMAND_PREFIX,\n LB_COMMANDS,\n LB_RESERVED_PREFIX,\n REQUEST_ROW_DELETE,\n REQUEST_ROW_INSERT,\n REQUEST_ROW_UPDATE,\n SHOW_NOT,\n URL_QUERY,\n} from \"../core/lb-constants.js\";\nimport { isRowRequest } from \"../core/lb-types.js\";\nimport type { Declared, DeclaredPages } from \"./declared.js\";\nimport type { PageFile } from \"./locations.js\";\nimport type { OriginScan } from \"./origins.js\";\n\n/**\n * The hub is one element, and it swaps each page into the one `<main>`\n * inside it (hub/lb-hub.browser.ts), so the chrome holds exactly one of each,\n * the `<main>` inside the hub and empty, since whatever it held would be\n * replaced by the first page. A page is swapped into that `<main>`, so it\n * carries neither.\n */\nfunction checkChrome(chromeFile: string, body: ParentNode): void {\n const where = `assemble: '${chromeFile}'`;\n const hubs = body.querySelectorAll(HUB_TAG_NAME).length;\n if (hubs !== 1) {\n throw new Error(\n `${where} has ${hubs} <${HUB_TAG_NAME}>; it needs exactly one`,\n );\n }\n const mains = body.querySelectorAll(\"main\");\n if (mains.length !== 1) {\n throw new Error(\n `${where} has ${mains.length} <main>; it needs exactly one`,\n );\n }\n const main = mains[0]!;\n if (!main.closest(HUB_TAG_NAME)) {\n throw new Error(\n `${where} has its <main> outside <${HUB_TAG_NAME}>, where the hub cannot reach it`,\n );\n }\n if (main.children.length > 0 || main.textContent!.trim() !== \"\") {\n throw new Error(\n `${where} has content in its <main>, which the first page replaces; it goes empty`,\n );\n }\n}\n\n/** A page lands inside the chrome's `<main>`, so it brings no second one and no hub. */\nfunction checkPage(file: string, root: ParentNode): void {\n for (const tag of [HUB_TAG_NAME, \"main\"]) {\n if (root.querySelector(tag)) {\n throw new Error(\n `assemble: '${file}' carries a <${tag}>, which belongs to the chrome alone`,\n );\n }\n }\n}\n\n/**\n * The hub calls showModal() on the `<dialog>` carrying lb-url-unknown\n * (hub/lb-hub.browser.ts), and looks for it inside itself, as it does for\n * everything else it acts on. A dialog elsewhere in the body would never open\n * and would say nothing about why.\n */\nfunction checkUnknownPageDialog(chromeFile: string, body: ParentNode): void {\n const el = body.querySelector(`[${ATTR_URL_UNKNOWN}]`);\n if (!el) return;\n if (!el.closest(HUB_TAG_NAME)) {\n throw new Error(\n `assemble: '${chromeFile}' declares ${ATTR_URL_UNKNOWN} outside ` +\n `<${HUB_TAG_NAME}>, where the hub cannot reach it`,\n );\n }\n}\n\n/**\n * Where the markup stands while the check walks it: inside which `lb-query`,\n * and whether there is a row there to take a value from. Inside a row\n * template there always is. Inside an `lb-query` outside one, there is when\n * the query is of kind `row`, which only the server knows.\n */\ninterface Scope {\n query: string;\n row: boolean | \"unknown\";\n}\n\n/** The queries the hub serves, which every page and the chrome may name. */\nconst HUB_QUERIES: readonly string[] = [URL_QUERY, CHOICES_QUERY, HUB_QUERY];\n\n/** The `Crud` key each request Loadbare provides runs. */\nconst CRUD_KEYS: Record<string, string> = {\n [REQUEST_ROW_INSERT]: \"rowInsert\",\n [REQUEST_ROW_UPDATE]: \"rowUpdate\",\n [REQUEST_ROW_DELETE]: \"rowDelete\",\n};\n\n/**\n * What a file's names are checked against: a page's declarations, or `null`\n * for the chrome, which belongs to no page and so names only what the hub\n * serves.\n */\ntype Names = { declared: Declared | null };\n\n/**\n * An `lb-query` or `lb-request` naming nothing the page declares would be\n * found only on the first round trip, as a server warning and an empty\n * answer, so a typo would build cleanly.\n *\n * A request Loadbare provides is for the query of what it gathers: a form's\n * own when the form carries `lb-query`, otherwise the nearest around the\n * element, as the hub decides it (hub/lb-hub.browser.ts). With no query\n * around it, the hub reports it in the browser.\n */\nfunction checkNames(\n el: Element,\n scope: Scope | null,\n names: Names,\n problems: string[],\n): void {\n const tag = el.localName;\n const { declared } = names;\n\n const query = el.getAttribute(ATTR_QUERY);\n if (query !== null && !HUB_QUERIES.includes(query)) {\n if (declared === null) {\n problems.push(\n `<${tag}> carries ${ATTR_QUERY}=\"${query}\"; the chrome belongs to ` +\n `no page, and names only ${HUB_QUERIES.slice(0, -1).join(\", \")} and ${HUB_QUERIES.at(-1)}`,\n );\n } else if (!declared.queries.has(query)) {\n problems.push(\n `<${tag}> carries ${ATTR_QUERY}=\"${query}\", which the page's ` +\n `queries do not declare`,\n );\n }\n }\n\n const request = el.getAttribute(ATTR_REQUEST);\n if (!request) return;\n if (isRowRequest(request)) {\n const target =\n tag === \"form\" && query !== null ? query : (scope?.query ?? null);\n if (target === null) return;\n if (target === HUB_QUERY) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}'; ` +\n `the hub's own state is written by the hub alone`,\n );\n return;\n }\n if (HUB_QUERIES.includes(target)) {\n if (request !== REQUEST_ROW_UPDATE) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}'; ` +\n `the hub answers only ${REQUEST_ROW_UPDATE} for it`,\n );\n }\n return;\n }\n // A query the page does not declare is reported once, where it is named.\n if (declared === null || !declared.queries.has(target)) return;\n const key = CRUD_KEYS[request]!;\n if (!declared.crud.get(target)?.has(key)) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}', ` +\n `whose crud entry the page does not declare with ${key}`,\n );\n }\n } else if (request.startsWith(LB_RESERVED_PREFIX)) {\n // Reported by walkMarkup as naming no request Loadbare provides.\n } else if (declared === null) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\"; the chrome belongs ` +\n `to no page, and sends no declared request`,\n );\n } else if (!declared.handlers.has(request)) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\", which the page's ` +\n `handlers do not declare`,\n );\n }\n}\n\n/**\n * The markup, checked once against the finished document rather than\n * discovered one console error at a time in a browser.\n *\n * Every rule here is a fact the markup states about itself. The developer\n * writes `lb-*` attributes in markup, and script never assigns them, which is\n * what makes checking the markup sound. See docs/reference/data-binding.md.\n *\n * A `<template>`'s children are walked in the scope that encloses the\n * template, because a row template's clones land in the element around it.\n */\nfunction walkMarkup(\n node: ParentNode,\n scope: Scope | null,\n names: Names | null,\n problems: string[],\n): void {\n for (const el of node.children) {\n const tag = el.localName;\n let here = scope;\n const query = el.getAttribute(ATTR_QUERY);\n if (query !== null) here = { query, row: \"unknown\" };\n if (names) checkNames(el, scope, names, problems);\n\n for (const { name } of el.attributes) {\n if (\n name.startsWith(LB_RESERVED_PREFIX) &&\n !(DEVELOPER_ATTRIBUTES as readonly string[]).includes(name)\n ) {\n problems.push(\n `<${tag}> carries ${name}, which is not an attribute a developer ` +\n `writes`,\n );\n }\n }\n\n const request = el.getAttribute(ATTR_REQUEST);\n if (\n request !== null &&\n request.startsWith(LB_RESERVED_PREFIX) &&\n !isRowRequest(request)\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\", which begins with ` +\n `'${LB_RESERVED_PREFIX}' but names no request Loadbare provides`,\n );\n }\n if (el.hasAttribute(ATTR_URL_LINK) && tag !== \"a\") {\n problems.push(`<${tag}> carries ${ATTR_URL_LINK}; it goes on an <a>`);\n }\n // A link's parms are columns of the row around it, and only a link the\n // hub handles takes them: the parms are the application's own URL.\n const parms = el.getAttribute(ATTR_URL_PARM);\n if (parms !== null) {\n const columns = parms.split(\",\").map((column) => column.trim());\n if (tag !== \"a\" || !el.hasAttribute(ATTR_URL_LINK)) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}; it goes on an <a> carrying ` +\n `${ATTR_URL_LINK}`,\n );\n } else if (columns.some((column) => column === \"\")) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\", which names no ` +\n `column between two commas or at either end`,\n );\n } else if (columns.some((column) => /\\s/.test(column))) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\"; columns are ` +\n `separated by commas`,\n );\n } else if (columns.some((c) => c.startsWith(LB_RESERVED_PREFIX))) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\"; a parm beginning ` +\n `'${LB_RESERVED_PREFIX}' is the hub's own`,\n );\n } else if (scope === null || scope.row === false) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\" with no row around ` +\n `it to take the values from`,\n );\n }\n }\n if (el.hasAttribute(ATTR_URL_PUSH) && request === null) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PUSH} and no ${ATTR_REQUEST}; it goes ` +\n `on an element with ${ATTR_REQUEST}`,\n );\n }\n // A column holds one value, except a query parm, which a URL may repeat.\n // The column belongs to the query around the element, even one that\n // names a query of its own, as a picker does.\n if (\n el.hasAttribute(ATTR_COLUMN) &&\n (el.hasAttribute(\"multiple\") ||\n (tag === \"input\" &&\n el.getAttribute(\"type\") === \"checkbox\" &&\n el.hasAttribute(\"value\"))) &&\n scope?.query !== URL_QUERY\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_COLUMN} and holds several values; only a ` +\n `column of ${URL_QUERY} holds several, so it goes inside ` +\n `${ATTR_QUERY}=\"${URL_QUERY}\"`,\n );\n }\n // A selector is a checkbox in a live row, and selects that row. It is no\n // column, and commits nothing of its own.\n if (el.hasAttribute(ATTR_SELECT)) {\n if (tag !== \"input\" || el.getAttribute(\"type\") !== \"checkbox\") {\n problems.push(\n `<${tag}> carries ${ATTR_SELECT}; it goes on an ` +\n `<input type=\"checkbox\">`,\n );\n } else if (scope?.row !== true) {\n problems.push(\n `<input> carries ${ATTR_SELECT} outside a row template; it ` +\n `selects the row it sits in`,\n );\n }\n for (const name of [ATTR_COLUMN, ATTR_REQUEST]) {\n if (el.hasAttribute(name)) {\n problems.push(\n `<${tag}> carries ${ATTR_SELECT} and ${name}; a selector is no ` +\n `column and sends nothing`,\n );\n }\n }\n }\n // HTML's own command attribute, whose `--lb-` values are Loadbare's.\n const command = el.getAttribute(\"command\");\n if (command !== null && command.startsWith(LB_COMMAND_PREFIX)) {\n if (!(LB_COMMANDS as readonly string[]).includes(command)) {\n problems.push(\n `<${tag}> carries command=\"${command}\", which begins with ` +\n `'${LB_COMMAND_PREFIX}' but names no command Loadbare provides`,\n );\n } else if (!el.hasAttribute(\"commandfor\")) {\n problems.push(\n `<${tag}> carries command=\"${command}\" and no commandfor; it ` +\n `names the element the command is for`,\n );\n }\n }\n if (el.hasAttribute(ATTR_URL_UNKNOWN) && tag !== \"dialog\") {\n problems.push(\n `<${tag}> carries ${ATTR_URL_UNKNOWN}; it goes on a <dialog>`,\n );\n }\n\n // A group is a template holding a heading and the template its\n // contents go in; an aggregate is set on an element, from the column it\n // names.\n if (el.hasAttribute(ATTR_GROUP)) {\n if (tag !== \"template\") {\n problems.push(\n `<${tag}> carries ${ATTR_GROUP}; it goes on a <template>`,\n );\n } else if (\n !(el as HTMLTemplateElement).content.querySelector(\n `template:not([${ATTR_SHOW}])`,\n )\n ) {\n problems.push(\n `a <template ${ATTR_GROUP}> holds no <template> for its contents`,\n );\n }\n }\n for (const name of AGGREGATES) {\n if (!el.hasAttribute(name)) continue;\n if (tag === \"template\") {\n problems.push(`a <template> carries ${name}; it goes on an element`);\n } else if (name !== ATTR_COUNT && !el.getAttribute(name)) {\n problems.push(`<${tag}> carries ${name} naming no column`);\n }\n }\n\n // The user's order and filter for the rows an element holds, each read\n // from a column of lb-choices it names.\n for (const name of [ATTR_ORDER, ATTR_FILTER]) {\n const value = el.getAttribute(name);\n if (value === null) continue;\n if (!el.hasAttribute(ATTR_QUERY)) {\n problems.push(\n `<${tag}> carries ${name}; it goes on the element carrying ` +\n `${ATTR_QUERY}`,\n );\n } else if (value.trim() === \"\") {\n problems.push(`<${tag}> carries ${name} naming no column`);\n }\n }\n const manual = el.getAttribute(ATTR_MANUAL);\n if (manual !== null) {\n const sides = manual.trim().split(/\\s+/).filter((side) => side !== \"\");\n const known = [MANUAL_ORDER, MANUAL_FILTER];\n if (!el.hasAttribute(ATTR_QUERY)) {\n problems.push(\n `<${tag}> carries ${ATTR_MANUAL}; it goes on the element carrying ` +\n `${ATTR_QUERY}`,\n );\n } else if (\n sides.length === 0 ||\n sides.some((side) => !known.includes(side))\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_MANUAL}=\"${manual}\"; it names ` +\n `${MANUAL_ORDER}, ${MANUAL_FILTER} or both, separated by a space`,\n );\n }\n }\n\n // Judged by the scope around the element, not one the element carries:\n // its condition is a column of the row around it. With no lb-query\n // around it at all, nothing ever lands on it, and the element never\n // shows.\n const show = el.getAttribute(ATTR_SHOW);\n if (show !== null) {\n if (tag === \"template\") {\n problems.push(\n `a <template> carries ${ATTR_SHOW}=\"${show}\"; write it on the ` +\n `element it shows, and Loadbare supplies the template`,\n );\n } else if (scope === null || scope.row === false) {\n problems.push(\n `<${tag}> carries ${ATTR_SHOW}=\"${show}\" with no row around it ` +\n `to take the value from`,\n );\n } else if (show === SHOW_NOT || show.startsWith(SHOW_NOT + SHOW_NOT)) {\n problems.push(\n `<${tag}> carries ${ATTR_SHOW}=\"${show}\"; write one ` +\n `${SHOW_NOT} and then the column it reverses`,\n );\n }\n }\n\n walkMarkup(el, here, names, problems);\n // By tag name rather than by instanceof: template content belongs to a\n // document with no window, so the constructor is not reachable from the\n // node.\n if (tag === \"template\") {\n const content = (el as HTMLTemplateElement).content;\n const isRowTemplate =\n scope !== null && !!el.parentElement?.closest(`[${ATTR_QUERY}]`);\n if (isRowTemplate) {\n for (const root of content.children) {\n if (root.hasAttribute(ATTR_SHOW)) {\n problems.push(\n `<${root.localName}> is a row template's root and carries ` +\n `${ATTR_SHOW}; a row that should not show is left out by ` +\n `the query`,\n );\n }\n }\n }\n walkMarkup(\n content,\n isRowTemplate ? { query: scope!.query, row: true } : here,\n names,\n problems,\n );\n }\n }\n}\n\n/**\n * Ship every `lb-show` element already inside the template the hub keeps an\n * absent branch in, so nothing conditional shows until its value says so.\n * A page is in the document before its data arrives, and a value that has not\n * arrived is no value.\n *\n * Elements are collected before any is moved, and a wrapped element is still\n * reached once its outer one has gone into a template, because the references\n * are held.\n */\nfunction wrapShown(holder: HTMLTemplateElement): void {\n const doc = holder.ownerDocument;\n const shown: Element[] = [];\n const collect = (root: ParentNode): void => {\n shown.push(...root.querySelectorAll(`[${ATTR_SHOW}]`));\n for (const t of root.querySelectorAll(\"template\")) {\n collect((t as HTMLTemplateElement).content);\n }\n };\n collect(holder.content);\n for (const el of shown) {\n const parked = doc.createElement(\"template\");\n parked.setAttribute(ATTR_SHOW, el.getAttribute(ATTR_SHOW)!);\n el.replaceWith(parked);\n parked.content.append(el);\n }\n}\n\n/**\n * Expand one file's markup, naming the file if expansion refuses it.\n *\n * What comes back is the tree the browser will build, so every pass after\n * this reads and changes it in place, and it is serialized once, when it\n * ships.\n */\nfunction expandFile(\n file: string,\n source: string,\n defs: Definitions,\n): HTMLTemplateElement {\n try {\n return expandTree(source, defs);\n } catch (e) {\n throw new Error(`assemble: '${file}': ${(e as Error).message}`);\n }\n}\n\n/** Check one expanded fragment, and name the file if anything is wrong. */\nfunction checkMarkup(\n file: string,\n root: ParentNode,\n names: Names | null,\n): void {\n const problems: string[] = [];\n walkMarkup(root, null, names, problems);\n if (problems.length > 0) {\n throw new Error(`assemble: '${file}' markup:\\n ` + problems.join(`\\n `));\n }\n}\n\n/**\n * A page file's `<title>` names the page. It is lifted out, since a page is\n * a fragment inside `<main>` and a `<title>` belongs in a document's head,\n * and its text content is stamped on the page as ATTR_PAGE_TITLE.\n */\nfunction liftTitle(holder: HTMLTemplateElement): string | null {\n const title = holder.content.querySelector(\"title\");\n if (!title) return null;\n const text = title.textContent?.trim() ?? \"\";\n title.remove();\n return text;\n}\n\n/** An attribute value, escaped for a double-quoted attribute. */\nfunction attributeValue(text: string): string {\n return text.replace(/&/g, \"&\").replace(/\"/g, \""\");\n}\n\nexport interface AssembleOptions {\n chromeFile: string;\n pages: PageFile[];\n /** Every origin, already scanned, in cascade order — see build/origins.ts. */\n scans: OriginScan[];\n /**\n * What each page declares — see build/declared.ts. Without it, the names\n * `lb-query` and `lb-request` carry are not checked.\n */\n declared?: DeclaredPages;\n}\n\nexport interface Assembled {\n html: string;\n /** Every custom element tag left in the document once expansion is done. */\n usedTags: Set<string>;\n}\n\nexport async function assemble({\n chromeFile,\n pages,\n scans,\n declared,\n}: AssembleOptions): Promise<Assembled> {\n // One layer per origin, in order, so a later origin's definition overrides\n // an earlier one's for the same tag. Each layer is checked for cycles as it\n // lands, against everything merged so far.\n let defs: Definitions = {};\n for (const scan of scans) {\n defs = await addDefinitions(defs, scan.definitions);\n }\n\n // Tags are collected from each tree as it goes by. What ships is these\n // trees and the chrome around its body, which is collected on its own.\n const usedTags = new Set<string>();\n const templates: string[] = [];\n for (const { name, file } of pages) {\n const authored = await readFile(file, \"utf-8\");\n const host = expandFile(file, authored, defs);\n const title = liftTitle(host);\n checkPage(file, host.content);\n checkMarkup(\n file,\n host.content,\n declared ? { declared: declared.get(name)! } : null,\n );\n wrapShown(host);\n customElementTags(host.content, usedTags);\n const titled =\n title === null ? \"\" : ` ${ATTR_PAGE_TITLE}=\"${attributeValue(title)}\"`;\n templates.push(\n `<template ${ATTR_PAGE}=\"${name}\"${titled}>${host.innerHTML}</template>`,\n );\n }\n\n let chromeSource: string;\n try {\n chromeSource = await readFile(chromeFile, \"utf-8\");\n } catch {\n throw new Error(`assemble: no chrome file at '${chromeFile}'`);\n }\n\n const body = /<body([^>]*)>([\\s\\S]*)<\\/body>/i.exec(chromeSource);\n if (!body) {\n throw new Error(\n `assemble: '${chromeFile}' has no <body>...</body> to expand`,\n );\n }\n const [whole, bodyAttrs, bodyContent] = body;\n const chromeBody = expandFile(chromeFile, bodyContent!, defs);\n checkChrome(chromeFile, chromeBody.content);\n checkUnknownPageDialog(chromeFile, chromeBody.content);\n checkMarkup(\n chromeFile,\n chromeBody.content,\n declared ? { declared: null } : null,\n );\n wrapShown(chromeBody);\n customElementTags(chromeBody.content, usedTags);\n customElementTags(chromeSource.replace(whole!, \"\"), usedTags);\n const withPages = chromeSource.replace(\n whole!,\n () =>\n `<body${bodyAttrs}>${chromeBody.innerHTML}\\n${templates.join(\"\\n\")}\\n</body>`,\n );\n\n return { html: await formatHtml(withPages), usedTags };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../build/assemble.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Assembling one document out of a chrome file and a set of pages.\n *\n * Every `.html` file in play — the chrome and each page — goes through the\n * same `expand()` (see build/expand.ts) against the same definitions: the\n * built-in widgets and whatever definitions were found in the caller's own\n * source tree. `expand()` only ever sees a fragment, so the chrome's own is\n * the text between its `<body>` tags; a page's is the whole file. A page's\n * expanded host is wrapped in `<template lb-page=\"<name>\">` and, together\n * with the chrome's own expanded body content, spliced back into the\n * chrome's `<body>`. The result is the one document a server has to serve\n * for every route — see docs/tutorials/000-getting-started.md.\n *\n * Every path here is a parameter, resolved once by build/locations.ts — this\n * module never reconstructs one of its own, and never reads a directory\n * looking for pages or widgets; it is handed exactly which files those are.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport {\n addDefinitions,\n customElementTags,\n expandTree,\n type Definitions,\n} from \"./expand.js\";\nimport { formatHtml } from \"./format.js\";\nimport {\n ATTR_FILTER,\n ATTR_MANUAL,\n MANUAL_FILTER,\n MANUAL_ORDER,\n ATTR_COLUMN,\n ATTR_PAGE,\n ATTR_PAGE_TITLE,\n ATTR_QUERY,\n ATTR_REQUEST,\n ATTR_SHOW,\n ATTR_URL_LINK,\n ATTR_URL_PUSH,\n ATTR_URL_PARM,\n ATTR_URL_UNKNOWN,\n FILTERS_QUERY,\n SORT_QUERY,\n HUB_QUERY,\n DEVELOPER_ATTRIBUTES,\n HUB_TAG_NAME,\n LB_COMMAND_PREFIX,\n COMMAND_NEW,\n LB_COMMANDS,\n LB_RESERVED_PREFIX,\n REQUEST_ROW_DELETE,\n REQUEST_ROW_INSERT,\n REQUEST_ROW_UPDATE,\n SHOW_NOT,\n URL_QUERY,\n} from \"../core/lb-constants.js\";\nimport { isRowRequest } from \"../core/lb-types.js\";\nimport type { Declared, DeclaredPages } from \"./declared.js\";\nimport type { PageFile } from \"./locations.js\";\nimport type { OriginScan } from \"./origins.js\";\n\n/**\n * The hub is one element, and it swaps each page into the one `<main>`\n * inside it (hub/lb-hub.browser.ts), so the chrome holds exactly one of each,\n * the `<main>` inside the hub and empty, since whatever it held would be\n * replaced by the first page. A page is swapped into that `<main>`, so it\n * carries neither.\n */\nfunction checkChrome(chromeFile: string, body: ParentNode): void {\n const where = `assemble: '${chromeFile}'`;\n const hubs = body.querySelectorAll(HUB_TAG_NAME).length;\n if (hubs !== 1) {\n throw new Error(\n `${where} has ${hubs} <${HUB_TAG_NAME}>; it needs exactly one`,\n );\n }\n const mains = body.querySelectorAll(\"main\");\n if (mains.length !== 1) {\n throw new Error(\n `${where} has ${mains.length} <main>; it needs exactly one`,\n );\n }\n const main = mains[0]!;\n if (!main.closest(HUB_TAG_NAME)) {\n throw new Error(\n `${where} has its <main> outside <${HUB_TAG_NAME}>, where the hub cannot reach it`,\n );\n }\n if (main.children.length > 0 || main.textContent!.trim() !== \"\") {\n throw new Error(\n `${where} has content in its <main>, which the first page replaces; it goes empty`,\n );\n }\n}\n\n/** A page lands inside the chrome's `<main>`, so it brings no second one and no hub. */\nfunction checkPage(file: string, root: ParentNode): void {\n for (const tag of [HUB_TAG_NAME, \"main\"]) {\n if (root.querySelector(tag)) {\n throw new Error(\n `assemble: '${file}' carries a <${tag}>, which belongs to the chrome alone`,\n );\n }\n }\n}\n\n/**\n * The hub calls showModal() on the `<dialog>` carrying lb-url-unknown\n * (hub/lb-hub.browser.ts), and looks for it inside itself, as it does for\n * everything else it acts on. A dialog elsewhere in the body would never open\n * and would say nothing about why.\n */\nfunction checkUnknownPageDialog(chromeFile: string, body: ParentNode): void {\n const el = body.querySelector(`[${ATTR_URL_UNKNOWN}]`);\n if (!el) return;\n if (!el.closest(HUB_TAG_NAME)) {\n throw new Error(\n `assemble: '${chromeFile}' declares ${ATTR_URL_UNKNOWN} outside ` +\n `<${HUB_TAG_NAME}>, where the hub cannot reach it`,\n );\n }\n}\n\n/**\n * Where the markup stands while the check walks it: inside which `lb-query`,\n * and whether there is a row there to take a value from. Inside a row\n * template there always is. Inside an `lb-query` outside one, there is when\n * the query is of kind `row`, which only the server knows.\n */\ninterface Scope {\n query: string;\n row: boolean | \"unknown\";\n}\n\n/** The queries the hub serves, which every page and the chrome may name. */\nconst HUB_QUERIES: readonly string[] = [URL_QUERY, SORT_QUERY, FILTERS_QUERY, HUB_QUERY];\n\n/** The `Crud` key each request Loadbare provides runs. */\nconst CRUD_KEYS: Record<string, string> = {\n [REQUEST_ROW_INSERT]: \"rowInsert\",\n [REQUEST_ROW_UPDATE]: \"rowUpdate\",\n [REQUEST_ROW_DELETE]: \"rowDelete\",\n};\n\n/**\n * What a file's names are checked against: a page's declarations, or `null`\n * for the chrome, which belongs to no page and so names only what the hub\n * serves.\n */\ntype Names = { declared: Declared | null };\n\n/**\n * An `lb-query` or `lb-request` naming nothing the page declares would be\n * found only on the first round trip, as a server warning and an empty\n * answer, so a typo would build cleanly.\n *\n * A request Loadbare provides is for the query of what it gathers: a form's\n * own when the form carries `lb-query`, otherwise the nearest around the\n * element, as the hub decides it (hub/lb-hub.browser.ts). With no query\n * around it, the hub reports it in the browser.\n */\nfunction checkNames(\n el: Element,\n scope: Scope | null,\n names: Names,\n problems: string[],\n): void {\n const tag = el.localName;\n const { declared } = names;\n\n const query = el.getAttribute(ATTR_QUERY);\n if (query !== null && !HUB_QUERIES.includes(query)) {\n if (declared === null) {\n problems.push(\n `<${tag}> carries ${ATTR_QUERY}=\"${query}\"; the chrome belongs to ` +\n `no page, and names only ${HUB_QUERIES.slice(0, -1).join(\", \")} and ${HUB_QUERIES.at(-1)}`,\n );\n } else if (!declared.queries.has(query)) {\n problems.push(\n `<${tag}> carries ${ATTR_QUERY}=\"${query}\", which the page's ` +\n `queries do not declare`,\n );\n }\n }\n\n const request = el.getAttribute(ATTR_REQUEST);\n if (!request) return;\n if (isRowRequest(request)) {\n const target =\n tag === \"form\" && query !== null ? query : (scope?.query ?? null);\n if (target === null) return;\n if (target === HUB_QUERY) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}'; ` +\n `the hub's own state is written by the hub alone`,\n );\n return;\n }\n if (HUB_QUERIES.includes(target)) {\n if (request !== REQUEST_ROW_UPDATE) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}'; ` +\n `the hub answers only ${REQUEST_ROW_UPDATE} for it`,\n );\n }\n return;\n }\n // A query the page does not declare is reported once, where it is named.\n if (declared === null || !declared.queries.has(target)) return;\n const key = CRUD_KEYS[request]!;\n if (!declared.crud.get(target)?.has(key)) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\" for '${target}', ` +\n `whose crud entry the page does not declare with ${key}`,\n );\n }\n } else if (request.startsWith(LB_RESERVED_PREFIX)) {\n // Reported by walkMarkup as naming no request Loadbare provides.\n } else if (declared === null) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\"; the chrome belongs ` +\n `to no page, and sends no declared request`,\n );\n } else if (!declared.handlers.has(request)) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\", which the page's ` +\n `handlers do not declare`,\n );\n }\n}\n\n/**\n * The markup, checked once against the finished document rather than\n * discovered one console error at a time in a browser.\n *\n * Every rule here is a fact the markup states about itself. The developer\n * writes `lb-*` attributes in markup, and script never assigns them, which is\n * what makes checking the markup sound.\n *\n * A `<template>`'s children are walked in the scope that encloses the\n * template, because a row template's clones land in the element around it.\n */\nfunction walkMarkup(\n node: ParentNode,\n scope: Scope | null,\n names: Names | null,\n problems: string[],\n): void {\n for (const el of node.children) {\n const tag = el.localName;\n let here = scope;\n const query = el.getAttribute(ATTR_QUERY);\n if (query !== null) here = { query, row: \"unknown\" };\n if (names) checkNames(el, scope, names, problems);\n\n for (const { name } of el.attributes) {\n if (\n name.startsWith(LB_RESERVED_PREFIX) &&\n !(DEVELOPER_ATTRIBUTES as readonly string[]).includes(name)\n ) {\n problems.push(\n `<${tag}> carries ${name}, which is not an attribute a developer ` +\n `writes`,\n );\n }\n }\n\n const request = el.getAttribute(ATTR_REQUEST);\n if (\n request !== null &&\n request.startsWith(LB_RESERVED_PREFIX) &&\n !isRowRequest(request)\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_REQUEST}=\"${request}\", which begins with ` +\n `'${LB_RESERVED_PREFIX}' but names no request Loadbare provides`,\n );\n }\n if (el.hasAttribute(ATTR_URL_LINK) && tag !== \"a\") {\n problems.push(`<${tag}> carries ${ATTR_URL_LINK}; it goes on an <a>`);\n }\n // A link's parms are columns of the row around it, and only a link the\n // hub handles takes them: the parms are the application's own URL.\n const parms = el.getAttribute(ATTR_URL_PARM);\n if (parms !== null) {\n const columns = parms.split(\",\").map((column) => column.trim());\n if (tag !== \"a\" || !el.hasAttribute(ATTR_URL_LINK)) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}; it goes on an <a> carrying ` +\n `${ATTR_URL_LINK}`,\n );\n } else if (columns.some((column) => column === \"\")) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\", which names no ` +\n `column between two commas or at either end`,\n );\n } else if (columns.some((column) => /\\s/.test(column))) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\"; columns are ` +\n `separated by commas`,\n );\n } else if (columns.some((c) => c.startsWith(LB_RESERVED_PREFIX))) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\"; a parm beginning ` +\n `'${LB_RESERVED_PREFIX}' is the hub's own`,\n );\n } else if (scope === null || scope.row === false) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PARM}=\"${parms}\" with no row around ` +\n `it to take the values from`,\n );\n }\n }\n if (el.hasAttribute(ATTR_URL_PUSH) && request === null) {\n problems.push(\n `<${tag}> carries ${ATTR_URL_PUSH} and no ${ATTR_REQUEST}; it goes ` +\n `on an element with ${ATTR_REQUEST}`,\n );\n }\n // A column holds one value, except a query parm, which a URL may repeat.\n // The column belongs to the query around the element, even one that\n // names a query of its own, as a picker does.\n if (\n el.hasAttribute(ATTR_COLUMN) &&\n (el.hasAttribute(\"multiple\") ||\n (tag === \"input\" &&\n el.getAttribute(\"type\") === \"checkbox\" &&\n el.hasAttribute(\"value\"))) &&\n scope?.query !== URL_QUERY\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_COLUMN} and holds several values; only a ` +\n `column of ${URL_QUERY} holds several, so it goes inside ` +\n `${ATTR_QUERY}=\"${URL_QUERY}\"`,\n );\n }\n // HTML's own command attribute, whose `--lb-` values are Loadbare's.\n const command = el.getAttribute(\"command\");\n if (command !== null && command.startsWith(LB_COMMAND_PREFIX)) {\n if (!(LB_COMMANDS as readonly string[]).includes(command)) {\n problems.push(\n `<${tag}> carries command=\"${command}\", which begins with ` +\n `'${LB_COMMAND_PREFIX}' but names no command Loadbare provides`,\n );\n } else if (!el.hasAttribute(\"commandfor\")) {\n problems.push(\n `<${tag}> carries command=\"${command}\" and no commandfor; it ` +\n `names the element the command is for`,\n );\n }\n }\n if (el.hasAttribute(ATTR_URL_UNKNOWN) && tag !== \"dialog\") {\n problems.push(\n `<${tag}> carries ${ATTR_URL_UNKNOWN}; it goes on a <dialog>`,\n );\n }\n\n // The columns of its rows an element lets the user filter, read from its\n // row of lb-filters.\n const filterValue = el.getAttribute(ATTR_FILTER);\n if (filterValue !== null) {\n if (!el.hasAttribute(ATTR_QUERY)) {\n problems.push(\n `<${tag}> carries ${ATTR_FILTER}; it goes on the element carrying ` +\n `${ATTR_QUERY}`,\n );\n } else if (filterValue.trim() === \"\") {\n problems.push(`<${tag}> carries ${ATTR_FILTER} naming no column`);\n }\n }\n const manual = el.getAttribute(ATTR_MANUAL);\n if (manual !== null) {\n const sides = manual.trim().split(/\\s+/).filter((side) => side !== \"\");\n const known = [MANUAL_ORDER, MANUAL_FILTER];\n if (!el.hasAttribute(ATTR_QUERY)) {\n problems.push(\n `<${tag}> carries ${ATTR_MANUAL}; it goes on the element carrying ` +\n `${ATTR_QUERY}`,\n );\n } else if (\n sides.length === 0 ||\n sides.some((side) => !known.includes(side))\n ) {\n problems.push(\n `<${tag}> carries ${ATTR_MANUAL}=\"${manual}\"; it names ` +\n `${MANUAL_ORDER}, ${MANUAL_FILTER} or both, separated by a space`,\n );\n }\n }\n\n // Judged by the scope around the element, not one the element carries:\n // its condition is a column of the row around it. With no lb-query\n // around it at all, nothing ever lands on it, and the element never\n // shows.\n const show = el.getAttribute(ATTR_SHOW);\n if (show !== null) {\n if (tag === \"template\") {\n problems.push(\n `a <template> carries ${ATTR_SHOW}=\"${show}\"; write it on the ` +\n `element it shows, and Loadbare supplies the template`,\n );\n } else if (scope === null || scope.row === false) {\n problems.push(\n `<${tag}> carries ${ATTR_SHOW}=\"${show}\" with no row around it ` +\n `to take the value from`,\n );\n } else if (show === SHOW_NOT || show.startsWith(SHOW_NOT + SHOW_NOT)) {\n problems.push(\n `<${tag}> carries ${ATTR_SHOW}=\"${show}\"; write one ` +\n `${SHOW_NOT} and then the column it reverses`,\n );\n }\n }\n\n walkMarkup(el, here, names, problems);\n // By tag name rather than by instanceof: template content belongs to a\n // document with no window, so the constructor is not reachable from the\n // node.\n if (tag === \"template\") {\n const content = (el as HTMLTemplateElement).content;\n const isRowTemplate =\n scope !== null && !!el.parentElement?.closest(`[${ATTR_QUERY}]`);\n if (isRowTemplate) {\n for (const root of content.children) {\n if (root.hasAttribute(ATTR_SHOW)) {\n problems.push(\n `<${root.localName}> is a row template's root and carries ` +\n `${ATTR_SHOW}; a row that should not show is left out by ` +\n `the query`,\n );\n }\n }\n }\n walkMarkup(\n content,\n isRowTemplate ? { query: scope!.query, row: true } : here,\n names,\n problems,\n );\n }\n }\n}\n\n/**\n * Ship every `lb-show` element already inside the template the hub keeps an\n * absent branch in, so nothing conditional shows until its value says so.\n * A page is in the document before its data arrives, and a value that has not\n * arrived is no value.\n *\n * Elements are collected before any is moved, and a wrapped element is still\n * reached once its outer one has gone into a template, because the references\n * are held.\n */\nfunction wrapShown(holder: HTMLTemplateElement): void {\n const doc = holder.ownerDocument;\n const shown: Element[] = [];\n const collect = (root: ParentNode): void => {\n shown.push(...root.querySelectorAll(`[${ATTR_SHOW}]`));\n for (const t of root.querySelectorAll(\"template\")) {\n collect((t as HTMLTemplateElement).content);\n }\n };\n collect(holder.content);\n for (const el of shown) {\n const parked = doc.createElement(\"template\");\n parked.setAttribute(ATTR_SHOW, el.getAttribute(ATTR_SHOW)!);\n el.replaceWith(parked);\n parked.content.append(el);\n }\n}\n\n/**\n * Expand one file's markup, naming the file if expansion refuses it.\n *\n * What comes back is the tree the browser will build, so every pass after\n * this reads and changes it in place, and it is serialized once, when it\n * ships.\n */\nfunction expandFile(\n file: string,\n source: string,\n defs: Definitions,\n): HTMLTemplateElement {\n try {\n return expandTree(source, defs);\n } catch (e) {\n throw new Error(`assemble: '${file}': ${(e as Error).message}`);\n }\n}\n\n/** Check one expanded fragment, and name the file if anything is wrong. */\nfunction checkMarkup(\n file: string,\n root: ParentNode,\n names: Names | null,\n): void {\n const problems: string[] = [];\n walkMarkup(root, null, names, problems);\n checkNewTargets(root, problems);\n if (problems.length > 0) {\n throw new Error(`assemble: '${file}' markup:\\n ` + problems.join(`\\n `));\n }\n}\n\n/** Every element under root, template content included. */\nfunction everyElement(root: ParentNode): Element[] {\n const found: Element[] = [];\n for (const el of root.querySelectorAll(\"*\")) {\n found.push(el);\n if (el.localName === \"template\") {\n found.push(...everyElement((el as HTMLTemplateElement).content));\n }\n }\n return found;\n}\n\n/**\n * `--lb-new` aimed at a list rather than a form puts a row not yet entered\n * in it, which only the submit of the form around it carries: the list is a\n * query nested directly in a form's own query. A target the markup does not\n * hold, as a page's own element named from the chrome, is not judged.\n */\nfunction checkNewTargets(root: ParentNode, problems: string[]): void {\n const all = everyElement(root);\n const byId = new Map<string, Element>();\n for (const el of all) {\n const id = el.getAttribute(\"id\");\n if (id !== null && !byId.has(id)) byId.set(id, el);\n }\n for (const button of all) {\n if (button.getAttribute(\"command\") !== COMMAND_NEW) continue;\n const target = byId.get(button.getAttribute(\"commandfor\") ?? \"\");\n if (!target || target.localName === \"form\") continue;\n const tag = target.localName;\n if (!target.hasAttribute(ATTR_QUERY)) {\n problems.push(\n `<${tag} id=\"${target.id}\"> is aimed at by ${COMMAND_NEW}, and is ` +\n `neither a <form> nor a list carrying ${ATTR_QUERY}`,\n );\n continue;\n }\n const form = target.closest(\"form\");\n const own = form?.hasAttribute(ATTR_QUERY)\n ? form\n : form?.parentElement?.closest(`[${ATTR_QUERY}]`);\n const around = target.parentElement?.closest(`[${ATTR_QUERY}]`);\n if (!form || !own || around !== own) {\n problems.push(\n `<${tag} id=\"${target.id}\"> is aimed at by ${COMMAND_NEW}, and is ` +\n `not a query nested directly in a form's own; a row not yet ` +\n `entered goes with the submit of the form around it`,\n );\n }\n }\n}\n\n/**\n * A page file's `<title>` names the page. It is lifted out, since a page is\n * a fragment inside `<main>` and a `<title>` belongs in a document's head,\n * and its text content is stamped on the page as ATTR_PAGE_TITLE.\n */\nfunction liftTitle(holder: HTMLTemplateElement): string | null {\n const title = holder.content.querySelector(\"title\");\n if (!title) return null;\n const text = title.textContent?.trim() ?? \"\";\n title.remove();\n return text;\n}\n\n/** An attribute value, escaped for a double-quoted attribute. */\nfunction attributeValue(text: string): string {\n return text.replace(/&/g, \"&\").replace(/\"/g, \""\");\n}\n\nexport interface AssembleOptions {\n chromeFile: string;\n pages: PageFile[];\n /** Every origin, already scanned, in cascade order — see build/origins.ts. */\n scans: OriginScan[];\n /**\n * What each page declares — see build/declared.ts. Without it, the names\n * `lb-query` and `lb-request` carry are not checked.\n */\n declared?: DeclaredPages;\n}\n\nexport interface Assembled {\n html: string;\n /** Every custom element tag left in the document once expansion is done. */\n usedTags: Set<string>;\n}\n\nexport async function assemble({\n chromeFile,\n pages,\n scans,\n declared,\n}: AssembleOptions): Promise<Assembled> {\n // One layer per origin, in order, so a later origin's definition overrides\n // an earlier one's for the same tag. Each layer is checked for cycles as it\n // lands, against everything merged so far.\n let defs: Definitions = {};\n for (const scan of scans) {\n defs = await addDefinitions(defs, scan.definitions);\n }\n\n // Tags are collected from each tree as it goes by. What ships is these\n // trees and the chrome around its body, which is collected on its own.\n const usedTags = new Set<string>();\n const templates: string[] = [];\n for (const { name, file } of pages) {\n const authored = await readFile(file, \"utf-8\");\n const host = expandFile(file, authored, defs);\n const title = liftTitle(host);\n checkPage(file, host.content);\n checkMarkup(\n file,\n host.content,\n declared ? { declared: declared.get(name)! } : null,\n );\n wrapShown(host);\n customElementTags(host.content, usedTags);\n const titled =\n title === null ? \"\" : ` ${ATTR_PAGE_TITLE}=\"${attributeValue(title)}\"`;\n templates.push(\n `<template ${ATTR_PAGE}=\"${name}\"${titled}>${host.innerHTML}</template>`,\n );\n }\n\n let chromeSource: string;\n try {\n chromeSource = await readFile(chromeFile, \"utf-8\");\n } catch {\n throw new Error(`assemble: no chrome file at '${chromeFile}'`);\n }\n\n const body = /<body([^>]*)>([\\s\\S]*)<\\/body>/i.exec(chromeSource);\n if (!body) {\n throw new Error(\n `assemble: '${chromeFile}' has no <body>...</body> to expand`,\n );\n }\n const [whole, bodyAttrs, bodyContent] = body;\n const chromeBody = expandFile(chromeFile, bodyContent!, defs);\n checkChrome(chromeFile, chromeBody.content);\n checkUnknownPageDialog(chromeFile, chromeBody.content);\n checkMarkup(\n chromeFile,\n chromeBody.content,\n declared ? { declared: null } : null,\n );\n wrapShown(chromeBody);\n customElementTags(chromeBody.content, usedTags);\n customElementTags(chromeSource.replace(whole!, \"\"), usedTags);\n const withPages = chromeSource.replace(\n whole!,\n () =>\n `<body${bodyAttrs}>${chromeBody.innerHTML}\\n${templates.join(\"\\n\")}\\n</body>`,\n );\n\n return { html: await formatHtml(withPages), usedTags };\n}\n"]}
|
package/dist/build/cli.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* document, and bundle the client script for exactly the custom elements
|
|
5
5
|
* that document uses. See docs/tutorials/000-getting-started.md.
|
|
6
6
|
*
|
|
7
|
-
* loadbare-app-build [--src src] [--out dist] [--
|
|
7
|
+
* loadbare-app-build [--src src] [--out dist] [--minify]
|
|
8
8
|
*
|
|
9
9
|
* `--src` names the application's own tree: the one `chrome.html` file,
|
|
10
10
|
* every `*.page.html` page, its `*.requests.ts`/`*.queries.ts` pairs, and
|
|
@@ -30,17 +30,11 @@
|
|
|
30
30
|
* transform for `app.css`, as a pass over the concatenation above. `app.html`
|
|
31
31
|
* is never minified — it is markup an application may still want to read.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* markup, a widget's class, a stylesheet, and `imports.ts` all feed the
|
|
36
|
-
* same build — and a rebuild that throws is reported without stopping the
|
|
37
|
-
* watch. There is no dev server and no browser reload here, only the files
|
|
38
|
-
* on disk staying current for the next manual refresh; `@loadbare/app/dev`
|
|
39
|
-
* is the dev server.
|
|
33
|
+
* This runs once and exits. Watching and rebuilding belong to
|
|
34
|
+
* `@loadbare/app/dev`, the dev server.
|
|
40
35
|
*
|
|
41
36
|
* The build itself is build/build.ts. This file is the command: its flags,
|
|
42
|
-
* and the
|
|
43
|
-
* failure on stderr.
|
|
37
|
+
* and the line it prints, `wrote ...` on stdout or the failure on stderr.
|
|
44
38
|
*/
|
|
45
39
|
export {};
|
|
46
40
|
//# sourceMappingURL=cli.d.ts.map
|
package/dist/build/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../build/cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../build/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG"}
|
package/dist/build/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* document, and bundle the client script for exactly the custom elements
|
|
5
5
|
* that document uses. See docs/tutorials/000-getting-started.md.
|
|
6
6
|
*
|
|
7
|
-
* loadbare-app-build [--src src] [--out dist] [--
|
|
7
|
+
* loadbare-app-build [--src src] [--out dist] [--minify]
|
|
8
8
|
*
|
|
9
9
|
* `--src` names the application's own tree: the one `chrome.html` file,
|
|
10
10
|
* every `*.page.html` page, its `*.requests.ts`/`*.queries.ts` pairs, and
|
|
@@ -30,50 +30,28 @@
|
|
|
30
30
|
* transform for `app.css`, as a pass over the concatenation above. `app.html`
|
|
31
31
|
* is never minified — it is markup an application may still want to read.
|
|
32
32
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* markup, a widget's class, a stylesheet, and `imports.ts` all feed the
|
|
36
|
-
* same build — and a rebuild that throws is reported without stopping the
|
|
37
|
-
* watch. There is no dev server and no browser reload here, only the files
|
|
38
|
-
* on disk staying current for the next manual refresh; `@loadbare/app/dev`
|
|
39
|
-
* is the dev server.
|
|
33
|
+
* This runs once and exits. Watching and rebuilding belong to
|
|
34
|
+
* `@loadbare/app/dev`, the dev server.
|
|
40
35
|
*
|
|
41
36
|
* The build itself is build/build.ts. This file is the command: its flags,
|
|
42
|
-
* and the
|
|
43
|
-
* failure on stderr.
|
|
37
|
+
* and the line it prints, `wrote ...` on stdout or the failure on stderr.
|
|
44
38
|
*/
|
|
45
39
|
import { parseArgs } from "node:util";
|
|
46
|
-
import { buildApp
|
|
40
|
+
import { buildApp } from "./build.js";
|
|
47
41
|
const { values } = parseArgs({
|
|
48
42
|
options: {
|
|
49
43
|
src: { type: "string", default: "src" },
|
|
50
44
|
out: { type: "string", default: "dist" },
|
|
51
|
-
watch: { type: "boolean", default: false },
|
|
52
45
|
minify: { type: "boolean", default: false },
|
|
53
46
|
},
|
|
54
47
|
});
|
|
55
48
|
const options = { src: values.src, out: values.out, minify: values.minify };
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
console.log(`loadbare-app-build: ${summary}`);
|
|
60
|
-
}
|
|
61
|
-
catch (err) {
|
|
62
|
-
console.error(`loadbare-app-build: ${err.message}`);
|
|
63
|
-
process.exitCode = 1;
|
|
64
|
-
}
|
|
49
|
+
try {
|
|
50
|
+
const { summary } = await buildApp(options);
|
|
51
|
+
console.log(`loadbare-app-build: ${summary}`);
|
|
65
52
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
onBuilt: (outcome) => {
|
|
70
|
-
if (outcome.ok)
|
|
71
|
-
console.log(`loadbare-app-build: ${outcome.built.summary}`);
|
|
72
|
-
else
|
|
73
|
-
console.error(`loadbare-app-build: ${outcome.error.message}`);
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
await watcher.ready;
|
|
77
|
-
console.log(`loadbare-app-build: watching ${options.src}`);
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`loadbare-app-build: ${err.message}`);
|
|
55
|
+
process.exitCode = 1;
|
|
78
56
|
}
|
|
79
57
|
//# sourceMappingURL=cli.js.map
|
package/dist/build/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../build/cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../build/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE;QACP,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QACvC,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;QACxC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;KAC5C;CACF,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,GAAI,EAAE,GAAG,EAAE,MAAM,CAAC,GAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;AAE9E,IAAI,CAAC;IACH,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC;AAChD,CAAC;AAAC,OAAO,GAAG,EAAE,CAAC;IACb,OAAO,CAAC,KAAK,CAAC,uBAAwB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * loadbare-app-build — assemble a chrome file and its pages into one HTML\n * document, and bundle the client script for exactly the custom elements\n * that document uses. See docs/tutorials/000-getting-started.md.\n *\n * loadbare-app-build [--src src] [--out dist] [--minify]\n *\n * `--src` names the application's own tree: the one `chrome.html` file,\n * every `*.page.html` page, its `*.requests.ts`/`*.queries.ts` pairs, and\n * `imports.ts` if there is one — see build/locations.ts. It is also the last\n * origin in the cascade that supplies widget definitions, widget scripts and\n * stylesheets; this package's own widgets come first and each package named\n * in `imports.ts` in between, all scanned the same way — see\n * build/origins.ts.\n *\n * The assembled document is written to `<out>/app.html`; the client bundle\n * to `<out>/client.js`, by way of a generated `<out>/client-entry.ts` — see\n * build/elements.ts for how a tag is resolved to the script that registers\n * it. When any page has a requests or queries file, the hub registry that used\n * to be hand-maintained is written to `<out>/pages.ts` — see build/pages.ts.\n * Every `lb-query` and `lb-request` in the chrome and the pages is checked\n * against what the page declares, which is read by loading the page modules\n * — see build/declared.ts.\n * Every origin's stylesheets are concatenated in that same cascade order and\n * written to `<out>/app.css` — see build/styles.ts.\n *\n * `--minify` minifies both output files: esbuild's own minifier for\n * `client.js`, as part of the same bundling pass, and esbuild's CSS\n * transform for `app.css`, as a pass over the concatenation above. `app.html`\n * is never minified — it is markup an application may still want to read.\n *\n * This runs once and exits. Watching and rebuilding belong to\n * `@loadbare/app/dev`, the dev server.\n *\n * The build itself is build/build.ts. This file is the command: its flags,\n * and the line it prints, `wrote ...` on stdout or the failure on stderr.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { buildApp } from \"./build.js\";\n\nconst { values } = parseArgs({\n options: {\n src: { type: \"string\", default: \"src\" },\n out: { type: \"string\", default: \"dist\" },\n minify: { type: \"boolean\", default: false },\n },\n});\n\nconst options = { src: values.src!, out: values.out!, minify: values.minify };\n\ntry {\n const { summary } = await buildApp(options);\n console.log(`loadbare-app-build: ${summary}`);\n} catch (err) {\n console.error(`loadbare-app-build: ${(err as Error).message}`);\n process.exitCode = 1;\n}\n"]}
|
package/dist/build/declared.js
CHANGED
|
@@ -26,7 +26,7 @@ function namesOf(page) {
|
|
|
26
26
|
])),
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
|
-
/** Each import gets a module of its own, so a rebuild
|
|
29
|
+
/** Each import gets a module of its own, so a rebuild in a watch reads the files as they now are. */
|
|
30
30
|
let generation = 0;
|
|
31
31
|
export async function loadDeclared(pages, pageSources, outDir) {
|
|
32
32
|
let loaded = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declared.js","sourceRoot":"","sources":["../../build/declared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAa5C,SAAS,OAAO,CAAC,IAAsB;IACrC,OAAO;QACL,OAAO,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QAClD,QAAQ,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,EAAE,IAAI,GAAG,CACX,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/D,KAAK;YACL,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC3B,CAAC,CACH;KACF,CAAC;AACJ,CAAC;AAED,
|
|
1
|
+
{"version":3,"file":"declared.js","sourceRoot":"","sources":["../../build/declared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAGnC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAa5C,SAAS,OAAO,CAAC,IAAsB;IACrC,OAAO;QACL,OAAO,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QAClD,QAAQ,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,EAAE,IAAI,GAAG,CACX,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;YAC/D,KAAK;YACL,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SAC3B,CAAC,CACH;KACF,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,IAAI,UAAU,GAAG,CAAC,CAAC;AAEnB,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAiB,EACjB,WAAoC,EACpC,MAAc;IAEd,IAAI,MAAM,GAAyB,EAAE,CAAC;IACtC,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CACpB,MAAM,EACN,gBAAgB,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,MAAM,CAClD,CAAC;QACF,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,MAAM,OAAO,CAAC,KAAK,CAAC;gBAClB,KAAK,EAAE;oBACL,QAAQ,EAAE,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC;oBACpD,UAAU,EAAE,MAAM;oBAClB,UAAU,EAAE,UAAU;oBACtB,MAAM,EAAE,IAAI;iBACb;gBACD,MAAM,EAAE,IAAI;gBACZ,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,UAAU;gBACpB,OAAO,EAAE,IAAI;gBACb,oEAAoE;gBACpE,yCAAyC;gBACzC,aAAa,EAAE,OAAO,CAAC,GAAG,EAAE;gBAC5B,QAAQ,EAAE,QAAQ;aACnB,CAAC,CAAC;YACH,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,8CAA+C,GAAa,CAAC,OAAO,EAAE,CACvE,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC","sourcesContent":["/**\n * What each page declares: the names its queries, its declared requests and\n * its `crud` entries answer to, read so the markup can be checked against\n * them before anything ships — see build/assemble.ts.\n *\n * The names are read off the finished objects rather than out of the\n * source, so they are exact however a module builds them. The page modules\n * are bundled from build/pages.ts's `declaredSource`, with every package\n * left external, into a module beside `pages.ts` in `outDir`, so it resolves\n * packages as `pages.ts` does. That module is imported and removed. The\n * build therefore runs each page module's import-time code, as the server\n * does when it starts.\n */\n\nimport { mkdir, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport * as esbuild from \"esbuild\";\nimport type { Page } from \"../server/lb-server.js\";\nimport type { PageFile, PageSource } from \"./locations.js\";\nimport { declaredSource } from \"./pages.js\";\n\n/** One page's names. */\nexport interface Declared {\n queries: Set<string>;\n handlers: Set<string>;\n /** By query name, the `Crud` keys declared for it: `rowInsert` and the rest. */\n crud: Map<string, Set<string>>;\n}\n\n/** By page name, every page, including one with no page modules. */\nexport type DeclaredPages = Map<string, Declared>;\n\nfunction namesOf(page: Page | undefined): Declared {\n return {\n queries: new Set(Object.keys(page?.queries ?? {})),\n handlers: new Set(Object.keys(page?.requests.handlers ?? {})),\n crud: new Map(\n Object.entries(page?.requests.crud ?? {}).map(([query, crud]) => [\n query,\n new Set(Object.keys(crud)),\n ]),\n ),\n };\n}\n\n/** Each import gets a module of its own, so a rebuild in a watch reads the files as they now are. */\nlet generation = 0;\n\nexport async function loadDeclared(\n pages: PageFile[],\n pageSources: Map<string, PageSource>,\n outDir: string,\n): Promise<DeclaredPages> {\n let loaded: Record<string, Page> = {};\n if (pageSources.size > 0) {\n const file = path.join(\n outDir,\n `.lb-declared-${process.pid}-${++generation}.mjs`,\n );\n try {\n await mkdir(outDir, { recursive: true });\n await esbuild.build({\n stdin: {\n contents: declaredSource(pages, pageSources, outDir),\n resolveDir: outDir,\n sourcefile: \"pages.ts\",\n loader: \"ts\",\n },\n bundle: true,\n platform: \"node\",\n format: \"esm\",\n packages: \"external\",\n outfile: file,\n // esbuild keeps the directory it started in, and paths here are the\n // caller's, relative to where it is now.\n absWorkingDir: process.cwd(),\n logLevel: \"silent\",\n });\n ({ pages: loaded } = await import(pathToFileURL(file).href));\n } catch (err) {\n throw new Error(\n `declared: could not load the page modules: ${(err as Error).message}`,\n );\n } finally {\n await rm(file, { force: true });\n }\n }\n return new Map(pages.map(({ name }) => [name, namesOf(loaded[name])]));\n}\n"]}
|
|
@@ -9,21 +9,13 @@ export declare const LIVE_ROW = "[lb-row-live]";
|
|
|
9
9
|
export declare const ATTR_QUERY_ROW_COUNT = "lb-query-row-count";
|
|
10
10
|
export declare const ATTR_QUERY_UNPLACED_COUNT = "lb-query-unplaced-count";
|
|
11
11
|
export declare const ATTR_QUERY_ORDER = "lb-query-order";
|
|
12
|
-
export declare const ATTR_GROUP = "lb-group";
|
|
13
|
-
export declare const ATTR_GROUP_LIVE = "lb-group-live";
|
|
14
|
-
export declare const ATTR_GROUP_COLUMN = "lb-group-column";
|
|
15
|
-
export declare const ATTR_GROUP_VALUE = "lb-group-value";
|
|
16
|
-
export declare const LIVE_GROUP = "[lb-group-live]";
|
|
17
|
-
export declare const ATTR_COUNT = "lb-count";
|
|
18
|
-
export declare const ATTR_SUM = "lb-sum";
|
|
19
|
-
export declare const ATTR_AVG = "lb-avg";
|
|
20
|
-
export declare const ATTR_MIN = "lb-min";
|
|
21
|
-
export declare const ATTR_MAX = "lb-max";
|
|
22
|
-
export declare const AGGREGATES: readonly ["lb-count", "lb-sum", "lb-avg", "lb-min", "lb-max"];
|
|
23
12
|
export declare const ORDER_DESCENDING = "-";
|
|
24
13
|
export declare const COLUMN_TYPES: readonly ["number", "boolean", "text"];
|
|
25
|
-
export declare const
|
|
26
|
-
export declare const
|
|
14
|
+
export declare const SORT_QUERY = "lb-sort";
|
|
15
|
+
export declare const SORT_COLUMN_QUERY = "query";
|
|
16
|
+
export declare const SORT_COLUMN_ORDER = "order";
|
|
17
|
+
export declare const FILTERS_QUERY = "lb-filters";
|
|
18
|
+
export declare const FILTERS_COLUMN_QUERY = "query";
|
|
27
19
|
export declare const ATTR_FILTER = "lb-filter";
|
|
28
20
|
export declare const ATTR_MANUAL = "lb-manual";
|
|
29
21
|
export declare const MANUAL_ORDER = "order";
|
|
@@ -38,7 +30,6 @@ export declare const REQUESTED_CHANGED = "changed";
|
|
|
38
30
|
export declare const REQUESTED_MOVED = "moved";
|
|
39
31
|
export declare const ATTR_ROW_UNPLACED = "lb-row-unplaced";
|
|
40
32
|
export declare const ATTR_ROW_LEAVING = "lb-row-leaving";
|
|
41
|
-
export declare const ATTR_GROUP_LEAVING = "lb-group-leaving";
|
|
42
33
|
export declare const ATTR_REQUEST = "lb-request";
|
|
43
34
|
export declare const LB_EVENT_NAME = "lb-request";
|
|
44
35
|
export declare const LB_DONE_EVENT_NAME = "lb-request-done";
|
|
@@ -53,13 +44,12 @@ export declare const COMMAND_PLACE = "--lb-place";
|
|
|
53
44
|
export declare const LB_COMMANDS: readonly ["--lb-edit", "--lb-new", "--lb-release", "--lb-place"];
|
|
54
45
|
export declare const LB_COMMAND_PREFIX = "--lb-";
|
|
55
46
|
export declare const ATTR_ROW_EDITING = "lb-row-editing";
|
|
56
|
-
export declare const ATTR_SELECT = "lb-select";
|
|
57
|
-
export declare const ATTR_ROW_SELECTED = "lb-row-selected";
|
|
58
47
|
export declare const LB_RESERVED_PREFIX = "lb-";
|
|
59
48
|
export declare const REQUEST_ROW_INSERT = "lb-row-insert";
|
|
60
49
|
export declare const REQUEST_ROW_UPDATE = "lb-row-update";
|
|
61
50
|
export declare const REQUEST_ROW_DELETE = "lb-row-delete";
|
|
62
51
|
export declare const LB_ROW_REQUESTS: readonly ["lb-row-insert", "lb-row-update", "lb-row-delete"];
|
|
52
|
+
export declare const REQUEST_READ = "lb-read";
|
|
63
53
|
export declare const LB_METHODS: readonly ["lbAttached", "lbRowsLanded", "lbRequestDone", "lbDetached"];
|
|
64
54
|
export declare const BROWSER_LIFECYCLE: readonly ["connectedCallback", "disconnectedCallback", "adoptedCallback", "connectedMoveCallback"];
|
|
65
55
|
export declare const KIND_ROW = "row";
|
|
@@ -68,7 +58,7 @@ export declare const URL_QUERY = "lb-url";
|
|
|
68
58
|
export declare const URL_COLUMN_PATH = "lb-path";
|
|
69
59
|
export declare const URL_COLUMN_PAGE_LABEL = "lb-page-label";
|
|
70
60
|
export declare const URL_COLUMN_PAGE_UNKNOWN = "lb-page-unknown";
|
|
71
|
-
export declare const HUB_QUERY = "lb-hub";
|
|
61
|
+
export declare const HUB_QUERY = "lb-hub-status";
|
|
72
62
|
export declare const HUB_COLUMN_LOAD_STATE = "lb-load-state";
|
|
73
63
|
export declare const HUB_COLUMN_SERVER_STATE = "lb-server-state";
|
|
74
64
|
export declare const HUB_COLUMN_ERROR = "lb-error";
|
|
@@ -90,7 +80,7 @@ export declare const ATTR_EXP_SLOT = "lb-exp-slot";
|
|
|
90
80
|
export declare const ATTR_EXP_TEMPLATE = "lb-exp-template";
|
|
91
81
|
export declare const ATTR_PAGE = "lb-page";
|
|
92
82
|
export declare const ATTR_PAGE_TITLE = "lb-page-title";
|
|
93
|
-
export declare const DEVELOPER_ATTRIBUTES: readonly ["lb-query", "lb-column", "lb-show", "lb-
|
|
83
|
+
export declare const DEVELOPER_ATTRIBUTES: readonly ["lb-query", "lb-column", "lb-show", "lb-filter", "lb-manual", "lb-request", "lb-url-link", "lb-url-push", "lb-url-parm", "lb-url-unknown"];
|
|
94
84
|
export declare const HUB_TAG_NAME = "lb-hub";
|
|
95
85
|
export declare const LB_ENDPOINT = "/lb";
|
|
96
86
|
export declare const LB_REQUEST_TIMEOUT_MS = 10000;
|