@bamboocss/parser 1.51.5 → 1.52.0

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.
package/dist/index.cjs CHANGED
@@ -1511,6 +1511,22 @@ var Project = class {
1511
1511
  this.#assertNotLoading();
1512
1512
  return this.options.parserOptions;
1513
1513
  }
1514
+ /**
1515
+ * `paths` and `baseUrl` as this project was configured with them, without opening a compiler.
1516
+ *
1517
+ * The same values `#planSpecifier` resolves against — read off the options the project was
1518
+ * built from rather than off the program, precisely so asking does not materialize one. A
1519
+ * caller that needs to know where a specifier could point *before* deciding what to install
1520
+ * has no compiler yet, and forcing one into existence to answer is the cost it is trying to
1521
+ * avoid.
1522
+ */
1523
+ get resolutionOptions() {
1524
+ const configured = this.#sourceFiles.projectOptions.compilerOptions;
1525
+ return {
1526
+ baseUrl: configured?.baseUrl,
1527
+ paths: configured?.paths
1528
+ };
1529
+ }
1514
1530
  constructor(options) {
1515
1531
  const { deferInitialSourceFiles, getFiles, parserOptions } = options;
1516
1532
  const tsProjectOptions = { ...options };
@@ -1838,6 +1854,7 @@ var Project = class {
1838
1854
  }
1839
1855
  invalidateResolutions();
1840
1856
  this.#resolver = void 0;
1857
+ this.#checkoutBoundaries = void 0;
1841
1858
  this.#fileTreeRevision++;
1842
1859
  this.sourcePreparations.clear();
1843
1860
  };
@@ -1850,6 +1867,27 @@ var Project = class {
1850
1867
  return specifier.startsWith(pattern.slice(0, wildcard)) && specifier.endsWith(pattern.slice(wildcard + 1));
1851
1868
  });
1852
1869
  };
