@suss/adapter-typescript 0.5.4 → 0.5.5

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 (3) hide show
  1. package/dist/index.cjs +103 -10
  2. package/dist/index.js +103 -10
  3. package/package.json +5 -5
package/dist/index.cjs CHANGED
@@ -1664,8 +1664,13 @@ function collectPackGates(pack) {
1664
1664
 
1665
1665
  // src/bootstrap/lazyProjectInit.ts
1666
1666
  async function createLazyProject(tsConfigFilePath, packs) {
1667
- const allFiles = parseTsconfigFileList(tsConfigFilePath);
1668
- const candidates = await selectCandidateFiles(allFiles, packs);
1667
+ const parsed = parseTsconfig(tsConfigFilePath);
1668
+ const allFiles = parsed.fileNames;
1669
+ const candidates = await selectCandidateFiles(
1670
+ allFiles,
1671
+ packs,
1672
+ parsed.options
1673
+ );
1669
1674
  const project = new import_ts_morph9.Project({
1670
1675
  tsConfigFilePath,
1671
1676
  skipAddingFilesFromTsConfig: true
@@ -1682,7 +1687,7 @@ async function createLazyProject(tsConfigFilePath, packs) {
1682
1687
  };
1683
1688
  }
1684
1689
  function readTsconfigFileList(tsConfigFilePath) {
1685
- return parseTsconfigFileList(tsConfigFilePath);
1690
+ return parseTsconfig(tsConfigFilePath).fileNames;
1686
1691
  }
1687
1692
  function lazyAddSourceFile(project, projectFileSet, filePath) {
1688
1693
  if (!projectFileSet.has(filePath)) {
@@ -1833,10 +1838,10 @@ function readFileText(project, filePath) {
1833
1838
  return null;
1834
1839
  }
1835
1840
  }
1836
- function parseTsconfigFileList(tsConfigFilePath) {
1841
+ function parseTsconfig(tsConfigFilePath) {
1837
1842
  const configFile = import_ts_morph9.ts.readConfigFile(tsConfigFilePath, import_ts_morph9.ts.sys.readFile);
1838
1843
  if (configFile.error !== void 0) {
1839
- return [];
1844
+ return { fileNames: [], options: {} };
1840
1845
  }
1841
1846
  const parsed = import_ts_morph9.ts.parseJsonConfigFileContent(
1842
1847
  configFile.config,
@@ -1846,9 +1851,9 @@ function parseTsconfigFileList(tsConfigFilePath) {
1846
1851
  void 0,
1847
1852
  tsConfigFilePath
1848
1853
  );
1849
- return parsed.fileNames;
1854
+ return { fileNames: parsed.fileNames, options: parsed.options };
1850
1855
  }
1851
- async function selectCandidateFiles(allFiles, packs) {
1856
+ async function selectCandidateFiles(allFiles, packs, options) {
1852
1857
  const ungatedExists = packs.some(packIsUngated);
1853
1858
  if (ungatedExists) {
1854
1859
  return [...allFiles];
@@ -1858,13 +1863,101 @@ async function selectCandidateFiles(allFiles, packs) {
1858
1863
  return [];
1859
1864
  }
1860
1865
  const fileImports = await readImportsConcurrently(allFiles);
1861
- const matched = [];
1866
+ const matched = /* @__PURE__ */ new Set();
1862
1867
  for (const { path: p, importedModules } of fileImports) {
1863
1868
  if (namesAnyPackage(importedModules, gates)) {
1864
- matched.push(p);
1869
+ matched.add(p);
1865
1870
  }
1866
1871
  }
1867
- return matched;
1872
+ addImportersOfMatches(fileImports, matched, options);
1873
+ return allFiles.filter((p) => matched.has(p));
1874
+ }
1875
+ function addImportersOfMatches(fileImports, matched, options) {
1876
+ const resolve2 = internalSpecifierResolver(
1877
+ fileImports.map((fi) => fi.path),
1878
+ options
1879
+ );
1880
+ const importersOf = /* @__PURE__ */ new Map();
1881
+ for (const { path: from, importedModules } of fileImports) {
1882
+ for (const spec of importedModules) {
1883
+ const target = resolve2(from, spec);
1884
+ if (target === null || target === from) {
1885
+ continue;
1886
+ }
1887
+ const list = importersOf.get(target);
1888
+ if (list === void 0) {
1889
+ importersOf.set(target, [from]);
1890
+ } else {
1891
+ list.push(from);
1892
+ }
1893
+ }
1894
+ }
1895
+ const queue = [...matched];
1896
+ while (queue.length > 0) {
1897
+ const target = queue.pop();
1898
+ for (const importer of importersOf.get(target) ?? []) {
1899
+ if (!matched.has(importer)) {
1900
+ matched.add(importer);
1901
+ queue.push(importer);
1902
+ }
1903
+ }
1904
+ }
1905
+ }
1906
+ function internalSpecifierResolver(files, options) {
1907
+ const fileSet = new Set(files);
1908
+ const probe = (base) => {
1909
+ const stems = [base];
1910
+ const swapped = base.replace(/\.(mjs|cjs|jsx|js)$/, "");
1911
+ if (swapped !== base) {
1912
+ stems.push(swapped);
1913
+ }
1914
+ for (const stem of stems) {
1915
+ for (const candidate of [
1916
+ stem,
1917
+ `${stem}.ts`,
1918
+ `${stem}.tsx`,
1919
+ import_node_path.default.join(stem, "index.ts"),
1920
+ import_node_path.default.join(stem, "index.tsx")
1921
+ ]) {
1922
+ if (fileSet.has(candidate)) {
1923
+ return candidate;
1924
+ }
1925
+ }
1926
+ }
1927
+ return null;
1928
+ };
1929
+ const pathsBase = options.baseUrl ?? (typeof options.pathsBasePath === "string" ? options.pathsBasePath : "");
1930
+ const aliasTargets = (spec) => {
1931
+ const out = [];
1932
+ for (const [pattern, targets] of Object.entries(options.paths ?? {})) {
1933
+ const star = pattern.indexOf("*");
1934
+ if (star === -1) {
1935
+ if (spec === pattern) {
1936
+ out.push(...targets);
1937
+ }
1938
+ continue;
1939
+ }
1940
+ const prefix = pattern.slice(0, star);
1941
+ const suffix = pattern.slice(star + 1);
1942
+ if (spec.length >= prefix.length + suffix.length && spec.startsWith(prefix) && spec.endsWith(suffix)) {
1943
+ const filler = spec.slice(prefix.length, spec.length - suffix.length);
1944
+ out.push(...targets.map((t) => t.replace("*", filler)));
1945
+ }
1946
+ }
1947
+ return out.map((t) => import_node_path.default.resolve(pathsBase, t));
1948
+ };
1949
+ return (fromFile, spec) => {
1950
+ if (spec.startsWith(".")) {
1951
+ return probe(import_node_path.default.resolve(import_node_path.default.dirname(fromFile), spec));
1952
+ }
1953
+ for (const target of aliasTargets(spec)) {
1954
+ const hit = probe(target);
1955
+ if (hit !== null) {
1956
+ return hit;
1957
+ }
1958
+ }
1959
+ return null;
1960
+ };
1868
1961
  }
1869
1962
  function collectAllGates(packs) {
1870
1963
  const gates = /* @__PURE__ */ new Set();
package/dist/index.js CHANGED
@@ -1634,8 +1634,13 @@ function collectPackGates(pack) {
1634
1634
 
1635
1635
  // src/bootstrap/lazyProjectInit.ts
1636
1636
  async function createLazyProject(tsConfigFilePath, packs) {
1637
- const allFiles = parseTsconfigFileList(tsConfigFilePath);
1638
- const candidates = await selectCandidateFiles(allFiles, packs);
1637
+ const parsed = parseTsconfig(tsConfigFilePath);
1638
+ const allFiles = parsed.fileNames;
1639
+ const candidates = await selectCandidateFiles(
1640
+ allFiles,
1641
+ packs,
1642
+ parsed.options
1643
+ );
1639
1644
  const project = new Project({
1640
1645
  tsConfigFilePath,
1641
1646
  skipAddingFilesFromTsConfig: true
@@ -1652,7 +1657,7 @@ async function createLazyProject(tsConfigFilePath, packs) {
1652
1657
  };
1653
1658
  }
1654
1659
  function readTsconfigFileList(tsConfigFilePath) {
1655
- return parseTsconfigFileList(tsConfigFilePath);
1660
+ return parseTsconfig(tsConfigFilePath).fileNames;
1656
1661
  }
1657
1662
  function lazyAddSourceFile(project, projectFileSet, filePath) {
1658
1663
  if (!projectFileSet.has(filePath)) {
@@ -1803,10 +1808,10 @@ function readFileText(project, filePath) {
1803
1808
  return null;
1804
1809
  }
1805
1810
  }
1806
- function parseTsconfigFileList(tsConfigFilePath) {
1811
+ function parseTsconfig(tsConfigFilePath) {
1807
1812
  const configFile = ts.readConfigFile(tsConfigFilePath, ts.sys.readFile);
1808
1813
  if (configFile.error !== void 0) {
1809
- return [];
1814
+ return { fileNames: [], options: {} };
1810
1815
  }
1811
1816
  const parsed = ts.parseJsonConfigFileContent(
1812
1817
  configFile.config,
@@ -1816,9 +1821,9 @@ function parseTsconfigFileList(tsConfigFilePath) {
1816
1821
  void 0,
1817
1822
  tsConfigFilePath
1818
1823
  );
1819
- return parsed.fileNames;
1824
+ return { fileNames: parsed.fileNames, options: parsed.options };
1820
1825
  }
1821
- async function selectCandidateFiles(allFiles, packs) {
1826
+ async function selectCandidateFiles(allFiles, packs, options) {
1822
1827
  const ungatedExists = packs.some(packIsUngated);
1823
1828
  if (ungatedExists) {
1824
1829
  return [...allFiles];
@@ -1828,13 +1833,101 @@ async function selectCandidateFiles(allFiles, packs) {
1828
1833
  return [];
1829
1834
  }
1830
1835
  const fileImports = await readImportsConcurrently(allFiles);
1831
- const matched = [];
1836
+ const matched = /* @__PURE__ */ new Set();
1832
1837
  for (const { path: p, importedModules } of fileImports) {
1833
1838
  if (namesAnyPackage(importedModules, gates)) {
1834
- matched.push(p);
1839
+ matched.add(p);
1835
1840
  }
1836
1841
  }
1837
- return matched;
1842
+ addImportersOfMatches(fileImports, matched, options);
1843
+ return allFiles.filter((p) => matched.has(p));
1844
+ }
1845
+ function addImportersOfMatches(fileImports, matched, options) {
1846
+ const resolve2 = internalSpecifierResolver(
1847
+ fileImports.map((fi) => fi.path),
1848
+ options
1849
+ );
1850
+ const importersOf = /* @__PURE__ */ new Map();
1851
+ for (const { path: from, importedModules } of fileImports) {
1852
+ for (const spec of importedModules) {
1853
+ const target = resolve2(from, spec);
1854
+ if (target === null || target === from) {
1855
+ continue;
1856
+ }
1857
+ const list = importersOf.get(target);
1858
+ if (list === void 0) {
1859
+ importersOf.set(target, [from]);
1860
+ } else {
1861
+ list.push(from);
1862
+ }
1863
+ }
1864
+ }
1865
+ const queue = [...matched];
1866
+ while (queue.length > 0) {
1867
+ const target = queue.pop();
1868
+ for (const importer of importersOf.get(target) ?? []) {
1869
+ if (!matched.has(importer)) {
1870
+ matched.add(importer);
1871
+ queue.push(importer);
1872
+ }
1873
+ }
1874
+ }
1875
+ }
1876
+ function internalSpecifierResolver(files, options) {
1877
+ const fileSet = new Set(files);
1878
+ const probe = (base) => {
1879
+ const stems = [base];
1880
+ const swapped = base.replace(/\.(mjs|cjs|jsx|js)$/, "");
1881
+ if (swapped !== base) {
1882
+ stems.push(swapped);
1883
+ }
1884
+ for (const stem of stems) {
1885
+ for (const candidate of [
1886
+ stem,
1887
+ `${stem}.ts`,
1888
+ `${stem}.tsx`,
1889
+ path.join(stem, "index.ts"),
1890
+ path.join(stem, "index.tsx")
1891
+ ]) {
1892
+ if (fileSet.has(candidate)) {
1893
+ return candidate;
1894
+ }
1895
+ }
1896
+ }
1897
+ return null;
1898
+ };
1899
+ const pathsBase = options.baseUrl ?? (typeof options.pathsBasePath === "string" ? options.pathsBasePath : "");
1900
+ const aliasTargets = (spec) => {
1901
+ const out = [];
1902
+ for (const [pattern, targets] of Object.entries(options.paths ?? {})) {
1903
+ const star = pattern.indexOf("*");
1904
+ if (star === -1) {
1905
+ if (spec === pattern) {
1906
+ out.push(...targets);
1907
+ }
1908
+ continue;
1909
+ }
1910
+ const prefix = pattern.slice(0, star);
1911
+ const suffix = pattern.slice(star + 1);
1912
+ if (spec.length >= prefix.length + suffix.length && spec.startsWith(prefix) && spec.endsWith(suffix)) {
1913
+ const filler = spec.slice(prefix.length, spec.length - suffix.length);
1914
+ out.push(...targets.map((t) => t.replace("*", filler)));
1915
+ }
1916
+ }
1917
+ return out.map((t) => path.resolve(pathsBase, t));
1918
+ };
1919
+ return (fromFile, spec) => {
1920
+ if (spec.startsWith(".")) {
1921
+ return probe(path.resolve(path.dirname(fromFile), spec));
1922
+ }
1923
+ for (const target of aliasTargets(spec)) {
1924
+ const hit = probe(target);
1925
+ if (hit !== null) {
1926
+ return hit;
1927
+ }
1928
+ }
1929
+ return null;
1930
+ };
1838
1931
  }
1839
1932
  function collectAllGates(packs) {
1840
1933
  const gates = /* @__PURE__ */ new Set();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/adapter-typescript",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "type": "module",
5
5
  "description": "TypeScript adapter for suss — walks source files with ts-morph and emits raw extractions for the suss pipeline.",
6
6
  "keywords": [
@@ -46,10 +46,10 @@
46
46
  "typecheck": "tsc --noEmit"
47
47
  },
48
48
  "dependencies": {
49
- "@suss/behavioral-ir": "0.5.4",
50
- "@suss/datalog": "0.5.4",
51
- "@suss/extractor": "0.5.4",
52
- "@suss/resolution": "0.5.4",
49
+ "@suss/behavioral-ir": "0.5.5",
50
+ "@suss/datalog": "0.5.5",
51
+ "@suss/extractor": "0.5.5",
52
+ "@suss/resolution": "0.5.5",
53
53
  "graphql": "^16.8.0",
54
54
  "picomatch": "^4.0.4",
55
55
  "ts-morph": "^23.0.0"