Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
42 changes: 35 additions & 7 deletions Herebyfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { task } from "hereby";
import assert from "node:assert";
import crypto from "node:crypto";
import fs from "node:fs";
import { createRequire } from "node:module";
import os from "node:os";
import path from "node:path";
import url from "node:url";
Expand Down Expand Up @@ -472,10 +473,18 @@ export const generateChecker = goGenerateTask("generate:checker", [
stringerGenerator("tsc/internal/checker/types.go", "SignatureKind", "stringer_generated.go"),
]);

export const generateCompilerOptions = goGenerateTask("generate:compileroptions", [
stringerGenerator("tsc/internal/core/compileroptions.go", "ModuleKind", "modulekind_stringer_generated.go", "ModuleKind"),
stringerGenerator("tsc/internal/core/compileroptions.go", "ScriptTarget", "scripttarget_stringer_generated.go", "ScriptTarget"),
]);
async function runGenerateOptionDefinitions() {
const { default: generate } = await import("./tools/scripts/tsc/generate-options.ts");
await generate(!!options.force);
}

export const generateCompilerOptions = goGenerateTask("generate:compileroptions", async () => {
await runGenerateOptionDefinitions();
await runGoGenerator("generate:compileroptions", stringerGenerator("tsc/internal/core/options_generated.go", "ModuleKind", "modulekind_stringer_generated.go", "ModuleKind"));
await runGoGenerator("generate:compileroptions", stringerGenerator("tsc/internal/core/options_generated.go", "ScriptTarget", "scripttarget_stringer_generated.go", "ScriptTarget"));
await runGenerateEnums();
await runGenerateAPI();
});

