1 | #!/usr/bin/env node
|
2 |
|
3 | const { execSync } = require('child_process');
|
4 | const program = require('commander');
|
5 | const fs = require('fs');
|
6 | const { resolve } = require('path');
|
7 |
|
8 | function patchJson(path, ...patches) {
|
9 | console.log(`Patching ${path}...`);
|
10 | const json = fs.existsSync(path)
|
11 | ? JSON.parse(
|
12 | fs.readFileSync(path).toString() || '{}',
|
13 | )
|
14 | : {};
|
15 |
|
16 | for (const patch of patches) {
|
17 | patch(json);
|
18 | }
|
19 |
|
20 | fs.writeFileSync(
|
21 | path,
|
22 | JSON.stringify(json, null, 2) + '\n',
|
23 | 'utf-8',
|
24 | );
|
25 | }
|
26 |
|
27 | program
|
28 | .command('init')
|
29 | .option('-l, --lib-only', 'Only install library helpers')
|
30 | .action((cmd) => {
|
31 | const destination = process.cwd();
|
32 | const packageOriginal = JSON.parse(fs.readFileSync(resolve(destination, 'package.json')));
|
33 | const libOnly = cmd.libOnly || packageOriginal.libOnly;
|
34 | const source = resolve(__dirname, '..');
|
35 |
|
36 | if (source === destination) {
|
37 | console.log('Cannot install into itself.');
|
38 | return;
|
39 | }
|
40 |
|
41 | console.log(`Init ${source} -> ${destination}`);
|
42 |
|
43 | function copy(file) {
|
44 | const toFile = file.endsWith('_publish') ? file.slice(0, -8) : file;
|
45 | console.log(`Copying ${toFile}...`);
|
46 | fs.copyFileSync(resolve(source, file), resolve(destination, toFile));
|
47 | }
|
48 |
|
49 | function copyOnce(file) {
|
50 | const toFile = file.endsWith('_publish') ? file.slice(0, -8) : file;
|
51 | if (fs.existsSync(toFile)) return;
|
52 |
|
53 | console.log(`Copying ${toFile}...`);
|
54 | fs.copyFileSync(resolve(source, file), resolve(destination, toFile));
|
55 | }
|
56 |
|
57 | try {
|
58 | fs.mkdirSync(resolve(destination, 'src'));
|
59 | } catch { }
|
60 | try {
|
61 | fs.mkdirSync(resolve(destination, '.vscode'));
|
62 | } catch { }
|
63 |
|
64 | copy('.editorconfig');
|
65 | copy('.eslintignore');
|
66 | copy('.eslintrc.js');
|
67 | copy('.dockerignore');
|
68 | copy('.gitignore_publish');
|
69 | copy('.npmignore_publish');
|
70 | copy('jest.config.js');
|
71 | if (!libOnly) {
|
72 | copy('nodemon.json');
|
73 | copyOnce('.vscode/launch.json');
|
74 | } else {
|
75 | if (fs.existsSync(resolve(destination, 'nodemon.json'))) {
|
76 | fs.unlinkSync(resolve(destination, 'nodemon.json'));
|
77 | }
|
78 | }
|
79 | copy('tsconfig.json');
|
80 |
|
81 | patchJson(resolve(destination, 'package.json'),
|
82 | (package) => {
|
83 | Object.assign(package, {
|
84 | main: './dist/index.js',
|
85 | types: './src/index.ts',
|
86 | });
|
87 | package.scripts = Object.assign(package.scripts || {}, {
|
88 | build: 'rm -rf dist && npx tsc --outDir dist --sourceMap',
|
89 | lint: './node_modules/.bin/eslint src/ --ext .ts,.tsx',
|
90 | postpublish: 'git push',
|
91 | prepublishOnly: 'npm run lint && npm run build && npm version patch',
|
92 | test: './node_modules/.bin/jest --coverage',
|
93 | });
|
94 | package.libOnly = libOnly;
|
95 | if (!libOnly) {
|
96 | package.scripts = Object.assign(package.scripts || {}, {
|
97 | start: 'node -r ts-node/register src/index.ts',
|
98 | watch: 'npx nodemon',
|
99 | });
|
100 | delete package.nodemonConfig;
|
101 | }
|
102 | delete package.jest;
|
103 | },
|
104 | );
|
105 |
|
106 | patchJson(resolve(destination, '.vscode/settings.json'),
|
107 | (json) => {
|
108 | const spelling = Array.from([
|
109 | 'asynciterable',
|
110 | 'camelcase',
|
111 | 'eqeqeq',
|
112 | 'esnext',
|
113 | 'geeebe',
|
114 | 'isnan',
|
115 | 'postpublish',
|
116 | ].reduce(
|
117 | (acc, word) => acc.add(word),
|
118 | new Set(json['cSpell.words'] || []),
|
119 | ));
|
120 | spelling.sort();
|
121 |
|
122 | Object.assign(json, {
|
123 | 'cSpell.words': spelling,
|
124 | 'editor.codeActionsOnSave': {
|
125 | 'source.fixAll': true,
|
126 | 'source.organizeImports': true,
|
127 | },
|
128 | 'editor.formatOnSave': true,
|
129 | 'editor.tabSize': 2,
|
130 | 'eslint.enable': true,
|
131 | 'files.eol': '\n',
|
132 | 'files.exclude': {
|
133 | ...json['files.exclude'],
|
134 | '**/*.js': {
|
135 | when: '$(basename).ts',
|
136 | },
|
137 | '**/*.js.map': true,
|
138 | '**/.DS_Store': true,
|
139 | '**/.git': true,
|
140 | '**/.idea': true,
|
141 | '**/node_modules': true,
|
142 | },
|
143 | 'files.insertFinalNewline': true,
|
144 | 'files.trimTrailingWhitespace': true,
|
145 | 'tslint.enable': false,
|
146 | 'typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces': true,
|
147 | });
|
148 | },
|
149 | );
|
150 |
|
151 | patchJson(resolve(destination, '.vscode/extensions.json'),
|
152 | (json) => {
|
153 | const original = json.recommendations || [];
|
154 | const set = {};
|
155 | original.forEach((rec) => {
|
156 | set[rec] = true;
|
157 | });
|
158 | set['ms-vscode.vscode-typescript-tslint-plugin'] = false;
|
159 | set['steoates.autoimport'] = true;
|
160 | set['editorconfig.editorconfig'] = true;
|
161 | set['christian-kohler.path-intellisense'] = true;
|
162 | set['dbaeumer.vscode-eslint'] = true;
|
163 | set['waderyan.gitblame'] = true;
|
164 | set['codezombiech.gitignore'] = true;
|
165 |
|
166 | const recommendations = [];
|
167 | Object.keys(set).forEach((key) => {
|
168 | if (!set.hasOwnProperty(key) || !set[key]) return;
|
169 | recommendations.push(key);
|
170 | });
|
171 | json.recommendations = recommendations;
|
172 | },
|
173 | );
|
174 |
|
175 | console.log('Installing packages...');
|
176 | const packages = [
|
177 | '@types/jest',
|
178 | '@types/node',
|
179 | '@typescript-eslint/eslint-plugin',
|
180 | '@typescript-eslint/eslint-plugin-tslint',
|
181 | '@typescript-eslint/parser',
|
182 | 'eslint',
|
183 | 'eslint-plugin-prefer-arrow',
|
184 | 'jest',
|
185 | 'typescript',
|
186 | 'ts-node',
|
187 | 'ts-jest',
|
188 | 'tslint',
|
189 | ];
|
190 | if (!libOnly) {
|
191 | packages.push('nodemon');
|
192 | }
|
193 | execSync('npm i -D ' + packages.join(' '));
|
194 |
|
195 | console.log('. Done');
|
196 | });
|
197 |
|
198 | program.parse(process.argv);
|