Socket
Socket
Sign inDemoInstall

@lavamoat/aa

Package Overview
Dependencies
10
Maintainers
6
Versions
13
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.1.5 to 4.0.0

.depcheckrc.yml

16

CHANGELOG.md
# Changelog
## [4.0.0](https://github.com/LavaMoat/LavaMoat/compare/aa-v3.1.5...aa-v4.0.0) (2023-10-18)
### ⚠ BREAKING CHANGES
* The minimum supported Node.js version is now v16.20.0.
### Features
* **aa:** ship generated types ([#638](https://github.com/LavaMoat/LavaMoat/issues/638)) ([d8d5996](https://github.com/LavaMoat/LavaMoat/commit/d8d5996c82c3bca21bd3091bc1f7b3af8db5f591))
### Bug Fixes
* drop Node.js v14 ([#729](https://github.com/LavaMoat/LavaMoat/issues/729)) ([10c667b](https://github.com/LavaMoat/LavaMoat/commit/10c667bd88eaabf60a8fd8e4493cc7676848b201))
## [3.1.5](https://github.com/LavaMoat/LavaMoat/compare/aa-v3.1.4...aa-v3.1.5) (2023-09-14)

@@ -4,0 +20,0 @@

9

package.json
{
"name": "@lavamoat/aa",
"version": "3.1.5",
"version": "4.0.0",
"main": "src/index.js",

@@ -17,2 +17,5 @@ "bin": {

},
"devDependencies": {
"@types/resolve": "^1.20.2"
},
"dependencies": {

@@ -27,3 +30,3 @@ "resolve": "^1.22.3"

"engines": {
"node": ">=14.0.0"
"node": "^16.20.0 || ^18.0.0 || ^20.0.0"
},

@@ -36,3 +39,3 @@ "ava": {

},
"gitHead": "5fb4a8824b4100150f891fabf17448a77de48498"
"types": "./types/index.d.ts"
}

@@ -11,3 +11,3 @@ ### @lavamoat/aa

- consistent across platform and package manager
- consistent whether only prod dependencies or dev and prod dependencies are installed
- consistent whether only prod dependencies or dev and prod dependencies are installed

@@ -21,2 +21,3 @@ #### scheme

with the logical paths:
- `abc>ijk>xyz`

@@ -23,0 +24,0 @@ - `abc>xyz`

@@ -5,3 +5,2 @@ #!/usr/bin/env node

start().catch((err) => {

@@ -12,6 +11,9 @@ console.error(err)

async function start () {
async function start() {
// log all package names, optionally filtered by a package self-name
const [,,filterKey] = process.argv
const canonicalNameMap = await loadCanonicalNameMap({ rootDir: process.cwd(), includeDevDeps: true })
const [, , filterKey] = process.argv
const canonicalNameMap = await loadCanonicalNameMap({
rootDir: process.cwd(),
includeDevDeps: true,
})
for (const logicalName of canonicalNameMap.values()) {

@@ -18,0 +20,0 @@ if (filterKey !== undefined) {

@@ -0,1 +1,3 @@

'use strict'
const { readFileSync } = require('fs')

@@ -13,3 +15,10 @@ const path = require('path')

function createPerformantResolve () {
/**
* @returns {Resolver}
*/
function createPerformantResolve() {
/**
* @param {string} self
* @returns {(readFileSync: (file: string) => (string|{toString(): string}), pkgfile: string) => Record<string,unknown>}
*/
const readPackageWithout = (self) => (readFileSync, pkgfile) => {

@@ -23,5 +32,6 @@ // avoid loading the package.json we're just trying to resolve

try {
// @ts-expect-error - JSON.parse calls toString() on its parameter if not given a string
var pkg = JSON.parse(body)
return pkg
} catch (jsonErr) { }
} catch (jsonErr) {}
}

@@ -39,7 +49,7 @@

/**
* @param {object} options
* @returns {Promise<Map<string, string>>}
* @param {LoadCanonicalNameMapOpts} options
* @returns {Promise<CanonicalNameMap>}
*/
async function loadCanonicalNameMap({ rootDir, includeDevDeps, resolve } = {}) {
const canonicalNameMap = new Map()
async function loadCanonicalNameMap({ rootDir, includeDevDeps, resolve }) {
const canonicalNameMap = /** @type {CanonicalNameMap} */ (new Map())
// performant resolve avoids loading package.jsons if their path is what's being resolved,

@@ -50,3 +60,7 @@ // offering 2x performance improvement compared to using original resolve

// walk tree
const logicalPathMap = walkDependencyTreeForBestLogicalPaths({ packageDir: rootDir, includeDevDeps, resolve, canonicalNameMap })
const logicalPathMap = walkDependencyTreeForBestLogicalPaths({
packageDir: rootDir,
includeDevDeps,
resolve,
})
//convert dependency paths to canonical package names

@@ -63,2 +77,8 @@ for (const [packageDir, logicalPathParts] of logicalPathMap.entries()) {

/**
* @param {Resolver} resolve
* @param {string} depName
* @param {string} packageDir
* @returns {string|undefined}
*/
function wrappedResolveSync(resolve, depName, packageDir) {

@@ -69,3 +89,3 @@ const depRelativePackageJsonPath = path.join(depName, 'package.json')

} catch (err) {
if (!err.message.includes('Cannot find module')) {
if (!(/** @type {Error} */ (err).message.includes('Cannot find module'))) {
throw err

@@ -77,2 +97,8 @@ }

}
/**
* @param {string} packageDir
* @param {boolean} includeDevDeps
* @returns {string[]}
*/
function getDependencies(packageDir, includeDevDeps) {

@@ -91,13 +117,26 @@ const packageJsonPath = path.join(packageDir, 'package.json')

/** @type {WalkDepTreeOpts[]} */
let currentLevelTodos
/** @type {WalkDepTreeOpts[]} */
let nextLevelTodos
/**
* @param {object} options
* @returns {Map<{packageDir: string, logicalPathParts: string[]}>}
* @param {WalkDepTreeOpts} options
* @returns {Map<string, string[]>}
*/
function walkDependencyTreeForBestLogicalPaths({ packageDir, logicalPath = [], includeDevDeps = false, visited = new Set(), resolve }) {
function walkDependencyTreeForBestLogicalPaths({
packageDir,
logicalPath = [],
includeDevDeps = false,
visited = new Set(),
resolve,
}) {
resolve = resolve ?? createPerformantResolve()
/** @type {Map<string, string[]>} */
const preferredPackageLogicalPathMap = new Map()
// add the entry package as the first work unit
currentLevelTodos = [{ packageDir, logicalPath, includeDevDeps, visited, resolve }]
currentLevelTodos = [
{ packageDir, logicalPath, includeDevDeps, visited, resolve },
]
nextLevelTodos = []

@@ -116,6 +155,17 @@ // drain work queue until empty, avoid going depth-first by prioritizing the current depth level

function processOnePackageInLogicalTree(preferredPackageLogicalPathMap, resolve) {
const { packageDir, logicalPath = [], includeDevDeps = false, visited = new Set() } = currentLevelTodos.pop()
/**
* @param {Map<string, string[]>} preferredPackageLogicalPathMap
* @param {Resolver} resolve
*/
function processOnePackageInLogicalTree(
preferredPackageLogicalPathMap,
resolve
) {
const {
packageDir,
logicalPath = [],
includeDevDeps = false,
visited = new Set(),
} = /** @type {WalkDepTreeOpts} */ (currentLevelTodos.pop())
const depsToWalk = getDependencies(packageDir, includeDevDeps)
const results = []

@@ -148,3 +198,8 @@ // deps are already sorted by preference for paths

// continue walking children, adding them to the end of the queue
nextLevelTodos.push({ packageDir: childPackageDir, logicalPath: childLogicalPath, includeDevDeps: false, visited: childVisited })
nextLevelTodos.push({
packageDir: childPackageDir,
logicalPath: childLogicalPath,
includeDevDeps: false,
visited: childVisited,
})
} else {

@@ -157,5 +212,9 @@ // debug: log skipped path traversals

}
return results
}
/**
* @param {CanonicalNameMap} canonicalNameMap
* @param {string} modulePath
* @returns {string}
*/
function getPackageNameForModulePath(canonicalNameMap, modulePath) {

@@ -167,7 +226,9 @@ const packageDir = getPackageDirForModulePath(canonicalNameMap, modulePath)

}
const packageName = canonicalNameMap.get(packageDir)
const packageName = /** @type {string} */ (canonicalNameMap.get(packageDir))
const relativeToPackageDir = path.relative(packageDir, modulePath)
// files should never be associated with a package directory across a package boundary (as tested via the presense of "node_modules" in the path)
if (relativeToPackageDir.includes('node_modules')) {
throw new Error(`LavaMoat - Encountered unknown package directory for file "${modulePath}"`)
throw new Error(
`LavaMoat - Encountered unknown package directory for file "${modulePath}"`
)
}

@@ -177,6 +238,12 @@ return packageName

/**
* @param {CanonicalNameMap} canonicalNameMap
* @param {string} modulePath
* @returns {string|undefined}
*/
function getPackageDirForModulePath(canonicalNameMap, modulePath) {
// find which of these directories the module is in
const matchingPackageDirs = Array.from(canonicalNameMap.keys())
.filter(packageDir => modulePath.startsWith(packageDir))
const matchingPackageDirs = Array.from(canonicalNameMap.keys()).filter(
(packageDir) => modulePath.startsWith(packageDir)
)
if (matchingPackageDirs.length === 0) {

@@ -190,3 +257,8 @@ return undefined

// for comparing string lengths
/**
* for comparing string lengths
* @param {string} a
* @param {string} b
* @returns {string}
*/
function takeLongest(a, b) {

@@ -196,3 +268,8 @@ return a.length > b.length ? a : b

// for package logical path names
/**
* for package logical path names
* @param {string} a
* @param {string} b
* @returns {0|1|-1}
*/
function comparePreferredPackageName(a, b) {

@@ -215,3 +292,8 @@ // prefer shorter package names

// for comparing package logical path arrays (shorter is better)
/**
* for comparing package logical path arrays (shorter is better)
* @param {string[]} [aPath]
* @param {string[]} [bPath]
* @returns {0|1|-1}
*/
function comparePackageLogicalPaths(aPath, bPath) {

@@ -251,1 +333,27 @@ // undefined is not preferred

}
/**
* @typedef Resolver
* @property {(path: string, opts: {basedir: string}) => string} sync
*/
/**
* @typedef LoadCanonicalNameMapOpts
* @property {string} rootDir
* @property {boolean} [includeDevDeps]
* @property {Resolver} [resolve]
*/
/**
* @internal
* @typedef WalkDepTreeOpts
* @property {string} packageDir
* @property {string[]} [logicalPath]
* @property {boolean} [includeDevDeps]
* @property {Set<string>} [visited]
* @property {Resolver} [resolve]
*/
/**
* @typedef {Map<string, string> & {rootDir: string}} CanonicalNameMap
*/

@@ -5,83 +5,59 @@ const path = require('path')

test('project 1', async t => {
const canonicalNameMap = await loadCanonicalNameMap({ rootDir: path.join(__dirname, 'projects', '1') })
test('project 1', async (t) => {
const canonicalNameMap = await loadCanonicalNameMap({
rootDir: path.join(__dirname, 'projects', '1'),
})
// normalize results to be relative
const normalizedMapEntries = Array.from(canonicalNameMap.entries()).sort()
.map(([packagePath,canonicalName]) => [path.relative(__dirname,packagePath), canonicalName])
const normalizedMapEntries = Array.from(canonicalNameMap.entries())
.sort()
.map(([packagePath, canonicalName]) => [
path.relative(__dirname, packagePath),
canonicalName,
])
t.deepEqual(normalizedMapEntries, [
[
'projects/1',
'$root$',
],
[
'projects/1/node_modules/aaa',
'aaa',
],
[
'projects/1/node_modules/bbb',
'bbb',
],
[
'projects/1/node_modules/bbb/node_modules/evil_dep',
'bbb>evil_dep',
],
['projects/1', '$root$'],
['projects/1/node_modules/aaa', 'aaa'],
['projects/1/node_modules/bbb', 'bbb'],
['projects/1/node_modules/bbb/node_modules/evil_dep', 'bbb>evil_dep'],
])
})
test('project 2', async t => {
const canonicalNameMap = await loadCanonicalNameMap({ rootDir: path.join(__dirname, 'projects', '2') })
test('project 2', async (t) => {
const canonicalNameMap = await loadCanonicalNameMap({
rootDir: path.join(__dirname, 'projects', '2'),
})
// normalize results to be relative
const normalizedMapEntries = Array.from(canonicalNameMap.entries()).sort()
.map(([packagePath,canonicalName]) => [path.relative(__dirname,packagePath), canonicalName])
const normalizedMapEntries = Array.from(canonicalNameMap.entries())
.sort()
.map(([packagePath, canonicalName]) => [
path.relative(__dirname, packagePath),
canonicalName,
])
t.deepEqual(normalizedMapEntries, [
[
'projects/2',
'$root$',
],
[
'projects/2/node_modules/aaa',
'aaa',
],
[
'projects/2/node_modules/bbb',
'bbb',
],
[
'projects/2/node_modules/bbb/node_modules/evil_dep',
'bbb>evil_dep',
],
[
'projects/2/node_modules/good_dep',
'good_dep',
],
['projects/2', '$root$'],
['projects/2/node_modules/aaa', 'aaa'],
['projects/2/node_modules/bbb', 'bbb'],
['projects/2/node_modules/bbb/node_modules/evil_dep', 'bbb>evil_dep'],
['projects/2/node_modules/good_dep', 'good_dep'],
])
})
test('project 3', async t => {
const canonicalNameMap = await loadCanonicalNameMap({ rootDir: path.join(__dirname, 'projects', '3') })
test('project 3', async (t) => {
const canonicalNameMap = await loadCanonicalNameMap({
rootDir: path.join(__dirname, 'projects', '3'),
})
// normalize results to be relative
const normalizedMapEntries = Array.from(canonicalNameMap.entries()).sort()
.map(([packagePath,canonicalName]) => [path.relative(__dirname,packagePath), canonicalName])
const normalizedMapEntries = Array.from(canonicalNameMap.entries())
.sort()
.map(([packagePath, canonicalName]) => [
path.relative(__dirname, packagePath),
canonicalName,
])
t.deepEqual(normalizedMapEntries, [
[
'projects/3',
'$root$',
],
[
'projects/3/node_modules/aaa',
'aaa',
],
[
'projects/3/node_modules/bbb',
'bbb',
],
[
'projects/3/node_modules/bbb/node_modules/good_dep',
'bbb>good_dep',
],
[
'projects/3/node_modules/evil_dep',
'evil_dep',
],
['projects/3', '$root$'],
['projects/3/node_modules/aaa', 'aaa'],
['projects/3/node_modules/bbb', 'bbb'],
['projects/3/node_modules/bbb/node_modules/good_dep', 'bbb>good_dep'],
['projects/3/node_modules/evil_dep', 'evil_dep'],
])
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc