-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support npm project scan without lock files
- Loading branch information
Showing
22 changed files
with
11,108 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import * as Debug from "debug"; | ||
import * as fs from "fs"; | ||
import * as path from "path"; | ||
import * as tmp from "tmp"; | ||
import { FilePathToContent, FilesByDir } from "./types"; | ||
const debug = Debug("snyk"); | ||
|
||
export { persistAppNodeModules, cleanupAppNodeModules, groupFilesByDirectory }; | ||
|
||
async function persistAppNodeModules( | ||
filePathToContent: FilePathToContent, | ||
fileNamesGroupedByDirectory: FilesByDir, | ||
): Promise<string[]> { | ||
const directoryTree = Object.keys(fileNamesGroupedByDirectory).sort(); | ||
if (directoryTree.length === 0) { | ||
debug(`Empty application directory tree.`); | ||
return ["", ""]; | ||
} | ||
|
||
const tempAppRootPath = tmp.dirSync().name; | ||
const appRootDirNameLength = directoryTree[0].indexOf("node_modules"); | ||
const appRootDir = | ||
appRootDirNameLength === -1 | ||
? directoryTree[0] | ||
: directoryTree[0].substring(0, appRootDirNameLength); | ||
const appRootDirPath = path.join(tempAppRootPath, appRootDir); | ||
|
||
try { | ||
fs.mkdirSync(appRootDirPath, { recursive: true }); | ||
} catch (error) { | ||
debug( | ||
`Failed to create the temporary directory structure of the application: ${error.message}`, | ||
); | ||
} | ||
const appRootPackageJsonPath = path.join(appRootDirPath, "package.json"); | ||
|
||
for (const directoryPath of directoryTree) { | ||
const filesInDirectory = fileNamesGroupedByDirectory[directoryPath]; | ||
if (filesInDirectory.length < 1) { | ||
continue; | ||
} | ||
const moduleJsonFilePath = path.join(directoryPath, filesInDirectory[0]); | ||
const moduleJsonFileContent = filePathToContent[moduleJsonFilePath]; | ||
const tempModuleJsonFilePath = path.join( | ||
tempAppRootPath, | ||
moduleJsonFilePath, | ||
); | ||
try { | ||
await createFile(tempModuleJsonFilePath, moduleJsonFileContent); | ||
} catch (error) { | ||
debug( | ||
`Failed to create the temporary directory structure of the application: ${error.message}`, | ||
); | ||
} | ||
} | ||
|
||
try { | ||
// Check if the package.json exists in the app root dir, | ||
// if it doesn't, create an empty "package.json" required by resolve-deps | ||
fs.statSync(appRootPackageJsonPath); | ||
} catch (error) { | ||
debug( | ||
`Creating an empty ${appRootPackageJsonPath} required by resolveDeps`, | ||
); | ||
fs.writeFileSync(appRootPackageJsonPath, JSON.stringify("{}"), "utf-8"); | ||
} | ||
|
||
return [tempAppRootPath, appRootDirPath]; | ||
} | ||
|
||
// Function to create file with content asynchronously | ||
async function createFile(filePath, fileContent) { | ||
try { | ||
const fileDir = path.dirname(filePath); | ||
// Ensure directory existence before writing the file | ||
fs.mkdirSync(fileDir, { recursive: true }); | ||
|
||
const fileContentJson = JSON.parse(fileContent); | ||
// Write content to the file | ||
fs.writeFileSync(filePath, JSON.stringify(fileContentJson), "utf-8"); | ||
} catch (error) { | ||
debug(`Error while creating ${filePath} : ${error.message}`); | ||
} | ||
} | ||
|
||
function groupFilesByDirectory( | ||
filePathToContent: FilePathToContent, | ||
): FilesByDir { | ||
const fileNamesGrouped: FilesByDir = {}; | ||
for (const filePath of Object.keys(filePathToContent)) { | ||
const directory = path.dirname(filePath); | ||
const fileName = path.basename(filePath); | ||
if (!fileNamesGrouped[directory]) { | ||
fileNamesGrouped[directory] = []; | ||
} | ||
fileNamesGrouped[directory].push(fileName); | ||
} | ||
return fileNamesGrouped; | ||
} | ||
|
||
async function cleanupAppNodeModules(appRootDir: string) { | ||
try { | ||
fs.rmSync(appRootDir, { recursive: true, force: true }); | ||
} catch (error) { | ||
debug(`Error while removing ${appRootDir} : ${error.message}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.