@tryghost/metafield-types 0.1.2 → 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/CHANGELOG.md +66 -0
- package/README.md +31 -22
- package/build/identity.d.ts +47 -25
- package/build/identity.d.ts.map +1 -1
- package/build/identity.js +52 -29
- package/build/identity.js.map +1 -1
- package/build/index.d.ts +278 -61
- package/build/index.d.ts.map +1 -1
- package/build/index.js +273 -96
- package/build/index.js.map +1 -1
- package/build/structure.d.ts +247 -59
- package/build/structure.d.ts.map +1 -1
- package/build/structure.js +158 -59
- package/build/structure.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# @tryghost/metafield-types
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Changed the catalog to describe each field type as a composition of building blocks, and to derive each type's rule from them.
|
|
8
|
+
|
|
9
|
+
- `FIELD_STRUCTURES` replaces `FIELD_PARTS`. A type is one leaf, `{ shape: 'scalar', leaf }`, or a record of named leaves, `{ shape: 'record', parts }`.
|
|
10
|
+
- A leaf is text of a size, `text(size)` with `TEXT_SIZES`, or a choice from a list, `choice(from)` with `LIST_SOURCES`. `country` is the choice from the list of countries.
|
|
11
|
+
- A part's type is now its leaf, so `PART_TYPE_IDS`, `PartType` and `partTypesOf` are removed. An address's postal code is `text('code')`, its country is `country`, and its other parts are `text('line')`.
|
|
12
|
+
- `FIELD_KINDS` and `FieldKind` are removed. A scalar's leaf says what it holds.
|
|
13
|
+
- `matchShape(type, { scalar, record })` and `matchLeaf(leaf, { text, choice })` call the handler for a type's shape or a leaf's kind, so a caller has to say what it does with every one. `matchShape` throws for a type the package doesn't know, so check a type from the wire with `isFieldType` first.
|
|
14
|
+
- `isRecordValue` tells whether a value is laid out as a record of parts.
|
|
15
|
+
- `StructureOf`, `ShapeOf`, `FieldTypeOfShape` and `PartsOf` name what a type is composed of, and `ValueOf` names the value it holds.
|
|
16
|
+
- `partsOf` names a record's parts as plain strings. Read one type's parts by name from `FIELD_STRUCTURES[type].parts`, whose keys are typed.
|
|
17
|
+
- `valueSchemaFor(field)` is the rule a value of one field must satisfy, derived from its type's composition. It replaces `FIELD_TYPES`, `FieldTypeDefinition`, `PART_TYPES` and `AddressValue`, which are removed. `FieldValue` and `Address` stay.
|
|
18
|
+
|
|
19
|
+
- Added helpers for editing a list field's answers.
|
|
20
|
+
|
|
21
|
+
- `inOptionOrder(settings, held)` is the answers among `held` that a list offers, in its order, and `editableAnswers(settings, held)` is what a form editing a list's answers starts from: none while a field taking one holds several.
|
|
22
|
+
|
|
23
|
+
- Added the list field type, whose field offers options of its own and takes one or several of them.
|
|
24
|
+
|
|
25
|
+
- `list` is `{ shape: 'set' }`: a value is the text of each option picked, as `string[]`, even when the field takes one. `matchShape` handlers take a `set` branch.
|
|
26
|
+
- A field now carries `settings` beside its `type`. `SettingsOf<T>` is what a type is set up with: `SetSettings` (`options`, in the order shown, and `multiple`) for a list, and nothing for every other type, so a field of another type has no settings. `TypedSettings` pairs a type with its settings. `withTypedSettings(base, settings)` builds what a field holds beside its type with that pair, a variant per shape, from how each shape's settings are held: `WRITTEN_SETTINGS` checks them against the rules, and `READ_SETTINGS` reads them back by `SetSettingsShape` alone, so a rule tightened later never hides a field set up under the old one. `TypedSettingsInputSchema` and `TypedSettingsSchema` are the pair on its own, and `MetafieldDefinitionSchema` is built the same way. `typesOfShape(shape)` lists the types of a shape.
|
|
27
|
+
- `MetafieldDefinitionSchema` reads `settings`, and `MetafieldDefinition` is typed by them, so a list definition always has its options.
|
|
28
|
+
- `valueSchemaFor(field)` takes the field's type and settings. A list's rule accepts only the options its field offers, and at most one when it takes one.
|
|
29
|
+
- `matchField(field, handlers)` calls a handler for the field's shape with the field narrowed, settings included.
|
|
30
|
+
- `optionText` is how an option's text is matched: trimmed, with accents encoded one way. `MIN_OPTIONS`, `MAX_OPTIONS` and `OPTION_SEPARATOR` are a list's limits and the character joining options in one CSV cell, which no option may contain.
|
|
31
|
+
|
|
32
|
+
- Added `SHAPE_SETTINGS`, each field shape's settings in one place: the shape a read is checked against, the rules a write is checked against on top of that shape, and the defaults a field starts with. `WRITTEN_SETTINGS` and `READ_SETTINGS` are now taken from it, and `SetSettingsSchema` is now built on `SetSettingsShape`.
|
|
33
|
+
|
|
34
|
+
- Added `refusedProperty(path)`, which names where a refusal points within what was sent by its path, with parts and positions joined by dots, such as `settings.options.2` for a field's third option. Ghost reports a custom field refusal's `property` this way, and a form can file the problems it finds under the same keys.
|
|
35
|
+
|
|
36
|
+
- Added the shape of a field definition as the Admin and Members APIs return it.
|
|
37
|
+
|
|
38
|
+
- `MetafieldDefinitionSchema` reads a definition (namespace, key, name, type, status, member access and dates) and `MetafieldDefinition` is the type it produces. Ghost writes every definition through it.
|
|
39
|
+
- `FIELD_STATUSES`, `FieldStatusSchema`, `FIELD_STATUS` and `FieldStatus` name whether a field is active or archived.
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
- Pointed the README at a guide for Ghost contributors adding a field type.
|
|
44
|
+
|
|
45
|
+
- Updated dependencies
|
|
46
|
+
|
|
47
|
+
- Updated dependencies
|
|
48
|
+
|
|
49
|
+
- Updated dependencies
|
|
50
|
+
|
|
51
|
+
## 0.2.0
|
|
52
|
+
|
|
53
|
+
### Minor Changes
|
|
54
|
+
|
|
55
|
+
- Changed `./identity` to name a field through types that only a check produces, and renamed the parts helper.
|
|
56
|
+
|
|
57
|
+
- `IdentityTextSchema` reads an identity such as `custom.shipping_address.country` into its namespace, key and parts, and writes one back. `z.safeDecode(IdentityTextSchema, text)` replaces `parseIdentity`, and `z.encode(IdentityTextSchema, identity)` replaces `formatIdentity`.
|
|
58
|
+
- `IdentitySchema` checks an identity whose segments arrive apart, such as a route's namespace and key. Reading a whole field's identity can leave `parts` out; what it reads always has them.
|
|
59
|
+
- `NamespaceSchema`, `KeySchema` and `PartSchema` check one segment each and produce the `Namespace`, `Key` and `Part` types. They replace `IDENTITY_SEGMENT`.
|
|
60
|
+
- `Identity` is the decoded shape, with `parts` in place of `partPath`. `FieldIdentity` and `FieldIdentityString` are removed.
|
|
61
|
+
- `CUSTOM_NAMESPACE` is a `Namespace` rather than the literal `'custom'`.
|
|
62
|
+
- `./identity` now loads `zod/mini`.
|
|
63
|
+
- `subFieldsOf` is renamed `partsOf`.
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- Corrected the description of CUSTOM_NAMESPACE: every field now records its namespace, so the constant only matters to code that speaks for the publisher's own fields.
|
|
68
|
+
|
|
3
69
|
## 0.1.2
|
|
4
70
|
|
|
5
71
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @tryghost/metafield-types
|
|
2
2
|
|
|
3
|
-
The types of member custom field Ghost supports: which types exist,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The types of member custom field Ghost supports: which types exist, what each type
|
|
4
|
+
is composed of, and how a value of each type is validated. Ghost, its Admin and Portal
|
|
5
|
+
use it, and so can an integration that offers inputs for a site's custom fields, such
|
|
6
|
+
as the Ghost Zapier integration.
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
9
|
npm install @tryghost/metafield-types
|
|
@@ -11,28 +11,37 @@ npm install @tryghost/metafield-types
|
|
|
11
11
|
|
|
12
12
|
## Entry points
|
|
13
13
|
|
|
14
|
-
- `@tryghost/metafield-types/structure`: the type ids
|
|
15
|
-
type of
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
14
|
+
- `@tryghost/metafield-types/structure`: the type ids and what each type is composed
|
|
15
|
+
of. A type is one leaf, a record of named leaves, or a set of options its field
|
|
16
|
+
offers, and a leaf is text of a size or a choice from a list, such as a country. A
|
|
17
|
+
field of a set type is set up with its options, which a field carries as its
|
|
18
|
+
`settings`. It depends on nothing.
|
|
19
|
+
- `@tryghost/metafield-types/countries`: the two-letter country codes the list of
|
|
20
|
+
countries offers. It depends on nothing.
|
|
21
|
+
- `@tryghost/metafield-types/identity`: how a field is named everywhere: its
|
|
22
|
+
namespace, its key, the parts of a record value, and the identity they make
|
|
23
|
+
together (`custom.shipping_address.country`). Each is a type that only its
|
|
24
|
+
check produces. It loads `zod/mini`, a small fraction of zod's size, so a
|
|
25
|
+
browser app can check identities without paying for the rest.
|
|
26
|
+
- `@tryghost/metafield-types`: the structure above, plus `valueSchemaFor(field)`,
|
|
27
|
+
the rule a value of a field must satisfy given its type and settings. The rules are built on
|
|
28
|
+
[zod](https://zod.dev), and only this entry point loads all of it, so an
|
|
29
|
+
integration that only draws inputs can use `./structure` and `./countries`
|
|
30
|
+
without loading zod at all.
|
|
24
31
|
|
|
25
32
|
## Compatibility
|
|
26
33
|
|
|
27
34
|
An integration using this package talks to sites on many Ghost versions, so a type
|
|
28
|
-
never changes once it has shipped
|
|
29
|
-
|
|
30
|
-
doesn't recognise, which is what happens when a site is on a newer
|
|
31
|
-
package the integration was built with.
|
|
35
|
+
never changes once it has shipped. It keeps what it is composed of: its shape, its
|
|
36
|
+
leaves, and the names of any parts. New structure arrives as a new type. An integration
|
|
37
|
+
should skip a type it doesn't recognise, which is what happens when a site is on a newer
|
|
38
|
+
Ghost than the package the integration was built with.
|
|
32
39
|
|
|
33
40
|
## Develop
|
|
34
41
|
|
|
35
|
-
This is a workspace package in the Ghost monorepo.
|
|
42
|
+
This is a workspace package in the Ghost monorepo. Adding a field type to Ghost is
|
|
43
|
+
covered in [`docs/adding-a-field-type.md`](docs/adding-a-field-type.md). From the repo
|
|
44
|
+
root:
|
|
36
45
|
|
|
37
46
|
```bash
|
|
38
47
|
pnpm --filter @tryghost/metafield-types build # compile to build/ with tsc (ESM)
|
|
@@ -49,9 +58,9 @@ imports in `src/` must carry an explicit extension; write the real `.ts` one —
|
|
|
49
58
|
`import {x} from './x.ts'` — and `tsc` rewrites it to `.js` on emit
|
|
50
59
|
(`rewriteRelativeImportExtensions`).
|
|
51
60
|
|
|
52
|
-
`./structure` is the half of the catalog a renderer needs
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
`./structure` is the half of the catalog a renderer needs, what each field type is
|
|
62
|
+
composed of, and it stands apart from `./index` so that importing it costs a bundle
|
|
63
|
+
almost nothing. The rules in `./index` are built on zod, some
|
|
55
64
|
seventeen kilobytes gzipped that a renderer never runs. Portal imports `./structure`
|
|
56
65
|
and loads on every page view of every themed site, so the difference reaches every
|
|
57
66
|
visitor of every Ghost site.
|
package/build/identity.d.ts
CHANGED
|
@@ -1,36 +1,58 @@
|
|
|
1
|
+
import * as z from 'zod/mini';
|
|
1
2
|
/**
|
|
2
|
-
* How a
|
|
3
|
-
*
|
|
3
|
+
* How a metafield is named, in the words every surface uses for it, and the checks that
|
|
4
|
+
* produce each word.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* - A **namespace** is who declared the field: `custom` for the fields a site's own staff
|
|
7
|
+
* define, and an app's own name for the fields it declares.
|
|
8
|
+
* - A **key** names the field within its namespace.
|
|
9
|
+
* - A **part** names one attribute of a record type's value, such as an address's
|
|
10
|
+
* `country`. A record inside a record takes a part for each level.
|
|
11
|
+
* - An **identity** is the namespace, the key and any parts, in that order, joined by dots:
|
|
12
|
+
* `custom.company` names a field, and `custom.shipping_address.country` one part of its
|
|
13
|
+
* value.
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
15
|
+
* Every one of them is a segment, and every segment follows the same rule: lowercase
|
|
16
|
+
* letters, digits and underscores. Filters, CSV columns, email replacement strings and
|
|
17
|
+
* themes all accept those and disagree about everything else. No segment can contain the
|
|
18
|
+
* dot, so an identity splits back into its segments by position.
|
|
19
|
+
*
|
|
20
|
+
* `metafields` is the qualifier, not part of an identity: it names the container, and each
|
|
21
|
+
* context writes it once, as the payload key, the route prefix, the CSV column prefix or the
|
|
22
|
+
* filter relation.
|
|
13
23
|
*/
|
|
14
24
|
export declare const QUALIFIER = "metafields";
|
|
15
25
|
export declare const SEPARATOR = ".";
|
|
26
|
+
export declare const NamespaceSchema: z.core.$ZodBranded<z.ZodMiniString<string>, "Namespace", "out">;
|
|
27
|
+
export type Namespace = z.infer<typeof NamespaceSchema>;
|
|
28
|
+
export declare const KeySchema: z.core.$ZodBranded<z.ZodMiniString<string>, "Key", "out">;
|
|
29
|
+
export type Key = z.infer<typeof KeySchema>;
|
|
30
|
+
export declare const PartSchema: z.core.$ZodBranded<z.ZodMiniString<string>, "Part", "out">;
|
|
31
|
+
export type Part = z.infer<typeof PartSchema>;
|
|
32
|
+
/**
|
|
33
|
+
* An identity's segments, each checked. A field's own identity has no parts, so reading one
|
|
34
|
+
* whose segments arrive apart, such as a route's namespace and key, can leave `parts` out.
|
|
35
|
+
* What it reads always has them.
|
|
36
|
+
*/
|
|
37
|
+
export declare const IdentitySchema: z.ZodMiniObject<{
|
|
38
|
+
namespace: z.core.$ZodBranded<z.ZodMiniString<string>, "Namespace", "out">;
|
|
39
|
+
key: z.core.$ZodBranded<z.ZodMiniString<string>, "Key", "out">;
|
|
40
|
+
parts: z.ZodMiniDefault<z.ZodMiniArray<z.core.$ZodBranded<z.ZodMiniString<string>, "Part", "out">>>;
|
|
41
|
+
}, z.core.$strip>;
|
|
42
|
+
export type Identity = z.output<typeof IdentitySchema>;
|
|
43
|
+
/** An identity read from its text, checking every segment, and written back to it. */
|
|
44
|
+
export declare const IdentityTextSchema: z.ZodMiniCodec<z.ZodMiniString<string>, z.ZodMiniObject<{
|
|
45
|
+
namespace: z.core.$ZodBranded<z.ZodMiniString<string>, "Namespace", "out">;
|
|
46
|
+
key: z.core.$ZodBranded<z.ZodMiniString<string>, "Key", "out">;
|
|
47
|
+
parts: z.ZodMiniDefault<z.ZodMiniArray<z.core.$ZodBranded<z.ZodMiniString<string>, "Part", "out">>>;
|
|
48
|
+
}, z.core.$strip>>;
|
|
16
49
|
/**
|
|
17
50
|
* The namespace holding the fields a site's own staff define.
|
|
18
51
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* namespace, not an error.
|
|
52
|
+
* Every field records its namespace, so reading and writing fields never needs this. It
|
|
53
|
+
* is for code that speaks only for the publisher's fields: who may define fields where,
|
|
54
|
+
* and the surfaces that name a publisher's field by key alone. Another namespace is not
|
|
55
|
+
* an error for not being this one: a namespace nobody has declared fields in is empty.
|
|
24
56
|
*/
|
|
25
|
-
export declare const CUSTOM_NAMESPACE
|
|
26
|
-
export declare const IDENTITY_SEGMENT: RegExp;
|
|
27
|
-
/** A formatted identity — `namespace.key`, or `namespace.key.partPath` for one part. */
|
|
28
|
-
export type FieldIdentityString = string;
|
|
29
|
-
export interface FieldIdentity {
|
|
30
|
-
namespace: string;
|
|
31
|
-
key: string;
|
|
32
|
-
partPath: string | null;
|
|
33
|
-
}
|
|
34
|
-
export declare function formatIdentity({ namespace, key, partPath }: FieldIdentity): FieldIdentityString;
|
|
35
|
-
export declare function parseIdentity(identity: string): FieldIdentity | null;
|
|
57
|
+
export declare const CUSTOM_NAMESPACE: string & z.$brand<"Namespace">;
|
|
36
58
|
//# sourceMappingURL=identity.d.ts.map
|
package/build/identity.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,eAAO,MAAM,SAAS,eAAe,CAAC;AAEtC,eAAO,MAAM,SAAS,MAAM,CAAC;AAU7B,eAAO,MAAM,eAAe,iEAA4C,CAAC;AACzE,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,SAAS,2DAAgC,CAAC;AACvD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAE5C,eAAO,MAAM,UAAU,4DAAkC,CAAC;AAC1D,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;iBAIzB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAEvD,sFAAsF;AACtF,eAAO,MAAM,kBAAkB;;;;kBAQ7B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,gCAAkC,CAAC"}
|
package/build/identity.js
CHANGED
|
@@ -1,40 +1,63 @@
|
|
|
1
|
+
import * as z from 'zod/mini';
|
|
1
2
|
/**
|
|
2
|
-
* How a
|
|
3
|
-
*
|
|
3
|
+
* How a metafield is named, in the words every surface uses for it, and the checks that
|
|
4
|
+
* produce each word.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* - A **namespace** is who declared the field: `custom` for the fields a site's own staff
|
|
7
|
+
* define, and an app's own name for the fields it declares.
|
|
8
|
+
* - A **key** names the field within its namespace.
|
|
9
|
+
* - A **part** names one attribute of a record type's value, such as an address's
|
|
10
|
+
* `country`. A record inside a record takes a part for each level.
|
|
11
|
+
* - An **identity** is the namespace, the key and any parts, in that order, joined by dots:
|
|
12
|
+
* `custom.company` names a field, and `custom.shipping_address.country` one part of its
|
|
13
|
+
* value.
|
|
9
14
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
15
|
+
* Every one of them is a segment, and every segment follows the same rule: lowercase
|
|
16
|
+
* letters, digits and underscores. Filters, CSV columns, email replacement strings and
|
|
17
|
+
* themes all accept those and disagree about everything else. No segment can contain the
|
|
18
|
+
* dot, so an identity splits back into its segments by position.
|
|
19
|
+
*
|
|
20
|
+
* `metafields` is the qualifier, not part of an identity: it names the container, and each
|
|
21
|
+
* context writes it once, as the payload key, the route prefix, the CSV column prefix or the
|
|
22
|
+
* filter relation.
|
|
13
23
|
*/
|
|
14
24
|
export const QUALIFIER = 'metafields';
|
|
15
25
|
export const SEPARATOR = '.';
|
|
26
|
+
function segment(noun) {
|
|
27
|
+
return z.string().check(z.regex(/^[a-z0-9_]+$/, {
|
|
28
|
+
error: `A ${noun} can only contain lowercase letters, numbers and underscores.`,
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
export const NamespaceSchema = segment('namespace').brand();
|
|
32
|
+
export const KeySchema = segment('key').brand();
|
|
33
|
+
export const PartSchema = segment('part').brand();
|
|
34
|
+
/**
|
|
35
|
+
* An identity's segments, each checked. A field's own identity has no parts, so reading one
|
|
36
|
+
* whose segments arrive apart, such as a route's namespace and key, can leave `parts` out.
|
|
37
|
+
* What it reads always has them.
|
|
38
|
+
*/
|
|
39
|
+
export const IdentitySchema = z.object({
|
|
40
|
+
namespace: NamespaceSchema,
|
|
41
|
+
key: KeySchema,
|
|
42
|
+
parts: z._default(z.array(PartSchema), () => []),
|
|
43
|
+
});
|
|
44
|
+
/** An identity read from its text, checking every segment, and written back to it. */
|
|
45
|
+
export const IdentityTextSchema = z.codec(z.string(), IdentitySchema, {
|
|
46
|
+
decode: (text) => {
|
|
47
|
+
const [namespace = '', key = '', ...parts] = text.split(SEPARATOR);
|
|
48
|
+
return { namespace, key, parts };
|
|
49
|
+
},
|
|
50
|
+
// Zod types the argument as what the schema reads, where `parts` can be left out, but `z.encode`
|
|
51
|
+
// refuses an identity without them before this runs.
|
|
52
|
+
encode: ({ namespace, key, parts = [] }) => [namespace, key, ...parts].join(SEPARATOR),
|
|
53
|
+
});
|
|
16
54
|
/**
|
|
17
55
|
* The namespace holding the fields a site's own staff define.
|
|
18
56
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* namespace, not an error.
|
|
57
|
+
* Every field records its namespace, so reading and writing fields never needs this. It
|
|
58
|
+
* is for code that speaks only for the publisher's fields: who may define fields where,
|
|
59
|
+
* and the surfaces that name a publisher's field by key alone. Another namespace is not
|
|
60
|
+
* an error for not being this one: a namespace nobody has declared fields in is empty.
|
|
24
61
|
*/
|
|
25
|
-
export const CUSTOM_NAMESPACE = 'custom';
|
|
26
|
-
export const IDENTITY_SEGMENT = /^[a-z0-9_]+$/;
|
|
27
|
-
export function formatIdentity({ namespace, key, partPath }) {
|
|
28
|
-
const identity = `${namespace}${SEPARATOR}${key}`;
|
|
29
|
-
return partPath ? `${identity}${SEPARATOR}${partPath}` : identity;
|
|
30
|
-
}
|
|
31
|
-
export function parseIdentity(identity) {
|
|
32
|
-
const [namespace, key, ...parts] = identity.split(SEPARATOR);
|
|
33
|
-
if (namespace === undefined ||
|
|
34
|
-
key === undefined ||
|
|
35
|
-
![namespace, key, ...parts].every((segment) => IDENTITY_SEGMENT.test(segment))) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
return { namespace, key, partPath: parts.length > 0 ? parts.join(SEPARATOR) : null };
|
|
39
|
-
}
|
|
62
|
+
export const CUSTOM_NAMESPACE = NamespaceSchema.parse('custom');
|
|
40
63
|
//# sourceMappingURL=identity.js.map
|
package/build/identity.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC;AAEtC,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,CAAC;AAE7B,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CACrB,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE;QACtB,KAAK,EAAE,KAAK,IAAI,+DAA+D;KAChF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,KAAK,EAAe,CAAC;AAGzE,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAS,CAAC;AAGvD,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAU,CAAC;AAG1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,SAAS,EAAE,eAAe;IAC1B,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;CACjD,CAAC,CAAC;AAGH,sFAAsF;AACtF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE;IACpE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,CAAC,SAAS,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IACD,iGAAiG;IACjG,qDAAqD;IACrD,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;CACvF,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC"}
|