@shapio/schema 0.5.6 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +49 -4
- package/dist/index.js +105 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -33,8 +33,18 @@ export declare const REFERENCE_DATA_TYPES: ReadonlySet<DataType>;
|
|
|
33
33
|
* How a value is physically represented in the content JSON. Changing a field's type within a storage
|
|
34
34
|
* family never needs a data conversion, only a validity check; across families it is a conversion.
|
|
35
35
|
*/
|
|
36
|
-
export type StorageFamily = 'jsonString' | 'jsonNumber' | 'numericString' | 'boolean' | 'json' | 'richtext' | 'media' | 'relation' | 'component' | 'dynamiczone';
|
|
36
|
+
export type StorageFamily = 'jsonString' | 'jsonStringArray' | 'jsonNumber' | 'numericString' | 'boolean' | 'json' | 'richtext' | 'media' | 'relation' | 'component' | 'dynamiczone';
|
|
37
37
|
export declare const STORAGE_FAMILY: Readonly<Record<DataType, StorageFamily>>;
|
|
38
|
+
/** The parts of a field that decide how its values are stored. */
|
|
39
|
+
export type StoredFieldShape = {
|
|
40
|
+
type: DataType;
|
|
41
|
+
settings?: object;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The storage family of a field's values, from its type and settings: a multi-value enum holds an array of
|
|
45
|
+
* strings, not a string. Use this rather than `STORAGE_FAMILY[type]` wherever a field's settings are known.
|
|
46
|
+
*/
|
|
47
|
+
export declare const storageFamilyOf: (field: StoredFieldShape) => StorageFamily;
|
|
38
48
|
//#endregion
|
|
39
49
|
//#region src/types/json.d.ts
|
|
40
50
|
export type JsonPrimitive = string | number | boolean | null;
|
|
@@ -797,7 +807,7 @@ export type ValidationIssue = {
|
|
|
797
807
|
/** Set by cross-definition checks so a multi-definition apply can say which file is wrong. */
|
|
798
808
|
definitionId?: string;
|
|
799
809
|
};
|
|
800
|
-
export type IssueCode = 'INVALID_STRUCTURE' | 'INVALID_ID' | 'DUPLICATE_ID' | 'API_KEY_INVALID' | 'API_KEY_TOO_LONG' | 'API_KEY_RESERVED_PREFIX' | 'API_KEY_RESERVED' | 'API_KEY_COLLISION' | 'PLURAL_API_KEY_SAME_AS_SINGULAR' | 'GENERATED_NAME_COLLISION' | 'INVALID_SETTINGS' | 'INVALID_RANGE' | 'INVALID_PATTERN' | 'DUPLICATE_ENUM_VALUE' | 'INVALID_ENUM_VALUE' | 'UNSUPPORTED_FLAG' | 'INVALID_DEFAULT_VALUE' | 'UNKNOWN_EDITOR' | 'INCOMPATIBLE_EDITOR' | 'INVALID_EDITOR_OPTIONS' | 'UNKNOWN_FIELD_REFERENCE' | 'INVALID_FIELD_REFERENCE' | 'DUPLICATE_GROUP' | 'UNKNOWN_REFERENCE' | 'INVALID_REFERENCE_TARGET' | 'COMPONENT_CYCLE' | 'COMPONENT_TOO_DEEP' | 'REFERENCED_DEFINITION';
|
|
810
|
+
export type IssueCode = 'INVALID_STRUCTURE' | 'INVALID_TEXT' | 'INVALID_ID' | 'DUPLICATE_ID' | 'API_KEY_INVALID' | 'API_KEY_TOO_LONG' | 'API_KEY_RESERVED_PREFIX' | 'API_KEY_RESERVED' | 'API_KEY_COLLISION' | 'PLURAL_API_KEY_SAME_AS_SINGULAR' | 'GENERATED_NAME_COLLISION' | 'INVALID_SETTINGS' | 'INVALID_RANGE' | 'INVALID_PATTERN' | 'DUPLICATE_ENUM_VALUE' | 'INVALID_ENUM_VALUE' | 'UNSUPPORTED_FLAG' | 'INVALID_DEFAULT_VALUE' | 'UNKNOWN_EDITOR' | 'INCOMPATIBLE_EDITOR' | 'INVALID_EDITOR_OPTIONS' | 'UNKNOWN_FIELD_REFERENCE' | 'INVALID_FIELD_REFERENCE' | 'DUPLICATE_GROUP' | 'UNKNOWN_REFERENCE' | 'INVALID_REFERENCE_TARGET' | 'COMPONENT_CYCLE' | 'COMPONENT_TOO_DEEP' | 'REFERENCED_DEFINITION';
|
|
801
811
|
export declare class SchemaValidationError extends Error {
|
|
802
812
|
readonly issues: readonly ValidationIssue[];
|
|
803
813
|
constructor(issues: readonly ValidationIssue[]);
|
|
@@ -939,6 +949,21 @@ export declare const findReferencingDefinitions: (definitions: readonly SchemaDe
|
|
|
939
949
|
*/
|
|
940
950
|
export declare const findDependentModels: (definitions: readonly SchemaDefinition[], componentId: string) => SchemaDefinition[];
|
|
941
951
|
//#endregion
|
|
952
|
+
//#region src/validators/text.d.ts
|
|
953
|
+
/**
|
|
954
|
+
* Text no database can store as is: PostgreSQL `text` and `jsonb` reject U+0000, and `jsonb` rejects an
|
|
955
|
+
* unpaired UTF-16 surrogate. Shapio refuses both everywhere it takes input, so every database accepts the same
|
|
956
|
+
* values (SQLite would store them).
|
|
957
|
+
*/
|
|
958
|
+
export declare const INVALID_TEXT_MESSAGE = "must not contain NUL characters or unpaired surrogates";
|
|
959
|
+
export declare const isValidText: (text: string) => boolean;
|
|
960
|
+
/**
|
|
961
|
+
* The JSON pointer (relative to `value`, `''` for the value itself) of the first string, or object key, that
|
|
962
|
+
* is not valid text; undefined when everything is. Walks arrays and plain objects; other values (numbers,
|
|
963
|
+
* buffers, dates) hold no text.
|
|
964
|
+
*/
|
|
965
|
+
export declare const findInvalidText: (value: unknown, path?: string) => string | undefined;
|
|
966
|
+
//#endregion
|
|
942
967
|
//#region src/diff/types.d.ts
|
|
943
968
|
export declare const CHANGE_KINDS: readonly ["definition.added", "definition.removed", "definition.apiKey", "definition.pluralApiKey", "definition.metadata", "model.kind", "model.localized", "model.draftAndPublish", "field.added", "field.removed", "field.order", "field.apiKey", "field.metadata", "field.editor", "field.type", "field.required", "field.localized", "field.public", "field.deprecated", "field.unique", "field.filterable", "field.sortable", "field.settings"];
|
|
944
969
|
export type ChangeKind = (typeof CHANGE_KINDS)[number];
|
|
@@ -982,6 +1007,7 @@ export declare const diffDefinitions: (before: SchemaDefinition | null, after: S
|
|
|
982
1007
|
* | (plus) type change of a unique field | as its type change | + checkUnique |
|
|
983
1008
|
* | (plus) tightened validation rules | validation | validateValues |
|
|
984
1009
|
* | (plus) localized true→false | conversion (destructive) | convert |
|
|
1010
|
+
* | (plus) localized flip of a unique field | as the flip | + checkUnique |
|
|
985
1011
|
* | (plus) type change Shapio can't convert | conversion (destructive, drops) | convert (+ validate/required) |
|
|
986
1012
|
*/
|
|
987
1013
|
export type ChangeCategory = 'metadata' | 'editorSwap' | 'additive' | 'requiredField' | 'validation' | 'conversion' | 'contract' | 'removal' | 'constraint' | 'index';
|
|
@@ -1008,9 +1034,19 @@ export type ClassifyContext = {
|
|
|
1008
1034
|
};
|
|
1009
1035
|
/**
|
|
1010
1036
|
* A type change Shapio cannot convert: the field keeps its stable ID and API ID, and every stored value is
|
|
1011
|
-
* dropped. The planner (`classifyChange`)
|
|
1037
|
+
* dropped. The planner (`classifyChange`) decides it from both sides' type and settings and records it as
|
|
1038
|
+
* `dropsValues` on the classified change; everything downstream (conversion job, impact, review, CLI) reads
|
|
1039
|
+
* that flag rather than deciding again from the type names.
|
|
1040
|
+
*/
|
|
1041
|
+
export declare const typeChangeDropsValues: (from: StoredFieldShape, to: StoredFieldShape) => boolean;
|
|
1042
|
+
/**
|
|
1043
|
+
* A change as a stored plan step carries it: classified since 0.5.6, plain before (no drops existed then).
|
|
1012
1044
|
*/
|
|
1013
|
-
export
|
|
1045
|
+
export type PlannedChange = SchemaChange & {
|
|
1046
|
+
dropsValues?: boolean;
|
|
1047
|
+
};
|
|
1048
|
+
/** Whether a (classified) change drops every stored value of its field; false for plans without the flag. */
|
|
1049
|
+
export declare const changeDropsValues: (change: PlannedChange) => boolean;
|
|
1014
1050
|
/** Classifies one change in the context of the definitions it was diffed from. */
|
|
1015
1051
|
export declare const classifyChange: (change: SchemaChange, context: ClassifyContext) => ClassifiedChange;
|
|
1016
1052
|
export declare const classifyChanges: (changes: readonly SchemaChange[], context: ClassifyContext) => ClassifiedChange[];
|
|
@@ -1041,6 +1077,15 @@ export type ClassifiedLocaleChange = {
|
|
|
1041
1077
|
*/
|
|
1042
1078
|
export declare const classifyLocaleChange: (kind: LocaleChangeKind, code: string) => ClassifiedLocaleChange;
|
|
1043
1079
|
//#endregion
|
|
1080
|
+
//#region src/diff/uniqueLocalization.d.ts
|
|
1081
|
+
/**
|
|
1082
|
+
* Unique fields of a model whose values move between per-locale and shared storage in this change (the field's
|
|
1083
|
+
* or the model's `localized` flips). Their registry rows change key (locale ↔ `*`), and values that were unique
|
|
1084
|
+
* per locale may collide once shared, so each needs a uniqueness check that rebuilds its rows. Deprecated fields
|
|
1085
|
+
* are skipped: the registry does not track them.
|
|
1086
|
+
*/
|
|
1087
|
+
export declare const uniqueFieldsChangingLocalization: (before: SchemaDefinition | null, after: SchemaDefinition | null) => FieldDefinition[];
|
|
1088
|
+
//#endregion
|
|
1044
1089
|
//#region src/fileFormat/canonical.d.ts
|
|
1045
1090
|
export declare const canonicalJson: (value: unknown) => string;
|
|
1046
1091
|
/**
|
package/dist/index.js
CHANGED
|
@@ -96,6 +96,11 @@ const STORAGE_FAMILY = {
|
|
|
96
96
|
component: "component",
|
|
97
97
|
dynamiczone: "dynamiczone"
|
|
98
98
|
};
|
|
99
|
+
/**
|
|
100
|
+
* The storage family of a field's values, from its type and settings: a multi-value enum holds an array of
|
|
101
|
+
* strings, not a string. Use this rather than `STORAGE_FAMILY[type]` wherever a field's settings are known.
|
|
102
|
+
*/
|
|
103
|
+
const storageFamilyOf = (field) => field.type === "enum" && field.settings?.multiple === true ? "jsonStringArray" : STORAGE_FAMILY[field.type];
|
|
99
104
|
//#endregion
|
|
100
105
|
//#region src/types/definitions.ts
|
|
101
106
|
/**
|
|
@@ -1172,6 +1177,46 @@ const generatedNames = (definition) => {
|
|
|
1172
1177
|
return names;
|
|
1173
1178
|
};
|
|
1174
1179
|
//#endregion
|
|
1180
|
+
//#region src/validators/text.ts
|
|
1181
|
+
/**
|
|
1182
|
+
* Text no database can store as is: PostgreSQL `text` and `jsonb` reject U+0000, and `jsonb` rejects an
|
|
1183
|
+
* unpaired UTF-16 surrogate. Shapio refuses both everywhere it takes input, so every database accepts the same
|
|
1184
|
+
* values (SQLite would store them).
|
|
1185
|
+
*/
|
|
1186
|
+
const INVALID_TEXT_MESSAGE = "must not contain NUL characters or unpaired surrogates";
|
|
1187
|
+
const isValidText = (text) => !text.includes("\0") && text.isWellFormed();
|
|
1188
|
+
/**
|
|
1189
|
+
* Parsed JSON and querystrings; not buffers, dates or class instances. Querystring parsers build objects
|
|
1190
|
+
* without `Object.prototype`, either with no prototype or with an empty one that has none.
|
|
1191
|
+
*/
|
|
1192
|
+
const isPlainObject = (value) => {
|
|
1193
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1194
|
+
return prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null;
|
|
1195
|
+
};
|
|
1196
|
+
const escapeSegment = (segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
1197
|
+
/**
|
|
1198
|
+
* The JSON pointer (relative to `value`, `''` for the value itself) of the first string, or object key, that
|
|
1199
|
+
* is not valid text; undefined when everything is. Walks arrays and plain objects; other values (numbers,
|
|
1200
|
+
* buffers, dates) hold no text.
|
|
1201
|
+
*/
|
|
1202
|
+
const findInvalidText = (value, path = "") => {
|
|
1203
|
+
if (typeof value === "string") return isValidText(value) ? void 0 : path;
|
|
1204
|
+
if (Array.isArray(value)) {
|
|
1205
|
+
for (const [index, item] of value.entries()) {
|
|
1206
|
+
const found = findInvalidText(item, `${path}/${index}`);
|
|
1207
|
+
if (found !== void 0) return found;
|
|
1208
|
+
}
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
if (typeof value !== "object" || value === null || !isPlainObject(value)) return;
|
|
1212
|
+
for (const [key, item] of Object.entries(value)) {
|
|
1213
|
+
const at = `${path}/${escapeSegment(key)}`;
|
|
1214
|
+
if (!isValidText(key)) return at;
|
|
1215
|
+
const found = findInvalidText(item, at);
|
|
1216
|
+
if (found !== void 0) return found;
|
|
1217
|
+
}
|
|
1218
|
+
};
|
|
1219
|
+
//#endregion
|
|
1175
1220
|
//#region src/validators/typeboxIssues.ts
|
|
1176
1221
|
/**
|
|
1177
1222
|
* TypeBox errors as (JSON pointer, message) pairs. The `schema is false` echo that accompanies every
|
|
@@ -1445,6 +1490,8 @@ const checkPluralApiKey = (definition) => {
|
|
|
1445
1490
|
/** All problems with one definition, in document order. Empty means valid on its own. */
|
|
1446
1491
|
const validateDefinition = (definition) => {
|
|
1447
1492
|
const issues = [];
|
|
1493
|
+
const invalidText = findInvalidText(definition);
|
|
1494
|
+
if (invalidText !== void 0) issues.push(issue(invalidText, "INVALID_TEXT", INVALID_TEXT_MESSAGE));
|
|
1448
1495
|
if (!isStableId(definition.id)) issues.push(issue("/id", "INVALID_ID", "must be a lower-case UUID"));
|
|
1449
1496
|
const syntax = checkApiKeySyntax(definition.apiKey);
|
|
1450
1497
|
if (syntax) issues.push(issue("/apiKey", syntax.code, syntax.message));
|
|
@@ -1917,6 +1964,26 @@ const diffDefinitions = (before, after) => {
|
|
|
1917
1964
|
return changes;
|
|
1918
1965
|
};
|
|
1919
1966
|
//#endregion
|
|
1967
|
+
//#region src/diff/uniqueLocalization.ts
|
|
1968
|
+
/**
|
|
1969
|
+
* Whether a field's values are stored per locale: on a localized model only (ADR 0004). The unique registry
|
|
1970
|
+
* keys such a field by locale and a shared one by `*`.
|
|
1971
|
+
*/
|
|
1972
|
+
const storedPerLocale = (definition, field) => definition.kind !== "component" && definition.localized === true && field.localized === true;
|
|
1973
|
+
/**
|
|
1974
|
+
* Unique fields of a model whose values move between per-locale and shared storage in this change (the field's
|
|
1975
|
+
* or the model's `localized` flips). Their registry rows change key (locale ↔ `*`), and values that were unique
|
|
1976
|
+
* per locale may collide once shared, so each needs a uniqueness check that rebuilds its rows. Deprecated fields
|
|
1977
|
+
* are skipped: the registry does not track them.
|
|
1978
|
+
*/
|
|
1979
|
+
const uniqueFieldsChangingLocalization = (before, after) => {
|
|
1980
|
+
if (!before || !after || after.kind === "component") return [];
|
|
1981
|
+
return after.fields.filter((field) => {
|
|
1982
|
+
const previous = before.fields.find((candidate) => candidate.id === field.id);
|
|
1983
|
+
return previous !== void 0 && field.unique === true && !field.deprecated && storedPerLocale(before, previous) !== storedPerLocale(after, field);
|
|
1984
|
+
});
|
|
1985
|
+
};
|
|
1986
|
+
//#endregion
|
|
1920
1987
|
//#region src/diff/classify.ts
|
|
1921
1988
|
const result = (category, extra = {}) => ({
|
|
1922
1989
|
category,
|
|
@@ -1974,22 +2041,27 @@ const hasTextConstraints = (field) => {
|
|
|
1974
2041
|
};
|
|
1975
2042
|
/**
|
|
1976
2043
|
* Whether Shapio converts a cross-family type change value by value (the pairs it knows); within one storage
|
|
1977
|
-
* family the stored JSON stays as it is.
|
|
2044
|
+
* family the stored JSON stays as it is. Families come from type and settings, so a multi-value enum's
|
|
2045
|
+
* arrays are never taken for text.
|
|
1978
2046
|
*/
|
|
1979
2047
|
const convertsAcrossFamilies = (from, to) => {
|
|
1980
|
-
const fromFamily =
|
|
1981
|
-
const toFamily =
|
|
2048
|
+
const fromFamily = storageFamilyOf(from);
|
|
2049
|
+
const toFamily = storageFamilyOf(to);
|
|
1982
2050
|
const numericPair = fromFamily === "jsonNumber" && toFamily === "numericString" || fromFamily === "numericString" && toFamily === "jsonNumber";
|
|
1983
|
-
const toText = SCALAR_FAMILIES.has(fromFamily) && PLAIN_TEXT_TYPES.has(to);
|
|
1984
|
-
const textToRichtext = fromFamily === "jsonString" && from !== "code" && to === "richtext";
|
|
1985
|
-
const richtextToText = from === "richtext" && PLAIN_TEXT_TYPES.has(to);
|
|
1986
|
-
return numericPair || toText || textToRichtext || richtextToText;
|
|
2051
|
+
const toText = SCALAR_FAMILIES.has(fromFamily) && PLAIN_TEXT_TYPES.has(to.type);
|
|
2052
|
+
const textToRichtext = fromFamily === "jsonString" && from.type !== "code" && to.type === "richtext";
|
|
2053
|
+
const richtextToText = from.type === "richtext" && PLAIN_TEXT_TYPES.has(to.type);
|
|
2054
|
+
return numericPair || toText || textToRichtext || richtextToText || fromFamily === "jsonString" && toFamily === "jsonStringArray";
|
|
1987
2055
|
};
|
|
1988
2056
|
/**
|
|
1989
2057
|
* A type change Shapio cannot convert: the field keeps its stable ID and API ID, and every stored value is
|
|
1990
|
-
* dropped. The planner (`classifyChange`)
|
|
2058
|
+
* dropped. The planner (`classifyChange`) decides it from both sides' type and settings and records it as
|
|
2059
|
+
* `dropsValues` on the classified change; everything downstream (conversion job, impact, review, CLI) reads
|
|
2060
|
+
* that flag rather than deciding again from the type names.
|
|
1991
2061
|
*/
|
|
1992
|
-
const typeChangeDropsValues = (from, to) =>
|
|
2062
|
+
const typeChangeDropsValues = (from, to) => storageFamilyOf(from) !== storageFamilyOf(to) && !convertsAcrossFamilies(from, to);
|
|
2063
|
+
/** Whether a (classified) change drops every stored value of its field; false for plans without the flag. */
|
|
2064
|
+
const changeDropsValues = (change) => change.kind === "field.type" && change.dropsValues === true;
|
|
1993
2065
|
/** A required field whose values are dropped is backfilled from its default, else checked (no silent nulls). */
|
|
1994
2066
|
const requiredStep = (field) => {
|
|
1995
2067
|
if (!field?.required) return [];
|
|
@@ -2000,14 +2072,22 @@ const requiredStep = (field) => {
|
|
|
2000
2072
|
* re-validates existing values. Across families Shapio converts values with a job, for the pairs it knows;
|
|
2001
2073
|
* any other pair drops the values (destructive, acknowledged in the review).
|
|
2002
2074
|
*/
|
|
2003
|
-
const classifyTypeChange = (from, to, after) => {
|
|
2075
|
+
const classifyTypeChange = (from, to, previous, after) => {
|
|
2004
2076
|
const breaking = API_SCALAR[from] !== API_SCALAR[to] || to === "code" && from !== "code";
|
|
2005
|
-
const
|
|
2006
|
-
|
|
2077
|
+
const fromShape = {
|
|
2078
|
+
type: from,
|
|
2079
|
+
...previous ? { settings: previous.settings } : {}
|
|
2080
|
+
};
|
|
2081
|
+
const toShape = {
|
|
2082
|
+
type: to,
|
|
2083
|
+
...after ? { settings: after.settings } : {}
|
|
2084
|
+
};
|
|
2085
|
+
const fromFamily = storageFamilyOf(fromShape);
|
|
2086
|
+
if (fromFamily === storageFamilyOf(toShape)) return fromFamily === "jsonString" && TEXT_TARGETS.has(to) && !hasTextConstraints(after) || from === "integer" && to === "number" || from === "biginteger" && to === "decimal" && after?.type === "decimal" && after.settings.precision === void 0 ? result("additive", { breaking }) : result("validation", {
|
|
2007
2087
|
breaking,
|
|
2008
2088
|
prerequisites: ["validateValues"]
|
|
2009
2089
|
});
|
|
2010
|
-
if (typeChangeDropsValues(
|
|
2090
|
+
if (typeChangeDropsValues(fromShape, toShape)) return result("conversion", {
|
|
2011
2091
|
breaking,
|
|
2012
2092
|
destructive: true,
|
|
2013
2093
|
dropsValues: true,
|
|
@@ -2100,7 +2180,7 @@ const classifyFieldChange = (change, { before, after }) => {
|
|
|
2100
2180
|
case "field.editor": return result("editorSwap");
|
|
2101
2181
|
case "field.apiKey": return result("contract", { breaking: true });
|
|
2102
2182
|
case "field.type": {
|
|
2103
|
-
const classification = classifyTypeChange(change.from, change.to, field);
|
|
2183
|
+
const classification = classifyTypeChange(change.from, change.to, previous, field);
|
|
2104
2184
|
return field?.unique && previous?.unique && !classification.prerequisites.includes("checkUnique") ? {
|
|
2105
2185
|
...classification,
|
|
2106
2186
|
prerequisites: [...classification.prerequisites, "checkUnique"]
|
|
@@ -2109,12 +2189,14 @@ const classifyFieldChange = (change, { before, after }) => {
|
|
|
2109
2189
|
case "field.required":
|
|
2110
2190
|
if (change.to !== true) return result("additive");
|
|
2111
2191
|
return result("requiredField", { prerequisites: [field?.defaultValue !== void 0 ? "backfill" : "validateRequired"] });
|
|
2112
|
-
case "field.localized":
|
|
2192
|
+
case "field.localized": {
|
|
2113
2193
|
if (!(after?.kind !== "component" && after?.localized === true)) return result("metadata");
|
|
2114
|
-
|
|
2194
|
+
const checks = uniqueFieldsChangingLocalization(before, after).some((candidate) => candidate.id === change.fieldId) ? ["checkUnique"] : [];
|
|
2195
|
+
return change.to === true ? result("additive", { prerequisites: checks }) : result("conversion", {
|
|
2115
2196
|
destructive: true,
|
|
2116
|
-
prerequisites: ["convert"]
|
|
2197
|
+
prerequisites: ["convert", ...checks]
|
|
2117
2198
|
});
|
|
2199
|
+
}
|
|
2118
2200
|
case "field.public":
|
|
2119
2201
|
case "field.deprecated": {
|
|
2120
2202
|
const hides = change.kind === "field.public" ? change.to === false : change.to === true;
|
|
@@ -2153,12 +2235,14 @@ const classifyChange = (change, context) => {
|
|
|
2153
2235
|
prerequisites: ["validateValues"]
|
|
2154
2236
|
}) : result("contract", { breaking: true });
|
|
2155
2237
|
break;
|
|
2156
|
-
case "model.localized":
|
|
2157
|
-
|
|
2238
|
+
case "model.localized": {
|
|
2239
|
+
const checks = uniqueFieldsChangingLocalization(context.before, context.after).length > 0 ? ["checkUnique"] : [];
|
|
2240
|
+
classification = change.to === true ? result("additive", { prerequisites: checks }) : result("conversion", {
|
|
2158
2241
|
destructive: true,
|
|
2159
|
-
prerequisites: ["convert"]
|
|
2242
|
+
prerequisites: ["convert", ...checks]
|
|
2160
2243
|
});
|
|
2161
2244
|
break;
|
|
2245
|
+
}
|
|
2162
2246
|
case "model.draftAndPublish":
|
|
2163
2247
|
classification = change.to === true ? result("additive") : result("conversion", {
|
|
2164
2248
|
destructive: true,
|
|
@@ -2801,6 +2885,6 @@ const SeoDefaultsSchema = Type.Object({
|
|
|
2801
2885
|
twitterHandle: Type.Union([Type.String({ pattern: SEO_TWITTER_HANDLE_PATTERN.source }), Type.Null()])
|
|
2802
2886
|
}, closed);
|
|
2803
2887
|
//#endregion
|
|
2804
|
-
export { API_KEY_PATTERN, BIGINTEGER_PATTERN, BUILT_IN_THEME_KEYS, CANVAS_ELIGIBLE, CHANGE_KINDS, CODE_LANGUAGES, COMPONENT_TYPE_SUFFIXES, CUSTOM_EDITOR_ID_PATTERN, ComponentDefinitionInputSchema, ComponentDisplayInputSchema, DATA_TYPES, DATETIME_PATTERN, DATE_PATTERN, DECIMAL_PATTERN, DEFAULT_EDITORS, DEFAULT_SEO_KEYS, DEFINITION_KINDS, DefinitionInputSchema, EDITOR_CATALOGUE, EMPTY_SEO_DEFAULTS, ENTRY_LAYOUTS, EditorChoiceInputSchema, EnumValueSchema, FIELD_WIDTHS, FieldInputSchema, INLINE_TITLE_TYPES, LOCALE_CODE_PATTERN, LOCK_FILE_FORMAT_VERSION, LOCK_FILE_PATH, LocaleInputSchema, LockEntrySchema, LockFileError, LockFileSchema, MARK_RULES, MAX_API_KEY_LENGTH, MAX_COMPONENT_DEPTH, MAX_DESCRIPTION_LENGTH, MAX_FALLBACK_CHAIN, MAX_FIELDS_PER_DEFINITION, MAX_LABEL_LENGTH, MAX_RICHTEXT_DEPTH, MEDIA_KINDS, MODEL_KINDS, MODEL_TYPE_SUFFIXES, MUTATION_PREFIXES, ModelDefinitionInputSchema, ModelDisplayInputSchema, NODE_RULES, PLURAL_FALLBACK_SUFFIX, REFERENCE_DATA_TYPES, RELATION_CARDINALITIES, RESERVED_DEFINITION_API_KEYS, RESERVED_FIELD_API_KEYS, RESERVED_QUERY_NAMES, RESERVED_TYPE_NAMES, RICHTEXT_FORMAT, RICHTEXT_FORMAT_VERSION, SAFE_LINK_PATTERN, SCALAR_DATA_TYPES, SCHEMA_KIND_DIRECTORIES, SEO_COMPONENT_API_KEY, SEO_COMPONENT_ID, SEO_DESCRIPTION_SOFT_MAX, SEO_EDITOR_ID, SEO_FIELD_IDS, SEO_TITLE_PLACEHOLDER, SEO_TITLE_SOFT_MAX, SEO_TITLE_TEMPLATE_PATTERN, SEO_TWITTER_HANDLE_PATTERN, SETTINGS_SCHEMAS, SITES_DIRECTORY, SLUG_PATTERN, SORT_DIRECTIONS, STABLE_ID_PATTERN, STORAGE_FAMILY, STRIP_DEFAULT_COUNT, SchemaValidationError, SeoDefaultsSchema, SeoLocaleDefaultsSchema, TEXT_TITLE_FIELD_TYPES, THEME_BRAND_TOKENS, THEME_COLOUR_PATTERN, THEME_DARK_UI_PAIRS, THEME_KEY_PATTERN, THEME_SEMANTIC_TOKENS, THEME_TEXT_PAIRS, THEME_TOKENS, THEME_UI_PAIRS, THEME_VARIANTS, TIME_PATTERN, TITLE_FIELD_TYPES, UID_PATTERN, UNIQUE_CAPABLE_DATA_TYPES, applyTitleTemplate, assignIds, canonicalJson, checkApiKeySyntax, checkDefaultValue, checkThemeContrast, classifyChange, classifyChanges, classifyLocaleChange, collectionQueryName, contrastRatio, createStableId, decideSync, diffDefinitions, effectiveFormLayout, effectiveLayout, effectiveTitleField, embeddedComponentIds, entryLayoutOf, escapeHtml, findDependentModels, findReferencingDefinitions, foldApiKey, generatedNames, hashDefinition, isApiKeySyntaxValid, isCanvasEligible, isComponentDefinition, isCoverEligible, isCustomEditorId, isDataType, isDocumentPlaceable, isEmptyRichText, isModelDefinition, isSeoField, isStableId, isValidTitleTemplate, issue, listCompatibleEditors, lockCoversSite, lockEntriesForSite, mergePulledLock, normalizeDefinition, parseDefinition, parseLockFile, plainTextToRichText, renderRichTextHtml, renormalizeDefinition, resolveSeo, richTextBodyOf, richTextMediaIds, richTextPlainText, richTextToPlainText, routeKeyOf, schemaFilePath, scopeDirectory, scopeOfSchemaFilePath, seoComponentDefinition, seoDefaultsForLocale, serializeDefinition, serializeLockFile, sha256, stripFieldsOf, suggestPlural, summarizeChanges, toTypeName, typeChangeDropsValues, upgradeLockFile, validateDefinition, validateRichText, validateSchema, withDerivedPlural, withSiteCovered };
|
|
2888
|
+
export { API_KEY_PATTERN, BIGINTEGER_PATTERN, BUILT_IN_THEME_KEYS, CANVAS_ELIGIBLE, CHANGE_KINDS, CODE_LANGUAGES, COMPONENT_TYPE_SUFFIXES, CUSTOM_EDITOR_ID_PATTERN, ComponentDefinitionInputSchema, ComponentDisplayInputSchema, DATA_TYPES, DATETIME_PATTERN, DATE_PATTERN, DECIMAL_PATTERN, DEFAULT_EDITORS, DEFAULT_SEO_KEYS, DEFINITION_KINDS, DefinitionInputSchema, EDITOR_CATALOGUE, EMPTY_SEO_DEFAULTS, ENTRY_LAYOUTS, EditorChoiceInputSchema, EnumValueSchema, FIELD_WIDTHS, FieldInputSchema, INLINE_TITLE_TYPES, INVALID_TEXT_MESSAGE, LOCALE_CODE_PATTERN, LOCK_FILE_FORMAT_VERSION, LOCK_FILE_PATH, LocaleInputSchema, LockEntrySchema, LockFileError, LockFileSchema, MARK_RULES, MAX_API_KEY_LENGTH, MAX_COMPONENT_DEPTH, MAX_DESCRIPTION_LENGTH, MAX_FALLBACK_CHAIN, MAX_FIELDS_PER_DEFINITION, MAX_LABEL_LENGTH, MAX_RICHTEXT_DEPTH, MEDIA_KINDS, MODEL_KINDS, MODEL_TYPE_SUFFIXES, MUTATION_PREFIXES, ModelDefinitionInputSchema, ModelDisplayInputSchema, NODE_RULES, PLURAL_FALLBACK_SUFFIX, REFERENCE_DATA_TYPES, RELATION_CARDINALITIES, RESERVED_DEFINITION_API_KEYS, RESERVED_FIELD_API_KEYS, RESERVED_QUERY_NAMES, RESERVED_TYPE_NAMES, RICHTEXT_FORMAT, RICHTEXT_FORMAT_VERSION, SAFE_LINK_PATTERN, SCALAR_DATA_TYPES, SCHEMA_KIND_DIRECTORIES, SEO_COMPONENT_API_KEY, SEO_COMPONENT_ID, SEO_DESCRIPTION_SOFT_MAX, SEO_EDITOR_ID, SEO_FIELD_IDS, SEO_TITLE_PLACEHOLDER, SEO_TITLE_SOFT_MAX, SEO_TITLE_TEMPLATE_PATTERN, SEO_TWITTER_HANDLE_PATTERN, SETTINGS_SCHEMAS, SITES_DIRECTORY, SLUG_PATTERN, SORT_DIRECTIONS, STABLE_ID_PATTERN, STORAGE_FAMILY, STRIP_DEFAULT_COUNT, SchemaValidationError, SeoDefaultsSchema, SeoLocaleDefaultsSchema, TEXT_TITLE_FIELD_TYPES, THEME_BRAND_TOKENS, THEME_COLOUR_PATTERN, THEME_DARK_UI_PAIRS, THEME_KEY_PATTERN, THEME_SEMANTIC_TOKENS, THEME_TEXT_PAIRS, THEME_TOKENS, THEME_UI_PAIRS, THEME_VARIANTS, TIME_PATTERN, TITLE_FIELD_TYPES, UID_PATTERN, UNIQUE_CAPABLE_DATA_TYPES, applyTitleTemplate, assignIds, canonicalJson, changeDropsValues, checkApiKeySyntax, checkDefaultValue, checkThemeContrast, classifyChange, classifyChanges, classifyLocaleChange, collectionQueryName, contrastRatio, createStableId, decideSync, diffDefinitions, effectiveFormLayout, effectiveLayout, effectiveTitleField, embeddedComponentIds, entryLayoutOf, escapeHtml, findDependentModels, findInvalidText, findReferencingDefinitions, foldApiKey, generatedNames, hashDefinition, isApiKeySyntaxValid, isCanvasEligible, isComponentDefinition, isCoverEligible, isCustomEditorId, isDataType, isDocumentPlaceable, isEmptyRichText, isModelDefinition, isSeoField, isStableId, isValidText, isValidTitleTemplate, issue, listCompatibleEditors, lockCoversSite, lockEntriesForSite, mergePulledLock, normalizeDefinition, parseDefinition, parseLockFile, plainTextToRichText, renderRichTextHtml, renormalizeDefinition, resolveSeo, richTextBodyOf, richTextMediaIds, richTextPlainText, richTextToPlainText, routeKeyOf, schemaFilePath, scopeDirectory, scopeOfSchemaFilePath, seoComponentDefinition, seoDefaultsForLocale, serializeDefinition, serializeLockFile, sha256, storageFamilyOf, stripFieldsOf, suggestPlural, summarizeChanges, toTypeName, typeChangeDropsValues, uniqueFieldsChangingLocalization, upgradeLockFile, validateDefinition, validateRichText, validateSchema, withDerivedPlural, withSiteCovered };
|
|
2805
2889
|
|
|
2806
2890
|
//# sourceMappingURL=index.js.map
|