@@ -5,57 +5,55 @@ import { globby } from 'globby'
55import ignore from 'ignore'
66// @ts -ignore This package provides no types
77import { directories } from 'ignore-by-default'
8+ import micromatch from 'micromatch'
89import { ErrorWithCause } from 'pony-cause'
910
1011import { InputError } from './errors.js'
1112import { isErrnoException } from './type-helpers.js'
1213
13- /** @type {readonly string[] } */
14- const SUPPORTED_LOCKFILES = [
15- 'package-lock.json' ,
16- 'yarn.lock' ,
17- ]
18-
1914/**
2015 * There are a lot of possible folders that we should not be looking in and "ignore-by-default" helps us with defining those
2116 *
2217 * @type {readonly string[] }
2318 */
2419const ignoreByDefault = directories ( )
2520
26- /** @type {readonly string[] } */
27- const GLOB_IGNORE = [
28- ...ignoreByDefault . map ( item => '**/' + item )
29- ]
21+ /** @type {import('globby').Options } */
22+ const BASE_GLOBBY_OPTS = {
23+ absolute : true ,
24+ expandDirectories : false ,
25+ gitignore : true ,
26+ ignore : [
27+ ...ignoreByDefault . map ( item => '**/' + item )
28+ ] ,
29+ markDirectories : true ,
30+ unique : true ,
31+ }
3032
3133/**
3234 * Resolves package.json and lockfiles from (globbed) input paths, applying relevant ignores
3335 *
3436 * @param {string } cwd The working directory to use when resolving paths
3537 * @param {string[] } inputPaths A list of paths to folders, package.json files and/or recognized lockfiles. Supports globs.
3638 * @param {import('@socketsecurity/config').SocketYml|undefined } config
39+ * @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data'] } supportedFiles
3740 * @param {typeof console.error } debugLog
3841 * @returns {Promise<string[]> }
3942 * @throws {InputError }
4043 */
41- export async function getPackageFiles ( cwd , inputPaths , config , debugLog ) {
44+ export async function getPackageFiles ( cwd , inputPaths , config , supportedFiles , debugLog ) {
4245 debugLog ( `Globbed resolving ${ inputPaths . length } paths:` , inputPaths )
4346
4447 // TODO: Does not support `~/` paths
4548 const entries = await globby ( inputPaths , {
46- absolute : true ,
49+ ... BASE_GLOBBY_OPTS ,
4750 cwd,
48- expandDirectories : false ,
49- gitignore : true ,
50- ignore : [ ...GLOB_IGNORE ] ,
51- markDirectories : true ,
52- onlyFiles : false ,
53- unique : true ,
51+ onlyFiles : false
5452 } )
5553
5654 debugLog ( `Globbed resolved ${ inputPaths . length } paths to ${ entries . length } paths:` , entries )
5755
58- const packageFiles = await mapGlobResultToFiles ( entries )
56+ const packageFiles = await mapGlobResultToFiles ( entries , supportedFiles )
5957
6058 debugLog ( `Mapped ${ entries . length } entries to ${ packageFiles . length } files:` , packageFiles )
6159
@@ -73,11 +71,14 @@ export async function getPackageFiles (cwd, inputPaths, config, debugLog) {
7371 * Takes paths to folders, package.json and/or recognized lock files and resolves them to package.json + lockfile pairs (where possible)
7472 *
7573 * @param {string[] } entries
74+ * @param {import('@socketsecurity/sdk').SocketSdkReturnType<"getReportSupportedFiles">['data'] } supportedFiles
7675 * @returns {Promise<string[]> }
7776 * @throws {InputError }
7877 */
79- export async function mapGlobResultToFiles ( entries ) {
80- const packageFiles = await Promise . all ( entries . map ( mapGlobEntryToFiles ) )
78+ export async function mapGlobResultToFiles ( entries , supportedFiles ) {
79+ const packageFiles = await Promise . all (
80+ entries . map ( entry => mapGlobEntryToFiles ( entry , supportedFiles ) )
81+ )
8182
8283 const uniquePackageFiles = [ ...new Set ( packageFiles . flat ( ) ) ]
8384
@@ -88,46 +89,58 @@ export async function mapGlobResultToFiles (entries) {
8889 * Takes a single path to a folder, package.json or a recognized lock file and resolves to a package.json + lockfile pair (where possible)
8990 *
9091 * @param {string } entry
92+ * @param {import('@socketsecurity/sdk').SocketSdkReturnType<'getReportSupportedFiles'>['data'] } supportedFiles
9193 * @returns {Promise<string[]> }
9294 * @throws {InputError }
9395 */
94- export async function mapGlobEntryToFiles ( entry ) {
96+ export async function mapGlobEntryToFiles ( entry , supportedFiles ) {
9597 /** @type {string|undefined } */
96- let pkgFile
97- /** @type {string|undefined } */
98- let lockFile
99-
98+ let pkgJSFile
99+ /** @type {string[] } */
100+ let jsLockFiles = [ ]
101+ /** @type {string[] } */
102+ let pyFiles = [ ]
103+
104+ const jsSupported = supportedFiles [ 'npm' ] || { }
105+ const jsLockFilePatterns = Object . keys ( jsSupported )
106+ . filter ( key => key !== 'packagejson' )
107+ . map ( key => /** @type {{ pattern: string } } */ ( jsSupported [ key ] ) . pattern )
108+
109+ const pyFilePatterns = Object . values ( supportedFiles [ 'pypi' ] || { } ) . map ( p => p . pattern )
100110 if ( entry . endsWith ( '/' ) ) {
101111 // If the match is a folder and that folder contains a package.json file, then include it
102112 const filePath = path . resolve ( entry , 'package.json' )
103- pkgFile = await fileExists ( filePath ) ? filePath : undefined
104- } else if ( path . basename ( entry ) === 'package.json' ) {
105- // If the match is a package.json file, then include it
106- pkgFile = entry
107- } else if ( SUPPORTED_LOCKFILES . includes ( path . basename ( entry ) ) ) {
108- // If the match is a lock file, include both it and the corresponding package.json file
109- lockFile = entry
110- pkgFile = path . resolve ( path . dirname ( entry ) , 'package.json' )
113+ if ( await fileExists ( filePath ) ) pkgJSFile = filePath
114+ pyFiles = await globby ( pyFilePatterns , {
115+ ...BASE_GLOBBY_OPTS ,
116+ cwd : entry
117+ } )
118+ } else {
119+ const entryFile = path . basename ( entry )
120+
121+ if ( entryFile === 'package.json' ) {
122+ // If the match is a package.json file, then include it
123+ pkgJSFile = entry
124+ } else if ( micromatch . isMatch ( entryFile , jsLockFilePatterns ) ) {
125+ jsLockFiles = [ entry ]
126+ pkgJSFile = path . resolve ( path . dirname ( entry ) , 'package.json' )
127+ if ( ! ( await fileExists ( pkgJSFile ) ) ) return [ ]
128+ } else if ( micromatch . isMatch ( entryFile , pyFilePatterns ) ) {
129+ pyFiles = [ entry ]
130+ }
111131 }
112132
113133 // If we will include a package.json file but don't already have a corresponding lockfile, then look for one
114- if ( ! lockFile && pkgFile ) {
115- const pkgDir = path . dirname ( pkgFile )
116-
117- for ( const name of SUPPORTED_LOCKFILES ) {
118- const lockFileAlternative = path . resolve ( pkgDir , name )
119- if ( await fileExists ( lockFileAlternative ) ) {
120- lockFile = lockFileAlternative
121- break
122- }
123- }
124- }
134+ if ( ! jsLockFiles . length && pkgJSFile ) {
135+ const pkgDir = path . dirname ( pkgJSFile )
125136
126- if ( pkgFile && lockFile ) {
127- return [ pkgFile , lockFile ]
137+ jsLockFiles = await globby ( jsLockFilePatterns , {
138+ ...BASE_GLOBBY_OPTS ,
139+ cwd : pkgDir
140+ } )
128141 }
129142
130- return pkgFile ? [ pkgFile ] : [ ]
143+ return [ ... jsLockFiles , ... pyFiles ] . concat ( pkgJSFile ? [ pkgJSFile ] : [ ] )
131144}
132145
133146/**
0 commit comments