@loadbare/app 0.4.0 → 0.5.1

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.
Files changed (165) hide show
  1. package/README.md +53 -82
  2. package/dist/build/assemble.d.ts +7 -5
  3. package/dist/build/assemble.d.ts.map +1 -1
  4. package/dist/build/assemble.js +29 -9
  5. package/dist/build/cli.d.ts +20 -12
  6. package/dist/build/cli.d.ts.map +1 -1
  7. package/dist/build/cli.js +34 -16
  8. package/dist/build/elements.d.ts +15 -29
  9. package/dist/build/elements.d.ts.map +1 -1
  10. package/dist/build/elements.js +25 -111
  11. package/dist/build/expand.d.ts +1 -1
  12. package/dist/build/expand.js +1 -1
  13. package/dist/build/format.d.ts +6 -3
  14. package/dist/build/format.d.ts.map +1 -1
  15. package/dist/build/format.js +6 -3
  16. package/dist/build/locations.d.ts +14 -37
  17. package/dist/build/locations.d.ts.map +1 -1
  18. package/dist/build/locations.js +31 -69
  19. package/dist/build/origins.d.ts +109 -0
  20. package/dist/build/origins.d.ts.map +1 -0
  21. package/dist/build/origins.js +270 -0
  22. package/dist/core/lb-constants.d.ts +1 -0
  23. package/dist/core/lb-constants.d.ts.map +1 -1
  24. package/dist/core/lb-constants.js +15 -8
  25. package/dist/core/lb-types.d.ts +2 -2
  26. package/dist/core/lb-types.d.ts.map +1 -1
  27. package/dist/hub/lb-apply.js +1 -1
  28. package/dist/hub/lb-hub.d.ts.map +1 -1
  29. package/dist/hub/lb-hub.js +44 -17
  30. package/dist/hub/lb-rows.d.ts.map +1 -1
  31. package/dist/hub/lb-rows.js +3 -3
  32. package/dist/server/lb-express.d.ts.map +1 -1
  33. package/dist/server/lb-server.d.ts +5 -4
  34. package/dist/server/lb-server.d.ts.map +1 -1
  35. package/dist/tests/assemble.test.js +11 -4
  36. package/dist/tests/elements.test.js +47 -51
  37. package/dist/tests/expand.test.d.ts +1 -1
  38. package/dist/tests/expand.test.js +2 -2
  39. package/dist/tests/fixtures/elements/collision/imports.d.ts +3 -0
  40. package/dist/tests/fixtures/elements/collision/imports.d.ts.map +1 -0
  41. package/dist/tests/fixtures/elements/collision/imports.js +1 -0
  42. package/dist/tests/fixtures/elements/manifest/imports.d.ts +3 -0
  43. package/dist/tests/fixtures/elements/manifest/imports.d.ts.map +1 -0
  44. package/dist/tests/fixtures/elements/manifest/imports.js +1 -0
  45. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts +3 -0
  46. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts.map +1 -0
  47. package/dist/tests/fixtures/elements/manifest-bad-entry/imports.js +1 -0
  48. package/dist/tests/fixtures/elements/{collision/elements.d.ts → manifest-not-array/imports.d.ts} +1 -1
  49. package/dist/tests/fixtures/elements/manifest-not-array/imports.d.ts.map +1 -0
  50. package/dist/tests/fixtures/elements/manifest-not-array/imports.js +1 -0
  51. package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts +2 -0
  52. package/dist/tests/fixtures/elements/pkg/acme-widget.d.ts.map +1 -0
  53. package/dist/tests/fixtures/elements/pkg/acme-widget.js +1 -0
  54. package/dist/tests/lb-express.test.js +1 -1
  55. package/dist/tests/origins.test.d.ts +10 -0
  56. package/dist/tests/origins.test.d.ts.map +1 -0
  57. package/dist/tests/origins.test.js +326 -0
  58. package/dist/tests/pages.test.js +3 -3
  59. package/dist/tests/styles.test.js +7 -4
  60. package/docs/reference/builder.md +128 -0
  61. package/docs/reference/chrome.md +75 -0
  62. package/docs/reference/css.md +44 -0
  63. package/docs/reference/custom-elements.md +327 -0
  64. package/docs/reference/data-binding.md +240 -0
  65. package/docs/reference/overview.md +38 -0
  66. package/docs/reference/page-files.md +175 -0
  67. package/docs/reference/server.md +123 -0
  68. package/docs/reference/widgets.md +163 -0
  69. package/docs/roadmap.md +130 -0
  70. package/docs/testing.md +228 -0
  71. package/docs/theory.md +344 -223
  72. package/docs/tutorials/000-getting-started.md +86 -0
  73. package/docs/tutorials/010-pages-and-navigation.md +129 -0
  74. package/docs/tutorials/020-css.md +103 -0
  75. package/docs/tutorials/030-html-decomposition.md +79 -0
  76. package/docs/tutorials/040-displaying-data.md +169 -0
  77. package/docs/tutorials/050-actions.md +77 -0
  78. package/docs/tutorials/060-custom-element-code.md +73 -0
  79. package/docs/tutorials/065-conditional-rendering.md +161 -0
  80. package/docs/tutorials/070-displaying-a-list.md +137 -0
  81. package/docs/tutorials/072-inserting-into-a-list.md +88 -0
  82. package/docs/tutorials/074-deleting-from-a-list.md +77 -0
  83. package/docs/tutorials/076-updating-a-list-item.md +86 -0
  84. package/docs/tutorials/080-widget-requests.md +124 -0
  85. package/docs/tutorials/090-using-widget-libraries.md +75 -0
  86. package/package.json +10 -18
  87. package/dist/client.js +0 -522
  88. package/dist/demo-static/src/widgets/app-box.d.ts +0 -15
  89. package/dist/demo-static/src/widgets/app-box.d.ts.map +0 -1
  90. package/dist/demo-static/src/widgets/app-box.js +0 -19
  91. package/dist/tests/fixtures/elements/collision/elements.d.ts.map +0 -1
  92. package/dist/tests/fixtures/elements/collision/elements.js +0 -3
  93. package/dist/tests/fixtures/elements/manifest/elements.d.ts +0 -5
  94. package/dist/tests/fixtures/elements/manifest/elements.d.ts.map +0 -1
  95. package/dist/tests/fixtures/elements/manifest/elements.js +0 -3
  96. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts +0 -5
  97. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.d.ts.map +0 -1
  98. package/dist/tests/fixtures/elements/manifest-bad-tag/elements.js +0 -3
  99. package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts +0 -5
  100. package/dist/tests/fixtures/elements/manifest-bad-value/elements.d.ts.map +0 -1
  101. package/dist/tests/fixtures/elements/manifest-bad-value/elements.js +0 -3
  102. package/dist/tests/golden.test.d.ts +0 -19
  103. package/dist/tests/golden.test.d.ts.map +0 -1
  104. package/dist/tests/golden.test.js +0 -60
  105. package/dist/tests/helpers/window.d.ts +0 -43
  106. package/dist/tests/helpers/window.d.ts.map +0 -1
  107. package/dist/tests/helpers/window.js +0 -78
  108. package/dist/tests/lb-input.test.d.ts +0 -9
  109. package/dist/tests/lb-input.test.d.ts.map +0 -1
  110. package/dist/tests/lb-input.test.js +0 -78
  111. package/dist/tests/lb-list.test.d.ts +0 -12
  112. package/dist/tests/lb-list.test.d.ts.map +0 -1
  113. package/dist/tests/lb-list.test.js +0 -44
  114. package/dist/tests/lb-options.test.d.ts +0 -10
  115. package/dist/tests/lb-options.test.d.ts.map +0 -1
  116. package/dist/tests/lb-options.test.js +0 -121
  117. package/dist/tests/lb-picker.test.d.ts +0 -14
  118. package/dist/tests/lb-picker.test.d.ts.map +0 -1
  119. package/dist/tests/lb-picker.test.js +0 -59
  120. package/dist/tests/lb-select.test.d.ts +0 -9
  121. package/dist/tests/lb-select.test.d.ts.map +0 -1
  122. package/dist/tests/lb-select.test.js +0 -71
  123. package/dist/tests/lb-table.test.d.ts +0 -15
  124. package/dist/tests/lb-table.test.d.ts.map +0 -1
  125. package/dist/tests/lb-table.test.js +0 -205
  126. package/dist/widgets/index.d.ts +0 -7
  127. package/dist/widgets/index.d.ts.map +0 -1
  128. package/dist/widgets/index.js +0 -6
  129. package/dist/widgets/lb-input.d.ts +0 -2
  130. package/dist/widgets/lb-input.d.ts.map +0 -1
  131. package/dist/widgets/lb-input.js +0 -48
  132. package/dist/widgets/lb-list.d.ts +0 -2
  133. package/dist/widgets/lb-list.d.ts.map +0 -1
  134. package/dist/widgets/lb-list.js +0 -17
  135. package/dist/widgets/lb-options.d.ts +0 -26
  136. package/dist/widgets/lb-options.d.ts.map +0 -1
  137. package/dist/widgets/lb-options.js +0 -72
  138. package/dist/widgets/lb-picker.d.ts +0 -2
  139. package/dist/widgets/lb-picker.d.ts.map +0 -1
  140. package/dist/widgets/lb-picker.js +0 -25
  141. package/dist/widgets/lb-select.d.ts +0 -2
  142. package/dist/widgets/lb-select.d.ts.map +0 -1
  143. package/dist/widgets/lb-select.js +0 -43
  144. package/dist/widgets/lb-table.d.ts +0 -2
  145. package/dist/widgets/lb-table.d.ts.map +0 -1
  146. package/dist/widgets/lb-table.js +0 -113
  147. package/docs/application-chrome.md +0 -36
  148. package/docs/building-html-pages.md +0 -130
  149. package/docs/getting-started.md +0 -120
  150. package/docs/guide.md +0 -1164
  151. package/docs/hosting.md +0 -218
  152. package/docs/latent-risks.md +0 -20
  153. package/widgets/index.ts +0 -6
  154. package/widgets/lb-input.html +0 -1
  155. package/widgets/lb-input.ts +0 -64
  156. package/widgets/lb-list.html +0 -1
  157. package/widgets/lb-list.ts +0 -21
  158. package/widgets/lb-options.html +0 -4
  159. package/widgets/lb-options.ts +0 -88
  160. package/widgets/lb-picker.html +0 -7
  161. package/widgets/lb-picker.ts +0 -27
  162. package/widgets/lb-select.html +0 -4
  163. package/widgets/lb-select.ts +0 -55
  164. package/widgets/lb-table.html +0 -8
  165. package/widgets/lb-table.ts +0 -126
