lavamoat-tofu
Advanced tools
Comparing version 2.0.10 to 3.1.0
{ | ||
"name": "lavamoat-tofu", | ||
"version": "2.0.10", | ||
"version": "3.1.0", | ||
"main": "src/index.js", | ||
"license": "MIT", | ||
"dependencies": { | ||
"acorn-globals": "^4.3.3" | ||
"acorn-globals": "^6.0.0", | ||
"acorn-walk": "^7.1.1" | ||
}, | ||
@@ -31,3 +32,3 @@ "devDependencies": { | ||
"homepage": "https://github.com/LavaMoat/lavamoat#readme", | ||
"gitHead": "c0ddda67f0fb21117ee203cc0c5bd00db832b006" | ||
"gitHead": "676f77b5cfecb655f58a272f2871b10abbf3c618" | ||
} |
@@ -1,7 +0,10 @@ | ||
const inspectSource = require('./inspectSource') | ||
const { parse } = require('acorn-globals') | ||
const { inspectGlobals, inspectImports } = require('./inspectSource') | ||
const utils = require('./util') | ||
module.exports = { | ||
inspectSource, | ||
utils | ||
inspectGlobals, | ||
inspectImports, | ||
utils, | ||
parse | ||
} |
const acornGlobals = require('acorn-globals') | ||
const walk = require('acorn-walk') | ||
const standardJsGlobals = require('./standardGlobals.js') | ||
@@ -6,3 +7,3 @@ | ||
getMemberExpressionNesting, | ||
getKeysForMemberExpressionChain, | ||
getPathFromMemberExpressionChain, | ||
reduceToTopmostApiCalls, | ||
@@ -12,5 +13,5 @@ addGlobalUsage | ||
module.exports = inspectSource | ||
module.exports = { inspectGlobals, inspectImports } | ||
function inspectSource (source, { | ||
function inspectGlobals (source, { | ||
ignoredRefs = [], | ||
@@ -20,3 +21,3 @@ globalRefs = [], | ||
} = {}) { | ||
const ast = acornGlobals.parse(source) | ||
const ast = (typeof source === 'object') ? source : acornGlobals.parse(source) | ||
const detectedGlobals = acornGlobals(ast) | ||
@@ -66,61 +67,6 @@ | ||
function inspectPatternElementForPaths (child) { | ||
if (child.type === 'ObjectPattern') { | ||
return inspectObjectPatternForPaths(child) | ||
} else if (child.type === 'ArrayPattern') { | ||
return inspectArrayPatternForPaths(child) | ||
} else if (child.type === 'Identifier') { | ||
// return a single empty element, meaning "one result, the whole thing" | ||
return [[]] | ||
} else { | ||
throw new Error(`LavaMoat/tofu - inspectPatternElementForPaths - unable to parse element "${child.type}"`) | ||
} | ||
} | ||
function inspectObjectPatternForPaths (node) { | ||
// if it has computed props or a RestElement, we cant meaningfully pursue any deeper | ||
// so return a single empty path, meaning "one result, the whole thing" | ||
const expansionForbidden = node.properties.some(prop => prop.computed || prop.type === 'RestElement') | ||
if (expansionForbidden) return [[]] | ||
// expand each property into a path, recursively | ||
let paths = [] | ||
node.properties.forEach(prop => { | ||
const propName = prop.key.name | ||
const child = prop.value | ||
paths = paths.concat( | ||
inspectPatternElementForPaths(child) | ||
.map(partial => [propName, ...partial]) | ||
) | ||
}) | ||
return paths | ||
} | ||
function inspectArrayPatternForPaths (node) { | ||
// if it has a RestElement, we cant meaningfully pursue any deeper | ||
// so return a single empty path, meaning "one result, the whole thing" | ||
const expansionForbidden = node.elements.some(el => el.type === 'RestElement') | ||
if (expansionForbidden) return [[]] | ||
// expand each property into a path, recursively | ||
let paths = [] | ||
node.elements.forEach((child, propName) => { | ||
paths = paths.concat( | ||
inspectPatternElementForPaths(child) | ||
.map(partial => [propName, ...partial]) | ||
) | ||
}) | ||
return paths | ||
} | ||
function inspectIdentifierForDirectMembershipChain (variableName, identifierNode) { | ||
let identifierUse = 'read' | ||
const memberExpressions = getMemberExpressionNesting(identifierNode) | ||
const hasMembershipChain = Boolean(memberExpressions.length) | ||
const { memberExpressions, parentOfMembershipChain, topmostMember } = getMemberExpressionNesting(identifierNode) | ||
// determine if used in an assignment expression | ||
const topmostMember = hasMembershipChain ? memberExpressions[0] : identifierNode | ||
const topmostMemberIndex = identifierNode.parents.indexOf(topmostMember) | ||
if (topmostMemberIndex < 1) { | ||
throw Error('unnexpected value for memberTopIndex') | ||
} | ||
const topmostMemberParentIndex = topmostMemberIndex - 1 | ||
const parentOfMembershipChain = identifierNode.parents[topmostMemberParentIndex] | ||
const isAssignment = parentOfMembershipChain.type === 'AssignmentExpression' | ||
@@ -133,7 +79,7 @@ const isAssignmentTarget = parentOfMembershipChain.left === topmostMember | ||
// if not used in any member expressions AND is not a global ref, expose as is | ||
if (!hasMembershipChain) { | ||
if (!memberExpressions.length) { | ||
return { identifierUse, path: [variableName], parent: parentOfMembershipChain } | ||
} | ||
const memberKeys = getKeysForMemberExpressionChain(memberExpressions) | ||
return { identifierUse, path: memberKeys, parent: parentOfMembershipChain } | ||
const path = [variableName, ...getPathFromMemberExpressionChain(memberExpressions)] | ||
return { identifierUse, path, parent: parentOfMembershipChain } | ||
} | ||
@@ -150,1 +96,79 @@ | ||
} | ||
function inspectImports (source) { | ||
const ast = (typeof source === 'object') ? source : acornGlobals.parse(source) | ||
let cjsImports = [] | ||
walk.ancestor(ast, { | ||
CallExpression: function (node, parents) { | ||
const { callee, arguments: [moduleNameNode] } = node | ||
if (callee.type !== 'Identifier') return | ||
if (callee.name !== 'require') return | ||
if (moduleNameNode.type !== 'Literal') return | ||
const moduleName = moduleNameNode.value | ||
// inspect for members | ||
node.parents = parents | ||
const { memberExpressions, parentOfMembershipChain } = getMemberExpressionNesting(node) | ||
const initialPath = [moduleName, ...getPathFromMemberExpressionChain(memberExpressions)] | ||
// exit early if unrecognized parent | ||
if (parentOfMembershipChain.type !== 'VariableDeclarator') { | ||
// not sure when this is would be hit? | ||
cjsImports.push(initialPath) | ||
return | ||
} | ||
// inspect for destructuring | ||
cjsImports = cjsImports.concat( | ||
inspectPatternElementForPaths(parentOfMembershipChain.id) | ||
.map(partial => [...initialPath, ...partial]) | ||
) | ||
} | ||
}) | ||
const cjsImportStrings = cjsImports.map(item => item.join('.')) | ||
return { cjsImports: cjsImportStrings } | ||
} | ||
function inspectPatternElementForPaths (child) { | ||
if (child.type === 'ObjectPattern') { | ||
return inspectObjectPatternForPaths(child) | ||
} else if (child.type === 'ArrayPattern') { | ||
return inspectArrayPatternForPaths(child) | ||
} else if (child.type === 'Identifier') { | ||
// return a single empty element, meaning "one result, the whole thing" | ||
return [[]] | ||
} else { | ||
throw new Error(`LavaMoat/tofu - inspectPatternElementForPaths - unable to parse element "${child.type}"`) | ||
} | ||
} | ||
function inspectObjectPatternForPaths (node) { | ||
// if it has computed props or a RestElement, we cant meaningfully pursue any deeper | ||
// so return a single empty path, meaning "one result, the whole thing" | ||
const expansionForbidden = node.properties.some(prop => prop.computed || prop.type === 'RestElement') | ||
if (expansionForbidden) return [[]] | ||
// expand each property into a path, recursively | ||
let paths = [] | ||
node.properties.forEach(prop => { | ||
const propName = prop.key.name | ||
const child = prop.value | ||
paths = paths.concat( | ||
inspectPatternElementForPaths(child) | ||
.map(partial => [propName, ...partial]) | ||
) | ||
}) | ||
return paths | ||
} | ||
function inspectArrayPatternForPaths (node) { | ||
// if it has a RestElement, we cant meaningfully pursue any deeper | ||
// so return a single empty path, meaning "one result, the whole thing" | ||
const expansionForbidden = node.elements.some(el => el.type === 'RestElement') | ||
if (expansionForbidden) return [[]] | ||
// expand each property into a path, recursively | ||
let paths = [] | ||
node.elements.forEach((child, propName) => { | ||
paths = paths.concat( | ||
inspectPatternElementForPaths(child) | ||
.map(partial => [propName, ...partial]) | ||
) | ||
}) | ||
return paths | ||
} |
module.exports = { | ||
getMemberExpressionNesting, | ||
getKeysForMemberExpressionChain, | ||
getPathFromMemberExpressionChain, | ||
isDirectMemberExpression, | ||
@@ -20,10 +20,16 @@ isUndefinedCheck, | ||
const memberExpressions = getTailmostMatchingChain(parents, isDirectMemberExpression).reverse() | ||
return memberExpressions | ||
// find parent of membership chain | ||
const hasMembershipChain = Boolean(memberExpressions.length) | ||
const topmostMember = hasMembershipChain ? memberExpressions[0] : identifierNode | ||
const topmostMemberIndex = identifierNode.parents.indexOf(topmostMember) | ||
if (topmostMemberIndex < 1) { | ||
throw Error('unnexpected value for memberTopIndex') | ||
} | ||
const topmostMemberParentIndex = topmostMemberIndex - 1 | ||
const parentOfMembershipChain = identifierNode.parents[topmostMemberParentIndex] | ||
return { memberExpressions, parentOfMembershipChain, topmostMember } | ||
} | ||
function getKeysForMemberExpressionChain (memberExpressions) { | ||
function getPathFromMemberExpressionChain (memberExpressions) { | ||
const keys = memberExpressions.map(member => getNameFromNode(member.property)) | ||
const rootMemberExpression = memberExpressions[0] | ||
const rootName = getNameFromNode(rootMemberExpression.object) | ||
keys.unshift(rootName) | ||
return keys | ||
@@ -30,0 +36,0 @@ } |
require('./inspectSource') | ||
require('./inspectImports') | ||
require('./util') |
const test = require('tape') | ||
const deepEqual = require('deep-equal') | ||
const { inspectSource } = require('../src/index') | ||
const { inspectGlobals } = require('../src/index') | ||
@@ -244,3 +244,3 @@ | ||
const src = fnToCodeBlock(fn) | ||
const result = inspectSource(src, opts) | ||
const result = inspectGlobals(src, opts) | ||
const resultSorted = [...result.entries()].sort(sortBy(0)) | ||
@@ -247,0 +247,0 @@ const expectedSorted = Object.entries(expectedResultObj).sort(sortBy(0)) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
21612
11
643
0
2
6
+ Addedacorn-walk@^7.1.1
+ Addedacorn@7.4.1(transitive)
+ Addedacorn-globals@6.0.0(transitive)
+ Addedacorn-walk@7.2.0(transitive)
- Removedacorn@6.4.2(transitive)
- Removedacorn-globals@4.3.4(transitive)
- Removedacorn-walk@6.2.0(transitive)
Updatedacorn-globals@^6.0.0