Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jobs:
- php
- scala3,schema-scala3
- elixir,schema-elixir,graphql-elixir
- comment-injection-treesitter,comment-injection-typescript,comment-injection-typescript-zod,comment-injection-typescript-effect-schema

# Partially working
# - schema-typescript # TODO Unify with typescript once fixed
Expand Down
64 changes: 64 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# AGENTS.md

Notes for coding agents working in this repository.

## Environment

- This is a TypeScript/npm monorepo using npm workspaces.
- Prefer the Node version from `.nvmrc` (`nvm use`; currently Node 22.14.0). `package.json` requires Node >= 18.12.0.
- Install dependencies with `npm ci`.

## Build and run

- Build everything with:

```bash
npm run build
```

This runs `npm run clean`, builds all workspaces that have a `build` script, then runs the root `tsc`.

- After building, the CLI entry point is `dist/index.js`, for example:

```bash
node dist/index.js --version
node dist/index.js --help
```

- For live rebuild/re-run while developing renderer output, use `npm start -- "<quicktype args>"`.

## Tests

- The test runner is `script/test`, exposed as:

```bash
npm test
```

- The full suite runs all fixtures and needs external language toolchains for many targets (`dotnet`, Java/Maven, Go, Rust, Python/mypy, PHP, Ruby, Kotlin, Scala, Elixir, etc.). On a machine without those tools, plain `npm test` will fail when it reaches the first missing toolchain.

- For local focused testing, use fixture filters. Fixture names are in `test/languages.ts` and `test/fixtures.ts`; comma-separated fixture groups are supported:

```bash
QUICKTEST=true FIXTURE=javascript npm test
QUICKTEST=true FIXTURE=typescript npm test -- test/inputs/json/samples/pokedex.json
CPUs=2 QUICKTEST=true FIXTURE=javascript npm test
```

`QUICKTEST=true` skips the large miscellaneous JSON input set. Extra arguments after `--` are sample files or directories to run.

- GitHub Actions uses the same pattern, e.g. `QUICKTEST=true FIXTURE=${{ matrix.fixture }} npm test`, after installing toolchain dependencies for each fixture group in `.github/workflows/test-pr.yaml`.

## Validation performed

The following commands were run successfully in this workspace:

```bash
npm ci
npm run build
node dist/index.js --version
CPUs=2 QUICKTEST=true FIXTURE=javascript npm test
QUICKTEST=true FIXTURE=typescript npm test -- test/inputs/json/samples/pokedex.json
```

Also observed: `npm test` without fixture filters started the full 70-fixture suite and failed on this machine because `dotnet` is not installed. `npm run lint` currently fails because ESLint cannot find a configuration file.
67 changes: 67 additions & 0 deletions COMMENT-INJECTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# JSON Schema comment injection

## TypeScript reproduction

Added a focused schema fixture:

- `test/inputs/schema/comment-injection.schema`
- `test/inputs/schema/comment-injection.1.json`

The schema puts comment-closing text in both an object `description` and a property `description`:

- `*/` for C-style block comments
- `{-` and `-}` for Elm/Haskell comments
- `"""` on its own line for Python/Elixir docstrings/heredocs
- `\r}` for line-comment outputs whose parsers treat carriage return as a line terminator

Run:

```bash
CPUs=1 QUICKTEST=true FIXTURE=schema-typescript npm test -- test/inputs/schema/comment-injection.schema
```

Expected result: the generated TypeScript validates `comment-injection.1.json` and prints equivalent JSON.

Before escaping was added, this test failed before validation because `TopLevel.ts` was syntactically invalid; the schema `description` escaped the generated `/** ... */` comment.

## Schema fields that can reach comments

In JSON Schema input, `packages/quicktype-core/src/attributes/Description.ts` collects `description` into type and property-description attributes. Renderers then emit those attributes as documentation comments.

Observed comment sinks:

- schema/type `description` on objects/classes
- property `description` for object properties/fields
- `description` on enum schemas
- `description` on union schemas and other named types when a renderer emits docs for those named types

`title` is different in the inspected path: JSON Schema input uses it for type/top-level naming, not as raw documentation text. The generated JSON Schema renderer can output JSON `title` fields, but those are JSON string values, not source comments.

Other non-schema inputs can also supply descriptions or leading comments, but the reproduction here is limited to JSON Schema `description`.

## Potentially affected outputs and triggers

Outputs are affected when raw schema descriptions are placed into comments/docstrings without escaping that target's comment delimiter or line terminators. The shared fix now normalizes description line endings and escapes delimiter text at comment-emission time.

- C-style doc comments `/** ... */`: TypeScript, Flow, JavaScript when descriptions are emitted, Java, C (`cjson`), C++, PHP, Kotlin, Scala 3, Smithy4s. Trigger with `*/`; escaped as `* /`.
- Elm/Haskell doc comments `{-| ... -}`: Elm, Haskell. Trigger with `{-` or `-}`; escaped as `{ -` and `- }`.
- Triple-quoted docstrings/heredocs: Python, Elixir. Trigger with `"""` on its own description line; escaped as `\"\"\"`.
- Line comments (`//`, `///`): C#, Go, Rust, Ruby, Swift, Objective-C, Dart, Pike, Crystal, and enum comments in TypeScript-Zod/TypeScript-Effect-Schema. Trigger with a carriage return (`\r`) when descriptions are split only on `\n`; fixed by normalizing `\r\n?` to `\n` before comment emission.

Plain JavaScript output did not emit the tested schema descriptions into model comments, so the object/property reproduction does not affect it the same way. TypeScript-Zod and TypeScript-Effect-Schema also did not emit the object/property descriptions from `comment-injection.schema`; they only emitted the enum description from `comment-injection-enum.schema`.

The tree-sitter fixture includes Go, Rust, and Ruby even though their grammars did not reproduce a syntax break with the CR line-comment payload; this keeps parser coverage in place for those generated outputs and future payload/escaping changes.

Still not covered by the tree-sitter fixture: Objective-C, Crystal, and Elm. Objective-C's available tree-sitter grammar reports baseline errors on generated `.m` output; Crystal and Elm have usable grammars but are not included in this parser-coverage pass.

## Test cases added

- `test/inputs/schema/comment-injection.schema` covers object and property descriptions, including both Elm/Haskell nested-comment delimiters.
- `test/inputs/schema/comment-injection-enum.schema` covers enum descriptions via an enum-valued property.
- `test/inputs/schema/comment-injection-nested-comment.schema` specifically covers an unmatched Elm/Haskell nested-comment opener (`{-`) in object and property descriptions.

The existing `JSONSchemaFixture` instances pick these samples up for schema-based language tests. Additional narrow `comment-injection-*` fixtures cover affected outputs that did not already have full schema fixtures: Objective-C uses both samples; TypeScript-Zod and TypeScript-Effect-Schema use only the enum-description sample.

A parser-only fixture, `comment-injection-treesitter`, generates all configured targets and parses them with tree-sitter WASM grammars. It currently covers TypeScript, TypeScript-Zod, TypeScript-Effect-Schema, Swift, C#, Java, Dart, C (`cjson`), C++, PHP, Kotlin, Go, Pike, Rust, Ruby, Python, Elixir, Scala 3, and Haskell. It is intentionally one fixture/test that loops over all configured languages and reports all parse failures together. The Swift, Dart, Kotlin, Pike, and Elixir grammars are vendored under `test/tree-sitter-wasms` to avoid npm peer/native dependency issues in CI.

These are regression tests and should pass with the shared comment escaping/sanitization in place.
Loading
Loading