@@ -3,127 +3,41 @@
3
3
  * and finding the script to import for it when it can.
4
4
  *
5
5
  * A used tag is valid if it has a script, a definition, or both:
6
- * - a script registers the class that upgrades it. It can come from a
7
- * built-in source (this package's own widgets/ or hub/ — hub/ is where
8
- * lb-hub itself lives, discovered exactly the same way as any built-in
9
- * widget, no special case for it here), an application's own — found
10
- * anywhere in its source tree by build/locations.ts, not confined to a
11
- * directory — or a third party's, declared by tag in `elements.ts`.
12
- * - a definition (an `.html` file, built-in or local) expands the tag's
13
- * content at build time. A widget with only a definition and no script
14
- * is markup only: expansion already gave it everything it will ever
15
- * have, and the tag survives just as an inert wrapper (see expand.ts).
6
+ * - a script registers the class that upgrades it.
7
+ * - a definition (an `.html` file) expands the tag's content at build
8
+ * time. A widget with only a definition and no script is markup only:
9
+ * expansion already gave it everything it will ever have, and the tag
10
+ * survives as an inert wrapper (see expand.ts).
16
11
  *
17
12
  * A tag with neither — no script anywhere and no definition — would do
18
13
  * nothing were it ever to reach the browser, so that is an error.
