Skip to content

Generate compiler option definitions, create JSON schema - #64457

Draft
Jake Bailey (jakebailey) wants to merge 16 commits into
microsoft:mainfrom
jakebailey:generate-compiler-options
Draft

Jake Bailey (jakebailey) wants to merge 16 commits into
microsoft:mainfrom
jakebailey:generate-compiler-options

Conversation

@jakebailey

@jakebailey Jake Bailey (jakebailey) commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

For the new website playground, I need some sort of spec for our CompilerOptions. In Strada, this was done by parsing out at runtime our internal options declarations and turning that into a website UI and JSON schema (if we remembered to do it), which then would eventually get sent over to schemastore (if we remembered to do it...), and then eventually make it into VS Code etc (if we remembered to do it........).

Instead, let's just define our options as metadata like we do the AST and other stuff, then code generate all of the Go code, TS code, and even our own JSON schema files. #54192 is a long-open issue requesting that we ship a JSON schema with the package, so, this PR also adds that file to the package too so node_modules/typescript/schemas/tsconfig.schema.json is now valid. Eventually, we can use this in our VSIX, I think, though historically that one's been more permissive of dead options.

A good bonus is that we can now codegen CompilerOptions.Clone, parseCompilerOptions, the transpile options clearing func, and more.

Fixes #54192

Compiler option metadata is duplicated across compiler declarations, API
types, enum mappings, and configuration schemas. Maintaining these
surfaces independently makes new options and compatibility changes easy
to miss.

Use one authoritative definition so these surfaces stay synchronized,
while preserving compiler behavior and providing reusable config
schemas.
Single-file transpilation must ignore options that only make sense for
whole-program builds. Keeping a separate clearing list lets it drift
from the existing transpile metadata whenever options are added.

Derive the clearing list from that metadata while leaving mode-specific
overrides and conditional behavior in the transpile worker.
Option enums and SyntaxKind already have authoritative metadata. Reading
generated Go back into the TypeScript generator adds an unnecessary
intermediate representation and points contributors at the wrong source.

Use those definitions directly while retaining one shared enum emitter
and Go-value verification for every input source.
Ship version-matched configuration schemas with the main package so tools
can use the installed compiler version without relying on a hosted schema.
Comment on lines +41 to +42
"./schemas/tsconfig.schema.json": "./schemas/tsconfig.schema.json",
"./schemas/jsconfig.schema.json": "./schemas/jsconfig.schema.json",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generated these into tsc/internal/tsoptions/schemas. Perhaps I should have just checked them in here?

Comment thread tools/scripts/tsc/options.ts Outdated
Comment thread tsc/internal/core/buildoptions_generated.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The schemas incorrectly deprecate active compiler options and lose draft-07 $ref sibling documentation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity · 2 Low severity

Open (3)
What changed in this PR

Centralizes compiler-option metadata to generate Go/TypeScript definitions and publish version-matched configuration schemas.

Changes:

  • Generates option structs, parsers, enums, maps, defaults, and transpile handling.
  • Adds generated tsconfig/jsconfig schemas to the npm package.
  • Expands code-generation, schema, packaging, and compatibility tests.
