doc-freshness-checker 2.0.17 → 2.0.19

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/README.md CHANGED
@@ -340,6 +340,8 @@ through 1. Omitted factors retain their defaults; weights are not normalized, an
340
340
  documented `0..100` range. Grade thresholds must be finite values from 0
341
341
  through 100 in strictly descending order: `gradeA > gradeB > gradeC > gradeD`.
342
342
 
343
+ Configured supported manifests (`package.json`, `requirements.txt`, `pyproject.toml`, `go.mod`, `Cargo.toml`, and `pom.xml`) must be readable; read failures abort validation. Parser errors also abort when a parser reports them. The regex-based parsers may treat malformed content as empty or partial and report missing dependencies instead. Unknown manifest basenames are ignored for compatibility. These parsers do not execute package managers.
344
+
343
345
  For details on CLI-to-config mapping and precedence, see [CLI and Configuration Precedence](docs/cli-and-config-precedence.md). For the internal execution pipeline, see [Runtime Architecture](docs/runtime-architecture.md).
344
346
 
345
347
  ## CI Integration
@@ -11,15 +11,19 @@ export class DependencyExtractor extends BaseExtractor {
11
11
  }
12
12
  extract(document) {
13
13
  const references = [];
14
+ const plainPackageEcosystem = this.ecosystems.includes('npm') ? 'npm' : 'pypi';
15
+ const pypiOnly = this.ecosystems.length === 1 && this.ecosystems[0] === 'pypi';
14
16
  const patterns = [
15
17
  // npm scoped packages: @scope/package-name
16
18
  { regex: /`(@[a-z0-9-]+\/[a-z0-9-]+)`/g, ecosystem: 'npm' },
17
- // npm regular packages in backticks
18
- { regex: /`([a-z][a-z0-9-]{2,})`/g, ecosystem: 'npm' },
19
+ // PyPI names distinguished by underscores or dots
20
+ { regex: /`([a-z][a-z0-9._-]{2,})`/g, ecosystem: 'pypi', requiresPythonSeparator: true },
21
+ // Plain/hyphen names are npm by default and PyPI when npm is disabled
22
+ { regex: /`([a-z][a-z0-9-]{2,})`/g, ecosystem: plainPackageEcosystem },
19
23
  // Go packages
20
24
  { regex: /`(github\.com\/[a-zA-Z0-9\-_]+\/[a-zA-Z0-9\-_]+)`/g, ecosystem: 'go' },
21
25
  ];
22
- for (const { regex, ecosystem } of patterns) {
26
+ for (const { regex, ecosystem, requiresPythonSeparator } of patterns) {
23
27
  if (!this.ecosystems.includes(ecosystem)) {
24
28
  continue;
25
29
  }
@@ -27,8 +31,11 @@ export class DependencyExtractor extends BaseExtractor {
27
31
  const re = new RegExp(regex.source, regex.flags);
28
32
  while ((match = re.exec(document.content)) !== null) {
29
33
  const pkg = match[1];
34
+ if (requiresPythonSeparator && !/[._]/.test(pkg)) {
35
+ continue;
36
+ }
30
37
  // Filter out common false positives
31
- if (this.isFalsePositive(pkg)) {
38
+ if (this.isFalsePositive(pkg, ecosystem === 'pypi' && pypiOnly)) {
32
39
  continue;
33
40
  }
34
41
  references.push({
@@ -43,7 +50,7 @@ export class DependencyExtractor extends BaseExtractor {
43
50
  }
44
51
  return references;
45
52
  }
46
- isFalsePositive(pkg) {
53
+ isFalsePositive(pkg, allowDottedPyPI) {
47
54
  // Skip very short names
48
55
  if (pkg.length < 3) {
49
56
  return true;
@@ -87,8 +94,8 @@ export class DependencyExtractor extends BaseExtractor {
87
94
  if (commonWords.includes(pkg.toLowerCase())) {
88
95
  return true;
89
96
  }
90
- // Skip file extensions
91
- if (/\.[a-z]{2,4}$/.test(pkg)) {
97
+ // Dotted names are ambiguous with file names unless PyPI is the only enabled ecosystem.
98
+ if (!allowDottedPyPI && /\.[a-z]{2,4}$/i.test(pkg)) {
92
99
  return true;
93
100
  }
94
101
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"dependencyExtractor.js","sourceRoot":"","sources":["../../../src/parsers/extractors/dependencyExtractor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dependencyExtractor.js","sourceRoot":"","sources":["../../../src/parsers/extractors/dependencyExtractor.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,28 @@ describe('DependencyExtractor', () => {
23
23
  expect(values).toContain('express');
24
24
  expect(values).toContain('commander');
25
25
  });
26
+ it('extracts underscore PyPI names without treating dotted names as packages by default', () => {
27
+ const refs = extractor.extract(makeDoc('Use `foo_bar`, `foo.bar`, and `foo-bar`'));
28
+ expect(refs.map(({ value, ecosystem }) => ({ value, ecosystem }))).toEqual([
29
+ { value: 'foo_bar', ecosystem: 'pypi' },
30
+ { value: 'foo-bar', ecosystem: 'npm' },
31
+ ]);
32
+ });
33
+ it('assigns ordinary packages to PyPI when npm is disabled', () => {
34
+ const pypiOnly = new DependencyExtractor({ ecosystems: ['pypi'] });
35
+ const refs = pypiOnly.extract(makeDoc('Use `requests`, `pytest-cov`, `foo_bar`, and `foo.bar`'));
36
+ expect(refs.map(({ value, ecosystem }) => ({ value, ecosystem }))).toEqual([
37
+ { value: 'foo_bar', ecosystem: 'pypi' },
38
+ { value: 'foo.bar', ecosystem: 'pypi' },
39
+ { value: 'requests', ecosystem: 'pypi' },
40
+ { value: 'pytest-cov', ecosystem: 'pypi' },
41
+ ]);
42
+ });
43
+ it.each(['go', 'crates'])('filters dotted names when PyPI is combined with %s', (otherEcosystem) => {
44
+ const mixed = new DependencyExtractor({ ecosystems: ['pypi', otherEcosystem] });
45
+ const refs = mixed.extract(makeDoc('Use `foo.bar` and edit `config.mjs`'));
46
+ expect(refs).toHaveLength(0);
47
+ });
26
48
  it('extracts Go packages', () => {
27
49
  const doc = makeDoc('Import `github.com/gin-gonic/gin`');
28
50
  const refs = extractor.extract(doc);
@@ -34,7 +56,7 @@ describe('DependencyExtractor', () => {
34
56
  expect(refs).toHaveLength(0);
35
57
  });
36
58
  it('filters out file extensions', () => {
37
- const doc = makeDoc('Edit `styles.css` and `app.tsx`');
59
+ const doc = makeDoc('Open `archive.zip`, `config.mjs`, `index.php`, `app.vue`, `schema.sql`, and `package.lock`');
38
60
  const refs = extractor.extract(doc);
39
61
  expect(refs).toHaveLength(0);
40
62
  });
@@ -1 +1 @@
1
- {"version":3,"file":"dependencyExtractor.test.js","sourceRoot":"","sources":["../../../src/parsers/extractors/dependencyExtractor.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dependencyExtractor.test.js","sourceRoot":"","sources":["../../../src/parsers/extractors/dependencyExtractor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAG/D,SAAS,OAAO,CAAC,OAAe;IAC9B,OAAO;QACL,IAAI,EAAE,cAAc;QACpB,YAAY,EAAE,uBAAuB;QACrC,OAAO;QACP,MAAM,EAAE,UAAU;QAClB,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QAC1B,UAAU,EAAE,EAAE;KACf,CAAC;AACJ,CAAC;AAED,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,SAAS,GAAG,IAAI,mBAAmB,EAAE,CAAC;IAE5C,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,GAAG,GAAG,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACvD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,OAAO,CAAC,uCAAuC,CAAC,CAAC;QAC7D,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qFAAqF,EAAE,GAAG,EAAE;QAC7F,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,yCAAyC,CAAC,CAAC,CAAC;QACnF,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACzE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE;YACvC,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE;SACvC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,QAAQ,GAAG,IAAI,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,wDAAwD,CAAC,CAAC,CAAC;QACjG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YACzE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE;YACvC,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE;YACvC,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE;YACxC,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE;SAC3C,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,oDAAoD,EAAE,CAAC,cAAc,EAAE,EAAE;QACjG,MAAM,KAAK,GAAG,IAAI,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;QAChF,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,qCAAqC,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,GAAG,GAAG,OAAO,CAAC,mCAAmC,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,0BAA0B,IAAI,CAAC,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,6CAA6C,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,GAAG,GAAG,OAAO,CAAC,4FAA4F,CAAC,CAAC;QAClH,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,OAAO,CAAC,8CAA8C,CAAC,CAAC;QACpE,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ export declare const PEP621_PYPROJECT_FIXTURES: readonly [{
2
+ readonly name: "core and optional dependency arrays";
3
+ readonly content: "[project]\nname = \"example\"\ndependencies = [\n \"fastapi>=0.100,<1\",\n \"uvicorn==0.30.1\", # server\n # \"ghost>=9\" ]\n \"typing_extensions[docs]===4.8; python_version < '3.13'\",\n \"direct_dep @ https://example.com/archive.whl#sha256=abc\",\n]\n\n[project.optional-dependencies]\ntest = [\"pytest==8.3.0\", \"httpx[http2]>=0.27\"]\ndocs = [\n # \"ghost-optional==9\" ]\n \"sphinx!=7\",\n \"mkdocs_material==9.5\",\n]\n";
4
+ readonly dependencies: {
5
+ readonly fastapi: "any";
6
+ readonly uvicorn: "0.30.1";
7
+ readonly typing_extensions: "4.8";
8
+ readonly direct_dep: "any";
9
+ readonly pytest: "8.3.0";
10
+ readonly httpx: "any";
11
+ readonly sphinx: "any";
12
+ readonly mkdocs_material: "9.5";
13
+ };
14
+ }, {
15
+ readonly name: "inline arrays with whitespace, pins, and canonical collisions";
16
+ readonly content: "[project]\ndependencies = [\" space_pkg [x] ==3.0 \", \"paren_pkg (==4.0)\", \"compatible_pkg (~= 2.0)\", \"foo_bar==1.0\", \"foo-bar==2.0\", \"reverse-name==2.0\", \"reverse_name==1.0\", \"same.name==5.0\", \"same_name==5.0\", \"epoch_pkg==2!4.2\", \"date_pkg==2024.01\"]\n";
17
+ readonly dependencies: {
18
+ readonly space_pkg: "3.0";
19
+ readonly paren_pkg: "4.0";
20
+ readonly compatible_pkg: "2.0";
21
+ readonly foo_bar: "any";
22
+ readonly 'foo-bar': "any";
23
+ readonly 'reverse-name': "any";
24
+ readonly reverse_name: "any";
25
+ readonly 'same.name': "5.0";
26
+ readonly same_name: "5.0";
27
+ readonly epoch_pkg: "2!4.2";
28
+ readonly date_pkg: "2024.01";
29
+ };
30
+ }, {
31
+ readonly name: "array-of-table boundary after optional dependencies";
32
+ readonly content: "[project]\ndependencies = [\"core_pkg==1.0\"]\n\n[project.optional-dependencies]\ntest = [\"optional_pkg==2.0\"]\n\n[[tool.demo]]\ntags = [\"ghost==9\"]\n";
33
+ readonly dependencies: {
34
+ readonly core_pkg: "1.0";
35
+ readonly optional_pkg: "2.0";
36
+ };
37
+ }, {
38
+ readonly name: "multiline project strings before dependencies";
39
+ readonly content: "[project]\ndescription = \"\"\"\n[not-a-real-section]\n\"ghost==9\"\n\"\"\"\nreadme = '''\ndependencies = [\"evil==9.9.9\"]\n'''\ndependencies = [\"requests==2.0\"]\n";
40
+ readonly dependencies: {
41
+ readonly requests: "2.0";
42
+ };
43
+ }];
@@ -0,0 +1,85 @@
1
+ export const PEP621_PYPROJECT_FIXTURES = [
2
+ {
3
+ name: 'core and optional dependency arrays',
4
+ content: `[project]
5
+ name = "example"
6
+ dependencies = [
7
+ "fastapi>=0.100,<1",
8
+ "uvicorn==0.30.1", # server
9
+ # "ghost>=9" ]
10
+ "typing_extensions[docs]===4.8; python_version < '3.13'",
11
+ "direct_dep @ https://example.com/archive.whl#sha256=abc",
12
+ ]
13
+
14
+ [project.optional-dependencies]
15
+ test = ["pytest==8.3.0", "httpx[http2]>=0.27"]
16
+ docs = [
17
+ # "ghost-optional==9" ]
18
+ "sphinx!=7",
19
+ "mkdocs_material==9.5",
20
+ ]
21
+ `,
22
+ dependencies: {
23
+ fastapi: 'any',
24
+ uvicorn: '0.30.1',
25
+ typing_extensions: '4.8',
26
+ direct_dep: 'any',
27
+ pytest: '8.3.0',
28
+ httpx: 'any',
29
+ sphinx: 'any',
30
+ mkdocs_material: '9.5',
31
+ },
32
+ },
33
+ {
34
+ name: 'inline arrays with whitespace, pins, and canonical collisions',
35
+ content: `[project]
36
+ dependencies = [" space_pkg [x] ==3.0 ", "paren_pkg (==4.0)", "compatible_pkg (~= 2.0)", "foo_bar==1.0", "foo-bar==2.0", "reverse-name==2.0", "reverse_name==1.0", "same.name==5.0", "same_name==5.0", "epoch_pkg==2!4.2", "date_pkg==2024.01"]
37
+ `,
38
+ dependencies: {
39
+ space_pkg: '3.0',
40
+ paren_pkg: '4.0',
41
+ compatible_pkg: '2.0',
42
+ foo_bar: 'any',
43
+ 'foo-bar': 'any',
44
+ 'reverse-name': 'any',
45
+ reverse_name: 'any',
46
+ 'same.name': '5.0',
47
+ same_name: '5.0',
48
+ epoch_pkg: '2!4.2',
49
+ date_pkg: '2024.01',
50
+ },
51
+ },
52
+ {
53
+ name: 'array-of-table boundary after optional dependencies',
54
+ content: `[project]
55
+ dependencies = ["core_pkg==1.0"]
56
+
57
+ [project.optional-dependencies]
58
+ test = ["optional_pkg==2.0"]
59
+
60
+ [[tool.demo]]
61
+ tags = ["ghost==9"]
62
+ `,
63
+ dependencies: {
64
+ core_pkg: '1.0',
65
+ optional_pkg: '2.0',
66
+ },
67
+ },
68
+ {
69
+ name: 'multiline project strings before dependencies',
70
+ content: `[project]
71
+ description = """
72
+ [not-a-real-section]
73
+ "ghost==9"
74
+ """
75
+ readme = '''
76
+ dependencies = ["evil==9.9.9"]
77
+ '''
78
+ dependencies = ["requests==2.0"]
79
+ `,
80
+ dependencies: {
81
+ requests: '2.0',
82
+ },
83
+ },
84
+ ];
85
+ //# sourceMappingURL=manifestFixtures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifestFixtures.js","sourceRoot":"","sources":["../../src/test-utils/manifestFixtures.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC;QACE,IAAI,EAAE,qCAAqC;QAC3C,OAAO,EAAE;;;;;;;;;;;;;;;;;CAiBZ;QACG,YAAY,EAAE;YACZ,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,QAAQ;YACjB,iBAAiB,EAAE,KAAK;YACxB,UAAU,EAAE,KAAK;YACjB,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,KAAK;YACb,eAAe,EAAE,KAAK;SACvB;KACF;IACD;QACE,IAAI,EAAE,+DAA+D;QACrE,OAAO,EAAE;;CAEZ;QACG,YAAY,EAAE;YACZ,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,KAAK;YAChB,cAAc,EAAE,KAAK;YACrB,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,KAAK;YAChB,cAAc,EAAE,KAAK;YACrB,YAAY,EAAE,KAAK;YACnB,WAAW,EAAE,KAAK;YAClB,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,OAAO;YAClB,QAAQ,EAAE,SAAS;SACpB;KACF;IACD;QACE,IAAI,EAAE,qDAAqD;QAC3D,OAAO,EAAE;;;;;;;;CAQZ;QACG,YAAY,EAAE;YACZ,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,KAAK;SACpB;KACF;IACD;QACE,IAAI,EAAE,+CAA+C;QACrD,OAAO,EAAE;;;;;;;;;CASZ;QACG,YAAY,EAAE;YACZ,QAAQ,EAAE,KAAK;SAChB;KACF;CACO,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  export function resolveManifestPaths(config) {
3
3
  const rootDir = config.rootDir || process.cwd();
4
- return (config.manifestFiles || ['package.json']).map((manifest) => path.join(rootDir, manifest));
4
+ return (config.manifestFiles || ['package.json']).map((manifest) => path.resolve(rootDir, manifest));
5
5
  }
6
6
  //# sourceMappingURL=manifestPaths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifestPaths.js","sourceRoot":"","sources":["../../src/utils/manifestPaths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAChD,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACpG,CAAC"}
1
+ {"version":3,"file":"manifestPaths.js","sourceRoot":"","sources":["../../src/utils/manifestPaths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,UAAU,oBAAoB,CAAC,MAA0B;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAChD,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvG,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function parsePyprojectDependencies(content: string): Map<string, string>;
2
+ export declare function parseRequirementsDependencies(content: string): Map<string, string>;
3
+ export declare function canonicalizePythonPackageName(name: string): string;
@@ -0,0 +1,114 @@
1
+ const QUOTED_STRING = /"((?:\\.|[^"\\])*)"|'([^']*)'/g;
2
+ const TOML_COMMENT = /("(?:\\.|[^"\\])*"|'[^']*')|#[^\r\n]*/g;
3
+ const TOML_ARRAY = /^\[((?:[^"'\]]|"(?:\\.|[^"\\])*"|'[^']*')*)\]/;
4
+ const TOML_MULTILINE_STRING = /"""(?:\\[\s\S]|"{1,2}(?!")|[^"\\])*"""|'''(?:'{1,2}(?!')|[^'])*'''/g;
5
+ export function parsePyprojectDependencies(content) {
6
+ const dependencyGroups = new Map();
7
+ const uncommented = stripComments(content.replace(TOML_MULTILINE_STRING, ''));
8
+ const coreSection = getSection(uncommented, 'project');
9
+ const optionalSection = getSection(uncommented, 'project.optional-dependencies');
10
+ const arrays = [
11
+ ...findArrays(coreSection, /^[ \t]*dependencies[ \t]*=[ \t]*\[/gm),
12
+ ...findArrays(optionalSection, /^[ \t]*[a-zA-Z0-9._-]+[ \t]*=[ \t]*\[/gm),
13
+ ];
14
+ for (const source of arrays) {
15
+ for (const match of source.matchAll(QUOTED_STRING)) {
16
+ const parsed = parsePythonRequirement(match[1] ?? match[2]);
17
+ if (!parsed) {
18
+ continue;
19
+ }
20
+ addDependency(dependencyGroups, parsed.name, parsed.version);
21
+ }
22
+ }
23
+ return flattenDependencyGroups(dependencyGroups);
24
+ }
25
+ export function parseRequirementsDependencies(content) {
26
+ const dependencyGroups = new Map();
27
+ for (const line of content.split('\n')) {
28
+ const parsed = parsePythonRequirement(stripRequirementInlineComment(line));
29
+ if (!parsed) {
30
+ continue;
31
+ }
32
+ addDependency(dependencyGroups, parsed.name, parsed.version);
33
+ }
34
+ return flattenDependencyGroups(dependencyGroups);
35
+ }
36
+ function flattenDependencyGroups(dependencyGroups) {
37
+ const dependencies = new Map();
38
+ for (const group of dependencyGroups.values()) {
39
+ for (const name of group.names) {
40
+ dependencies.set(name, group.version);
41
+ }
42
+ }
43
+ return dependencies;
44
+ }
45
+ export function canonicalizePythonPackageName(name) {
46
+ return name.toLowerCase().replace(/[-_.]+/g, '-');
47
+ }
48
+ function stripComments(content) {
49
+ return content.replace(TOML_COMMENT, (_match, quoted) => quoted ?? '');
50
+ }
51
+ function getSection(content, name) {
52
+ const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
53
+ const header = new RegExp(`^[ \\t]*\\[${escapedName}\\][ \\t]*\\r?$`, 'm').exec(content);
54
+ if (!header) {
55
+ return undefined;
56
+ }
57
+ const remainder = content.slice(header.index + header[0].length);
58
+ const nextSection = remainder.search(/^[ \t]*(?:\[[^\]\r\n]+\]|\[\[[^\]\r\n]+\]\])[ \t]*\r?$/m);
59
+ return nextSection === -1 ? remainder : remainder.slice(0, nextSection);
60
+ }
61
+ function findArrays(section, assignmentPattern) {
62
+ if (!section) {
63
+ return [];
64
+ }
65
+ const arrays = [];
66
+ for (const match of section.matchAll(assignmentPattern)) {
67
+ const openingBracket = match.index + match[0].lastIndexOf('[');
68
+ const array = section.slice(openingBracket).match(TOML_ARRAY)?.[1];
69
+ if (array !== undefined) {
70
+ arrays.push(array);
71
+ }
72
+ }
73
+ return arrays;
74
+ }
75
+ function getComparableVersion(constraint) {
76
+ const version = constraint.match(/^(?:={2,3}|~=)\s*([^,\s*]+)\s*$/) ?? constraint.match(/^\(\s*(?:={2,3}|~=)\s*([^,\s*()]+)\s*\)$/);
77
+ return version?.[1];
78
+ }
79
+ function parsePythonRequirement(requirement) {
80
+ const parsed = requirement.trim().match(/^([a-zA-Z0-9][a-zA-Z0-9._-]*)(?:\s*\[[^\]]+\])?\s*(.*)$/);
81
+ if (!parsed) {
82
+ return undefined;
83
+ }
84
+ const constraint = parsed[2].split(';', 1)[0].trim();
85
+ return { name: parsed[1], version: getComparableVersion(constraint) ?? 'any' };
86
+ }
87
+ function stripRequirementInlineComment(requirement) {
88
+ let quote;
89
+ for (let index = 0; index < requirement.length; index += 1) {
90
+ const character = requirement[index];
91
+ if ((character === '"' || character === "'") && requirement[index - 1] !== '\\') {
92
+ quote = quote === character ? undefined : quote || character;
93
+ }
94
+ else if (character === '#' && !quote && index > 0 && /\s/.test(requirement[index - 1])) {
95
+ return requirement.slice(0, index).trimEnd();
96
+ }
97
+ }
98
+ return requirement;
99
+ }
100
+ function addDependency(dependencies, name, version) {
101
+ const normalizedName = name.toLowerCase();
102
+ const canonicalName = canonicalizePythonPackageName(normalizedName);
103
+ const existing = dependencies.get(canonicalName);
104
+ if (existing) {
105
+ existing.names.add(normalizedName);
106
+ if (existing.version !== version) {
107
+ existing.version = 'any';
108
+ }
109
+ }
110
+ else {
111
+ dependencies.set(canonicalName, { names: new Set([normalizedName]), version });
112
+ }
113
+ }
114
+ //# sourceMappingURL=pythonDependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pythonDependencies.js","sourceRoot":"","sources":["../../src/utils/pythonDependencies.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,9 @@ import type { DocFreshnessConfig, Document, Reference, ValidationResult } from '
4
4
  */
5
5
  export declare class DependencyValidator {
6
6
  private dependencies;
7
+ private pythonDependencies;
7
8
  private loadedFromKey;
8
9
  constructor();
9
10
  private loadDependencies;
10
- private parseManifest;
11
11
  validateBatch(references: Reference[], _document: Document, config: DocFreshnessConfig): Promise<ValidationResult[]>;
12
12
  }
@@ -1,14 +1,17 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { resolveManifestPaths } from '../utils/manifestPaths.js';
4
+ import { canonicalizePythonPackageName, parsePyprojectDependencies, parseRequirementsDependencies } from '../utils/pythonDependencies.js';
4
5
  /**
5
6
  * Validates that mentioned dependencies exist in manifest files
6
7
  */
7
8
  export class DependencyValidator {
8
9
  dependencies;
10
+ pythonDependencies;
9
11
  loadedFromKey;
10
12
  constructor() {
11
13
  this.dependencies = null;
14
+ this.pythonDependencies = new Set();
12
15
  this.loadedFromKey = null;
13
16
  }
14
17
  /** @internal */
@@ -21,25 +24,31 @@ export class DependencyValidator {
21
24
  if (this.dependencies && this.loadedFromKey === configKey) {
22
25
  return;
23
26
  }
24
- this.dependencies = new Set();
25
- this.loadedFromKey = configKey;
27
+ const dependencies = new Set();
28
+ const pythonDependencies = new Set();
26
29
  for (const manifestPath of manifestPaths) {
27
30
  const fileName = path.basename(manifestPath);
31
+ const parser = manifestDependencyParsers[fileName];
32
+ if (!parser) {
33
+ continue;
34
+ }
28
35
  try {
29
36
  const content = await fs.promises.readFile(manifestPath, 'utf-8');
30
- const deps = await this.parseManifest(fileName, content);
37
+ const deps = parser(content);
31
38
  for (const dep of deps) {
32
- this.dependencies.add(dep.toLowerCase());
39
+ dependencies.add(dep.toLowerCase());
40
+ if (fileName === 'pyproject.toml' || fileName === 'requirements.txt') {
41
+ pythonDependencies.add(canonicalizePythonPackageName(dep));
42
+ }
33
43
  }
34
44
  }
35
- catch {
36
- // Manifest not found
45
+ catch (cause) {
46
+ throw new Error(`Failed to load manifest: ${manifestPath}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
37
47
  }
38
48
  }
39
- }
40
- async parseManifest(fileName, content) {
41
- const parser = manifestDependencyParsers[fileName];
42
- return parser ? parser(content) : [];
49
+ this.dependencies = dependencies;
50
+ this.pythonDependencies = pythonDependencies;
51
+ this.loadedFromKey = configKey;
43
52
  }
44
53
  async validateBatch(references, _document, config) {
45
54
  await this.loadDependencies(config);
@@ -47,7 +56,9 @@ export class DependencyValidator {
47
56
  for (const ref of references) {
48
57
  const pkg = ref.value.toLowerCase();
49
58
  // Check if package exists in dependencies
50
- const found = this.dependencies.has(pkg);
59
+ const found = ref.ecosystem === 'pypi'
60
+ ? this.pythonDependencies.has(canonicalizePythonPackageName(pkg))
61
+ : this.dependencies.has(pkg) || (!ref.ecosystem && this.pythonDependencies.has(canonicalizePythonPackageName(pkg)));
51
62
  if (found) {
52
63
  results.push({
53
64
  reference: ref,
@@ -71,19 +82,8 @@ const manifestDependencyParsers = {
71
82
  const json = JSON.parse(content);
72
83
  return ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'].flatMap((key) => Object.keys(json[key] || {}));
73
84
  },
74
- 'requirements.txt': (content) => content
75
- .split('\n')
76
- .map((line) => line.trim())
77
- .filter((line) => line && !line.startsWith('#'))
78
- .map((line) => line.match(/^([a-zA-Z0-9\-_]+)/)?.[1])
79
- .filter((dep) => Boolean(dep)),
80
- 'pyproject.toml': (content) => {
81
- const depsMatch = content.match(/\[project\.dependencies\]([\s\S]*?)(?:\[|$)/);
82
- if (!depsMatch) {
83
- return [];
84
- }
85
- return Array.from(depsMatch[1].matchAll(/"([^"<>=!]+)/g), (match) => match[1].split(/[<>=!]/)[0]);
86
- },
85
+ 'requirements.txt': (content) => Array.from(parseRequirementsDependencies(content).keys()),
86
+ 'pyproject.toml': (content) => Array.from(parsePyprojectDependencies(content).keys()),
87
87
  'go.mod': (content) => {
88
88
  const requireMatch = content.match(/require\s+\(([\s\S]*?)\)/);
89
89
  if (!requireMatch) {
@@ -1 +1 @@
1
- {"version":3,"file":"dependencyValidator.js","sourceRoot":"","sources":["../../src/validators/dependencyValidator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dependencyValidator.js","sourceRoot":"","sources":["../../src/validators/dependencyValidator.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,9 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { DependencyValidator } from './dependencyValidator.js';
4
+ import { DependencyExtractor } from '../parsers/extractors/dependencyExtractor.js';
4
5
  import { makeDoc, makeRef as makeBaseRef } from '../test-utils/factories.js';
6
+ import { PEP621_PYPROJECT_FIXTURES } from '../test-utils/manifestFixtures.js';
5
7
  function makeRef(value) {
6
8
  return makeBaseRef('dependency', value, { ecosystem: 'npm' });
7
9
  }
@@ -54,12 +56,6 @@ describe('DependencyValidator', () => {
54
56
  const results = await validator.validateBatch([makeRef('nonexistent-pkg')], doc, config);
55
57
  expect(results[0].severity).toBe('error');
56
58
  });
57
- it('handles missing manifest files gracefully', async () => {
58
- const validator = new DependencyValidator();
59
- const config = { rootDir: process.cwd(), manifestFiles: ['nonexistent.json'] };
60
- const results = await validator.validateBatch([makeRef('anything')], doc, config);
61
- expect(results[0].valid).toBe(false);
62
- });
63
59
  it('uses default manifestFiles when not specified', async () => {
64
60
  const validator = new DependencyValidator();
65
61
  const config = { rootDir: process.cwd() };
@@ -79,11 +75,22 @@ describe('DependencyValidator', () => {
79
75
  ]);
80
76
  expect(results).toEqual([true, true, true]);
81
77
  });
82
- it('parses pyproject.toml', async () => {
83
- const results = await writeAndValidate('pyproject.toml', '[project.dependencies]\n"fastapi>=0.100"\n"uvicorn"', [
84
- 'fastapi',
85
- 'uvicorn',
86
- ]);
78
+ it('parses dotted requirements names and validates their Python aliases', async () => {
79
+ const dir = path.join(tmpBase, 'requirements-dotted-name');
80
+ const filePath = path.join(dir, 'requirements.txt');
81
+ await fs.promises.mkdir(dir, { recursive: true });
82
+ await fs.promises.writeFile(filePath, 'foo.bar==7\n');
83
+ const validator = new DependencyValidator();
84
+ const config = {
85
+ rootDir: process.cwd(),
86
+ manifestFiles: [path.relative(process.cwd(), filePath)],
87
+ };
88
+ const references = ['foo.bar', 'foo_bar', 'foo-bar'].map((value) => makeBaseRef('dependency', value, { ecosystem: 'pypi' }));
89
+ const results = await validator.validateBatch(references, doc, config);
90
+ expect(results.map((result) => result.valid)).toEqual([true, true, true]);
91
+ });
92
+ it('parses PEP 621 core and optional dependencies', async () => {
93
+ const results = await writeAndValidate('pyproject.toml', PEP621_PYPROJECT_FIXTURES[0].content, ['fastapi', 'pytest']);
87
94
  expect(results).toEqual([true, true]);
88
95
  });
89
96
  it('parses go.mod', async () => {
@@ -105,6 +112,31 @@ describe('DependencyValidator', () => {
105
112
  const results = await validator.validateBatch([makeRef('Vitest'), makeRef('VITEST')], doc, config);
106
113
  expect(results.every((r) => r.valid)).toBe(true);
107
114
  });
115
+ it('validates extracted PyPI aliases without treating npm names as equivalent', async () => {
116
+ const dir = path.join(tmpBase, 'mixed-ecosystems');
117
+ await fs.promises.mkdir(dir, { recursive: true });
118
+ const packageJson = path.join(dir, 'package.json');
119
+ const pyproject = path.join(dir, 'pyproject.toml');
120
+ await fs.promises.writeFile(packageJson, JSON.stringify({ dependencies: { foo_bar: '1.0.0', 'foo.bar': '1.0.0' } }));
121
+ await fs.promises.writeFile(pyproject, '[project]\ndependencies = ["python-name==1.0"]\n');
122
+ const validator = new DependencyValidator();
123
+ const config = {
124
+ rootDir: process.cwd(),
125
+ manifestFiles: [path.relative(process.cwd(), packageJson), path.relative(process.cwd(), pyproject)],
126
+ };
127
+ const content = 'Use `python_name`, `python.name`, `foo_bar`, and `foo.bar`';
128
+ const integrationDoc = makeDoc({ content, lines: [content] });
129
+ const references = new DependencyExtractor({ ecosystems: ['pypi'] }).extract(integrationDoc);
130
+ integrationDoc.references = references;
131
+ const results = await validator.validateBatch(references, integrationDoc, config);
132
+ expect(references.map(({ value, ecosystem }) => ({ value, ecosystem }))).toEqual([
133
+ { value: 'python_name', ecosystem: 'pypi' },
134
+ { value: 'python.name', ecosystem: 'pypi' },
135
+ { value: 'foo_bar', ecosystem: 'pypi' },
136
+ { value: 'foo.bar', ecosystem: 'pypi' },
137
+ ]);
138
+ expect(results.map((result) => result.valid)).toEqual([true, true, false, false]);
139
+ });
108
140
  describe('manifest edge cases', () => {
109
141
  async function writeAndValidate(fileName, content, pkgNames) {
110
142
  const dirName = `edge-${fileName.replace(/\./g, '-')}`;
@@ -122,10 +154,6 @@ describe('DependencyValidator', () => {
122
154
  const results = await writeAndValidate('Cargo.toml', '[package]\nname = "myapp"\nversion = "0.1.0"\n', ['myapp']);
123
155
  expect(results).toEqual([false]);
124
156
  });
125
- it('handles unknown manifest format gracefully', async () => {
126
- const results = await writeAndValidate('build.gradle', 'implementation "org.something:artifact:1.0"\n', ['org.something']);
127
- expect(results).toEqual([false]);
128
- });
129
157
  it('handles requirements.txt with blank lines and comments only', async () => {
130
158
  const results = await writeAndValidate('requirements.txt', '# this is a comment\n\n# another comment\n', ['flask']);
131
159
  expect(results).toEqual([false]);