1870
+ /**
1871
+ * Local candidates per *resolution*, rather than per importer that asks for one.
1872
+ *
1873
+ * `createResolver` memoizes by importing directory and specifier and hands back the same
1874
+ * `ResolvedModule` to every caller that lands on it — so the object identity is exactly the
1875
+ * unit this answer belongs to. Deriving it again per importer re-walked every failed lookup
1876
+ * a specifier produced, and canonicalised each one to place it in the checkout: a specifier
1877
+ * with fifty probes, imported by five hundred files, is twenty-five thousand repetitions of
1878
+ * a list that could not have changed.
1879
+ *
1880
+ * Keyed weakly so it lasts exactly as long as the resolution it describes; when the resolver
1881
+ * clears its memo the entries here become unreachable with it.
1882
+ */
1883
+ #localCandidates = /* @__PURE__ */ new WeakMap();
1884
+ localCandidatesOf = (resolved) => {
1885
+ const remembered = this.#localCandidates.get(resolved);
1886
+ if (remembered) return remembered;
1887
+ const derived = this.getLocalFailedLookupCandidates(resolved.failedLookups);
1888
+ this.#localCandidates.set(resolved, derived);
1889
+ return derived;
1890
+ };
1853
1891
  getLocalFailedLookupCandidates = (failedLookupLocations) => {
1854
1892
  const seen = /* @__PURE__ */ new Set();
1855
1893
  const candidates = [];
@@ -1864,12 +1902,29 @@ var Project = class {
1864
1902
  return candidates;
1865
1903
  };
1866
1904
  isUnresolvedLocalSpecifier = (specifier, pendingCandidates) => specifier.startsWith(".") || specifier.startsWith("/") || this.isLocalAlias(specifier) || pendingCandidates.length > 0;
1867
- isInCheckout = (filePath) => {
1868
- if (this.#sourceFiles.projectOptions.useInMemoryFileSystem) return true;
1905
+ /**
1906
+ * The checkout's two spellings, resolved once.
1907
+ *
1908
+ * Both are fixed for the life of the project — they come from `cwd` — and canonicalising the
1909
+ * root is a `realpath`, which is a `lstat` per path component. `isInCheckout` is asked once
1910
+ * per failed lookup a resolution produced, so recomputing the boundary there made half of
1911
+ * every such question a syscall walk over a path that had not moved since the last one.
1912
+ *
1913
+ * Invalidated wherever the resolver is, since a retargeted `cwd` moves the boundary too.
1914
+ */
1915
+ #checkoutBoundaries;
1916
+ getCheckoutBoundaries = () => {
1917
+ if (this.#checkoutBoundaries) return this.#checkoutBoundaries;
1869
1918
  const fileSystem = this.project.getFileSystem();
1870
1919
  const configured = this.options.parserOptions.config.cwd;
1871
1920
  const spelledRoot = this.normalizePath(configured || fileSystem.getCurrentDirectory()).replace(/\/$/, "");
1872
1921
  const root = this.normalizePath(fileSystem.realpathSync(spelledRoot)).replace(/\/$/, "");
1922
+ return this.#checkoutBoundaries = [root, spelledRoot];
1923
+ };
1924
+ isInCheckout = (filePath) => {
1925
+ if (this.#sourceFiles.projectOptions.useInMemoryFileSystem) return true;
1926
+ const fileSystem = this.project.getFileSystem();
1927
+ const [root, spelledRoot] = this.getCheckoutBoundaries();
1873
1928
  let target;
1874
1929
  try {
1875
1930
  target = this.normalizePath(fileSystem.realpathSync(filePath));
@@ -1877,7 +1932,7 @@ var Project = class {
1877
1932
  if (!isMissingPathShapeError(error)) throw error;
1878
1933
  target = this.normalizePath(filePath);
1879
1934
  }
1880
- return [root, spelledRoot].some((boundary) => target === boundary || target.startsWith(`${boundary}/`));
1935
+ return target === root || target.startsWith(`${root}/`) || target === spelledRoot || target.startsWith(`${spelledRoot}/`);
1881
1936
  };
1882
1937
  /**
1883
1938
  * Resolve one specifier, stopping short of installing what it names.
@@ -1923,7 +1978,7 @@ var Project = class {
1923
1978
  paths: configured?.paths
1924
1979
  });
1925
1980
  for (const filePath of resolved.affectingFiles) recordConfigurationFile(filePath);
1926
- const pendingCandidates = this.getLocalFailedLookupCandidates(resolved.failedLookups);
1981
+ const pendingCandidates = this.localCandidatesOf(resolved);
1927
1982
  const module = resolved.path ? {
1928
1983
  resolvedFileName: resolved.path,
1929
1984
  isExternalLibraryImport: resolved.path.includes("/node_modules/")
package/dist/index.d.cts CHANGED
@@ -471,6 +471,19 @@ declare class Project {
471
471
  project: Project$1;
472
472
  private options;
473
473
  get parserOptions(): ParserOptions;
474
+ /**
475
+ * `paths` and `baseUrl` as this project was configured with them, without opening a compiler.
476
+ *
477
+ * The same values `#planSpecifier` resolves against — read off the options the project was
478
+ * built from rather than off the program, precisely so asking does not materialize one. A
479
+ * caller that needs to know where a specifier could point *before* deciding what to install
480
+ * has no compiler yet, and forcing one into existence to answer is the cost it is trying to
481
+ * avoid.
482
+ */
483
+ get resolutionOptions(): {
484
+ baseUrl?: string;
485
+ paths?: Record<string, string[]>;
486
+ };
474
487
  constructor(options: ProjectOptions);
475
488
  get files(): string[];
476
489
  /** Reverse dependency graph: resolved target -> importers. */
@@ -569,8 +582,10 @@ declare class Project {
569
582
  */
570
583
  refreshResolutionConfiguration: (compilerOptions: CompilerOptions | undefined, resolutionConfigFiles: readonly string[], replaceCompilerOptions: boolean) => void;
571
584
  private isLocalAlias;
585
+ private localCandidatesOf;
572
586
  private getLocalFailedLookupCandidates;
573
587
  private isUnresolvedLocalSpecifier;
588
+ private getCheckoutBoundaries;
574
589
  private isInCheckout;
575
590
  private retractImporter;
576
591
  private publishResolutionFacts;
package/dist/index.d.mts CHANGED
@@ -471,6 +471,19 @@ declare class Project {
471
471
  project: Project$1;
472
472
  private options;
473
473
  get parserOptions(): ParserOptions;
474
+ /**
475
+ * `paths` and `baseUrl` as this project was configured with them, without opening a compiler.
476
+ *
477
+ * The same values `#planSpecifier` resolves against — read off the options the project was
478
+ * built from rather than off the program, precisely so asking does not materialize one. A
479
+ * caller that needs to know where a specifier could point *before* deciding what to install
480
+ * has no compiler yet, and forcing one into existence to answer is the cost it is trying to
481
+ * avoid.
482
+ */
483
+ get resolutionOptions(): {
484
+ baseUrl?: string;
485
+ paths?: Record<string, string[]>;
486
+ };
474
487
  constructor(options: ProjectOptions);
475
488
  get files(): string[];
476
489
  /** Reverse dependency graph: resolved target -> importers. */
@@ -569,8 +582,10 @@ declare class Project {
569
582
  */
570
583
  refreshResolutionConfiguration: (compilerOptions: CompilerOptions | undefined, resolutionConfigFiles: readonly string[], replaceCompilerOptions: boolean) => void;
571
584
  private isLocalAlias;
585
+ private localCandidatesOf;
572
586
  private getLocalFailedLookupCandidates;
573
587
  private isUnresolvedLocalSpecifier;
588
+ private getCheckoutBoundaries;
574
589
  private isInCheckout;
575
590
  private retractImporter;
576
591
  private publishResolutionFacts;
package/dist/index.mjs CHANGED
@@ -1510,6 +1510,22 @@ var Project = class {
1510
1510
  this.#assertNotLoading();
1511
1511
  return this.options.parserOptions;
1512
1512
  }
1513
+ /**
1514
+ * `paths` and `baseUrl` as this project was configured with them, without opening a compiler.
1515
+ *
1516
+ * The same values `#planSpecifier` resolves against — read off the options the project was
1517
+ * built from rather than off the program, precisely so asking does not materialize one. A
1518
+ * caller that needs to know where a specifier could point *before* deciding what to install
1519
+ * has no compiler yet, and forcing one into existence to answer is the cost it is trying to
1520
+ * avoid.
1521
+ */
1522
+ get resolutionOptions() {
1523
+ const configured = this.#sourceFiles.projectOptions.compilerOptions;
1524
+ return {
1525
+ baseUrl: configured?.baseUrl,
1526
+ paths: configured?.paths
1527
+ };
1528
+ }
1513
1529
  constructor(options) {
1514
1530
  const { deferInitialSourceFiles, getFiles, parserOptions } = options;
1515
1531
  const tsProjectOptions = { ...options };
@@ -1837,6 +1853,7 @@ var Project = class {
1837
1853
  }
1838
1854
  invalidateResolutions();
1839
1855
  this.#resolver = void 0;
1856
+ this.#checkoutBoundaries = void 0;
1840
1857
  this.#fileTreeRevision++;
1841
1858
  this.sourcePreparations.clear();
1842
1859
  };
@@ -1849,6 +1866,27 @@ var Project = class {
1849
1866
  return specifier.startsWith(pattern.slice(0, wildcard)) && specifier.endsWith(pattern.slice(wildcard + 1));
1850
1867
  });
1851
1868
  };
1869
+ /**
1870
+ * Local candidates per *resolution*, rather than per importer that asks for one.
1871
+ *
1872
+ * `createResolver` memoizes by importing directory and specifier and hands back the same
1873
+ * `ResolvedModule` to every caller that lands on it — so the object identity is exactly the
1874
+ * unit this answer belongs to. Deriving it again per importer re-walked every failed lookup
1875
+ * a specifier produced, and canonicalised each one to place it in the checkout: a specifier
1876
+ * with fifty probes, imported by five hundred files, is twenty-five thousand repetitions of
1877
+ * a list that could not have changed.
1878
+ *
1879
+ * Keyed weakly so it lasts exactly as long as the resolution it describes; when the resolver
1880
+ * clears its memo the entries here become unreachable with it.
1881
+ */
1882
+ #localCandidates = /* @__PURE__ */ new WeakMap();
1883
+ localCandidatesOf = (resolved) => {
1884
+ const remembered = this.#localCandidates.get(resolved);
1885
+ if (remembered) return remembered;
1886
+ const derived = this.getLocalFailedLookupCandidates(resolved.failedLookups);
1887
+ this.#localCandidates.set(resolved, derived);
1888
+ return derived;
1889
+ };
1852
1890
  getLocalFailedLookupCandidates = (failedLookupLocations) => {
1853
1891
  const seen = /* @__PURE__ */ new Set();
1854
1892
  const candidates = [];
@@ -1863,12 +1901,29 @@ var Project = class {
1863
1901
  return candidates;
1864
1902
  };
1865
1903
  isUnresolvedLocalSpecifier = (specifier, pendingCandidates) => specifier.startsWith(".") || specifier.startsWith("/") || this.isLocalAlias(specifier) || pendingCandidates.length > 0;
1866
- isInCheckout = (filePath) => {
1867
- if (this.#sourceFiles.projectOptions.useInMemoryFileSystem) return true;
1904
+ /**
1905
+ * The checkout's two spellings, resolved once.
1906
+ *
1907
+ * Both are fixed for the life of the project — they come from `cwd` — and canonicalising the
1908
+ * root is a `realpath`, which is a `lstat` per path component. `isInCheckout` is asked once
1909
+ * per failed lookup a resolution produced, so recomputing the boundary there made half of
1910
+ * every such question a syscall walk over a path that had not moved since the last one.
1911
+ *
1912
+ * Invalidated wherever the resolver is, since a retargeted `cwd` moves the boundary too.
1913
+ */
1914
+ #checkoutBoundaries;
1915
+ getCheckoutBoundaries = () => {
1916
+ if (this.#checkoutBoundaries) return this.#checkoutBoundaries;
1868
1917
  const fileSystem = this.project.getFileSystem();
1869
1918
  const configured = this.options.parserOptions.config.cwd;
1870
1919
  const spelledRoot = this.normalizePath(configured || fileSystem.getCurrentDirectory()).replace(/\/$/, "");
1871
1920
  const root = this.normalizePath(fileSystem.realpathSync(spelledRoot)).replace(/\/$/, "");
1921
+ return this.#checkoutBoundaries = [root, spelledRoot];
1922
+ };
1923
+ isInCheckout = (filePath) => {
1924
+ if (this.#sourceFiles.projectOptions.useInMemoryFileSystem) return true;
1925
+ const fileSystem = this.project.getFileSystem();
1926
+ const [root, spelledRoot] = this.getCheckoutBoundaries();
1872
1927
  let target;
1873
1928
  try {
1874
1929
  target = this.normalizePath(fileSystem.realpathSync(filePath));
@@ -1876,7 +1931,7 @@ var Project = class {
1876
1931
  if (!isMissingPathShapeError(error)) throw error;
1877
1932
  target = this.normalizePath(filePath);
1878
1933
  }
1879
- return [root, spelledRoot].some((boundary) => target === boundary || target.startsWith(`${boundary}/`));
1934
+ return target === root || target.startsWith(`${root}/`) || target === spelledRoot || target.startsWith(`${spelledRoot}/`);
1880
1935
  };
1881
1936
  /**
1882
1937
  * Resolve one specifier, stopping short of installing what it names.
@@ -1922,7 +1977,7 @@ var Project = class {
1922
1977
  paths: configured?.paths
1923
1978
  });
1924
1979
  for (const filePath of resolved.affectingFiles) recordConfigurationFile(filePath);
1925
- const pendingCandidates = this.getLocalFailedLookupCandidates(resolved.failedLookups);
1980
+ const pendingCandidates = this.localCandidatesOf(resolved);
1926
1981
  const module = resolved.path ? {
1927
1982
  resolvedFileName: resolved.path,
1928
1983
  isExternalLibraryImport: resolved.path.includes("/node_modules/")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/parser",
3
- "version": "1.51.5",
3
+ "version": "1.52.0",
4
4
  "description": "The static parser for bamboo css",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -33,20 +33,20 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "ts-pattern": "5.9.0",
36
- "@bamboocss/config": "^1.51.5",
37
- "@bamboocss/core": "^1.51.5",
38
- "@bamboocss/extractor": "1.51.5",
39
- "@bamboocss/logger": "1.51.5",
40
- "@bamboocss/shared": "1.51.5",
41
- "@bamboocss/ts-ast": "1.51.5",
42
- "@bamboocss/types": "1.51.5"
36
+ "@bamboocss/config": "^1.52.0",
37
+ "@bamboocss/core": "^1.52.0",
38
+ "@bamboocss/extractor": "1.52.0",
39
+ "@bamboocss/logger": "1.52.0",
40
+ "@bamboocss/shared": "1.52.0",
41
+ "@bamboocss/ts-ast": "1.52.0",
42
+ "@bamboocss/types": "1.52.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@typescript/api": "npm:typescript@7.1.0-dev.20260826.1",
46
46
  "ts-morph": "28.0.0",
47
- "@bamboocss/generator": "1.51.5",
48
- "@bamboocss/plugin-svelte": "1.51.5",
49
- "@bamboocss/plugin-vue": "1.51.5"
47
+ "@bamboocss/generator": "1.52.0",
48
+ "@bamboocss/plugin-svelte": "1.52.0",
49
+ "@bamboocss/plugin-vue": "1.52.0"
50
50
  },
51
51
  "scripts": {
52
52
  "build": "tsdown src/index.ts --format=esm,cjs --dts",