File Description
Herebyfile.mjs Integrates generation, validation, and schema packaging.
packages/​typescript/​package.json Exports packaged schemas.
packages/​typescript/​src/​enums/​jsxEmit.enum.ts Updates generation source.
packages/​typescript/​src/​enums/​jsxEmit.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleDetectionKind.enum.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleDetectionKind.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleKind.enum.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleKind.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleResolutionKind.enum.ts Updates generation source.
packages/​typescript/​src/​enums/​moduleResolutionKind.ts Updates generation source.
packages/​typescript/​src/​enums/​newLineKind.enum.ts Updates generation source.
packages/​typescript/​src/​enums/​newLineKind.ts Updates generation source.
packages/​typescript/​src/​enums/​scriptTarget.enum.ts Makes ScriptTarget metadata-generated.
packages/​typescript/​src/​enums/​scriptTarget.ts Makes ScriptTarget metadata-generated.
packages/​typescript/​src/​enums/​syntaxKind.enum.ts Generates from AST metadata.
packages/​typescript/​src/​enums/​syntaxKind.ts Generates from AST metadata.
tools/​scripts/​gen/​generatedFile.test.mts Extends code-generation tests.
tools/​scripts/​tsc/​generate-enums.ts Generates enums from shared metadata.
tools/​scripts/​tsc/​generate-options.ts Adds the option artifact generator.
tools/​scripts/​tsc/​options-model.ts Defines shared metadata types.
tools/​scripts/​tsc/​options-schema.ts Generates configuration schemas.
tools/​scripts/​tsc/​options.test.ts Tests metadata and generated artifacts.
tools/​scripts/​tsc/​options.ts Centralizes option metadata.
tsc/​internal/​api/​enum_values_generated.go Adds generated option enum values.
tsc/​internal/​core/​buildoptions_generated.go Marks build options as generated.
tsc/​internal/​core/​compileroptions.go Removes moved generated definitions.
tsc/​internal/​core/​compileroptions_generated.go Generates CompilerOptions and cloning.
tsc/​internal/​core/​optionenums_generated.go Generates option enums.
tsc/​internal/​core/​typeacquisition.go Removes moved struct definition.
tsc/​internal/​core/​typeacquisition_generated.go Generates TypeAcquisition.
tsc/​internal/​core/​watchoptions.go Removes moved option definitions.
tsc/​internal/​core/​watchoptions_generated.go Generates WatchOptions.
tsc/​internal/​transpile/​compileroptions_generated.go Generates transpile option clearing.
tsc/​internal/​transpile/​options_test.go Tests transpile option isolation.
tsc/​internal/​transpile/​transpile.go Uses generated option clearing.
tsc/​internal/​tsoptions/​commandlineoption.go Removes generated maps.
tsc/​internal/​tsoptions/​compileroptions_generated.go Generates parsing and defaults.
tsc/​internal/​tsoptions/​compileroptions_test.go Tests parsing and cloning.
tsc/​internal/​tsoptions/​declarations_generated.go Generates option declarations.
tsc/​internal/​tsoptions/​declsbuild.go Removes superseded declarations.
tsc/​internal/​tsoptions/​declscompiler.go Retains declaration consumers.
tsc/​internal/​tsoptions/​declstypeacquisition.go Removes superseded declarations.
tsc/​internal/​tsoptions/​declswatch.go Removes superseded declarations.
tsc/​internal/​tsoptions/​enummaps.go Removes generated enum maps.
tsc/​internal/​tsoptions/​enummaps_generated.go Generates enum and library maps.
tsc/​internal/​tsoptions/​otheroptions_generated.go Generates auxiliary parsers.
tsc/​internal/​tsoptions/​parsinghelpers.go Removes generated parsers.
tsc/​internal/​tsoptions/​rootoptions_generated.go Generates root config declarations.
tsc/​internal/​tsoptions/​schemas/​jsconfig.schema.json Adds generated jsconfig schema.
tsc/​internal/​tsoptions/​schemas/​tsconfig.schema.json Adds generated tsconfig schema.
tsc/​internal/​tsoptions/​tsconfigparsing.go Removes generated declarations/defaults.
Files not reviewed (4)
  • tsc/internal/api/enum_values_generated.go: Generated file
  • tsc/internal/core/compileroptions_generated.go: Generated file
  • tsc/internal/core/optionenums_generated.go: Generated file
  • tsc/internal/core/typeacquisition_generated.go: Generated file

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +177 to +180
if (option.deprecated) {
schema.deprecated = true;
schema.deprecationMessage = "This compiler option is deprecated.";
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, knowledge cutoff

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That being said, perhaps I should restore es3/es5 just for the schema, or other options...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And then going forward we only ever add to the schema for back compat?

Comment thread tools/scripts/tsc/options-schema.ts Outdated
Comment thread tools/scripts/tsc/options-schema.ts Outdated
Comment thread tsc/internal/tsoptions/declscompiler.go Outdated
Use diagnostic message keys for completion and typo checking instead of
untyped Go identifier strings. Preserve the original text for schema
output without a separate diagnostic lookup or generation step.
Draft-07 ignores siblings of a reference. Keep root option descriptions
outside the reference so consumers retain their documentation and links.
Keep the distinction between build options and compiler options visible
in the generated struct, as it was before generation.
Option metadata already identifies which fields affect diagnostics, emit,
declaration paths, and build info. Use it to avoid runtime reflection
without maintaining another handwritten list of fields.

Preserve effective strict defaults and build-info ordering and zero-value
semantics, with the previous reflection logic retained as a test oracle.
The option metadata already describes every field and its JSON name.
Use it to avoid reflective field access and tag parsing during config
merging while keeping new options covered automatically.

Preserve explicit-null overrides, nonzero source precedence, and shallow
sharing of slices and pointers.
@jakebailey
Jake Bailey (jakebailey) marked this pull request as draft September 26, 2026 02:32
Keep config directory substitution aligned with option metadata instead
of maintaining a separate handwritten field list. Explicitly exclude
project and pprofDir, preserving the existing substitution behavior and
copy-on-write semantics.

Keep substitution eligibility out of runtime declarations, narrow the
prefix helper to strings, and note the existing case-sensitivity mismatch
between prefix detection and replacement.
Reduce handwritten serialization machinery by deriving field handling
and enum names from the existing option metadata. This keeps option
coverage centralized and makes field access statically checked rather
than relying on reflection and runtime assertions.

Preserve output ordering, enum aliases, and unset-value behavior while
retaining handwritten formatting helpers and implied-option rules.
Keep whole-options equality aligned with the option definitions without
runtime reflection. Preserve stored values, pointer contents, collection
ordering, and nil-versus-empty distinctions.

Compare paths by their ordered entries rather than ordered-map backing
storage, so allocation history does not cause spurious project changes.
Aggregate reflection bypassed compiler option equality, making watch mode
sensitive to ordered-map backing storage that the project system ignores.
Compose option equality methods so both callers honor the same semantics.

Treat absent and empty type acquisition lists alike, matching their
existing acquisition behavior, while retaining other presence and order
distinctions.
Handwritten equality can silently overlook fields added to parsed options
or content mappers. Require every field to have a populated test value
whose removal changes equality, including promoted mapper fields.
Per-feature outputs fragmented related option code across too many files.
Group generated code by package, retaining a separate declarations file
in tsoptions, and keep compiler option tests together.

This reduces file proliferation without changing generated declarations
or test coverage.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The published schema advertises watchOptions, but tsconfig parsing does not recognize or populate them.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
Resolved since last review (2)
Files not reviewed (1)
  • tsc/internal/api/enum_values_generated.go: Generated file

};
const properties: Record<string, JSONSchema> = {
$schema: { type: "string", description: "The JSON schema used to validate this configuration." },
watchOptions: withDescription({ allOf: [{ $ref: "#/definitions/watchOptions" }] }, "Options for watching files and directories.", "watchOptions"),

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

Add JSON schema to the typescript package for tsconfig.json and jsconfig.json

2 participants