obsidian-plugin-config 1.0.2
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/.vscode/settings.json +4 -0
- package/README.md +45 -0
- package/bin/obsidian-inject.js +98 -0
- package/obsidian-plugin-config-1.0.2.tgz +0 -0
- package/package.json +88 -0
- package/scripts/acp.ts +71 -0
- package/scripts/build-npm.ts +137 -0
- package/scripts/esbuild.config.ts +311 -0
- package/scripts/help.ts +46 -0
- package/scripts/inject-path.ts +487 -0
- package/scripts/inject-prompt.ts +399 -0
- package/scripts/open-editor.mjs +18 -0
- package/scripts/release.ts +97 -0
- package/scripts/update-exports.js +91 -0
- package/scripts/update-version-config.ts +98 -0
- package/scripts/update-version.ts +102 -0
- package/scripts/utils.ts +117 -0
- package/src/index.ts +6 -0
- package/src/main_test.ts +106 -0
- package/src/modals/GenericConfirmModal.ts +67 -0
- package/src/modals/index.ts +3 -0
- package/src/test-centralized-utils.ts +23 -0
- package/src/tools/index.ts +9 -0
- package/src/utils/NoticeHelper.ts +102 -0
- package/src/utils/SettingsHelper.ts +180 -0
- package/src/utils/index.ts +3 -0
- package/templates/.vscode/settings.json +4 -0
- package/templates/eslint.config.ts +48 -0
- package/templates/help-plugin.ts +39 -0
- package/templates/package-versions.json +28 -0
- package/templates/tsconfig.json +37 -0
- package/test-plugin/manifest.json +10 -0
- package/test-plugin/package.json +38 -0
- package/test-plugin/scripts/acp.ts +71 -0
- package/test-plugin/scripts/esbuild.config.ts +165 -0
- package/test-plugin/scripts/help.ts +29 -0
- package/test-plugin/scripts/release.ts +97 -0
- package/test-plugin/scripts/update-version.ts +102 -0
- package/test-plugin/scripts/utils.ts +117 -0
- package/test-plugin/src/main.ts +11 -0
- package/test-plugin/yarn.lock +386 -0
- package/test-plugin-v2/main.js +5 -0
- package/test-plugin-v2/manifest.json +10 -0
- package/test-plugin-v2/package.json +40 -0
- package/test-plugin-v2/scripts/acp.ts +71 -0
- package/test-plugin-v2/scripts/esbuild.config.ts +165 -0
- package/test-plugin-v2/scripts/help.ts +29 -0
- package/test-plugin-v2/scripts/release.ts +97 -0
- package/test-plugin-v2/scripts/update-version.ts +102 -0
- package/test-plugin-v2/scripts/utils.ts +117 -0
- package/test-plugin-v2/src/main.ts +11 -0
- package/test-plugin-v2/tsconfig.json +31 -0
- package/test-plugin-v2/yarn.lock +1986 -0
- package/tsconfig.json +38 -0
- package/versions.json +5 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import {
|
|
7
|
+
askQuestion,
|
|
8
|
+
askConfirmation,
|
|
9
|
+
createReadlineInterface,
|
|
10
|
+
isValidPath
|
|
11
|
+
} from "./utils.js";
|
|
12
|
+
|
|
13
|
+
const rl = createReadlineInterface();
|
|
14
|
+
|
|
15
|
+
interface InjectionPlan {
|
|
16
|
+
targetPath: string;
|
|
17
|
+
isObsidianPlugin: boolean;
|
|
18
|
+
hasPackageJson: boolean;
|
|
19
|
+
hasManifest: boolean;
|
|
20
|
+
hasScriptsFolder: boolean;
|
|
21
|
+
currentDependencies: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Analyze the target plugin directory
|
|
26
|
+
*/
|
|
27
|
+
async function analyzePlugin(pluginPath: string): Promise<InjectionPlan> {
|
|
28
|
+
const packageJsonPath = path.join(pluginPath, "package.json");
|
|
29
|
+
const manifestPath = path.join(pluginPath, "manifest.json");
|
|
30
|
+
const scriptsPath = path.join(pluginPath, "scripts");
|
|
31
|
+
|
|
32
|
+
const plan: InjectionPlan = {
|
|
33
|
+
targetPath: pluginPath,
|
|
34
|
+
isObsidianPlugin: false,
|
|
35
|
+
hasPackageJson: await isValidPath(packageJsonPath),
|
|
36
|
+
hasManifest: await isValidPath(manifestPath),
|
|
37
|
+
hasScriptsFolder: await isValidPath(scriptsPath),
|
|
38
|
+
currentDependencies: []
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Check if it's an Obsidian plugin
|
|
42
|
+
if (plan.hasManifest) {
|
|
43
|
+
try {
|
|
44
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
45
|
+
plan.isObsidianPlugin = !!(manifest.id && manifest.name && manifest.version);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
console.warn("Warning: Could not parse manifest.json");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Get current dependencies
|
|
52
|
+
if (plan.hasPackageJson) {
|
|
53
|
+
try {
|
|
54
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
55
|
+
plan.currentDependencies = [
|
|
56
|
+
...Object.keys(packageJson.dependencies || {}),
|
|
57
|
+
...Object.keys(packageJson.devDependencies || {})
|
|
58
|
+
];
|
|
59
|
+
} catch (error) {
|
|
60
|
+
console.warn("Warning: Could not parse package.json");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return plan;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Display injection plan and ask for confirmation
|
|
69
|
+
*/
|
|
70
|
+
async function showInjectionPlan(plan: InjectionPlan): Promise<boolean> {
|
|
71
|
+
console.log(`\n🎯 Injection Plan for: ${plan.targetPath}`);
|
|
72
|
+
console.log(`📁 Target: ${path.basename(plan.targetPath)}`);
|
|
73
|
+
console.log(`📦 Package.json: ${plan.hasPackageJson ? '✅' : '❌'}`);
|
|
74
|
+
console.log(`📋 Manifest.json: ${plan.hasManifest ? '✅' : '❌'}`);
|
|
75
|
+
console.log(`📂 Scripts folder: ${plan.hasScriptsFolder ? '✅ (will be updated)' : '❌ (will be created)'}`);
|
|
76
|
+
console.log(`🔌 Obsidian plugin: ${plan.isObsidianPlugin ? '✅' : '❌'}`);
|
|
77
|
+
|
|
78
|
+
if (!plan.isObsidianPlugin) {
|
|
79
|
+
console.log(`\n⚠️ Warning: This doesn't appear to be a valid Obsidian plugin`);
|
|
80
|
+
console.log(` Missing manifest.json or invalid structure`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
console.log(`\n📋 Will inject:`);
|
|
84
|
+
console.log(` ✅ Local scripts (utils.ts, esbuild.config.ts, acp.ts, etc.)`);
|
|
85
|
+
console.log(` ✅ Updated package.json scripts`);
|
|
86
|
+
console.log(` ✅ Required dependencies`);
|
|
87
|
+
console.log(` 🔍 Analyze centralized imports (manual commenting may be needed)`);
|
|
88
|
+
|
|
89
|
+
return await askConfirmation(`\nProceed with injection?`, rl);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Find plugin-config root directory
|
|
94
|
+
*/
|
|
95
|
+
function findPluginConfigRoot(): string {
|
|
96
|
+
// Auto-detect parent, fallback to current
|
|
97
|
+
const parentPath = path.resolve(process.cwd(), "../obsidian-plugin-config");
|
|
98
|
+
if (fs.existsSync(parentPath)) {
|
|
99
|
+
return parentPath;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Fallback to current directory
|
|
103
|
+
return process.cwd();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Copy file content from local plugin-config directory
|
|
108
|
+
*/
|
|
109
|
+
function copyFromLocal(filePath: string): string {
|
|
110
|
+
const configRoot = findPluginConfigRoot();
|
|
111
|
+
const sourcePath = path.join(configRoot, filePath);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
return fs.readFileSync(sourcePath, 'utf8');
|
|
115
|
+
} catch (error) {
|
|
116
|
+
throw new Error(`Failed to copy ${filePath}: ${error}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Inject scripts from local files
|
|
122
|
+
*/
|
|
123
|
+
async function injectScripts(targetPath: string): Promise<void> {
|
|
124
|
+
const scriptsPath = path.join(targetPath, "scripts");
|
|
125
|
+
|
|
126
|
+
// Create scripts directory if it doesn't exist
|
|
127
|
+
if (!await isValidPath(scriptsPath)) {
|
|
128
|
+
fs.mkdirSync(scriptsPath, { recursive: true });
|
|
129
|
+
console.log(`📁 Created scripts directory`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const scriptFiles = [
|
|
133
|
+
"scripts/utils.ts",
|
|
134
|
+
"scripts/esbuild.config.ts",
|
|
135
|
+
"scripts/acp.ts",
|
|
136
|
+
"scripts/update-version.ts",
|
|
137
|
+
"scripts/release.ts",
|
|
138
|
+
"scripts/help.ts"
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
const configFiles = [
|
|
142
|
+
"templates/tsconfig.json"
|
|
143
|
+
];
|
|
144
|
+
|
|
145
|
+
console.log(`\n📥 Copying scripts from local files...`);
|
|
146
|
+
|
|
147
|
+
for (const scriptFile of scriptFiles) {
|
|
148
|
+
try {
|
|
149
|
+
const content = copyFromLocal(scriptFile);
|
|
150
|
+
const fileName = path.basename(scriptFile);
|
|
151
|
+
const targetFile = path.join(scriptsPath, fileName);
|
|
152
|
+
|
|
153
|
+
fs.writeFileSync(targetFile, content, 'utf8');
|
|
154
|
+
console.log(` ✅ ${fileName}`);
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(` ❌ Failed to inject ${scriptFile}: ${error}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(`\n📥 Copying config files from local files...`);
|
|
161
|
+
|
|
162
|
+
for (const configFile of configFiles) {
|
|
163
|
+
try {
|
|
164
|
+
const content = copyFromLocal(configFile);
|
|
165
|
+
const fileName = path.basename(configFile);
|
|
166
|
+
const targetFile = path.join(targetPath, fileName);
|
|
167
|
+
|
|
168
|
+
// Force inject tsconfig.json to ensure correct template
|
|
169
|
+
if (fileName === 'tsconfig.json' && await isValidPath(targetFile)) {
|
|
170
|
+
console.log(` 🔄 ${fileName} exists, updating with template`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
fs.writeFileSync(targetFile, content, 'utf8');
|
|
174
|
+
console.log(` ✅ ${fileName}`);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(` ❌ Failed to inject ${configFile}: ${error}`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Update package.json with autonomous configuration
|
|
183
|
+
*/
|
|
184
|
+
async function updatePackageJson(targetPath: string): Promise<void> {
|
|
185
|
+
const packageJsonPath = path.join(targetPath, "package.json");
|
|
186
|
+
|
|
187
|
+
if (!await isValidPath(packageJsonPath)) {
|
|
188
|
+
console.log(`❌ No package.json found, skipping package.json update`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
194
|
+
|
|
195
|
+
// Update scripts
|
|
196
|
+
packageJson.scripts = {
|
|
197
|
+
...packageJson.scripts,
|
|
198
|
+
"start": "yarn install && yarn dev",
|
|
199
|
+
"dev": "tsx scripts/esbuild.config.ts",
|
|
200
|
+
"build": "tsc -noEmit -skipLibCheck && tsx scripts/esbuild.config.ts production",
|
|
201
|
+
"real": "tsx scripts/esbuild.config.ts production real",
|
|
202
|
+
"acp": "tsx scripts/acp.ts",
|
|
203
|
+
"bacp": "tsx scripts/acp.ts -b",
|
|
204
|
+
"update-version": "tsx scripts/update-version.ts",
|
|
205
|
+
"v": "tsx scripts/update-version.ts",
|
|
206
|
+
"release": "tsx scripts/release.ts",
|
|
207
|
+
"r": "tsx scripts/release.ts",
|
|
208
|
+
"help": "tsx scripts/help.ts",
|
|
209
|
+
"h": "tsx scripts/help.ts"
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Remove centralized dependency
|
|
213
|
+
if (packageJson.dependencies && packageJson.dependencies["obsidian-plugin-config"]) {
|
|
214
|
+
delete packageJson.dependencies["obsidian-plugin-config"];
|
|
215
|
+
console.log(` 🗑️ Removed obsidian-plugin-config dependency`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Add required dependencies
|
|
219
|
+
if (!packageJson.devDependencies) packageJson.devDependencies = {};
|
|
220
|
+
|
|
221
|
+
const requiredDeps = {
|
|
222
|
+
"@types/node": "^22.15.26",
|
|
223
|
+
"@types/semver": "^7.7.0",
|
|
224
|
+
"builtin-modules": "3.3.0",
|
|
225
|
+
"dedent": "^1.6.0",
|
|
226
|
+
"dotenv": "^16.4.5",
|
|
227
|
+
"esbuild": "latest",
|
|
228
|
+
"obsidian": "*",
|
|
229
|
+
"obsidian-typings": "^3.9.5",
|
|
230
|
+
"semver": "^7.7.2",
|
|
231
|
+
"tsx": "^4.19.4",
|
|
232
|
+
"typescript": "^5.8.2"
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
let addedDeps = 0;
|
|
236
|
+
let updatedDeps = 0;
|
|
237
|
+
for (const [dep, version] of Object.entries(requiredDeps)) {
|
|
238
|
+
if (!packageJson.devDependencies[dep]) {
|
|
239
|
+
packageJson.devDependencies[dep] = version;
|
|
240
|
+
addedDeps++;
|
|
241
|
+
} else if (packageJson.devDependencies[dep] !== version) {
|
|
242
|
+
packageJson.devDependencies[dep] = version;
|
|
243
|
+
updatedDeps++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Ensure yarn protection
|
|
248
|
+
if (!packageJson.engines) packageJson.engines = {};
|
|
249
|
+
packageJson.engines.npm = "please-use-yarn";
|
|
250
|
+
packageJson.engines.yarn = ">=1.22.0";
|
|
251
|
+
|
|
252
|
+
// Write updated package.json
|
|
253
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
254
|
+
console.log(` ✅ Updated package.json (${addedDeps} new, ${updatedDeps} updated dependencies)`);
|
|
255
|
+
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.error(` ❌ Failed to update package.json: ${error}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Run yarn install in target directory
|
|
263
|
+
*/
|
|
264
|
+
async function runYarnInstall(targetPath: string): Promise<void> {
|
|
265
|
+
console.log(`\n📦 Installing dependencies...`);
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
execSync('yarn install', {
|
|
269
|
+
cwd: targetPath,
|
|
270
|
+
stdio: 'inherit'
|
|
271
|
+
});
|
|
272
|
+
console.log(` ✅ Dependencies installed successfully`);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
console.error(` ❌ Failed to install dependencies: ${error}`);
|
|
275
|
+
console.log(` 💡 You may need to run 'yarn install' manually in the target directory`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Direct injection function (without argument parsing)
|
|
281
|
+
*/
|
|
282
|
+
async function performInjectionDirect(targetPath: string): Promise<void> {
|
|
283
|
+
console.log(`\n🚀 Starting injection process...`);
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
// Step 1: Inject scripts
|
|
287
|
+
await injectScripts(targetPath);
|
|
288
|
+
|
|
289
|
+
// Step 2: Update package.json
|
|
290
|
+
console.log(`\n📦 Updating package.json...`);
|
|
291
|
+
await updatePackageJson(targetPath);
|
|
292
|
+
|
|
293
|
+
// Step 3: Install dependencies
|
|
294
|
+
await runYarnInstall(targetPath);
|
|
295
|
+
|
|
296
|
+
console.log(`\n✅ Injection completed successfully!`);
|
|
297
|
+
console.log(`\n📋 Next steps:`);
|
|
298
|
+
console.log(` 1. cd ${targetPath}`);
|
|
299
|
+
console.log(` 2. yarn build # Test the build`);
|
|
300
|
+
console.log(` 3. yarn start # Test development mode`);
|
|
301
|
+
console.log(` 4. yarn acp # Commit changes (or yarn bacp for build+commit)`);
|
|
302
|
+
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error(`\n❌ Injection failed: ${error}`);
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Ask user for target directory path
|
|
311
|
+
*/
|
|
312
|
+
async function promptForTargetPath(): Promise<string> {
|
|
313
|
+
console.log(`\n📁 Select target plugin directory:`);
|
|
314
|
+
console.log(` Common paths (copy-paste ready):`);
|
|
315
|
+
console.log(` - ../test-sample-plugin`);
|
|
316
|
+
console.log(` - ../sample-plugin-modif`);
|
|
317
|
+
console.log(` - ../my-obsidian-plugin`);
|
|
318
|
+
console.log(` 💡 Tip: You can paste paths with or without quotes`);
|
|
319
|
+
|
|
320
|
+
while (true) {
|
|
321
|
+
const rawInput = await askQuestion(`\nEnter plugin directory path: `, rl);
|
|
322
|
+
|
|
323
|
+
if (!rawInput.trim()) {
|
|
324
|
+
console.log(`❌ Please enter a valid path`);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Remove quotes if present and trim
|
|
329
|
+
const cleanPath = rawInput.trim().replace(/^["']|["']$/g, '');
|
|
330
|
+
const resolvedPath = path.resolve(cleanPath);
|
|
331
|
+
|
|
332
|
+
if (!await isValidPath(resolvedPath)) {
|
|
333
|
+
console.log(`❌ Directory not found: ${resolvedPath}`);
|
|
334
|
+
const retry = await askConfirmation(`Try again?`, rl);
|
|
335
|
+
if (!retry) {
|
|
336
|
+
throw new Error("User cancelled");
|
|
337
|
+
}
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
console.log(`📁 Target directory: ${resolvedPath}`);
|
|
342
|
+
return resolvedPath;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Main function
|
|
348
|
+
*/
|
|
349
|
+
async function main(): Promise<void> {
|
|
350
|
+
try {
|
|
351
|
+
console.log(`🎯 Obsidian Plugin Config - Interactive Injection Tool`);
|
|
352
|
+
console.log(`📥 Inject autonomous configuration with prompts\n`);
|
|
353
|
+
|
|
354
|
+
// Check if path provided as argument
|
|
355
|
+
const args = process.argv.slice(2);
|
|
356
|
+
let targetPath: string;
|
|
357
|
+
|
|
358
|
+
if (args.length > 0) {
|
|
359
|
+
// Use provided argument
|
|
360
|
+
const rawPath = args[0];
|
|
361
|
+
const cleanPath = rawPath.trim().replace(/^["']|["']$/g, '');
|
|
362
|
+
targetPath = path.resolve(cleanPath);
|
|
363
|
+
|
|
364
|
+
if (!await isValidPath(targetPath)) {
|
|
365
|
+
console.error(`❌ Directory not found: ${targetPath}`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
console.log(`📁 Using provided path: ${targetPath}`);
|
|
370
|
+
} else {
|
|
371
|
+
// Prompt for target directory
|
|
372
|
+
targetPath = await promptForTargetPath();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Analyze the plugin
|
|
376
|
+
console.log(`\n🔍 Analyzing plugin...`);
|
|
377
|
+
const plan = await analyzePlugin(targetPath);
|
|
378
|
+
|
|
379
|
+
// Show plan and ask for confirmation
|
|
380
|
+
const confirmed = await showInjectionPlan(plan);
|
|
381
|
+
|
|
382
|
+
if (!confirmed) {
|
|
383
|
+
console.log(`❌ Injection cancelled by user`);
|
|
384
|
+
process.exit(0);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Perform injection directly
|
|
388
|
+
await performInjectionDirect(targetPath);
|
|
389
|
+
|
|
390
|
+
} catch (error) {
|
|
391
|
+
console.error(`💥 Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
} finally {
|
|
394
|
+
rl.close();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Run the script
|
|
399
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { platform } from 'os';
|
|
3
|
+
|
|
4
|
+
const isWindows = platform() === 'win32';
|
|
5
|
+
|
|
6
|
+
console.log(`Starting the ${process.env.npm_lifecycle_event} process...\n`);
|
|
7
|
+
console.log('- Dependencies installed');
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
if (isWindows) {
|
|
11
|
+
execSync("start /B code .", { stdio: "ignore", shell: true });
|
|
12
|
+
} else {
|
|
13
|
+
execSync("code .", { stdio: "ignore" });
|
|
14
|
+
}
|
|
15
|
+
console.log('- Opened current folder in VSCode');
|
|
16
|
+
} catch (error) {
|
|
17
|
+
console.warn('Warning: Could not open VSCode');
|
|
18
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeFile,
|
|
3
|
+
stat
|
|
4
|
+
} from "fs/promises";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import dedent from "dedent";
|
|
7
|
+
import {
|
|
8
|
+
askQuestion,
|
|
9
|
+
askConfirmation,
|
|
10
|
+
createReadlineInterface
|
|
11
|
+
} from "./utils.js";
|
|
12
|
+
|
|
13
|
+
const rl = createReadlineInterface();
|
|
14
|
+
|
|
15
|
+
const body = ".github/workflows/release-body.md";
|
|
16
|
+
|
|
17
|
+
async function checkOrCreateFile(filename: string): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
await stat(filename);
|
|
20
|
+
} catch {
|
|
21
|
+
console.log(`Creating ${filename} because it doesn't exist. Avoid deleting it.`);
|
|
22
|
+
await writeFile(filename, "");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function createReleaseNotesFile(tagMessage: string, tag: string): Promise<void> {
|
|
27
|
+
await writeFile(body, tagMessage);
|
|
28
|
+
console.log(`Release notes for tag ${tag} have been written to release-body.md`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleExistingTag(tag: string): Promise<boolean> {
|
|
32
|
+
const confirmed = await askConfirmation(`Tag ${tag} already exists. Do you want to replace it?`, rl);
|
|
33
|
+
|
|
34
|
+
if (!confirmed) {
|
|
35
|
+
console.log("Operation aborted");
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
execSync(`git tag -d ${tag}`);
|
|
40
|
+
execSync(`git push origin :refs/tags/${tag}`);
|
|
41
|
+
console.log(`Deleted existing tag ${tag} locally and remotely.`);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function createTag(): Promise<void> {
|
|
46
|
+
const currentVersion = process.env.npm_package_version;
|
|
47
|
+
const tag = `${currentVersion}`;
|
|
48
|
+
|
|
49
|
+
await checkOrCreateFile(body);
|
|
50
|
+
const exists = execSync("git ls-remote --tags origin").toString().includes(`refs/tags/${tag}`);
|
|
51
|
+
|
|
52
|
+
if (exists && !(await handleExistingTag(tag))) {
|
|
53
|
+
rl.close();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await doCommit(currentVersion, tag);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
async function doCommit(currentVersion: string | undefined, tag: string): Promise<void> {
|
|
62
|
+
rl.question(`Enter the commit message for version ${currentVersion}: `, async (message) => {
|
|
63
|
+
doNextSteps(message, tag);
|
|
64
|
+
rl.close();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function doNextSteps(message: string, tag: string): Promise<void> {
|
|
69
|
+
const messages = message.split("\\n");
|
|
70
|
+
const toShow = message.replace(/\\n/g, "\n");
|
|
71
|
+
await createReleaseNotesFile(toShow, tag);
|
|
72
|
+
const tagMessage = messages.map(m => `-m "${m}"`).join(" ");
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
execSync("git add -A");
|
|
76
|
+
execSync("git commit -m \"update tag description\"");
|
|
77
|
+
execSync("git push");
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
console.error("Error:", error.message);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
execSync(`git tag -a ${tag} ${tagMessage}`);
|
|
83
|
+
} catch {
|
|
84
|
+
execSync(`git tag -d ${tag}`);
|
|
85
|
+
execSync(`git push origin :refs/tags/${tag}`);
|
|
86
|
+
console.log("Fixed");
|
|
87
|
+
execSync(`git tag -a ${tag} ${tagMessage}`);
|
|
88
|
+
}
|
|
89
|
+
execSync(`git push origin ${tag}`);
|
|
90
|
+
console.log(`Release ${tag} pushed to repo.`);
|
|
91
|
+
console.log(dedent`
|
|
92
|
+
with message:
|
|
93
|
+
${toShow}
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
createTag().catch(console.error);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
// Get current directory (equivalent to __dirname in CommonJS)
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Scans the src directory for subdirectories with index.ts files
|
|
11
|
+
* and generates the main index.ts with appropriate exports
|
|
12
|
+
*/
|
|
13
|
+
function updateExports() {
|
|
14
|
+
console.log('🔄 Updating exports...');
|
|
15
|
+
|
|
16
|
+
const srcDir = path.join(__dirname, '../src');
|
|
17
|
+
const mainIndexPath = path.join(srcDir, 'index.ts');
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Check if src directory exists
|
|
21
|
+
if (!fs.existsSync(srcDir)) {
|
|
22
|
+
console.error('❌ src directory not found');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Get all subdirectories in src/
|
|
27
|
+
const items = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
28
|
+
const subdirs = items
|
|
29
|
+
.filter(item => item.isDirectory())
|
|
30
|
+
.map(item => item.name);
|
|
31
|
+
|
|
32
|
+
// Find subdirectories that have an index.ts file
|
|
33
|
+
const exportsToGenerate = [];
|
|
34
|
+
|
|
35
|
+
for (const subdir of subdirs) {
|
|
36
|
+
const subdirPath = path.join(srcDir, subdir);
|
|
37
|
+
const indexPath = path.join(subdirPath, 'index.ts');
|
|
38
|
+
|
|
39
|
+
if (fs.existsSync(indexPath)) {
|
|
40
|
+
exportsToGenerate.push(subdir);
|
|
41
|
+
console.log(`✅ Found exportable module: ${subdir}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Generate the export statements
|
|
46
|
+
const exportStatements = exportsToGenerate
|
|
47
|
+
.map(subdir => `export * from './${subdir}/index.js';`)
|
|
48
|
+
.join('\n');
|
|
49
|
+
|
|
50
|
+
// Add header comment
|
|
51
|
+
const fileContent = `// Auto-generated exports - DO NOT EDIT MANUALLY
|
|
52
|
+
// Run 'npm run update-exports' to regenerate this file
|
|
53
|
+
|
|
54
|
+
${exportStatements}
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
// Write the main index.ts file
|
|
58
|
+
fs.writeFileSync(mainIndexPath, fileContent, 'utf8');
|
|
59
|
+
|
|
60
|
+
// Update package.json exports
|
|
61
|
+
const packageJsonPath = path.join(__dirname, '../package.json');
|
|
62
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
63
|
+
|
|
64
|
+
// Generate exports object
|
|
65
|
+
const exportsObj = {
|
|
66
|
+
".": "./src/index.ts",
|
|
67
|
+
"./scripts/*": "./scripts/*"
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Add exports for each module
|
|
71
|
+
for (const subdir of exportsToGenerate) {
|
|
72
|
+
exportsObj[`./${subdir}`] = `./src/${subdir}/index.ts`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
packageJson.exports = exportsObj;
|
|
76
|
+
|
|
77
|
+
// Write updated package.json
|
|
78
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf8');
|
|
79
|
+
|
|
80
|
+
console.log(`✅ Updated ${mainIndexPath}`);
|
|
81
|
+
console.log(`✅ Updated ${packageJsonPath} exports`);
|
|
82
|
+
console.log(`📦 Generated ${exportsToGenerate.length} export(s): ${exportsToGenerate.join(', ')}`);
|
|
83
|
+
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('❌ Error updating exports:', error.message);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Run the function
|
|
91
|
+
updateExports();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile, writeFile } from "fs/promises";
|
|
2
|
+
import dedent from "dedent";
|
|
3
|
+
import { inc, valid } from "semver";
|
|
4
|
+
import { createReadlineInterface, askQuestion, gitExec } from "./utils";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const rl = createReadlineInterface();
|
|
8
|
+
|
|
9
|
+
async function getTargetVersion(currentVersion: string): Promise<string> {
|
|
10
|
+
const updateType = await askQuestion(dedent`
|
|
11
|
+
Current version: ${currentVersion}
|
|
12
|
+
Kind of update:
|
|
13
|
+
patch(1.0.1) -> type 1 or p
|
|
14
|
+
minor(1.1.0) -> type 2 or min
|
|
15
|
+
major(2.0.0) -> type 3 or maj
|
|
16
|
+
or version number (e.g. 2.0.0)
|
|
17
|
+
Enter choice: `, rl);
|
|
18
|
+
|
|
19
|
+
switch (updateType.trim()) {
|
|
20
|
+
case "p":
|
|
21
|
+
case "1":
|
|
22
|
+
return inc(currentVersion, "patch") || "";
|
|
23
|
+
case "min":
|
|
24
|
+
case "2":
|
|
25
|
+
return inc(currentVersion, "minor") || "";
|
|
26
|
+
case "maj":
|
|
27
|
+
case "3":
|
|
28
|
+
return inc(currentVersion, "major") || "";
|
|
29
|
+
default:
|
|
30
|
+
return valid(updateType.trim()) || "";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function updateJsonFile(filename: string, updateFn: (json: any) => void): Promise<void> {
|
|
35
|
+
try {
|
|
36
|
+
const content = JSON.parse(await readFile(filename, "utf8"));
|
|
37
|
+
updateFn(content);
|
|
38
|
+
await writeFile(filename, JSON.stringify(content, null, "\t"));
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error(`Error updating ${filename}:`, error instanceof Error ? error.message : String(error));
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function updateConfigVersions(targetVersion: string): Promise<void> {
|
|
46
|
+
try {
|
|
47
|
+
await Promise.all([
|
|
48
|
+
updateJsonFile("package.json", json => json.version = targetVersion),
|
|
49
|
+
updateJsonFile("versions.json", json => json[targetVersion] = "1.8.9")
|
|
50
|
+
]);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error("Error updating config versions:", error instanceof Error ? error.message : String(error));
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function updateVersion(): Promise<void> {
|
|
58
|
+
try {
|
|
59
|
+
const currentVersion = process.env.npm_package_version || "1.0.0";
|
|
60
|
+
const targetVersion = await getTargetVersion(currentVersion);
|
|
61
|
+
|
|
62
|
+
if (!targetVersion) {
|
|
63
|
+
console.log("Invalid version");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
// Update all files first
|
|
69
|
+
await updateConfigVersions(targetVersion);
|
|
70
|
+
console.log(`Files updated to version ${targetVersion}`);
|
|
71
|
+
|
|
72
|
+
// Add files to git
|
|
73
|
+
gitExec("git add package.json versions.json");
|
|
74
|
+
gitExec(`git commit -m "Updated to version ${targetVersion}"`);
|
|
75
|
+
console.log("Changes committed");
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error("Error during update or commit:", error instanceof Error ? error.message : String(error));
|
|
78
|
+
console.log("Operation failed.");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
gitExec("git push");
|
|
84
|
+
console.log(`Version successfully updated to ${targetVersion} and pushed.`);
|
|
85
|
+
} catch (pushError) {
|
|
86
|
+
console.error("Failed to push version update:", pushError instanceof Error ? pushError.message : String(pushError));
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
90
|
+
} finally {
|
|
91
|
+
rl.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
updateVersion().catch(console.error).finally(() => {
|
|
96
|
+
console.log("Exiting...");
|
|
97
|
+
process.exit();
|
|
98
|
+
});
|