@avocadostudio-ai/shared 0.5.1 → 0.6.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/dist/block-manifest.d.ts +23 -1
- package/dist/block-manifest.js +59 -4
- package/dist/blocks/_registry.d.ts +29 -0
- package/dist/editable-coverage.js +61 -6
- package/dist/panel-coverage.js +9 -3
- package/package.json +2 -2
package/dist/block-manifest.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export declare const fieldMetaSchema: z.ZodObject<{
|
|
|
36
36
|
}, z.core.$strip>>;
|
|
37
37
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
38
38
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
39
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
40
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
39
41
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
40
42
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
41
43
|
name: z.ZodString;
|
|
@@ -80,6 +82,8 @@ export declare const listFieldMetaSchema: z.ZodObject<{
|
|
|
80
82
|
}, z.core.$strip>>;
|
|
81
83
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
82
84
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
85
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
86
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
83
87
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
84
88
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
85
89
|
name: z.ZodString;
|
|
@@ -123,6 +127,8 @@ export declare const listFieldMetaSchema: z.ZodObject<{
|
|
|
123
127
|
}, z.core.$strip>>;
|
|
124
128
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
125
129
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
130
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
131
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
126
132
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
127
133
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
128
134
|
name: z.ZodString;
|
|
@@ -172,6 +178,8 @@ export declare const blockDefinitionSchema: z.ZodObject<{
|
|
|
172
178
|
}, z.core.$strip>>;
|
|
173
179
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
174
180
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
181
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
182
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
175
183
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
176
184
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
177
185
|
name: z.ZodString;
|
|
@@ -216,6 +224,8 @@ export declare const blockDefinitionSchema: z.ZodObject<{
|
|
|
216
224
|
}, z.core.$strip>>;
|
|
217
225
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
218
226
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
227
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
228
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
219
229
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
220
230
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
221
231
|
name: z.ZodString;
|
|
@@ -259,6 +269,8 @@ export declare const blockDefinitionSchema: z.ZodObject<{
|
|
|
259
269
|
}, z.core.$strip>>;
|
|
260
270
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
261
271
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
272
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
273
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
262
274
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
263
275
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
264
276
|
name: z.ZodString;
|
|
@@ -314,6 +326,8 @@ export declare const blockManifestSchema: z.ZodObject<{
|
|
|
314
326
|
}, z.core.$strip>>;
|
|
315
327
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
316
328
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
329
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
330
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
317
331
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
318
332
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
319
333
|
name: z.ZodString;
|
|
@@ -358,6 +372,8 @@ export declare const blockManifestSchema: z.ZodObject<{
|
|
|
358
372
|
}, z.core.$strip>>;
|
|
359
373
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
360
374
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
375
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
376
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
361
377
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
362
378
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
363
379
|
name: z.ZodString;
|
|
@@ -401,6 +417,8 @@ export declare const blockManifestSchema: z.ZodObject<{
|
|
|
401
417
|
}, z.core.$strip>>;
|
|
402
418
|
multiline: z.ZodOptional<z.ZodBoolean>;
|
|
403
419
|
referenceLabelKey: z.ZodOptional<z.ZodString>;
|
|
420
|
+
panelOnly: z.ZodOptional<z.ZodBoolean>;
|
|
421
|
+
internal: z.ZodOptional<z.ZodBoolean>;
|
|
404
422
|
inline: z.ZodOptional<z.ZodBoolean>;
|
|
405
423
|
decorators: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
406
424
|
name: z.ZodString;
|
|
@@ -466,7 +484,11 @@ export declare function validateManifestDefaultProps(blocks: BlockDefinition[]):
|
|
|
466
484
|
*
|
|
467
485
|
* - `propsSchema` decides *which* props exist. A declared entry for a key the
|
|
468
486
|
* schema does not expose is ignored, not added — otherwise a stale manifest
|
|
469
|
-
* would put a control on a prop the block cannot store.
|
|
487
|
+
* would put a control on a prop the block cannot store. The one exception is
|
|
488
|
+
* `internal: true`, which adds no control by definition: it is how a site
|
|
489
|
+
* names a prop the derivation skipped for being structural (a Contentful
|
|
490
|
+
* `sys`, a `__source` snapshot) so the coverage checkers stop reporting it as
|
|
491
|
+
* undescribed. Nothing else can be conjured this way.
|
|
470
492
|
* - A declared entry is merged *over* the derived one, key by key, so a site
|
|
471
493
|
* can supply just `multiline` and keep the label and options that were
|
|
472
494
|
* inferred for it.
|
package/dist/block-manifest.js
CHANGED
|
@@ -61,6 +61,15 @@ export const fieldMetaSchema = z.object({
|
|
|
61
61
|
* label it and no sign that anything had been declared.
|
|
62
62
|
*/
|
|
63
63
|
referenceLabelKey: z.string().optional(),
|
|
64
|
+
/*
|
|
65
|
+
* Both of these decide whether a surface *mentions* a field, and every one
|
|
66
|
+
* of those surfaces is on the far side of this boundary — the panel, the
|
|
67
|
+
* planner's schema summary, the coverage checkers. A key this schema omits
|
|
68
|
+
* is stripped rather than rejected, so an undeclared flag here means the
|
|
69
|
+
* declaration silently does nothing where it was supposed to act.
|
|
70
|
+
*/
|
|
71
|
+
panelOnly: z.boolean().optional(),
|
|
72
|
+
internal: z.boolean().optional(),
|
|
64
73
|
inline: z.boolean().optional(),
|
|
65
74
|
decorators: z
|
|
66
75
|
.array(z.object({ name: z.string().min(1), title: z.string().optional() }))
|
|
@@ -257,6 +266,29 @@ const FILE_MEDIA_TYPE_RE = /^application\/(?!json\b)|^text\/(?:csv|calendar)\b/i
|
|
|
257
266
|
function isInternalPropKey(key) {
|
|
258
267
|
return key.startsWith("_");
|
|
259
268
|
}
|
|
269
|
+
/**
|
|
270
|
+
* The same statement the paragraph above makes, as a field rather than as an
|
|
271
|
+
* absence.
|
|
272
|
+
*
|
|
273
|
+
* These props used to be skipped outright, which kept them out of the panel
|
|
274
|
+
* and away from the planner — correct, and invisible to everything that reads
|
|
275
|
+
* the resolved metadata afterwards. `panelCoverage` is the one that noticed:
|
|
276
|
+
* a prop in the content and in no field set is an `orphan_prop`, and one
|
|
277
|
+
* Storyblok integration's `_uid` produced **~800 of them**, burying every real
|
|
278
|
+
* finding under a wall of noise that could not be closed. There was no way to
|
|
279
|
+
* close it, because "skipped" and "never declared" were the same thing.
|
|
280
|
+
*
|
|
281
|
+
* Emitting `internal: true` says it out loud instead. Every surface that must
|
|
282
|
+
* not mention the prop checks that flag, so nothing about the promise above
|
|
283
|
+
* changes; what changes is that the checkers can tell a known non-content prop
|
|
284
|
+
* from an undescribed one.
|
|
285
|
+
*
|
|
286
|
+
* `kind` is a formality here — nothing renders the field — so it does not
|
|
287
|
+
* matter that a `_key` and a `sys` object both come out as `text`.
|
|
288
|
+
*/
|
|
289
|
+
function internalFieldMeta(key) {
|
|
290
|
+
return { kind: "text", label: labelFromKey(key), internal: true };
|
|
291
|
+
}
|
|
260
292
|
function labelFromKey(key) {
|
|
261
293
|
// ctaText → "CTA text", imageUrl → "Image", logoAlt → "Logo alt",
|
|
262
294
|
// background_image → "Background image", video_url → "Video", src → "Src"
|
|
@@ -348,7 +380,11 @@ function deriveItemFields(itemSchema) {
|
|
|
348
380
|
for (const [key, propSchema] of Object.entries(props)) {
|
|
349
381
|
if (!isObject(propSchema))
|
|
350
382
|
continue;
|
|
351
|
-
if (isInternalPropKey(key)
|
|
383
|
+
if (isInternalPropKey(key)) {
|
|
384
|
+
fields[key] = internalFieldMeta(key);
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (isItemIdentityKey(key))
|
|
352
388
|
continue;
|
|
353
389
|
// Skip opaque object/array props (they'd render as "[object Object]"), but
|
|
354
390
|
// keep richtext docs — those self-identify and get the richtext editor.
|
|
@@ -443,8 +479,10 @@ export function deriveFieldMetaFromSchema(propsSchema) {
|
|
|
443
479
|
for (const [key, propSchema] of Object.entries(props)) {
|
|
444
480
|
if (!isObject(propSchema))
|
|
445
481
|
continue;
|
|
446
|
-
if (isInternalPropKey(key))
|
|
482
|
+
if (isInternalPropKey(key)) {
|
|
483
|
+
fields[key] = internalFieldMeta(key);
|
|
447
484
|
continue;
|
|
485
|
+
}
|
|
448
486
|
const type = typeof propSchema.type === "string" ? propSchema.type : undefined;
|
|
449
487
|
// Array of a discriminated union (oneOf/anyOf of object branches) →
|
|
450
488
|
// polymorphic list field: per-branch fields keyed by the discriminant value.
|
|
@@ -504,7 +542,11 @@ export function validateManifestDefaultProps(blocks) {
|
|
|
504
542
|
*
|
|
505
543
|
* - `propsSchema` decides *which* props exist. A declared entry for a key the
|
|
506
544
|
* schema does not expose is ignored, not added — otherwise a stale manifest
|
|
507
|
-
* would put a control on a prop the block cannot store.
|
|
545
|
+
* would put a control on a prop the block cannot store. The one exception is
|
|
546
|
+
* `internal: true`, which adds no control by definition: it is how a site
|
|
547
|
+
* names a prop the derivation skipped for being structural (a Contentful
|
|
548
|
+
* `sys`, a `__source` snapshot) so the coverage checkers stop reporting it as
|
|
549
|
+
* undescribed. Nothing else can be conjured this way.
|
|
508
550
|
* - A declared entry is merged *over* the derived one, key by key, so a site
|
|
509
551
|
* can supply just `multiline` and keep the label and options that were
|
|
510
552
|
* inferred for it.
|
|
@@ -515,7 +557,20 @@ export function resolveManifestFieldMeta(definition) {
|
|
|
515
557
|
const resolvedFields = {};
|
|
516
558
|
for (const [key, derived] of Object.entries(fields)) {
|
|
517
559
|
const declared = declaredFields[key];
|
|
518
|
-
|
|
560
|
+
const merged = isObject(declared) ? { ...derived, ...declared } : derived;
|
|
561
|
+
// The underscore convention is not negotiable by declaration: a site may
|
|
562
|
+
// label `_key` or change its kind, and it still may not hand it to a
|
|
563
|
+
// person, because the value typed there is the address a field-level
|
|
564
|
+
// publish patches by.
|
|
565
|
+
resolvedFields[key] = isInternalPropKey(key) ? { ...merged, internal: true } : merged;
|
|
566
|
+
}
|
|
567
|
+
for (const [key, declared] of Object.entries(declaredFields)) {
|
|
568
|
+
if (key in resolvedFields)
|
|
569
|
+
continue;
|
|
570
|
+
if (!isObject(declared) || declared.internal !== true)
|
|
571
|
+
continue;
|
|
572
|
+
const fm = declared;
|
|
573
|
+
resolvedFields[key] = { label: labelFromKey(key), ...fm, kind: fm.kind ?? "text" };
|
|
519
574
|
}
|
|
520
575
|
const declaredLists = isObject(definition.listFields) ? definition.listFields : {};
|
|
521
576
|
const resolvedListFields = {};
|
|
@@ -116,6 +116,35 @@ export type FieldMeta = {
|
|
|
116
116
|
* Use this one when there is no element at all.
|
|
117
117
|
*/
|
|
118
118
|
panelOnly?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* This prop belongs to the system that stores the content, not to anyone
|
|
121
|
+
* editing it.
|
|
122
|
+
*
|
|
123
|
+
* Storyblok's `_uid`, Contentful's `sys.id`, a `__source` snapshot, a
|
|
124
|
+
* revision stamp: the publisher needs them, a person must never edit them,
|
|
125
|
+
* and the planner must never be told they exist. Until this flag there was
|
|
126
|
+
* no way to say so, so they rode along undeclared — which is not the same as
|
|
127
|
+
* absent. An undeclared prop is an `orphan_prop` to `panelCoverage`, and one
|
|
128
|
+
* integration's `_uid` produced **~800 of them**, burying every real finding
|
|
129
|
+
* under a wall of noise that could not be closed.
|
|
130
|
+
*
|
|
131
|
+
* Declaring the prop internal says the opposite of what leaving it out says:
|
|
132
|
+
* "this is known, it is not content, and nothing that talks to a human or a
|
|
133
|
+
* model should mention it." Concretely it is hidden from the property panel,
|
|
134
|
+
* absent from the schema summary the planner reads, not expected to carry a
|
|
135
|
+
* preview marker, never offered for translation, and not a coverage finding
|
|
136
|
+
* in either direction — neither an orphan nor a phantom.
|
|
137
|
+
*
|
|
138
|
+
* It is not access control. The value still rides in `props`, still
|
|
139
|
+
* round-trips through the draft, and is still what the adapter writes back;
|
|
140
|
+
* an operation that names one is refused the way any undeclared prop is,
|
|
141
|
+
* because the planner was never told about it.
|
|
142
|
+
*
|
|
143
|
+
* `panelOnly` is the weaker neighbour and means almost the reverse: *a
|
|
144
|
+
* person does edit this, just not on the page.* Reach for that one when the
|
|
145
|
+
* field has no element; reach for this one when the field has no audience.
|
|
146
|
+
*/
|
|
147
|
+
internal?: boolean;
|
|
119
148
|
/**
|
|
120
149
|
* For `kind: "reference"`: the key inside the value holding something a
|
|
121
150
|
* person can read.
|
|
@@ -49,6 +49,10 @@ const DRAWN_KINDS = new Set(["text", "richtext", "image"]);
|
|
|
49
49
|
* button, and the panel offering one is the site saying the image is editable.
|
|
50
50
|
*/
|
|
51
51
|
function needsMarker(meta) {
|
|
52
|
+
// Not content at all — a CMS's `_uid`, a revision stamp. Nobody edits it
|
|
53
|
+
// anywhere, so there is nothing on the page for it to be missing from.
|
|
54
|
+
if (meta.internal)
|
|
55
|
+
return false;
|
|
52
56
|
// The site has said outright that nothing on the page draws this — a
|
|
53
57
|
// `sectionId`, a `<video poster>`, an input's `placeholder`. See `panelOnly`.
|
|
54
58
|
if (meta.panelOnly)
|
|
@@ -73,10 +77,19 @@ const VOID_ELEMENTS = new Set([
|
|
|
73
77
|
"link", "meta", "param", "source", "track", "wbr",
|
|
74
78
|
]);
|
|
75
79
|
/** One element: its tag name, and the raw attribute text, quotes respected. */
|
|
76
|
-
const TAG_RE = /<([a-zA-Z][\w-]*)((?:"[^"]*"|'[^']*'|[^>"'])*)>/g;
|
|
80
|
+
const TAG_RE = /<(\/?)([a-zA-Z][\w-]*)((?:"[^"]*"|'[^']*'|[^>"'])*)>/g;
|
|
77
81
|
const BLOCK_ID_RE = /\bdata-block-id="([^"]*)"/;
|
|
78
82
|
const BLOCK_TYPE_RE = /\bdata-block-type="([^"]*)"/;
|
|
79
83
|
const TARGET_RE = /\bdata-editable-target="([^"]*)"/;
|
|
84
|
+
const SCOPE_RE = /\bdata-editable-scope="([^"]*)"/;
|
|
85
|
+
/** `items[3]` + `question` → `items[3].question`; `cards` + `[0].title` → `cards[0].title`. */
|
|
86
|
+
function joinPath(scope, path) {
|
|
87
|
+
if (scope === "")
|
|
88
|
+
return path;
|
|
89
|
+
if (path === "")
|
|
90
|
+
return scope;
|
|
91
|
+
return path.startsWith("[") ? `${scope}${path}` : `${scope}.${path}`;
|
|
92
|
+
}
|
|
80
93
|
/**
|
|
81
94
|
* Read the marked blocks out of a rendered page's HTML.
|
|
82
95
|
*
|
|
@@ -90,9 +103,35 @@ const TARGET_RE = /\bdata-editable-target="([^"]*)"/;
|
|
|
90
103
|
export function extractMarkedBlocks(html) {
|
|
91
104
|
const blocks = [];
|
|
92
105
|
let current = null;
|
|
106
|
+
/*
|
|
107
|
+
* The open elements that carry a `data-editable-scope`, innermost last, each
|
|
108
|
+
* remembered with the tag that will close it. A component rendering a list
|
|
109
|
+
* row marks a bare `question` and its parent supplies `items[3]`, so the
|
|
110
|
+
* path this file compares against the manifest exists only as the join —
|
|
111
|
+
* see `editableScopeProps`. Without the stack a scoped site's every field
|
|
112
|
+
* reads as missing, and the check that exists to catch a lost marker becomes
|
|
113
|
+
* the reason nobody runs it.
|
|
114
|
+
*/
|
|
115
|
+
const scopes = [];
|
|
116
|
+
const depths = new Map();
|
|
93
117
|
for (const match of html.matchAll(TAG_RE)) {
|
|
94
|
-
const
|
|
95
|
-
const
|
|
118
|
+
const closing = match[1] === "/";
|
|
119
|
+
const tag = match[2].toLowerCase();
|
|
120
|
+
const attrs = match[3] ?? "";
|
|
121
|
+
const selfClosing = attrs.trimEnd().endsWith("/");
|
|
122
|
+
const isVoid = VOID_ELEMENTS.has(tag);
|
|
123
|
+
if (closing) {
|
|
124
|
+
const depth = (depths.get(tag) ?? 0) - 1;
|
|
125
|
+
depths.set(tag, depth);
|
|
126
|
+
while (scopes.length > 0) {
|
|
127
|
+
const top = scopes[scopes.length - 1];
|
|
128
|
+
if (top.tag === tag && top.depth === depth)
|
|
129
|
+
scopes.pop();
|
|
130
|
+
else
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
96
135
|
const blockId = BLOCK_ID_RE.exec(attrs)?.[1];
|
|
97
136
|
const blockType = BLOCK_TYPE_RE.exec(attrs)?.[1];
|
|
98
137
|
if (blockId !== undefined || blockType !== undefined) {
|
|
@@ -102,13 +141,29 @@ export function extractMarkedBlocks(html) {
|
|
|
102
141
|
paths: [],
|
|
103
142
|
};
|
|
104
143
|
blocks.push(current);
|
|
144
|
+
// A path is scoped from the block down, so a scope opened outside this
|
|
145
|
+
// block must not reach into it.
|
|
146
|
+
scopes.length = 0;
|
|
105
147
|
}
|
|
106
148
|
const target = TARGET_RE.exec(attrs)?.[1];
|
|
107
149
|
if (target !== undefined && current) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
150
|
+
const path = scopes.reduce((acc, s) => joinPath(acc, s.scope), "");
|
|
151
|
+
const full = joinPath(path, target);
|
|
152
|
+
current.paths.push(full);
|
|
153
|
+
if (isVoid)
|
|
154
|
+
(current.voidPaths ??= []).push(full);
|
|
111
155
|
}
|
|
156
|
+
if (isVoid || selfClosing)
|
|
157
|
+
continue;
|
|
158
|
+
const depth = depths.get(tag) ?? 0;
|
|
159
|
+
depths.set(tag, depth + 1);
|
|
160
|
+
const scope = SCOPE_RE.exec(attrs)?.[1];
|
|
161
|
+
// The scoping element's own marker is not inside its scope — a component
|
|
162
|
+
// that both scopes its children and marks a field of its own would
|
|
163
|
+
// otherwise prefix its own path with the scope it sets for them. That is
|
|
164
|
+
// why this comes after the target is recorded.
|
|
165
|
+
if (scope !== undefined && scope !== "")
|
|
166
|
+
scopes.push({ tag, scope, depth });
|
|
112
167
|
}
|
|
113
168
|
return blocks;
|
|
114
169
|
}
|
package/dist/panel-coverage.js
CHANGED
|
@@ -58,7 +58,9 @@ function hasContent(value) {
|
|
|
58
58
|
* had no way to use it. A finding with no remedy gets switched off.
|
|
59
59
|
*/
|
|
60
60
|
export function deriveRowLabel(fields, item, index, options) {
|
|
61
|
-
|
|
61
|
+
// An internal field is not content — `_uid` is a perfectly good string and
|
|
62
|
+
// would label every row in the list with a UUID.
|
|
63
|
+
const candidates = Object.keys(fields).filter((k) => k !== options?.discriminator && !fields[k].internal);
|
|
62
64
|
for (const key of candidates) {
|
|
63
65
|
if (fields[key].kind !== "text" && fields[key].kind !== "richtext")
|
|
64
66
|
continue;
|
|
@@ -312,8 +314,12 @@ export function panelCoverage(manifest, pages, options) {
|
|
|
312
314
|
}
|
|
313
315
|
const branchKey = `${block.type}\u0000${listKey}\u0000${discriminantValue}`;
|
|
314
316
|
let declared = declaredItemKeys.get(branchKey);
|
|
315
|
-
if (!declared)
|
|
316
|
-
|
|
317
|
+
if (!declared) {
|
|
318
|
+
// An internal field is declared so that the props carrying it stop
|
|
319
|
+
// reading as orphans; it is not a promise that a row holds one, so
|
|
320
|
+
// it cannot be a phantom either.
|
|
321
|
+
declaredItemKeys.set(branchKey, (declared = new Set(Object.keys(fields).filter((k) => !fields[k].internal))));
|
|
322
|
+
}
|
|
317
323
|
let seen = seenItemKeys.get(branchKey);
|
|
318
324
|
if (!seen)
|
|
319
325
|
seenItemKeys.set(branchKey, (seen = new Set()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avocadostudio-ai/shared",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"zod": "^4.3.6",
|
|
22
|
-
"@avocadostudio-ai/richtext": "^0.
|
|
22
|
+
"@avocadostudio-ai/richtext": "^0.6.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"tsx": "^4.21.0",
|