@loadbare/app 0.18.2 → 0.19.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/README.md +17 -17
- package/dist/build/assemble.d.ts +7 -1
- package/dist/build/assemble.d.ts.map +1 -1
- package/dist/build/assemble.js +81 -11
- package/dist/build/assemble.js.map +1 -1
- package/dist/build/cli.d.ts +3 -0
- package/dist/build/cli.d.ts.map +1 -1
- package/dist/build/cli.js +6 -1
- package/dist/build/cli.js.map +1 -1
- package/dist/build/declared.d.ts +25 -0
- package/dist/build/declared.d.ts.map +1 -0
- package/dist/build/declared.js +62 -0
- package/dist/build/declared.js.map +1 -0
- package/dist/build/pages.d.ts +6 -0
- package/dist/build/pages.d.ts.map +1 -1
- package/dist/build/pages.js +32 -12
- package/dist/build/pages.js.map +1 -1
- package/docs/TECHREF-1.0.md +27 -72
- package/docs/comparison.md +692 -480
- package/docs/departures.md +63 -0
- package/docs/miswarts.md +140 -0
- package/docs/opinions.md +155 -0
- package/docs/reference/builder.md +9 -2
- package/docs/reference/chrome.md +2 -1
- package/docs/reference/custom-elements.md +1 -1
- package/docs/reference/data-binding.md +36 -9
- package/docs/reference/page-files.md +36 -4
- package/docs/roadmap.md +55 -43
- package/docs/testing.md +62 -28
- package/docs/theory.md +348 -108
- package/package.json +1 -1
- package/skills/loadbare-app/SKILL.md +10 -6
- package/skills/loadbare-app/references/TECHREF-1.0.md +27 -72
- package/skills/loadbare-app/references/builder.md +9 -2
- package/skills/loadbare-app/references/chrome.md +2 -1
- package/skills/loadbare-app/references/custom-elements.md +1 -1
- package/skills/loadbare-app/references/data-binding.md +36 -9
- package/skills/loadbare-app/references/miswarts.md +140 -0
- package/skills/loadbare-app/references/page-files.md +36 -4
- package/docs/possible-ideas.md +0 -314
- package/docs/theory-old.md +0 -839
- package/docs/what-does-loadbare-extend.md +0 -124
package/docs/roadmap.md
CHANGED
|
@@ -15,13 +15,6 @@ mechanism Release 1.0 already ships. Each is here because deciding it
|
|
|
15
15
|
speculatively, before a real page forces the question, risks designing the
|
|
16
16
|
wrong thing. Revisit when the described symptom actually shows up.
|
|
17
17
|
|
|
18
|
-
### Staleness and concurrent writers
|
|
19
|
-
|
|
20
|
-
Two tabs, or two users, updating the same rows at once. A solo developer
|
|
21
|
-
testing in one browser will not produce this by accident, and retrofitting a
|
|
22
|
-
version or conflict check onto every row after the fact touches every widget
|
|
23
|
-
that writes.
|
|
24
|
-
|
|
25
18
|
### A query that pages or limits its rows
|
|
26
19
|
|
|
27
20
|
The user's order and filters apply to the rows the browser holds. A query
|
|
@@ -49,6 +42,31 @@ end up living in the widget while the server remains authoritative for the
|
|
|
49
42
|
same field. Not yet designed — revisit the first time an application needs
|
|
50
43
|
inline validation.
|
|
51
44
|
|
|
45
|
+
### Compound foreign keys
|
|
46
|
+
|
|
47
|
+
A picker is the UI for a foreign key. `<select lb-query="statuses"
|
|
48
|
+
lb-column="status">` says the row's `status` references a row of
|
|
49
|
+
`statuses`, and offers every one of them. For a single-column foreign key
|
|
50
|
+
that is exactly right, which is why a query in a row template answers the
|
|
51
|
+
same rows in every live row.
|
|
52
|
+
|
|
53
|
+
A compound foreign key cannot be expressed. When `(type, status)`
|
|
54
|
+
references `allowed_statuses(type, status)`, the choices for `status`
|
|
55
|
+
depend on the row's own `type`, and every row is offered every status.
|
|
56
|
+
The database knows the constraint, and the UI cannot say it, so a user is
|
|
57
|
+
offered choices the server will refuse.
|
|
58
|
+
|
|
59
|
+
A likely direction keeps one query and one answer: the lookup answers every
|
|
60
|
+
allowed pair as ordinary rows, the picker names the columns of its row that
|
|
61
|
+
restrict it, and the hub shows each picker only the rows that match, as it
|
|
62
|
+
already filters the rows it holds. Two questions come with it:
|
|
63
|
+
|
|
64
|
+
- Whether the restricting value is the one that landed or the control's
|
|
65
|
+
current value, so the choices follow an edit before it is saved.
|
|
66
|
+
- What becomes of a chosen value the restriction no longer allows.
|
|
67
|
+
|
|
68
|
+
Revisit when an application needs a choice restricted by its row.
|
|
69
|
+
|
|
52
70
|
## Release 1.1 candidates
|
|
53
71
|
|
|
54
72
|
Net-new scope, not gaps in 1.0. Release 1.1 will optimize for operational
|
|
@@ -128,9 +146,10 @@ breaks nothing.
|
|
|
128
146
|
|
|
129
147
|
### Queries stated by the chrome
|
|
130
148
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
pattern from the framework side,
|
|
149
|
+
The chrome belongs to no page, so the builder refuses an application query
|
|
150
|
+
named there, and a custom element in the chrome cannot show application
|
|
151
|
+
data. `lb-url` and `lb-choices` show the pattern from the framework side,
|
|
152
|
+
and an application has no equivalent.
|
|
134
153
|
|
|
135
154
|
A chrome-level query set on `createHub` would close this, and it is additive.
|
|
136
155
|
It takes its place in the [options on `createHub`](#options-on-createhub).
|
|
@@ -159,39 +178,6 @@ A query parm write replaces the history entry, and `lb-url-push` pushes
|
|
|
159
178
|
one. Which of the two a user wants may be the user's to say, rather
|
|
160
179
|
than the page's.
|
|
161
180
|
|
|
162
|
-
### Build-time checking of `lb-request` against the declared requests
|
|
163
|
-
|
|
164
|
-
Release 1.0 resolves every `lb-request` value at request time. A value naming
|
|
165
|
-
no entry under `handlers`, or one of the requests Loadbare provides for a
|
|
166
|
-
query with no entry under `crud`, is found on the first commit: a server
|
|
167
|
-
console warning and an empty answer, described in
|
|
168
|
-
[Page files](./reference/page-files.md). A typo builds cleanly.
|
|
169
|
-
|
|
170
|
-
The builder already expands each page and walks the finished document in
|
|
171
|
-
`walkMarkup`, tracking the enclosing `lb-query`, so collecting every request
|
|
172
|
-
name together with the query it is issued for needs no new machinery. What
|
|
173
|
-
it lacks is the other half of the comparison: it knows the path of a
|
|
174
|
-
`.requests.ts` file and never reads its contents.
|
|
175
|
-
|
|
176
|
-
Two routes to the declared names, and the choice is the decision:
|
|
177
|
-
|
|
178
|
-
- **Load the built module.** Bundle the generated `pages.ts`, import it, and
|
|
179
|
-
read the keys off the finished objects. Exact, and indifferent to how the
|
|
180
|
-
object was written. The build then executes application import-time code,
|
|
181
|
-
and a builder that only reads files stops being that.
|
|
182
|
-
- **Parse the source.** Read the keys statically with the TypeScript compiler
|
|
183
|
-
API. No application code runs, at the price of a real dependency and of
|
|
184
|
-
guessing wrong on anything not written as a plain object literal.
|
|
185
|
-
|
|
186
|
-
Two smaller calls come with either route. The chrome belongs to no page, so
|
|
187
|
-
a request there can only be required of every page or forbidden. A page with
|
|
188
|
-
no requests file makes any request on it an error. The check is sound
|
|
189
|
-
because the developer writes `lb-*` attributes in markup and script never
|
|
190
|
-
assigns them.
|
|
191
|
-
|
|
192
|
-
The same machinery would then also let `lb-query` names be checked against
|
|
193
|
-
the declared queries.
|
|
194
|
-
|
|
195
181
|
### A language server
|
|
196
182
|
|
|
197
183
|
...for Loadbare HTML.
|
|
@@ -203,6 +189,23 @@ expansion allows a strings file. We could either preserve the fully
|
|
|
203
189
|
static build-time system and create multiple versions of `app.html`, or we
|
|
204
190
|
could add label hydration to the page navigation stage.
|
|
205
191
|
|
|
192
|
+
### Version checks on update and delete
|
|
193
|
+
|
|
194
|
+
The last write to a row wins, at the grain of the columns each request
|
|
195
|
+
carries, and a write whose outcome matters states its precondition in its
|
|
196
|
+
own SQL; see [crud](./reference/page-files.md#crud). A plain edit has no
|
|
197
|
+
such precondition: only the value the user saw, or a version standing for
|
|
198
|
+
it, tells that the row changed in between, and the server remembers
|
|
199
|
+
nothing.
|
|
200
|
+
|
|
201
|
+
A query would declare its version column. The hub keeps every query's
|
|
202
|
+
last answer, patches included, so it would send the version it holds with
|
|
203
|
+
each update and delete for that query, and the handler would put it in its
|
|
204
|
+
`WHERE`. No widget changes, and a control committing alone takes part.
|
|
205
|
+
|
|
206
|
+
Revisit when an application needs a write refused because the row changed
|
|
207
|
+
since the user saw it.
|
|
208
|
+
|
|
206
209
|
## Decided against
|
|
207
210
|
|
|
208
211
|
Settled questions, kept here so they are not reopened. Each names what was
|
|
@@ -222,3 +225,12 @@ attribute value, with no escape for either.
|
|
|
222
225
|
|
|
223
226
|
Text has a workaround: `<div>Hello, <span>{{world}}</span></div>` places the
|
|
224
227
|
placeholder in a text node of its own. Attribute values have none.
|
|
228
|
+
|
|
229
|
+
### Serving the static files
|
|
230
|
+
|
|
231
|
+
A router beside `hubRoutes` that serves `client.js`, `app.css` and
|
|
232
|
+
`app.html` would save an application three routes. It would also decide
|
|
233
|
+
for every application how those files are read, cached and placed among
|
|
234
|
+
its own routes, and whether a path naming no page answers `app.html`.
|
|
235
|
+
Loadbare/app ships no server, and serving the build's output is the
|
|
236
|
+
application's choice, as the rest of its server is.
|
package/docs/testing.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Testing
|
|
2
2
|
|
|
3
|
+
> LLM-authored and LLM-maintained. This is acceptable because the
|
|
4
|
+
> document is fact-based, describing tests that exist in this package, and
|
|
5
|
+
> is written to be consumed by an LLM working on the package.
|
|
6
|
+
|
|
3
7
|
A contributor's document, and a companion to [theory.md](./theory.md). It
|
|
4
8
|
describes how this package tests itself.
|
|
5
9
|
|
|
@@ -26,6 +30,23 @@ All four tiers run under `npm test` today and need no dependency that is not
|
|
|
26
30
|
already installed. A fifth environment — a real browser — is discussed at the
|
|
27
31
|
end and is not built.
|
|
28
32
|
|
|
33
|
+
## What the tests are evidence for
|
|
34
|
+
|
|
35
|
+
[Theory](./theory.md) makes three claims that can be checked, and this suite
|
|
36
|
+
carries evidence for two of them.
|
|
37
|
+
|
|
38
|
+
- **Correctness.** Most of what Theory's correctness section names is
|
|
39
|
+
tested here: rows landed by key, an unchanged row left alone with what the
|
|
40
|
+
user typed, an answer in the wrong shape left out, a write sent once, a
|
|
41
|
+
refusal shown on the controls it names, and a server that refuses what a
|
|
42
|
+
page did not declare.
|
|
43
|
+
- **The vocabulary rule.** The markup checks in tier 1 enforce it at build
|
|
44
|
+
time: an `lb-` attribute outside the set the developer writes is a build
|
|
45
|
+
that fails.
|
|
46
|
+
- **Performance.** No tier measures the 300ms round trip. Node and jsdom
|
|
47
|
+
have no network and no paint, so they are not evidence for it, and this
|
|
48
|
+
suite does not try.
|
|
49
|
+
|
|
29
50
|
## The runner
|
|
30
51
|
|
|
31
52
|
`node:test`, run through `tsx`:
|
|
@@ -78,17 +99,14 @@ the most of what Loadbare promises, so it is first.
|
|
|
78
99
|
- more than one `lb-exp-slot`
|
|
79
100
|
|
|
80
101
|
**Markup checks.** The assembled chrome and every page are checked before
|
|
81
|
-
anything ships
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- a chrome without exactly one `<lb-hub>` and one empty `<main>` inside it,
|
|
90
|
-
and a page carrying either
|
|
91
|
-
- a widget script declaring an `lb` method Loadbare does not define
|
|
102
|
+
anything ships, against the list in
|
|
103
|
+
[The markup checks](./reference/data-binding.md#the-markup-checks). Each one
|
|
104
|
+
is a build that must not produce output. The checks of `lb-query` and
|
|
105
|
+
`lb-request` names take each page's declarations as `loadDeclared` reads
|
|
106
|
+
them, and `loadDeclared` is tested against real page modules: names read
|
|
107
|
+
off objects built with spreads and computed keys, nothing declared for a
|
|
108
|
+
page with no modules, nothing left in the output directory, and a module
|
|
109
|
+
that throws named in the error.
|
|
92
110
|
|
|
93
111
|
A page file's `<title>` is lifted out and stamped as `lb-page-title`.
|
|
94
112
|
|
|
@@ -118,7 +136,7 @@ Review the golden files rather than blessing them. `npm run test:golden -w
|
|
|
118
136
|
@loadbare/demo` rewrites them; the diff is the point, and a diff nobody read
|
|
119
137
|
is a test nobody ran.
|
|
120
138
|
|
|
121
|
-
The rest of the build — `assemble`, `elements`, `pages`, `styles`,
|
|
139
|
+
The rest of the build — `assemble`, `declared`, `elements`, `pages`, `styles`,
|
|
122
140
|
`package-css` — is tested the same way and in the same tier, since none of it
|
|
123
141
|
needs a browser either.
|
|
124
142
|
|
|
@@ -126,7 +144,7 @@ needs a browser either.
|
|
|
126
144
|
a temporary project, which carries a stand-in `@loadbare/app` pointing at
|
|
127
145
|
the hub's source so the test needs no prior build. It is tested for its
|
|
128
146
|
default `src` and `dist`, every file it writes, `--minify`, a failed build's
|
|
129
|
-
exit code, and `--watch` rebuilding on a change, skipping a file it does not
|
|
147
|
+
exit code, a name the page does not declare, and `--watch` rebuilding on a change, skipping a file it does not
|
|
130
148
|
watch, and surviving a failed build.
|
|
131
149
|
|
|
132
150
|
## Tier 2 — The engine
|
|
@@ -149,11 +167,22 @@ watch, and surviving a failed build.
|
|
|
149
167
|
operator away from silently reversing
|
|
150
168
|
- a handler returning `url()` answers with the `lb-url` item alone, and runs
|
|
151
169
|
no refresh set
|
|
170
|
+
- a `row` query that finds no row answers `null`
|
|
171
|
+
- at startup, a malformed order, an unknown column type, and a crud request
|
|
172
|
+
that refreshes its own `rows` query are refused
|
|
173
|
+
- an update or delete for several rows runs once per key, lays the patches
|
|
174
|
+
together, and refreshes once
|
|
175
|
+
- `onPageEnter` may return `url()` or `choices()`, and `onChoices` hears
|
|
176
|
+
every choice the user makes
|
|
177
|
+
- a refusal carries a message, columns or both, and passes through the
|
|
178
|
+
engine untouched
|
|
152
179
|
|
|
153
180
|
`tests/lb-express.test.ts` runs against a listening app: the page comes from
|
|
154
181
|
the path, the query parms reach `contextFor`, a `url()` answer is followed by
|
|
155
|
-
the page loaded at the new URL, an undeclared request is refused,
|
|
156
|
-
malformed body does not throw
|
|
182
|
+
the page loaded at the new URL, an undeclared request is refused, a
|
|
183
|
+
malformed body does not throw, an oversized body is refused, a refusal
|
|
184
|
+
answers 422 with its words, and any other throw answers 500 with nothing in
|
|
185
|
+
it.
|
|
157
186
|
|
|
158
187
|
## Tier 3 — Landing
|
|
159
188
|
|
|
@@ -187,6 +216,10 @@ evidence here.
|
|
|
187
216
|
groups and leaving them out of counts and aggregates (`lb-choices.test.ts`)
|
|
188
217
|
- `lb-show` moves an element into a template and back, and landing reaches
|
|
189
218
|
inside it
|
|
219
|
+
- a row whose values arrive as it already shows them is not filled again,
|
|
220
|
+
so what the user typed into it stays
|
|
221
|
+
- a `row` query answered with no row empties the columns it names and drops
|
|
222
|
+
its key
|
|
190
223
|
|
|
191
224
|
Two properties, written as loops rather than with a library. Applying the
|
|
192
225
|
same rows twice is applying them once. And rows reached through any sequence
|
|
@@ -252,6 +285,17 @@ What the hub is tested for here:
|
|
|
252
285
|
loaded there
|
|
253
286
|
- `hidden` comes off the body once a page has landed, including the page
|
|
254
287
|
that failed to load, and a link whose page fails to load marks no element
|
|
288
|
+
- an answer that returns after the user has moved to another URL does not
|
|
289
|
+
land
|
|
290
|
+
- focus goes to the first element the user can operate once a page's
|
|
291
|
+
queries land
|
|
292
|
+
- a form pointed at a row by `commandfor` fills from the row the hub holds,
|
|
293
|
+
and a row not yet entered sends no update or delete
|
|
294
|
+
- ticked `lb-select` rows travel as `keys`, and the selection clears once
|
|
295
|
+
the request succeeds
|
|
296
|
+
- a refusal lands its message on the element that committed and on each
|
|
297
|
+
control it names
|
|
298
|
+
- `lb-request-done` reaches the element that committed and its ancestors
|
|
255
299
|
|
|
256
300
|
Widgets are small and their logic is local, so jsdom carries them: a value
|
|
257
301
|
reaches the control the widget owns, the widget is a form-associated control
|
|
@@ -282,18 +326,8 @@ No browser test runner is installed and none of the following exists. They
|
|
|
282
326
|
are recorded here as the shape of the work, not as coverage:
|
|
283
327
|
|
|
284
328
|
1. a cold load fills `<main>` with no empty flash
|
|
285
|
-
2. the wizard never displays a step the server has
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
The last is the one worth a browser. Loadbare's central claim is that no
|
|
289
|
-
markup exists in the DOM that is not in view-source, and that the difference
|
|
290
|
-
between the two is exactly the dynamic half. That is a property, it is stated
|
|
291
|
-
precisely in [theory.md](./theory.md), and it should be enforced mechanically
|
|
292
|
-
rather than believed: fetch the shell as text, compare the element set
|
|
293
|
-
against the live document after interaction, and assert that the only
|
|
294
|
-
additions are clones of row templates.
|
|
295
|
-
|
|
296
|
-
See [TODO.md](../TODO.md) for this and the rest of the open work.
|
|
329
|
+
2. the wizard page in `@loadbare/demo` never displays a step the server has
|
|
330
|
+
not confirmed
|
|
297
331
|
|
|
298
332
|
## Continuous integration
|
|
299
333
|
|
|
@@ -307,7 +341,7 @@ tiers here stay fast enough to run on every save.
|
|
|
307
341
|
## One change the tests want
|
|
308
342
|
|
|
309
343
|
The client reports through `console.error` and `console.warn` directly, from
|
|
310
|
-
|
|
344
|
+
more than twenty places across `hub/` and `@loadbare/widgets`. Routing those through a
|
|
311
345
|
single `report()` in `core/` would give the tests one seam to observe instead
|
|
312
346
|
of a global to mock per file, and would put the framework's error channel in
|
|
313
347
|
the same file as the rest of its vocabulary. It is a small change and it is
|