@localess/schema 4.0.3-dev.20261004124605 → 4.0.3-dev.20261004140136

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/SKILL.md CHANGED
@@ -81,7 +81,7 @@ Everything below is `export type` — importable with `import type { ... } from
81
81
  | Authoring (from `define.ts`) | `EnumDefinition` (result of `defineEnum`), `ComponentDefinition` (result of `defineSchema`), `SchemaDefinition` (`ComponentDefinition \| EnumDefinition`), `LocalessSchemaConfig` (`{ schemas: readonly SchemaDefinition[] }` — what `validate`/`toSchemaExport` accept), `SchemaFieldInput` (a field as authored: `source`/`schemas` accept by-value refs), `EnumDefinitionInput`, `ComponentDefinitionInput` |
82
82
  | Inference (from `infer.ts`) | `InferContentData`, `InferContent`, `InferEnum` |
83
83
  | Validation (from `validate.ts`) | `ValidationIssue` (`{ severity: 'error' \| 'warning'; code; path; message }`), `ValidationResult` (`{ ok; issues }`) |
84
- | Wire model (re-exported from `@localess/model`) | `SchemaType`, `SchemaFieldKind`, `AssetFileType`, `SchemaEnumValue`, `SchemaFieldBase`, `SchemaField`, the 18 per-kind interfaces (`SchemaFieldText`, `SchemaFieldTextarea`, `SchemaFieldRichText`, `SchemaFieldMarkdown`, `SchemaFieldNumber`, `SchemaFieldColor`, `SchemaFieldDate`, `SchemaFieldDateTime`, `SchemaFieldBoolean`, `SchemaFieldOption`, `SchemaFieldOptions`, `SchemaFieldLink`, `SchemaFieldReference`, `SchemaFieldReferences`, `SchemaFieldAsset`, `SchemaFieldAssets`, `SchemaFieldSchema`, `SchemaFieldSchemas`), `SchemaComponentExport`, `SchemaEnumExport`, `SchemaExport` |
84
+ | Wire model (re-exported from `@localess/model`) | `SchemaType`, `SchemaFieldKind`, `AssetFileType`, `SchemaEnumValue`, `SchemaFieldBase`, `SchemaFieldTranslatable`, `TranslatableSchemaFieldKind`, `SchemaField`, the 18 per-kind interfaces (`SchemaFieldText`, `SchemaFieldTextarea`, `SchemaFieldRichText`, `SchemaFieldMarkdown`, `SchemaFieldNumber`, `SchemaFieldColor`, `SchemaFieldDate`, `SchemaFieldDateTime`, `SchemaFieldBoolean`, `SchemaFieldOption`, `SchemaFieldOptions`, `SchemaFieldLink`, `SchemaFieldReference`, `SchemaFieldReferences`, `SchemaFieldAsset`, `SchemaFieldAssets`, `SchemaFieldSchema`, `SchemaFieldSchemas`), `SchemaComponentExport`, `SchemaEnumExport`, `SchemaExport` |
85
85
  | Content values (re-exported from `@localess/model`) | `ContentAsset`, `ContentLink`, `ContentReference`, `ContentRichText` — plus every other `@localess/model` type (`Content`, `Locale`, `Space`, `Translations`, …), since `src/index.ts` ends with `export * from '@localess/model'` |
86
86
 
87
87
  ## `defineField`
@@ -126,6 +126,8 @@ Fallbacks when a reference can't be resolved against the config:
126
126
 
127
127
  Every field carries `name`, `kind`, and the base optional properties
128
128
  (`displayName`, `required`, `description`, `defaultValue`, `translatable`).
129
+ `translatable` is rejected on `REFERENCE`/`REFERENCES`/`SCHEMA`/`SCHEMAS` — at compile time and by
130
+ `validate()` — since the Studio editor never translates those kinds.
129
131
  `required: true` fields are non-optional keys on the inferred content type;
130
132
  everything else is optional.
131
133
 
@@ -176,6 +178,7 @@ schema in the config is checked, not just the first. Rules and their `code`:
176
178
  | `field/unresolved-schema-ref` | Every `SCHEMA`/`SCHEMAS` `schemas` entry must be the id of a schema in the config. |
177
179
  | `field/schema-ref-is-enum` | ...and that schema must be `NODE`, not `ENUM`. |
178
180
  | `field/schema-ref-is-root` | ...nor `ROOT` — the Studio editor only offers `NODE` schemas. |
181
+ | `field/translatable-unsupported` | `translatable` must not be set on `REFERENCE`/`REFERENCES`/`SCHEMA`/`SCHEMAS`; the Studio editor never translates them. |
179
182
  | `field/missing-schemas` | A `SCHEMA`/`SCHEMAS` field must list at least one schema in `schemas`; with none the editor can add no block. |
180
183
 
181
184
  `validate` does not check for stray properties from the wrong field kind —
package/dist/define.d.ts CHANGED
@@ -28,6 +28,11 @@ type FieldInputOf<F> = F extends {
28
28
  kind: 'SCHEMA' | 'SCHEMAS';
29
29
  } ? Omit<DeepReadonly<F>, 'schemas'> & {
30
30
  readonly schemas: readonly (string | ComponentDefinition)[];
31
+ readonly translatable?: never;
32
+ } : F extends {
33
+ kind: 'REFERENCE' | 'REFERENCES';
34
+ } ? DeepReadonly<F> & {
35
+ readonly translatable?: never;
31
36
  } : DeepReadonly<F>;
32
37
  /**
33
38
  * A field as authored: OPTION/OPTIONS source and SCHEMA/SCHEMAS schemas accept by-value refs.
@@ -133,7 +138,8 @@ export declare function defineEnum<const TId extends string, const TValues exten
133
138
  * of a field's origin. See `docs/decisions/008-schema-package.md`.
134
139
  *
135
140
  * Every `kind` accepts `name` (required), plus `displayName?`, `required?`, `description?`,
136
- * `defaultValue?`, `translatable?`. Kind-specific extras:
141
+ * `defaultValue?`, and — except on `REFERENCE` / `REFERENCES` / `SCHEMA` / `SCHEMAS`, which the
142
+ * Studio editor never translates — `translatable?`. Kind-specific extras:
137
143
  * - `TEXT` / `TEXTAREA` / `RICH_TEXT` / `MARKDOWN` — `minLength?`, `maxLength?`
138
144
  * - `NUMBER` — `minValue?`, `maxValue?`
139
145
  * - `COLOR` / `DATE` / `DATETIME` / `BOOLEAN` / `LINK` — no extras
package/dist/index.js CHANGED
@@ -36,7 +36,8 @@ function defineEnum(definition) {
36
36
  * of a field's origin. See `docs/decisions/008-schema-package.md`.
37
37
  *
38
38
  * Every `kind` accepts `name` (required), plus `displayName?`, `required?`, `description?`,
39
- * `defaultValue?`, `translatable?`. Kind-specific extras:
39
+ * `defaultValue?`, and — except on `REFERENCE` / `REFERENCES` / `SCHEMA` / `SCHEMAS`, which the
40
+ * Studio editor never translates — `translatable?`. Kind-specific extras:
40
41
  * - `TEXT` / `TEXTAREA` / `RICH_TEXT` / `MARKDOWN` — `minLength?`, `maxLength?`
41
42
  * - `NUMBER` — `minValue?`, `maxValue?`
42
43
  * - `COLOR` / `DATE` / `DATETIME` / `BOOLEAN` / `LINK` — no extras
@@ -150,6 +151,22 @@ var RESERVED_SCHEMA_IDS = [
150
151
  "Content"
151
152
  ];
152
153
  var RESERVED_FIELD_NAMES = ["_id", "_schema"];
154
+ var TRANSLATABLE_FIELD_KINDS = {
155
+ TEXT: true,
156
+ TEXTAREA: true,
157
+ RICH_TEXT: true,
158
+ MARKDOWN: true,
159
+ NUMBER: true,
160
+ COLOR: true,
161
+ DATE: true,
162
+ DATETIME: true,
163
+ BOOLEAN: true,
164
+ OPTION: true,
165
+ OPTIONS: true,
166
+ LINK: true,
167
+ ASSET: true,
168
+ ASSETS: true
169
+ };
153
170
  /**
154
171
  * Validate a schema config against the Localess authoring rules (ID/name patterns, reserved
155
172
  * names, length limits, reference resolution). Non-throwing; `ok` is false only when at least
@@ -188,6 +205,7 @@ function validate(config) {
188
205
  if (field.displayName && field.displayName.length > 30) error("field/display-name-too-long", fieldPath, "Field displayName exceeds 30 characters");
189
206
  if (field.description && field.description.length > 250) error("field/description-too-long", fieldPath, "Field description exceeds 250 characters");
190
207
  if (field.defaultValue && field.defaultValue.length > 250) error("field/default-value-too-long", fieldPath, "Field defaultValue exceeds 250 characters");
208
+ if ("translatable" in field && field.translatable && !(field.kind in TRANSLATABLE_FIELD_KINDS)) error("field/translatable-unsupported", fieldPath, `${field.kind} fields cannot be translatable; the Studio editor never translates them`);
191
209
  if (field.kind === "OPTION" || field.kind === "OPTIONS") {
192
210
  const source = byId.get(field.source);
193
211
  if (!source) error("field/unresolved-source", fieldPath, `source '${field.source}' does not resolve to a schema in the config`);
package/dist/index.mjs CHANGED
@@ -35,7 +35,8 @@ function defineEnum(definition) {
35
35
  * of a field's origin. See `docs/decisions/008-schema-package.md`.
36
36
  *
37
37
  * Every `kind` accepts `name` (required), plus `displayName?`, `required?`, `description?`,
38
- * `defaultValue?`, `translatable?`. Kind-specific extras:
38
+ * `defaultValue?`, and — except on `REFERENCE` / `REFERENCES` / `SCHEMA` / `SCHEMAS`, which the
39
+ * Studio editor never translates — `translatable?`. Kind-specific extras:
39
40
  * - `TEXT` / `TEXTAREA` / `RICH_TEXT` / `MARKDOWN` — `minLength?`, `maxLength?`
40
41
  * - `NUMBER` — `minValue?`, `maxValue?`
41
42
  * - `COLOR` / `DATE` / `DATETIME` / `BOOLEAN` / `LINK` — no extras
@@ -149,6 +150,22 @@ var RESERVED_SCHEMA_IDS = [
149
150
  "Content"
150
151
  ];
151
152
  var RESERVED_FIELD_NAMES = ["_id", "_schema"];
153
+ var TRANSLATABLE_FIELD_KINDS = {
154
+ TEXT: true,
155
+ TEXTAREA: true,
156
+ RICH_TEXT: true,
157
+ MARKDOWN: true,
158
+ NUMBER: true,
159
+ COLOR: true,
160
+ DATE: true,
161
+ DATETIME: true,
162
+ BOOLEAN: true,
163
+ OPTION: true,
164
+ OPTIONS: true,
165
+ LINK: true,
166
+ ASSET: true,
167
+ ASSETS: true
168
+ };
152
169
  /**
153
170
  * Validate a schema config against the Localess authoring rules (ID/name patterns, reserved
154
171
  * names, length limits, reference resolution). Non-throwing; `ok` is false only when at least
@@ -187,6 +204,7 @@ function validate(config) {
187
204
  if (field.displayName && field.displayName.length > 30) error("field/display-name-too-long", fieldPath, "Field displayName exceeds 30 characters");
188
205
  if (field.description && field.description.length > 250) error("field/description-too-long", fieldPath, "Field description exceeds 250 characters");
189
206
  if (field.defaultValue && field.defaultValue.length > 250) error("field/default-value-too-long", fieldPath, "Field defaultValue exceeds 250 characters");
207
+ if ("translatable" in field && field.translatable && !(field.kind in TRANSLATABLE_FIELD_KINDS)) error("field/translatable-unsupported", fieldPath, `${field.kind} fields cannot be translatable; the Studio editor never translates them`);
190
208
  if (field.kind === "OPTION" || field.kind === "OPTIONS") {
191
209
  const source = byId.get(field.source);
192
210
  if (!source) error("field/unresolved-source", fieldPath, `source '${field.source}' does not resolve to a schema in the config`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localess/schema",
3
- "version": "4.0.3-dev.20261004124605",
3
+ "version": "4.0.3-dev.20261004140136",
4
4
  "description": "Programmatic schema definitions for Localess with TypeScript content type inference.",
5
5
  "keywords": [
6
6
  "localess",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "license": "MIT",
45
45
  "dependencies": {
46
- "@localess/model": "4.0.3-dev.20261004124605"
46
+ "@localess/model": "4.0.3-dev.20261004140136"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/node": "^24",