tsifdef 1.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/CHANGELOG.zh-CN.md +22 -0
  3. package/CONTRIBUTING.md +52 -0
  4. package/INTEGRATION.md +166 -0
  5. package/INTEGRATION.zh-CN.md +159 -0
  6. package/LICENSE +210 -0
  7. package/README.md +150 -0
  8. package/README.zh-CN.md +141 -0
  9. package/SECURITY.md +15 -0
  10. package/assets/icon-mono.svg +15 -0
  11. package/assets/icon.png +0 -0
  12. package/assets/icon.svg +16 -0
  13. package/dist/cli/build.d.ts +70 -0
  14. package/dist/cli/build.js +298 -0
  15. package/dist/cli/config.d.ts +30 -0
  16. package/dist/cli/config.js +135 -0
  17. package/dist/cli/diagnostics.d.ts +3 -0
  18. package/dist/cli/diagnostics.js +31 -0
  19. package/dist/cli/index.d.ts +6 -0
  20. package/dist/cli/index.js +35 -0
  21. package/dist/cli/main.d.ts +9 -0
  22. package/dist/cli/main.js +165 -0
  23. package/dist/cli/precompile.d.ts +38 -0
  24. package/dist/cli/precompile.js +192 -0
  25. package/dist/cli/source-files.d.ts +10 -0
  26. package/dist/cli/source-files.js +75 -0
  27. package/dist/cli/watch.d.ts +34 -0
  28. package/dist/cli/watch.js +183 -0
  29. package/dist/core/conditional.d.ts +18 -0
  30. package/dist/core/conditional.js +126 -0
  31. package/dist/core/expression.d.ts +44 -0
  32. package/dist/core/expression.js +224 -0
  33. package/dist/core/index.d.ts +7 -0
  34. package/dist/core/index.js +37 -0
  35. package/dist/core/projection.d.ts +15 -0
  36. package/dist/core/projection.js +99 -0
  37. package/dist/core/scanner.d.ts +33 -0
  38. package/dist/core/scanner.js +344 -0
  39. package/dist/eslint/package.d.ts +10 -0
  40. package/dist/eslint/package.js +55 -0
  41. package/dist/eslint/parser.d.ts +35 -0
  42. package/dist/eslint/parser.js +59 -0
  43. package/dist/eslint/plugin.d.ts +78 -0
  44. package/dist/eslint/plugin.js +229 -0
  45. package/dist/eslint/projection.d.ts +11 -0
  46. package/dist/eslint/projection.js +116 -0
  47. package/dist/tsserver/host-projection.d.ts +45 -0
  48. package/dist/tsserver/host-projection.js +160 -0
  49. package/dist/tsserver/index.d.ts +3 -0
  50. package/dist/tsserver/index.js +32 -0
  51. package/dist/tsserver/plugin.d.ts +15 -0
  52. package/dist/tsserver/plugin.js +129 -0
  53. package/dist/tsserver/project-controller.d.ts +37 -0
  54. package/dist/tsserver/project-controller.js +60 -0
  55. package/dist/version.d.ts +3 -0
  56. package/dist/version.js +20 -0
  57. package/dist/vscode/document-analysis.d.ts +62 -0
  58. package/dist/vscode/document-analysis.js +111 -0
  59. package/dist/vscode/extension.d.ts +133 -0
  60. package/dist/vscode/extension.js +241 -0
  61. package/dist/vscode/host.d.ts +79 -0
  62. package/dist/vscode/host.js +16 -0
  63. package/dist/vscode/index.d.ts +7 -0
  64. package/dist/vscode/index.js +36 -0
  65. package/dist/vscode/macro-presentation.d.ts +43 -0
  66. package/dist/vscode/macro-presentation.js +130 -0
  67. package/dist/vscode/package-profile.d.ts +27 -0
  68. package/dist/vscode/package-profile.js +142 -0
  69. package/dist/vscode/profile-state.d.ts +22 -0
  70. package/dist/vscode/profile-state.js +81 -0
  71. package/package.json +129 -0
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // Copyright (C) 2026 Tencent. All rights reserved.
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.CliExitCode = void 0;
18
+ exports.runCli = runCli;
19
+ const node_path_1 = require("node:path");
20
+ const build_js_1 = require("./build.js");
21
+ const config_js_1 = require("./config.js");
22
+ const precompile_js_1 = require("./precompile.js");
23
+ const watch_js_1 = require("./watch.js");
24
+ exports.CliExitCode = {
25
+ success: 0,
26
+ diagnostics: 1,
27
+ failure: 2,
28
+ };
29
+ /** Run the TSIfDef CLI: `build` for projected compilation, else legacy precompile. */
30
+ async function runCli(args, cwd = process.cwd()) {
31
+ if (args[0] === "build") {
32
+ return runBuild(args.slice(1), cwd);
33
+ }
34
+ return runPrecompile(args, cwd);
35
+ }
36
+ /**
37
+ * `tsifdef build [--watch] [--emit-projection <dir>] [-p <tsconfig>] [-- <tsc flags>]`.
38
+ * Flags after `--` are parsed as tsc compiler-option overrides (e.g.
39
+ * `-- --module commonjs --outDir dist`), mirroring how a build pipeline would
40
+ * pass per-invocation options to `tsc`.
41
+ */
42
+ async function runBuild(args, cwd) {
43
+ const separatorIndex = args.indexOf("--");
44
+ const ownArgs = separatorIndex >= 0 ? args.slice(0, separatorIndex) : args;
45
+ const overrideArgs = separatorIndex >= 0 ? args.slice(separatorIndex + 1) : [];
46
+ const watch = ownArgs.includes("--watch");
47
+ let emitProjectionDir;
48
+ const rest = [];
49
+ for (let index = 0; index < ownArgs.length; index += 1) {
50
+ const arg = ownArgs[index];
51
+ if (arg === "--watch")
52
+ continue;
53
+ if (arg === "--emit-projection") {
54
+ const value = ownArgs[index + 1];
55
+ if (value === undefined || value.trim() === "") {
56
+ process.stderr.write("Usage: tsifdef build [--emit-projection <dir>]\n");
57
+ return exports.CliExitCode.failure;
58
+ }
59
+ emitProjectionDir = (0, node_path_1.resolve)(cwd, value);
60
+ index += 1;
61
+ continue;
62
+ }
63
+ rest.push(arg);
64
+ }
65
+ try {
66
+ const project = parseProjectOption(rest, "Usage: tsifdef build [--watch] [--emit-projection <dir>] [-p <tsconfig>] [-- <tsc flags>]");
67
+ const compilerOptionsOverride = await (0, build_js_1.parseTscOverride)(overrideArgs, cwd);
68
+ const projectRoot = (0, node_path_1.resolve)(cwd);
69
+ const configuration = await (0, config_js_1.loadProjectConfiguration)(projectRoot);
70
+ const profile = await (0, config_js_1.loadProfileFile)(configuration.profilePath);
71
+ if (watch) {
72
+ await (0, watch_js_1.watchProject)({
73
+ projectRoot,
74
+ project: project ?? "tsconfig.json",
75
+ profilePath: configuration.profilePath,
76
+ compilerOptionsOverride,
77
+ ...(emitProjectionDir === undefined ? {} : { emitProjectionDir }),
78
+ onBuild: (info) => {
79
+ process.stdout.write(info.hasErrors
80
+ ? `Rebuilt with errors (${info.macroDiagnostics.size} macro issue(s)).\n`
81
+ : `Rebuilt ${info.outputFiles.length} file(s).\n`);
82
+ },
83
+ onProfileReload: (reloaded) => {
84
+ process.stdout.write(`Profile changed to ${reloaded.fileName}; rebuilding.\n`);
85
+ },
86
+ });
87
+ // Watch mode runs until the process is terminated.
88
+ return await new Promise(() => { });
89
+ }
90
+ const result = await (0, build_js_1.buildProject)({
91
+ projectRoot,
92
+ project: project ?? "tsconfig.json",
93
+ profile,
94
+ compilerOptionsOverride,
95
+ ...(emitProjectionDir === undefined ? {} : { emitProjectionDir }),
96
+ });
97
+ if (result.hasErrors) {
98
+ return exports.CliExitCode.diagnostics;
99
+ }
100
+ process.stdout.write(`Built ${result.outputFiles.length} file(s) with ${profile.fileName}.\n`);
101
+ return exports.CliExitCode.success;
102
+ }
103
+ catch (error) {
104
+ if (error instanceof build_js_1.BuildMacroDiagnosticsError) {
105
+ for (const file of error.files) {
106
+ for (const diagnostic of file.diagnostics) {
107
+ process.stderr.write(`${file.file}:${diagnostic.range.start}: ${diagnostic.message}\n`);
108
+ }
109
+ }
110
+ return exports.CliExitCode.diagnostics;
111
+ }
112
+ if (error instanceof build_js_1.BuildUnsupportedError) {
113
+ process.stderr.write(`${error.message}\n`);
114
+ return exports.CliExitCode.failure;
115
+ }
116
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
117
+ return exports.CliExitCode.failure;
118
+ }
119
+ }
120
+ /** Legacy `tsifdef [--project <tsconfig>]`: emit the auditable projected project. */
121
+ async function runPrecompile(args, cwd) {
122
+ try {
123
+ const project = parseProjectOption(args, "Usage: tsifdef [--project <tsconfig>]");
124
+ const projectRoot = (0, node_path_1.resolve)(cwd);
125
+ const configuration = await (0, config_js_1.loadProjectConfiguration)(projectRoot);
126
+ const profile = await (0, config_js_1.loadProfileFile)(configuration.profilePath);
127
+ const result = await (0, precompile_js_1.precompileProject)({
128
+ projectRoot,
129
+ project: project ?? "tsconfig.json",
130
+ profile,
131
+ });
132
+ process.stdout.write(`Precompiled ${result.manifest.files.length} file(s) with ${profile.fileName} to ${result.outputRoot}\n`);
133
+ return exports.CliExitCode.success;
134
+ }
135
+ catch (error) {
136
+ if (error instanceof precompile_js_1.PrecompileDiagnosticsError) {
137
+ for (const file of error.files) {
138
+ for (const diagnostic of file.diagnostics) {
139
+ process.stderr.write(`${file.file}:${diagnostic.range.start}: ${diagnostic.message}\n`);
140
+ }
141
+ }
142
+ return exports.CliExitCode.diagnostics;
143
+ }
144
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
145
+ return exports.CliExitCode.failure;
146
+ }
147
+ }
148
+ /** Accept both `--project <path>` and `-p <path>`; otherwise no override. */
149
+ function parseProjectOption(args, usage) {
150
+ if (args.length === 0)
151
+ return undefined;
152
+ if (args.length === 2 &&
153
+ (args[0] === "--project" || args[0] === "-p") &&
154
+ args[1] !== undefined &&
155
+ args[1].trim() !== "") {
156
+ return args[1];
157
+ }
158
+ throw new Error(usage);
159
+ }
160
+ if (require.main === module) {
161
+ void runCli(process.argv.slice(2)).then((code) => {
162
+ process.exitCode = code;
163
+ });
164
+ }
165
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1,38 @@
1
+ import type { ProfileFile } from "./config.js";
2
+ export interface PrecompileOptions {
3
+ readonly projectRoot: string;
4
+ readonly project: string;
5
+ readonly profile: ProfileFile;
6
+ }
7
+ export interface PrecompileManifestFile {
8
+ readonly source: string;
9
+ readonly projected: string;
10
+ readonly sourceHash: string;
11
+ readonly projectedHash: string;
12
+ }
13
+ export interface PrecompileManifest {
14
+ readonly schemaVersion: 1;
15
+ readonly toolVersion: string;
16
+ readonly profileFile: string;
17
+ readonly profileHash: string;
18
+ readonly sourceProject: string;
19
+ readonly generatedProject: string;
20
+ readonly files: readonly PrecompileManifestFile[];
21
+ }
22
+ export interface PrecompileResult {
23
+ readonly outputRoot: string;
24
+ readonly projectPath: string;
25
+ readonly manifest: PrecompileManifest;
26
+ }
27
+ export interface PrecompileFileDiagnostic {
28
+ readonly file: string;
29
+ readonly diagnostics: readonly import("../core/index.js").MacroDiagnostic[];
30
+ }
31
+ export declare class PrecompileDiagnosticsError extends Error {
32
+ readonly files: readonly PrecompileFileDiagnostic[];
33
+ readonly code: "precompile-diagnostics";
34
+ constructor(files: readonly PrecompileFileDiagnostic[]);
35
+ }
36
+ /** Emit an auditable projected project derived from the original TypeScript Program. */
37
+ export declare function precompileProject(options: PrecompileOptions): Promise<PrecompileResult>;
38
+ //# sourceMappingURL=precompile.d.ts.map
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ // Copyright (C) 2026 Tencent. All rights reserved.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.PrecompileDiagnosticsError = void 0;
17
+ exports.precompileProject = precompileProject;
18
+ const node_crypto_1 = require("node:crypto");
19
+ const node_fs_1 = require("node:fs");
20
+ const promises_1 = require("node:fs/promises");
21
+ const node_path_1 = require("node:path");
22
+ const index_js_1 = require("../core/index.js");
23
+ const source_files_js_1 = require("./source-files.js");
24
+ class PrecompileDiagnosticsError extends Error {
25
+ files;
26
+ code = "precompile-diagnostics";
27
+ constructor(files) {
28
+ super(`Cannot precompile because ${files.length} source file(s) have macro diagnostics.`);
29
+ this.files = files;
30
+ this.name = "PrecompileDiagnosticsError";
31
+ }
32
+ }
33
+ exports.PrecompileDiagnosticsError = PrecompileDiagnosticsError;
34
+ const macroFilePattern = /(?:\.d)?\.(?:ts|tsx|mts|cts)$/i;
35
+ /** Emit an auditable projected project derived from the original TypeScript Program. */
36
+ async function precompileProject(options) {
37
+ const ts = (await import("typescript")).default;
38
+ const projectRoot = (0, node_path_1.resolve)(options.projectRoot);
39
+ const sourceProject = (0, node_path_1.resolve)(projectRoot, options.project);
40
+ const outputRoot = (0, node_path_1.resolve)(projectRoot, ".tsifdef", "Output");
41
+ const configFile = ts.readConfigFile(sourceProject, ts.sys.readFile);
42
+ if (configFile.error !== undefined)
43
+ throw new Error(formatDiagnostic(ts, configFile.error));
44
+ const parsed = ts.parseJsonConfigFileContent(configFile.config, ts.sys, (0, node_path_1.dirname)(sourceProject), undefined, sourceProject);
45
+ if (parsed.errors.length > 0)
46
+ throw new Error(parsed.errors.map((item) => formatDiagnostic(ts, item)).join("\n"));
47
+ const projected = new Map();
48
+ const failures = [];
49
+ const host = ts.createCompilerHost(parsed.options, true);
50
+ const readProjected = (fileName) => {
51
+ if (!macroFilePattern.test(fileName))
52
+ return ts.sys.readFile(fileName);
53
+ const absolute = (0, node_path_1.resolve)(fileName);
54
+ const cached = projected.get(absolute);
55
+ if (cached !== undefined)
56
+ return cached.projected;
57
+ const sourceBytes = (0, node_fs_1.readFileSync)(absolute);
58
+ const source = (0, source_files_js_1.decodeTypeScriptText)(sourceBytes);
59
+ const result = (0, index_js_1.projectSource)(source, options.profile.definitions);
60
+ if (result.diagnostics.length > 0) {
61
+ failures.push({ file: (0, node_path_1.relative)(projectRoot, absolute), diagnostics: result.diagnostics });
62
+ }
63
+ projected.set(absolute, { source, sourceHash: hash(sourceBytes), projected: result.projectedText });
64
+ return result.projectedText;
65
+ };
66
+ host.readFile = readProjected;
67
+ host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
68
+ const text = readProjected(fileName);
69
+ if (text === undefined) {
70
+ onError?.(`Cannot read '${fileName}'.`);
71
+ return undefined;
72
+ }
73
+ return ts.createSourceFile(fileName, text, languageVersion, true);
74
+ };
75
+ ts.createProgram({
76
+ rootNames: parsed.fileNames,
77
+ options: parsed.options,
78
+ host,
79
+ ...(parsed.projectReferences === undefined ? {} : { projectReferences: parsed.projectReferences }),
80
+ });
81
+ if (failures.length > 0)
82
+ throw new PrecompileDiagnosticsError(failures);
83
+ const internalFiles = [...projected.entries()]
84
+ .filter(([path]) => isInside(projectRoot, path) && !(0, node_path_1.relative)(projectRoot, path).split(node_path_1.sep).includes("node_modules"))
85
+ .sort(([left], [right]) => left.localeCompare(right, "en"));
86
+ const staging = `${outputRoot}.tmp-${process.pid}-${Date.now()}`;
87
+ const generatedProject = (0, node_path_1.resolve)(outputRoot, "tsconfig.json");
88
+ const manifestFiles = [];
89
+ await (0, promises_1.rm)(staging, { recursive: true, force: true });
90
+ try {
91
+ for (const [sourcePath, texts] of internalFiles) {
92
+ const relativePath = (0, node_path_1.relative)(projectRoot, sourcePath);
93
+ const projectedPath = (0, node_path_1.resolve)(staging, "project", relativePath);
94
+ await (0, promises_1.mkdir)((0, node_path_1.dirname)(projectedPath), { recursive: true });
95
+ await (0, promises_1.writeFile)(projectedPath, texts.projected, "utf8");
96
+ manifestFiles.push({
97
+ source: relativePath.replaceAll("\\", "/"),
98
+ projected: `project/${relativePath.replaceAll("\\", "/")}`,
99
+ sourceHash: texts.sourceHash,
100
+ projectedHash: hash(texts.projected),
101
+ });
102
+ }
103
+ const generatedConfig = {
104
+ extends: sourceProject.replaceAll("\\", "/"),
105
+ files: manifestFiles.map((file) => `./${file.projected}`),
106
+ include: [],
107
+ compilerOptions: projectedPathOptions(parsed.options, projectRoot, outputRoot, sourceProject),
108
+ };
109
+ await (0, promises_1.writeFile)((0, node_path_1.resolve)(staging, "tsconfig.json"), `${JSON.stringify(generatedConfig, null, 2)}\n`, "utf8");
110
+ const profileBytes = await (0, promises_1.readFile)(options.profile.path);
111
+ const manifest = {
112
+ schemaVersion: 1,
113
+ toolVersion: String(index_js_1.coreApiVersion),
114
+ profileFile: options.profile.path,
115
+ profileHash: hash(profileBytes),
116
+ sourceProject,
117
+ generatedProject,
118
+ files: manifestFiles,
119
+ };
120
+ await (0, promises_1.writeFile)((0, node_path_1.resolve)(staging, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
121
+ await (0, promises_1.rm)(outputRoot, { recursive: true, force: true });
122
+ await (0, promises_1.mkdir)((0, node_path_1.dirname)(outputRoot), { recursive: true });
123
+ await (0, promises_1.rename)(staging, outputRoot);
124
+ return { outputRoot, projectPath: generatedProject, manifest };
125
+ }
126
+ finally {
127
+ await (0, promises_1.rm)(staging, { recursive: true, force: true });
128
+ }
129
+ }
130
+ function projectedPathOptions(options, projectRoot, outputRoot, sourceProject) {
131
+ const result = {};
132
+ const mapProjectTarget = (path) => {
133
+ const absolute = (0, node_path_1.resolve)(path);
134
+ return isInside(projectRoot, absolute)
135
+ ? (0, node_path_1.resolve)(outputRoot, "project", (0, node_path_1.relative)(projectRoot, absolute))
136
+ : absolute;
137
+ };
138
+ const mapOutputTarget = (path) => {
139
+ const absolute = (0, node_path_1.resolve)(path);
140
+ return isInside(projectRoot, absolute)
141
+ ? (0, node_path_1.resolve)(outputRoot, (0, node_path_1.relative)(projectRoot, absolute))
142
+ : absolute;
143
+ };
144
+ const mapProjectAbsolute = (path) => {
145
+ const mapped = mapProjectTarget(path);
146
+ let value = (0, node_path_1.relative)(outputRoot, mapped).replaceAll("\\", "/");
147
+ if (!value.startsWith("."))
148
+ value = `./${value}`;
149
+ return value;
150
+ };
151
+ const mapOutputAbsolute = (path) => {
152
+ const mapped = mapOutputTarget(path);
153
+ let value = (0, node_path_1.relative)(outputRoot, mapped).replaceAll("\\", "/");
154
+ if (!value.startsWith("."))
155
+ value = `./${value}`;
156
+ return value;
157
+ };
158
+ if (options.baseUrl !== undefined)
159
+ result.baseUrl = mapProjectAbsolute(options.baseUrl);
160
+ if (options.rootDir !== undefined)
161
+ result.rootDir = mapProjectAbsolute(options.rootDir);
162
+ if (options.rootDirs !== undefined)
163
+ result.rootDirs = options.rootDirs.map(mapProjectAbsolute);
164
+ if (options.typeRoots !== undefined)
165
+ result.typeRoots = options.typeRoots.map(mapProjectAbsolute);
166
+ if (options.mapRoot !== undefined)
167
+ result.mapRoot = "./";
168
+ if (options.tsBuildInfoFile !== undefined)
169
+ result.tsBuildInfoFile = mapOutputAbsolute(options.tsBuildInfoFile);
170
+ else if (options.incremental === true || options.composite === true)
171
+ result.tsBuildInfoFile = "./tsconfig.tsbuildinfo";
172
+ if (options.paths !== undefined) {
173
+ const base = options.baseUrl ?? (0, node_path_1.dirname)(sourceProject);
174
+ const mappedBase = mapProjectTarget(base);
175
+ result.paths = Object.fromEntries(Object.entries(options.paths).map(([key, values]) => [
176
+ key,
177
+ values.map((value) => (0, node_path_1.relative)(mappedBase, mapProjectTarget((0, node_path_1.resolve)(base, value))).replaceAll("\\", "/")),
178
+ ]));
179
+ }
180
+ return result;
181
+ }
182
+ function isInside(root, path) {
183
+ const value = (0, node_path_1.relative)(root, path);
184
+ return !value.startsWith(`..${node_path_1.sep}`) && value !== ".." && !(0, node_path_1.isAbsolute)(value);
185
+ }
186
+ function hash(content) {
187
+ return (0, node_crypto_1.createHash)("sha256").update(content).digest("hex");
188
+ }
189
+ function formatDiagnostic(ts, diagnostic) {
190
+ return `TS${diagnostic.code}: ${ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`;
191
+ }
192
+ //# sourceMappingURL=precompile.js.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Read source with the pinned TypeScript 5.5.4 `ts.sys.readFile` semantics.
3
+ * BOM-marked UTF-16/UTF-8 is recognized; every other byte stream is decoded as
4
+ * non-fatal UTF-8, including the same U+FFFD replacement behavior as stock tsc.
5
+ */
6
+ export declare function readSourceText(file: string, _displayPath?: string): Promise<string>;
7
+ export declare function decodeTypeScriptText(input: Uint8Array): string;
8
+ /** Discover TypeScript-family files in deterministic relative-path order. */
9
+ export declare function discoverSourceFiles(root: string, excludedRoot?: string): Promise<string[]>;
10
+ //# sourceMappingURL=source-files.d.ts.map
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ // Copyright (C) 2026 Tencent. All rights reserved.
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.readSourceText = readSourceText;
17
+ exports.decodeTypeScriptText = decodeTypeScriptText;
18
+ exports.discoverSourceFiles = discoverSourceFiles;
19
+ const promises_1 = require("node:fs/promises");
20
+ const node_path_1 = require("node:path");
21
+ const sourceExtensionPattern = /(?:\.d)?\.(?:ts|tsx|mts|cts)$/i;
22
+ const ignoredDirectories = new Set([".git", "node_modules"]);
23
+ /**
24
+ * Read source with the pinned TypeScript 5.5.4 `ts.sys.readFile` semantics.
25
+ * BOM-marked UTF-16/UTF-8 is recognized; every other byte stream is decoded as
26
+ * non-fatal UTF-8, including the same U+FFFD replacement behavior as stock tsc.
27
+ */
28
+ async function readSourceText(file, _displayPath = file) {
29
+ return decodeTypeScriptText(await (0, promises_1.readFile)(file));
30
+ }
31
+ function decodeTypeScriptText(input) {
32
+ const bytes = Buffer.from(input);
33
+ const length = bytes.length;
34
+ if (length >= 2 && bytes[0] === 0xfe && bytes[1] === 0xff) {
35
+ const evenLength = length & ~1;
36
+ const swapped = Buffer.from(bytes.subarray(0, evenLength));
37
+ for (let index = 0; index < evenLength; index += 2) {
38
+ const value = swapped[index];
39
+ swapped[index] = swapped[index + 1];
40
+ swapped[index + 1] = value;
41
+ }
42
+ return swapped.toString("utf16le", 2);
43
+ }
44
+ if (length >= 2 && bytes[0] === 0xff && bytes[1] === 0xfe) {
45
+ return bytes.toString("utf16le", 2);
46
+ }
47
+ if (length >= 3 && bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf) {
48
+ return bytes.toString("utf8", 3);
49
+ }
50
+ return bytes.toString("utf8");
51
+ }
52
+ /** Discover TypeScript-family files in deterministic relative-path order. */
53
+ async function discoverSourceFiles(root, excludedRoot) {
54
+ const files = [];
55
+ const resolvedExcludedRoot = excludedRoot === undefined ? undefined : (0, node_path_1.resolve)(excludedRoot);
56
+ const visit = async (directory) => {
57
+ const entries = await (0, promises_1.readdir)(directory, { withFileTypes: true });
58
+ entries.sort((left, right) => left.name.localeCompare(right.name, "en"));
59
+ for (const entry of entries) {
60
+ const path = (0, node_path_1.join)(directory, entry.name);
61
+ if (entry.isDirectory()) {
62
+ if (ignoredDirectories.has(entry.name) || (0, node_path_1.resolve)(path) === resolvedExcludedRoot) {
63
+ continue;
64
+ }
65
+ await visit(path);
66
+ }
67
+ else if (entry.isFile() && sourceExtensionPattern.test(entry.name)) {
68
+ files.push(path);
69
+ }
70
+ }
71
+ };
72
+ await visit((0, node_path_1.resolve)(root));
73
+ return files;
74
+ }
75
+ //# sourceMappingURL=source-files.js.map
@@ -0,0 +1,34 @@
1
+ import { type MacroDiagnostic } from "../core/index.js";
2
+ import { type ProfileFile } from "./config.js";
3
+ export interface WatchBuildInfo {
4
+ /** Absolute paths written by the latest emit, sorted. */
5
+ readonly outputFiles: readonly string[];
6
+ /** Files whose macro structure is invalid this build; emit is skipped for them. */
7
+ readonly macroDiagnostics: ReadonlyMap<string, readonly MacroDiagnostic[]>;
8
+ readonly hasErrors: boolean;
9
+ }
10
+ export interface WatchOptions {
11
+ readonly projectRoot: string;
12
+ readonly project: string;
13
+ /** Path to the Profile file (already resolved from the package pointer). */
14
+ readonly profilePath: string;
15
+ /** Called after each compilation finishes (initial build and every rebuild). */
16
+ readonly onBuild?: (info: WatchBuildInfo) => void;
17
+ /** Called after the Profile file changes and the WatchProgram is rebuilt. */
18
+ readonly onProfileReload?: (profile: ProfileFile) => void;
19
+ /** Compiler options that override the tsconfig (parsed via `parseTscOverride`). */
20
+ readonly compilerOptionsOverride?: import("typescript").CompilerOptions;
21
+ /** Optional equal-length projection dump, matching `build --emit-projection`. */
22
+ readonly emitProjectionDir?: string;
23
+ }
24
+ export interface WatchHandle {
25
+ close(): void;
26
+ }
27
+ /**
28
+ * Watch mode for projected compilation. A `createWatchCompilerHost` drives
29
+ * incremental rebuilds with the same equal-length masking as one-shot builds.
30
+ * The Profile file is watched separately; any change tears down the current
31
+ * WatchProgram and rebuilds it in full under the new Profile.
32
+ */
33
+ export declare function watchProject(options: WatchOptions): Promise<WatchHandle>;
34
+ //# sourceMappingURL=watch.d.ts.map