Skip to content

Commit

Permalink
refactor: migrate to Node.js native test runner (#108)
Browse files Browse the repository at this point in the history
* refactor: migrate to Node.js native test runner

* ci: remove Node.js v16.x

* chore: remove index.js

* fix: remove tape

* fix: test suite
  • Loading branch information
fraxken authored Sep 3, 2023
1 parent 6cb745f commit 3858a11
Show file tree
Hide file tree
Showing 28 changed files with 555 additions and 699 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [18.x]
fail-fast: false
steps:
- name: Harden Runner
Expand All @@ -36,7 +36,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x]
node-version: [18.x]
fail-fast: false
steps:
- name: Harden Runner
Expand Down
118 changes: 57 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,61 +1,57 @@
{
"name": "@nodesecure/js-x-ray",
"version": "6.1.1",
"description": "JavaScript AST XRay analysis",
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"lint": "eslint src test",
"prepublishOnly": "pkg-ok",
"test-only": "cross-env esm-tape-runner 'test/**/*.spec.js' | tap-monkey",
"test": "c8 --all --src ./src --reporter=lcov npm run test-only",
"check": "cross-env npm run lint && npm run test-only"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NodeSecure/js-x-ray.git"
},
"keywords": [
"ast",
"nsecure",
"nodesecure",
"analysis",
"dependencies",
"security"
],
"files": [
"src",
"types",
"index.js",
"index.d.ts"
],
"author": "GENTILHOMME Thomas <gentilhomme.thomas@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/NodeSecure/js-x-ray/issues"
},
"homepage": "https://github.com/NodeSecure/js-x-ray#readme",
"dependencies": {
"@nodesecure/estree-ast-utils": "^1.4.1",
"@nodesecure/sec-literal": "^1.2.0",
"estree-walker": "^3.0.1",
"is-minified-code": "^2.0.0",
"meriyah": "^4.3.3",
"safe-regex": "^2.1.1"
},
"devDependencies": {
"@nodesecure/eslint-config": "^1.6.0",
"@slimio/is": "^2.0.0",
"@small-tech/esm-tape-runner": "^2.0.0",
"@small-tech/tap-monkey": "^1.4.0",
"@types/node": "^20.3.0",
"c8": "^8.0.0",
"cross-env": "^7.0.3",
"eslint": "^8.31.0",
"pkg-ok": "^3.0.0",
"tape": "^5.6.1"
}
}
{
"name": "@nodesecure/js-x-ray",
"version": "6.1.1",
"description": "JavaScript AST XRay analysis",
"type": "module",
"exports": "./index.js",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"scripts": {
"lint": "eslint src test",
"prepublishOnly": "pkg-ok",
"test-only": "glob -c \"node --test-reporter=spec --test\" \"./test/**/*.spec.js\"",
"test": "c8 --all --src ./src -r html npm run test-only",
"check": "npm run lint && npm run test-only"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NodeSecure/js-x-ray.git"
},
"keywords": [
"ast",
"nsecure",
"nodesecure",
"analysis",
"dependencies",
"security"
],
"files": [
"src",
"types",
"index.js",
"index.d.ts"
],
"author": "GENTILHOMME Thomas <gentilhomme.thomas@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/NodeSecure/js-x-ray/issues"
},
"homepage": "https://github.com/NodeSecure/js-x-ray#readme",
"dependencies": {
"@nodesecure/estree-ast-utils": "^1.3.1",
"@nodesecure/sec-literal": "^1.2.0",
"estree-walker": "^3.0.1",
"is-minified-code": "^2.0.0",
"meriyah": "^4.3.3",
"safe-regex": "^2.1.1"
},
"devDependencies": {
"@nodesecure/eslint-config": "^1.6.0",
"@types/node": "^18.11.18",
"c8": "^7.12.0",
"eslint": "^8.31.0",
"glob": "^10.3.4",
"pkg-ok": "^3.0.0"
}
}
3 changes: 2 additions & 1 deletion src/probes/isRequire.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function walkRequireCallExpression(nodeToWalk, tracer) {
const fullName = node.callee.type === "MemberExpression" ?
[...getMemberExpressionIdentifier(node.callee)].join(".") :
node.callee.name;
const tracedFullName = tracer.getDataFromIdentifier(fullName)?.name ?? fullName;
const tracedFullName = tracer.getDataFromIdentifier(fullName)?.identifierOrMemberExpr ?? fullName;

switch (tracedFullName) {
case "atob": {
Expand All @@ -146,6 +146,7 @@ function walkRequireCallExpression(nodeToWalk, tracer) {
break;
}
case "require.resolve": {
console.log("require.resolve!");
if (rootArgument.type === "Literal") {
dependencies.add(rootArgument.value);
}
Expand Down
161 changes: 77 additions & 84 deletions test/astdeps.spec.js
Original file line number Diff line number Diff line change
@@ -1,89 +1,82 @@
// Require Third-party Dependencies
import is from "@slimio/is";
import test from "tape";
// Import Node.js Dependencies
import { describe, it } from "node:test";
import assert from "node:assert";

// Require Internal Dependencies
// Import Internal Dependencies
import ASTDeps from "../src/ASTDeps.js";

test("assert ASTDeps class default properties and values", (tape) => {
const deps = new ASTDeps();

tape.strictEqual(deps.isInTryStmt, false);
tape.strictEqual(is.plainObject(deps.dependencies), true);
tape.strictEqual(deps.size, 0);
tape.deepEqual([...deps], []);

tape.end();
});

test("add values to ASTDeps instance", (tape) => {
const deps = new ASTDeps();
deps.add("foo");
deps.isInTryStmt = true;
deps.add("boo");

tape.strictEqual(deps.size, 2);
tape.deepEqual([...deps], ["foo", "boo"]);
tape.deepEqual([...deps.getDependenciesInTryStatement()], ["boo"]);

tape.end();
});

test("add method should cleanup ending slash", (tape) => {
const deps = new ASTDeps();
deps.add("foo/");

tape.strictEqual(deps.size, 1);
tape.ok(deps.has("foo"));

tape.end();
});

test("delete values from ASTDeps instance", (tape) => {
const deps = new ASTDeps();
deps.add("foo");
deps.removeByName("foo");
deps.removeByName("boo");

tape.strictEqual(deps.size, 0);
tape.end();
});

test("isIntryStmt must be a boolean!", (tape) => {
const deps = new ASTDeps();

tape.throws(() => {
deps.isInTryStmt = 1;
}, "value must be a boolean!");

tape.end();
});

test("check presence of a dependency", (tape) => {
const deps = new ASTDeps();

deps.add("foo");

tape.strictEqual(deps.has("foo"), true);
tape.strictEqual(deps.has("bar"), false);
tape.strictEqual(deps.has(""), false);
tape.end();
describe("ASTDeps", () => {
it("assert ASTDeps class default properties and values", () => {
const deps = new ASTDeps();

assert.strictEqual(deps.isInTryStmt, false);
assert.ok(typeof deps.dependencies === "object");
assert.strictEqual(
Object.getPrototypeOf(deps.dependencies),
null
);
assert.strictEqual(deps.size, 0);
assert.deepEqual([...deps], []);
});

it("add values to ASTDeps instance", () => {
const deps = new ASTDeps();
deps.add("foo");
deps.isInTryStmt = true;
deps.add("boo");

assert.strictEqual(deps.size, 2);
assert.deepEqual([...deps], ["foo", "boo"]);
assert.deepEqual([...deps.getDependenciesInTryStatement()], ["boo"]);
});

it("add method should cleanup ending slash", () => {
const deps = new ASTDeps();
deps.add("foo/");

assert.strictEqual(deps.size, 1);
assert.ok(deps.has("foo"));
});

it("delete values from ASTDeps instance", () => {
const deps = new ASTDeps();
deps.add("foo");
deps.removeByName("foo");
deps.removeByName("boo");

assert.strictEqual(deps.size, 0);
});

it("isIntryStmt must be a boolean!", () => {
const deps = new ASTDeps();

assert.throws(() => {
deps.isInTryStmt = 1;
}, new TypeError("value must be a boolean!"));
});

it("should assert presence of a dependency", () => {
const deps = new ASTDeps();

deps.add("foo");

assert.strictEqual(deps.has("foo"), true);
assert.strictEqual(deps.has("bar"), false);
assert.strictEqual(deps.has(""), false);
});

it("should not add dependency if not a string primitive", () => {
const deps = new ASTDeps();

deps.add(5);
assert.strictEqual(deps.size, 0);
});

it("should not add dependency if provided with empty string", () => {
const deps = new ASTDeps();

deps.add("");
assert.strictEqual(deps.size, 0);
});
});

test("it should not add dependency if not a string primitive", (tape) => {
const deps = new ASTDeps();

deps.add(5);
tape.strictEqual(deps.size, 0);

tape.end();
});

test("it should not add dependency if provided with empty string", (tape) => {
const deps = new ASTDeps();

deps.add("");
tape.strictEqual(deps.size, 0);

tape.end();
});
24 changes: 11 additions & 13 deletions test/module.spec.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
// Import Third-party Dependencies
import test from "tape";
// Import Node.js Dependencies
import { test } from "node:test";
import assert from "node:assert";

// Import Internal Dependencies
import { runASTAnalysis } from "../index.js";

test("it should not crash even if module 'false' is provided (import keyword)", (tape) => {
test("it should not crash even if module 'false' is provided (import keyword)", () => {
runASTAnalysis("import * as foo from \"foo\";", {
module: false
});

tape.end();
});

test("it should not crash even if module 'false' is provided (export keyword)", (tape) => {
test("it should not crash even if module 'false' is provided (export keyword)", () => {
runASTAnalysis("export const foo = 5;", {
module: false
});

tape.end();
});

test("it should be capable to extract dependencies name for ECMAScript Modules (ESM)", (tape) => {
test("it should be capable to extract dependencies name for ECMAScript Modules (ESM)", () => {
const { dependencies, warnings } = runASTAnalysis(`
import * as http from "http";
import fs from "fs";
import { foo } from "xd";
`, { module: true });

tape.strictEqual(warnings.length, 0);
tape.deepEqual([...dependencies].sort(), ["http", "fs", "xd"].sort());

tape.end();
assert.strictEqual(warnings.length, 0);
assert.deepEqual(
[...dependencies].sort(),
["http", "fs", "xd"].sort()
);
});
Loading

0 comments on commit 3858a11

Please sign in to comment.