From 9529c3325969c0366d8325fa603a2493f96164f5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 23 May 2026 19:43:40 +0000 Subject: [PATCH 1/2] chore: version packages --- .changeset/modern-parrots-search.md | 5 - CHANGELOG.md | 6 + package.json | 2 +- public/v0.18.json | 544 ++++++++++++++++++++++++++++ 4 files changed, 551 insertions(+), 6 deletions(-) delete mode 100644 .changeset/modern-parrots-search.md create mode 100644 public/v0.18.json diff --git a/.changeset/modern-parrots-search.md b/.changeset/modern-parrots-search.md deleted file mode 100644 index a4bef1a..0000000 --- a/.changeset/modern-parrots-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"typesync-cli": minor ---- - -Add Firestore `document-reference` schema support, including optional target-model narrowing in generated TypeScript and Zod types, schema validation for referenced models, and integration coverage across TypeScript, Zod, Python, and Swift. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e638da..fbc962e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.18.0 + +### Minor Changes + +- 96a90bb: Add Firestore `document-reference` schema support, including optional target-model narrowing in generated TypeScript and Zod types, schema validation for referenced models, and integration coverage across TypeScript, Zod, Python, and Swift. + ## 0.17.0 ### Minor Changes diff --git a/package.json b/package.json index c445fc6..cf5ca75 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "typesync-cli", - "version": "0.17.0", + "version": "0.18.0", "description": "Schema-first Firestore tooling for types, validation, and visualization", "keywords": [ "typesync", diff --git a/public/v0.18.json b/public/v0.18.json new file mode 100644 index 0000000..0f720d7 --- /dev/null +++ b/public/v0.18.json @@ -0,0 +1,544 @@ +{ + "$ref": "#/definitions/v0.18", + "definitions": { + "__schema0": { + "description": "A tuple type", + "type": "object", + "properties": { + "type": { "type": "string", "const": "tuple" }, + "elements": { + "type": "array", + "items": { "$ref": "#/definitions/__schema1" }, + "description": "An ordered list of types that comprise this tuple." + } + }, + "required": ["type", "elements"], + "additionalProperties": false + }, + "__schema1": { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "anyOf": [ + { + "type": "string", + "const": "any", + "description": "Any type." + }, + { + "type": "string", + "const": "unknown", + "description": "An unknown type." + }, + { + "type": "string", + "const": "nil", + "description": "A nil type." + }, + { + "type": "string", + "const": "string", + "description": "A string type." + }, + { + "type": "string", + "const": "boolean", + "description": "A boolean type." + }, + { + "type": "string", + "const": "int", + "description": "An integer type." + }, + { + "type": "string", + "const": "double", + "description": "A double type." + }, + { + "type": "string", + "const": "timestamp", + "description": "A timestamp type." + }, + { + "type": "string", + "const": "bytes", + "description": "A bytes type." + }, + { + "type": "string", + "const": "document-reference", + "description": "A Firestore document reference type. Use this for fields that store a pointer to another Firestore document (e.g. a `DocumentReference` to `users/alice`) rather than the document id as a `string`. Firestore only allows storing document references in fields (not collection references), hence the explicit name." + } + ], + "description": "A primitive type" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "document-reference" + }, + "model": { + "description": "Name of the target model (alias or document) that the referenced document belongs to. When specified, generators that support generics (TypeScript and Zod) narrow the emitted type to `DocumentReference` instead of `DocumentReference`. Generators without generic `DocumentReference` classes (Python, Swift) ignore this field at the type level but the schema validator still checks that the named model exists.", + "type": "string", + "minLength": 1 + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "A Firestore document reference type, parameterized by the target model. Equivalent to the bare `document-reference` string form when `model` is omitted." + } + ] + }, + { + "anyOf": [ + { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "literal" + }, + "value": { + "type": "string", + "description": "The literal value." + } + }, + "required": ["type", "value"], + "description": "A string literal type" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "literal" + }, + "value": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "The literal value." + } + }, + "required": ["type", "value"], + "description": "An int literal type" + } + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "literal" + }, + "value": { + "type": "boolean", + "description": "The literal value." + } + }, + "required": ["type", "value"], + "description": "A boolean literal type" + } + ], + "description": "A literal type" + } + ] + }, + { + "anyOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "enum" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "The label for this enumeration item." + }, + "value": { + "type": "string", + "description": "The value for this enumeration item." + } + }, + "required": ["label", "value"], + "additionalProperties": false + }, + "description": "A list containing the enumeration members." + } + }, + "required": ["type", "members"], + "description": "A string enum type" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "enum" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string", + "description": "The label for this enumeration item." + }, + "value": { + "type": "integer", + "minimum": -9007199254740991, + "maximum": 9007199254740991, + "description": "The value for this enumeration item." + } + }, + "required": ["label", "value"], + "additionalProperties": false + }, + "description": "A list containing the enumeration members." + } + }, + "required": ["type", "members"], + "description": "An int enum type" + } + ], + "description": "An enum type" + } + ] + }, + { "$ref": "#/definitions/__schema0" } + ] + }, + { "$ref": "#/definitions/__schema2" } + ] + }, + { "$ref": "#/definitions/__schema3" } + ] + }, + { + "description": "An object type.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "object" }, + "fields": { + "type": "object", + "propertyNames": { "type": "string" }, + "additionalProperties": { + "type": "object", + "properties": { + "type": { "$ref": "#/definitions/__schema1" }, + "optional": { + "description": "Whether this field is optional. Defaults to false.", + "type": "boolean" + }, + "readonly": { + "description": "Whether this field is read-only. Defaults to false. This information is used by the Security Rules generator when producing validators that detect whether a read-only field has been affected by a write.", + "type": "boolean" + }, + "docs": { + "description": "Optional documentation for the object field.", + "type": "string" + }, + "swift": { + "description": "Per-platform overrides for the Swift generator. See `SwiftFieldOptions`.", + "type": "object", + "properties": { + "name": { + "description": "Overrides the Swift property name used to decode this field. Encoding is unaffected: the field is still serialized to Firestore under the schema's field name (the Swift renderer routes the original name through `CodingKeys`). Useful when the schema name collides with a Swift keyword or with an auto-generated property such as `@DocumentID var id`.", + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": false + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "An object field." + }, + "description": "The fields that belong to this object." + }, + "additionalFields": { + "description": "Whether to allow adding arbitrary fields to the object. This currently does not have an effect on Swift output.", + "type": "boolean" + } + }, + "required": ["type", "fields"], + "additionalProperties": false + } + ] + }, + { + "anyOf": [ + { + "description": "A discriminated union type.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "union" }, + "discriminant": { "type": "string", "minLength": 1 }, + "variants": { + "type": "array", + "items": { + "anyOf": [ + { + "description": "An object type.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "object" }, + "fields": { + "type": "object", + "propertyNames": { "type": "string" }, + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/__schema1" + }, + "optional": { + "description": "Whether this field is optional. Defaults to false.", + "type": "boolean" + }, + "readonly": { + "description": "Whether this field is read-only. Defaults to false. This information is used by the Security Rules generator when producing validators that detect whether a read-only field has been affected by a write.", + "type": "boolean" + }, + "docs": { + "description": "Optional documentation for the object field.", + "type": "string" + }, + "swift": { + "description": "Per-platform overrides for the Swift generator. See `SwiftFieldOptions`.", + "type": "object", + "properties": { + "name": { + "description": "Overrides the Swift property name used to decode this field. Encoding is unaffected: the field is still serialized to Firestore under the schema's field name (the Swift renderer routes the original name through `CodingKeys`). Useful when the schema name collides with a Swift keyword or with an auto-generated property such as `@DocumentID var id`.", + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": false + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "An object field." + }, + "description": "The fields that belong to this object." + }, + "additionalFields": { + "description": "Whether to allow adding arbitrary fields to the object. This currently does not have an effect on Swift output.", + "type": "boolean" + } + }, + "required": ["type", "fields"], + "additionalProperties": false + }, + { "type": "string", "description": "An alias type." } + ] + } + } + }, + "required": ["type", "discriminant", "variants"], + "additionalProperties": false + }, + { + "description": "A simple union type.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "union" }, + "variants": { + "type": "array", + "items": { "$ref": "#/definitions/__schema1" } + } + }, + "required": ["type", "variants"], + "additionalProperties": false + } + ], + "description": "A union type." + } + ] + }, + { "type": "string", "description": "An alias type." } + ], + "description": "Any valid type." + }, + "__schema2": { + "description": "A list type", + "type": "object", + "properties": { + "type": { "type": "string", "const": "list" }, + "elementType": { + "description": "The type representing each element in this list.", + "$ref": "#/definitions/__schema1" + } + }, + "required": ["type", "elementType"], + "additionalProperties": false + }, + "__schema3": { + "description": "An arbitrary mapping from strings to any valid types.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "map" }, + "valueType": { + "description": "The type representing the values in this map. The keys in a map are always strings.", + "$ref": "#/definitions/__schema1" + } + }, + "required": ["type", "valueType"], + "additionalProperties": false + }, + "v0.18": { + "type": "object", + "properties": { "$schema": { "type": "string" } }, + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "model": { + "type": "string", + "const": "alias", + "description": "A literal field indicating that this is an 'alias' model." + }, + "docs": { + "description": "Optional documentation for the model.", + "type": "string" + }, + "type": { + "description": "The type that this model is an alias of.", + "$ref": "#/definitions/__schema1" + } + }, + "required": ["model", "type"], + "additionalProperties": false, + "description": "An alias model" + }, + { + "type": "object", + "properties": { + "model": { + "type": "string", + "const": "document", + "description": "A literal field indicating that this is a 'document' model." + }, + "docs": { + "description": "Optional documentation for the model.", + "type": "string" + }, + "type": { + "description": "The type that represents the shape of the document model. Must be an 'object' type.", + "type": "object", + "properties": { + "type": { "type": "string", "const": "object" }, + "fields": { + "type": "object", + "propertyNames": { "type": "string" }, + "additionalProperties": { + "type": "object", + "properties": { + "type": { "$ref": "#/definitions/__schema1" }, + "optional": { + "description": "Whether this field is optional. Defaults to false.", + "type": "boolean" + }, + "readonly": { + "description": "Whether this field is read-only. Defaults to false. This information is used by the Security Rules generator when producing validators that detect whether a read-only field has been affected by a write.", + "type": "boolean" + }, + "docs": { + "description": "Optional documentation for the object field.", + "type": "string" + }, + "swift": { + "description": "Per-platform overrides for the Swift generator. See `SwiftFieldOptions`.", + "type": "object", + "properties": { + "name": { + "description": "Overrides the Swift property name used to decode this field. Encoding is unaffected: the field is still serialized to Firestore under the schema's field name (the Swift renderer routes the original name through `CodingKeys`). Useful when the schema name collides with a Swift keyword or with an auto-generated property such as `@DocumentID var id`.", + "type": "string", + "minLength": 1 + } + }, + "additionalProperties": false + } + }, + "required": ["type"], + "additionalProperties": false, + "description": "An object field." + }, + "description": "The fields that belong to this object." + }, + "additionalFields": { + "description": "Whether to allow adding arbitrary fields to the object. This currently does not have an effect on Swift output.", + "type": "boolean" + } + }, + "required": ["type", "fields"], + "additionalProperties": false + }, + "path": { + "type": "string", + "minLength": 1, + "description": "An exact or generic path to the document. Must be a string consisting of path segments separated by a '/' (slash). Each segment can either be a literal ID or a generic ID of the collection or document. A literal ID is a plain string, such as 'users', while a generic ID must be enclosed in curly braces (e.g. '{userId}')." + }, + "swift": { + "description": "Per-platform overrides for the Swift generator. See `SwiftDocumentModelOptions`.", + "type": "object", + "properties": { + "documentIdProperty": { + "description": "Configuration for the auto-generated `@DocumentID`-annotated property that the Swift generator emits on every document-model struct. The Firebase iOS SDK populates this property from the document's path on read and excludes it from the encoded body on write.", + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "The Swift property name for the auto-generated `@DocumentID`-annotated field. Defaults to `id`. Set this to a non-`id` value (e.g. `documentId`) when the schema's document body has a field whose Firestore key is also `id`, since the Firebase iOS SDK refuses to decode a document where the `@DocumentID` property name matches an existing body field's key." + } + }, + "required": ["name"], + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + "required": ["model", "type", "path"], + "additionalProperties": false, + "description": "A document model." + } + ] + } + } + }, + "$schema": "http://json-schema.org/draft-07/schema#" +} From 1c491083f76407b928f79e1f427dcdc808b63736 Mon Sep 17 00:00:00 2001 From: Anar Kafkas Date: Sat, 23 May 2026 22:45:53 +0300 Subject: [PATCH 2/2] Update docs --- docs/schema/definition.mdx | 8 ++++---- docs/snippets/example-definition-graph.mdx | 2 +- docs/snippets/example-definition.mdx | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/schema/definition.mdx b/docs/schema/definition.mdx index e88e1f7..b275775 100644 --- a/docs/schema/definition.mdx +++ b/docs/schema/definition.mdx @@ -53,7 +53,7 @@ Example values: ### Example ```yaml user.yml -# yaml-language-server: $schema=https://schema.typesync.org/v0.16.json +# yaml-language-server: $schema=https://schema.typesync.org/v0.18.json User: model: document @@ -89,7 +89,7 @@ An alias model is used for convenience purposes to define reusable type aliases. ### Example ```yaml user.yml -# yaml-language-server: $schema=https://schema.typesync.org/v0.16.json +# yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias @@ -113,7 +113,7 @@ UserRole: of each definition file. ```yaml - # yaml-language-server: $schema=https://schema.typesync.org/v0.16.json + # yaml-language-server: $schema=https://schema.typesync.org/v0.18.json ``` This indicates to your IDE that the file is not just any YAML file but a part of a Typesync definition by linking it to the relevant JSON Schema.. This will allow your IDE to provide Intellisense/autocomplete for definition fields. @@ -133,7 +133,7 @@ UserRole: ```json { - "$schema": "https://schema.typesync.org/v0.16.json" + "$schema": "https://schema.typesync.org/v0.18.json" // ... } ``` diff --git a/docs/snippets/example-definition-graph.mdx b/docs/snippets/example-definition-graph.mdx index 3f1157b..c11d7fd 100644 --- a/docs/snippets/example-definition-graph.mdx +++ b/docs/snippets/example-definition-graph.mdx @@ -1,5 +1,5 @@ ```yaml models.yml -# yaml-language-server: $schema=https://schema.typesync.org/v0.16.json +# yaml-language-server: $schema=https://schema.typesync.org/v0.18.json Author: model: document diff --git a/docs/snippets/example-definition.mdx b/docs/snippets/example-definition.mdx index d26d485..067295e 100644 --- a/docs/snippets/example-definition.mdx +++ b/docs/snippets/example-definition.mdx @@ -1,5 +1,5 @@ ```yaml models.yml -# yaml-language-server: $schema=https://schema.typesync.org/v0.16.json +# yaml-language-server: $schema=https://schema.typesync.org/v0.18.json UserRole: model: alias