sygnal 7.0.0 → 7.1.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/CHANGELOG.md +126 -0
- package/dist/astro/server.cjs.js +32 -43
- package/dist/astro/server.cjs.js.map +1 -1
- package/dist/astro/server.mjs +32 -43
- package/dist/astro/server.mjs.map +1 -1
- package/dist/diagnostics.cjs.js +67 -2
- package/dist/diagnostics.cjs.js.map +1 -1
- package/dist/diagnostics.esm.js +67 -2
- package/dist/diagnostics.esm.js.map +1 -1
- package/dist/guide/accessibility.md +1 -1
- package/dist/guide/resources.md +2 -0
- package/dist/guide/timers.md +3 -3
- package/dist/index.cjs.js +189 -77
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +103 -16
- package/dist/index.esm.js +188 -78
- package/dist/index.esm.js.map +1 -1
- package/dist/sygnal.min.js +1 -1
- package/dist/sygnal.min.js.map +1 -1
- package/dist/vike/config/package.json +1 -1
- package/llms.txt +7 -7
- package/package.json +1 -1
- package/src/core/hosts/switchable.ts +26 -8
- package/src/core/instance.ts +12 -7
- package/src/core/statics.ts +5 -5
- package/src/extra/ai/transports/shared.ts +3 -1
- package/src/extra/behaviors.ts +3 -3
- package/src/extra/diagnostics/checks/next.ts +46 -3
- package/src/extra/diagnostics/checks/props.ts +6 -1
- package/src/extra/diagnostics/codes.ts +11 -0
- package/src/extra/fetchDriver.ts +3 -0
- package/src/extra/fetchEventSource.ts +6 -2
- package/src/extra/socketDriver.ts +51 -6
- package/src/extra/ssr.ts +30 -41
- package/src/extra/testing.ts +32 -7
- package/src/extra/timers.ts +5 -2
- package/src/index.d.ts +102 -15
- package/src/index.ts +2 -0
package/dist/diagnostics.esm.js
CHANGED
|
@@ -117,6 +117,8 @@ const CODE_TITLES = {
|
|
|
117
117
|
SYG111: 'Controlled input has no input listener',
|
|
118
118
|
SYG115: 'Unknown DOM event shorthand',
|
|
119
119
|
SYG116: 'EVENTS value has no string type',
|
|
120
|
+
// PLAN-13 N-1: dev entry (checks/next.ts onNext) and sygnal-check
|
|
121
|
+
SYG117: 'next() names an action with no model entry',
|
|
120
122
|
SYG124: 'Component used as a control or selector',
|
|
121
123
|
SYG125: 'Control given .intent, .model or .initialState',
|
|
122
124
|
SYG126: 'Control rendered but never listened to',
|
|
@@ -152,6 +154,8 @@ const CODE_TITLES = {
|
|
|
152
154
|
// PLAN-5 V-1: VirtualCollection (checks/virtual.ts)
|
|
153
155
|
SYG430: 'VirtualCollection has no bounded height',
|
|
154
156
|
SYG431: 'VirtualCollection items without ids',
|
|
157
|
+
// PLAN-13 F-3: dev entry (checks/next.ts onRender) and sygnal-check
|
|
158
|
+
SYG429: 'Switchable state map names no page',
|
|
155
159
|
SYG432: 'VirtualCollection item does not render one element',
|
|
156
160
|
SYG433: 'VirtualCollection scroll target not in the list',
|
|
157
161
|
SYG434: 'Invalid VirtualCollection estimateSize or overscan',
|
|
@@ -167,6 +171,8 @@ const CODE_TITLES = {
|
|
|
167
171
|
SYG202: 'STATE reducer returned undefined',
|
|
168
172
|
// SYG3xx streams & intent construction (1A)
|
|
169
173
|
SYG301: 'RxJS operator used on an xstream stream',
|
|
174
|
+
// PLAN-13 X-1: static only (sygnal-check)
|
|
175
|
+
SYG302: "Default import from 'xstream'",
|
|
170
176
|
// SYG4xx collections / switchable / sub-components / context (1A)
|
|
171
177
|
SYG401: "Collection 'from' field is missing or not an array",
|
|
172
178
|
// SYG5xx strict mode / canonical forms (2A; dev-plans/PLAN-1-canonical-forms.md)
|
|
@@ -395,6 +401,7 @@ const DEV_CODE_SEVERITY = {
|
|
|
395
401
|
SYG112: 'error',
|
|
396
402
|
SYG115: 'warn',
|
|
397
403
|
SYG116: 'error',
|
|
404
|
+
SYG117: 'warn',
|
|
398
405
|
// PLAN-4 1-D: controls, static (sygnal-check)
|
|
399
406
|
SYG124: 'error',
|
|
400
407
|
SYG125: 'error',
|
|
@@ -406,6 +413,10 @@ const DEV_CODE_SEVERITY = {
|
|
|
406
413
|
SYG129: 'warn',
|
|
407
414
|
// PLAN-10 X-1: static only (sygnal-check)
|
|
408
415
|
SYG170: 'warn',
|
|
416
|
+
// PLAN-13 X-1: static only (sygnal-check)
|
|
417
|
+
SYG302: 'info',
|
|
418
|
+
// PLAN-13 F-3 (checks/next.ts)
|
|
419
|
+
SYG429: 'warn',
|
|
409
420
|
SYG171: 'warn',
|
|
410
421
|
SYG221: 'error',
|
|
411
422
|
// PLAN-4 GS-4 (state.ts)
|
|
@@ -1127,7 +1138,9 @@ const propsCheck = {
|
|
|
1127
1138
|
data: { prop: key },
|
|
1128
1139
|
});
|
|
1129
1140
|
}
|
|
1130
|
-
|
|
1141
|
+
// PLAN-13 F-3 follow-up: a Switchable page gets the Switchable's props, whose `state` is the
|
|
1142
|
+
// host's binding (a per-page map too), consumed by the host: not a prop meant for the page
|
|
1143
|
+
if ('state' in props && component.__next?.kind !== 'page') {
|
|
1131
1144
|
const value = props.state;
|
|
1132
1145
|
const isLens = typeof value === 'string' || (value && typeof value === 'object' && typeof value.get === 'function');
|
|
1133
1146
|
if (!isLens && value !== undefined && once(`SYG106:${name}:state`)) {
|
|
@@ -3855,7 +3868,8 @@ const audited = (f, type, sink, h) => (s, d, nx, p, ...r) => {
|
|
|
3855
3868
|
* page after a patch, G-460: on rendered elements), SYG612 (D173: a form
|
|
3856
3869
|
* 6.0 removed, met at runtime; once per form and component, with a link to the migration
|
|
3857
3870
|
* guide), SYG453 (PLAN-9, D470: two children with one identity share one instance), SYG426
|
|
3858
|
-
* (PLAN-9, D471: a lowercase <collection> / <switchable> tag, deprecated in 6.3.0)
|
|
3871
|
+
* (PLAN-9, D471: a lowercase <collection> / <switchable> tag, deprecated in 6.3.0), SYG117
|
|
3872
|
+
* (PLAN-13 N-1: next() to an action the component has no model entry for).
|
|
3859
3873
|
*
|
|
3860
3874
|
* Only while diagnostics are on (the checks' own rule); production builds never load this.
|
|
3861
3875
|
*/
|
|
@@ -4051,6 +4065,36 @@ function lowercaseTags(iv) {
|
|
|
4051
4065
|
};
|
|
4052
4066
|
walk(raw.tmpl, 0);
|
|
4053
4067
|
}
|
|
4068
|
+
/**
|
|
4069
|
+
* PLAN-13 F-3 SYG429: a Switchable's per-page `state={{ page: … }}` with a key that names no page
|
|
4070
|
+
* (read from the owner's template, as SYG426; 0 production bytes). Once per component and key
|
|
4071
|
+
*/
|
|
4072
|
+
function switchableMaps(iv) {
|
|
4073
|
+
const raw = iv.i;
|
|
4074
|
+
if (!raw?.kids?.size || !raw.tmpl)
|
|
4075
|
+
return;
|
|
4076
|
+
const walk = (n, d) => {
|
|
4077
|
+
if (!n || typeof n != 'object' || n.$p || d > 300)
|
|
4078
|
+
return;
|
|
4079
|
+
const p = n.sel == 'switchable' && n.data?.props, st = p?.state;
|
|
4080
|
+
if (st && isPlainObject(st) && typeof st.get != 'function' && isPlainObject(p.of)) {
|
|
4081
|
+
const pages = Object.keys(p.of);
|
|
4082
|
+
for (const k of Object.keys(st))
|
|
4083
|
+
if (!(k in p.of) && once(`SYG429:${iv.name}:${k}`))
|
|
4084
|
+
devReport('SYG429', {
|
|
4085
|
+
component: iv.name,
|
|
4086
|
+
message: `${iv.name}'s Switchable state map binds '${k}', which is not one of its pages (${pages.join(', ')}), so that binding is never used${didYouMean(k, pages)}`,
|
|
4087
|
+
fix: 'Use the page name from of={{ … }} as the key, or remove the entry',
|
|
4088
|
+
data: { key: k, pages },
|
|
4089
|
+
});
|
|
4090
|
+
}
|
|
4091
|
+
const kids = n.children;
|
|
4092
|
+
if (Array.isArray(kids))
|
|
4093
|
+
for (const c of kids)
|
|
4094
|
+
walk(c, d + 1);
|
|
4095
|
+
};
|
|
4096
|
+
walk(raw.tmpl, 0);
|
|
4097
|
+
}
|
|
4054
4098
|
/** the instance fields the checks read from today's Component instances */
|
|
4055
4099
|
class Facade {
|
|
4056
4100
|
constructor(__next) {
|
|
@@ -4327,6 +4371,7 @@ function nextHooks(_api) {
|
|
|
4327
4371
|
removedTags(f, vnode);
|
|
4328
4372
|
try {
|
|
4329
4373
|
lowercaseTags(iv);
|
|
4374
|
+
switchableMaps(iv);
|
|
4330
4375
|
}
|
|
4331
4376
|
catch (_) { /* a check never breaks the app */ }
|
|
4332
4377
|
// SYG453: only a view with children can render one twice
|
|
@@ -4369,6 +4414,26 @@ function nextHooks(_api) {
|
|
|
4369
4414
|
}
|
|
4370
4415
|
catch (_) { /* a check never breaks the app */ }
|
|
4371
4416
|
},
|
|
4417
|
+
// SYG117 (PLAN-13 N-1): next('X') goes to the component's own model only; with no entry
|
|
4418
|
+
// for X it does nothing (an ancestor's entry of that name never runs)
|
|
4419
|
+
onNext(iv, type) {
|
|
4420
|
+
if (!on() || iv.def.handlers.has(type))
|
|
4421
|
+
return;
|
|
4422
|
+
const name = iv.name;
|
|
4423
|
+
if (!once(`SYG117:${name}:${type}`))
|
|
4424
|
+
return;
|
|
4425
|
+
let up = live.get(iv.parentId);
|
|
4426
|
+
while (up && !up.def.handlers.has(type))
|
|
4427
|
+
up = live.get(up.parentId);
|
|
4428
|
+
devReport('SYG117', {
|
|
4429
|
+
component: name,
|
|
4430
|
+
message: `${name} calls next('${type}'), but ${name} has no model entry '${type}', so the action does nothing${up ? `: next() never reaches ${up.name}, which handles '${type}'` : ''}${didYouMean(type, iv.def.handlers.keys())}`,
|
|
4431
|
+
fix: up
|
|
4432
|
+
? `next() stays in its own component. Send it up instead: give the entry that calls it a PARENT sink (PARENT: (state) => ({ … })) and add ${type}: CHILD.select(${name}) to ${up.name}.intent, or emit EVENTS: event('${type}', …) and select it there`
|
|
4433
|
+
: `Add the entry to ${name}.model (${type}: (state, data) => …), or fix the name to match an existing one`,
|
|
4434
|
+
data: { action: type, ...(up ? { handledBy: up.name } : {}) },
|
|
4435
|
+
});
|
|
4436
|
+
},
|
|
4372
4437
|
onElementCommand(iv, cmd) {
|
|
4373
4438
|
if (!on())
|
|
4374
4439
|
return;
|