@weatherboard/cms 0.1.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/README.md +122 -0
- package/dist/contracts/query.d.cts +1 -0
- package/dist/contracts/query.d.mts +1 -0
- package/dist/contracts/query.d.ts +1 -0
- package/dist/contracts/text.d.cts +26 -1
- package/dist/contracts/text.d.mts +26 -1
- package/dist/contracts/text.d.ts +26 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +3 -3
- package/dist/next.cjs +1 -1
- package/dist/next.cjs.map +3 -3
- package/dist/next.mjs +1 -1
- package/dist/next.mjs.map +3 -3
- package/dist/portable/sections.d.cts +136 -0
- package/dist/portable/sections.d.mts +136 -0
- package/dist/portable/sections.d.ts +136 -0
- package/dist/portable/site-content.d.cts +13 -0
- package/dist/portable/site-content.d.mts +13 -0
- package/dist/portable/site-content.d.ts +13 -0
- package/dist/runtime/reader.d.cts +3 -1
- package/dist/runtime/reader.d.mts +3 -1
- package/dist/runtime/reader.d.ts +3 -1
- package/dist/sanity.cjs +1 -1
- package/dist/sanity.cjs.map +2 -2
- package/dist/sanity.mjs +1 -1
- package/dist/sanity.mjs.map +2 -2
- package/dist/server.cjs +1 -1
- package/dist/server.cjs.map +3 -3
- package/dist/server.mjs +1 -1
- package/dist/server.mjs.map +3 -3
- package/dist/site-content.cjs +3 -3
- package/dist/site-content.cjs.map +4 -4
- package/dist/site-content.d.cts +4 -0
- package/dist/site-content.d.mts +4 -0
- package/dist/site-content.d.ts +4 -0
- package/dist/site-content.mjs +3 -3
- package/dist/site-content.mjs.map +4 -4
- package/package.json +34 -5
package/README.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# @weatherboard/cms
|
|
2
|
+
|
|
3
|
+
Published content contracts and server readers. The pure root and
|
|
4
|
+
`@weatherboard/cms/site-content` expose `siteHeroQuery`, `parseSiteHero` and the
|
|
5
|
+
hero types without a provider SDK or environment access. Server reads use
|
|
6
|
+
`@weatherboard/cms/server` or `/next`, with the `/sanity` adapter; `/webhook`
|
|
7
|
+
provides portable signature verification. `/testing` and `/guard` are tooling.
|
|
8
|
+
|
|
9
|
+
## Site hero
|
|
10
|
+
|
|
11
|
+
The singleton `siteHero` keeps its existing heading (1–80 characters, single
|
|
12
|
+
line, no trailing full stop) and intro (1–320 characters). Both trim whitespace,
|
|
13
|
+
count Unicode code points and refuse an em dash.
|
|
14
|
+
|
|
15
|
+
The additive fields in 0.2.0 are:
|
|
16
|
+
|
|
17
|
+
- `layout`: `"columns"` (Side by side) or `"rows"` (Stacked), exported as
|
|
18
|
+
`SITE_HERO_LAYOUTS`. Missing or unknown CMS values resolve to `"columns"`,
|
|
19
|
+
including when the local fallback selects rows.
|
|
20
|
+
- `taglines`: `{ key: string, text: string }[]`. Keys are site-defined lowercase
|
|
21
|
+
identifiers, 1–32 characters, starting with a letter; remaining characters
|
|
22
|
+
may be letters, digits, short dashes or underscores. Duplicate keys refuse
|
|
23
|
+
the whole field. Text uses the heading copy rules and is limited to
|
|
24
|
+
`SITE_HERO_TAGLINE_MAX_LENGTH` (provisionally 36 Unicode code points).
|
|
25
|
+
An empty array deliberately clears taglines; the site can continue using
|
|
26
|
+
heading. A missing or invalid array uses the reviewed local array, or `[]`
|
|
27
|
+
for a legacy fallback.
|
|
28
|
+
|
|
29
|
+
`SiteHero` accepts existing heading/intro-only fallbacks. `parseSiteHero` returns
|
|
30
|
+
normalized `ParsedSiteHero` data with both new fields present. Invalid CMS fields
|
|
31
|
+
fall back individually, preserving valid siblings. Invalid local fallbacks throw
|
|
32
|
+
before network I/O. A missing whole document uses the normalized local hero.
|
|
33
|
+
|
|
34
|
+
A defaulted CMS layout records `SITE_HERO_LAYOUT_WARNING`, whose value is
|
|
35
|
+
`siteHero.layout.defaulted`, in the resolution/read result's `warnings`, with
|
|
36
|
+
`layout` in `fallbackFields`. The server reader includes it in its existing safe
|
|
37
|
+
`cms.partial-fallback` diagnostic (or `cms.fallback` for a whole fallback).
|
|
38
|
+
Supply `onDiagnostic` to log diagnostics; without it the reader logs safe JSON
|
|
39
|
+
through `console.warn`. Diagnostics contain paths and warning names, never copy.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { parseSiteHero } from '@weatherboard/cms/site-content';
|
|
43
|
+
|
|
44
|
+
const fallback = { heading: 'Fresh air at home', intro: 'Comfort through the year' };
|
|
45
|
+
const resolved = parseSiteHero({
|
|
46
|
+
heading: 'Fresh air at home',
|
|
47
|
+
intro: 'Comfort through the year',
|
|
48
|
+
layout: 'rows',
|
|
49
|
+
taglines: [{ key: 'spring', text: 'Welcome the fresh air' }],
|
|
50
|
+
}, fallback);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Page sections (0.3.0)
|
|
54
|
+
|
|
55
|
+
`parseContentPage` (and `contentPageQuery`, `contentPagesQuery`) read the
|
|
56
|
+
optional `page.sections[]` that `@weatherboard/sanity-schema-base` declares
|
|
57
|
+
(A-1889). Each entry maps to a `kind`, listed in `READER_SECTION_KINDS`:
|
|
58
|
+
|
|
59
|
+
| Sanity `_type` | `kind` | composition | default layout |
|
|
60
|
+
| --- | --- | --- | --- |
|
|
61
|
+
| `featureStoriesBlock`, `surfaceCardBlock`, `accentBandBlock`, `locationsBlock` | `feature_stories`, `cta`, `accent_band`, `locations` | none | none |
|
|
62
|
+
| `textMediaBlock` | `text_media` | Split | `media-end` |
|
|
63
|
+
| `faqBlock` (items `faqItem`) | `faq` | HeadingList | `beside` |
|
|
64
|
+
| `galleryBlock` | `gallery` | StaggerRow | `staggered` |
|
|
65
|
+
| `contactBlock` | `contact` | Split | `media-end` |
|
|
66
|
+
|
|
67
|
+
The four home kinds read exactly as they do on the home page. The new kinds
|
|
68
|
+
return every key, `null` where there is nothing, with images as
|
|
69
|
+
`SectionImageInput` (`asset` id, `alt`, `caption`, `hotspot` `{ x, y }`).
|
|
70
|
+
|
|
71
|
+
The layout values are the A-1876 variant names, exported as `SPLIT_LAYOUTS`
|
|
72
|
+
(`media-end`, `media-start`, `media-below`), `HEADING_LIST_LAYOUTS` (`beside`,
|
|
73
|
+
`stacked`) and `STAGGER_ROW_LAYOUTS` (`staggered`, `aligned`), with the defaults
|
|
74
|
+
in `SECTION_LAYOUT_DEFAULTS`. A later contract test can compare them with the UI
|
|
75
|
+
package's lists.
|
|
76
|
+
|
|
77
|
+
`PageContent.sections` and `PageContent.warnings` are present only when the
|
|
78
|
+
stored page has a `sections` list, so a page without one reads exactly as it did
|
|
79
|
+
in 0.2.0. Each warning is `{ code, where }`, a code from `SECTION_WARNINGS` and
|
|
80
|
+
the path in the stored document, never copy:
|
|
81
|
+
|
|
82
|
+
- `section.layout.defaulted`: missing or unknown `layout`; the composition
|
|
83
|
+
default renders. It never throws and never yields an empty section.
|
|
84
|
+
- `section.type.unknown`: a section `_type` this reader does not know is
|
|
85
|
+
skipped; the rest of the page reads.
|
|
86
|
+
- `section.image.missing-alt`: an image without alt text is dropped, never
|
|
87
|
+
returned without it. `text_media.image` is then `null`; a gallery keeps its
|
|
88
|
+
other photos.
|
|
89
|
+
- `section.image.missing-asset`: an image with no uploaded asset is dropped.
|
|
90
|
+
- `section.empty.skipped`: a gallery whose every photo was dropped, or a contact
|
|
91
|
+
section with email, phone, text and button all off, is skipped.
|
|
92
|
+
|
|
93
|
+
Everything else stays a named refusal, as for the rest of the reader: missing
|
|
94
|
+
required copy, a FAQ with no questions, a gallery outside 2 to 4 photos, a
|
|
95
|
+
repeated jump link or a button jumping to a section that is not on the page
|
|
96
|
+
throws `MalformedContentError` naming the path. Page fallbacks that carry
|
|
97
|
+
`sections` are validated against the same kinds.
|
|
98
|
+
|
|
99
|
+
The warnings travel in the page data, not in the server reader's
|
|
100
|
+
`CmsResolution.warnings`, which still names only the hero warning.
|
|
101
|
+
|
|
102
|
+
0.3.0 is an additive minor under the pilot semver policy: a new reader kind.
|
|
103
|
+
|
|
104
|
+
## Schema and release delivery
|
|
105
|
+
|
|
106
|
+
`@weatherboard/sanity-schema-base` derives the hero schema from these rules:
|
|
107
|
+
Layout is a radio with initial value columns; taglines use the same validator
|
|
108
|
+
for item fields and duplicate keys. Schema validation is advisory; Content Lake
|
|
109
|
+
API writes still need boundary validation.
|
|
110
|
+
|
|
111
|
+
The schema source and its committed TypeGen outputs are local artifacts. Updating
|
|
112
|
+
this package does not mutate or deploy a dataset schema. Existing operator/admin
|
|
113
|
+
schema consumers must take the updated shared schema and rebuild their schema
|
|
114
|
+
bundle; generated client schemas require their existing reviewed upgrade path.
|
|
115
|
+
The dashboard's later editor slice must add the picker/tagline controls and use
|
|
116
|
+
these validators before publishing. New field values require a separately
|
|
117
|
+
authorized content write; existing documents remain readable with defaults.
|
|
118
|
+
|
|
119
|
+
0.2.0 is an additive minor under the pilot semver policy. CI publishes CMS after
|
|
120
|
+
merge through the registered release workflow; clients then need an exact package
|
|
121
|
+
bump and deploy. The CI publish and trusted-publisher proof are release evidence
|
|
122
|
+
that this source change alone cannot supply.
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { type CmsQuery } from "./query.cjs";
|
|
1
|
+
import { type CmsQuery, type CmsResolution } from "./query.cjs";
|
|
2
|
+
export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
|
|
3
|
+
export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
|
|
4
|
+
export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
|
|
5
|
+
export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
|
|
6
|
+
export type SiteHeroTagline = {
|
|
7
|
+
readonly key: string;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
};
|
|
10
|
+
/** Optional additions preserve existing heading/intro-only consumer fallbacks. */
|
|
2
11
|
export type SiteHero = {
|
|
3
12
|
readonly heading: string;
|
|
4
13
|
readonly intro: string;
|
|
14
|
+
readonly layout?: SiteHeroLayout;
|
|
15
|
+
readonly taglines?: readonly SiteHeroTagline[];
|
|
16
|
+
};
|
|
17
|
+
export type ParsedSiteHero = SiteHero & {
|
|
18
|
+
readonly layout: SiteHeroLayout;
|
|
19
|
+
readonly taglines: readonly SiteHeroTagline[];
|
|
5
20
|
};
|
|
6
21
|
export type TextFieldDefinition = {
|
|
7
22
|
readonly name: string;
|
|
@@ -37,4 +52,14 @@ export type TextValidation = {
|
|
|
37
52
|
export declare const CMS_CONTRACT_VERSION = 1;
|
|
38
53
|
export declare const SITE_HERO: TextDocumentDefinition;
|
|
39
54
|
export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
|
|
55
|
+
/** Shared with the schema adapter; no provider metadata is returned. */
|
|
56
|
+
export declare function validateSiteHeroTaglines(raw: unknown): {
|
|
57
|
+
readonly ok: true;
|
|
58
|
+
readonly value: readonly SiteHeroTagline[];
|
|
59
|
+
} | {
|
|
60
|
+
readonly ok: false;
|
|
61
|
+
readonly error: string;
|
|
62
|
+
};
|
|
63
|
+
/** Strict per-field resolution: an invalid list never partially changes keyed copy. */
|
|
64
|
+
export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
|
|
40
65
|
export declare function siteHeroQuery(): CmsQuery<SiteHero>;
|
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { type CmsQuery } from "./query.mjs";
|
|
1
|
+
import { type CmsQuery, type CmsResolution } from "./query.mjs";
|
|
2
|
+
export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
|
|
3
|
+
export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
|
|
4
|
+
export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
|
|
5
|
+
export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
|
|
6
|
+
export type SiteHeroTagline = {
|
|
7
|
+
readonly key: string;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
};
|
|
10
|
+
/** Optional additions preserve existing heading/intro-only consumer fallbacks. */
|
|
2
11
|
export type SiteHero = {
|
|
3
12
|
readonly heading: string;
|
|
4
13
|
readonly intro: string;
|
|
14
|
+
readonly layout?: SiteHeroLayout;
|
|
15
|
+
readonly taglines?: readonly SiteHeroTagline[];
|
|
16
|
+
};
|
|
17
|
+
export type ParsedSiteHero = SiteHero & {
|
|
18
|
+
readonly layout: SiteHeroLayout;
|
|
19
|
+
readonly taglines: readonly SiteHeroTagline[];
|
|
5
20
|
};
|
|
6
21
|
export type TextFieldDefinition = {
|
|
7
22
|
readonly name: string;
|
|
@@ -37,4 +52,14 @@ export type TextValidation = {
|
|
|
37
52
|
export declare const CMS_CONTRACT_VERSION = 1;
|
|
38
53
|
export declare const SITE_HERO: TextDocumentDefinition;
|
|
39
54
|
export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
|
|
55
|
+
/** Shared with the schema adapter; no provider metadata is returned. */
|
|
56
|
+
export declare function validateSiteHeroTaglines(raw: unknown): {
|
|
57
|
+
readonly ok: true;
|
|
58
|
+
readonly value: readonly SiteHeroTagline[];
|
|
59
|
+
} | {
|
|
60
|
+
readonly ok: false;
|
|
61
|
+
readonly error: string;
|
|
62
|
+
};
|
|
63
|
+
/** Strict per-field resolution: an invalid list never partially changes keyed copy. */
|
|
64
|
+
export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
|
|
40
65
|
export declare function siteHeroQuery(): CmsQuery<SiteHero>;
|
package/dist/contracts/text.d.ts
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
|
-
import { type CmsQuery } from "./query.js";
|
|
1
|
+
import { type CmsQuery, type CmsResolution } from "./query.js";
|
|
2
|
+
export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
|
|
3
|
+
export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
|
|
4
|
+
export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
|
|
5
|
+
export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
|
|
6
|
+
export type SiteHeroTagline = {
|
|
7
|
+
readonly key: string;
|
|
8
|
+
readonly text: string;
|
|
9
|
+
};
|
|
10
|
+
/** Optional additions preserve existing heading/intro-only consumer fallbacks. */
|
|
2
11
|
export type SiteHero = {
|
|
3
12
|
readonly heading: string;
|
|
4
13
|
readonly intro: string;
|
|
14
|
+
readonly layout?: SiteHeroLayout;
|
|
15
|
+
readonly taglines?: readonly SiteHeroTagline[];
|
|
16
|
+
};
|
|
17
|
+
export type ParsedSiteHero = SiteHero & {
|
|
18
|
+
readonly layout: SiteHeroLayout;
|
|
19
|
+
readonly taglines: readonly SiteHeroTagline[];
|
|
5
20
|
};
|
|
6
21
|
export type TextFieldDefinition = {
|
|
7
22
|
readonly name: string;
|
|
@@ -37,4 +52,14 @@ export type TextValidation = {
|
|
|
37
52
|
export declare const CMS_CONTRACT_VERSION = 1;
|
|
38
53
|
export declare const SITE_HERO: TextDocumentDefinition;
|
|
39
54
|
export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
|
|
55
|
+
/** Shared with the schema adapter; no provider metadata is returned. */
|
|
56
|
+
export declare function validateSiteHeroTaglines(raw: unknown): {
|
|
57
|
+
readonly ok: true;
|
|
58
|
+
readonly value: readonly SiteHeroTagline[];
|
|
59
|
+
} | {
|
|
60
|
+
readonly ok: false;
|
|
61
|
+
readonly error: string;
|
|
62
|
+
};
|
|
63
|
+
/** Strict per-field resolution: an invalid list never partially changes keyed copy. */
|
|
64
|
+
export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
|
|
40
65
|
export declare function siteHeroQuery(): CmsQuery<SiteHero>;
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var f=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var o in t)f(e,o,{get:t[o],enumerable:!0})},A=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of R(t))!v.call(e,n)&&n!==o&&f(e,n,{get:()=>t[n],enumerable:!(r=C(t,n))||r.enumerable});return e};var I=e=>A(f({},"__esModule",{value:!0}),e);var z={};_(z,{CMS_CONTRACT_VERSION:()=>k,SITE_HERO:()=>l,SITE_HERO_LAYOUTS:()=>m,SITE_HERO_LAYOUT_WARNING:()=>h,SITE_HERO_TAGLINE_MAX_LENGTH:()=>T,cmsTags:()=>H,defineCmsQuery:()=>c,parseSiteHero:()=>S,siteHeroQuery:()=>E,validateSiteHeroTaglines:()=>p,validateTextDocument:()=>y});module.exports=I(z);var L=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,j=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,D=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function x(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let t=[...e.types];for(let r of t)if(typeof r!="string"||!L.test(r))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let r of o??[])if(typeof r!="string"||!j.test(r)||/^(drafts|versions)\./.test(r))throw new TypeError("Invalid CMS document ID");if(new Set(t).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(t),...o===void 0?{}:{ids:Object.freeze(o)}})}function c(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let t=e.params;if(!t||typeof t!="object"||Object.getPrototypeOf(t)!==Object.prototype&&Object.getPrototypeOf(t)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let r of Reflect.ownKeys(t)){let n=Object.getOwnPropertyDescriptor(t,r);if(typeof r!="string"||!n||!Object.hasOwn(n,"value")||!n.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=n.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,r,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:x(e.dependencies),resolve:e.resolve})}function H(e,t){if(typeof e!="string"||e.length>77||!D.test(e))throw new TypeError("Invalid CMS scope");let o=x(t),r=[...[...new Set(o.types)].sort().map(n=>`cms:${e}:type:${n}`),...[...new Set(o.ids??[])].sort().map(n=>`cms:${e}:id:${n}`)];return Object.freeze(r)}var m=["columns","rows"],T=36,h="siteHero.layout.defaulted",k=1,l={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function $(e,t){let{article:o,word:r}=e.noun;if(t.length===0)return e.required?`Enter ${o} ${r}.`:null;let n=[...t].length;return n<e.minLength?`Make the ${r} at least ${String(e.minLength)} characters. It is ${String(n)} now.`:n>e.maxLength?`Keep the ${r} to ${String(e.maxLength)} characters or fewer. It is ${String(n)} now.`:t.includes("\u2014")?`The ${r} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(t)?`The ${r} must be a single line.`:e.noTrailingFullStop===!0&&t.endsWith(".")?`${r.charAt(0).toUpperCase()}${r.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function y(e,t){let o={},r={};for(let n of e.fields){let i=Object.hasOwn(t,n.name)?t[n.name]:void 0,a=typeof i=="string"?i.trim():"",s=$(n,a);Object.defineProperty(s===null?o:r,n.name,{value:s??a,enumerable:!0})}return Object.keys(r).length>0?{ok:!1,errors:r}:{ok:!0,value:o}}function p(e){if(!Array.isArray(e))return{ok:!1,error:"Enter a list of taglines."};let t=l.fields[0];if(!t)throw new TypeError("Missing siteHero heading definition");let o={...t,name:"text",noun:{article:"a",word:"tagline"},maxLength:T},r=[],n=new Set;for(let i of e){if(!i||typeof i!="object"||Array.isArray(i))return{ok:!1,error:"Enter a key and text for each tagline."};let a=i,s=Object.hasOwn(a,"key")?a.key:void 0;if(typeof s!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(s))return{ok:!1,error:"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter."};if(n.has(s))return{ok:!1,error:"Use each tagline key only once."};let d=y({...l,fields:[o]},a);if(!d.ok)return{ok:!1,error:d.errors.text??"Invalid tagline."};n.add(s),r.push({key:s,text:d.value.text??""})}return{ok:!0,value:r}}function O(e){return m.some(t=>e===t)}function S(e,t){let o=y(l,t),r=p(t.taglines??[]);if(!o.ok||!r.ok||t.layout!==void 0&&!O(t.layout))throw new TypeError("Invalid siteHero fallback");let n={heading:o.value.heading??"",intro:o.value.intro??"",layout:t.layout??"columns",taglines:r.value};if(e===null||typeof e!="object"||Array.isArray(e))return{data:n,fallbackFields:["$"]};let i=e,a=y(l,i),s=a.ok?[]:Object.keys(a.errors);for(let u of l.fields)if(!s.includes(u.name)){let b=a.ok?a.value[u.name]:i[u.name];typeof b=="string"&&(u.name==="heading"||u.name==="intro")&&(n[u.name]=b.trim())}let d=Object.hasOwn(i,"layout")?i.layout:void 0,g=[];O(d)?n.layout=d:(n.layout="columns",s.push("layout"),g.push(h));let w=p(Object.hasOwn(i,"taglines")?i.taglines:void 0);return w.ok?n.taglines=w.value:s.push("taglines"),{data:n,fallbackFields:s.length===l.fields.length+2?["$"]:s,...g.length>0?{warnings:g}:{}}}function E(){return c({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro,layout,taglines}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:S})}0&&(module.exports={CMS_CONTRACT_VERSION,SITE_HERO,SITE_HERO_LAYOUTS,SITE_HERO_LAYOUT_WARNING,SITE_HERO_TAGLINE_MAX_LENGTH,cmsTags,defineCmsQuery,parseSiteHero,siteHeroQuery,validateSiteHeroTaglines,validateTextDocument});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/contracts/query.ts", "../src/contracts/text.ts"],
|
|
4
|
-
"sourcesContent": ["export { defineCmsQuery, cmsTags } from \"./contracts/query.js\";\nexport type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from \"./contracts/query.js\";\nexport { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from \"./contracts/text.js\";\nexport type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from \"./contracts/text.js\";\n", "/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery } from \"./query.js\";\n\nexport type SiteHero = { readonly heading: string; readonly intro: string };\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: (raw, fallback) => {\n const local = validateTextDocument(SITE_HERO, fallback);\n if (!local.ok) throw new TypeError(\"Invalid siteHero fallback\");\n const data = { heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\" };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const result = validateTextDocument(SITE_HERO, raw as Readonly<Record<string, unknown>>);\n if (result.ok) return { data: { heading: result.value.heading ?? \"\", intro: result.value.intro ?? \"\" }, fallbackFields: [] };\n const fallbackFields = Object.keys(result.errors);\n for (const field of SITE_HERO.fields) {\n if (!Object.hasOwn(result.errors, field.name)) {\n const submitted = Object.hasOwn(raw, field.name) ? (raw as Record<string, unknown>)[field.name] : undefined;\n if (typeof submitted === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = submitted.trim();\n }\n }\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length ? [\"$\"] : fallbackFields };\n },\n });\n}\n"],
|
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,0BAAAE,EAAA,cAAAC,EAAA,YAAAC,EAAA,mBAAAC,EAAA,kBAAAC,EAAA,yBAAAC,IAAA,eAAAC,
|
|
6
|
-
"names": ["index_exports", "__export", "CMS_CONTRACT_VERSION", "SITE_HERO", "cmsTags", "defineCmsQuery", "siteHeroQuery", "validateTextDocument", "__toCommonJS", "TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "
|
|
4
|
+
"sourcesContent": ["export { defineCmsQuery, cmsTags } from \"./contracts/query.js\";\nexport type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from \"./contracts/query.js\";\nexport { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from \"./contracts/text.js\";\nexport type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from \"./contracts/text.js\";\n", "/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n readonly warnings?: readonly \"siteHero.layout.defaulted\"[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery, type CmsResolution } from \"./query.js\";\n\nexport const SITE_HERO_LAYOUTS = [\"columns\", \"rows\"] as const;\nexport const SITE_HERO_TAGLINE_MAX_LENGTH = 36;\nexport const SITE_HERO_LAYOUT_WARNING = \"siteHero.layout.defaulted\" as const;\nexport type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];\nexport type SiteHeroTagline = { readonly key: string; readonly text: string };\n/** Optional additions preserve existing heading/intro-only consumer fallbacks. */\nexport type SiteHero = {\n readonly heading: string;\n readonly intro: string;\n readonly layout?: SiteHeroLayout;\n readonly taglines?: readonly SiteHeroTagline[];\n};\nexport type ParsedSiteHero = SiteHero & {\n readonly layout: SiteHeroLayout;\n readonly taglines: readonly SiteHeroTagline[];\n};\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\n/** Shared with the schema adapter; no provider metadata is returned. */\nexport function validateSiteHeroTaglines(raw: unknown):\n | { readonly ok: true; readonly value: readonly SiteHeroTagline[] }\n | { readonly ok: false; readonly error: string } {\n if (!Array.isArray(raw)) return { ok: false, error: \"Enter a list of taglines.\" };\n const heading = SITE_HERO.fields[0];\n if (!heading) throw new TypeError(\"Missing siteHero heading definition\");\n const field = { ...heading, name: \"text\", noun: { article: \"a\", word: \"tagline\" } as const,\n maxLength: SITE_HERO_TAGLINE_MAX_LENGTH };\n const value: SiteHeroTagline[] = [];\n const keys = new Set<string>();\n for (const item of raw as unknown[]) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { ok: false, error: \"Enter a key and text for each tagline.\" };\n const record = item as Record<string, unknown>;\n const key = Object.hasOwn(record, \"key\") ? record.key : undefined;\n if (typeof key !== \"string\" || !/^[a-z][a-z0-9_-]{0,31}$/.test(key)) {\n return { ok: false, error: \"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter.\" };\n }\n if (keys.has(key)) return { ok: false, error: \"Use each tagline key only once.\" };\n const text = validateTextDocument({ ...SITE_HERO, fields: [field] }, record);\n if (!text.ok) return { ok: false, error: text.errors.text ?? \"Invalid tagline.\" };\n keys.add(key);\n value.push({ key, text: text.value.text ?? \"\" });\n }\n return { ok: true, value };\n}\n\nfunction isLayout(value: unknown): value is SiteHeroLayout {\n return SITE_HERO_LAYOUTS.some((layout) => value === layout);\n}\n\n/** Strict per-field resolution: an invalid list never partially changes keyed copy. */\nexport function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero> {\n const local = validateTextDocument(SITE_HERO, fallback);\n const localTaglines = validateSiteHeroTaglines(fallback.taglines ?? []);\n if (!local.ok || !localTaglines.ok || (fallback.layout !== undefined && !isLayout(fallback.layout))) {\n throw new TypeError(\"Invalid siteHero fallback\");\n }\n const data: { heading: string; intro: string; layout: SiteHeroLayout; taglines: readonly SiteHeroTagline[] } = {\n heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\",\n layout: fallback.layout ?? \"columns\", taglines: localTaglines.value,\n };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const record = raw as Readonly<Record<string, unknown>>;\n const text = validateTextDocument(SITE_HERO, record);\n const fallbackFields: string[] = text.ok ? [] : Object.keys(text.errors);\n for (const field of SITE_HERO.fields) {\n if (!fallbackFields.includes(field.name)) {\n const value = text.ok ? text.value[field.name] : record[field.name];\n if (typeof value === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = value.trim();\n }\n }\n const layout = Object.hasOwn(record, \"layout\") ? record.layout : undefined;\n const warnings: (typeof SITE_HERO_LAYOUT_WARNING)[] = [];\n if (isLayout(layout)) data.layout = layout;\n else {\n data.layout = \"columns\";\n fallbackFields.push(\"layout\");\n warnings.push(SITE_HERO_LAYOUT_WARNING);\n }\n const taglines = validateSiteHeroTaglines(Object.hasOwn(record, \"taglines\") ? record.taglines : undefined);\n if (taglines.ok) data.taglines = taglines.value;\n else fallbackFields.push(\"taglines\");\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length + 2 ? [\"$\"] : fallbackFields,\n ...(warnings.length > 0 ? { warnings } : {}) };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery<SiteHero>({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro,layout,taglines}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: parseSiteHero,\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["index_exports", "__export", "CMS_CONTRACT_VERSION", "SITE_HERO", "SITE_HERO_LAYOUTS", "SITE_HERO_LAYOUT_WARNING", "SITE_HERO_TAGLINE_MAX_LENGTH", "cmsTags", "defineCmsQuery", "parseSiteHero", "siteHeroQuery", "validateSiteHeroTaglines", "validateTextDocument", "__toCommonJS", "TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "SITE_HERO_LAYOUTS", "SITE_HERO_TAGLINE_MAX_LENGTH", "SITE_HERO_LAYOUT_WARNING", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "validateSiteHeroTaglines", "heading", "keys", "item", "record", "key", "isLayout", "layout", "parseSiteHero", "fallback", "local", "localTaglines", "data", "fallbackFields", "warnings", "taglines", "siteHeroQuery", "defineCmsQuery"]
|
|
7
7
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { defineCmsQuery, cmsTags } from "./contracts/query.cjs";
|
|
2
2
|
export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.cjs";
|
|
3
|
-
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.cjs";
|
|
4
|
-
export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.cjs";
|
|
3
|
+
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.cjs";
|
|
4
|
+
export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.cjs";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { defineCmsQuery, cmsTags } from "./contracts/query.mjs";
|
|
2
2
|
export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.mjs";
|
|
3
|
-
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.mjs";
|
|
4
|
-
export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.mjs";
|
|
3
|
+
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.mjs";
|
|
4
|
+
export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.mjs";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { defineCmsQuery, cmsTags } from "./contracts/query.js";
|
|
2
2
|
export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.js";
|
|
3
|
-
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.js";
|
|
4
|
-
export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.js";
|
|
3
|
+
export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.js";
|
|
4
|
+
export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.js";
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
1
|
+
var H=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,O=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,k=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function T(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let t=[...e.types];for(let n of t)if(typeof n!="string"||!H.test(n))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let n of o??[])if(typeof n!="string"||!O.test(n)||/^(drafts|versions)\./.test(n))throw new TypeError("Invalid CMS document ID");if(new Set(t).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(t),...o===void 0?{}:{ids:Object.freeze(o)}})}function p(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let t=e.params;if(!t||typeof t!="object"||Object.getPrototypeOf(t)!==Object.prototype&&Object.getPrototypeOf(t)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let n of Reflect.ownKeys(t)){let r=Object.getOwnPropertyDescriptor(t,n);if(typeof n!="string"||!r||!Object.hasOwn(r,"value")||!r.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=r.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,n,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:T(e.dependencies),resolve:e.resolve})}function E(e,t){if(typeof e!="string"||e.length>77||!k.test(e))throw new TypeError("Invalid CMS scope");let o=T(t),n=[...[...new Set(o.types)].sort().map(r=>`cms:${e}:type:${r}`),...[...new Set(o.ids??[])].sort().map(r=>`cms:${e}:id:${r}`)];return Object.freeze(n)}var S=["columns","rows"],w=36,b="siteHero.layout.defaulted",C=1,l={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function R(e,t){let{article:o,word:n}=e.noun;if(t.length===0)return e.required?`Enter ${o} ${n}.`:null;let r=[...t].length;return r<e.minLength?`Make the ${n} at least ${String(e.minLength)} characters. It is ${String(r)} now.`:r>e.maxLength?`Keep the ${n} to ${String(e.maxLength)} characters or fewer. It is ${String(r)} now.`:t.includes("\u2014")?`The ${n} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(t)?`The ${n} must be a single line.`:e.noTrailingFullStop===!0&&t.endsWith(".")?`${n.charAt(0).toUpperCase()}${n.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function y(e,t){let o={},n={};for(let r of e.fields){let i=Object.hasOwn(t,r.name)?t[r.name]:void 0,a=typeof i=="string"?i.trim():"",s=R(r,a);Object.defineProperty(s===null?o:n,r.name,{value:s??a,enumerable:!0})}return Object.keys(n).length>0?{ok:!1,errors:n}:{ok:!0,value:o}}function g(e){if(!Array.isArray(e))return{ok:!1,error:"Enter a list of taglines."};let t=l.fields[0];if(!t)throw new TypeError("Missing siteHero heading definition");let o={...t,name:"text",noun:{article:"a",word:"tagline"},maxLength:w},n=[],r=new Set;for(let i of e){if(!i||typeof i!="object"||Array.isArray(i))return{ok:!1,error:"Enter a key and text for each tagline."};let a=i,s=Object.hasOwn(a,"key")?a.key:void 0;if(typeof s!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(s))return{ok:!1,error:"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter."};if(r.has(s))return{ok:!1,error:"Use each tagline key only once."};let d=y({...l,fields:[o]},a);if(!d.ok)return{ok:!1,error:d.errors.text??"Invalid tagline."};r.add(s),n.push({key:s,text:d.value.text??""})}return{ok:!0,value:n}}function h(e){return S.some(t=>e===t)}function x(e,t){let o=y(l,t),n=g(t.taglines??[]);if(!o.ok||!n.ok||t.layout!==void 0&&!h(t.layout))throw new TypeError("Invalid siteHero fallback");let r={heading:o.value.heading??"",intro:o.value.intro??"",layout:t.layout??"columns",taglines:n.value};if(e===null||typeof e!="object"||Array.isArray(e))return{data:r,fallbackFields:["$"]};let i=e,a=y(l,i),s=a.ok?[]:Object.keys(a.errors);for(let u of l.fields)if(!s.includes(u.name)){let m=a.ok?a.value[u.name]:i[u.name];typeof m=="string"&&(u.name==="heading"||u.name==="intro")&&(r[u.name]=m.trim())}let d=Object.hasOwn(i,"layout")?i.layout:void 0,c=[];h(d)?r.layout=d:(r.layout="columns",s.push("layout"),c.push(b));let f=g(Object.hasOwn(i,"taglines")?i.taglines:void 0);return f.ok?r.taglines=f.value:s.push("taglines"),{data:r,fallbackFields:s.length===l.fields.length+2?["$"]:s,...c.length>0?{warnings:c}:{}}}function v(){return p({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro,layout,taglines}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:x})}export{C as CMS_CONTRACT_VERSION,l as SITE_HERO,S as SITE_HERO_LAYOUTS,b as SITE_HERO_LAYOUT_WARNING,w as SITE_HERO_TAGLINE_MAX_LENGTH,E as cmsTags,p as defineCmsQuery,x as parseSiteHero,v as siteHeroQuery,g as validateSiteHeroTaglines,y as validateTextDocument};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/contracts/query.ts", "../src/contracts/text.ts"],
|
|
4
|
-
"sourcesContent": ["/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery } from \"./query.js\";\n\nexport type SiteHero = { readonly heading: string; readonly intro: string };\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: (raw, fallback) => {\n const local = validateTextDocument(SITE_HERO, fallback);\n if (!local.ok) throw new TypeError(\"Invalid siteHero fallback\");\n const data = { heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\" };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const result = validateTextDocument(SITE_HERO, raw as Readonly<Record<string, unknown>>);\n if (result.ok) return { data: { heading: result.value.heading ?? \"\", intro: result.value.intro ?? \"\" }, fallbackFields: [] };\n const fallbackFields = Object.keys(result.errors);\n for (const field of SITE_HERO.fields) {\n if (!Object.hasOwn(result.errors, field.name)) {\n const submitted = Object.hasOwn(raw, field.name) ? (raw as Record<string, unknown>)[field.name] : undefined;\n if (typeof submitted === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = submitted.trim();\n }\n }\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length ? [\"$\"] : fallbackFields };\n },\n });\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "
|
|
4
|
+
"sourcesContent": ["/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n readonly warnings?: readonly \"siteHero.layout.defaulted\"[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery, type CmsResolution } from \"./query.js\";\n\nexport const SITE_HERO_LAYOUTS = [\"columns\", \"rows\"] as const;\nexport const SITE_HERO_TAGLINE_MAX_LENGTH = 36;\nexport const SITE_HERO_LAYOUT_WARNING = \"siteHero.layout.defaulted\" as const;\nexport type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];\nexport type SiteHeroTagline = { readonly key: string; readonly text: string };\n/** Optional additions preserve existing heading/intro-only consumer fallbacks. */\nexport type SiteHero = {\n readonly heading: string;\n readonly intro: string;\n readonly layout?: SiteHeroLayout;\n readonly taglines?: readonly SiteHeroTagline[];\n};\nexport type ParsedSiteHero = SiteHero & {\n readonly layout: SiteHeroLayout;\n readonly taglines: readonly SiteHeroTagline[];\n};\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\n/** Shared with the schema adapter; no provider metadata is returned. */\nexport function validateSiteHeroTaglines(raw: unknown):\n | { readonly ok: true; readonly value: readonly SiteHeroTagline[] }\n | { readonly ok: false; readonly error: string } {\n if (!Array.isArray(raw)) return { ok: false, error: \"Enter a list of taglines.\" };\n const heading = SITE_HERO.fields[0];\n if (!heading) throw new TypeError(\"Missing siteHero heading definition\");\n const field = { ...heading, name: \"text\", noun: { article: \"a\", word: \"tagline\" } as const,\n maxLength: SITE_HERO_TAGLINE_MAX_LENGTH };\n const value: SiteHeroTagline[] = [];\n const keys = new Set<string>();\n for (const item of raw as unknown[]) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { ok: false, error: \"Enter a key and text for each tagline.\" };\n const record = item as Record<string, unknown>;\n const key = Object.hasOwn(record, \"key\") ? record.key : undefined;\n if (typeof key !== \"string\" || !/^[a-z][a-z0-9_-]{0,31}$/.test(key)) {\n return { ok: false, error: \"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter.\" };\n }\n if (keys.has(key)) return { ok: false, error: \"Use each tagline key only once.\" };\n const text = validateTextDocument({ ...SITE_HERO, fields: [field] }, record);\n if (!text.ok) return { ok: false, error: text.errors.text ?? \"Invalid tagline.\" };\n keys.add(key);\n value.push({ key, text: text.value.text ?? \"\" });\n }\n return { ok: true, value };\n}\n\nfunction isLayout(value: unknown): value is SiteHeroLayout {\n return SITE_HERO_LAYOUTS.some((layout) => value === layout);\n}\n\n/** Strict per-field resolution: an invalid list never partially changes keyed copy. */\nexport function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero> {\n const local = validateTextDocument(SITE_HERO, fallback);\n const localTaglines = validateSiteHeroTaglines(fallback.taglines ?? []);\n if (!local.ok || !localTaglines.ok || (fallback.layout !== undefined && !isLayout(fallback.layout))) {\n throw new TypeError(\"Invalid siteHero fallback\");\n }\n const data: { heading: string; intro: string; layout: SiteHeroLayout; taglines: readonly SiteHeroTagline[] } = {\n heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\",\n layout: fallback.layout ?? \"columns\", taglines: localTaglines.value,\n };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const record = raw as Readonly<Record<string, unknown>>;\n const text = validateTextDocument(SITE_HERO, record);\n const fallbackFields: string[] = text.ok ? [] : Object.keys(text.errors);\n for (const field of SITE_HERO.fields) {\n if (!fallbackFields.includes(field.name)) {\n const value = text.ok ? text.value[field.name] : record[field.name];\n if (typeof value === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = value.trim();\n }\n }\n const layout = Object.hasOwn(record, \"layout\") ? record.layout : undefined;\n const warnings: (typeof SITE_HERO_LAYOUT_WARNING)[] = [];\n if (isLayout(layout)) data.layout = layout;\n else {\n data.layout = \"columns\";\n fallbackFields.push(\"layout\");\n warnings.push(SITE_HERO_LAYOUT_WARNING);\n }\n const taglines = validateSiteHeroTaglines(Object.hasOwn(record, \"taglines\") ? record.taglines : undefined);\n if (taglines.ok) data.taglines = taglines.value;\n else fallbackFields.push(\"taglines\");\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length + 2 ? [\"$\"] : fallbackFields,\n ...(warnings.length > 0 ? { warnings } : {}) };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery<SiteHero>({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro,layout,taglines}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: parseSiteHero,\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "SITE_HERO_LAYOUTS", "SITE_HERO_TAGLINE_MAX_LENGTH", "SITE_HERO_LAYOUT_WARNING", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "validateSiteHeroTaglines", "heading", "keys", "item", "record", "key", "isLayout", "layout", "parseSiteHero", "fallback", "local", "localTaglines", "data", "fallbackFields", "warnings", "taglines", "siteHeroQuery", "defineCmsQuery"]
|
|
7
7
|
}
|