@loadbare/app 0.6.0 → 0.7.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.
- package/dist/build/assemble.js +1 -0
- package/dist/build/assemble.js.map +1 -0
- package/dist/build/cli.js +1 -0
- package/dist/build/cli.js.map +1 -0
- package/dist/build/elements.js +1 -0
- package/dist/build/elements.js.map +1 -0
- package/dist/build/expand.js +1 -0
- package/dist/build/expand.js.map +1 -0
- package/dist/build/format.js +1 -0
- package/dist/build/format.js.map +1 -0
- package/dist/build/locations.d.ts +2 -2
- package/dist/build/locations.d.ts.map +1 -1
- package/dist/build/locations.js +3 -4
- package/dist/build/locations.js.map +1 -0
- package/dist/build/origins.js +1 -0
- package/dist/build/origins.js.map +1 -0
- package/dist/build/package-root.js +1 -0
- package/dist/build/package-root.js.map +1 -0
- package/dist/build/pages.d.ts +4 -0
- package/dist/build/pages.d.ts.map +1 -1
- package/dist/build/pages.js +5 -0
- package/dist/build/pages.js.map +1 -0
- package/dist/build/styles.js +1 -0
- package/dist/build/styles.js.map +1 -0
- package/dist/core/lb-constants.js +1 -0
- package/dist/core/lb-constants.js.map +1 -0
- package/dist/core/lb-types.d.ts +1 -1
- package/dist/core/lb-types.d.ts.map +1 -1
- package/dist/core/lb-types.js +2 -1
- package/dist/core/lb-types.js.map +1 -0
- package/dist/hub/lb-apply.d.ts +11 -1
- package/dist/hub/lb-apply.d.ts.map +1 -1
- package/dist/hub/lb-apply.js +50 -13
- package/dist/hub/lb-apply.js.map +1 -0
- package/dist/hub/lb-hub.browser.d.ts +1 -1
- package/dist/hub/lb-hub.browser.d.ts.map +1 -1
- package/dist/hub/lb-hub.browser.js +143 -112
- package/dist/hub/lb-hub.browser.js.map +1 -0
- package/dist/server/lb-express.d.ts +1 -1
- package/dist/server/lb-express.d.ts.map +1 -1
- package/dist/server/lb-express.js +1 -0
- package/dist/server/lb-express.js.map +1 -0
- package/dist/server/lb-server.d.ts +1 -1
- package/dist/server/lb-server.d.ts.map +1 -1
- package/dist/server/lb-server.js +2 -1
- package/dist/server/lb-server.js.map +1 -0
- package/docs/TECHREF-1.0.md +158 -43
- package/docs/analysis-accidental-complexity.md +149 -0
- package/docs/reference/custom-elements.md +27 -17
- package/docs/reference/data-binding.md +88 -29
- package/docs/reference/server.md +18 -0
- package/docs/reference/widgets.md +3 -3
- package/docs/theory.md +114 -1
- package/docs/tutorials/072-inserting-into-a-list.md +14 -11
- package/docs/tutorials/080-widget-requests.md +9 -26
- package/package.json +2 -2
- package/dist/tests/assemble.test.d.ts +0 -8
- package/dist/tests/assemble.test.d.ts.map +0 -1
- package/dist/tests/assemble.test.js +0 -210
- package/dist/tests/elements.test.d.ts +0 -8
- package/dist/tests/elements.test.d.ts.map +0 -1
- package/dist/tests/elements.test.js +0 -118
- package/dist/tests/expand.test.d.ts +0 -10
- package/dist/tests/expand.test.d.ts.map +0 -1
- package/dist/tests/expand.test.js +0 -253
- package/dist/tests/fixtures/elements/collision/imports.d.ts +0 -3
- package/dist/tests/fixtures/elements/collision/imports.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/collision/imports.js +0 -1
- package/dist/tests/fixtures/elements/collision/widgets/acme-widget.browser.d.ts +0 -2
- package/dist/tests/fixtures/elements/collision/widgets/acme-widget.browser.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/collision/widgets/acme-widget.browser.js +0 -1
- package/dist/tests/fixtures/elements/local/widgets/app-box.browser.d.ts +0 -2
- package/dist/tests/fixtures/elements/local/widgets/app-box.browser.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/local/widgets/app-box.browser.js +0 -1
- package/dist/tests/fixtures/elements/manifest/imports.d.ts +0 -3
- package/dist/tests/fixtures/elements/manifest/imports.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest/imports.js +0 -1
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts +0 -3
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest-bad-entry/imports.js +0 -1
- package/dist/tests/fixtures/elements/manifest-not-array/imports.d.ts +0 -5
- package/dist/tests/fixtures/elements/manifest-not-array/imports.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/manifest-not-array/imports.js +0 -1
- package/dist/tests/fixtures/elements/pkg/acme-widget.browser.d.ts +0 -2
- package/dist/tests/fixtures/elements/pkg/acme-widget.browser.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/pkg/acme-widget.browser.js +0 -1
- package/dist/tests/fixtures/elements/unmarked/widgets/app-box.d.ts +0 -6
- package/dist/tests/fixtures/elements/unmarked/widgets/app-box.d.ts.map +0 -1
- package/dist/tests/fixtures/elements/unmarked/widgets/app-box.js +0 -1
- package/dist/tests/helpers/console.d.ts +0 -20
- package/dist/tests/helpers/console.d.ts.map +0 -1
- package/dist/tests/helpers/console.js +0 -28
- package/dist/tests/helpers/dom.d.ts +0 -18
- package/dist/tests/helpers/dom.d.ts.map +0 -1
- package/dist/tests/helpers/dom.js +0 -22
- package/dist/tests/helpers/hub.d.ts +0 -73
- package/dist/tests/helpers/hub.d.ts.map +0 -1
- package/dist/tests/helpers/hub.js +0 -151
- package/dist/tests/lb-apply.test.d.ts +0 -8
- package/dist/tests/lb-apply.test.d.ts.map +0 -1
- package/dist/tests/lb-apply.test.js +0 -177
- package/dist/tests/lb-express.test.d.ts +0 -14
- package/dist/tests/lb-express.test.d.ts.map +0 -1
- package/dist/tests/lb-express.test.js +0 -243
- package/dist/tests/lb-hub.test.d.ts +0 -14
- package/dist/tests/lb-hub.test.d.ts.map +0 -1
- package/dist/tests/lb-hub.test.js +0 -319
- package/dist/tests/lb-list.test.d.ts +0 -12
- package/dist/tests/lb-list.test.d.ts.map +0 -1
- package/dist/tests/lb-list.test.js +0 -339
- package/dist/tests/lb-server.test.d.ts +0 -9
- package/dist/tests/lb-server.test.d.ts.map +0 -1
- package/dist/tests/lb-server.test.js +0 -546
- package/dist/tests/origins.test.d.ts +0 -10
- package/dist/tests/origins.test.d.ts.map +0 -1
- package/dist/tests/origins.test.js +0 -387
- package/dist/tests/pages.test.d.ts +0 -6
- package/dist/tests/pages.test.d.ts.map +0 -1
- package/dist/tests/pages.test.js +0 -148
- package/dist/tests/styles.test.d.ts +0 -7
- package/dist/tests/styles.test.d.ts.map +0 -1
- package/dist/tests/styles.test.js +0 -76
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Assembling a chrome file and its pages — see build/assemble.ts.
|
|
3
|
-
*
|
|
4
|
-
* The chrome and pages together are one write to a temp tree per test,
|
|
5
|
-
* since assemble() reads from disk rather than taking sources in memory.
|
|
6
|
-
*/
|
|
7
|
-
import assert from "node:assert/strict";
|
|
8
|
-
import { describe, it } from "node:test";
|
|
9
|
-
import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
10
|
-
import { tmpdir } from "node:os";
|
|
11
|
-
import path from "node:path";
|
|
12
|
-
import { assemble } from "../build/assemble";
|
|
13
|
-
import { resolveLocations } from "../build/locations";
|
|
14
|
-
import { scanAll } from "../build/origins";
|
|
15
|
-
async function tree(files) {
|
|
16
|
-
const dir = await mkdtemp(path.join(tmpdir(), "loadbare-assemble-"));
|
|
17
|
-
for (const [name, content] of Object.entries(files)) {
|
|
18
|
-
const file = path.join(dir, name);
|
|
19
|
-
await mkdir(path.dirname(file), { recursive: true });
|
|
20
|
-
await writeFile(file, content, "utf-8");
|
|
21
|
-
}
|
|
22
|
-
return dir;
|
|
23
|
-
}
|
|
24
|
-
async function scansFor(locations) {
|
|
25
|
-
return scanAll(locations, locations.srcDir, locations.importsFile);
|
|
26
|
-
}
|
|
27
|
-
describe("assemble", () => {
|
|
28
|
-
it("expands a widget written in the chrome, not only in pages", async () => {
|
|
29
|
-
const src = await tree({
|
|
30
|
-
"chrome.html": `<!doctype html><body><lb-nav exp-label="Site"><a href="/a">A</a></lb-nav><lb-hub><main></main></lb-hub></body>`,
|
|
31
|
-
"lb-nav.html": `<nav aria-label="{{label}}" lb-slot></nav>`,
|
|
32
|
-
});
|
|
33
|
-
try {
|
|
34
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
35
|
-
const { html, usedTags } = await assemble({
|
|
36
|
-
...locations,
|
|
37
|
-
scans: await scansFor(locations),
|
|
38
|
-
});
|
|
39
|
-
assert.match(html, /<nav aria-label="Site"><a href="\/a">A<\/a><\/nav>/);
|
|
40
|
-
assert.ok(usedTags.has("lb-nav"));
|
|
41
|
-
}
|
|
42
|
-
finally {
|
|
43
|
-
await rm(src, { recursive: true, force: true });
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
it("reports a chrome widget with no definition as a used tag, for elements.ts to refuse", async () => {
|
|
47
|
-
// Expansion leaves an undefined tag alone; whether it can do anything is
|
|
48
|
-
// one rule in one place — see build/elements.ts.
|
|
49
|
-
const src = await tree({
|
|
50
|
-
"chrome.html": `<!doctype html><body><lb-nope></lb-nope></body>`,
|
|
51
|
-
});
|
|
52
|
-
try {
|
|
53
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
54
|
-
const { html, usedTags } = await assemble({
|
|
55
|
-
...locations,
|
|
56
|
-
scans: await scansFor(locations),
|
|
57
|
-
});
|
|
58
|
-
assert.match(html, /<lb-nope><\/lb-nope>/);
|
|
59
|
-
assert.ok(usedTags.has("lb-nope"));
|
|
60
|
-
}
|
|
61
|
-
finally {
|
|
62
|
-
await rm(src, { recursive: true, force: true });
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe("the unknown-page dialog", () => {
|
|
67
|
-
it("accepts a chrome that declares none", async () => {
|
|
68
|
-
const src = await tree({
|
|
69
|
-
"chrome.html": `<!doctype html><body><lb-hub><main></main></lb-hub></body>`,
|
|
70
|
-
});
|
|
71
|
-
try {
|
|
72
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
73
|
-
const { html } = await assemble({
|
|
74
|
-
...locations,
|
|
75
|
-
scans: await scansFor(locations),
|
|
76
|
-
});
|
|
77
|
-
assert.doesNotMatch(html, /lb-unknown-page/);
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
await rm(src, { recursive: true, force: true });
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
it("refuses the attribute on anything but a <dialog>", async () => {
|
|
84
|
-
const src = await tree({
|
|
85
|
-
"chrome.html": `<!doctype html><body><lb-hub><main></main><div lb-unknown-page></div></lb-hub></body>`,
|
|
86
|
-
});
|
|
87
|
-
try {
|
|
88
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
89
|
-
const scans = await scansFor(locations);
|
|
90
|
-
await assert.rejects(() => assemble({ ...locations, scans }), /lb-unknown-page on <div>, must be a <dialog>/);
|
|
91
|
-
}
|
|
92
|
-
finally {
|
|
93
|
-
await rm(src, { recursive: true, force: true });
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
it("refuses a dialog outside the hub, where the hub cannot reach it", async () => {
|
|
97
|
-
const src = await tree({
|
|
98
|
-
"chrome.html": `<!doctype html><body><dialog lb-unknown-page></dialog><lb-hub><main></main></lb-hub></body>`,
|
|
99
|
-
});
|
|
100
|
-
try {
|
|
101
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
102
|
-
const scans = await scansFor(locations);
|
|
103
|
-
await assert.rejects(() => assemble({ ...locations, scans }), /lb-unknown-page outside <lb-hub>/);
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
await rm(src, { recursive: true, force: true });
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
/**
|
|
111
|
-
* The binding vocabulary, checked against the finished document rather than
|
|
112
|
-
* discovered one console error at a time in a browser — see walkBinding in
|
|
113
|
-
* build/assemble.ts. Every case here is a build that must not produce output.
|
|
114
|
-
*/
|
|
115
|
-
describe("the binding check", () => {
|
|
116
|
-
const CHROME = `<!doctype html><body><lb-hub><main></main></lb-hub></body>`;
|
|
117
|
-
/** Assemble a chrome and one page, and hand back whatever it did. */
|
|
118
|
-
async function build(files) {
|
|
119
|
-
const src = await tree({ "chrome.html": CHROME, ...files });
|
|
120
|
-
try {
|
|
121
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
122
|
-
const scans = await scansFor(locations);
|
|
123
|
-
return await assemble({ ...locations, scans });
|
|
124
|
-
}
|
|
125
|
-
finally {
|
|
126
|
-
await rm(src, { recursive: true, force: true });
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async function refuses(page, pattern) {
|
|
130
|
-
await assert.rejects(() => build({ "a.page.html": page }), pattern);
|
|
131
|
-
}
|
|
132
|
-
it("refuses both scope attributes on one element", async () => {
|
|
133
|
-
await refuses(`<ul lb-list="roster" lb-row="prefs"></ul>`, /carries both lb-list and lb-row/);
|
|
134
|
-
});
|
|
135
|
-
it("refuses a cell with no scope around it", async () => {
|
|
136
|
-
await refuses(`<p><span lb-cell="name"></span></p>`, /carries lb-cell="name" with no lb-list or lb-row scope/);
|
|
137
|
-
});
|
|
138
|
-
it("refuses a cell whose only scope is inside a template with none around it", async () => {
|
|
139
|
-
// A template's children are walked in the scope enclosing the template,
|
|
140
|
-
// because a row template's clones land in the list around it.
|
|
141
|
-
await refuses(`<template><span lb-cell="name"></span></template>`, /carries lb-cell="name" with no lb-list or lb-row scope/);
|
|
142
|
-
});
|
|
143
|
-
it("refuses lb-key on anything but a template", async () => {
|
|
144
|
-
await refuses(`<ul lb-list="roster"><li lb-key="id"></li></ul>`, /<li> carries lb-key; it names the column/);
|
|
145
|
-
});
|
|
146
|
-
it("refuses lb-key on a template outside any list scope", async () => {
|
|
147
|
-
await refuses(`<div lb-row="prefs"><template lb-key="id"><p></p></template></div>`, /carries lb-key outside any lb-list scope/);
|
|
148
|
-
});
|
|
149
|
-
it("refuses a template carrying lb-key with no scope at all", async () => {
|
|
150
|
-
await refuses(`<template lb-key="id"><p></p></template>`, /carries lb-key outside any lb-list scope/);
|
|
151
|
-
});
|
|
152
|
-
it("reports every problem in one build, not the first", async () => {
|
|
153
|
-
await refuses(`<span lb-cell="name"></span><ul lb-list="a" lb-row="b"></ul>`, /no lb-list or lb-row scope[\s\S]*carries both lb-list and lb-row/);
|
|
154
|
-
});
|
|
155
|
-
it("names the file the problem is in", async () => {
|
|
156
|
-
await refuses(`<span lb-cell="name"></span>`, /a\.page\.html' binding:/);
|
|
157
|
-
});
|
|
158
|
-
it("checks the chrome as well as the pages", async () => {
|
|
159
|
-
const src = await tree({
|
|
160
|
-
"chrome.html": `<!doctype html><body><lb-hub><main></main><span lb-cell="name"></span></lb-hub></body>`,
|
|
161
|
-
});
|
|
162
|
-
try {
|
|
163
|
-
const locations = await resolveLocations({ src, out: `${src}/dist` });
|
|
164
|
-
const scans = await scansFor(locations);
|
|
165
|
-
await assert.rejects(() => assemble({ ...locations, scans }), /chrome\.html' binding:/);
|
|
166
|
-
}
|
|
167
|
-
finally {
|
|
168
|
-
await rm(src, { recursive: true, force: true });
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
it("accepts a cell in either kind of scope", async () => {
|
|
172
|
-
const { html } = await build({
|
|
173
|
-
"a.page.html": `
|
|
174
|
-
<div lb-row="prefs"><span lb-cell="theme"></span></div>
|
|
175
|
-
<ul lb-list="roster">
|
|
176
|
-
<template lb-key="id"><li lb-cell="name"></li></template>
|
|
177
|
-
</ul>`,
|
|
178
|
-
});
|
|
179
|
-
assert.match(html, /lb-cell="theme"/);
|
|
180
|
-
assert.match(html, /lb-cell="name"/);
|
|
181
|
-
});
|
|
182
|
-
it("accepts a nested scope, which begins a scope of its own", async () => {
|
|
183
|
-
const { html } = await build({
|
|
184
|
-
"a.page.html": `
|
|
185
|
-
<div lb-row="prefs">
|
|
186
|
-
<ul lb-list="roster">
|
|
187
|
-
<template lb-key="id"><li lb-cell="name"></li></template>
|
|
188
|
-
</ul>
|
|
189
|
-
</div>`,
|
|
190
|
-
});
|
|
191
|
-
assert.match(html, /lb-cell="name"/);
|
|
192
|
-
});
|
|
193
|
-
it("scopes a template's content by the scope the template itself carries", async () => {
|
|
194
|
-
// A template with no scope of its own is walked in the scope enclosing
|
|
195
|
-
// it, which is what makes a row template's cells legal. One that carries
|
|
196
|
-
// a scope establishes it for its own content instead. That is today's
|
|
197
|
-
// behavior, and this is the test that flips if it changes.
|
|
198
|
-
const { html } = await build({
|
|
199
|
-
"a.page.html": `<template lb-row="prefs"><span lb-cell="theme"></span></template>`,
|
|
200
|
-
});
|
|
201
|
-
assert.match(html, /lb-cell="theme"/);
|
|
202
|
-
});
|
|
203
|
-
it("accepts a list scope with no row template, which displays nothing", async () => {
|
|
204
|
-
// An insert form names the list it adds to and has no rows of its own.
|
|
205
|
-
const { html } = await build({
|
|
206
|
-
"a.page.html": `<form lb-list="roster" lb-action="lb-row-insert"></form>`,
|
|
207
|
-
});
|
|
208
|
-
assert.match(html, /lb-list="roster"/);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolving a used tag to the script that registers it — see build/elements.ts.
|
|
3
|
-
*
|
|
4
|
-
* Fixtures under tests/fixtures/elements/ each stand in for one <src> tree,
|
|
5
|
-
* the same role tests/fixtures/definitions plays for expand.ts.
|
|
6
|
-
*/
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=elements.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"elements.test.d.ts","sourceRoot":"","sources":["../../tests/elements.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resolving a used tag to the script that registers it — see build/elements.ts.
|
|
3
|
-
*
|
|
4
|
-
* Fixtures under tests/fixtures/elements/ each stand in for one <src> tree,
|
|
5
|
-
* the same role tests/fixtures/definitions plays for expand.ts.
|
|
6
|
-
*/
|
|
7
|
-
import assert from "node:assert/strict";
|
|
8
|
-
import { describe, it } from "node:test";
|
|
9
|
-
import { fileURLToPath } from "node:url";
|
|
10
|
-
import { customElementTags } from "../build/expand";
|
|
11
|
-
import { loadElementManifest, resolveElements } from "../build/elements";
|
|
12
|
-
import { packageInfo } from "../build/locations";
|
|
13
|
-
import { scanOrigin } from "../build/origins";
|
|
14
|
-
const FIXTURES = fileURLToPath(new URL("./fixtures/elements", import.meta.url));
|
|
15
|
-
/**
|
|
16
|
-
* The cascade resolveElements reads, built here rather than by
|
|
17
|
-
* build/origins.ts's buildOrigins: these fixtures name packages that are not
|
|
18
|
-
* installed, and resolution is what is under test, not package lookup.
|
|
19
|
-
*/
|
|
20
|
-
async function scansFor(src, packageDir) {
|
|
21
|
-
const info = await packageInfo();
|
|
22
|
-
const origins = [
|
|
23
|
-
{
|
|
24
|
-
name: info.packageName,
|
|
25
|
-
dirs: [info.builtinHubDir],
|
|
26
|
-
specifier: () => info.packageName,
|
|
27
|
-
},
|
|
28
|
-
...(packageDir ? [{ name: "@acme/widget", dirs: [packageDir] }] : []),
|
|
29
|
-
{ name: src, dirs: [src] },
|
|
30
|
-
];
|
|
31
|
-
return Promise.all(origins.map(scanOrigin));
|
|
32
|
-
}
|
|
33
|
-
describe("customElementTags", () => {
|
|
34
|
-
it("collects every hyphenated tag, native elements excluded", () => {
|
|
35
|
-
const tags = customElementTags(`<div><lb-input></lb-input><app-box>hi</app-box><span></span></div>`);
|
|
36
|
-
assert.deepEqual([...tags].sort(), ["app-box", "lb-input"]);
|
|
37
|
-
});
|
|
38
|
-
it("reaches into template content", () => {
|
|
39
|
-
const tags = customElementTags(`<template><acme-widget></acme-widget></template>`);
|
|
40
|
-
assert.deepEqual([...tags], ["acme-widget"]);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
describe("loadElementManifest", () => {
|
|
44
|
-
it("returns the declared package list", async () => {
|
|
45
|
-
const declared = await loadElementManifest(`${FIXTURES}/manifest/imports.ts`);
|
|
46
|
-
assert.deepEqual(declared, ["@acme/widget"]);
|
|
47
|
-
});
|
|
48
|
-
it("returns empty when there is no imports.ts", async () => {
|
|
49
|
-
const declared = await loadElementManifest(`${FIXTURES}/local/imports.ts`);
|
|
50
|
-
assert.deepEqual(declared, []);
|
|
51
|
-
});
|
|
52
|
-
it("rejects a default export that is not an array", async () => {
|
|
53
|
-
await assert.rejects(() => loadElementManifest(`${FIXTURES}/manifest-not-array/imports.ts`), /must default-export an array of package names/);
|
|
54
|
-
});
|
|
55
|
-
it("rejects an entry that is not a package name", async () => {
|
|
56
|
-
await assert.rejects(() => loadElementManifest(`${FIXTURES}/manifest-bad-entry/imports.ts`), /every entry must be a package name/);
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
describe("resolveElements", () => {
|
|
60
|
-
it("resolves lb-hub to the package itself, the one built-in", async () => {
|
|
61
|
-
const { resolved } = resolveElements({
|
|
62
|
-
used: new Set(["lb-hub"]),
|
|
63
|
-
scans: await scansFor(`${FIXTURES}/local`),
|
|
64
|
-
});
|
|
65
|
-
assert.deepEqual(resolved.get("lb-hub"), {
|
|
66
|
-
kind: "specifier",
|
|
67
|
-
value: "@loadbare/app",
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
it("resolves a local tag to its file in <src>", async () => {
|
|
71
|
-
const { resolved } = resolveElements({
|
|
72
|
-
used: new Set(["app-box"]),
|
|
73
|
-
scans: await scansFor(`${FIXTURES}/local`),
|
|
74
|
-
});
|
|
75
|
-
assert.equal(resolved.get("app-box")?.kind, "file");
|
|
76
|
-
assert.match(resolved.get("app-box").value, /local\/widgets\/app-box\.browser$/);
|
|
77
|
-
});
|
|
78
|
-
it("resolves a tag found by scanning a declared package", async () => {
|
|
79
|
-
const { resolved } = resolveElements({
|
|
80
|
-
used: new Set(["acme-widget"]),
|
|
81
|
-
scans: await scansFor(`${FIXTURES}/manifest`, `${FIXTURES}/pkg`),
|
|
82
|
-
});
|
|
83
|
-
assert.equal(resolved.get("acme-widget")?.kind, "file");
|
|
84
|
-
assert.match(resolved.get("acme-widget").value, /pkg\/acme-widget\.browser$/);
|
|
85
|
-
});
|
|
86
|
-
it("needs no script for a tag with only an .html definition", async () => {
|
|
87
|
-
const { resolved } = resolveElements({
|
|
88
|
-
used: new Set(["lb-nav"]),
|
|
89
|
-
scans: await scansFor(`${FIXTURES}/markup-only`),
|
|
90
|
-
});
|
|
91
|
-
assert.equal(resolved.size, 0);
|
|
92
|
-
});
|
|
93
|
-
it("names the unmarked file when a tag's script forgot to say .browser", async () => {
|
|
94
|
-
await assert.rejects(async () => resolveElements({
|
|
95
|
-
used: new Set(["app-box"]),
|
|
96
|
-
scans: await scansFor(`${FIXTURES}/unmarked`),
|
|
97
|
-
}), (err) => {
|
|
98
|
-
assert.match(err.message, /<app-box> has no script/);
|
|
99
|
-
assert.match(err.message, /widgets[/\\]app-box\.ts' is named after it/);
|
|
100
|
-
assert.match(err.message, /rename it 'app-box\.browser\.ts'/);
|
|
101
|
-
return true;
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
it("throws when a used tag registers nothing", async () => {
|
|
105
|
-
await assert.rejects(async () => resolveElements({
|
|
106
|
-
used: new Set(["nowhere-widget"]),
|
|
107
|
-
scans: await scansFor(`${FIXTURES}/local`),
|
|
108
|
-
}), /<nowhere-widget> has neither a script nor a definition/);
|
|
109
|
-
});
|
|
110
|
-
it("lets src win over a package that has the same tag", async () => {
|
|
111
|
-
const { resolved } = resolveElements({
|
|
112
|
-
used: new Set(["acme-widget"]),
|
|
113
|
-
scans: await scansFor(`${FIXTURES}/collision`, `${FIXTURES}/pkg`),
|
|
114
|
-
});
|
|
115
|
-
assert.equal(resolved.get("acme-widget")?.kind, "file");
|
|
116
|
-
assert.match(resolved.get("acme-widget").value, /collision\/widgets\/acme-widget\.browser$/);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Expansion — see docs/reference/custom-elements.md and docs/testing.md, tier 1.
|
|
3
|
-
*
|
|
4
|
-
* Definitions are written inline here because `expand` takes them as a map
|
|
5
|
-
* and a two-line definition beside its assertion reads better than a file
|
|
6
|
-
* reference. The cases that genuinely need files — the checks `loadDefinitions`
|
|
7
|
-
* runs, and directory ordering — use tests/fixtures/definitions.
|
|
8
|
-
*/
|
|
9
|
-
export {};
|
|
10
|
-
//# sourceMappingURL=expand.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"expand.test.d.ts","sourceRoot":"","sources":["../../tests/expand.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Expansion — see docs/reference/custom-elements.md and docs/testing.md, tier 1.
|
|
3
|
-
*
|
|
4
|
-
* Definitions are written inline here because `expand` takes them as a map
|
|
5
|
-
* and a two-line definition beside its assertion reads better than a file
|
|
6
|
-
* reference. The cases that genuinely need files — the checks `loadDefinitions`
|
|
7
|
-
* runs, and directory ordering — use tests/fixtures/definitions.
|
|
8
|
-
*/
|
|
9
|
-
import assert from "node:assert/strict";
|
|
10
|
-
import { describe, it } from "node:test";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { JSDOM } from "jsdom";
|
|
13
|
-
import { expand, loadDefinitions } from "../build/expand";
|
|
14
|
-
const FIXTURES = fileURLToPath(new URL("./fixtures/definitions", import.meta.url));
|
|
15
|
-
/**
|
|
16
|
-
* Read expansion's output as a tree.
|
|
17
|
-
*
|
|
18
|
-
* Used where the claim is about the document rather than about the text —
|
|
19
|
-
* which elements exist, which attributes an element has. Matching a
|
|
20
|
-
* serialization would test the serializer.
|
|
21
|
-
*/
|
|
22
|
-
function parseHtml(html) {
|
|
23
|
-
const holder = new JSDOM("").window.document.createElement("div");
|
|
24
|
-
holder.innerHTML = html;
|
|
25
|
-
return holder;
|
|
26
|
-
}
|
|
27
|
-
/** Definitions are keyed by the uppercased tag they define. */
|
|
28
|
-
function defs(entries) {
|
|
29
|
-
const map = {};
|
|
30
|
-
for (const [tag, source] of Object.entries(entries)) {
|
|
31
|
-
map[tag.toUpperCase()] = source;
|
|
32
|
-
}
|
|
33
|
-
return map;
|
|
34
|
-
}
|
|
35
|
-
// --- Rejections ----------------------------------------------------------
|
|
36
|
-
//
|
|
37
|
-
// Expansion runs before any request exists, so every one of these is a build
|
|
38
|
-
// that must not produce output. Each asserts on the message as well as the
|
|
39
|
-
// throw: an author reads the message, and it is the whole of the diagnosis.
|
|
40
|
-
describe("expansion rejects", () => {
|
|
41
|
-
it("a parameter the definition never declared", () => {
|
|
42
|
-
assert.throws(() => expand(`<lb-thing exp-label="Name"></lb-thing>`, defs({ "lb-thing": `<div></div>` })), /given exp-label, but its definition has no \{\{label\}\}/);
|
|
43
|
-
});
|
|
44
|
-
it("a placeholder no tag could supply", async () => {
|
|
45
|
-
await assert.rejects(() => loadDefinitions([`${FIXTURES}/camel`]), /declares \{\{inputClass\}\}.*Write \{\{input-class\}\}/s);
|
|
46
|
-
});
|
|
47
|
-
it("a cycle in the definition graph", async () => {
|
|
48
|
-
await assert.rejects(() => loadDefinitions([`${FIXTURES}/cycle`]), /cycle in the definition graph/);
|
|
49
|
-
});
|
|
50
|
-
it("two destinations with one name", () => {
|
|
51
|
-
assert.throws(() => expand(`<lb-thing></lb-thing>`, defs({
|
|
52
|
-
"lb-thing": `<table><thead lb-template="head"></thead><tfoot lb-template="head"></tfoot></table>`,
|
|
53
|
-
})), /declares two lb-template="head" destinations/);
|
|
54
|
-
});
|
|
55
|
-
it("two templates for one destination", () => {
|
|
56
|
-
assert.throws(() => expand(`<lb-thing>` +
|
|
57
|
-
`<template lb-template="head"><tr></tr></template>` +
|
|
58
|
-
`<template lb-template="head"><tr></tr></template>` +
|
|
59
|
-
`</lb-thing>`, defs({
|
|
60
|
-
"lb-thing": `<table><thead lb-template="head"></thead></table>`,
|
|
61
|
-
})), /was given two templates for 'head'/);
|
|
62
|
-
});
|
|
63
|
-
it("a template naming a destination the definition does not have", () => {
|
|
64
|
-
assert.throws(() => expand(`<lb-thing><template lb-template="foot"><tr></tr></template></lb-thing>`, defs({
|
|
65
|
-
"lb-thing": `<table><thead lb-template="head"></thead></table>`,
|
|
66
|
-
})), /has no destination by that name/);
|
|
67
|
-
});
|
|
68
|
-
it("content written into a definition with no slot", () => {
|
|
69
|
-
assert.throws(() => expand(`<lb-thing><p>hello</p></lb-thing>`, defs({ "lb-thing": `<div></div>` })), /content was written inside <lb-thing>, whose definition has no lb-slot/);
|
|
70
|
-
});
|
|
71
|
-
it("a definition declaring more than one slot", () => {
|
|
72
|
-
assert.throws(() => expand(`<lb-thing></lb-thing>`, defs({
|
|
73
|
-
"lb-thing": `<div lb-slot></div><span lb-slot></span>`,
|
|
74
|
-
})), /declares more than one lb-slot/);
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
// --- Substitution --------------------------------------------------------
|
|
78
|
-
describe("substitution", () => {
|
|
79
|
-
it("fills an attribute and a text node", () => {
|
|
80
|
-
const html = expand(`<lb-thing exp-label="Name" exp-name="who"></lb-thing>`, defs({
|
|
81
|
-
"lb-thing": `<label>{{label}}<input name="{{name}}" /></label>`,
|
|
82
|
-
}));
|
|
83
|
-
assert.match(html, /<label>Name<input name="who"><\/label>/);
|
|
84
|
-
});
|
|
85
|
-
it("drops an attribute whose placeholder was not supplied", () => {
|
|
86
|
-
// Presence propagates: an unsupplied placeholder must not emit
|
|
87
|
-
// readonly="", which HTML reads as readonly.
|
|
88
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({ "lb-thing": `<input readonly="{{readonly}}" />` }));
|
|
89
|
-
assert.match(html, /<input>/);
|
|
90
|
-
assert.doesNotMatch(html, /readonly/);
|
|
91
|
-
});
|
|
92
|
-
it("keeps the whitespace around a text placeholder", () => {
|
|
93
|
-
// "{{label}} <input>" has to keep separating the label from the control.
|
|
94
|
-
const html = expand(`<lb-thing exp-label="Name"></lb-thing>`, defs({ "lb-thing": `<label>{{label}} <input /></label>` }));
|
|
95
|
-
assert.match(html, /<label>Name <input><\/label>/);
|
|
96
|
-
});
|
|
97
|
-
it("fills an unsupplied text placeholder with nothing", () => {
|
|
98
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({ "lb-thing": `<label>{{label}}</label>` }));
|
|
99
|
-
assert.match(html, /<label><\/label>/);
|
|
100
|
-
});
|
|
101
|
-
it("falls back to a default the definition wrote", () => {
|
|
102
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({ "lb-thing": `<button>{{text|OK}}</button>` }));
|
|
103
|
-
assert.match(html, /<button>OK<\/button>/);
|
|
104
|
-
});
|
|
105
|
-
it("lets a supplied value win over a default", () => {
|
|
106
|
-
const html = expand(`<lb-thing exp-text="Go"></lb-thing>`, defs({ "lb-thing": `<button>{{text|OK}}</button>` }));
|
|
107
|
-
assert.match(html, /<button>Go<\/button>/);
|
|
108
|
-
});
|
|
109
|
-
it("trims whitespace around a name and its default", () => {
|
|
110
|
-
// A spaced form that shipped as literal braces would be a silent failure
|
|
111
|
-
// found in the browser, so the space is not part of either side.
|
|
112
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({
|
|
113
|
-
"lb-thing": `<button title="{{ tip | Press me }}">{{ text | OK }}</button>`,
|
|
114
|
-
}));
|
|
115
|
-
assert.match(html, /<button title="Press me">OK<\/button>/);
|
|
116
|
-
});
|
|
117
|
-
it("emits an attribute whose default is empty", () => {
|
|
118
|
-
// The one case a default distinguishes from no default: presence.
|
|
119
|
-
// readonly="{{readonly|}}" is a boolean attribute on unless a tag turns
|
|
120
|
-
// it off — which, since a supplied value is a string, a tag cannot do;
|
|
121
|
-
// the default is for a definition that wants the attribute there.
|
|
122
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({ "lb-thing": `<input readonly="{{readonly|}}" />` }));
|
|
123
|
-
assert.match(html, /<input readonly="">/);
|
|
124
|
-
});
|
|
125
|
-
it("reaches placeholders inside template content", () => {
|
|
126
|
-
// lb-picker ships a row template of its own, so {{key}} written inside
|
|
127
|
-
// one has to be a placeholder rather than literal text that ships.
|
|
128
|
-
const html = expand(`<lb-thing exp-key="id" exp-cell="name"></lb-thing>`, defs({
|
|
129
|
-
"lb-thing": `<select><template lb-key="{{key}}"><option lb-cell="{{cell}}"></option></template></select>`,
|
|
130
|
-
}));
|
|
131
|
-
assert.match(html, /<template lb-key="id">/);
|
|
132
|
-
assert.match(html, /<option lb-cell="name">/);
|
|
133
|
-
});
|
|
134
|
-
it("leaves a partial placeholder alone", () => {
|
|
135
|
-
// A placeholder is an entire attribute value or an entire text node.
|
|
136
|
-
const html = expand(`<lb-thing></lb-thing>`, defs({ "lb-thing": `<label title="a {{label}} b"></label>` }));
|
|
137
|
-
assert.match(html, /title="a \{\{label\}\} b"/);
|
|
138
|
-
});
|
|
139
|
-
it("refuses a parameter for a partial placeholder", () => {
|
|
140
|
-
// The consequence of the rule above, and the reason it is safe: a name
|
|
141
|
-
// that is not a placeholder is a name the definition never declared, so
|
|
142
|
-
// supplying it is the same error as supplying a name that is not there
|
|
143
|
-
// at all. The author is told rather than shipped literal braces.
|
|
144
|
-
assert.throws(() => expand(`<lb-thing exp-label="Name"></lb-thing>`, defs({ "lb-thing": `<label title="a {{label}} b"></label>` })), /has no \{\{label\}\}/);
|
|
145
|
-
});
|
|
146
|
-
it("keeps the exp- attributes on the expanded tag", () => {
|
|
147
|
-
// What ships shows what was asked for beside what it produced.
|
|
148
|
-
const html = expand(`<lb-thing exp-label="Name"></lb-thing>`, defs({ "lb-thing": `<label>{{label}}</label>` }));
|
|
149
|
-
assert.match(html, /<lb-thing exp-label="Name">/);
|
|
150
|
-
});
|
|
151
|
-
it("cannot inject markup, by construction", () => {
|
|
152
|
-
// Substitution goes through setAttribute and node values, never through a
|
|
153
|
-
// string. This test exists to fail if anyone reaches for concatenation.
|
|
154
|
-
//
|
|
155
|
-
// The assertion reparses rather than matching the serialization, because
|
|
156
|
-
// the serialization is not the claim. An expanded tag keeps the exp-
|
|
157
|
-
// attributes it was given, and `<` in an attribute value is legal HTML
|
|
158
|
-
// that no serializer has to escape — so the output does contain the
|
|
159
|
-
// characters. What must not exist is an element.
|
|
160
|
-
const html = expand(`<lb-thing exp-label="<img src=x onerror=alert(1)>" exp-name="" onclick="alert(1)"></lb-thing>`, defs({
|
|
161
|
-
"lb-thing": `<label>{{label}}<input name="{{name}}" /></label>`,
|
|
162
|
-
}));
|
|
163
|
-
const tree = parseHtml(html);
|
|
164
|
-
assert.equal(tree.querySelectorAll("img").length, 0);
|
|
165
|
-
assert.equal(tree.querySelector("label").textContent, "<img src=x onerror=alert(1)>");
|
|
166
|
-
// The second value closes an attribute and opens an event handler, if it
|
|
167
|
-
// is ever concatenated. Through setAttribute it is one attribute's value.
|
|
168
|
-
const input = tree.querySelector("input");
|
|
169
|
-
assert.deepEqual([...input.attributes].map((a) => a.name), ["name"]);
|
|
170
|
-
assert.equal(input.getAttribute("name"), `" onclick="alert(1)`);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
// --- Slots and destinations ---------------------------------------------
|
|
174
|
-
describe("placement", () => {
|
|
175
|
-
it("puts authored content in the slot and removes the marker", () => {
|
|
176
|
-
const html = expand(`<lb-list><p>hello</p></lb-list>`, defs({ "lb-list": `<div lb-slot></div>` }));
|
|
177
|
-
assert.match(html, /<div><p>hello<\/p><\/div>/);
|
|
178
|
-
assert.doesNotMatch(html, /lb-slot/);
|
|
179
|
-
});
|
|
180
|
-
it("unwraps a named template into its destination as real markup", () => {
|
|
181
|
-
// The wrapper existed only to survive the parser. What ships is a real
|
|
182
|
-
// <tr> in a real <thead>, visible in view-source like everything else.
|
|
183
|
-
const html = expand(`<lb-table>` +
|
|
184
|
-
`<template lb-template="head"><tr><th>Name</th></tr></template>` +
|
|
185
|
-
`<template lb-key="id"><tr><td lb-cell="name"></td></tr></template>` +
|
|
186
|
-
`</lb-table>`, defs({
|
|
187
|
-
"lb-table": `<table><thead lb-template="head"></thead><tbody lb-slot></tbody></table>`,
|
|
188
|
-
}));
|
|
189
|
-
assert.match(html, /<thead><tr><th>Name<\/th><\/tr><\/thead>/);
|
|
190
|
-
assert.match(html, /<tbody><template lb-key="id">/);
|
|
191
|
-
assert.doesNotMatch(html, /lb-template/);
|
|
192
|
-
});
|
|
193
|
-
it("does not count whitespace as content", () => {
|
|
194
|
-
// An author who writes only named templates still leaves the newlines
|
|
195
|
-
// between them, and those are the file's formatting.
|
|
196
|
-
const html = expand(`<lb-thing>\n \n</lb-thing>`, defs({ "lb-thing": `<div></div>` }));
|
|
197
|
-
assert.match(html, /<lb-thing><div><\/div><\/lb-thing>/);
|
|
198
|
-
});
|
|
199
|
-
it("expands a widget used inside a definition", () => {
|
|
200
|
-
const html = expand(`<lb-outer></lb-outer>`, defs({
|
|
201
|
-
"lb-outer": `<div><lb-inner exp-label="deep"></lb-inner></div>`,
|
|
202
|
-
"lb-inner": `<span>{{label}}</span>`,
|
|
203
|
-
}));
|
|
204
|
-
assert.match(html, /<span>deep<\/span>/);
|
|
205
|
-
});
|
|
206
|
-
it("expands a widget written inside a page's row template", () => {
|
|
207
|
-
// Template content is markup in a file like any other, and it is inert,
|
|
208
|
-
// so a row template ships already expanded.
|
|
209
|
-
const html = expand(`<lb-list><template lb-key="id"><lb-inner exp-label="row"></lb-inner></template></lb-list>`, defs({
|
|
210
|
-
"lb-list": `<div lb-slot></div>`,
|
|
211
|
-
"lb-inner": `<span>{{label}}</span>`,
|
|
212
|
-
}));
|
|
213
|
-
assert.match(html, /<span>row<\/span>/);
|
|
214
|
-
});
|
|
215
|
-
it("expands a tag outside the lb- namespace when it has a definition", () => {
|
|
216
|
-
// An application's widget can use its own prefix — see docs/tutorials/000-getting-started.md.
|
|
217
|
-
// The definition must still apply; discovering it is not enough.
|
|
218
|
-
const html = expand(`<app-nav exp-label="Site"></app-nav>`, defs({ "app-nav": `<nav aria-label="{{label}}" lb-slot></nav>` }));
|
|
219
|
-
assert.match(html, /<nav aria-label="Site"><\/nav>/);
|
|
220
|
-
});
|
|
221
|
-
it("leaves a tag outside the lb- namespace alone when it has no definition", () => {
|
|
222
|
-
// A plain custom element, registered by script alone — see build/elements.ts.
|
|
223
|
-
const html = expand(`<app-box>hi</app-box>`, defs({}));
|
|
224
|
-
assert.match(html, /<app-box>hi<\/app-box>/);
|
|
225
|
-
});
|
|
226
|
-
it("leaves a tag with no definition alone, whatever its name", () => {
|
|
227
|
-
// No name is special, the hub's own tag included. A tag that has neither
|
|
228
|
-
// a definition nor a script is refused once, in build/elements.ts.
|
|
229
|
-
const html = expand(`<lb-nope></lb-nope><lb-hub></lb-hub>`, defs({}));
|
|
230
|
-
assert.match(html, /<lb-nope><\/lb-nope><lb-hub><\/lb-hub>/);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
// --- Loading -------------------------------------------------------------
|
|
234
|
-
describe("loadDefinitions", () => {
|
|
235
|
-
it("keys a definition by the tag its filename names", async () => {
|
|
236
|
-
const loaded = await loadDefinitions([`${FIXTURES}/base`]);
|
|
237
|
-
assert.deepEqual(Object.keys(loaded), ["LB-THING"]);
|
|
238
|
-
});
|
|
239
|
-
it("lets a later directory override a built-in", async () => {
|
|
240
|
-
const loaded = await loadDefinitions([
|
|
241
|
-
`${FIXTURES}/base`,
|
|
242
|
-
`${FIXTURES}/override`,
|
|
243
|
-
]);
|
|
244
|
-
assert.match(loaded["LB-THING"], /application/);
|
|
245
|
-
});
|
|
246
|
-
it("skips a directory that is not there", async () => {
|
|
247
|
-
const loaded = await loadDefinitions([
|
|
248
|
-
`${FIXTURES}/nothing-here`,
|
|
249
|
-
`${FIXTURES}/base`,
|
|
250
|
-
]);
|
|
251
|
-
assert.deepEqual(Object.keys(loaded), ["LB-THING"]);
|
|
252
|
-
});
|
|
253
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../../../../tests/fixtures/elements/collision/imports.ts"],"names":[],"mappings":";AAAA,wBAAgC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default ["@acme/widget"];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"acme-widget.browser.d.ts","sourceRoot":"","sources":["../../../../../../tests/fixtures/elements/collision/widgets/acme-widget.browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"app-box.browser.d.ts","sourceRoot":"","sources":["../../../../../../tests/fixtures/elements/local/widgets/app-box.browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|