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.cjs.js
CHANGED
|
@@ -137,6 +137,8 @@ const CODE_TITLES = {
|
|
|
137
137
|
SYG111: 'Controlled input has no input listener',
|
|
138
138
|
SYG115: 'Unknown DOM event shorthand',
|
|
139
139
|
SYG116: 'EVENTS value has no string type',
|
|
140
|
+
// PLAN-13 N-1: dev entry (checks/next.ts onNext) and sygnal-check
|
|
141
|
+
SYG117: 'next() names an action with no model entry',
|
|
140
142
|
SYG124: 'Component used as a control or selector',
|
|
141
143
|
SYG125: 'Control given .intent, .model or .initialState',
|
|
142
144
|
SYG126: 'Control rendered but never listened to',
|
|
@@ -172,6 +174,8 @@ const CODE_TITLES = {
|
|
|
172
174
|
// PLAN-5 V-1: VirtualCollection (checks/virtual.ts)
|
|
173
175
|
SYG430: 'VirtualCollection has no bounded height',
|
|
174
176
|
SYG431: 'VirtualCollection items without ids',
|
|
177
|
+
// PLAN-13 F-3: dev entry (checks/next.ts onRender) and sygnal-check
|
|
178
|
+
SYG429: 'Switchable state map names no page',
|
|
175
179
|
SYG432: 'VirtualCollection item does not render one element',
|
|
176
180
|
SYG433: 'VirtualCollection scroll target not in the list',
|
|
177
181
|
SYG434: 'Invalid VirtualCollection estimateSize or overscan',
|
|
@@ -187,6 +191,8 @@ const CODE_TITLES = {
|
|
|
187
191
|
SYG202: 'STATE reducer returned undefined',
|
|
188
192
|
// SYG3xx streams & intent construction (1A)
|
|
189
193
|
SYG301: 'RxJS operator used on an xstream stream',
|
|
194
|
+
// PLAN-13 X-1: static only (sygnal-check)
|
|
195
|
+
SYG302: "Default import from 'xstream'",
|
|
190
196
|
// SYG4xx collections / switchable / sub-components / context (1A)
|
|
191
197
|
SYG401: "Collection 'from' field is missing or not an array",
|
|
192
198
|
// SYG5xx strict mode / canonical forms (2A; dev-plans/PLAN-1-canonical-forms.md)
|
|
@@ -415,6 +421,7 @@ const DEV_CODE_SEVERITY = {
|
|
|
415
421
|
SYG112: 'error',
|
|
416
422
|
SYG115: 'warn',
|
|
417
423
|
SYG116: 'error',
|
|
424
|
+
SYG117: 'warn',
|
|
418
425
|
// PLAN-4 1-D: controls, static (sygnal-check)
|
|
419
426
|
SYG124: 'error',
|
|
420
427
|
SYG125: 'error',
|
|
@@ -426,6 +433,10 @@ const DEV_CODE_SEVERITY = {
|
|
|
426
433
|
SYG129: 'warn',
|
|
427
434
|
// PLAN-10 X-1: static only (sygnal-check)
|
|
428
435
|
SYG170: 'warn',
|
|
436
|
+
// PLAN-13 X-1: static only (sygnal-check)
|
|
437
|
+
SYG302: 'info',
|
|
438
|
+
// PLAN-13 F-3 (checks/next.ts)
|
|
439
|
+
SYG429: 'warn',
|
|
429
440
|
SYG171: 'warn',
|
|
430
441
|
SYG221: 'error',
|
|
431
442
|
// PLAN-4 GS-4 (state.ts)
|
|
@@ -1147,7 +1158,9 @@ const propsCheck = {
|
|
|
1147
1158
|
data: { prop: key },
|
|
1148
1159
|
});
|
|
1149
1160
|
}
|
|
1150
|
-
|
|
1161
|
+
// PLAN-13 F-3 follow-up: a Switchable page gets the Switchable's props, whose `state` is the
|
|
1162
|
+
// host's binding (a per-page map too), consumed by the host: not a prop meant for the page
|
|
1163
|
+
if ('state' in props && component.__next?.kind !== 'page') {
|
|
1151
1164
|
const value = props.state;
|
|
1152
1165
|
const isLens = typeof value === 'string' || (value && typeof value === 'object' && typeof value.get === 'function');
|
|
1153
1166
|
if (!isLens && value !== undefined && once(`SYG106:${name}:state`)) {
|
|
@@ -3875,7 +3888,8 @@ const audited = (f, type, sink, h) => (s, d, nx, p, ...r) => {
|
|
|
3875
3888
|
* page after a patch, G-460: on rendered elements), SYG612 (D173: a form
|
|
3876
3889
|
* 6.0 removed, met at runtime; once per form and component, with a link to the migration
|
|
3877
3890
|
* guide), SYG453 (PLAN-9, D470: two children with one identity share one instance), SYG426
|
|
3878
|
-
* (PLAN-9, D471: a lowercase <collection> / <switchable> tag, deprecated in 6.3.0)
|
|
3891
|
+
* (PLAN-9, D471: a lowercase <collection> / <switchable> tag, deprecated in 6.3.0), SYG117
|
|
3892
|
+
* (PLAN-13 N-1: next() to an action the component has no model entry for).
|
|
3879
3893
|
*
|
|
3880
3894
|
* Only while diagnostics are on (the checks' own rule); production builds never load this.
|
|
3881
3895
|
*/
|
|
@@ -4071,6 +4085,36 @@ function lowercaseTags(iv) {
|
|
|
4071
4085
|
};
|
|
4072
4086
|
walk(raw.tmpl, 0);
|
|
4073
4087
|
}
|
|
4088
|
+
/**
|
|
4089
|
+
* PLAN-13 F-3 SYG429: a Switchable's per-page `state={{ page: … }}` with a key that names no page
|
|
4090
|
+
* (read from the owner's template, as SYG426; 0 production bytes). Once per component and key
|
|
4091
|
+
*/
|
|
4092
|
+
function switchableMaps(iv) {
|
|
4093
|
+
const raw = iv.i;
|
|
4094
|
+
if (!raw?.kids?.size || !raw.tmpl)
|
|
4095
|
+
return;
|
|
4096
|
+
const walk = (n, d) => {
|
|
4097
|
+
if (!n || typeof n != 'object' || n.$p || d > 300)
|
|
4098
|
+
return;
|
|
4099
|
+
const p = n.sel == 'switchable' && n.data?.props, st = p?.state;
|
|
4100
|
+
if (st && isPlainObject(st) && typeof st.get != 'function' && isPlainObject(p.of)) {
|
|
4101
|
+
const pages = Object.keys(p.of);
|
|
4102
|
+
for (const k of Object.keys(st))
|
|
4103
|
+
if (!(k in p.of) && once(`SYG429:${iv.name}:${k}`))
|
|
4104
|
+
devReport('SYG429', {
|
|
4105
|
+
component: iv.name,
|
|
4106
|
+
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)}`,
|
|
4107
|
+
fix: 'Use the page name from of={{ … }} as the key, or remove the entry',
|
|
4108
|
+
data: { key: k, pages },
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
const kids = n.children;
|
|
4112
|
+
if (Array.isArray(kids))
|
|
4113
|
+
for (const c of kids)
|
|
4114
|
+
walk(c, d + 1);
|
|
4115
|
+
};
|
|
4116
|
+
walk(raw.tmpl, 0);
|
|
4117
|
+
}
|
|
4074
4118
|
/** the instance fields the checks read from today's Component instances */
|
|
4075
4119
|
class Facade {
|
|
4076
4120
|
constructor(__next) {
|
|
@@ -4347,6 +4391,7 @@ function nextHooks(_api) {
|
|
|
4347
4391
|
removedTags(f, vnode);
|
|
4348
4392
|
try {
|
|
4349
4393
|
lowercaseTags(iv);
|
|
4394
|
+
switchableMaps(iv);
|
|
4350
4395
|
}
|
|
4351
4396
|
catch (_) { /* a check never breaks the app */ }
|
|
4352
4397
|
// SYG453: only a view with children can render one twice
|
|
@@ -4389,6 +4434,26 @@ function nextHooks(_api) {
|
|
|
4389
4434
|
}
|
|
4390
4435
|
catch (_) { /* a check never breaks the app */ }
|
|
4391
4436
|
},
|
|
4437
|
+
// SYG117 (PLAN-13 N-1): next('X') goes to the component's own model only; with no entry
|
|
4438
|
+
// for X it does nothing (an ancestor's entry of that name never runs)
|
|
4439
|
+
onNext(iv, type) {
|
|
4440
|
+
if (!on() || iv.def.handlers.has(type))
|
|
4441
|
+
return;
|
|
4442
|
+
const name = iv.name;
|
|
4443
|
+
if (!once(`SYG117:${name}:${type}`))
|
|
4444
|
+
return;
|
|
4445
|
+
let up = live.get(iv.parentId);
|
|
4446
|
+
while (up && !up.def.handlers.has(type))
|
|
4447
|
+
up = live.get(up.parentId);
|
|
4448
|
+
devReport('SYG117', {
|
|
4449
|
+
component: name,
|
|
4450
|
+
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())}`,
|
|
4451
|
+
fix: up
|
|
4452
|
+
? `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`
|
|
4453
|
+
: `Add the entry to ${name}.model (${type}: (state, data) => …), or fix the name to match an existing one`,
|
|
4454
|
+
data: { action: type, ...(up ? { handledBy: up.name } : {}) },
|
|
4455
|
+
});
|
|
4456
|
+
},
|
|
4392
4457
|
onElementCommand(iv, cmd) {
|
|
4393
4458
|
if (!on())
|
|
4394
4459
|
return;
|