@webjsdev/core 0.7.49 → 0.7.51
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/webjs-core-browser.js +5 -5
- package/dist/webjs-core-browser.js.map +3 -3
- package/dist/webjs-core-testing.js +21 -21
- package/dist/webjs-core-testing.js.map +3 -3
- package/dist/webjs-core.js +7 -7
- package/dist/webjs-core.js.map +3 -3
- package/index-browser.js +1 -1
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/src/attribute-reader.js +178 -0
- package/src/component/lifecycle.js +1481 -0
- package/src/component/reactive.js +171 -0
- package/src/component/server-element.js +248 -0
- package/src/component.d.ts +10 -0
- package/src/component.js +2 -1931
- package/src/html-entities.js +2179 -0
- package/src/render-client/parts.js +2007 -0
- package/src/render-client/reconciler.js +388 -0
- package/src/render-client/template-compiler.js +525 -0
- package/src/render-client.js +1 -2939
- package/src/render-server/attrs.js +160 -0
- package/src/render-server/dsd.js +445 -0
- package/src/render-server/html-scan.js +402 -0
- package/src/render-server/slots.js +213 -0
- package/src/render-server/stream.js +163 -0
- package/src/render-server/template-renderer.js +923 -0
- package/src/render-server/text.js +163 -0
- package/src/render-server.js +6 -2334
- package/src/router-client/anchors.js +44 -0
- package/src/router-client/boundaries.js +221 -0
- package/src/router-client/constants.js +187 -0
- package/src/router-client/diagnostics.js +377 -0
- package/src/router-client/dom-differ.js +709 -0
- package/src/router-client/dom-parse.js +150 -0
- package/src/router-client/events.js +139 -0
- package/src/router-client/fetch-apply.js +387 -0
- package/src/router-client/form-encoder.js +135 -0
- package/src/router-client/frames.js +329 -0
- package/src/router-client/head-merge.js +344 -0
- package/src/router-client/nav-error.js +105 -0
- package/src/router-client/navigator.js +781 -0
- package/src/router-client/prefetch.js +824 -0
- package/src/router-client/scroll.js +259 -0
- package/src/router-client/snapshot-cache.js +97 -0
- package/src/router-client/state.js +92 -0
- package/src/router-client/stream.js +206 -0
- package/src/router-client/swap.js +451 -0
- package/src/router-client/upgrade.js +261 -0
- package/src/router-client/view-transition.js +223 -0
- package/src/router-client.d.ts +10 -1
- package/src/router-client.js +75 -5345
- package/src/slot/assignment.js +304 -0
- package/src/slot/interception.js +558 -0
- package/src/slot/polyfills.js +365 -0
- package/src/slot/project.js +432 -0
- package/src/slot/sensors.js +303 -0
- package/src/slot/state.js +245 -0
- package/src/slot/symbols.js +85 -0
- package/src/slot.js +7 -2199
- package/src/webjs-config.d.ts +13 -2
package/index-browser.js
CHANGED
|
@@ -60,7 +60,7 @@ import './src/router-client.js';
|
|
|
60
60
|
// it, `import { loadFrame } from '@webjsdev/core/client-router'` type-checks,
|
|
61
61
|
// works in dev (where the subpath maps to `src/router-client.js`) and is
|
|
62
62
|
// `undefined` in production.
|
|
63
|
-
export { enableClientRouter, disableClientRouter, navigate, revalidate, loadFrame } from './src/router-client.js';
|
|
63
|
+
export { enableClientRouter, disableClientRouter, navigate, revalidate, refreshPage, loadFrame } from './src/router-client.js';
|
|
64
64
|
export { WebjsFrame } from './src/webjs-frame.js';
|
|
65
65
|
export { WebjsStream, renderStream } from './src/webjs-stream.js';
|
|
66
66
|
|
package/index.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ export { repeat, isRepeat } from './src/repeat.js';
|
|
|
81
81
|
export { Suspense, isSuspense } from './src/suspense.js';
|
|
82
82
|
export { connectWS } from './src/websocket-client.js';
|
|
83
83
|
export { richFetch } from './src/rich-fetch.js';
|
|
84
|
-
export { enableClientRouter, disableClientRouter, revalidate, loadFrame } from './src/router-client.js';
|
|
84
|
+
export { enableClientRouter, disableClientRouter, revalidate, refreshPage, loadFrame } from './src/router-client.js';
|
|
85
85
|
|
|
86
86
|
// `navigate` is typed against the generated `Route` union (#258) rather than
|
|
87
87
|
// the JSDoc `string`. Until an app runs `webjs types`, `Route` resolves to
|
package/index.js
CHANGED
|
@@ -28,7 +28,7 @@ export {
|
|
|
28
28
|
stringify, parse,
|
|
29
29
|
serialize, deserialize,
|
|
30
30
|
} from './src/serialize.js';
|
|
31
|
-
export { enableClientRouter, disableClientRouter, navigate, revalidate, loadFrame } from './src/router-client.js';
|
|
31
|
+
export { enableClientRouter, disableClientRouter, navigate, revalidate, refreshPage, loadFrame } from './src/router-client.js';
|
|
32
32
|
export { WebjsFrame } from './src/webjs-frame.js';
|
|
33
33
|
export { WebjsStream, renderStream } from './src/webjs-stream.js';
|
|
34
34
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webjsdev/core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The runtime for WebJs, a full-stack JavaScript framework built on web components with server-side rendering and no build step. Ships the html and css template tags, the WebComponent base class, signals, directives, and the isomorphic renderers.",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE attribute reader, singular.
|
|
3
|
+
*
|
|
4
|
+
* `attributeChangedCallback` in `component.js` and `applyAttrsToInstance` in
|
|
5
|
+
* `render-server.js` are both thin callers of the two functions below, so the
|
|
6
|
+
* client and the SSR pass cannot drift on precedence, on a fallback, or on
|
|
7
|
+
* which attributes they read at all. They had drifted four ways before this
|
|
8
|
+
* module existed: the unparseable-JSON fallback (#1253), a missing converter
|
|
9
|
+
* arm (#1340), and three name-resolution gaps plus the entity decoding (#1341).
|
|
10
|
+
*
|
|
11
|
+
* The split between the two exports is the one place the sides legitimately
|
|
12
|
+
* differ. `resolveAttributeProperty` takes the name the PLATFORM would deliver,
|
|
13
|
+
* so the SSR caller lowercases its source name first and the client passes the
|
|
14
|
+
* browser's name straight through. Everything after that is common.
|
|
15
|
+
*
|
|
16
|
+
* WHY ITS OWN MODULE, rather than living beside the declaration semantics it
|
|
17
|
+
* interprets in `component.js`. That was the first shape, and `component.d.ts`
|
|
18
|
+
* cannot carry the declaration for it: `index.d.ts` re-exports that overlay
|
|
19
|
+
* with a bare `export *`, so a value declared there joins the ROOT public type
|
|
20
|
+
* surface of `@webjsdev/core` while `index.js` exports no such runtime value.
|
|
21
|
+
* An app writing `import { readAttributeValue } from '@webjsdev/core'` would
|
|
22
|
+
* then type-check and crash at load, which is exactly the phantom the #1031
|
|
23
|
+
* guard in `test/types/dts-no-phantom-exports.test.mjs` exists to catch, and it
|
|
24
|
+
* caught this one. Re-exporting the function from `index.js` would silence the
|
|
25
|
+
* guard by making an internal framework seam app-facing API, which is the wrong
|
|
26
|
+
* trade. A module with no `.d.ts` overlay keeps the seam internal and typed
|
|
27
|
+
* from its own JSDoc, which is how `escape.js` and `binding-prefixes.js`
|
|
28
|
+
* already work.
|
|
29
|
+
*
|
|
30
|
+
* It also drops an edge rather than adding one: `render-server.js` reaches the
|
|
31
|
+
* reader without importing `component.js` at all.
|
|
32
|
+
*
|
|
33
|
+
* lit solves the same problem structurally, though in the other direction.
|
|
34
|
+
* `@lit-labs/ssr`'s LitElementRenderer forwards its `attributeChangedCallback`
|
|
35
|
+
* into the element's own `_$attributeToProperty` through
|
|
36
|
+
* `lit-element/private-ssr-support.js`, so its server pass runs the browser's
|
|
37
|
+
* reader rather than a copy of it. lit can reach INTO the element because its
|
|
38
|
+
* elements are TypeScript with a generated declaration; WebJs ships buildless
|
|
39
|
+
* JS under a hand-written overlay, so the shared code moves out instead.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Read one attribute string into its declared property value.
|
|
44
|
+
*
|
|
45
|
+
* The caller owns only the one platform-specific step, lowercasing the source
|
|
46
|
+
* name at SSR; `resolveAttributeProperty` below owns NAME resolution and
|
|
47
|
+
* declaration normalisation for both sides, and this function owns the value.
|
|
48
|
+
* The two callers used to reach an attribute by different routes and NOT see
|
|
49
|
+
* the same attribute set, which #1341 closed.
|
|
50
|
+
*
|
|
51
|
+
* @param {import('./component.js').PropertyDeclaration} def normalised declaration (`{ type, … }`)
|
|
52
|
+
* @param {string|null} value the attribute text
|
|
53
|
+
*
|
|
54
|
+
* BOTH callers hand in an already-decoded value, so no branch decodes anything
|
|
55
|
+
* (#1341). The client's came out of the DOM, which decodes every character
|
|
56
|
+
* reference before any reader sees it; the SSR caller runs `decodeAttrEntities`
|
|
57
|
+
* once at its own call site, ahead of this function, over EVERY branch rather
|
|
58
|
+
* than only the ones that parse. This used to be a third `decode` parameter
|
|
59
|
+
* applied to the JSON and converter branches alone, which left a `String`-typed
|
|
60
|
+
* prop holding the raw source text at SSR while `getAttribute()` on the client
|
|
61
|
+
* returned the decoded one.
|
|
62
|
+
* @returns {unknown}
|
|
63
|
+
*/
|
|
64
|
+
export function readAttributeValue(def, value) {
|
|
65
|
+
if (def.converter && def.converter.fromAttribute) {
|
|
66
|
+
// Deliberately UNGUARDED, and deliberately first (#1340). An author who
|
|
67
|
+
// supplies a converter owns the whole read, which is the same rule
|
|
68
|
+
// `_reflectAttribute` already states for `toAttribute`: its guards sit
|
|
69
|
+
// AFTER the converter branch because a custom converter is
|
|
70
|
+
// author-controlled. So a converter that throws throws, on both sides. At
|
|
71
|
+
// SSR that lands in per-component error isolation (render-server.js), which
|
|
72
|
+
// surfaces an error box in dev and an empty element at a 200 in prod with
|
|
73
|
+
// the cause in the server log; on the client it escapes
|
|
74
|
+
// attributeChangedCallback during upgrade. Catching on one side only would
|
|
75
|
+
// manufacture a fresh divergence (an SSR paint holding a fallback against a
|
|
76
|
+
// browser holding the constructor value), which is worse than both sides
|
|
77
|
+
// failing. lit propagates too (reactive-element `_$attributeToProperty`).
|
|
78
|
+
//
|
|
79
|
+
// A converter RETURN that SSR cannot serialise needs no guard here either.
|
|
80
|
+
// Unreflected it is only a property, and a function in a text hole renders
|
|
81
|
+
// as nothing. Reflected, the #1169 function guard and the #1253
|
|
82
|
+
// unserializable guard in `_reflectAttribute` already run on the SSR side
|
|
83
|
+
// and cover whatever the converter produced.
|
|
84
|
+
//
|
|
85
|
+
// The converter is handed DECODED text, which matters more here than
|
|
86
|
+
// anywhere: the documented reason to write one is a type the built-in
|
|
87
|
+
// converters cannot parse (Date, Map, Set), those parse their input, and
|
|
88
|
+
// `escapeAttr` encodes every `"` in an emitted attribute, so an encoded
|
|
89
|
+
// `{"a":1}` would throw inside the author's converter and (since
|
|
90
|
+
// the throw is deliberately uncaught) render an empty component at a 200.
|
|
91
|
+
// Both callers now decode before calling, so it gets the same text on both
|
|
92
|
+
// sides for hand-written markup as well as for anything WebJs emitted
|
|
93
|
+
// (#1341); this used to be a `decode` argument applied on this branch and
|
|
94
|
+
// the JSON one.
|
|
95
|
+
return def.converter.fromAttribute(value, def.type);
|
|
96
|
+
}
|
|
97
|
+
if (def.type === Number) return value == null ? null : Number(value);
|
|
98
|
+
if (def.type === Boolean) return value != null && value !== 'false';
|
|
99
|
+
if (def.type === Object || def.type === Array) {
|
|
100
|
+
// An attribute that is not parseable JSON yields `null` rather than the raw
|
|
101
|
+
// string (#1253), because a STRING is never a valid value for a property
|
|
102
|
+
// the author declared `Object` or `Array`, whatever put it there. lit's
|
|
103
|
+
// `defaultConverter.fromAttribute` lands on the same `null`, for the reason
|
|
104
|
+
// its own comment gives: an element does not complain about being
|
|
105
|
+
// mis-configured. Both readers reach this line, so they cannot disagree.
|
|
106
|
+
//
|
|
107
|
+
// An attribute that was never PRESENT does not reach either reader, so such
|
|
108
|
+
// a prop simply keeps its constructor value.
|
|
109
|
+
//
|
|
110
|
+
// The two readers now see the SAME attribute set, so this fallback is not
|
|
111
|
+
// the only thing they agree on (#1341). Both resolve a name through
|
|
112
|
+
// `resolveAttributeProperty` below, which matches the same
|
|
113
|
+
// `d.attribute || hyphenate(k)` expression `observedAttributes` maps over
|
|
114
|
+
// and nothing else, so it skips a `state: true` prop and ignores a name that
|
|
115
|
+
// maps to no attribute-backed property exactly as the observed list does.
|
|
116
|
+
// The SSR caller lowercases its source name first, because the browser
|
|
117
|
+
// lowercases while parsing. And both are handed a value with every
|
|
118
|
+
// character reference already decoded, legacy semicolon-less names included.
|
|
119
|
+
if (value == null) return null;
|
|
120
|
+
try { return JSON.parse(value); } catch { return null; }
|
|
121
|
+
}
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Kebab-case a property name for its default HTML attribute. @param {string} s */
|
|
126
|
+
function hyphenate(s) {
|
|
127
|
+
return s.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Resolve an attribute NAME to the property it feeds, and to that property's
|
|
132
|
+
* normalised declaration.
|
|
133
|
+
*
|
|
134
|
+
* `state: true` props are skipped, because they are absent from
|
|
135
|
+
* `observedAttributes` and so the browser never delivers their attribute to any
|
|
136
|
+
* reader. lit reaches the same outcome the same way, resolving through the very
|
|
137
|
+
* map `observedAttributes` is built from (`reactive-element.ts`
|
|
138
|
+
* `_$attributeToProperty`).
|
|
139
|
+
*
|
|
140
|
+
* `attrName` must already be the name the PLATFORM would deliver. The browser
|
|
141
|
+
* lowercases attribute names while parsing, so the SSR caller lowercases its
|
|
142
|
+
* source name before calling and the client caller passes the browser's name
|
|
143
|
+
* through untouched. That one step is the only thing that differs between the
|
|
144
|
+
* two sides, which is why it lives in the callers and not here. A custom
|
|
145
|
+
* `attribute` option is matched VERBATIM, as lit matches it and as a browser
|
|
146
|
+
* would, so a camelCase custom attribute stays unreachable from markup rather
|
|
147
|
+
* than being reachable at SSR only. Lowercasing the DECLARED side would make
|
|
148
|
+
* SSR read MORE than a browser can deliver, which is the bug this function
|
|
149
|
+
* exists to remove, so do not add it.
|
|
150
|
+
*
|
|
151
|
+
* The match is EXACTLY `d.attribute || hyphenate(k)`, the same expression
|
|
152
|
+
* `observedAttributes` maps over, and nothing else. A `props[attrName] ||
|
|
153
|
+
* props[camelCase(attrName)]` fallback used to sit after the loop, so a prop
|
|
154
|
+
* declaring a custom attribute also answered to its PROPERTY name. Both readers
|
|
155
|
+
* carried that code, which read like an agreement and was not one: the browser
|
|
156
|
+
* only ever calls in with a name from `observedAttributes`, and that list holds
|
|
157
|
+
* the declared attribute alone, so the fallback was unreachable on the client
|
|
158
|
+
* and live on the server. Measured, `open: prop(Boolean, { attribute:
|
|
159
|
+
* 'is-open' })` with `<my-el open>` SSR'd `true` and upgraded to the
|
|
160
|
+
* constructor value. Deriving the match from the same expression the observed
|
|
161
|
+
* list is built from is what makes the two sides agree by construction rather
|
|
162
|
+
* than by two copies staying in step (#1341).
|
|
163
|
+
*
|
|
164
|
+
* @param {any} Cls the component class
|
|
165
|
+
* @param {string} attrName
|
|
166
|
+
* @returns {{ propName: string, def: PropertyDeclaration } | undefined}
|
|
167
|
+
* `undefined` when the attribute maps to no attribute-backed property, in
|
|
168
|
+
* which case the caller must IGNORE the attribute entirely (#1341).
|
|
169
|
+
*/
|
|
170
|
+
export function resolveAttributeProperty(Cls, attrName) {
|
|
171
|
+
const props = (Cls && Cls.properties) || {};
|
|
172
|
+
for (const [k, decl] of Object.entries(props)) {
|
|
173
|
+
const d = typeof decl === 'object' && decl !== null ? decl : { type: decl };
|
|
174
|
+
if (d.state) continue;
|
|
175
|
+
if ((d.attribute || hyphenate(k)) === attrName) return { propName: k, def: d };
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|