Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: update to esm #191

Merged
merged 5 commits into from
Aug 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
indent_size = 4
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf

[*.md]
max_line_length = off
trim_trailing_whitespace = false
7 changes: 4 additions & 3 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "@slimio/eslint-config",
"rules": {
"jsdoc/require-jsdoc": "off"
"extends": "@nodesecure/eslint-config",
"parserOptions": {
"sourceType": "module",
"requireConfigFile": false
}
}
7 changes: 0 additions & 7 deletions .travis.yml

This file was deleted.

20 changes: 10 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
# Contributing to Slim.io
# Contributing to NodeSecure

Contributions to Slim.io include code, documentation, answering user questions,
running the project's infrastructure, and advocating for all types of Slim.io
Contributions to NodeSecure include code, documentation, answering user questions,
running the project's infrastructure, and advocating for all types of NodeSecure
users.

The Slim.io project welcomes all contributions from anyone willing to work in
The NodeSecure project welcomes all contributions from anyone willing to work in
good faith with other contributors and the community. No contribution is too
small and all contributions are valued.

This guide explains the process for contributing to the Slim.io project's.
This guide explains the process for contributing to the NodeSecure project's.

## [Code of Conduct](https://github.com/SlimIO/Governance/blob/master/CODE_OF_CONDUCT.md)
## [Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/CONTRIBUTING.md)

