@d1g1tal/tsbuild 1.0.3 → 1.1.1

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.
@@ -78,7 +78,7 @@ var ConfigurationError = class extends BuildError {
78
78
  this.name = "ConfigurationError";
79
79
  }
80
80
  };
81
- var UnsupportedSyntaxError = class extends Error {
81
+ var UnsupportedSyntaxError = class extends BundleError {
82
82
  /**
83
83
  * Creates an instance of UnsupportedSyntaxError.
84
84
  * @param node The node with unsupported syntax
@@ -88,6 +88,7 @@ var UnsupportedSyntaxError = class extends Error {
88
88
  const syntaxKindName = SyntaxKind[node.kind] ?? `Unknown(${node.kind})`;
89
89
  const nodeText = node.getText ? node.getText().slice(0, 100) : "<no text>";
90
90
  super(`${message}: ${syntaxKindName} - "${nodeText}"`);
91
+ this.name = "UnsupportedSyntaxError";
91
92
  }
92
93
  };
93
94
  var castError = (exception) => {
@@ -557,7 +558,7 @@ var DeclarationProcessor = class _DeclarationProcessor {
557
558
  let hasDeclare = false;
558
559
  for (const modifier of node.modifiers ?? []) {
559
560
  if (modifier.kind === SyntaxKind2.DefaultKeyword || modifier.kind === SyntaxKind2.ExportKeyword) {
560
- code.remove(modifier.getStart(), modifier.getEnd() + 1);
561
+ code.remove(modifier.getStart(), modifier.getEnd() + getTrailingWhitespaceLength(modifier.getEnd(), node.getEnd()));
561
562
  } else if (modifier.kind === SyntaxKind2.DeclareKeyword) {
562
563
  hasDeclare = true;
563
564
  }
@@ -828,8 +829,10 @@ function mergeImports(imports) {
828
829
  return result;
829
830
  }
830
831
  var DeclarationBundler = class {
831
- /** d.ts Bundle Options (internally mutable for caching - stores pre-processed declarations) */
832
+ /** Project declaration files from in-memory FileManager */
832
833
  declarationFiles = /* @__PURE__ */ new Map();
834
+ /** External declaration files resolved from disk (node_modules) when resolve is enabled */
835
+ externalDeclarationFiles = /* @__PURE__ */ new Map();
833
836
  /** d.ts Bundle Options */
834
837
  options;
835
838
  /** WeakMap cache for identifier collection to avoid re-parsing same source files */
@@ -841,10 +844,10 @@ var DeclarationBundler = class {
841
844
  // Create a proper module resolution host that supports both in-memory files and disk files
842
845
  moduleResolutionHost = {
843
846
  fileExists: (fileName) => {
844
- return this.declarationFiles.has(fileName) || this.options.resolve && sys.fileExists(fileName);
847
+ return this.declarationFiles.has(fileName) || this.externalDeclarationFiles.has(fileName) || this.options.resolve && sys.fileExists(fileName);
845
848
  },
846
849
  readFile: (fileName) => {
847
- const cached = this.declarationFiles.get(fileName);
850
+ const cached = this.declarationFiles.get(fileName) ?? this.externalDeclarationFiles.get(fileName);
848
851
  if (cached) {
849
852
  return cached.code;
850
853
  }
@@ -854,7 +857,7 @@ var DeclarationBundler = class {
854
857
  const rawContent = sys.readFile(fileName, Encoding.utf8);
855
858
  if (rawContent !== void 0) {
856
859
  const preProcessOutput = DeclarationProcessor.preProcess(createSourceFile(fileName, rawContent, ScriptTarget.Latest, true));
857
- this.declarationFiles.set(fileName, preProcessOutput);
860
+ this.externalDeclarationFiles.set(fileName, preProcessOutput);
858
861
  return preProcessOutput.code;
859
862
  }
860
863
  return void 0;
@@ -888,6 +891,14 @@ var DeclarationBundler = class {
888
891
  }
889
892
  this.options = dtsBundleOptions;
890
893
  }
894
+ /**
895
+ * Clears external declaration files and module resolution cache to free memory.
896
+ * Called after all entry points have been bundled.
897
+ */
898
+ clearExternalFiles() {
899
+ this.externalDeclarationFiles.clear();
900
+ this.moduleResolutionCache.clear();
901
+ }
891
902
  /**
892
903
  * Convert a source file path to its corresponding declaration file path
893
904
  * @param sourcePath - Absolute path to a source file (.ts, .tsx)
@@ -900,17 +911,20 @@ var DeclarationBundler = class {
900
911
  const dtsPath = posix.normalize(Paths.join(outDir, Paths.relative(rootDir, sourceWithoutExt) + FileExtension.DTS));
901
912
  return this.declarationFiles.has(dtsPath) ? dtsPath : sourcePath;
902
913
  }
914
+ let bestMatch;
915
+ let bestRelativeLength = Infinity;
903
916
  for (const dtsPath of this.declarationFiles.keys()) {
904
917
  if (!dtsPath.endsWith(FileExtension.DTS)) {
905
918
  continue;
906
919
  }
907
920
  const withoutOutDir = dtsPath.startsWith(outDir + "/") ? dtsPath.slice(outDir.length + 1) : dtsPath;
908
921
  const relativeDtsPath = withoutOutDir.slice(0, -FileExtension.DTS.length);
909
- if (sourceWithoutExt === relativeDtsPath || sourceWithoutExt.endsWith("/" + relativeDtsPath)) {
910
- return dtsPath;
922
+ if ((sourceWithoutExt === relativeDtsPath || sourceWithoutExt.endsWith("/" + relativeDtsPath)) && relativeDtsPath.length < bestRelativeLength) {
923
+ bestRelativeLength = relativeDtsPath.length;
924
+ bestMatch = dtsPath;
911
925
  }
912
926
  }
913
- return sourcePath;
927
+ return bestMatch ?? sourcePath;
914
928
  }
915
929
  /**
916
930
  * Extract import statements from declaration file content using AST
@@ -984,7 +998,7 @@ var DeclarationBundler = class {
984
998
  return;
985
999
  }
986
1000
  visited.add(path);
987
- const cached = this.declarationFiles.get(path);
1001
+ const cached = this.declarationFiles.get(path) ?? this.externalDeclarationFiles.get(path);
988
1002
  if (cached === void 0) {
989
1003
  return;
990
1004
  }
@@ -1001,7 +1015,7 @@ var DeclarationBundler = class {
1001
1015
  if (resolvedPath?.includes(nodeModules) && !this.matchesPattern(specifier, this.options.noExternal)) {
1002
1016
  continue;
1003
1017
  }
1004
- if (resolvedPath && this.declarationFiles.has(resolvedPath)) {
1018
+ if (resolvedPath && (this.declarationFiles.has(resolvedPath) || this.externalDeclarationFiles.has(resolvedPath))) {
1005
1019
  module.imports.add(resolvedPath);
1006
1020
  bundledSpecs.push(specifier);
1007
1021
  visit(resolvedPath);
@@ -1024,7 +1038,11 @@ var DeclarationBundler = class {
1024
1038
  const visited = /* @__PURE__ */ new Set();
1025
1039
  const visiting = /* @__PURE__ */ new Set();
1026
1040
  const visit = (path) => {
1027
- if (visited.has(path) || visiting.has(path)) {
1041
+ if (visited.has(path)) {
1042
+ return;
1043
+ }
1044
+ if (visiting.has(path)) {
1045
+ Logger.warn(`Circular dependency detected: ${Paths.relative(this.options.currentDirectory, path)}`);
1028
1046
  return;
1029
1047
  }
1030
1048
  visiting.add(path);
@@ -1203,9 +1221,15 @@ var DeclarationBundler = class {
1203
1221
  for (const [name, sourcesSet] of declarationSources) {
1204
1222
  if (sourcesSet.size > 1) {
1205
1223
  const sources = Array.from(sourcesSet);
1206
- sources.slice(1).forEach((modulePath, index) => {
1207
- renameMap.set(`${name}:${modulePath}`, `${name}$${index + 1}`);
1208
- });
1224
+ let suffix = 1;
1225
+ for (const modulePath of sources.slice(1)) {
1226
+ let candidate = `${name}$${suffix}`;
1227
+ while (declarationSources.has(candidate)) {
1228
+ candidate = `${name}$${++suffix}`;
1229
+ }
1230
+ renameMap.set(`${name}:${modulePath}`, candidate);
1231
+ suffix++;
1232
+ }
1209
1233
  }
1210
1234
  }
1211
1235
  for (const { path, typeReferences, fileReferences, sourceFile, code, identifiers } of sortedModules) {
@@ -1316,7 +1340,9 @@ async function bundleDeclarations(options) {
1316
1340
  await writeFile2(outPath, content, Encoding.utf8);
1317
1341
  return { path: Paths.relative(options.currentDirectory, outPath), size: content.length };
1318
1342
  });
1319
- return Promise.all(bundleTasks);
1343
+ const results = await Promise.all(bundleTasks);
1344
+ dtsBundler.clearExternalFiles();
1345
+ return results;
1320
1346
  }
1321
1347
 
1322
1348
  // src/plugins/output.ts
@@ -1744,6 +1770,8 @@ var IncrementalBuildCache = class {
1744
1770
  cacheFilePath;
1745
1771
  /** Pre-loading promise started in constructor for async cache restoration */
1746
1772
  cacheLoaded;
1773
+ /** Set to true when invalidate() is called to prevent stale cache from being restored */
1774
+ invalidated = false;
1747
1775
  /**
1748
1776
  * Creates a new build cache instance and begins pre-loading the cache asynchronously.
1749
1777
  * @param projectRoot - Root directory of the project
@@ -1775,6 +1803,9 @@ var IncrementalBuildCache = class {
1775
1803
  * @param target - The map to populate with cached declarations
1776
1804
  */
1777
1805
  async restore(target) {
1806
+ if (this.invalidated) {
1807
+ return;
1808
+ }
1778
1809
  const cache = await this.cacheLoaded;
1779
1810
  if (cache === void 0) {
1780
1811
  return;
@@ -1793,6 +1824,7 @@ var IncrementalBuildCache = class {
1793
1824
  }
1794
1825
  /** Invalidates the build cache by removing the cache directory. */
1795
1826
  invalidate() {
1827
+ this.invalidated = true;
1796
1828
  try {
1797
1829
  rmSync(this.cacheDirectoryPath, defaultCleanOptions);
1798
1830
  } catch {
@@ -1815,6 +1847,97 @@ var IncrementalBuildCache = class {
1815
1847
  }
1816
1848
  };
1817
1849
 
1850
+ // src/entry-points.ts
1851
+ var importConditions = ["import", "default"];
1852
+ var outputToSourceExtension = /* @__PURE__ */ new Map([
1853
+ [".js", ".ts"],
1854
+ [".mjs", ".ts"],
1855
+ [".jsx", ".tsx"],
1856
+ [".d.ts", ".ts"],
1857
+ [".d.mts", ".ts"]
1858
+ ]);
1859
+ function outputToSourcePath(outputPath, outDir, sourceDir) {
1860
+ const normalizedOutput = outputPath.replace(/^\.\//, "");
1861
+ const normalizedOutDir = outDir.replace(/^\.\//, "").replace(/\/$/, "");
1862
+ if (!normalizedOutput.startsWith(normalizedOutDir + "/") && normalizedOutput !== normalizedOutDir) {
1863
+ return void 0;
1864
+ }
1865
+ const relativePortion = normalizedOutput.slice(normalizedOutDir.length + 1);
1866
+ for (const [outExt, srcExt] of outputToSourceExtension) {
1867
+ if (relativePortion.endsWith(outExt)) {
1868
+ const stem = relativePortion.slice(0, -outExt.length);
1869
+ return `./${sourceDir}/${stem}${srcExt}`;
1870
+ }
1871
+ }
1872
+ return void 0;
1873
+ }
1874
+ function resolveConditionalExport(exportValue) {
1875
+ if (typeof exportValue === "string") {
1876
+ return exportValue;
1877
+ }
1878
+ for (const condition of importConditions) {
1879
+ const value = exportValue[condition];
1880
+ if (typeof value === "string") {
1881
+ return value;
1882
+ }
1883
+ }
1884
+ return void 0;
1885
+ }
1886
+ function subpathToEntryName(subpath, packageName) {
1887
+ if (subpath === ".") {
1888
+ return packageName ?? "index";
1889
+ }
1890
+ const withoutPrefix = subpath.replace(/^\.\//, "");
1891
+ const lastSegment = withoutPrefix.lastIndexOf("/");
1892
+ return lastSegment === -1 ? withoutPrefix : withoutPrefix.slice(lastSegment + 1);
1893
+ }
1894
+ function inferEntryPoints(packageJson, outDir, sourceDir = "src") {
1895
+ const entryPoints = {};
1896
+ if (packageJson.exports !== void 0) {
1897
+ if (typeof packageJson.exports === "string") {
1898
+ const sourcePath = outputToSourcePath(packageJson.exports, outDir, sourceDir);
1899
+ if (sourcePath) {
1900
+ entryPoints[packageJson.name ?? "index"] = sourcePath;
1901
+ }
1902
+ } else {
1903
+ for (const [subpath, exportValue] of Object.entries(packageJson.exports)) {
1904
+ if (subpath.includes("*")) {
1905
+ continue;
1906
+ }
1907
+ const outputPath = resolveConditionalExport(exportValue);
1908
+ if (outputPath === void 0) {
1909
+ continue;
1910
+ }
1911
+ const sourcePath = outputToSourcePath(outputPath, outDir, sourceDir);
1912
+ if (sourcePath) {
1913
+ entryPoints[subpathToEntryName(subpath, packageJson.name)] = sourcePath;
1914
+ }
1915
+ }
1916
+ }
1917
+ }
1918
+ if (packageJson.bin !== void 0) {
1919
+ const binEntries = typeof packageJson.bin === "string" ? { [packageJson.name ?? "cli"]: packageJson.bin } : packageJson.bin;
1920
+ for (const [name, outputPath] of Object.entries(binEntries)) {
1921
+ if (entryPoints[name] === void 0) {
1922
+ const sourcePath = outputToSourcePath(outputPath, outDir, sourceDir);
1923
+ if (sourcePath) {
1924
+ entryPoints[name] = sourcePath;
1925
+ }
1926
+ }
1927
+ }
1928
+ }
1929
+ if (Object.keys(entryPoints).length === 0) {
1930
+ const legacyPath = packageJson.module ?? packageJson.main;
1931
+ if (legacyPath !== void 0) {
1932
+ const sourcePath = outputToSourcePath(legacyPath, outDir, sourceDir);
1933
+ if (sourcePath) {
1934
+ entryPoints["index"] = sourcePath;
1935
+ }
1936
+ }
1937
+ }
1938
+ return Object.keys(entryPoints).length > 0 ? entryPoints : void 0;
1939
+ }
1940
+
1818
1941
  // src/type-script-project.ts
1819
1942
  import { build as esbuild, formatMessages } from "esbuild";
1820
1943
  import { sys as sys3, createIncrementalProgram, formatDiagnostics, formatDiagnosticsWithColorAndContext, parseJsonConfigFileContent, readConfigFile, findConfigFile } from "typescript";
@@ -1840,6 +1963,7 @@ var _TypeScriptProject = class _TypeScriptProject {
1840
1963
  __publicField(this, "pendingChanges", []);
1841
1964
  __publicField(this, "buildDependencies", /* @__PURE__ */ new Set());
1842
1965
  __publicField(this, "dependencyPaths");
1966
+ __publicField(this, "packageJson");
1843
1967
  this.directory = Paths.absolute(directory);
1844
1968
  this.configuration = _TypeScriptProject.resolveConfiguration(this.directory, options);
1845
1969
  const { buildCache, rootNames, projectReferences, configFileParsingDiagnostics, tsbuild: { entryPoints, ...tsbuildOptions }, compilerOptions: { target, outDir } } = this.configuration;
@@ -1858,7 +1982,7 @@ var _TypeScriptProject = class _TypeScriptProject {
1858
1982
  return Files.empty(this.buildConfiguration.outDir);
1859
1983
  }
1860
1984
  async build() {
1861
- Logger.header(`\u{1F680} tsbuild v${"1.0.3"}${this.configuration.compilerOptions.incremental ? " [incremental]" : ""}`);
1985
+ Logger.header(`\u{1F680} tsbuild v${"1.1.1"}${this.configuration.compilerOptions.incremental ? " [incremental]" : ""}`);
1862
1986
  try {
1863
1987
  const processes = [];
1864
1988
  const filesWereEmitted = await this.typeCheck();
@@ -2073,6 +2197,19 @@ var _TypeScriptProject = class _TypeScriptProject {
2073
2197
  const bundle = typeScriptOptions.tsbuild?.bundle ?? configResult.config.tsbuild?.bundle ?? true;
2074
2198
  const platform2 = configResult.config.compilerOptions?.lib?.some(domPredicate) ? Platform.BROWSER : Platform.NODE;
2075
2199
  const noExternal = typeScriptOptions.tsbuild?.noExternal ?? configResult.config.tsbuild?.noExternal ?? [];
2200
+ const hasExplicitEntryPoints = typeScriptOptions.tsbuild?.entryPoints !== void 0 || configResult.config.tsbuild?.entryPoints !== void 0;
2201
+ let inferredEntryPoints;
2202
+ if (!hasExplicitEntryPoints && bundle) {
2203
+ const packageJsonContent = sys3.readFile(Paths.join(directory, "package.json"));
2204
+ if (packageJsonContent) {
2205
+ try {
2206
+ const pkgJson = JSON.parse(packageJsonContent);
2207
+ const outDir = typeScriptOptions.compilerOptions?.outDir ?? configResult.config.compilerOptions?.outDir ?? defaultOutDirectory;
2208
+ inferredEntryPoints = inferEntryPoints(pkgJson, outDir);
2209
+ } catch {
2210
+ }
2211
+ }
2212
+ }
2076
2213
  const defaultTsbuildConfig = {
2077
2214
  splitting: bundle,
2078
2215
  minify: false,
@@ -2084,7 +2221,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2084
2221
  platform: platform2,
2085
2222
  dts: { resolve: platform2 !== Platform.NODE, entryPoints: bundle ? void 0 : [] },
2086
2223
  watch: { enabled: false, recursive: true, ignoreInitial: true, persistent: true },
2087
- entryPoints: bundle ? { [defaultEntryPoint]: defaultEntryFile } : { src: defaultSourceDirectory }
2224
+ entryPoints: inferredEntryPoints ?? (bundle ? { [defaultEntryPoint]: defaultEntryFile } : { src: defaultSourceDirectory })
2088
2225
  };
2089
2226
  const baseConfig = {
2090
2227
  ...configResult.config,
@@ -2140,11 +2277,14 @@ var _TypeScriptProject = class _TypeScriptProject {
2140
2277
  }
2141
2278
  /**
2142
2279
  * Gets the project dependency paths, cached after first call.
2280
+ * Reads package.json and caches it for reuse.
2143
2281
  * @returns A promise that resolves to an array of project dependency paths.
2144
2282
  */
2145
2283
  getProjectDependencyPaths() {
2146
2284
  return this.dependencyPaths ??= Files.read(Paths.absolute(this.directory, "package.json")).then((content) => {
2147
- const { dependencies = {}, peerDependencies = {} } = Json.parse(content);
2285
+ const packageJson = Json.parse(content);
2286
+ this.packageJson = packageJson;
2287
+ const { dependencies = {}, peerDependencies = {} } = packageJson;
2148
2288
  return [.../* @__PURE__ */ new Set([...Object.keys(dependencies), ...Object.keys(peerDependencies)])];
2149
2289
  });
2150
2290
  }
package/dist/index.d.ts CHANGED
@@ -258,6 +258,7 @@ declare class TypeScriptProject implements Closable {
258
258
  private readonly pendingChanges;
259
259
  private readonly buildDependencies;
260
260
  private dependencyPaths?;
261
+ private packageJson?;
261
262
  /**
262
263
  * Creates a TypeScript project and prepares it for building/bundling.
263
264
  * @param directory - Project root directory (defaults to current working directory)
@@ -319,6 +320,7 @@ declare class TypeScriptProject implements Closable {
319
320
  private getEntryPoints;
320
321
  /**
321
322
  * Gets the project dependency paths, cached after first call.
323
+ * Reads package.json and caches it for reuse.
322
324
  * @returns A promise that resolves to an array of project dependency paths.
323
325
  */
324
326
  private getProjectDependencyPaths;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TypeScriptProject
3
- } from "./7SPSROV3.js";
3
+ } from "./YGGCSRAC.js";
4
4
  import "./VMWNQL2J.js";
5
5
  export {
6
6
  TypeScriptProject
package/dist/tsbuild.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BuildError,
4
4
  TypeScriptProject
5
- } from "./7SPSROV3.js";
5
+ } from "./YGGCSRAC.js";
6
6
  import "./VMWNQL2J.js";
7
7
 
8
8
  // src/tsbuild.ts
@@ -30,7 +30,7 @@ if (help) {
30
30
  process.exit(0);
31
31
  }
32
32
  if (version) {
33
- console.log("1.0.3");
33
+ console.log("1.1.1");
34
34
  process.exit(0);
35
35
  }
36
36
  var typeScriptOptions = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d1g1tal/tsbuild",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "packageManager": "pnpm@10.29.3",
5
5
  "description": "A fast, ESM-only TypeScript build tool combining the TypeScript API for type checking and declaration generation, esbuild for bundling, and SWC for decorator metadata.",
6
6
  "type": "module",
package/schema.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "additionalProperties": false,
17
17
  "properties": {
18
18
  "entryPoints": {
19
- "markdownDescription": "Files that each serve as an input to the bundling algorithm. Can be an array of paths or an object mapping output names to input paths.",
19
+ "markdownDescription": "Files that each serve as an input to the bundling algorithm. Can be an array of paths or an object mapping output names to input paths.\n\nWhen omitted, tsbuild auto-infers entry points from the `exports`, `bin`, `main`, or `module` fields in `package.json` by reverse-mapping output paths to source paths.",
20
20
  "oneOf": [
21
21
  {
22
22
  "type": "array",