create-tampermonkey-typescript 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +285 -0
- package/package.json +1 -1
package/dist/cli.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import prompts from 'prompts';
|
|
5
|
+
import kleur from 'kleur';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
const __FILENAME = fileURLToPath(import.meta.url);
|
|
9
|
+
const __DIRNAME = path.dirname(__FILENAME);
|
|
10
|
+
const TEMPLATES_DIR = path.join(__DIRNAME, '../templates');
|
|
11
|
+
const defaultDevDeps = [
|
|
12
|
+
'typescript', //
|
|
13
|
+
'vite',
|
|
14
|
+
'vite-plugin-banner',
|
|
15
|
+
'vite-plugin-css-injected-by-js',
|
|
16
|
+
'ts-node',
|
|
17
|
+
'@types/tampermonkey',
|
|
18
|
+
];
|
|
19
|
+
const defaultDeps = [];
|
|
20
|
+
const baseTsConfig = {
|
|
21
|
+
compilerOptions: {
|
|
22
|
+
types: ['vite/client', 'node'],
|
|
23
|
+
target: 'ES2022',
|
|
24
|
+
module: 'ESNext',
|
|
25
|
+
moduleResolution: 'NodeNext',
|
|
26
|
+
strict: true,
|
|
27
|
+
esModuleInterop: true,
|
|
28
|
+
forceConsistentCasingInFileNames: true,
|
|
29
|
+
skipLibCheck: true,
|
|
30
|
+
resolveJsonModule: true,
|
|
31
|
+
outDir: 'dist',
|
|
32
|
+
baseUrl: '.',
|
|
33
|
+
paths: {
|
|
34
|
+
'@/*': ['src/*'],
|
|
35
|
+
},
|
|
36
|
+
lib: ['ES2022', 'dom', 'dom.iterable'],
|
|
37
|
+
},
|
|
38
|
+
include: ['src'],
|
|
39
|
+
};
|
|
40
|
+
const availableFeatures = [
|
|
41
|
+
{
|
|
42
|
+
name: 'React',
|
|
43
|
+
description: 'Adds react support to the project',
|
|
44
|
+
directory: path.join(TEMPLATES_DIR, 'react'),
|
|
45
|
+
tsConfigModifier: (config) => (config.compilerOptions.jsx = 'react-jsx'),
|
|
46
|
+
devDependencies: ['react', 'react-dom', '@types/react', '@types/react-dom'],
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Git',
|
|
50
|
+
description: 'Initializes the new project as a git repository',
|
|
51
|
+
directory: path.join(TEMPLATES_DIR, 'git'),
|
|
52
|
+
hook: (params) => {
|
|
53
|
+
fs.renameSync(path.join(params.projectPath, '_gitignore'), path.join(params.projectPath, '.gitignore'));
|
|
54
|
+
execInProjectDir(`git init && git add . && git commit -m "Initial commit"`, params);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'Github Workflows',
|
|
59
|
+
description: 'Includes 2 workflows; one for tagging releases with current version, and another for building & creating a release',
|
|
60
|
+
directory: path.join(TEMPLATES_DIR, 'github-workflows'),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
const availablePackageManagers = [
|
|
64
|
+
{
|
|
65
|
+
name: 'npm',
|
|
66
|
+
exists: () => commandExists('npm --version'),
|
|
67
|
+
installCmd: 'npm install',
|
|
68
|
+
addDependencyCmd: 'npm install',
|
|
69
|
+
runCmd: 'npm run',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'yarn',
|
|
73
|
+
exists: () => commandExists('yarn --version'),
|
|
74
|
+
installCmd: 'yarn install',
|
|
75
|
+
addDependencyCmd: 'yarn add',
|
|
76
|
+
runCmd: 'yarn run',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'pnpm',
|
|
80
|
+
exists: () => commandExists('pnpm --version'),
|
|
81
|
+
installCmd: 'pnpm install',
|
|
82
|
+
addDependencyCmd: 'pnpm add',
|
|
83
|
+
runCmd: 'pnpm run',
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
async function main() {
|
|
87
|
+
console.log(kleur.green('create-tampermonkey-typescript'));
|
|
88
|
+
if (!checkCwdAccess())
|
|
89
|
+
return;
|
|
90
|
+
if (!findValidPackageManager())
|
|
91
|
+
return;
|
|
92
|
+
// Prompt for project parameters
|
|
93
|
+
const promptResults = await promptForParams();
|
|
94
|
+
const params = {
|
|
95
|
+
...promptResults,
|
|
96
|
+
projectPath: path.join(process.cwd(), promptResults.projectName),
|
|
97
|
+
features: promptResults.featureNames.map((featureName) => availableFeatures.find((a) => a.name === featureName)),
|
|
98
|
+
packageManager: availablePackageManagers.find((pm) => pm.name === promptResults.packageManagerName),
|
|
99
|
+
};
|
|
100
|
+
// Create the directory
|
|
101
|
+
logWithPrefix(`Creating directory ${kleur.yellow(params.projectPath)}`);
|
|
102
|
+
const createDirResult = await createProjectDirectory(params.projectPath);
|
|
103
|
+
if (typeof createDirResult === 'string') {
|
|
104
|
+
console.log(kleur.red('An occurred while attempting to create the project directory:'));
|
|
105
|
+
console.log(kleur.red(createDirResult));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Initialize package.json
|
|
109
|
+
logWithPrefix(`Creating ${kleur.yellow('package.json')}`);
|
|
110
|
+
const packageJson = createPackageJson(params);
|
|
111
|
+
writeObjectToFile(packageJson, 'package.json', params);
|
|
112
|
+
// Initialize the lock file
|
|
113
|
+
logWithPrefix(`Initializing lock file`);
|
|
114
|
+
execInProjectDir(`${params.packageManager.installCmd}`, params);
|
|
115
|
+
// Gather dependencies
|
|
116
|
+
const devDeps = [...defaultDevDeps, ...params.features.flatMap((f) => f.devDependencies ?? [])];
|
|
117
|
+
const deps = [...defaultDeps, ...params.features.flatMap((f) => f.dependencies ?? [])];
|
|
118
|
+
// Install dev dependencies
|
|
119
|
+
if (devDeps.length > 0) {
|
|
120
|
+
logWithPrefix('Installing dev dependencies');
|
|
121
|
+
console.log(` ${kleur.dim(devDeps.join(', '))}`);
|
|
122
|
+
execInProjectDir(`${params.packageManager.addDependencyCmd} -D ${devDeps.join(' ')}`, params);
|
|
123
|
+
}
|
|
124
|
+
// Install dependencies
|
|
125
|
+
if (deps.length > 0) {
|
|
126
|
+
logWithPrefix('Installing dependencies');
|
|
127
|
+
console.log(` ${kleur.dim(deps.join(', '))}`);
|
|
128
|
+
execInProjectDir(`${params.packageManager.addDependencyCmd} ${deps.join(' ')}`, params);
|
|
129
|
+
}
|
|
130
|
+
// Handle tsconfig.json
|
|
131
|
+
const tsConfig = { ...baseTsConfig };
|
|
132
|
+
for (const feature of params.features) {
|
|
133
|
+
if (feature.tsConfigModifier) {
|
|
134
|
+
feature.tsConfigModifier(tsConfig);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
logWithPrefix(`Creating ${kleur.yellow('tsconfig.json')}`);
|
|
138
|
+
writeObjectToFile(tsConfig, 'tsconfig.json', params);
|
|
139
|
+
// Copy files
|
|
140
|
+
logWithPrefix('Copying project files');
|
|
141
|
+
// Base files
|
|
142
|
+
fs.cpSync(path.join(TEMPLATES_DIR, 'base'), params.projectPath, { recursive: true, force: true });
|
|
143
|
+
// README.md replacements
|
|
144
|
+
const readmePath = path.join(params.projectPath, 'README.md');
|
|
145
|
+
let content = fs.readFileSync(readmePath, 'utf-8');
|
|
146
|
+
content = content.replaceAll('{{PROJECT_NAME}}', params.projectName);
|
|
147
|
+
content = content.replaceAll('{{PROJECT_PATH}}', params.projectPath);
|
|
148
|
+
content = content.replaceAll('{{PM_ADD_DEPENDENCY}}', params.packageManager.addDependencyCmd);
|
|
149
|
+
content = content.replaceAll('{{PM_RUN_SCRIPT}}', params.packageManager.runCmd);
|
|
150
|
+
fs.writeFileSync(readmePath, content);
|
|
151
|
+
// Feature files
|
|
152
|
+
params.features
|
|
153
|
+
.filter((f) => f.directory)
|
|
154
|
+
.forEach((f) => fs.cpSync(f.directory, params.projectPath, { recursive: true, force: true }));
|
|
155
|
+
// Handle feature hooks
|
|
156
|
+
params.features
|
|
157
|
+
.filter((f) => f.hook)
|
|
158
|
+
.forEach((f) => {
|
|
159
|
+
logWithPrefix(`Running feature hook: ${kleur.yellow(f.name)}`);
|
|
160
|
+
f.hook(params);
|
|
161
|
+
});
|
|
162
|
+
console.log(`${kleur.green('Done!')} Project created at ${kleur.yellow(params.projectPath)}`);
|
|
163
|
+
}
|
|
164
|
+
function logWithPrefix(message) {
|
|
165
|
+
console.log(`${kleur.cyan('-')} ${kleur.white(message)}`);
|
|
166
|
+
}
|
|
167
|
+
function commandExists(cmd) {
|
|
168
|
+
try {
|
|
169
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function checkCwdAccess() {
|
|
177
|
+
try {
|
|
178
|
+
fs.accessSync(process.cwd(), fs.constants.W_OK | fs.constants.R_OK);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
console.log(kleur.red('Read & write access to current working directory is required.'));
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
function findValidPackageManager() {
|
|
187
|
+
if (!availablePackageManagers.find((pm) => pm.exists())) {
|
|
188
|
+
console.log(kleur.red('Could not find any valid package manager: '));
|
|
189
|
+
console.log(kleur.yellow(`(${availablePackageManagers.map((pm) => pm.name).join(', ')})`));
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
function validateProjectName(projectName) {
|
|
195
|
+
if (!projectName || projectName.length === 0)
|
|
196
|
+
return 'Project name cannot be empty';
|
|
197
|
+
if (projectName.includes(' '))
|
|
198
|
+
return 'Project name cannot contain spaces';
|
|
199
|
+
const projectPath = path.join(process.cwd(), projectName);
|
|
200
|
+
try {
|
|
201
|
+
const stats = fs.statSync(projectPath);
|
|
202
|
+
if (!stats.isDirectory()) {
|
|
203
|
+
return `Path ${projectPath} already exists and is not a directory.`;
|
|
204
|
+
}
|
|
205
|
+
const files = fs.readdirSync(projectPath);
|
|
206
|
+
if (files.length > 0)
|
|
207
|
+
return `Directory ${projectPath} already exists and is not empty.`;
|
|
208
|
+
}
|
|
209
|
+
catch { }
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
async function promptForParams() {
|
|
213
|
+
return await prompts([
|
|
214
|
+
{
|
|
215
|
+
type: 'text',
|
|
216
|
+
name: 'projectName',
|
|
217
|
+
message: 'Project name:',
|
|
218
|
+
format: (s) => s.trim(),
|
|
219
|
+
validate: (s) => validateProjectName(s.trim()),
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
type: 'text',
|
|
223
|
+
name: 'version',
|
|
224
|
+
message: 'Version:',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
type: 'text',
|
|
228
|
+
name: 'description',
|
|
229
|
+
message: 'Description:',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
type: 'text',
|
|
233
|
+
name: 'author',
|
|
234
|
+
message: 'Author:',
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
type: 'select',
|
|
238
|
+
name: 'packageManagerName',
|
|
239
|
+
message: 'Package manager:',
|
|
240
|
+
choices: availablePackageManagers.filter((pm) => pm.exists()).map((pm) => ({ title: pm.name, value: pm.name })),
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
type: 'multiselect',
|
|
244
|
+
name: 'featureNames',
|
|
245
|
+
message: 'Select features:',
|
|
246
|
+
choices: availableFeatures.map((f) => ({ title: f.name, value: f.name, description: f.description })),
|
|
247
|
+
},
|
|
248
|
+
], {
|
|
249
|
+
onCancel: () => process.exit(0),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
async function createProjectDirectory(path) {
|
|
253
|
+
try {
|
|
254
|
+
fs.mkdirSync(path, { recursive: true });
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
if (error instanceof Error) {
|
|
259
|
+
return error.message;
|
|
260
|
+
}
|
|
261
|
+
return 'Unknown error.';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
function createPackageJson(params) {
|
|
265
|
+
return {
|
|
266
|
+
name: params.projectName,
|
|
267
|
+
description: params.description,
|
|
268
|
+
version: params.version,
|
|
269
|
+
author: params.author,
|
|
270
|
+
main: 'dist/script.user.js',
|
|
271
|
+
type: 'module',
|
|
272
|
+
scripts: {
|
|
273
|
+
build: 'vite build',
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function writeObjectToFile(object, fileName, params) {
|
|
278
|
+
const filePath = path.join(params.projectPath, fileName);
|
|
279
|
+
const jsonString = JSON.stringify(object, null, 2);
|
|
280
|
+
fs.writeFileSync(filePath, jsonString);
|
|
281
|
+
}
|
|
282
|
+
function execInProjectDir(command, params) {
|
|
283
|
+
execSync(command, { stdio: 'inherit', cwd: params.projectPath });
|
|
284
|
+
}
|
|
285
|
+
main().then(() => { }, (e) => console.error(kleur.red(e.message || e)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-tampermonkey-typescript",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "CLI tool for generating a TamperMonkey script project written in typescript which is transpiled to JavaScript to be ran in the browser",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/neth392/create-tampermonkey-typescript",
|