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.
Files changed (55) hide show
  1. package/.vscode/settings.json +4 -0
  2. package/README.md +45 -0
  3. package/bin/obsidian-inject.js +98 -0
  4. package/obsidian-plugin-config-1.0.2.tgz +0 -0
  5. package/package.json +88 -0
  6. package/scripts/acp.ts +71 -0
  7. package/scripts/build-npm.ts +137 -0
  8. package/scripts/esbuild.config.ts +311 -0
  9. package/scripts/help.ts +46 -0
  10. package/scripts/inject-path.ts +487 -0
  11. package/scripts/inject-prompt.ts +399 -0
  12. package/scripts/open-editor.mjs +18 -0
  13. package/scripts/release.ts +97 -0
  14. package/scripts/update-exports.js +91 -0
  15. package/scripts/update-version-config.ts +98 -0
  16. package/scripts/update-version.ts +102 -0
  17. package/scripts/utils.ts +117 -0
  18. package/src/index.ts +6 -0
  19. package/src/main_test.ts +106 -0
  20. package/src/modals/GenericConfirmModal.ts +67 -0
  21. package/src/modals/index.ts +3 -0
  22. package/src/test-centralized-utils.ts +23 -0
  23. package/src/tools/index.ts +9 -0
  24. package/src/utils/NoticeHelper.ts +102 -0
  25. package/src/utils/SettingsHelper.ts +180 -0
  26. package/src/utils/index.ts +3 -0
  27. package/templates/.vscode/settings.json +4 -0
  28. package/templates/eslint.config.ts +48 -0
  29. package/templates/help-plugin.ts +39 -0
  30. package/templates/package-versions.json +28 -0
  31. package/templates/tsconfig.json +37 -0
  32. package/test-plugin/manifest.json +10 -0
  33. package/test-plugin/package.json +38 -0
  34. package/test-plugin/scripts/acp.ts +71 -0
  35. package/test-plugin/scripts/esbuild.config.ts +165 -0
  36. package/test-plugin/scripts/help.ts +29 -0
  37. package/test-plugin/scripts/release.ts +97 -0
  38. package/test-plugin/scripts/update-version.ts +102 -0
  39. package/test-plugin/scripts/utils.ts +117 -0
  40. package/test-plugin/src/main.ts +11 -0
  41. package/test-plugin/yarn.lock +386 -0
  42. package/test-plugin-v2/main.js +5 -0
  43. package/test-plugin-v2/manifest.json +10 -0
  44. package/test-plugin-v2/package.json +40 -0
  45. package/test-plugin-v2/scripts/acp.ts +71 -0
  46. package/test-plugin-v2/scripts/esbuild.config.ts +165 -0
  47. package/test-plugin-v2/scripts/help.ts +29 -0
  48. package/test-plugin-v2/scripts/release.ts +97 -0
  49. package/test-plugin-v2/scripts/update-version.ts +102 -0
  50. package/test-plugin-v2/scripts/utils.ts +117 -0
  51. package/test-plugin-v2/src/main.ts +11 -0
  52. package/test-plugin-v2/tsconfig.json +31 -0
  53. package/test-plugin-v2/yarn.lock +1986 -0
  54. package/tsconfig.json +38 -0
  55. 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
+ });