Socket
Socket
Sign inDemoInstall

suf-cli

Package Overview
Dependencies
10
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.2 to 0.4.2

dist/cli.js

630

dist/index.js

@@ -1,626 +0,16 @@

#!/usr/bin/env node
'use strict';
var fs = require('fs');
var sufLog = require('suf-log');
var sufNode = require('suf-node');
var path = require('path');
var fetch = require('node-fetch');
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var license = require('./license-66aabde9.js');
require('fs');
require('suf-node');
require('path');
require('node-fetch');
require('suf-log');
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch);
const insertionMarker = {
marker: 'SUF_CLI_DOC_INSERTION_MARKER',
regex: /SUF_CLI_DOC_INSERTION_MARKER/g,
};
const Markers = {
tsDoc: {
regex: /<span id="DOC_GENERATION_MARKER_0"><\/span>[\S\s]*<span id="DOC_GENERATION_MARKER_1"><\/span>/,
marker: '<span id="DOC_GENERATION_MARKER_0"></span>\n__INSERT_GENERATED__\n_Generated with_ **[suf-cli](https://www.npmjs.com/package/suf-cli)**\n<span id="DOC_GENERATION_MARKER_1"></span>',
},
badges: {
regex: /<span id="BADGE_GENERATION_MARKER_0"><\/span>[\S\s]*<span id="BADGE_GENERATION_MARKER_1"><\/span>/,
marker: '<span id="BADGE_GENERATION_MARKER_0"></span>\n__INSERT_GENERATED__\n<span id="BADGE_GENERATION_MARKER_1"></span>',
},
license: {
regex: /<span id="LICENSE_GENERATION_MARKER_0"><\/span>[\S\s]*<span id="LICENSE_GENERATION_MARKER_1"><\/span>/,
marker: '<span id="LICENSE_GENERATION_MARKER_0"></span>\n__INSERT_GENERATED__\n<span id="LICENSE_GENERATION_MARKER_1"></span>',
},
};
function readFileAndAddMarker(file, type) {
let output = insertionMarker.marker;
if (fs.existsSync(file)) {
const inputFile = fs.readFileSync(file).toString();
output = inputFile.replace(Markers[type].regex, insertionMarker.marker);
if (!insertionMarker.regex.test(output)) {
output += `\n${insertionMarker.marker}`;
}
}
return output;
}
function insertGenerated(generatedText, type) {
return Markers[type].marker.replace(/__INSERT_GENERATED__/, generatedText);
}
const colors = {
info: '#f64',
yellow: '#fc2',
blue: '#2af',
red: '#f26',
gray: '#aaa',
error: '#f00',
};
const genMessage = (module) => `Generated ${module} at:`;
const loggers = {
info: {
styles: [colors.info, colors.yellow],
},
intro: {
styles: [colors.red, colors.blue],
},
error: {
styles: [{ color: colors.error, 'font-weight': 'bold' }],
},
help: {
styles: [
{ color: '#72a', background: '#111' },
{ color: colors.red, background: '#222' },
{ color: colors.blue, background: '#222' },
],
},
};
function log(type, ...messages) {
if (type !== 'help') {
sufLog.Log(...messages.map((msg, i) => sufLog.styler(msg, loggers[type].styles[i])));
}
else {
console.log(nodeHelpMessage({
text: ` INFO: All arguments can start with - or --, but i would recommend to just use letters.
a | all: Calls all modules.
b | badges: Calls the badges module.
t | ts | d.ts | docs: Calls the tsDoc module.
l | licence: Calls the license module.
h | help: Displays this Message.`,
splitter: ':',
firstColumnWidth: 25,
secondColumnWidth: 90,
}, {
styles: loggers.help,
rawMessages: [],
}));
}
}
const nodeHelpMessage = (preset, data) => {
if (preset.text) {
const lines = preset.text.split(/\n/g);
preset.text = undefined;
let output = '';
output += nodeHelpMessage(preset, {
...data,
rawMessages: ['\n ', ' '],
});
for (const line of lines) {
output += nodeHelpMessage(preset, {
...data,
rawMessages: '\n'.concat(line).split(preset.splitter),
});
}
output += nodeHelpMessage(preset, {
...data,
rawMessages: ['\n ', ''],
});
return output.replace(/^\n/, '');
}
else {
const messages = [];
for (let i = 0; i < data.rawMessages.length; i++) {
messages.push({ message: data.rawMessages[i] });
}
const lastIndex = messages.length - 1;
/*istanbul ignore else */
if (messages.length > 1) {
const space = preset.firstColumnWidth - messages[0].message.length;
/*istanbul ignore else */
if (space >= 0) {
messages[0].message = messages[0].message
.replace(/^(\n)?/, '$1 ')
.concat(' '.repeat(space));
}
let concatenatedMessages = '';
for (let i = 1; i < messages.length; i++) {
concatenatedMessages += messages[i].message;
}
const endingSpace = preset.secondColumnWidth - (concatenatedMessages.length + (messages.length - 1) * 2);
/*istanbul ignore else */
if (endingSpace >= 0) {
messages[lastIndex].message = messages[lastIndex].message.concat(' '.repeat(endingSpace));
}
}
let output = '';
for (let i = 0; i < messages.length; i++) {
messages[i].message = messages[i].message.replace(/^(\n)?/, '$1 ');
output += sufLog.styler(messages[i].message.concat(' '), data.styles[i]);
}
return output;
}
};
async function Badges(STATE) {
const CONFIG = await STATE.getConfigSection('badges');
if (!CONFIG)
return;
const outPath = CONFIG.out || 'README.md';
const generatedBadges = genBadges(CONFIG);
const input = readFileAndAddMarker(outPath, 'badges');
await fs.promises.writeFile(outPath, input.replace(insertionMarker.regex, insertGenerated(generatedBadges, 'badges')));
log('info', genMessage('Badges'), outPath);
}
function genBadges(CONFIG) {
let out = '';
for (const _badge of CONFIG.badges) {
out += addBadge(_badge, CONFIG);
}
return out.replace(/^ /, '');
}
function addBadge(_badge, CONFIG) {
const badge = parseBadge(_badge);
if (Array.isArray(badge)) {
log('info', `Badge: ${badge} is an invalid badge type.`);
return '';
}
const { type, link, params, split, customBadge, customLink } = badge;
let baseLink = 'https://img.shields.io';
switch (type) {
case 'install':
case 'npmDep':
case 'npmNode':
case 'npmLicense':
baseLink = 'https://badgen.net';
break;
case 'codecov':
baseLink = 'https://codecov.io';
break;
}
if (BADGES[type] || (customBadge && LINKS[link]) || customLink) {
return ` [![${customBadge ? 'Custom' : type}](${customBadge ? '' : baseLink}${customBadge ? customBadge : replacePlaceholders(CONFIG, BADGES[type])}${params ? params : ''})](${customLink ? customLink : replacePlaceholders(CONFIG, LINKS[link])})`;
}
log('info', `Badge: "${split.join(' ')}" is not valid.`);
return '';
}
function parseBadge(badge) {
if (typeof badge === 'string') {
let customLink = '';
if (/ link=.+/.test(badge)) {
customLink = badge.replace(/.*?link=([^ ]*) ?.*/, '$1');
}
let customBadge = '';
if (/badge=.+/.test(badge)) {
customBadge = badge.replace(/badge=([^ ]*) ?.*/, '$1');
}
const split = badge.split(' ');
const type = split[0];
const link = split[1];
const params = split[2];
return { type, customBadge, link, customLink, params, split };
}
if (typeof badge === 'object' && Array.isArray(badge)) {
return {
type: badge[0],
link: badge[1],
params: badge[2] || '',
customBadge: '',
customLink: '',
split: badge,
};
}
return [badge];
}
function replacePlaceholders(CONFIG, text) {
text = text.replace(/<NAME>/g, CONFIG.name);
text = text.replace(/<GITHUB>/g, CONFIG.github);
text = text.replace(/<VSCODE>/g, CONFIG.vscode || '');
text = text.replace(/<REPO>/g, CONFIG.repo);
return text;
}
const BADGES = {
circleci: '/circleci/build/github/<GITHUB>/<REPO>',
codecov: '/gh/<GITHUB>/<REPO>/branch/master/graph/badge.svg',
vscV: '/visual-studio-marketplace/v/<VSCODE>',
vscD: '/visual-studio-marketplace/d/<VSCODE>',
vscI: '/visual-studio-marketplace/i/<VSCODE>',
vscR: '/visual-studio-marketplace/r/<VSCODE>',
min: '/bundlephobia/min/<NAME>',
minzip: '/bundlephobia/minzip/<NAME>',
install: '/packagephobia/install/<NAME>',
publish: '/packagephobia/publish/<NAME>',
npmV: '/npm/v/<NAME>',
npmDM: '/npm/dm/<NAME>',
npmDT: '/npm/dt/<NAME>',
npmDW: '/npm/dw/<NAME>',
npmDY: '/npm/dy/<NAME>',
npmDep: '/npm/dependents/<NAME>',
npmLicense: '/npm/license/<NAME>',
npmNode: '/npm/node/<NAME>',
npmTypes: '/npm/types/<NAME>',
githubFollowers: '/github/followers/<GITHUB>',
githubForks: '/github/forks/<GITHUB>/<REPO>',
githubStars: '/github/stars/<GITHUB>/<REPO>',
githubIssues: '/github/issues/<GITHUB>/<REPO>',
githubLastCommit: '/github/last-commit/<GITHUB>/<REPO>',
// badge: '<CUSTOM>',
};
// https://app.circleci.com/pipelines/github/TheRealSyler/sass-formatter
const LINKS = {
npm: 'https://www.npmjs.com/package/<NAME>',
github: 'https://github.com/<GITHUB>/<REPO>',
circleci: 'https://app.circleci.com/pipelines/github/<GITHUB>/<REPO>',
vscode: 'https://marketplace.visualstudio.com/items?itemName=<VSCODE>',
bundle: 'https://bundlephobia.com/result?p=<NAME>',
package: 'https://packagephobia.now.sh/result?p=<NAME>',
codecov: 'https://codecov.io/gh/<GITHUB>/<REPO>',
// link: '<CUSTOM>',
};
const codeBlock = '```';
async function TsDoc(STATE) {
const section = await STATE.getConfigSection('tsDoc');
if (section === undefined)
return;
const CONFIG = addDefaultsToConfig(section);
const filesPaths = await getPaths(CONFIG);
const input = readFileAndAddMarker(CONFIG.out, 'tsDoc');
const declarationBlockRegex = /(\/\*\*?[\S\s]*?\*\/\n)?export[ \t]*(declare|interface)[ \t]*([\w-]*)[ \t]*([\w-]*)(.*?;|[\S\s]*?^})/gm;
let output = '';
const navLinks = [];
for (const path of filesPaths) {
const fileText = fs.readFileSync(path).toString();
const fileName = path.replace(/.*(\/|\\\\|\\)([\w\.-]*)\.d\.ts/, '$2');
let match;
navLinks.push(`#${fileName}`);
let fileOutput = `\n### ${fileName}\n`;
while ((match = declarationBlockRegex.exec(fileText)) !== null) {
/* istanbul ignore if */
if (match.index === declarationBlockRegex.lastIndex) {
declarationBlockRegex.lastIndex++;
}
let [all, comment, declaration, type, name, content] = match;
const isInternalDeclaration = /^internal/i.test(convertComment(comment));
if (!isInternalDeclaration) {
navLinks.push(declaration === 'interface' ? type : name);
fileOutput += `\n##### ${declaration === 'interface' ? type : name}\n
${codeBlock}ts
${all.replace(/export ?| ?declare ?/g, '').replace(/\n^[ \t]*private .*$/gm, '')}
${codeBlock}
`;
}
}
output += fileOutput;
}
const title = CONFIG.title ? `\n# ${CONFIG.title}\n` : '';
await fs.promises.writeFile(CONFIG.out, input.replace(insertionMarker.regex, insertGenerated(`${title}${createNav(navLinks)}${output}`, 'tsDoc')));
log('info', genMessage('TsDoc'), CONFIG.out);
}
function addDefaultsToConfig(config) {
return {
...config,
dir: /* istanbul ignore next */ config?.dir || '',
out: /* istanbul ignore next */ config?.out || 'README.md',
};
}
async function getPaths(CONFIG) {
const dir = await sufNode.Walk(path.resolve('./', CONFIG.dir));
if (CONFIG.exclude !== undefined && CONFIG.include !== undefined) {
log('error', '[suf-cli:tsDoc] Cannot use option "include" and "exclude" at the same time, all d.ts files will be used.');
return dir.filter((fileName) => fileName.endsWith('d.ts'));
}
const isInclude = CONFIG.include !== undefined ? CONFIG.include.length === 0 : true;
const type = isInclude ? 'exclude' : 'include';
const checkArr = CONFIG[type] || [];
const includeCheck = (a, b) => a === b;
const excludeCheck = (a, b) => a !== b;
const check = isInclude ? includeCheck : excludeCheck;
const filename = (name) => path.basename(name).replace(/\.d\.ts$/, '');
const filesPaths = dir.filter((fileName) => fileName.endsWith('d.ts') && check(checkArr.indexOf(filename(fileName)), -1));
return filesPaths;
}
function createNav(links) {
let output = '';
for (const link of links) {
if (link.startsWith('#')) {
output += `\n- **[${link.replace(/#/, '')}](${link.toLowerCase()})**\n\n`;
}
else {
output += ` - [${link}](#${link.toLowerCase()})\n`;
}
}
return output;
}
function convertComment(comment) {
return comment ? comment.replace(/(\/?\*\*?\/?|[\t \n]*)/g, '') : '';
}
async function getPackageJson() {
const hasPackage = await sufNode.Exits('./package.json');
if (!hasPackage) {
log('info', 'No package.json found!');
process.exit(1);
}
return JSON.parse((await fs.promises.readFile('./package.json')).toString());
}
function getArgs() {
const [, , ...args] = process.argv;
let ARGS = [];
args.forEach((arg, i) => {
ARGS[i] = arg.toLowerCase();
});
return ARGS;
}
const configPath = (extension) => `./suf.config.${extension}`;
async function checkConfigExists() {
/*istanbul ignore else */
if (await sufNode.Exits(configPath('json')))
return 'json';
/*istanbul ignore else */
if (await sufNode.Exits(configPath('ts')))
return 'ts';
return null;
}
async function getConfig(Package) {
const extension = await checkConfigExists();
if (!extension) {
log('info', 'No config Found, do you want to create one? ', '[Y/n]');
const answer = await sufNode.getYNAnswer();
if (answer) {
const newConfig = await createOrUpdateConfig(Package);
if (!newConfig) {
process.exit(0);
}
return { config: newConfig, configPath: configPath('json') };
}
process.exit(1);
}
else {
switch (extension) {
case 'json':
return {
config: JSON.parse((await fs.promises.readFile(configPath('json'))).toString()),
configPath: configPath('json'),
};
case 'ts':
try {
const transpileModule = (await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('typescript')); })).transpileModule;
const text = (await fs.promises.readFile(configPath('ts'))).toString();
const funcText = transpileModule(text, {}).outputText.replace(`Object.defineProperty(exports, "__esModule", { value: true });`, "const exports = {default: {}}") + "\nreturn exports.default";
const config = Function(funcText)();
if (!config) {
log('error', `${configPath('ts')} export is invalid.`);
process.exit(1);
}
return { config: config || {}, configPath: configPath('ts') };
}
catch (e) {
console.log(e);
log('error', 'Please install typescript or use a .json config file!');
process.exit(1);
}
}
}
}
async function createOrUpdateConfig(packageJson, type, STATE) {
const path = STATE?.configPath || configPath('json');
if (!path.endsWith('.json'))
return undefined;
let config;
let updateOrCreate = 'Update';
if (type && STATE) {
log('info', `Adding ${type} to Config.`);
config = { ...STATE.CONFIG, [type]: await configFuncs[type](packageJson) };
}
else {
/**this will only be executed when there is no config. */
config = {};
updateOrCreate = 'Create';
for (const key in configFuncs) {
if (configFuncs.hasOwnProperty(key)) {
const configFunc = configFuncs[key];
log('info', `Add ${key} to Config?`, '[Y/n]');
if (await sufNode.getYNAnswer()) {
config = { ...config, [key]: await configFunc(packageJson) };
}
}
}
}
console.log(`${sufLog.styler(`${updateOrCreate} Config`, colors.blue)}: ${path}`);
fs.promises.writeFile(path, JSON.stringify(config, null, 2));
return config;
}
const configFuncs = {
badges: async (Package) => {
return {
name: await getInp('Name', 'PACKAGE NAME', Package.name || ''),
github: await getInp('Github', 'Username'),
repo: await getInp('Github', 'Repo', Package.name || ''),
out: await getInp('out', 'OUTPUT PATH', 'README.md'),
badges: [...(await getBadges())],
};
},
tsDoc: async () => {
return {
title: await getInp('title', 'TITLE', 'Docs'),
dir: await getInp('dir', 'INPUT PATH', 'dist'),
out: await getInp('out', 'OUTPUT PATH', 'README.md'),
};
},
license: async () => {
return {
name: await getInp('name', 'FULL NAME(S)'),
type: await getLicenseType(),
year: await getInp('year', 'YEAR', new Date().getFullYear().toString()),
out: await getInp('out', 'OUTPUT PATH', 'README.md'),
file: await getInp('file', 'LICENSE FILE PATH', 'LICENSE'),
};
},
};
async function getLicenseType() {
process.stdout.write(sufLog.styler('Getting Licenses from api...\n', colors.gray));
const licenses = await (await fetch__default["default"]('https://api.github.com/licenses')).json();
process.stdout.write(sufLog.styler('Choose From: ' +
JSON.stringify(licenses.map((l) => l.key), null, 2).replace(/[\[\]",]/g, ''), colors.gray));
return await getInp('type', 'LICENSE', 'mit');
}
async function getInp(type, type2, _default) {
process.stdout.write(sufLog.styler(type, colors.blue));
process.stdout.write(sufLog.styler(` ${type2}`, colors.yellow));
process.stdout.write(sufLog.styler(': ', colors.gray));
if (_default) {
process.stdout.write(sufLog.styler(`(${_default})`, colors.gray));
const input = await sufNode.readConsole();
if (input.length === 0) {
return _default;
}
return input;
}
return sufNode.readConsole();
}
async function getBadges(out) {
if (!out) {
out = [];
process.stdout.write(sufLog.styler('Press Enter to Accept. ', colors.info));
process.stdout.write(sufLog.styler('Format: ', colors.gray));
process.stdout.write(sufLog.styler('BADGE ', colors.blue));
process.stdout.write(sufLog.styler('LINK ', colors.yellow));
process.stdout.write(sufLog.styler('Parameters?\n', colors.gray));
}
process.stdout.write(sufLog.styler('Add', colors.blue));
process.stdout.write(sufLog.styler(' Badge', colors.yellow));
process.stdout.write(sufLog.styler(': ', colors.gray));
const input = await sufNode.readConsole();
if (/^e$|^end$|^$/i.test(input)) {
if (input) {
out.push(input);
}
return out;
}
else {
if (input) {
out.push(input);
}
return await getBadges(out);
}
}
class State {
PACKAGE;
CONFIG;
configPath;
canCreateOrUpdateConfig;
constructor(PACKAGE, CONFIG, configPath, canCreateOrUpdateConfig = false) {
this.PACKAGE = PACKAGE;
this.CONFIG = CONFIG;
this.configPath = configPath;
this.canCreateOrUpdateConfig = canCreateOrUpdateConfig;
}
async getConfigSection(type) {
if (this.CONFIG[type] !== undefined) {
return this.CONFIG[type];
}
else if (this.canCreateOrUpdateConfig) {
const config = await createOrUpdateConfig(this.PACKAGE, type, this);
if (config && config[type]) {
return config[type];
}
}
}
}
async function License(STATE) {
const CONFIG = await STATE.getConfigSection('license');
if (!CONFIG)
return;
const license = await (await fetch__default["default"](`https://api.github.com/licenses/${CONFIG.type}`)).json();
const OUT = CONFIG.out || 'README.md';
const FILE = CONFIG.file || 'LICENSE';
const YEAR = CONFIG.year ? CONFIG.year : new Date().getFullYear();
const input = readFileAndAddMarker(OUT, 'license');
const readmeText = `Copyright (c) YEAR NAME Licensed under the TYPE license.`
.replace(/NAME/, CONFIG.name)
.replace(/YEAR/, YEAR.toString())
.replace(/TYPE/, license.spdx_id);
await fs.promises.writeFile(OUT, input.replace(insertionMarker.regex, insertGenerated(readmeText, 'license')));
log('info', genMessage('License'), OUT);
await fs.promises.writeFile(FILE, license.body.replace(/\[year\]/, YEAR).replace(/\[fullname\]/, CONFIG.name));
log('info', genMessage('License'), FILE);
}
const logIntro = (module) => log('intro', 'SUF Cli', `(${module})`);
async function run() {
const ARGS = getArgs();
const Package = await getPackageJson();
const { config, configPath } = await getConfig(Package);
const STATE = new State(Package, config, configPath);
const ARG0 = ARGS[0] && ARGS[0].replace(/^--?/, '').toLowerCase();
switch (ARG0) {
case 'a':
case 'all':
logIntro('All Modules');
await CallAll(STATE);
break;
case 'b':
case 'badges':
logIntro('Badges Module');
STATE.canCreateOrUpdateConfig = true;
await Badges(STATE);
break;
case 't':
case 'ts':
case 'd.ts':
case 'docs':
logIntro('TsDoc Module');
STATE.canCreateOrUpdateConfig = true;
await TsDoc(STATE);
break;
case 'l':
case 'license':
logIntro('License Module');
STATE.canCreateOrUpdateConfig = true;
await License(STATE);
break;
case 'h':
case 'help':
logIntro('Help');
log('help');
break;
default:
logIntro('default, All Modules');
await CallAll(STATE);
break;
}
}
async function CallAll(STATE) {
await Badges(STATE);
await TsDoc(STATE);
await License(STATE);
}
run();
exports.Badges = license.Badges;
exports.License = license.License;
exports.TsDoc = license.TsDoc;
{
"name": "suf-cli",
"version": "0.3.2",
"version": "0.4.2",
"description": "Utility Cli",
"scripts": {
"prepack": "yarn build && node ./dist/index.js",
"build": "del-cli ./dist && rollup --config rollup.config.ts --configPlugin typescript",
"prepack": "yarn build && yarn test && node ./dist/index.js",
"build": "del-cli ./dist && rollup --config rollup.config.ts --configPlugin swc3",
"watch": "tsc -w",

@@ -16,4 +16,5 @@ "test": "jest --coverage",

"bin": {
"suf": "./dist/index.js"
"suf": "./dist/cli.js"
},
"main": "./dist/index.js",
"files": [

@@ -30,8 +31,6 @@ "dist/src",

"suf-log": "^2.5.3",
"suf-node": "^1.3.3",
"tslib": "^2.4.0",
"typescript": "^4.6.4"
"suf-node": "^1.3.3"
},
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.2",
"@swc/core": "^1.3.20",
"@types/jest": "^27.5.0",

@@ -48,5 +47,9 @@ "@types/node": "^17.0.31",

"rollup": "^2.72.1",
"rollup-plugin-dts": "^5.0.0",
"rollup-plugin-hashbang": "^3.0.0",
"ts-jest": "^28.0.2"
"rollup-plugin-swc3": "^0.7.0",
"ts-jest": "^28.0.2",
"tslib": "^2.4.0",
"typescript": "^4.9.3"
}
}
SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc