standard-pkg
Version:
<p align="center"> <img alt="Logo" src="https://i.imgur.com/MsQMjew.png" width="420"> </p>
190 lines (185 loc) • 6.8 kB
JavaScript
import * as fs from './util/fs.js';
import validateFile from './util/babel-validate-file.js';
import * as path from 'path';
import chalk from 'chalk';
import minimist from 'minimist';
import nodeFs from 'fs';
import mkdirp from 'mkdirp';
import babel from '@babel/core';
import babelPluginDynamicImportSyntax from '@babel/plugin-syntax-dynamic-import';
import babelPluginNullishCoalescingOperator from '@babel/plugin-syntax-nullish-coalescing-operator';
import babelPluginOptionalChaining from '@babel/plugin-syntax-optional-chaining';
import babelPluginBigint from '@babel/plugin-syntax-bigint';
import babelPluginImportMetaSyntax from '@babel/plugin-syntax-import-meta';
import babelPresetTypeScript from '@babel/preset-typescript';
import babelPluginImportRewrite from '@pika/babel-plugin-esm-import-rewrite';
/*
$ standard-pkg [--src src/] [--dist dist-src/]
- builds `src/` -> `dist-src/`
- writes `src/` -> `dist-src/`
- lints `dist-src/`
$ standard-pkg [--src src/]
- builds `src/` -> `dist-src/`
- lints `dist-src/`
- (does not write to disk)
$ standard-pkg [--dist dist-src/]
$ standard-pkg lint dist-src/
- lints `dist-src/`
*/
// const argv = yargs.command({
// command: 'build',
// describe: 'describe',
// builder: (yargs) => yargs.option('src', {
// default: 'src/',
// describe: 'x marks the spot',
// type: 'string'
// }).option('dist', {
// default: 'dist/',
// describe: 'x marks the spot',
// type: 'string'
// }),
// handler: (argv) => undefined,
// }).command({
// command: 'lint [dist]',
// aliases: ['$0'],
// describe: 'describe',
// builder: (yargs) => yargs.option('src', {
// default: 'src/',
// describe: 'x marks the spot',
// type: 'string'
// }),
// handler: (argv) => undefined
// }).help();
// console.log(argv);
function log(fileName, errors) {
console.log(chalk.bold(fileName));
for (const error of errors) {
console.log(' ', error.level === 2 ? '⚠️ ' : ' ', error.msg);
}
}
export class Lint {
constructor(dist, { ignoreExtensions } = {}) {
this.dist = dist;
this.errors = new Map();
this.totalNum = 0;
this.ignoreExtensions = ignoreExtensions || false;
}
addError(filename, msg, level = 2) {
const errors = this.errors.get(filename) || [];
errors.push({ msg, level });
this.errors.set(filename, errors);
}
async init() {
const { dist } = this;
const dir = path.join(dist, '..');
const files = await fs.glob(`**/*`, {
cwd: dist,
absolute: true,
nodir: true,
});
for (const fileLoc of files) {
const relativePath = path.relative(path.join(dist, '..'), fileLoc);
const extName = path.extname(fileLoc);
if (extName === '.map') {
continue;
}
if (fileLoc.includes('README')) {
continue;
}
if (extName !== '.js') {
this.addError(relativePath, 'Only JavaScript files are expected in your dist-src/ distribution.');
this.totalNum++;
continue;
}
const fileContents = await fs.readFile(fileLoc);
const validateErrors = validateFile(fileContents, fileLoc, dir, dist, this.ignoreExtensions);
for (const errMsg of validateErrors) {
this.addError(relativePath, errMsg);
}
this.totalNum += validateErrors.size;
}
}
summary() {
if (this.totalNum === 0) {
return;
}
console.log(``);
for (const [filename, errors] of this.errors.entries()) {
log(filename, errors);
}
console.log(``);
console.log(chalk.red('✘'), `${this.totalNum} issues found.`);
}
exitCode() {
return this.totalNum === 0 ? 0 : 1;
}
}
export class Build {
constructor(dir, options = {}) {
this.dir = dir;
this.options = options;
this.result = new Map();
}
async init() {
const { dir, options } = this;
const files = (await fs.glob(`**/*`, {
cwd: dir,
nodir: true,
absolute: false,
ignore: options.exclude || [],
})).filter(filepath => !filepath.endsWith('.d.ts') && !filepath.includes('README'));
for (const sourcePath of files) {
const sourcePathAbs = path.join(dir, sourcePath);
const transformedPath = sourcePath
// .replace(path.join(dir, 'src/'), path.join(out, 'dist-src/'))
.replace('.ts', '.js')
.replace('.tsx', '.js')
.replace('.jsx', '.js')
.replace('.mjs', '.js');
const resultSrc = await babel.transformFileAsync(sourcePathAbs, {
presets: [[babelPresetTypeScript]],
plugins: [
[babelPluginImportRewrite, { addExtensions: true }],
babelPluginDynamicImportSyntax,
babelPluginImportMetaSyntax,
babelPluginNullishCoalescingOperator,
babelPluginOptionalChaining,
babelPluginBigint,
],
});
this.result.set(transformedPath, resultSrc.code);
}
return this.result;
}
async write(out, result = this.result) {
for (const [filepath, contents] of result.entries()) {
const transformedPathAbs = path.join(out, filepath);
mkdirp.sync(path.dirname(transformedPathAbs));
nodeFs.writeFileSync(transformedPathAbs, contents);
}
}
}
// export async function runBuild(args: Arguments): Promise<void> {
// }
export async function run(argv) {
var args = minimist(argv.slice(2));
const srcDir = path.resolve(process.cwd(), typeof args.src === 'string' ? args.src : 'src');
const distDir = path.resolve(process.cwd(), typeof args.dist === 'string' ? args.dist : 'lib');
if (args.src) {
console.log(chalk.bold.dim(`»`), chalk(`Building ${path.relative(process.cwd(), srcDir)}${path.sep} → ${path.relative(process.cwd(), distDir)}${path.sep}...`));
const builder = new Build(srcDir);
await builder.init();
await builder.write(distDir);
}
console.log(chalk.bold.dim(`»`), chalk(`Linting ${path.relative(process.cwd(), distDir)}${path.sep}...`));
const linter = new Lint(distDir);
await linter.init();
if (linter.totalNum === 0) {
// console.log(``);
console.log(chalk.bold.green(`✓`), '0 issues found.');
}
else {
linter.summary();
}
process.exit(linter.exitCode());
}