export const generateLanguageVariant = goGenerateTask("generate:languagevariant", [
stringerGenerator("tsc/internal/core/languagevariant.go", "LanguageVariant", "languagevariant_stringer_generated.go"),
Expand Down Expand Up @@ -628,7 +637,7 @@ async function runGenerateEnums() {

export const generateEnums = task({
name: "generate:enums",
description: "Generates TypeScript enum files from Go source. Pass --force to regenerate unchanged files.",
description: "Generates TypeScript enums from metadata and Go source. Pass --force to regenerate unchanged files.",
run: runGenerateEnums,
});

Expand Down Expand Up @@ -656,6 +665,7 @@ export const generateSync = task({
});

async function runGenerateAPI() {
await runGenerateOptionDefinitions();
await runGoGenerator("generate:api", {
file: "tsc/internal/api/proto.go",
cwd: __dirname,
Expand All @@ -668,7 +678,7 @@ async function runGenerateAPI() {
"tsc/internal/tspath/path.go",
"tools/gen-proto/*.go",
],
exclude: ["**/*_test.go", "**/*_generated.go"],
exclude: ["**/*_test.go"],
envInputs: [],
outputs: ["packages/typescript/src/api/proto.generated.ts"],
commands: [
Expand Down Expand Up @@ -964,7 +974,7 @@ export const testCodegen = task({
description: "Runs incremental codegen tests.",
run: async () => {
await run("go", ["-C", "tsc", "mod", "download"]);
await run("node", ["--test", "--test-concurrency=1", "./tools/scripts/gen/*.test.mts"]);
await run("node", ["--test", "--test-concurrency=1", "./tools/scripts/gen/*.test.mts", "./tools/scripts/tsc/*.test.ts"]);
},
});

Expand Down Expand Up @@ -1170,6 +1180,9 @@ export const validate = task({
}
if (options.all) {
await runValidation("test:tools", runTestTools);
await runValidation("test:options", async () => {
await run("node", ["--test", "./tools/scripts/tsc/options.test.ts"]);
});
await runValidation("test:smoke", runSmokeTest); // in CI this is run with `--race`
}
await runValidation("lint", runLint);
Expand Down Expand Up @@ -2237,6 +2250,7 @@ async function runBuildNativePreviewPackages() {
// Copy package contents excluding node_modules and dist (dist is copied separately after build).
// The package.json "files" field controls what npm pack actually includes.
await cpRecursive(inputDir, mainPackageDir, p => !p.endsWith("/node_modules") && !p.includes("/dist"));
await cpRecursive("tsc/internal/tsoptions/schemas", path.join(mainPackageDir, "schemas"));
if (publishAsTypescript) {
await fs.promises.writeFile(path.join(mainPackageDir, "bin", "tsc"), '#!/usr/bin/env node\nimport "../lib/tsc.js";\n');
await fs.promises.chmod(path.join(mainPackageDir, "bin", "tsc"), 0o755);
Expand Down Expand Up @@ -2354,6 +2368,20 @@ async function testNativePreviewPackage(platforms) {
await cpRecursive(hostPlatform.npmDir, platformPackageDir);
await fs.promises.writeFile(sourceFile, 'export const value: string = "value";\n');

const require = createRequire(sourceFile);
const { stdout } = await runOutput("npm", ["pack", "--dry-run", "--json", mainPackageDir]);
/** @type {{ files: { path: string }[] }[]} */
const packed = JSON.parse(stdout);
for (const name of ["tsconfig", "jsconfig"]) {
const schemaPath = `schemas/${name}.schema.json`;
assert(packed[0].files.some(file => file.path === schemaPath), `Package is missing ${schemaPath}`);
assert.deepEqual(
await fs.promises.readFile(path.join(mainPackageDir, schemaPath)),
await fs.promises.readFile(path.join("tsc/internal/tsoptions/schemas", `${name}.schema.json`)),
);
assert.equal(require.resolve(`${mainNativePreviewPackage.npmPackageName}/${schemaPath}`), path.join(mainPackageDir, schemaPath));
}

const binName = publishAsTypescript ? "tsc" : "tsgo";
const binPath = path.join(mainPackageDir, "bin", binName);
const { stdout: versionOutput } = await runOutput(process.execPath, [binPath, "--version"]);
Expand Down
3 changes: 3 additions & 0 deletions packages/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"files": [
"bin",
"lib",
"schemas",
"dist",
"vendor"
],
Expand All @@ -37,6 +38,8 @@
},
"exports": {
"./package.json": "./package.json",
"./schemas/tsconfig.schema.json": "./schemas/tsconfig.schema.json",
"./schemas/jsconfig.schema.json": "./schemas/jsconfig.schema.json",
Comment on lines +41 to +42

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?

".": "./lib/version.cjs",
"./unstable/sync": {
"@typescript/source": "./src/api/sync/api.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/jsxEmit.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum JsxEmit {
None = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/jsxEmit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var JsxEmit: any;
(function (JsxEmit) {
JsxEmit[JsxEmit["None"] = 0] = "None";
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleDetectionKind.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum ModuleDetectionKind {
None = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleDetectionKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var ModuleDetectionKind: any;
(function (ModuleDetectionKind) {
ModuleDetectionKind[ModuleDetectionKind["None"] = 0] = "None";
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleKind.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum ModuleKind {
None = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var ModuleKind: any;
(function (ModuleKind) {
ModuleKind[ModuleKind["None"] = 0] = "None";
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleResolutionKind.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum ModuleResolutionKind {
Unknown = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/moduleResolutionKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var ModuleResolutionKind: any;
(function (ModuleResolutionKind) {
ModuleResolutionKind[ModuleResolutionKind["Unknown"] = 0] = "Unknown";
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/newLineKind.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum NewLineKind {
None = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/newLineKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/core/compileroptions.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var NewLineKind: any;
(function (NewLineKind) {
NewLineKind[NewLineKind["None"] = 0] = "None";
Expand Down
2 changes: 2 additions & 0 deletions packages/typescript/src/enums/scriptTarget.enum.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.

export enum ScriptTarget {
ES2015 = 2,
ES2016 = 3,
Expand Down
1 change: 1 addition & 0 deletions packages/typescript/src/enums/scriptTarget.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/options.ts. DO NOT EDIT.
export var ScriptTarget: any;
(function (ScriptTarget) {
ScriptTarget[ScriptTarget["ES2015"] = 2] = "ES2015";
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/syntaxKind.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/ast/kind_generated.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/ast.json. DO NOT EDIT.

export enum SyntaxKind {
Unknown = 0,
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/enums/syntaxKind.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Code generated by tools/scripts/tsc/generate-enums.ts from tsc/internal/ast/kind_generated.go. DO NOT EDIT.
// Code generated by tools/scripts/tsc/generate-enums.ts from tools/scripts/tsc/ast.json. DO NOT EDIT.
export var SyntaxKind: any;
(function (SyntaxKind) {
SyntaxKind[SyntaxKind["Unknown"] = 0] = "Unknown";
Expand Down
26 changes: 24 additions & 2 deletions tools/scripts/gen/generatedFile.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ test("validate generates before building and selects the generation scope", asyn
runTestAPI: action("test:api"),
runTestBenchmarks: action("test:benchmarks"),
runTestTools: action("test:tools"),
run: async (command: string, args: string[]) => {
assert.equal(command, "node");
assert.deepEqual(Array.from(args), ["--test", "./tools/scripts/tsc/options.test.ts"]);
calls.push("test:options");
},
runSmokeTest: action("test:smoke"),
runLint: action("lint"),
runFormat: action("format"),
Expand All @@ -71,6 +76,7 @@ test("validate generates before building and selects the generation scope", asyn
assert.ok(calls.indexOf("build") < calls.indexOf("test:tsc"));
assert.equal(calls.includes("test:api"), "api" in options || "all" in options);
assert.equal(calls.includes("test:tools"), "all" in options);
assert.equal(calls.includes("test:options"), "all" in options);
if ("all" in options) {
assert.deepEqual(calls.filter(name => name.startsWith("generate")), ["generate"]);
}
Expand Down Expand Up @@ -349,7 +355,7 @@ test("generate:go runs Go generators directly and shares caches with Go fallback
const generate = () => x("npx", ["hereby", "generate:go"], { throwOnError: true, nodeOptions: { cwd: root } });
const first = await generate();
assert.doesNotMatch(first.stdout, /\$ go generate|npm run --silent cache|\$ node .*generate-unicode-data/);
const files = fs.globSync(["tsc/internal/**/*generated.go", "packages/typescript/src/api/proto.generated.ts"], { cwd: root });
const files = fs.globSync(["tsc/internal/**/*generated.go", "packages/typescript/src/api/proto.generated.ts", "packages/typescript/src/enums/*.ts", "tsc/internal/tsoptions/schemas/*.schema.json"], { cwd: root });
const timestamps = files.map(file => fs.statSync(path.join(root, file)).mtimeMs);
const current = await generate();
assert.doesNotMatch(current.stdout, /Generated codegen outputs|Generated Unicode tables/);
Expand All @@ -358,7 +364,8 @@ test("generate:go runs Go generators directly and shares caches with Go fallback
const fallback = await x("go", ["-C", "./tsc", "generate", "./internal/diagnostics"], { throwOnError: true, nodeOptions: { cwd: root } });
assert.equal(fallback.stdout.match(/codegen outputs are already up to date/g)?.length, 2);
const nested = await x("npx", ["hereby", "generate:compileroptions"], { throwOnError: true, nodeOptions: { cwd: path.join(root, "tsc/internal/core") } });
assert.equal(nested.stdout.match(/codegen outputs are already up to date/g)?.length, 2);
assert.equal(nested.stdout.match(/codegen outputs are already up to date/g)?.length, 3);
assert.match(nested.stdout, /Enums are up to date/);
});

test("generate includes standalone generators without Go traversal", async () => {
Expand Down Expand Up @@ -778,6 +785,21 @@ test("enum generation skips unchanged outputs and Go verification", async () =>
const regenerated = await generate();
assert.match(regenerated.stdout, /All generated values match Go\./);
assert.match((await generate()).stdout, /Enums are up to date\./);

const astSchema = path.join(root, "tools/scripts/tsc/ast.json");
const originalSchema = fs.readFileSync(astSchema, "utf8");
const goKinds = path.join(root, "tsc/internal/ast/kind_generated.go");
const goKindsTimestamp = fs.statSync(goKinds).mtimeMs;
try {
fs.writeFileSync(astSchema, originalSchema + "\n");
assert.match((await generate()).stdout, /All generated values match Go\./);
assert.equal(fs.statSync(goKinds).mtimeMs, goKindsTimestamp);
assert.match((await generate()).stdout, /Enums are up to date\./);
}
finally {
fs.writeFileSync(astSchema, originalSchema);
await generate();
}
});

test("AST generation forwards force to schema generators and the kind stringer", async () => {
Expand Down
Loading
Loading