@nubbin/core 0.2.0 → 0.3.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/index.d.ts +103 -32
- package/dist/index.js +30 -17
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,12 @@ interface FieldNode {
|
|
|
22
22
|
optional: boolean;
|
|
23
23
|
/** Present only for `enum`. */
|
|
24
24
|
members?: readonly string[];
|
|
25
|
+
/** The schema's own upper bound on a `string` field's length, when it declares one. */
|
|
26
|
+
maxLength?: number;
|
|
27
|
+
/** The schema's own lower bound on an `array` field's row count, when it declares one. */
|
|
28
|
+
minItems?: number;
|
|
29
|
+
/** The schema's own upper bound on an `array` field's row count, when it declares one. */
|
|
30
|
+
maxItems?: number;
|
|
25
31
|
}
|
|
26
32
|
/** The contract for reading a schema's field structure — what `defineCatalog` resolves hint
|
|
27
33
|
* paths through, and what an editing surface reads a block's fields from. */
|
|
@@ -161,6 +167,31 @@ interface Block<Schema extends StandardSchemaV1 = StandardSchemaV1, Component =
|
|
|
161
167
|
* registry — two blocks sharing a name are refused.
|
|
162
168
|
*/
|
|
163
169
|
name: string;
|
|
170
|
+
/**
|
|
171
|
+
* One line saying what the block is for, shown wherever an editing surface lists blocks.
|
|
172
|
+
* Editor metadata with the same standing as editing hints: it sits beside the schema, never
|
|
173
|
+
* inside it, and compile never reads it — no artifact carries a description.
|
|
174
|
+
*/
|
|
175
|
+
description?: string;
|
|
176
|
+
/**
|
|
177
|
+
* A single glyph — an emoji or short string the consumer chooses — shown beside the name
|
|
178
|
+
* wherever an editing surface lists blocks. A string rather than a component, so `core` stays
|
|
179
|
+
* render-agnostic. Editor metadata like `description`: compile never reads it.
|
|
180
|
+
*/
|
|
181
|
+
icon?: string;
|
|
182
|
+
/**
|
|
183
|
+
* The palette section the block files under, wherever an editing surface groups blocks. An
|
|
184
|
+
* opaque label the consumer chooses — Nubbin holds no taxonomy of its own, and a surface may
|
|
185
|
+
* derive a grouping for a block that omits it. Editor metadata like `description`: compile
|
|
186
|
+
* never reads it.
|
|
187
|
+
*/
|
|
188
|
+
category?: string;
|
|
189
|
+
/**
|
|
190
|
+
* Opaque links keyed by destination — `docs: { figma: "…", storybook: "…" }` — that an editing
|
|
191
|
+
* surface renders as "Open in {Key}" for the selected block. Nubbin never inspects a URL or
|
|
192
|
+
* knows what is behind it; the consumer supplies them. Compile never reads it.
|
|
193
|
+
*/
|
|
194
|
+
docs?: Record<string, string>;
|
|
164
195
|
/**
|
|
165
196
|
* The schema props are validated against, through its own `~standard.validate`. It must answer
|
|
166
197
|
* synchronously; compile refuses a schema that returns a promise.
|
|
@@ -352,6 +383,12 @@ interface FieldHint {
|
|
|
352
383
|
* path, fails registration.
|
|
353
384
|
*/
|
|
354
385
|
data?: FieldHintData;
|
|
386
|
+
/**
|
|
387
|
+
* Names the control an editing surface renders for the field — `"link"` for a string holding
|
|
388
|
+
* a destination. Core validates the path and reads nothing else: an unrecognised name falls
|
|
389
|
+
* back to the field's kind, so a hint never breaks an editor that predates it.
|
|
390
|
+
*/
|
|
391
|
+
control?: string;
|
|
355
392
|
}
|
|
356
393
|
/**
|
|
357
394
|
* The editing half of a catalog entry: how the studio should treat this block's fields.
|
|
@@ -393,6 +430,28 @@ interface CatalogEntry {
|
|
|
393
430
|
* read through `~standard.jsonSchema`.
|
|
394
431
|
*/
|
|
395
432
|
schema: unknown;
|
|
433
|
+
/**
|
|
434
|
+
* One line saying what the block is for, shown wherever an editing surface lists blocks. The
|
|
435
|
+
* serializable twin of `Block.description`, for a studio that fetches the catalog without the
|
|
436
|
+
* components. Compile never reads it.
|
|
437
|
+
*/
|
|
438
|
+
description?: string;
|
|
439
|
+
/**
|
|
440
|
+
* A single glyph shown beside the name wherever an editing surface lists blocks. The
|
|
441
|
+
* serializable twin of `Block.icon` — a string, never a component. Compile never reads it.
|
|
442
|
+
*/
|
|
443
|
+
icon?: string;
|
|
444
|
+
/**
|
|
445
|
+
* Opaque links keyed by destination, the serializable twin of `Block.docs`. An editing surface
|
|
446
|
+
* renders each as "Open in {Key}"; the consumer supplies the URLs. Compile never reads it.
|
|
447
|
+
*/
|
|
448
|
+
docs?: Record<string, string>;
|
|
449
|
+
/**
|
|
450
|
+
* The palette section the block files under, the serializable twin of `Block.category` — an
|
|
451
|
+
* opaque label the consumer chooses; a surface may derive a grouping for a block that omits
|
|
452
|
+
* it. Compile never reads it.
|
|
453
|
+
*/
|
|
454
|
+
category?: string;
|
|
396
455
|
/** Editing hints, keyed by schema path. Omit it and every field is treated as static. */
|
|
397
456
|
ui?: BlockUi;
|
|
398
457
|
/**
|
|
@@ -557,8 +616,9 @@ interface PointerMove {
|
|
|
557
616
|
* repeated `write` as a no-op and a repeated `publish` as an ordinary one so a retried publish
|
|
558
617
|
* succeeds, and by writing each pointer whole — two publishes racing for one route must leave one
|
|
559
618
|
* of them intact, never a blend. `@nubbin/store-fs` is the reference implementation, and
|
|
560
|
-
* `
|
|
561
|
-
*
|
|
619
|
+
* `runArtifactStoreContract` from `@nubbin/store-fs/testing` is the suite every implementation is
|
|
620
|
+
* expected to pass — call it with a factory for your store and the guarantees above are executed
|
|
621
|
+
* rather than read. It needs vitest, which the package declares as an optional peer.
|
|
562
622
|
*
|
|
563
623
|
* @example
|
|
564
624
|
* ```ts
|
|
@@ -1331,6 +1391,41 @@ declare function defineCatalog(entries: Record<string, CatalogEntry>): Catalog;
|
|
|
1331
1391
|
*/
|
|
1332
1392
|
declare function formatCompatibilityReport(report: CompatibilityReport): string;
|
|
1333
1393
|
|
|
1394
|
+
/**
|
|
1395
|
+
* The inline emphasis a span may carry. A mark outside this set is a validation issue at the
|
|
1396
|
+
* mark's own path, never a dropped value.
|
|
1397
|
+
*/
|
|
1398
|
+
type RichTextMark = "strong" | "em" | "code";
|
|
1399
|
+
/** The block kinds rich text is built from. A renderer maps each to an element it chooses. */
|
|
1400
|
+
type RichTextBlockKind = "paragraph" | "listItem";
|
|
1401
|
+
/** A run of text and what is true of it. Inert: nothing here is parsed or evaluated at render. */
|
|
1402
|
+
interface RichTextSpan {
|
|
1403
|
+
/** The literal text of the run. Never markup — a tag here renders as the characters typed. */
|
|
1404
|
+
text: string;
|
|
1405
|
+
/** Emphasis over the whole run. Absent and empty mean the same thing: plain text. */
|
|
1406
|
+
marks?: readonly RichTextMark[];
|
|
1407
|
+
/** Link target for the whole run. Absent leaves the run unlinked. */
|
|
1408
|
+
href?: string;
|
|
1409
|
+
}
|
|
1410
|
+
/** One block of a rich-text value: its kind, and the ordered spans it reads as. */
|
|
1411
|
+
interface RichTextBlock {
|
|
1412
|
+
/** What the block is, which decides how a renderer wraps its spans. */
|
|
1413
|
+
kind: RichTextBlockKind;
|
|
1414
|
+
/** The runs the block reads as, in order. An empty array is a block with no text. */
|
|
1415
|
+
spans: readonly RichTextSpan[];
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* An ordered array of blocks — the whole value a `richText()` field holds. An empty array is a
|
|
1419
|
+
* valid empty document.
|
|
1420
|
+
*/
|
|
1421
|
+
type RichText = readonly RichTextBlock[];
|
|
1422
|
+
|
|
1423
|
+
/** Narrows a value to a member of the closed block-kind set. */
|
|
1424
|
+
declare function isRichTextBlockKind(value: unknown): value is RichTextBlockKind;
|
|
1425
|
+
|
|
1426
|
+
/** Narrows a value to a member of the closed mark set. */
|
|
1427
|
+
declare function isRichTextMark(value: unknown): value is RichTextMark;
|
|
1428
|
+
|
|
1334
1429
|
/**
|
|
1335
1430
|
* Moves a node into a slot: the reference is taken out of whatever held it — a slot, or the
|
|
1336
1431
|
* document's roots — and placed in the target slot.
|
|
@@ -1496,35 +1591,6 @@ declare function refuse(code: NubbinIssue["code"], message: string, at?: string)
|
|
|
1496
1591
|
*/
|
|
1497
1592
|
declare function removeNode(version: DocumentVersion, nodeId: string): DocumentVersion;
|
|
1498
1593
|
|
|
1499
|
-
/**
|
|
1500
|
-
* The inline emphasis a span may carry. A mark outside this set is a validation issue at the
|
|
1501
|
-
* mark's own path, never a dropped value.
|
|
1502
|
-
*/
|
|
1503
|
-
type RichTextMark = "strong" | "em" | "code";
|
|
1504
|
-
/** The block kinds rich text is built from. A renderer maps each to an element it chooses. */
|
|
1505
|
-
type RichTextBlockKind = "paragraph" | "listItem";
|
|
1506
|
-
/** A run of text and what is true of it. Inert: nothing here is parsed or evaluated at render. */
|
|
1507
|
-
interface RichTextSpan {
|
|
1508
|
-
/** The literal text of the run. Never markup — a tag here renders as the characters typed. */
|
|
1509
|
-
text: string;
|
|
1510
|
-
/** Emphasis over the whole run. Absent and empty mean the same thing: plain text. */
|
|
1511
|
-
marks?: readonly RichTextMark[];
|
|
1512
|
-
/** Link target for the whole run. Absent leaves the run unlinked. */
|
|
1513
|
-
href?: string;
|
|
1514
|
-
}
|
|
1515
|
-
/** One block of a rich-text value: its kind, and the ordered spans it reads as. */
|
|
1516
|
-
interface RichTextBlock {
|
|
1517
|
-
/** What the block is, which decides how a renderer wraps its spans. */
|
|
1518
|
-
kind: RichTextBlockKind;
|
|
1519
|
-
/** The runs the block reads as, in order. An empty array is a block with no text. */
|
|
1520
|
-
spans: readonly RichTextSpan[];
|
|
1521
|
-
}
|
|
1522
|
-
/**
|
|
1523
|
-
* An ordered array of blocks — the whole value a `richText()` field holds. An empty array is a
|
|
1524
|
-
* valid empty document.
|
|
1525
|
-
*/
|
|
1526
|
-
type RichText = readonly RichTextBlock[];
|
|
1527
|
-
|
|
1528
1594
|
/**
|
|
1529
1595
|
* A schema `core` writes itself, such as the one `richText()` returns. It satisfies both
|
|
1530
1596
|
* `StandardSchemaV1` and `StandardJSONSchemaV1`, so a block, a catalog entry or an adapter takes
|
|
@@ -1607,6 +1673,11 @@ interface StandardDataSchema<Value> {
|
|
|
1607
1673
|
*/
|
|
1608
1674
|
declare function richText(): StandardDataSchema<RichText>;
|
|
1609
1675
|
|
|
1676
|
+
/** The closed mark set, in the order an editor would offer it. */
|
|
1677
|
+
declare const RICH_TEXT_MARKS: readonly ["strong", "em", "code"];
|
|
1678
|
+
/** The closed block-kind set. */
|
|
1679
|
+
declare const RICH_TEXT_BLOCK_KINDS: readonly ["paragraph", "listItem"];
|
|
1680
|
+
|
|
1610
1681
|
/**
|
|
1611
1682
|
* Writes a value at a dotted path in a plain object, copying every level the path passes
|
|
1612
1683
|
* through. `setNodeProp` edits props with it, and the renderer fills a resolved hole with it.
|
|
@@ -1667,4 +1738,4 @@ declare function setAtPath(target: Record<string, unknown>, path: string, value:
|
|
|
1667
1738
|
*/
|
|
1668
1739
|
declare function setNodeProp(version: DocumentVersion, nodeId: string, path: string, value: unknown): DocumentVersion;
|
|
1669
1740
|
|
|
1670
|
-
export { type Artifact, type ArtifactNode, type ArtifactStore, type Block, type BlockDrift, type BlockUi, type Catalog, type CatalogEntry, type CompatibilityReport, type CompileResult, type DocumentMeta, type DocumentVersion, type FieldHint, type FieldHintData, type FieldKind, type FieldNode, type Holes, type InferProps, type LiveRoute, type Manifest, type Node, NubbinError, type NubbinIssue, NubbinIssueCode, type PointerMove, type Registry, type RichText, type RichTextBlock, type RichTextBlockKind, type RichTextMark, type RichTextSpan, type RollbackCheck, type RouteIncompatibility, type RoutePointer, type SchemaAdapter, type SlotConstraint, type StandardDataSchema, type UnknownProps, addNode, checkCompatibility, checkRollback, compile, createRegistry, defineBlock, defineCatalog, formatCompatibilityReport, moveNode, parseMatchKind, refuse, removeNode, richText, setAtPath, setNodeProp, zodAdapter };
|
|
1741
|
+
export { type Artifact, type ArtifactNode, type ArtifactStore, type Block, type BlockDrift, type BlockUi, type Catalog, type CatalogEntry, type CompatibilityReport, type CompileResult, type DocumentMeta, type DocumentVersion, type FieldHint, type FieldHintData, type FieldKind, type FieldNode, type Holes, type InferProps, type LiveRoute, type Manifest, type Node, NubbinError, type NubbinIssue, NubbinIssueCode, type PointerMove, RICH_TEXT_BLOCK_KINDS, RICH_TEXT_MARKS, type Registry, type RichText, type RichTextBlock, type RichTextBlockKind, type RichTextMark, type RichTextSpan, type RollbackCheck, type RouteIncompatibility, type RoutePointer, type SchemaAdapter, type SlotConstraint, type StandardDataSchema, type UnknownProps, addNode, checkCompatibility, checkRollback, compile, createRegistry, defineBlock, defineCatalog, formatCompatibilityReport, isRichTextBlockKind, isRichTextMark, moveNode, parseMatchKind, refuse, removeNode, richText, setAtPath, setNodeProp, zodAdapter };
|
package/dist/index.js
CHANGED
|
@@ -194,6 +194,15 @@ function fieldNodeAt(path, node, optional) {
|
|
|
194
194
|
if (kind === "enum" && Array.isArray(node.enum)) {
|
|
195
195
|
return { path, kind, optional, members: node.enum.map(String) };
|
|
196
196
|
}
|
|
197
|
+
if (kind === "string" && typeof node.maxLength === "number") {
|
|
198
|
+
return { path, kind, optional, maxLength: node.maxLength };
|
|
199
|
+
}
|
|
200
|
+
if (kind === "array") {
|
|
201
|
+
const field = { path, kind, optional };
|
|
202
|
+
if (typeof node.minItems === "number") field.minItems = node.minItems;
|
|
203
|
+
if (typeof node.maxItems === "number") field.maxItems = node.maxItems;
|
|
204
|
+
return field;
|
|
205
|
+
}
|
|
197
206
|
return { path, kind, optional };
|
|
198
207
|
}
|
|
199
208
|
|
|
@@ -874,7 +883,7 @@ function validateStructure(version, registry) {
|
|
|
874
883
|
}
|
|
875
884
|
|
|
876
885
|
// src/version.constants.ts
|
|
877
|
-
var NUBBIN_VERSION = "0.
|
|
886
|
+
var NUBBIN_VERSION = "0.3.0";
|
|
878
887
|
|
|
879
888
|
// src/compile.ts
|
|
880
889
|
function compile(version, catalog, registry, route) {
|
|
@@ -1044,6 +1053,22 @@ function formatCompatibilityReport(report) {
|
|
|
1044
1053
|
return [summary, ...report.incompatible.map(formatRouteIncompatibility)].join("\n");
|
|
1045
1054
|
}
|
|
1046
1055
|
|
|
1056
|
+
// src/richText.constants.ts
|
|
1057
|
+
var RICH_TEXT_MARKS = ["strong", "em", "code"];
|
|
1058
|
+
var RICH_TEXT_BLOCK_KINDS = ["paragraph", "listItem"];
|
|
1059
|
+
var RICH_TEXT_SPAN_KEYS = ["text", "marks", "href"];
|
|
1060
|
+
var RICH_TEXT_BLOCK_KEYS = ["kind", "spans"];
|
|
1061
|
+
|
|
1062
|
+
// src/isRichTextBlockKind.ts
|
|
1063
|
+
function isRichTextBlockKind(value) {
|
|
1064
|
+
return RICH_TEXT_BLOCK_KINDS.some((kind) => kind === value);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// src/isRichTextMark.ts
|
|
1068
|
+
function isRichTextMark(value) {
|
|
1069
|
+
return RICH_TEXT_MARKS.some((mark) => mark === value);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1047
1072
|
// src/withoutSlotChildren.ts
|
|
1048
1073
|
function withoutSlotChildren(node, removed) {
|
|
1049
1074
|
const entries = Object.entries(node.slots ?? {});
|
|
@@ -1117,17 +1142,6 @@ function defineStandardSchema(issuesOf, jsonSchemaOf) {
|
|
|
1117
1142
|
};
|
|
1118
1143
|
}
|
|
1119
1144
|
|
|
1120
|
-
// src/richText.constants.ts
|
|
1121
|
-
var RICH_TEXT_MARKS = ["strong", "em", "code"];
|
|
1122
|
-
var RICH_TEXT_BLOCK_KINDS = ["paragraph", "listItem"];
|
|
1123
|
-
var RICH_TEXT_SPAN_KEYS = ["text", "marks", "href"];
|
|
1124
|
-
var RICH_TEXT_BLOCK_KEYS = ["kind", "spans"];
|
|
1125
|
-
|
|
1126
|
-
// src/isRichTextBlockKind.ts
|
|
1127
|
-
function isRichTextBlockKind(value) {
|
|
1128
|
-
return RICH_TEXT_BLOCK_KINDS.some((kind) => kind === value);
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
1145
|
// src/nestedSchemaIssues.ts
|
|
1132
1146
|
function nestedSchemaIssues(schema, value, prefix) {
|
|
1133
1147
|
const result = standardValidate(schema, value);
|
|
@@ -1138,11 +1152,6 @@ function nestedSchemaIssues(schema, value, prefix) {
|
|
|
1138
1152
|
}));
|
|
1139
1153
|
}
|
|
1140
1154
|
|
|
1141
|
-
// src/isRichTextMark.ts
|
|
1142
|
-
function isRichTextMark(value) {
|
|
1143
|
-
return RICH_TEXT_MARKS.some((mark) => mark === value);
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
1155
|
// src/richTextMarkIssues.ts
|
|
1147
1156
|
function richTextMarkIssues(marks) {
|
|
1148
1157
|
if (marks === void 0) return [];
|
|
@@ -1273,6 +1282,8 @@ function setNodeProp(version, nodeId, path, value) {
|
|
|
1273
1282
|
export {
|
|
1274
1283
|
NubbinError,
|
|
1275
1284
|
NubbinIssueCode,
|
|
1285
|
+
RICH_TEXT_BLOCK_KINDS,
|
|
1286
|
+
RICH_TEXT_MARKS,
|
|
1276
1287
|
addNode,
|
|
1277
1288
|
checkCompatibility,
|
|
1278
1289
|
checkRollback,
|
|
@@ -1281,6 +1292,8 @@ export {
|
|
|
1281
1292
|
defineBlock,
|
|
1282
1293
|
defineCatalog,
|
|
1283
1294
|
formatCompatibilityReport,
|
|
1295
|
+
isRichTextBlockKind,
|
|
1296
|
+
isRichTextMark,
|
|
1284
1297
|
moveNode,
|
|
1285
1298
|
parseMatchKind,
|
|
1286
1299
|
refuse,
|
package/package.json
CHANGED