Skip to content

Commit 7a9cc80

Browse files
committed
docs(metadata): README and changeset say what TypeScriptSerializer annotates per metadata type
Claude-Session: https://claude.ai/code/session_01TEhopqrWQYBycZzyJHpAZr Co-authored-by: Claude <noreply@anthropic.com>
1 parent b933283 commit 7a9cc80

3 files changed

Lines changed: 20 additions & 6 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@objectstack/metadata": patch
3+
---
4+
5+
`TypeScriptSerializer` no longer annotates every `typescript`-format file `ServiceObject` (#19852). A saved view, or any other item that is not an object, used to be written as `export const metadata: ServiceObject = { … }`: a false annotation, which `tsc` refused with TS2353 (for a view, `'"type"' does not exist in type …`).
6+
7+
If you type-check the `.ts` files that `MetadataManager.save()` / `FilesystemLoader.save()` write:
8+
9+
- An `object` file is byte-identical: `import type { ServiceObject } from '@objectstack/spec/data'` and `export const metadata: ServiceObject = …`.
10+
- Every other metadata type whose spec type is exactly the `z.input` type of its schema is now annotated with that type instead: `Flow` (`@objectstack/spec/automation`) for a `flow`, `Page` (`@objectstack/spec/ui`) for a `page`, `PermissionSet` (`@objectstack/spec/security`) for a `permission`, and so on, 28 metadata types in all. Such a file now fails `tsc` only where its content is not a valid item of its own type.
11+
- `view`, `book`, `external_catalog` and any other metadata type (a plugin's own, for example) are written with no annotation and no import: `export const metadata = { … };`. `ViewMetadata` is `unknown` and `Book` is narrower than `BookSchema`, so neither would be a true annotation.
12+
- If you call `TypeScriptSerializer.serialize()` yourself, pass the item's metadata type as the new optional `SerializeOptions.metadataType` to get its annotation. Without it the file carries no annotation (it used to carry `ServiceObject`).
13+
14+
Reading is unchanged: `deserialize` still reads the first JSON block, so a file written before this fix, `ServiceObject` annotation and all, still reads back. The `javascript` format is unchanged.

‎packages/metadata/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Serializers convert metadata objects to/from different file formats:
7474

7575
- **JSONSerializer** — `.json` files with optional key sorting
7676
- **YAMLSerializer** — `.yaml`/`.yml` files (JSON_SCHEMA for security)
77-
- **TypeScriptSerializer** — the `typescript` / `javascript` formats (`.ts` / `.js`): a JSON document wrapped in a module, the file format `FilesystemLoader` writes and reads for those two formats (`typescript` is `FilesystemLoader.save()`'s default, so `MetadataManager.save()` routed to the filesystem loader writes `{rootDir}/{type}/{name}.ts`). It writes `export const metadata = { …JSON… };` then `export default metadata;` — the `typescript` format also imports the `ServiceObject` type and annotates the constant with it, whatever the item's metadata type — and reads back the first `{ … }` block after the first `export const` (or, failing that, `export default`), which must be JSON: double-quoted keys and strings, no comments, no trailing commas, no functions. It is **not** an authoring shape: authored metadata such as a `*.object.ts` is written `ObjectSchema.create({ … })` (or `defineView()`, …), which this serializer never emits, and an authored file with unquoted keys is refused rather than read.
77+
- **TypeScriptSerializer** — the `typescript` / `javascript` formats (`.ts` / `.js`): a JSON document wrapped in a module, the file format `FilesystemLoader` writes and reads for those two formats (`typescript` is `FilesystemLoader.save()`'s default, so `MetadataManager.save()` routed to the filesystem loader writes `{rootDir}/{type}/{name}.ts`). It writes `export const metadata = { …JSON… };` then `export default metadata;`. The `typescript` format also annotates that constant with the spec type of the item's metadata type, which `FilesystemLoader.save()` passes as `SerializeOptions.metadataType`, and imports it: `ServiceObject` from `@objectstack/spec/data` for an `object`, `Flow` from `@objectstack/spec/automation` for a `flow`, and so on, each exactly the `z.input` type of the schema `getMetadataTypeSchema()` resolves for that metadata type. A metadata type with no such spec type is written with no annotation and no import: `view` (its `ViewMetadata` type is `unknown`), `book`, `external_catalog`, a plugin's own type, and any `serialize()` call that passes no `metadataType`. It reads back the first `{ … }` block after the first `export const` (or, failing that, `export default`), which must be JSON: double-quoted keys and strings, no comments, no trailing commas, no functions. It is **not** an authoring shape: authored metadata such as a `*.object.ts` is written `ObjectSchema.create({ … })` (or `defineView()`, …), which this serializer never emits, and an authored file with unquoted keys is refused rather than read.
7878

7979
### 4. Overlay / Customization System
8080

‎packages/metadata/src/serializers/typescript-serializer.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ import type { MetadataSerializer, SerializeOptions } from './serializer-interfac
1717
* An emitted annotation must never be false. So a metadata type is listed only
1818
* when the spec exports a type that IS the input type of the schema
1919
* `getMetadataTypeSchema()` resolves for it (`z.input<typeof XSchema>`, the
20-
* ADR-0122 authoring name): then any body that metadata type's contract accepts
21-
* also type-checks. A metadata type that is not listed (a plugin's own type,
22-
* a misspelling, or one whose spec type is narrower than its schema) gets no
23-
* annotation and no `import type`, never `any`, `unknown` or another type's
24-
* shape.
20+
* ADR-0122 authoring name): the annotation then states that type's own
21+
* contract, nothing narrower and nothing else. A metadata type that is not
22+
* listed (a plugin's own type, a misspelling, or one whose spec type does not
23+
* state its schema) gets no annotation and no `import type`: never `any`,
24+
* `unknown` or another type's shape.
2525
*
2626
* Two metadata types are deliberately absent:
2727
* - `view`: `ViewMetadataSchema` is a `z.preprocess`, so its input type, and

0 commit comments

Comments
 (0)