@trustify-da/trustify-da-javascript-client 0.3.0-ea.a783c26 → 0.3.0-ea.a8c3942
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/package.json +0 -1
- package/dist/src/cyclone_dx_sbom.d.ts +7 -1
- package/dist/src/cyclone_dx_sbom.js +18 -5
- package/dist/src/index.d.ts +62 -3
- package/dist/src/index.js +68 -4
- package/dist/src/providers/base_java.d.ts +0 -9
- package/dist/src/providers/base_java.js +2 -38
- package/dist/src/providers/base_pyproject.d.ts +5 -1
- package/dist/src/providers/base_pyproject.js +5 -4
- package/dist/src/providers/golang_gomodules.d.ts +9 -0
- package/dist/src/providers/golang_gomodules.js +64 -7
- package/dist/src/providers/java_gradle.d.ts +19 -0
- package/dist/src/providers/java_gradle.js +116 -2
- package/dist/src/providers/java_maven.d.ts +8 -0
- package/dist/src/providers/java_maven.js +93 -1
- package/dist/src/providers/javascript_pnpm.js +6 -2
- package/dist/src/providers/marker_evaluator.d.ts +14 -0
- package/dist/src/providers/marker_evaluator.js +191 -0
- package/dist/src/providers/python_controller.d.ts +5 -1
- package/dist/src/providers/python_controller.js +1 -1
- package/dist/src/providers/python_pip.d.ts +4 -0
- package/dist/src/providers/python_pip.js +4 -4
- package/dist/src/providers/python_pip_pyproject.js +3 -1
- package/dist/src/providers/python_poetry.d.ts +35 -3
- package/dist/src/providers/python_poetry.js +73 -10
- package/dist/src/providers/python_uv.d.ts +28 -0
- package/dist/src/providers/python_uv.js +78 -0
- package/dist/src/sbom.d.ts +7 -1
- package/dist/src/sbom.js +4 -2
- package/dist/src/tools.d.ts +26 -0
- package/dist/src/tools.js +58 -0
- package/dist/src/workspace.d.ts +9 -0
- package/dist/src/workspace.js +1 -1
- package/package.json +1 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { parse as parseToml } from 'smol-toml';
|
|
3
4
|
import { environmentVariableIsPopulated, getCustom, getCustomPath, invokeCommand } from '../tools.js';
|
|
4
5
|
import Base_pyproject from './base_pyproject.js';
|
|
6
|
+
import { evaluateMarker } from './marker_evaluator.js';
|
|
5
7
|
export default class Python_poetry extends Base_pyproject {
|
|
6
8
|
/**
|
|
7
9
|
* Poetry has no native workspace/monorepo support (python-poetry/poetry#2270).
|
|
@@ -43,7 +45,9 @@ export default class Python_poetry extends Base_pyproject {
|
|
|
43
45
|
let treeOutput = this._getPoetryShowTreeOutput(manifestDir, hasDevGroup, opts);
|
|
44
46
|
let showAllOutput = this._getPoetryShowAllOutput(manifestDir, opts);
|
|
45
47
|
let versionMap = this._parsePoetryShowAll(showAllOutput);
|
|
46
|
-
|
|
48
|
+
let lockDir = this._findLockFileDir(manifestDir, opts);
|
|
49
|
+
let markerData = this._extractMarkerData(lockDir, parsed);
|
|
50
|
+
return this._parsePoetryTree(treeOutput, versionMap, markerData);
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Get poetry show --tree output.
|
|
@@ -98,16 +102,60 @@ export default class Python_poetry extends Base_pyproject {
|
|
|
98
102
|
}
|
|
99
103
|
return versions;
|
|
100
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Collects PEP 508 marker expressions for direct and transitive deps.
|
|
107
|
+
* Direct markers come from pyproject.toml dependency strings, e.g.:
|
|
108
|
+
* "pywin32>=311 ; sys_platform == 'win32'" → directMarkers['pywin32'] = "sys_platform == 'win32'"
|
|
109
|
+
* Transitive markers come from poetry.lock [package.dependencies] entries, e.g.:
|
|
110
|
+
* colorama = {version = "*", markers = "sys_platform == 'win32'"}
|
|
111
|
+
* → transitiveMarkers['click']['colorama'] = "sys_platform == 'win32'"
|
|
112
|
+
* @param {string|null} lockDir
|
|
113
|
+
* @param {object} parsed - parsed pyproject.toml
|
|
114
|
+
* @returns {{directMarkers: Map<string, string>, transitiveMarkers: Map<string, Map<string, string>>}}
|
|
115
|
+
*/
|
|
116
|
+
_extractMarkerData(lockDir, parsed) {
|
|
117
|
+
let directMarkers = new Map();
|
|
118
|
+
let transitiveMarkers = new Map();
|
|
119
|
+
// Extract markers from PEP 621 dependency strings: "name[extras]>=ver ; marker"
|
|
120
|
+
let deps = parsed.project?.dependencies || [];
|
|
121
|
+
for (let dep of deps) {
|
|
122
|
+
let m = dep.match(/^([A-Za-z0-9][A-Za-z0-9._-]*)\s*[^;]*;\s*(.+)$/);
|
|
123
|
+
if (m) {
|
|
124
|
+
directMarkers.set(this._canonicalize(m[1]), m[2].trim());
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (lockDir) {
|
|
128
|
+
let lockPath = path.join(lockDir, this._lockFileName());
|
|
129
|
+
if (fs.existsSync(lockPath)) {
|
|
130
|
+
let lockContent = fs.readFileSync(lockPath, 'utf-8');
|
|
131
|
+
let lock = parseToml(lockContent);
|
|
132
|
+
let packages = lock.package || [];
|
|
133
|
+
for (let pkg of packages) {
|
|
134
|
+
let pkgKey = this._canonicalize(pkg.name);
|
|
135
|
+
let pkgDeps = pkg.dependencies || {};
|
|
136
|
+
for (let [depName, depSpec] of Object.entries(pkgDeps)) {
|
|
137
|
+
let markers = typeof depSpec === 'object' && depSpec != null ? depSpec.markers : null;
|
|
138
|
+
if (markers) {
|
|
139
|
+
if (!transitiveMarkers.has(pkgKey)) {
|
|
140
|
+
transitiveMarkers.set(pkgKey, new Map());
|
|
141
|
+
}
|
|
142
|
+
transitiveMarkers.get(pkgKey).set(this._canonicalize(depName), markers);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { directMarkers, transitiveMarkers };
|
|
149
|
+
}
|
|
101
150
|
/**
|
|
102
151
|
* Parse poetry show --tree output into a dependency graph structure.
|
|
103
|
-
* Top-level lines (no indentation/tree chars) are direct deps: "name version description"
|
|
104
|
-
* Indented lines are transitive deps with tree chars: "├── name >=constraint"
|
|
105
152
|
*
|
|
106
153
|
* @param {string} treeOutput
|
|
107
154
|
* @param {Map<string, string>} versionMap - canonical name -> resolved version
|
|
155
|
+
* @param {{directMarkers: Map<string, string>, transitiveMarkers: Map<string, Map<string, string>>}} markerData
|
|
108
156
|
* @returns {{directDeps: string[], graph: Map<string, {name: string, version: string, children: string[]}>}}
|
|
109
157
|
*/
|
|
110
|
-
_parsePoetryTree(treeOutput, versionMap) {
|
|
158
|
+
_parsePoetryTree(treeOutput, versionMap, markerData) {
|
|
111
159
|
let lines = treeOutput.split(/\r?\n/);
|
|
112
160
|
let graph = new Map();
|
|
113
161
|
let directDeps = [];
|
|
@@ -123,6 +171,12 @@ export default class Python_poetry extends Base_pyproject {
|
|
|
123
171
|
let name = topMatch[1];
|
|
124
172
|
let version = topMatch[2];
|
|
125
173
|
let key = this._canonicalize(name);
|
|
174
|
+
let marker = markerData.directMarkers.get(key);
|
|
175
|
+
if (marker && !evaluateMarker(marker)) {
|
|
176
|
+
currentDirectDep = null;
|
|
177
|
+
stack = [];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
126
180
|
directDeps.push(key);
|
|
127
181
|
if (!graph.has(key)) {
|
|
128
182
|
graph.set(key, { name, version, children: [] });
|
|
@@ -149,6 +203,20 @@ export default class Python_poetry extends Base_pyproject {
|
|
|
149
203
|
// determine depth by counting tree-drawing groups in the prefix
|
|
150
204
|
let prefix = line.substring(0, nameStart);
|
|
151
205
|
let depth = (prefix.match(/(?:[├└│ ][\s─]{2} ?)/g) || []).length;
|
|
206
|
+
// pop stack back to find the parent at depth-1
|
|
207
|
+
while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {
|
|
208
|
+
stack.pop();
|
|
209
|
+
}
|
|
210
|
+
let parentKey = stack.length > 0 ? stack[stack.length - 1].key : null;
|
|
211
|
+
if (parentKey) {
|
|
212
|
+
let parentMarkers = markerData.transitiveMarkers.get(parentKey);
|
|
213
|
+
if (parentMarkers) {
|
|
214
|
+
let marker = parentMarkers.get(depKey);
|
|
215
|
+
if (marker && !evaluateMarker(marker)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
152
220
|
// resolve version from the version map
|
|
153
221
|
let version = versionMap.get(depKey) || null;
|
|
154
222
|
if (!version) {
|
|
@@ -157,12 +225,7 @@ export default class Python_poetry extends Base_pyproject {
|
|
|
157
225
|
if (!graph.has(depKey)) {
|
|
158
226
|
graph.set(depKey, { name: depName, version, children: [] });
|
|
159
227
|
}
|
|
160
|
-
|
|
161
|
-
while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {
|
|
162
|
-
stack.pop();
|
|
163
|
-
}
|
|
164
|
-
if (stack.length > 0) {
|
|
165
|
-
let parentKey = stack[stack.length - 1].key;
|
|
228
|
+
if (parentKey) {
|
|
166
229
|
let parentEntry = graph.get(parentKey);
|
|
167
230
|
if (parentEntry && !parentEntry.children.includes(depKey)) {
|
|
168
231
|
parentEntry.children.push(depKey);
|
|
@@ -1,4 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover all pyproject.toml manifest paths in a uv workspace.
|
|
3
|
+
* Parses `[tool.uv.workspace]` from root pyproject.toml and glob-expands member patterns.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain pyproject.toml and uv.lock)
|
|
6
|
+
* @param {{ workspaceDiscoveryIgnore?: string[], TRUSTIFY_DA_WORKSPACE_DISCOVERY_IGNORE?: string, [key: string]: unknown }} [opts={}]
|
|
7
|
+
* @returns {Promise<string[]>} Paths to pyproject.toml files (absolute)
|
|
8
|
+
*/
|
|
9
|
+
export function discoverUvWorkspaceMembers(workspaceRoot: string, opts?: {
|
|
10
|
+
workspaceDiscoveryIgnore?: string[];
|
|
11
|
+
TRUSTIFY_DA_WORKSPACE_DISCOVERY_IGNORE?: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}): Promise<string[]>;
|
|
1
14
|
export default class Python_uv extends Base_pyproject {
|
|
15
|
+
/**
|
|
16
|
+
* @param {string} manifestDir - directory containing the target pyproject.toml
|
|
17
|
+
* @param {string} workspaceDir - workspace root (for resolving editable install paths)
|
|
18
|
+
* @param {object} parsed - parsed pyproject.toml
|
|
19
|
+
* @param {Object} opts
|
|
20
|
+
* @returns {Promise<{directDeps: string[], graph: Map<string, {name: string, version: string, children: string[]}>}>}
|
|
21
|
+
*/
|
|
22
|
+
_getDependencyData(manifestDir: string, workspaceDir: string, parsed: object, opts: any): Promise<{
|
|
23
|
+
directDeps: string[];
|
|
24
|
+
graph: Map<string, {
|
|
25
|
+
name: string;
|
|
26
|
+
version: string;
|
|
27
|
+
children: string[];
|
|
28
|
+
}>;
|
|
29
|
+
}>;
|
|
2
30
|
/**
|
|
3
31
|
* Get the uv export output, either from env var or by running the command.
|
|
4
32
|
* @param {string} manifestDir
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import fg from 'fast-glob';
|
|
3
4
|
import { parse as parseToml } from 'smol-toml';
|
|
4
5
|
import { environmentVariableIsPopulated, getCustomPath, invokeCommand } from '../tools.js';
|
|
6
|
+
import { filterManifestPathsByDiscoveryIgnore, resolveWorkspaceDiscoveryIgnore, toManifestGlobPatterns } from '../workspace.js';
|
|
5
7
|
import Base_pyproject from './base_pyproject.js';
|
|
8
|
+
import { evaluateMarker } from './marker_evaluator.js';
|
|
6
9
|
import { getParser, getPinnedVersionQuery } from './requirements_parser.js';
|
|
7
10
|
export default class Python_uv extends Base_pyproject {
|
|
8
11
|
/** @returns {string} */
|
|
@@ -89,6 +92,16 @@ export default class Python_uv extends Base_pyproject {
|
|
|
89
92
|
if (!nameNode) {
|
|
90
93
|
continue;
|
|
91
94
|
}
|
|
95
|
+
// Skip packages with non-matching PEP 508 markers, e.g. "pywin32==311 ; sys_platform == 'win32'"
|
|
96
|
+
let markerNode = child.children.find(c => c.type === 'marker_spec');
|
|
97
|
+
if (markerNode) {
|
|
98
|
+
let markerText = markerNode.text.replace(/^\s*;\s*/, '');
|
|
99
|
+
if (!evaluateMarker(markerText)) {
|
|
100
|
+
currentPkg = null;
|
|
101
|
+
collectingVia = false;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
92
105
|
let name = nameNode.text;
|
|
93
106
|
let version = null;
|
|
94
107
|
let versionMatches = pinnedVersionQuery.matches(child);
|
|
@@ -147,3 +160,68 @@ export default class Python_uv extends Base_pyproject {
|
|
|
147
160
|
return { directDeps, graph };
|
|
148
161
|
}
|
|
149
162
|
}
|
|
163
|
+
const DEFAULT_UV_DISCOVERY_IGNORE = [
|
|
164
|
+
'**/__pycache__/**',
|
|
165
|
+
'**/.venv/**',
|
|
166
|
+
];
|
|
167
|
+
/**
|
|
168
|
+
* Discover all pyproject.toml manifest paths in a uv workspace.
|
|
169
|
+
* Parses `[tool.uv.workspace]` from root pyproject.toml and glob-expands member patterns.
|
|
170
|
+
*
|
|
171
|
+
* @param {string} workspaceRoot - Absolute or relative path to workspace root (must contain pyproject.toml and uv.lock)
|
|
172
|
+
* @param {{ workspaceDiscoveryIgnore?: string[], TRUSTIFY_DA_WORKSPACE_DISCOVERY_IGNORE?: string, [key: string]: unknown }} [opts={}]
|
|
173
|
+
* @returns {Promise<string[]>} Paths to pyproject.toml files (absolute)
|
|
174
|
+
*/
|
|
175
|
+
export async function discoverUvWorkspaceMembers(workspaceRoot, opts = {}) {
|
|
176
|
+
const root = path.resolve(workspaceRoot);
|
|
177
|
+
const rootPyproject = path.join(root, 'pyproject.toml');
|
|
178
|
+
const uvLock = path.join(root, 'uv.lock');
|
|
179
|
+
if (!fs.existsSync(rootPyproject) || !fs.existsSync(uvLock)) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
let parsed;
|
|
183
|
+
try {
|
|
184
|
+
parsed = parseToml(fs.readFileSync(rootPyproject, 'utf-8'));
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
const workspaceConfig = parsed?.tool?.uv?.workspace;
|
|
190
|
+
if (!workspaceConfig) {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const memberPatterns = workspaceConfig.members;
|
|
194
|
+
if (!Array.isArray(memberPatterns) || memberPatterns.length === 0) {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
const excludePatterns = Array.isArray(workspaceConfig.exclude) ? workspaceConfig.exclude : [];
|
|
198
|
+
const excludeGlobs = excludePatterns
|
|
199
|
+
.filter(p => typeof p === 'string' && p.trim())
|
|
200
|
+
.map(p => `${p.trim()}/pyproject.toml`);
|
|
201
|
+
const ignorePatterns = [...resolveWorkspaceDiscoveryIgnore(opts), ...DEFAULT_UV_DISCOVERY_IGNORE];
|
|
202
|
+
const globOpts = {
|
|
203
|
+
cwd: root,
|
|
204
|
+
absolute: true,
|
|
205
|
+
onlyFiles: true,
|
|
206
|
+
ignore: [...ignorePatterns, ...excludeGlobs],
|
|
207
|
+
followSymbolicLinks: false,
|
|
208
|
+
};
|
|
209
|
+
const patterns = toManifestGlobPatterns(memberPatterns.filter(p => typeof p === 'string'), 'pyproject.toml');
|
|
210
|
+
const manifestPaths = await fg(patterns, globOpts);
|
|
211
|
+
if (!manifestPaths.includes(rootPyproject) && hasProjectMetadata(parsed)) {
|
|
212
|
+
manifestPaths.unshift(rootPyproject);
|
|
213
|
+
}
|
|
214
|
+
return filterManifestPathsByDiscoveryIgnore(manifestPaths, root, ignorePatterns);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* @param {import('smol-toml').TomlTable} parsedPyProject
|
|
218
|
+
* @returns {boolean}
|
|
219
|
+
*/
|
|
220
|
+
function hasProjectMetadata(parsedPyProject) {
|
|
221
|
+
try {
|
|
222
|
+
return typeof parsedPyProject?.project?.name === 'string' && parsedPyProject.project.name.trim() !== '';
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
package/dist/src/sbom.d.ts
CHANGED
|
@@ -25,9 +25,14 @@ export default class Sbom {
|
|
|
25
25
|
/**
|
|
26
26
|
* @param {component} sourceRef current source Component ( Starting from root component by clients)
|
|
27
27
|
* @param {PackageURL} targetRef current dependency to add to Dependencies list of component sourceRef
|
|
28
|
+
* @param {string} [scope] - Scope of the dependency
|
|
29
|
+
* @param {Array<{alg: string, content: string}>} [targetHashes] - Optional hashes for the target component
|
|
28
30
|
* @return Sbom
|
|
29
31
|
*/
|
|
30
|
-
addDependency(sourceRef: component, targetRef: PackageURL, scope
|
|
32
|
+
addDependency(sourceRef: component, targetRef: PackageURL, scope?: string, targetHashes?: Array<{
|
|
33
|
+
alg: string;
|
|
34
|
+
content: string;
|
|
35
|
+
}>): CycloneDxSbom;
|
|
31
36
|
/**
|
|
32
37
|
* @return String sbom json in a string format
|
|
33
38
|
*/
|
|
@@ -45,6 +50,7 @@ export default class Sbom {
|
|
|
45
50
|
version: any;
|
|
46
51
|
scope: any;
|
|
47
52
|
licenses?: any;
|
|
53
|
+
hashes?: any;
|
|
48
54
|
};
|
|
49
55
|
/** This method gets a component object, and a string name, and checks if the name is a substring of the component' purl.
|
|
50
56
|
* @param {} component to search in its dependencies
|
package/dist/src/sbom.js
CHANGED
|
@@ -43,10 +43,12 @@ export default class Sbom {
|
|
|
43
43
|
/**
|
|
44
44
|
* @param {component} sourceRef current source Component ( Starting from root component by clients)
|
|
45
45
|
* @param {PackageURL} targetRef current dependency to add to Dependencies list of component sourceRef
|
|
46
|
+
* @param {string} [scope] - Scope of the dependency
|
|
47
|
+
* @param {Array<{alg: string, content: string}>} [targetHashes] - Optional hashes for the target component
|
|
46
48
|
* @return Sbom
|
|
47
49
|
*/
|
|
48
|
-
addDependency(sourceRef, targetRef, scope) {
|
|
49
|
-
return this.sbomModel.addDependency(sourceRef, targetRef, scope);
|
|
50
|
+
addDependency(sourceRef, targetRef, scope, targetHashes) {
|
|
51
|
+
return this.sbomModel.addDependency(sourceRef, targetRef, scope, targetHashes);
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
52
54
|
* @return String sbom json in a string format
|
package/dist/src/tools.d.ts
CHANGED
|
@@ -61,6 +61,32 @@ export function toPurlFromString(strPurl: any): PackageURL | null;
|
|
|
61
61
|
* @param {string} cwd - directory for which to find the root of the git repository.
|
|
62
62
|
*/
|
|
63
63
|
export function getGitRootDir(cwd: string): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Normalize a filesystem path, lowercasing on Windows for case-insensitive comparison.
|
|
66
|
+
*
|
|
67
|
+
* @param {string} thePath
|
|
68
|
+
* @returns {string}
|
|
69
|
+
*/
|
|
70
|
+
export function normalizePath(thePath: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Walk up from `startDir` to `repoRoot` looking for an executable wrapper script.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} startDir - Absolute directory to start from
|
|
75
|
+
* @param {string} wrapperName - Wrapper filename (e.g. `mvnw`, `gradlew`)
|
|
76
|
+
* @param {string} [repoRoot] - Stop boundary (defaults to git root or filesystem root)
|
|
77
|
+
* @returns {string | undefined}
|
|
78
|
+
*/
|
|
79
|
+
export function traverseForWrapper(startDir: string, wrapperName: string, repoRoot?: string): string | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Resolve a build-tool binary, preferring a wrapper when configured.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} globalBinary - Global binary name (e.g. `mvn`, `gradle`)
|
|
84
|
+
* @param {string} localWrapper - Wrapper filename (e.g. `mvnw`, `gradlew.bat`)
|
|
85
|
+
* @param {string} startDir - Directory from which to start the wrapper search
|
|
86
|
+
* @param {import('./index.js').Options} [opts={}]
|
|
87
|
+
* @returns {string} Path to the resolved binary
|
|
88
|
+
*/
|
|
89
|
+
export function resolveBinary(globalBinary: string, localWrapper: string, startDir: string, opts?: import("./index.js").Options): string;
|
|
64
90
|
/** this method invokes command string in a process in a synchronous way.
|
|
65
91
|
* @param {string} bin - the command to be invoked
|
|
66
92
|
* @param {Array<string>} args - the args to pass to the binary
|
package/dist/src/tools.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
2
4
|
import { EOL } from "os";
|
|
3
5
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
4
6
|
import { PackageURL } from "packageurl-js";
|
|
@@ -128,6 +130,62 @@ export function getGitRootDir(cwd) {
|
|
|
128
130
|
return undefined;
|
|
129
131
|
}
|
|
130
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Normalize a filesystem path, lowercasing on Windows for case-insensitive comparison.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} thePath
|
|
137
|
+
* @returns {string}
|
|
138
|
+
*/
|
|
139
|
+
export function normalizePath(thePath) {
|
|
140
|
+
const normalized = path.resolve(thePath).normalize();
|
|
141
|
+
return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Walk up from `startDir` to `repoRoot` looking for an executable wrapper script.
|
|
145
|
+
*
|
|
146
|
+
* @param {string} startDir - Absolute directory to start from
|
|
147
|
+
* @param {string} wrapperName - Wrapper filename (e.g. `mvnw`, `gradlew`)
|
|
148
|
+
* @param {string} [repoRoot] - Stop boundary (defaults to git root or filesystem root)
|
|
149
|
+
* @returns {string | undefined}
|
|
150
|
+
*/
|
|
151
|
+
export function traverseForWrapper(startDir, wrapperName, repoRoot = undefined) {
|
|
152
|
+
const currentDir = normalizePath(startDir);
|
|
153
|
+
repoRoot = repoRoot || getGitRootDir(currentDir) || path.parse(currentDir).root;
|
|
154
|
+
const wrapperPath = path.join(currentDir, wrapperName);
|
|
155
|
+
try {
|
|
156
|
+
fs.accessSync(wrapperPath, fs.constants.X_OK);
|
|
157
|
+
return wrapperPath;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
const rootDir = path.parse(currentDir).root;
|
|
161
|
+
if (currentDir === repoRoot || currentDir === rootDir) {
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
const parentDir = path.dirname(currentDir);
|
|
165
|
+
if (parentDir === currentDir || parentDir === rootDir) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
return traverseForWrapper(parentDir, wrapperName, repoRoot);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Resolve a build-tool binary, preferring a wrapper when configured.
|
|
173
|
+
*
|
|
174
|
+
* @param {string} globalBinary - Global binary name (e.g. `mvn`, `gradle`)
|
|
175
|
+
* @param {string} localWrapper - Wrapper filename (e.g. `mvnw`, `gradlew.bat`)
|
|
176
|
+
* @param {string} startDir - Directory from which to start the wrapper search
|
|
177
|
+
* @param {import('./index.js').Options} [opts={}]
|
|
178
|
+
* @returns {string} Path to the resolved binary
|
|
179
|
+
*/
|
|
180
|
+
export function resolveBinary(globalBinary, localWrapper, startDir, opts = {}) {
|
|
181
|
+
if (getWrapperPreference(globalBinary, opts)) {
|
|
182
|
+
const wrapper = traverseForWrapper(startDir, localWrapper);
|
|
183
|
+
if (wrapper !== undefined) {
|
|
184
|
+
return wrapper;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return getCustomPath(globalBinary, opts);
|
|
188
|
+
}
|
|
131
189
|
/** this method invokes command string in a process in a synchronous way.
|
|
132
190
|
* @param {string} bin - the command to be invoked
|
|
133
191
|
* @param {Array<string>} args - the args to pass to the binary
|
package/dist/src/workspace.d.ts
CHANGED
|
@@ -42,6 +42,15 @@ export function discoverWorkspacePackages(workspaceRoot: string, opts?: {
|
|
|
42
42
|
TRUSTIFY_DA_WORKSPACE_DISCOVERY_IGNORE?: string;
|
|
43
43
|
[key: string]: unknown;
|
|
44
44
|
}): Promise<string[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Convert workspace glob patterns to manifest-file glob patterns,
|
|
47
|
+
* correctly handling negation prefixes.
|
|
48
|
+
*
|
|
49
|
+
* @param {string[]} patterns - Workspace glob patterns (may include negations)
|
|
50
|
+
* @param {string} manifestFileName - e.g. 'package.json' or 'Cargo.toml'
|
|
51
|
+
* @returns {string[]}
|
|
52
|
+
*/
|
|
53
|
+
export function toManifestGlobPatterns(patterns: string[], manifestFileName: string): string[];
|
|
45
54
|
/**
|
|
46
55
|
* Discover all Cargo.toml manifest paths in a Cargo workspace.
|
|
47
56
|
* Uses `cargo metadata` to get workspace members.
|
package/dist/src/workspace.js
CHANGED
|
@@ -172,7 +172,7 @@ function parsePnpmPackages(content) {
|
|
|
172
172
|
* @param {string} manifestFileName - e.g. 'package.json' or 'Cargo.toml'
|
|
173
173
|
* @returns {string[]}
|
|
174
174
|
*/
|
|
175
|
-
function toManifestGlobPatterns(patterns, manifestFileName) {
|
|
175
|
+
export function toManifestGlobPatterns(patterns, manifestFileName) {
|
|
176
176
|
return patterns.map(p => {
|
|
177
177
|
if (p.startsWith('!')) {
|
|
178
178
|
return `!${p.slice(1)}/${manifestFileName}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trustify-da/trustify-da-javascript-client",
|
|
3
|
-
"version": "0.3.0-ea.
|
|
3
|
+
"version": "0.3.0-ea.a8c3942",
|
|
4
4
|
"description": "Code-Ready Dependency Analytics JavaScript API.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/guacsec/trustify-da-javascript-client#README.md",
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"@cyclonedx/cyclonedx-library": "^6.13.0",
|
|
52
52
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
53
53
|
"fast-glob": "^3.3.3",
|
|
54
|
-
"fast-toml": "^0.5.4",
|
|
55
54
|
"fast-xml-parser": "^5.3.4",
|
|
56
55
|
"help": "^3.0.2",
|
|
57
56
|
"https-proxy-agent": "^7.0.6",
|