diff --git a/mininode.bash b/mininode.bash new file mode 100755 index 0000000..31690d2 --- /dev/null +++ b/mininode.bash @@ -0,0 +1,102 @@ +#!/bin/bash +: ' +This is for the package installation, debloating, and validation in the Docker +Container. Assuming the source code of the package is already downloaded as +tar.gz file and stored under the root directory. +' + +: 'SHAREDMOUNT is the directory that stores the package tar.gz file' +SHAREDMOUNT="/sharedMount" +ROOT="/" +MININODE="index.js" +SUFFIX_ORIG="orig" +SUFFIX_PROD="prod" +SUFFIX_RDUC="reduced" + +File_Name=$1 +: 'Check whether the file exists' +if [ ! -f "$File_Name" ]; then + echo "File not found!" + exit 1 +fi + +echo "File_Name is $File_Name" +: 'for the full path, use this: PACKAGE_NAME=”${fullfile##*/}” ' + +: ' +extract the tar.gz file for the original version of the package +obtain the directory of the unpacked package +modify the name of the directory by appending SUFFIX_ORIG +' +unpacked=$(tar -xvzf $File_Name) +echo "unpacked: $unpacked" +packdir=$(echo $unpacked | cut -f1 -d" ") + +: 'remove the last "/" from packdir if it exists' +packdir=${packdir%/} + +PACKAGE_ORIG="$packdir-$SUFFIX_ORIG" +echo "unpacked: $packdir" +echo "PACKAGE_ORIG: $PACKAGE_ORIG" +mv $packdir $PACKAGE_ORIG + +: ' +go to the orig directory, install the package, and run the test +' +cd $PACKAGE_ORIG +if npm install; then + echo "$PACKAGE_ORIG sucessfully installed." +else + echo "$PACKAGE_ORIG failed to be installed!" + exit 1 +fi + +if npm run test; then + echo "$PACKAGE_ORIG test run sucessfully." +else + echo "$PACKAGE_ORIG failed to run test!" + exit 1 +fi + +: ' +re-extract the tar.gz file for the product version of this package +obtain the directory of the unpacked package +modify the name of the directory by appending SUFFIX_PROD +' +cd $SHAREDMOUNT +tar -xvzf $File_Name + +# reuse the $packdir obtained from the original extraction +PACKAGE_PROD="$packdir-$SUFFIX_PROD" +echo "unpacked: $packdir" +echo "PACKAGE_PROD: $PACKAGE_PROD" +mv $packdir $PACKAGE_PROD + +: ' +go to the prod directory, install the package +' +cd $PACKAGE_PROD +if npm install --only=prod; then + echo "$PACKAGE_PROD sucessfully installed." +else + echo "$PACKAGE_PROD failed to be installed!" + exit 1 +fi + +cd $ROOT +# reuse the $packdir obtained from the original extraction +PACKAGE_RDUC="$packdir-$SUFFIX_RDUC" +# specify the full path of the produce version, and the reduced version, respectively +package_prod_full="$SHAREDMOUNT/$PACKAGE_PROD/" +package_rduc_full="$SHAREDMOUNT/$PACKAGE_RDUC" # take out slash so program works correctly + +echo "node --max-old-space-size=8192 $MININODE $package_prod_full --mode=fine --destination=$package_rduc_full" +echo $package_rduc_full +if node --max-old-space-size=8192 $MININODE $package_prod_full --mode=fine --destination=$package_rduc_full; then + echo "$PACKAGE_PROD sucessfully debloated." +else + echo "$PACKAGE_PROD failed to be debloated!" + exit 1 +fi +echo "skipped validation" +exit 1 diff --git a/src/index.js b/src/index.js index 6b62153..486bc79 100755 --- a/src/index.js +++ b/src/index.js @@ -63,10 +63,10 @@ let entries = []; // 3. add to individual modules used globals. for (let modul of _app.modules) { for (let mem in modul.memusages) { - _app.globals.forEach((i) => { - if (i.name === mem) { + _app.globals.forEach((globalVar) => { + if (globalVar.name === mem) { for (let m of modul.memusages[mem]) { - i.members.push(m); + globalVar.members.push(m); } } }); @@ -200,16 +200,16 @@ async function init() { if (testEntryPoints && testEntryPoints.length > 0) { //TODO-Hui: here do we need to find the path to these test entry points? //TODO-Hui: also, with these test entry points, perhaps we should not block test directories? - testEntryPoints.forEach(entryP => { + testEntryPoints.forEach((entryP) => { if (!_app.main.includes(entryP)) { _app.main.push(entryP); } - }) + }); } - - if (packageJson.hasOwnProperty('directories')) { - if (packageJson.directories.hasOwnProperty('test')) { - _app.directories = packageJson.directories.test + + if (packageJson.hasOwnProperty("directories")) { + if (packageJson.directories.hasOwnProperty("test")) { + _app.directories = packageJson.directories.test; } } @@ -217,9 +217,9 @@ async function init() { if (!_app.main) { throw new Error("NO_ENTRY_POINT"); } - _app.main.forEach(entryP => { + _app.main.forEach((entryP) => { entries.push(path.join(_app.path, entryP)); - }) + }); } else { for (let seed of config.seeds) { let s = utils.entryPoint(location, seed); @@ -541,21 +541,19 @@ function getJSFilenamesInScriptsField(packageJson) { let stringToDealWith = scripts[key]; let words = stringToDealWith.split(" "); for (let wPotentialFile of words) { - if (wPotentialFile.indexOf('*') > -1) { + if (wPotentialFile.indexOf("*") > -1) { continue; } let splitWordArr = wPotentialFile.split("."); if (splitWordArr.length > 1) { if ( - ["js", "mjs", "cjs"].includes( - splitWordArr[splitWordArr.length - 1] - ) + ["js", "mjs", "cjs"].includes(splitWordArr[splitWordArr.length - 1]) ) { result.push(wPotentialFile); } } } } - } + } return result; -} \ No newline at end of file +} diff --git a/src/lib/Stat.js b/src/lib/Stat.js index fcd4e21..3fae9da 100644 --- a/src/lib/Stat.js +++ b/src/lib/Stat.js @@ -108,7 +108,7 @@ async function initialPass(modul) { } break; case syntax.MemberExpression: - // TODO-Hui: this branch only tracks "exports". + // TODO-Hui: this branch only tracks "exports". // We will see whether we need to handle case #3 in syntax.ImportExpression if (node.object.type === syntax.Identifier) { if ( @@ -219,10 +219,12 @@ async function initialPass(modul) { modul.exporters.push(node.left.name); break; } - } else if ( (node.right.type === syntax.ImportExpression) || - ( (node.right.type === syntax.AwaitExpression ) && (node.right.argument.type === syntax.ImportExpression) ) - ) { - // TODO-Hui: do we need this? + } else if ( + node.right.type === syntax.ImportExpression || + (node.right.type === syntax.AwaitExpression && + node.right.argument.type === syntax.ImportExpression) + ) { + // TODO-Hui: do we need this? // add the support of Case 4 (see case syntax.ImportExpression) here modul.requires.push(node.left.name); } else if (node.right.type === syntax.MemberExpression) { @@ -275,7 +277,7 @@ async function initialPass(modul) { modul.exporters.push(node.id.name); } } else if (node.init.type === syntax.ImportExpression) { - // TODO-Hui: do we need this? + // TODO-Hui: do we need this? // add the support of Case 5 (see case syntax.ImportExpression) here modul.requires.push(node.id.name); } @@ -308,27 +310,29 @@ async function initialPass(modul) { } break; case syntax.FunctionDeclaration: - if (parent.type === syntax.ExportNamedDeclaration || - parent.type === syntax.ExportDefaultDeclaration) { - console.debug(`modul name: ${modul.name}`); - } + if ( + parent.type === syntax.ExportNamedDeclaration || + parent.type === syntax.ExportDefaultDeclaration + ) { + console.debug(`modul name: ${modul.name}`); + } modul.functions += 1; break; case syntax.ImportDeclaration: - // ImportDeclaration: static import in ES6. + // ImportDeclaration: static import in ES6. // type: "ImportDeclaration" // specifiers: [ ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier ] // source: Literal const modulePath = node.source.value; - node.specifiers.forEach(specifier => { + node.specifiers.forEach((specifier) => { const alias = specifier.local.name; let name; switch (specifier.type) { - case 'ImportSpecifier': + case "ImportSpecifier": // type: "ImportSpecifier" // imported: Identifier // example: {foo} in import {foo} from "mode", or {foo as bar} in import {foo as bar} from "mode" - // In the first example, imported and local are equivalent Identifier node. + // In the first example, imported and local are equivalent Identifier node. // In the second example, imported represents foo while local represents bar name = specifier.imported.name; modul.staticRequire += 1; @@ -336,20 +340,20 @@ async function initialPass(modul) { //modul.identifiers.addIdentifier(modulePath); // should we add identifier here? //modul.requires.push(name); // we do not push requires at this stage break; - case 'ImportDefaultSpecifier': + case "ImportDefaultSpecifier": // type: "ImportDefaultSpecifier" // example: foo in import foo from "mod.js" - name = 'default'; + name = "default"; modul.staticRequire += 1; modules.push(alias); //modul.identifiers.addIdentifier(modulePath); // should we add identifier here? //modul.requires.push(modulePath); // we do not push requires at this stage break; - case 'ImportNamespaceSpecifier': + case "ImportNamespaceSpecifier": // type: "ImportNamespaceSpecifier" // example: * as foo in import * as foo from "mod.js" // TODO-Hui: document all functions in modulePath? - name = '*'; + name = "*"; modul.staticRequire += 1; modules.push(alias); //modul.identifiers.addIdentifier(modulePath); // should we add identifier here? @@ -359,32 +363,35 @@ async function initialPass(modul) { // attack surface marking. TODO-Hui: check the logic if (utils.hasKey(attack, modulePath)) { - helper.VariableAssignmentName(parent, (name) => { - if (name) { - if (Array.isArray(name)) { - console.log(name); + helper.VariableAssignmentName(parent, (name) => { + if (name) { + if (Array.isArray(name)) { + console.log(name); + } + tracker.push(name); + let vector = { name: name, value: arg.value, members: [] }; + modul.attackVectors.push(vector); + //if (parent.type === syntax.MemberExpression) { + // vector.members.push(parent.property.name); + //} } - tracker.push(name); - let vector = { name: name, value: arg.value, members: [] }; - modul.attackVectors.push(vector); - //if (parent.type === syntax.MemberExpression) { - // vector.members.push(parent.property.name); - //} - } }); } - + // console.log below is for debugging only. They will be removed after the processing is done in the above three cases if (name) { - console.debug(`Static Import: modul name: ${modul.name}, alias: ${alias}, name: ${name}, modulePath: ${modulePath}`); - } - else { - console.debug(`Static Import: NOT supported. modul name: ${modul.name}, modulePath: ${modulePath}`); + console.debug( + `Static Import: modul name: ${modul.name}, alias: ${alias}, name: ${name}, modulePath: ${modulePath}` + ); + } else { + console.debug( + `Static Import: NOT supported. modul name: ${modul.name}, modulePath: ${modulePath}` + ); } - }) + }); break; case syntax.ImportExpression: - // This is for import() which is a import from an ESM module to a commonjs module. + // This is for import() which is a import from an ESM module to a commonjs module. // It can be either static import or dynamic import, depending on the argument // five cases to support as of 03/22/2023: @@ -393,40 +400,60 @@ async function initialPass(modul) { // 3: import("/my-module.mjs").init; await import("/my-module.mjs").init; // 4: exs = import("/my-module.mjs"); exs = await import("/my-module.mjs"); // 5: const exs = import("/my-module.mjs"); - // Note: + // Note: // Case 1 & 2: these imports are not used by themselves in the application // The processing of 3, 4 and 5 is in syntax.MemberExpression, syntax.AssignmentExpression and syntax.VariableDeclarator, respectively // The ConditionalExpression is not supported yet: import(someCondition ? "./mod1.js" : "./mod2.js"); await import(someCondition ? "./mod1.js" : "./mod2.js"); - + // The following is for debugging only - if ( (parent.type === syntax.ExpressionStatement) || - ( (parent.type === syntax.AwaitExpression) && (parent.xParent.type === syntax.ExpressionStatement) ) + if ( + parent.type === syntax.ExpressionStatement || + (parent.type === syntax.AwaitExpression && + parent.xParent.type === syntax.ExpressionStatement) ) { if (node.source.type === syntax.Literal) { // case 1 - either a standalone statement, or part of a IfStatement or BlockStatement - console.debug(`Import() case 1. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); + console.debug( + `Import() case 1. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); } else if (node.source.type === syntax.BinaryExpression) { // case 2 - either a standalone statement, or part of a IfStatement or BlockStatement - console.debug(`Import() case 2. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); + console.debug( + `Import() case 2. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); } else { // general case 2 - console.debug(`Import() general case 2. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); + console.debug( + `Import() general case 2. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); } } else if (parent.type === syntax.MemberExpression) { // case 3 - console.debug(`Import() case 3. modul name: ${modul.name}, modulePath: ${node.source.type}, parent type: ${parent.type}, ${parent.xParent.type}`); - } else if ( (parent.type === syntax.AssignmentExpression) || - ( (parent.type === syntax.AwaitExpression) && (parent.xParent.type === syntax.AssignmentExpression) ) + console.debug( + `Import() case 3. modul name: ${modul.name}, modulePath: ${node.source.type}, parent type: ${parent.type}, ${parent.xParent.type}` + ); + } else if ( + parent.type === syntax.AssignmentExpression || + (parent.type === syntax.AwaitExpression && + parent.xParent.type === syntax.AssignmentExpression) ) { // case 4 - console.debug(`Import() case 4. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); - } else if ( (parent.type === syntax.VariableDeclarator) || - ( (parent.type === syntax.AwaitExpression) && (parent.xParent.type === syntax.VariableDeclarator) ) + console.debug( + `Import() case 4. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); + } else if ( + parent.type === syntax.VariableDeclarator || + (parent.type === syntax.AwaitExpression && + parent.xParent.type === syntax.VariableDeclarator) ) { // case 5 - console.debug(`Import() case 5. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); + console.debug( + `Import() case 5. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); } else { - console.debug(`Import() case unknown. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}`); + console.debug( + `Import() case unknown. modul name: ${modul.name}, modulePath: ${node.source.value}, parent type: ${parent.type}, ${parent.xParent.type}` + ); } // end of the debugging block @@ -435,7 +462,8 @@ async function initialPass(modul) { if (arg.type !== syntax.Literal) { modul.dynamicRequire += 1; if (arg.type === syntax.BinaryExpression) { - let isDynamicBinaryExpression = utils.BinaryExpression.isDynamic(arg); + let isDynamicBinaryExpression = + utils.BinaryExpression.isDynamic(arg); if (isDynamicBinaryExpression) modul.complexDynamicRequire += 1; } else if ( arg.type === syntax.Identifier && @@ -469,10 +497,7 @@ async function initialPass(modul) { if (vardeclarator) { modules.push(vardeclarator.id.name); } - let assignment = helper.closests( - node, - syntax.AssignmentExpression - ); + let assignment = helper.closests(node, syntax.AssignmentExpression); if (assignment && assignment.left.type === syntax.Identifier) { modules.push(assignment.left.name); } @@ -493,20 +518,23 @@ async function initialPass(modul) { // export const move = _move.move modul.staticExport += 1; - console.log(`ExportNamedDeclaration: modul name: ${modul.name}, source: ${node.source}`); + console.log( + `ExportNamedDeclaration: modul name: ${modul.name}, source: ${node.source}` + ); if (node.declaration) { // for now I only see the following types in the declaration of ExportNamedDeclaration console.log(` declaration type: ${node.declaration.type}`); if (node.declaration.type === syntax.VariableDeclaration) { // this supports multiple VariableDeclarator in declaration.declarations for (const declaElem of node.declaration.declarations) { - if ( (declaElem.type === syntax.VariableDeclarator) ) { + if (declaElem.type === syntax.VariableDeclarator) { if (declaElem.id.type === syntax.Identifier) { self.push(declaElem.id.name); // TODO-Hui: we may not need to use self to store this - if (!modul.exporters.includes(declaElem.id.name)) { // TODO-Hui: do we need to check this? + if (!modul.exporters.includes(declaElem.id.name)) { + // TODO-Hui: do we need to check this? modul.exporters.push(declaElem.id.name); } - } + } // TODO-Hui: do we need to consider the init (e.g., MemberExpression)? perhaps not since the detail is only needed in Analyzer.js? // also, do we need to update attackVectors if tracker.includes(node.object.name) when syntax.MemberExpression? example: module.exports = _copy @@ -515,9 +543,10 @@ async function initialPass(modul) { } console.log(` declaration.id.name: ${declaElem.id.name}`); } - } else if ( (node.declaration.type === syntax.FunctionDeclaration) || - (node.declaration.type === syntax.ClassDeclaration) - ) { + } else if ( + node.declaration.type === syntax.FunctionDeclaration || + node.declaration.type === syntax.ClassDeclaration + ) { // there is no declarations in the function or class declaration. Use declaration directly // follow the same to-dos in syntax.VariableDeclaration if (node.declaration.id.type === syntax.Identifier) { @@ -528,19 +557,24 @@ async function initialPass(modul) { } } else { // TODO-Hui: will there be MemberExpression or AssignmentExpression? The answer is no for now. - console.log(` warning: this declaration.id.type ${node.declaration.type} is not supported!`); + console.log( + ` warning: this declaration.id.type ${node.declaration.type} is not supported!` + ); } } - + if (node.specifiers && node.specifiers.length > 0) { // follow the same to-dos in syntax.VariableDeclaration - node.specifiers.forEach(specifier => { - console.log(` specifier: Exported: ${specifier.exported.name}, Local: ${specifier.local.name}`); - self.push(specifier.local.name); + // specifier.exported.name is the alias, specifier.local.name is the actual + node.specifiers.forEach((specifier) => { + console.log( + ` specifier: Exported: ${specifier.exported.name}, Local: ${specifier.local.name}` + ); + self.push(specifier.local.name); if (!modul.exporters.includes(specifier.local.name)) { modul.exporters.push(specifier.local.name); } - }) + }); } break; case syntax.ExportDefaultDeclaration: @@ -553,10 +587,12 @@ async function initialPass(modul) { // export default class MyClass{}, export default class {} // export default function myfunc2() {}, export default function () {} // Note: export default Literal is not considered here. I believe it does not have impact on our debloating. - + // TODO-Hui: follow the same to-dos in syntax.ExportNamedDeclaration modul.staticExport += 1; - console.log(`ExportDefaultDeclaration: modul name: ${modul.name}, declaration type: ${node.declaration.type}`); + console.log( + `ExportDefaultDeclaration: modul name: ${modul.name}, declaration type: ${node.declaration.type}` + ); switch (node.declaration.type) { case syntax.Identifier: // export default foo @@ -573,44 +609,63 @@ async function initialPass(modul) { if (!modul.exporters.includes(node.declaration.left.name)) { modul.exporters.push(node.declaration.left.name); } - console.log(` declaration.left.name: ${node.declaration.left.name}`); + console.log( + ` declaration.left.name: ${node.declaration.left.name}` + ); break; case syntax.ClassDeclaration: - if (node.declaration.id && (node.declaration.id.type === syntax.Identifier) ) { + if ( + node.declaration.id && + node.declaration.id.type === syntax.Identifier + ) { self.push(node.declaration.id.name); if (!modul.exporters.includes(node.declaration.id.name)) { modul.exporters.push(node.declaration.id.name); } - console.log(` declaration.id.name: ${node.declaration.id.name}`); + console.log( + ` declaration.id.name: ${node.declaration.id.name}` + ); } break; case syntax.FunctionDeclaration: - if (node.declaration.id && (node.declaration.id.type === syntax.Identifier) ) { + if ( + node.declaration.id && + node.declaration.id.type === syntax.Identifier + ) { self.push(node.declaration.id.name); if (!modul.exporters.includes(node.declaration.id.name)) { modul.exporters.push(node.declaration.id.name); } - console.log(` declaration.id.name: ${node.declaration.id.name}`); + console.log( + ` declaration.id.name: ${node.declaration.id.name}` + ); } break; case syntax.ObjectExpression: - // I only see ObjectExpression from the specification/examples. + // I only see ObjectExpression from the specification/examples. // The peroperties of ObjectExpression include SpreadElements. The argument of each SpreadElement is an identifier if (node.declaration.properties) { for (const spreadElem of node.declaration.properties) { - if ( spreadElem.argument && (spreadElem.argument.type === syntax.Identifier) ) { - self.push(spreadElem.argument.name); + if ( + spreadElem.argument && + spreadElem.argument.type === syntax.Identifier + ) { + self.push(spreadElem.argument.name); if (!modul.exporters.includes(spreadElem.argument.name)) { modul.exporters.push(spreadElem.argument.name); } - } - console.log(` declaration.properties.element.argument: ${spreadElem.argument.name}`); + } + console.log( + ` declaration.properties.element.argument: ${spreadElem.argument.name}` + ); } } break; default: // in case there is other Expression type - console.log(`Warning: Not supported node.declaration.type ${node.declaration.type} in ExportDefaultDeclaration.`); + console.log( + `Warning: Not supported node.declaration.type ${node.declaration.type} in ExportDefaultDeclaration.` + ); } break; case syntax.ExportAllDeclaration: @@ -619,8 +674,10 @@ async function initialPass(modul) { // TODO-Hui: This is also called re-exporting since the exported is from another file. Does this make our analysis task easier? // To get the detail, this may need to go to 'source' to retrieve all related identifiers // Note: in commonjs modules, to support the same function, we need module.exports = {a function to loop all items in the source and then require(item)} - console.log(`ExportAllDeclaration: modul name: ${modul.name}, source: ${node.source}`); - break; + console.log( + `ExportAllDeclaration: modul name: ${modul.name}, source: ${node.source}` + ); + break; } }, leave: function (node, parent) { @@ -645,9 +702,11 @@ async function initialPass(modul) { // do the same thing for dynamic import (from ESM to CommonJS module) // TODO-Hui: after the implementation of ImportExpression, check whether this is duplicate if (node.type === syntax.ImportExpression) { - console.log(`leave function for dynamic import: modul name: ${modul.name}`); + console.log( + `leave function for dynamic import: modul name: ${modul.name}` + ); if ( - node.source.type === syntax.Identifier && + node.source.type === syntax.Identifier && modul.identifiers.hasIdentifier(node.source.value) ) { // marking the identifier as a module diff --git a/src/lib/models/AppBuilder.js b/src/lib/models/AppBuilder.js index ed1ac4f..19377a0 100644 --- a/src/lib/models/AppBuilder.js +++ b/src/lib/models/AppBuilder.js @@ -1,9 +1,9 @@ -const ModuleBuilder = require('./ModuleBuilder'); +const ModuleBuilder = require("./ModuleBuilder"); module.exports = function () { - this.appname = ''; - this.version = ''; - this.type = ''; - this.path = ''; + this.appname = ""; + this.version = ""; + this.type = ""; + this.path = ""; // Hui Zeng: in Node.js v19.8.1, "exports" provides a modern alternative to "main" allowing multiple entry points to defined this.main = []; this.testsDirectory = null; @@ -25,10 +25,10 @@ module.exports = function () { this.declaredDependencyCount = 0; this.installedUniqueDependencyCount = 0; this.installedTotalDependencyCount = 0; - + this.totalStaticExports = 0; this.totalDynamicExports = 0; - + this.totalStaticRequire = 0; this.totalDynamicRequire = 0; this.totalComplexDynamicRequire = 0; @@ -36,7 +36,7 @@ module.exports = function () { this.totalFunctions = 0; this.totalVariables = 0; - + this.totalEval = 0; this.totalEvalWithVar = 0; this.totalFunctionNew = 0; @@ -60,9 +60,10 @@ module.exports = function () { this.globals = []; // all global variables that Application has. Ex: {name: 'foo', path: 'lib/foo.js', members: []} this.dimports = []; // all modules that dynamically imported. Ex: {name: 'foo', members: [], by: ''}. DIMPORTS has higher precedence than GLOBALS /** @type {ModuleBuilder} */ - this.modules = [];// all modules that Application has, i.e. all js files inside every package. Ex: express/lib/express.js, mocha/index.js - - this.dependencies = {};// all packages Application has. Ex: express, mocha, lodash. {parent: "", name:"", version:""} + this.modules = []; // all modules that Application has, i.e. all js files inside every package. Ex: express/lib/express.js, mocha/index.js + + this.dependencies = {}; // all packages Application has. Ex: express, mocha, lodash. {parent: "", name:"", version:""} this.builtins = {}; // all native modules that were used inside the application. + this.parsedBlacklist = []; };