19
14
  *
20
- * Every directory and file here is a parameter, resolved once by
21
- * build/locations.ts — this module never reconstructs one of its own, and
22
- * the application's own widgets are handed over already found, not scanned
23
- * again here.
15
+ * Both halves are looked for in the same ordered origins, and the later
16
+ * origin wins: an application's own script overrides one from a package it
17
+ * imported, which overrides a built-in. Two files claiming one tag *within*
18
+ * one origin is the error case, and build/origins.ts raises it while
19
+ * scanning. Nothing is scanned here.
24
20
  */
25
- import { readdir } from "node:fs/promises";
26
21
  import path from "node:path";
27
- import { pathToFileURL } from "node:url";
28
- import { CUSTOM_ELEMENT_TAG } from "./locations.js";
29
- /** This package's own built-in sources are still a directory scan — that layout is fixed and internal, not discovered from an application's tree. */
30
- async function scanBuiltinDir(dir) {
31
- const found = new Map();
32
- let names;
33
- try {
34
- names = await readdir(dir);
35
- }
36
- catch {
37
- return found;
38
- }
39
- const entry = (tag) => {
40
- let w = found.get(tag);
41
- if (!w) {
42
- w = {};
43
- found.set(tag, w);
44
- }
45
- return w;
46
- };
47
- for (const name of names) {
48
- if (name.endsWith(".ts")) {
49
- entry(name.slice(0, -".ts".length).toLowerCase()).script = path.join(dir, name);
50
- }
51
- else if (name.endsWith(".html")) {
52
- entry(name.slice(0, -".html".length).toLowerCase()).html = path.join(dir, name);
53
- }
54
- }
55
- return found;
56
- }
57
- /**
58
- * `elements.ts`, executed rather than parsed — it runs through the same
59
- * loader as the rest of the build, so it is ordinary TypeScript, not a data
60
- * format with its own rules.
61
- */
62
- export async function loadElementManifest(file) {
63
- let mod;
64
- try {
65
- // pathToFileURL requires an absolute path; the caller's may not be one.
66
- mod = (await import(pathToFileURL(path.resolve(file)).href));
67
- }
68
- catch (err) {
69
- if (err.code === "ERR_MODULE_NOT_FOUND")
70
- return {};
71
- throw new Error(`elements: '${file}' failed to load: ${err.message}`);
72
- }
73
- const manifest = (mod.default ?? {});
74
- for (const [tag, spec] of Object.entries(manifest)) {
75
- if (!CUSTOM_ELEMENT_TAG.test(tag)) {
76
- throw new Error(`elements.ts: '${tag}' is not a valid custom element name`);
77
- }
78
- if (typeof spec !== "string") {
79
- throw new Error(`elements.ts: '${tag}' must map to an import specifier string, got ${typeof spec}`);
80
- }
81
- }
82
- return manifest;
83
- }
84
- export async function resolveElements({ used, widgets, elementsFile, builtinWidgetsDir, builtinHubDir, packageName, }) {
85
- // lb-hub is found here the same way as any other built-in: hub/ is just a
86
- // second built-in source, named specifiers differently because it is the
87
- // package's main entry point rather than a widgets/ subpath.
88
- const builtinSources = [
89
- {
90
- dir: builtinWidgetsDir,
91
- specifier: (tag) => `${packageName}/widgets/${tag}`,
92
- },
93
- { dir: builtinHubDir, specifier: () => packageName },
94
- ];
95
- const builtinDirs = await Promise.all(builtinSources.map((source) => scanBuiltinDir(source.dir)));
96
- const manifest = elementsFile ? await loadElementManifest(elementsFile) : {};
22
+ export { loadElementManifest } from "./origins.js";
23
+ export function resolveElements({ used, scans, }) {
97
24
  const resolved = new Map();
98
25
  for (const tag of used) {
99
- const hits = [];
26
+ let script;
100
27
  let hasDefinition = false;
101
- builtinSources.forEach((source, i) => {
102
- const entry = builtinDirs[i].get(tag);
103
- if (entry?.script) {
104
- hits.push([
105
- source.dir,
106
- { kind: "specifier", value: source.specifier(tag) },
107
- ]);
108
- }
109
- if (entry?.html)
28
+ // In order, so the last origin holding a script is the one that wins.
29
+ for (const scan of scans) {
30
+ if (scan.definitions.has(tag))
110
31
  hasDefinition = true;
111
- });
112
- const local = widgets.get(tag);
113
- if (local?.script) {
114
- hits.push(["src", { kind: "file", value: local.script }]);
115
- }
116
- if (local?.html)
117
- hasDefinition = true;
118
- if (tag in manifest) {
119
- hits.push([elementsFile, { kind: "specifier", value: manifest[tag] }]);
120
- }
121
- if (hits.length > 1) {
122
- throw new Error(`build: <${tag}> is declared in more than one place: ` +
123
- hits.map(([where]) => where).join(", "));
32
+ const found = scan.scripts.get(tag);
33
+ if (found === undefined)
34
+ continue;
35
+ script = scan.specifier
36
+ ? { kind: "specifier", value: scan.specifier(tag) }
37
+ : { kind: "file", value: found };
124
38
  }
125
- if (hits.length === 1) {
126
- resolved.set(tag, hits[0][1]);
39
+ if (script) {
40
+ resolved.set(tag, script);
127
41
  continue;
128
42
  }
129
43
  // No script anywhere. Valid only if a definition gave the tag its
@@ -131,7 +45,7 @@ export async function resolveElements({ used, widgets, elementsFile, builtinWidg
131
45
  // tag would do nothing were it to reach the browser.
132
46
  if (!hasDefinition) {
133
47
  throw new Error(`build: <${tag}> has neither a script nor a definition, so it would ` +
134
- `do nothing (checked built-in widgets, the src tree, and elements.ts)`);
48
+ `do nothing (checked ${scans.map((s) => `'${s.name}'`).join(", ")})`);
135
49
  }
136
50
  }
137
51
  return { resolved };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Expansion — see docs/expansion.md.
2
+ * Expansion — see docs/reference/custom-elements.md, "HTML".
3
3
  *
4
4
  * A page author writes one tag and gets the tree it stands for. Expansion
5
5
  * runs at build time, before any request exists, so it has no data. That is
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Expansion — see docs/expansion.md.
2
+ * Expansion — see docs/reference/custom-elements.md, "HTML".
3
3
  *
4
4
  * A page author writes one tag and gets the tree it stands for. Expansion
5
5
  * runs at build time, before any request exists, so it has no data. That is
@@ -6,9 +6,12 @@
6
6
  * markup but inherits its whitespace from the definition files, so the
7
7
  * assembled document reads like a concatenation, which is what it is.
8
8
  *
9
- * Prettier is a nice-to-have here and is treated as one. It runs on the whole
10
- * document once, after everything is assembled, and every way it can fail —
11
- * throwing, or not being installed — leaves the unformatted string in place.
9
+ * So prettier is a dependency rather than something an application author has
10
+ * to know to add: legible output is the default install's job, not an
11
+ * easter egg for whoever reads a warning closely enough to act on it. It runs
12
+ * on the whole document once, after everything is assembled, and the one way
13
+ * it can fail — throwing on a document — leaves the unformatted string in
14
+ * place.
12
15
  *
13
16
  * Ignoring the throw is the point rather than an oversight. The correct output
14
17
  * is what `expand` already returned; formatting only makes it pleasant. If a
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../build/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,qEAAqE;AACrE,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBhE"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../build/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,qEAAqE;AACrE,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBhE"}
@@ -6,9 +6,12 @@
6
6
  * markup but inherits its whitespace from the definition files, so the
7
7
  * assembled document reads like a concatenation, which is what it is.
8
8
  *
9
- * Prettier is a nice-to-have here and is treated as one. It runs on the whole
10
- * document once, after everything is assembled, and every way it can fail —
11
- * throwing, or not being installed — leaves the unformatted string in place.
9
+ * So prettier is a dependency rather than something an application author has
10
+ * to know to add: legible output is the default install's job, not an
11
+ * easter egg for whoever reads a warning closely enough to act on it. It runs
12
+ * on the whole document once, after everything is assembled, and the one way
13
+ * it can fail — throwing on a document — leaves the unformatted string in
14
+ * place.
12
15
  *
13
16
  * Ignoring the throw is the point rather than an oversight. The correct output
14
17
  * is what `expand` already returned; formatting only makes it pleasant. If a
@@ -1,16 +1,12 @@
1
1
  /**
2
- * Finding every file a build needs by what it's named, not by which
3
- * directory it happens to sit in.
2
+ * Finding the application's own files by what they're named, not by which
3
+ * directory they happen to sit in.
4
4
  *
5
5
  * A page and a widget definition can be byte-for-byte identical markup —
6
6
  * the only thing that says which one a file is, is extrinsic to its
7
7
  * content. `pages/` vs. `widgets/` used to carry that meaning; here a
8
- * filename suffix does instead: `*.chrome.html` is the one chrome file,
9
- * `*.page.html` is a page, and anything else `.html` is a widget
10
- * definition. A `.ts` file shaped like a custom element tag is a widget
11
- * script, found the same way regardless of where it lives. Both halves of
12
- * one widget — its markup and its class — are free to sit side by side or
13
- * apart; nothing here requires a `widgets/` directory to exist at all.
8
+ * filename suffix does instead: `chrome.html` is the one chrome file, and
9
+ * `*.page.html` is a page.
14
10
  *
15
11
  * A page's server half is named the same way: `*.hooks.ts` and
16
12
  * `*.queries.ts` pair with a `*.page.html` by sharing its basename, and are
@@ -18,12 +14,10 @@
18
14
  * neither — but one with no matching `*.page.html` is a naming mistake and
19
15
  * is rejected below.
20
16
  *
21
- * A `.css` file is not paired with anything — it is not a widget's, a
22
- * page's, or the chrome's, because build/styles.ts does not distinguish
23
- * them. Every `.css` file anywhere under `src` is concatenated, in an order
24
- * controlled entirely by the author: sorted by filename first, so a global
25
- * stylesheet sorts to the front by naming itself `00-reset.css` or similar,
26
- * regardless of which directory it lives in.
17
+ * Widget definitions, widget scripts and stylesheets are not found here.
18
+ * They arrive from more than one origin — this package's own widgets, an
19
+ * imported package, or `src` — and all three are scanned the same way by
20
+ * build/origins.ts. `src` is simply the last origin in that cascade.
27
21
  *
28
22
  * `--src` names the one tree scanned this way; `--out` names where the
29
23
  * build lands. Those, plus this package's own root (for its built-in
@@ -31,18 +25,12 @@
31
25
  * other module takes the result as a plain parameter and never
32
26
  * reconstructs one of its own.
33
27
  */
34
- /** Lowercase, hyphenated — the one shape every custom element tag has, and the one native elements never do. */
35
- export declare const CUSTOM_ELEMENT_TAG: RegExp;
28
+ import type { BuiltinDirs } from "./origins.js";
29
+ export { CUSTOM_ELEMENT_TAG } from "./origins.js";
36
30
  export interface PageFile {
37
31
  name: string;
38
32
  file: string;
39
33
  }
40
- export interface WidgetSource {
41
- /** Absolute path to the `.html` definition, if this tag has one. */
42
- html?: string;
43
- /** Absolute path, without extension, to the `.ts` script, if this tag has one. */
44
- script?: string;
45
- }
46
34
  export interface PageSource {
47
35
  /** Absolute path, without extension, to the `.hooks.ts` module, if this page has one. */
48
36
  hooks?: string;
@@ -53,20 +41,11 @@ interface Discovered {
53
41
  chromeCandidates: string[];
54
42
  pages: PageFile[];
55
43
  pageSources: Map<string, PageSource>;
56
- widgets: Map<string, WidgetSource>;
57
- elementsCandidates: string[];
58
- cssFiles: string[];
44
+ importsCandidates: string[];
59
45
  }
60
46
  /** The raw walk, with no uniqueness checks — usable on its own by anything that does not need a chrome file. */
61
47
  export declare function discoverSrc(src: string): Promise<Discovered>;
62
- export interface PackageInfo {
63
- /** This package's own widgets/ — the built-in widget definitions and classes. */
64
- builtinWidgetsDir: string;
65
- /** This package's own hub/ — where lb-hub's script lives, found the same way as any built-in widget. */
66
- builtinHubDir: string;
67
- /** This package's own name, e.g. "@loadbare/app" — for naming a built-in's import specifier. */
68
- packageName: string;
69
- }
48
+ export type PackageInfo = BuiltinDirs;
70
49
  export declare function packageInfo(): Promise<PackageInfo>;
71
50
  export interface LocationArgs {
72
51
  /** The application's source tree, e.g. "src". Scanned as a whole — see this file's header. */
@@ -74,14 +53,12 @@ export interface LocationArgs {
74
53
  out: string;
75
54
  }
76
55
  export interface Locations extends PackageInfo {
56
+ srcDir: string;
77
57
  chromeFile: string;
78
58
  pages: PageFile[];
79
59
  pageSources: Map<string, PageSource>;
80
- widgets: Map<string, WidgetSource>;
81
- elementsFile?: string;
82
- cssFiles: string[];
60
+ importsFile?: string;
83
61
  outDir: string;
84
62
  }
85
63
  export declare function resolveLocations(args: LocationArgs): Promise<Locations>;
86
- export {};
87
64
  //# sourceMappingURL=locations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"locations.d.ts","sourceRoot":"","sources":["../../build/locations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAQH,gHAAgH;AAChH,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AASlE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,UAAU;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,gHAAgH;AAChH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA+ElE;AAED,MAAM,WAAW,WAAW;IAC1B,iFAAiF;IACjF,iBAAiB,EAAE,MAAM,CAAC;IAC1B,wGAAwG;IACxG,aAAa,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAiBxD;AAED,MAAM,WAAW,YAAY;IAC3B,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAoD7E"}
1
+ {"version":3,"file":"locations.d.ts","sourceRoot":"","sources":["../../build/locations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAOH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAQlD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,UAAU;IAClB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,gHAAgH;AAChH,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA6ClE;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;AAEtC,wBAAsB,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,CAmBxD;AAED,MAAM,WAAW,YAAY;IAC3B,8FAA8F;IAC9F,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CA6C7E"}
@@ -1,16 +1,12 @@
1
1
  /**
2
- * Finding every file a build needs by what it's named, not by which
3
- * directory it happens to sit in.
2
+ * Finding the application's own files by what they're named, not by which
3
+ * directory they happen to sit in.
4
4
  *
5
5
  * A page and a widget definition can be byte-for-byte identical markup —
6
6
  * the only thing that says which one a file is, is extrinsic to its
7
7
  * content. `pages/` vs. `widgets/` used to carry that meaning; here a
8
- * filename suffix does instead: `*.chrome.html` is the one chrome file,
9
- * `*.page.html` is a page, and anything else `.html` is a widget
10
- * definition. A `.ts` file shaped like a custom element tag is a widget
11
- * script, found the same way regardless of where it lives. Both halves of
12
- * one widget — its markup and its class — are free to sit side by side or
13
- * apart; nothing here requires a `widgets/` directory to exist at all.
8
+ * filename suffix does instead: `chrome.html` is the one chrome file, and
9
+ * `*.page.html` is a page.
14
10
  *
15
11
  * A page's server half is named the same way: `*.hooks.ts` and
16
12
  * `*.queries.ts` pair with a `*.page.html` by sharing its basename, and are
@@ -18,12 +14,10 @@
18
14
  * neither — but one with no matching `*.page.html` is a naming mistake and
19
15
  * is rejected below.
20
16
  *
21
- * A `.css` file is not paired with anything — it is not a widget's, a
22
- * page's, or the chrome's, because build/styles.ts does not distinguish
23
- * them. Every `.css` file anywhere under `src` is concatenated, in an order
24
- * controlled entirely by the author: sorted by filename first, so a global
25
- * stylesheet sorts to the front by naming itself `00-reset.css` or similar,
26
- * regardless of which directory it lives in.
17
+ * Widget definitions, widget scripts and stylesheets are not found here.
18
+ * They arrive from more than one origin — this package's own widgets, an
19
+ * imported package, or `src` — and all three are scanned the same way by
20
+ * build/origins.ts. `src` is simply the last origin in that cascade.
27
21
  *
28
22
  * `--src` names the one tree scanned this way; `--out` names where the
29
23
  * build lands. Those, plus this package's own root (for its built-in
@@ -35,22 +29,18 @@ import { readdir, readFile } from "node:fs/promises";
35
29
  import path from "node:path";
36
30
  import { fileURLToPath } from "node:url";
37
31
  import { findPackageRoot } from "./package-root.js";
38
- /** Lowercase, hyphenated — the one shape every custom element tag has, and the one native elements never do. */
39
- export const CUSTOM_ELEMENT_TAG = /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/;
40
- const CHROME_SUFFIX = ".chrome.html";
32
+ export { CUSTOM_ELEMENT_TAG } from "./origins.js";
33
+ const CHROME_FILENAME = "chrome.html";
41
34
  const PAGE_SUFFIX = ".page.html";
42
35
  const HOOKS_SUFFIX = ".hooks.ts";
43
36
  const QUERIES_SUFFIX = ".queries.ts";
44
- const CSS_SUFFIX = ".css";
45
- const ELEMENTS_FILENAME = "elements.ts";
37
+ const IMPORTS_FILENAME = "imports.ts";
46
38
  /** The raw walk, with no uniqueness checks — usable on its own by anything that does not need a chrome file. */
47
39
  export async function discoverSrc(src) {
48
40
  const chromeCandidates = [];
49
41
  const pages = [];
50
42
  const pageSources = new Map();
51
- const widgets = new Map();
52
- const elementsCandidates = [];
53
- const cssFiles = [];
43
+ const importsCandidates = [];
54
44
  let entries;
55
45
  try {
56
46
  entries = await readdir(src, { withFileTypes: true, recursive: true });
@@ -58,14 +48,6 @@ export async function discoverSrc(src) {
58
48
  catch {
59
49
  entries = [];
60
50
  }
61
- const widget = (tag) => {
62
- let w = widgets.get(tag);
63
- if (!w) {
64
- w = {};
65
- widgets.set(tag, w);
66
- }
67
- return w;
68
- };
69
51
  const pageSource = (name) => {
70
52
  let p = pageSources.get(name);
71
53
  if (!p) {
@@ -78,10 +60,10 @@ export async function discoverSrc(src) {
78
60
  if (!entry.isFile())
79
61
  continue;
80
62
  const file = path.join(entry.parentPath, entry.name);
81
- if (entry.name === ELEMENTS_FILENAME) {
82
- elementsCandidates.push(file);
63
+ if (entry.name === IMPORTS_FILENAME) {
64
+ importsCandidates.push(file);
83
65
  }
84
- else if (entry.name.endsWith(CHROME_SUFFIX)) {
66
+ else if (entry.name === CHROME_FILENAME) {
85
67
  chromeCandidates.push(file);
86
68
  }
87
69
  else if (entry.name.endsWith(PAGE_SUFFIX)) {
@@ -94,35 +76,13 @@ export async function discoverSrc(src) {
94
76
  pageSource(entry.name.slice(0, -QUERIES_SUFFIX.length)).queries =
95
77
  file.slice(0, -".ts".length);
96
78
  }
97
- else if (entry.name.endsWith(CSS_SUFFIX)) {
98
- cssFiles.push(file);
99
- }
100
- else if (entry.name.endsWith(".html")) {
101
- widget(entry.name.slice(0, -".html".length).toLowerCase()).html = file;
102
- }
103
- else if (entry.name.endsWith(".ts")) {
104
- const tag = entry.name.slice(0, -".ts".length).toLowerCase();
105
- // Without the extension: this becomes an import specifier, and esbuild
106
- // resolves ".ts" from the bare path the same way it resolves ".js".
107
- if (CUSTOM_ELEMENT_TAG.test(tag))
108
- widget(tag).script = file.slice(0, -".ts".length);
109
- }
110
79
  }
111
80
  pages.sort((a, b) => a.name.localeCompare(b.name));
112
- // By filename first, full path only to break a tie — see this file's
113
- // header. A directory a file happens to sit in never affects the order.
114
- cssFiles.sort((a, b) => path.basename(a).localeCompare(path.basename(b)) || a.localeCompare(b));
115
- return {
116
- chromeCandidates,
117
- pages,
118
- pageSources,
119
- widgets,
120
- elementsCandidates,
121
- cssFiles,
122
- };
81
+ return { chromeCandidates, pages, pageSources, importsCandidates };
123
82
  }
124
83
  export async function packageInfo() {
125
- const root = await findPackageRoot(path.dirname(fileURLToPath(import.meta.url)));
84
+ const here = path.dirname(fileURLToPath(import.meta.url));
85
+ const root = await findPackageRoot(here);
126
86
  let pkg;
127
87
  try {
128
88
  pkg = JSON.parse(await readFile(path.join(root, "package.json"), "utf-8"));
@@ -131,8 +91,11 @@ export async function packageInfo() {
131
91
  throw new Error(`locations: could not read '${root}/package.json': ${err.message}`);
132
92
  }
133
93
  return {
134
- builtinWidgetsDir: path.join(root, "widgets"),
135
- builtinHubDir: path.join(root, "hub"),
94
+ // `hub/` beside this module, not beside package.json: running from source
95
+ // that is the package's own hub/, and running compiled it is dist/hub —
96
+ // the one an installed package ships, since `files` carries dist and not
97
+ // the source tree.
98
+ builtinHubDir: path.join(path.dirname(here), "hub"),
136
99
  packageName: pkg.name,
137
100
  };
138
101
  }
@@ -141,17 +104,17 @@ export async function resolveLocations(args) {
141
104
  packageInfo(),
142
105
  discoverSrc(args.src),
143
106
  ]);
144
- const { chromeCandidates, elementsCandidates, pages, pageSources, widgets, cssFiles, } = discovered;
107
+ const { chromeCandidates, importsCandidates, pages, pageSources } = discovered;
145
108
  if (chromeCandidates.length === 0) {
146
- throw new Error(`locations: no *${CHROME_SUFFIX} file found under '${args.src}'`);
109
+ throw new Error(`locations: no ${CHROME_FILENAME} file found under '${args.src}'`);
147
110
  }
148
111
  if (chromeCandidates.length > 1) {
149
- throw new Error(`locations: more than one *${CHROME_SUFFIX} file found under '${args.src}': ` +
112
+ throw new Error(`locations: more than one ${CHROME_FILENAME} file found under '${args.src}': ` +
150
113
  chromeCandidates.join(", "));
151
114
  }
152
- if (elementsCandidates.length > 1) {
153
- throw new Error(`locations: more than one ${ELEMENTS_FILENAME} found under '${args.src}': ` +
154
- elementsCandidates.join(", "));
115
+ if (importsCandidates.length > 1) {
116
+ throw new Error(`locations: more than one ${IMPORTS_FILENAME} found under '${args.src}': ` +
117
+ importsCandidates.join(", "));
155
118
  }
156
119
  const pageNames = new Set(pages.map((p) => p.name));
157
120
  for (const name of pageSources.keys()) {
@@ -162,12 +125,11 @@ export async function resolveLocations(args) {
162
125
  }
163
126
  return {
164
127
  ...info,
128
+ srcDir: args.src,
165
129
  chromeFile: chromeCandidates[0],
166
130
  pages,
167
131
  pageSources,
168
- widgets,
169
- elementsFile: elementsCandidates[0],
170
- cssFiles,
132
+ ...(importsCandidates[0] ? { importsFile: importsCandidates[0] } : {}),
171
133
  outDir: args.out,
172
134
  };
173
135
  }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Where a build's files come from — see docs/reference/builder.md.
3
+ *
4
+ * Three kinds of file reach the assembled application: a `.html` definition
5
+ * that expands a tag, a `.ts` script that registers its class, and a `.css`
6
+ * stylesheet. All three arrive from the same places, so all three are found
7
+ * the same way: one ordered list of origins, scanned once each, read by
8
+ * whoever needs them.
9
+ *
10
+ * The order is the cascade, and it is the same for every file kind:
11
+ *
12
+ * 1. this package's own `hub/`
13
+ * 2. each package declared in `imports.ts`, in first-mention order
14
+ * 3. the application's own `--src` tree
15
+ *
16
+ * A package contributes one directory of its own choosing — `loadbare.widgets`
17
+ * in its package.json, or the whole package when it says nothing. See
18
+ * `widgetDir` below for why a package gets to answer that.
19
+ *
20
+ * The one built-in origin holds one tag, `lb-hub`, and it is there because
21
+ * every application has a hub whether or not it says so. A widget is not in
22
+ * that position: `@loadbare/widgets` is a declared package like any other,
23
+ * and the builder cannot tell it from someone else's.
24
+ *
25
+ * Two rules fall out of that list, and there is no third:
26
+ *
27
+ * - Within one origin, two files claiming the same tag are an error. That
28
+ * is a typo, and the origin's own author is the one who can fix it.
29
+ * - Across origins, the later one wins. An application always has the
30
+ * final say over a package it imported, and a package over a built-in,
31
+ * without anyone having to out-name a dependency they do not control.
32
+ */
33
+ /** Lowercase, hyphenated — the one shape every custom element tag has, and the one native elements never do. */
34
+ export declare const CUSTOM_ELEMENT_TAG: RegExp;
35
+ export interface Origin {
36
+ /** How this origin is named in an error message: a package name, or "src". */
37
+ name: string;
38
+ /** The roots to scan. */
39
+ dirs: string[];
40
+ /**
41
+ * How a script from here is imported, when a bare specifier is wanted
42
+ * instead of the scanned file's own path. Only this package's `hub/` uses
43
+ * it: `lb-hub` is the package's main entry point rather than a file an
44
+ * application should reach into.
45
+ */
46
+ specifier?: (tag: string) => string;
47
+ }
48
+ export interface OriginScan {
49
+ name: string;
50
+ specifier?: (tag: string) => string;
51
+ /** Tag to its `.html` definition. */
52
+ definitions: Map<string, string>;
53
+ /** Tag to its `.ts` script, extension stripped. */
54
+ scripts: Map<string, string>;
55
+ /** Every `.css` file here, sorted by filename with the full path breaking a tie. */
56
+ css: string[];
57
+ }
58
+ /**
59
+ * One origin's contribution, classified by filename alone.
60
+ *
61
+ * A `.html` or `.ts` file is a widget's only when its basename is a tag —
62
+ * which is what excludes `chrome.html`, `about.page.html`, `about.hooks.ts`
63
+ * and `imports.ts` here without naming any of them. Those are the
64
+ * application's own files, and build/locations.ts picks them out of `src`
65
+ * separately.
66
+ */
67
+ export declare function scanOrigin(origin: Origin): Promise<OriginScan>;
68
+ /** The shape of an `imports.ts` module's default export: the packages an application pulls widgets from. */
69
+ export type ElementManifest = string[];
70
+ /**
71
+ * `imports.ts`, executed rather than parsed — it runs through the same
72
+ * loader as the rest of the build, so it is ordinary TypeScript, not a data
73
+ * format with its own rules. It lists the packages an application pulls
74
+ * widgets from, and each one becomes an origin, scanned exactly as `src` is.
75
+ */
76
+ export declare function loadElementManifest(file: string): Promise<ElementManifest>;
77
+ /**
78
+ * The ordinary node_modules walk, stopping at the first directory that has
79
+ * the package installed — not a full resolution of an entry file, on
80
+ * purpose: this only needs the package's root directory, and stopping short
81
+ * avoids caring whether the package exposes an "exports" map at all. Which
82
+ * part of that root holds the widgets is the package's own answer to give —
83
+ * `widgetDir` asks it.
84
+ */
85
+ export declare function findInstalledPackage(packageName: string, fromDir: string): Promise<string>;
86
+ export interface BuiltinDirs {
87
+ /** This package's own hub/ — where lb-hub's script lives, found the same way as any widget. */
88
+ builtinHubDir: string;
89
+ /** This package's own name, e.g. "@loadbare/app" — for naming the built-in's import specifier. */
90
+ packageName: string;
91
+ }
92
+ /**
93
+ * The cascade, in order. A declared package is an origin like any other: the
94
+ * directory it points `loadbare.widgets` at is scanned the way `src` is — its
95
+ * whole installed directory, when it points at nothing — and a widget there is
96
+ * found by its filename, not by being named in a manifest.
97
+ *
98
+ * `hub/` is the only origin naming a specifier, because `lb-hub` is the
99
+ * package's main entry point rather than a file to reach into.
100
+ */
101
+ export declare function buildOrigins(builtin: BuiltinDirs, declared: ElementManifest, src: string): Promise<Origin[]>;
102
+ /**
103
+ * The whole cascade, scanned. Everything a build reads from disk that is not
104
+ * a page, the chrome, or a page's server half comes back from here.
105
+ */
106
+ export declare function scanAll(builtin: BuiltinDirs, src: string, importsFile?: string): Promise<OriginScan[]>;
107
+ /** Every origin's stylesheets, concatenated in cascade order. */
108
+ export declare function cssFrom(scans: OriginScan[]): string[];
109
+ //# sourceMappingURL=origins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"origins.d.ts","sourceRoot":"","sources":["../../build/origins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAOH,gHAAgH;AAChH,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAMlE,MAAM,WAAW,MAAM;IACrB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,qCAAqC;IACrC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,mDAAmD;IACnD,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,oFAAoF;IACpF,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAsBD;;;;;;;;GAQG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA4DpE;AAED,4GAA4G;AAC5G,MAAM,MAAM,eAAe,GAAG,MAAM,EAAE,CAAC;AAEvC;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC,CA4B1B;AAED;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAwED,MAAM,WAAW,WAAW;IAC1B,+FAA+F;IAC/F,aAAa,EAAE,MAAM,CAAC;IACtB,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,eAAe,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,EAAE,CAAC,CAkBnB;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,EAAE,CAAC,CAIvB;AAED,iEAAiE;AACjE,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,EAAE,CAErD"}