docs: ProfileMethod descriptor taxonomy + field type draft - #163
Closed
ryukzak wants to merge 6 commits into
Closed
Conversation
…e index Adds a writer-ready profile representation alongside the raw ProfileTypeSchema. Snapshots are flattened (fields merged across the hierarchy, extensions consolidated) and discriminated by `identifier.kind === "profile-snapshot"`. Type additions: - SnapshotProfileIdentifier in the Identifier union. - SnapshotProfileTypeSchema in the TypeSchema union. - Guards: isSnapshotProfileIdentifier, isSnapshotProfileTypeSchema. - Helper: snapshotIdentifier(id) — ProfileIdentifier → SnapshotProfileIdentifier. - Export PrimitiveTypeSchema (was implicitly public via TypeSchema; the resolve overload signature now needs the name directly). Index integration in mkTypeSchemaIndex: - New `snapshotIndex` (parallel to nestedIndex) holds pre-built snapshots. - Snapshots are eagerly built for every well-formed profile during index construction. Profiles whose hierarchy lacks a non-profile ancestor are skipped structurally via tryHierarchy + guard checks, so direct flatProfile callers still see the original exception path. - New `collectSnapshotProfiles()` returns all built snapshots. - `resolve` and `resolveType` route SnapshotProfileIdentifier (kind "profile-snapshot") to the snapshot store. - Both functions are now overloaded — passing a specific identifier variant (Resource, Profile, Snapshot, Binding, ValueSet, Logical, Primitive, ComplexType; plus Nested for resolveType) narrows the return type without a cast. Implementation uses a named callable type (ResolveFn/ResolveTypeFn) to avoid circular type inference through TypeSchemaIndex. - findLastSpecialization uses guard-based filter (skips both profile and profile-snapshot variants) so it composes when called via findLastSpecializationByIdentifier on a snapshot identifier. - entityTree includes the "profile-snapshot" bucket so EntityTree stays exhaustive over Identifier["kind"]. Tree-shake short-circuit: - treeShakeTypeSchema returns snapshots untouched (they're derived data; they never reach tree shaking in practice, but the typed switch needs to acknowledge them).
Pipes snapshots from the index through the writer end-to-end. - writer.generate() now collects via tsIndex.collectSnapshotProfiles(). - generateResourceModule dispatches on isSnapshotProfileTypeSchema; the inline `tsIndex.resolve(...)` call inside the profile branch is gone — the iterated schema is already the snapshot. - generateFhirPackageIndexFile and the per-package filter use isSnapshotProfileTypeSchema. - generateProfileIndexFile signature takes SnapshotProfileTypeSchema[]. - resolveExtensionProfile resolves the snapshot via the overloaded resolve() — no cast — and returns it as `snapshot` on ExtensionProfileInfo (replacing the previous `flatProfile` field). - All profile-generation helpers (factory info, slice defs, extension methods, validation, slice setters/getters) take `snapshot: SnapshotProfileTypeSchema` instead of `flatProfile: ProfileTypeSchema`. - Name helpers (tsProfileModuleName/FileName/ClassName) narrow to SnapshotProfileTypeSchema. tsProfileModuleName switches to findLastSpecializationByIdentifier so it no longer depends on the TypeSchema union. Drive-by: biome --write trimmed a redundant `!!canonicalUrl` (already inside an `&&` chain).
Captures the 8 emit categories the TS writer currently produces inside a profile module (constants, factory, lifecycle, field/slice/extension accessors, validator, type aliases), the descriptor data each needs, and the migration target: a `methods` array on SnapshotProfileTypeSchema where each entry is a tagged descriptor and the writer becomes a renderer that dispatches on `entry.kind`. This is the foundation for the follow-up PR series that moves method derivation out of the writer.
…ema.methods First pass at the language-neutral descriptor model that future code generation will dispatch on. Adds a "methods field type — first draft" section to the design doc: - Shared records (AutoField, ParamField, SliceAutoField, SliceMatchConstant, FieldAccessorSpec, SliceSpec, ExtensionAccessorSpec, ValidationCheck, SubExtensionSlice). - Tagged ProfileMethod union with 22 variants covering all eight taxonomy categories. - Open questions: ordering, hasMeta inlining vs derivation, flavor as sub-field vs sub-variant, where validation lives, helper-import gating, type aliases as a separate array.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on #158.
Design groundwork for the follow-up PR series that moves profile-method derivation out of the TS writer onto `SnapshotProfileTypeSchema`.
What this PR contains
Just docs — `docs/design/profile-methods.md`. Two sections:
1. Taxonomy
Catalogs every emit the TS writer currently produces inside a profile module, grouped into 8 categories:
Each entry has its source helper and emit condition.
2. `methods` field type — first draft
Proposes the language-neutral `ProfileMethod` tagged union (22 variants) plus shared records:
```ts
export type ProfileMethod =
| { kind: "static-canonical-url" }
| { kind: "static-slice-match"; def: SliceMatchConstant }
| { kind: "static-from"; baseType: TypeIdentifier; hasMeta: boolean }
| { kind: "static-is"; baseType: TypeIdentifier; mode: "resource" | "extension" }
| { kind: "static-apply"; ... }
| { kind: "static-create-resource"; ... }
| { kind: "static-create"; viaResolveInput: boolean }
| { kind: "static-resolve-input"; subSlices: SubExtensionSlice[] }
| { kind: "constructor"; baseType: TypeIdentifier }
| { kind: "to-resource"; baseType: TypeIdentifier }
| { kind: "field-get"; field: FieldAccessorSpec }
| { kind: "field-set"; field: FieldAccessorSpec }
| { kind: "slice-get"; def: SliceSpec }
| { kind: "slice-set"; def: SliceSpec }
| { kind: "extension-get"; spec: ExtensionAccessorSpec }
| { kind: "extension-set"; spec: ExtensionAccessorSpec }
| { kind: "validate"; checks: ValidationCheck[] }
| { kind: "type-alias-raw"; ... }
| { kind: "type-alias-flat"; subSlices: SubExtensionSlice[] }
| { kind: "type-alias-slice-flat"; ... }
| { kind: "type-alias-slice-flat-all"; ... }
| { kind: "type-alias-extension-flat"; ... };
```
Everything is language-neutral — identifiers stay as `TypeIdentifier`, values stay as `unknown`. Renderers consume the array and dispatch on `kind`.
Open questions
Listed at the bottom of the doc:
What this enables
Not in this PR
Those land in follow-up PRs once the descriptor shape is approved.