#!/usr/bin/env node const { execSync } = require('child_process'); const program = require('commander'); const fs = require('fs'); const { resolve } = require('path'); function patchJson(path, ...patches) { console.log(`Patching ${path}...`); const json = fs.existsSync(path) ? JSON.parse( fs.readFileSync(path).toString() || '{}', ) : {}; for (const patch of patches) { patch(json); } fs.writeFileSync( path, JSON.stringify(json, null, 2) + '\n', 'utf-8', ); } program .command('init') .option('-l, --lib-only', 'Only install library helpers') .action((cmd) => { const destination = process.cwd(); const packageOriginal = JSON.parse(fs.readFileSync(resolve(destination, 'package.json'))); const libOnly = cmd.libOnly || packageOriginal.libOnly; const source = resolve(__dirname, '..'); if (source === destination) { console.log('Cannot install into itself.'); return; } console.log(`Init ${source} -> ${destination}`); function copy(file) { const toFile = file.endsWith('_publish') ? file.slice(0, -8) : file; console.log(`Copying ${toFile}...`); fs.copyFileSync(resolve(source, file), resolve(destination, toFile)); } function copyOnce(file) { const toFile = file.endsWith('_publish') ? file.slice(0, -8) : file; if (fs.existsSync(toFile)) return; console.log(`Copying ${toFile}...`); fs.copyFileSync(resolve(source, file), resolve(destination, toFile)); } try { fs.mkdirSync(resolve(destination, 'src')); } catch { } try { fs.mkdirSync(resolve(destination, '.vscode')); } catch { } copy('.editorconfig'); copy('.eslintignore'); copy('.eslintrc.js'); copy('.dockerignore'); copy('.gitignore_publish'); copy('.npmignore_publish'); copy('jest.config.js'); if (!libOnly) { copy('nodemon.json'); copyOnce('.vscode/launch.json'); } else { if (fs.existsSync(resolve(destination, 'nodemon.json'))) { fs.unlinkSync(resolve(destination, 'nodemon.json')); } } copy('tsconfig.json'); patchJson(resolve(destination, 'package.json'), (package) => { Object.assign(package, { main: './dist/index.js', types: './src/index.ts', }); package.scripts = Object.assign(package.scripts || {}, { build: 'rm -rf dist && npx tsc --outDir dist --sourceMap', lint: './node_modules/.bin/eslint src/ --ext .ts,.tsx', postpublish: 'git push', prepublishOnly: 'npm run lint && npm run build && npm version patch', test: './node_modules/.bin/jest --coverage', }); package.libOnly = libOnly; if (!libOnly) { package.scripts = Object.assign(package.scripts || {}, { start: 'node -r ts-node/register src/index.ts', watch: 'npx nodemon', }); delete package.nodemonConfig; } delete package.jest; }, ); patchJson(resolve(destination, '.vscode/settings.json'), (json) => { const spelling = Array.from([ 'asynciterable', 'camelcase', 'eqeqeq', 'esnext', 'geeebe', 'isnan', 'postpublish', ].reduce( (acc, word) => acc.add(word), new Set(json['cSpell.words'] || []), )); spelling.sort(); Object.assign(json, { 'cSpell.words': spelling, 'editor.codeActionsOnSave': { 'source.fixAll': true, 'source.organizeImports': true, }, 'editor.formatOnSave': true, 'editor.tabSize': 2, 'eslint.enable': true, 'files.eol': '\n', 'files.exclude': { ...json['files.exclude'], '**/*.js': { when: '$(basename).ts', }, '**/*.js.map': true, '**/.DS_Store': true, '**/.git': true, '**/.idea': true, '**/node_modules': true, }, 'files.insertFinalNewline': true, 'files.trimTrailingWhitespace': true, 'tslint.enable': false, 'typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces': true, }); }, ); patchJson(resolve(destination, '.vscode/extensions.json'), (json) => { const original = json.recommendations || []; const set = {}; original.forEach((rec) => { set[rec] = true; }); set['ms-vscode.vscode-typescript-tslint-plugin'] = false; set['steoates.autoimport'] = true; set['editorconfig.editorconfig'] = true; set['christian-kohler.path-intellisense'] = true; set['dbaeumer.vscode-eslint'] = true; set['waderyan.gitblame'] = true; set['codezombiech.gitignore'] = true; const recommendations = []; Object.keys(set).forEach((key) => { if (!set.hasOwnProperty(key) || !set[key]) return; recommendations.push(key); }); json.recommendations = recommendations; }, ); console.log('Installing packages...'); const packages = [ '@types/jest', '@types/node', '@typescript-eslint/eslint-plugin', '@typescript-eslint/eslint-plugin-tslint', '@typescript-eslint/parser', 'eslint', 'eslint-plugin-prefer-arrow', 'jest', 'typescript', 'ts-node', 'ts-jest', 'tslint', ]; if (!libOnly) { packages.push('nodemon'); } execSync('npm i -D ' + packages.join(' ')); console.log('. Done'); }); program.parse(process.argv);