The Slim.io project has a
[Code of Conduct](https://github.com/SlimIO/Governance/blob/master/CODE_OF_CONDUCT.md)
The NodeSecure project has a
[Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/CONTRIBUTING.md)
that *all* contributors are expected to follow. This code describes the
*minimum* behavior expectations for all contributors.

See [details on our policy on Code of Conduct](https://github.com/SlimIO/Governance/blob/master/COC_POLICY.md).
See [details on our policy on Code of Conduct](https://github.com/NodeSecure/Governance/blob/main/COC_POLICY.md).

<a id="developers-certificate-of-origin"></a>
## Developer's Certificate of Origin 1.1
Expand All @@ -44,4 +44,4 @@ By making a contribution to this project, I certify that:
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
this project or the open source license(s) involved.
16 changes: 0 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,21 +109,5 @@ The theme can be either `dark` or `light`. Themes are editable in *public/css/th

> All D3 scale-chromatic for charts can be found [here](https://github.com/d3/d3-scale-chromatic/blob/master/README.md).

## Dependencies

|Name|Refactoring|Security Risk|Usage|
|---|---|---|---|
|[@slimio/async-cli-spinner](https://github.com/SlimIO/Async-cli-spinner)|Minor|Low|Elegant Asynchronous Terminal (CLI) Spinner|
|[@slimio/lock](https://github.com/SlimIO/Lock)|Minor|Low|Semaphore for async/await|
|[@slimio/utils](https://github.com/SlimIO/Utils)|Minor|Low|Bunch of useful functions for SlimIO|
|[dotenv](https://github.com/motdotla/dotenv)|Minor|Low|Loads environment variables from .env|
|[filenamify](https://github.com/sindresorhus/filenamify#readme)|Minor|High|Convert a string to a valid safe filename|
|[isomorphic-git](https://isomorphic-git.org/)|Minor|High|A pure JavaScript implementation of git for node and browsers!|
|[kleur](https://github.com/lukeed/kleur)|Minor|Low|The fastest Node.js library for formatting terminal text with ANSI colors|
|[make-promises-safe](https://github.com/mcollina/make-promises-safe)|⚠️Major|Low|Force Node.js [DEP00018](https://nodejs.org/dist/latest-v8.x/docs/api/deprecations.html#deprecations_dep0018_unhandled_promise_rejections)|
|[nsecure](https://github.com/ES-Community/node-secure#readme)|Minor|High|Node.js security CLI / API that allow you to deeply analyze the dependency tree of a given package / directory|
|[puppeteer](https://github.com/puppeteer/puppeteer#readme)|Minor|High|Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium|
|[zup](https://github.com/mscdex/zup#readme)|Minor|Low|A simple and fast template engine for Node.js|

## License
MIT
5 changes: 0 additions & 5 deletions commitlint.config.js

This file was deleted.

244 changes: 124 additions & 120 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,152 +1,156 @@
/* eslint-disable max-depth */
"use strict";

require("dotenv").config();
require("make-promises-safe");

/* eslint-disable max-depth, max-len */
// Require Node.js Dependencies
const { join, basename } = require("path");
const { readdirSync, promises: { mkdir, rmdir, readFile, writeFile } } = require("fs");
import path from "path";
import fs, { promises } from "fs";
import { fileURLToPath } from "url";

// Require Third-party Dependencies
const { cyan, white } = require("kleur");
const { taggedString } = require("@slimio/utils");
const compile = require("zup");
const Spinner = require("@slimio/async-cli-spinner");
import dotenv from "dotenv";
dotenv.config();

import kleur from "kleur";
import { taggedString } from "@slimio/utils";
import compile from "zup";
import Spinner from "@slimio/async-cli-spinner";
Spinner.DEFAULT_SPINNER = "dots";

// Require Internal Dependencies
const { cloneGITRepository, fetchStatsFromNsecurePayloads, nsecure, cleanReportName } = require("./src/utils");
const { generatePDF } = require("./src/pdf");
const config = require("./data/config.json");
import { cloneGITRepository, fetchStatsFromNsecurePayloads, nsecure, cleanReportName } from "./src/utils.js";
import { generatePDF } from "./src/pdf.js";
const config = JSON.parse(
fs.readFileSync(new URL("./data/config.json", import.meta.url))
);

// CONSTANTS
const kCloneDir = join(__dirname, "clones");
const kJsonDir = join(__dirname, "json");
const kViewsDir = join(__dirname, "views");
const kReportsDir = join(__dirname, "reports");
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const kCloneDir = path.join(__dirname, "clones");
const kJsonDir = path.join(__dirname, "json");
const kViewsDir = path.join(__dirname, "views");
const kReportsDir = path.join(__dirname, "reports");
const kChartTemplate = taggedString`\tcreateChart("${0}", "${4}", { labels: [${1}], interpolate: ${3}, data: [${2}] });`;
const kAvailableThemes = new Set(readdirSync(join(__dirname, "public", "css", "themes")).map((file) => basename(file, ".css")));
const kAvailableThemes = new Set(fs.readdirSync(path.join(__dirname, "public", "css", "themes")).map((file) => path.basename(file, ".css")));

async function fetchPackagesStats() {
const spinner = new Spinner({
prefixText: white().bold("Fetching packages stats on nsecure")
}).start();

try {
const jsonFiles = await Promise.all(config.npm_packages.map(nsecure.onPackage));
const elapsed = `${spinner.elapsedTime.toFixed(2)}ms`;
spinner.succeed(`Successfully done in ${cyan().bold(elapsed)}`);

return fetchStatsFromNsecurePayloads(jsonFiles.filter((value) => value !== null));
}
catch (error) {
spinner.failed(error.message);
throw error;
}
const spinner = new Spinner({
prefixText: kleur.white().bold("Fetching packages stats on nsecure")
}).start();

try {
const jsonFiles = await Promise.all(config.npm_packages.map(nsecure.onPackage));
const elapsed = `${spinner.elapsedTime.toFixed(2)}ms`;
spinner.succeed(`Successfully done in ${kleur.cyan().bold(elapsed)}`);

return fetchStatsFromNsecurePayloads(jsonFiles.filter((value) => value !== null));
}
catch (error) {
spinner.failed(error.message);
throw error;
}
}

async function fetchRepositoriesStats() {
const spinner = new Spinner({
prefixText: white().bold("Clone and analyze built-in addons")
}).start("clone repositories...");

try {
const repos = await Promise.all(config.git_repositories.map(cloneGITRepository));
spinner.text = "Run node-secure analyze";

const jsonFiles = await Promise.all(repos.map(nsecure.onLocalDirectory));
const elapsed = `${spinner.elapsedTime.toFixed(2)}ms`;
spinner.succeed(`Successfully done in ${cyan().bold(elapsed)}`);

return fetchStatsFromNsecurePayloads(jsonFiles.filter((value) => value !== null));
}
catch (error) {
spinner.failed(error.message);
throw error;
}
const spinner = new Spinner({
prefixText: kleur.white().bold("Clone and analyze built-in addons")
}).start("clone repositories...");

try {
const repos = await Promise.all(config.git_repositories.map(cloneGITRepository));
spinner.text = "Run node-secure analyze";

const jsonFiles = await Promise.all(repos.map(nsecure.onLocalDirectory));
const elapsed = `${spinner.elapsedTime.toFixed(2)}ms`;
spinner.succeed(`Successfully done in ${kleur.cyan().bold(elapsed)}`);

return fetchStatsFromNsecurePayloads(jsonFiles.filter((value) => value !== null));
}
catch (error) {
spinner.failed(error.message);
throw error;
}
}

// eslint-disable-next-line max-params
function toChart(baliseName, data, interpolateName, type = "bar") {
const graphLabels = Object.keys(data).map((key) => `"${key}"`).join(",");
const graphLabels = Object.keys(data).map((key) => `"${key}"`).join(",");

return kChartTemplate(baliseName, graphLabels, Object.values(data).join(","), interpolateName, type);
return kChartTemplate(baliseName, graphLabels, Object.values(data).join(","), interpolateName, type);
}

function generateChartArray(pkgStats, repoStats) {
const charts = [];
const displayableCharts = config.charts.filter((chart) => chart.display);

if (pkgStats !== null) {
for (const chart of displayableCharts) {
const name = chart.name.toLowerCase();
charts.push(toChart(`npm_${name}_canvas`, pkgStats[name], chart.interpolation, chart.type));
}
const charts = [];
const displayableCharts = config.charts.filter((chart) => chart.display);

if (pkgStats !== null) {
for (const chart of displayableCharts) {
const name = chart.name.toLowerCase();
charts.push(toChart(`npm_${name}_canvas`, pkgStats[name], chart.interpolation, chart.type));
}
if (repoStats !== null) {
for (const chart of displayableCharts) {
const name = chart.name.toLowerCase();
charts.push(toChart(`git_${name}_canvas`, repoStats[name], chart.interpolation, chart.type));
}
}
if (repoStats !== null) {
for (const chart of displayableCharts) {
const name = chart.name.toLowerCase();
charts.push(toChart(`git_${name}_canvas`, repoStats[name], chart.interpolation, chart.type));
}
}

return charts;
return charts;
}

async function main() {
await Promise.all([
mkdir(kJsonDir, { recursive: true }),
mkdir(kCloneDir, { recursive: true }),
mkdir(kReportsDir, { recursive: true })
]);

try {
// eslint-disable-next-line new-cap
const generationDate = Intl.DateTimeFormat("en-GB", {
day: "2-digit", month: "short", year: "numeric", hour: "numeric", minute: "numeric", second: "numeric"
}).format(new Date());

const pkgStats = await (config.npm_packages.length === 0 ? Promise.resolve(null) : fetchPackagesStats());
const repoStats = await (config.git_repositories.length === 0 ? Promise.resolve(null) : fetchRepositoriesStats());
if (pkgStats === null && repoStats === null) {
console.log("No git repositories and no npm packages to fetch in the local configuration!");
process.exit(0);
}

console.log("Start generating template!");
const HTMLTemplateStr = await readFile(join(kViewsDir, "template.html"), "utf8");
const templateGenerator = compile(HTMLTemplateStr);

const templatePayload = {
report_theme: kAvailableThemes.has(config.theme) ? config.theme : "dark",
report_title: config.report_title,
report_logo: config.report_logo,
report_date: generationDate,
npm_stats: pkgStats,
git_stats: repoStats,
charts: config.charts.filter((chart) => chart.display).map(({ name, help = null }) => {
return { name, help };
})
};

const charts = generateChartArray(pkgStats, repoStats);
const HTMLReport = templateGenerator(templatePayload)
.concat(`\n<script>\ndocument.addEventListener("DOMContentLoaded", () => {\n${charts.join("\n")}\n});\n</script>`);

const reportHTMLPath = join(kReportsDir, cleanReportName(config.report_title, ".html"));
await writeFile(reportHTMLPath, HTMLReport);
await new Promise((resolve) => setTimeout(resolve, 100));
console.log("HTML Report writted on disk!");

await generatePDF(reportHTMLPath);
console.log("Report sucessfully generated!");
}
finally {
await new Promise((resolve) => setTimeout(resolve, 100));
await rmdir(kCloneDir, { recursive: true });
process.exit(0);
await Promise.all([
promises.mkdir(kJsonDir, { recursive: true }),
promises.mkdir(kCloneDir, { recursive: true }),
promises.mkdir(kReportsDir, { recursive: true })
]);

try {
// eslint-disable-next-line new-cap
const generationDate = Intl.DateTimeFormat("en-GB", {
day: "2-digit", month: "short", year: "numeric", hour: "numeric", minute: "numeric", second: "numeric"
}).format(new Date());

const pkgStats = await (config.npm_packages.length === 0 ? Promise.resolve(null) : fetchPackagesStats());
const repoStats = await (config.git_repositories.length === 0 ? Promise.resolve(null) : fetchRepositoriesStats());
if (pkgStats === null && repoStats === null) {
console.log("No git repositories and no npm packages to fetch in the local configuration!");
process.exit(0);
}

console.log("Start generating template!");
const HTMLTemplateStr = await promises.readFile(path.join(kViewsDir, "template.html"), "utf8");
const templateGenerator = compile(HTMLTemplateStr);


const templatePayload = {
report_theme: kAvailableThemes.has(config.theme) ? config.theme : "dark",
report_title: config.report_title,
report_logo: config.report_logo,
report_date: generationDate,
npm_stats: pkgStats,
git_stats: repoStats,
charts: config.charts.filter((chart) => chart.display).map(({ name, help = null }) => {
return { name, help };
})
};

const charts = generateChartArray(pkgStats, repoStats);

const HTMLReport = templateGenerator(templatePayload)
.concat(`\n<script>\ndocument.addEventListener("DOMContentLoaded", () => {\n${charts.join("\n")}\n});\n</script>`);

const reportHTMLPath = path.join(kReportsDir, cleanReportName(config.report_title, ".html"));
await promises.writeFile(reportHTMLPath, HTMLReport);
await new Promise((resolve) => setTimeout(resolve, 100));
console.log("HTML Report writted on disk!");

await generatePDF(reportHTMLPath);
console.log("Report sucessfully generated!");
}
finally {
await new Promise((resolve) => setTimeout(resolve, 100));
await promises.rm(kCloneDir, { recursive: true });
process.exit(0);
}
}
main().catch(console.error);

Loading