Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V15 #1

Open
wants to merge 132 commits into
base: master
Choose a base branch
from
Open

V15 #1

wants to merge 132 commits into from

Conversation

incompl
Copy link
Member

@incompl incompl commented Oct 18, 2024

If you don't want to invoke CI, put [skip ci] in the commit message

Screenshots

Test Plan (Steps to test):

Checklist:

  • Create a Test Plan
  • Changes Communicated (in commits or above)
  • Docs Updated
  • Storybook Updated

Boris Cherny and others added 30 commits May 15, 2022 20:24
Optimize optimizer to avoid deep JSON serialization (fix bcherny#422)
Add reasonable max for tuple types (fix bcherny#438)
Bugfix: Add support for $id in sub-schemas
hopefully ensures a stable order for testing snapshots across
different systems.
This will reduce the diff when comparing actual changes (done on linux)
avoids early expansion and false negative test runs on some platforms,
mostly mine.
…based

🧪 Cross platform tests (follow up)
bcherny and others added 30 commits May 2, 2024 15:25
Added escape chars to avoid the `|` in type definition being interpreted as cell separator
* Add option to generate TS string enums

* Added e2e test for --inferStringEnumKeysFromValues
* Add new test cases.

* Intersection schema generation is order-dependent

- Given a schema that contains a named definition (`B`),
- And that named definition is referenced in multiple locations,
- And that named schema is also an intersection type (`allOf` in this
  example),

Then when parsed, the generated TypeScript will contain the correct
reference only for the _first_ location in which the named schema is
encountered, during a depth-first traversal.

Subsequent references to the same schema will be generated as though
they were only the intersection type, and not the named schema.

Example

Given the following schema:

```yaml
$id: Intersection
type: object
oneOf:
  - $ref: '#/definitions/A'
  - $ref: '#/definitions/B'

definitions:
  A:
    type: object
    additionalProperties: false
    allOf: [$ref: '#/definitions/Base']
    properties:
      b: {$ref: '#/definitions/B'}
  B:
    type: object
    additionalProperties: false,
    allOf: [$ref: '#/definitions/Base']
    properties:
      x: {type: string}
  Base:
    type: object
    additionalProperties: false,
    properties:
      y: {type: string}
```

The current resulting TypeScript will be (comments adjusted
for clarity):

```ts
// Incorrect: should be `type Intersection = A | B`
// Note that the B type at this location is the _second_ reference to
// B during a depth-first traversal.
export type Intersection = A | B1;
export type A = A1 & {
  b?: B;
};
export type A1 = Base;
export type B = B1 & {
  x?: string;
};
export type B1 = Base;

export interface Base {
  y?: string;
}
```

Root Cause

In `parser.ts`, [lines 57 - 75][1], when schema that matches multiple
"types" is encountered, the parser generates a new `ALL_OF` intersection
schema to contain each sub-type, then adds each sub-type to the new
`ALL_OF` schema.

Each sub-type is then parsed sequentially. During this process,
`maybeStripNameHints` is called, which mutates the schema by removing
the `$id`, `description`, and `name` properties.

Notably, these properties are used by `typesOfSchema` to detect the
`NAMED_SCHEMA` type. As a result, this schema object will never again be
detected as a `NAMED_SCHEMA` type.

Therefore, the _first_ instance of the schema object is correctly
handled as an intersection schema **and** a named schema, but all
subsequent instances are treated as though they are **only** an
intersection schema.

Proposed Solution

- The call to `typesOfSchema` is moved from `parser.ts` to
  `normalizer.ts`, with the goal of avoiding confusion due to a mutated
  schema object. The resulting list of schema types is persisted on the
  schema using a newly-introduced `Types` symbol.

- The generated intersection schema is _also_ moved from `parser.ts` to
  `normalizer.ts`. This is because it is advantageous to let the
  generated intersection schema participate in the caching mechanism
  (which it could not previously do, since it was generated dynamically
  during each encounter). Without this, multiple instances of the same
  schema are generated.

Related Issues

- bcherny#597

[1]: https://github.com/bcherny/json-schema-to-typescript/blob/31993def993b610ba238d3024260129e31ddc371/src/parser.ts#L57-L75 'parser.ts, lines 57 - 75'

* Additionally hoist `allOf` behavior.

* Traverse the generated intersection schema.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.