obsidian-plugin-config 1.4.6 → 1.4.8

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/scripts/help.ts CHANGED
@@ -1,152 +1,152 @@
1
- #!/usr/bin/env tsx
2
-
3
- console.log(`
4
- 🎯 Obsidian Plugin Config - Quick Help
5
- Injection system for autonomous Obsidian plugins
6
-
7
- ═══════════════════════════════════════════════════════════════════
8
-
9
- 📋 PLUGIN CONFIG COMMANDS
10
-
11
- INSTALLATION & SETUP:
12
- yarn i, install # Install dependencies
13
- yarn update-exports, ue # Update package.json exports
14
-
15
- GIT & VERSION MANAGEMENT:
16
- yarn acp # Add, commit, push
17
- yarn bacp # Build + add, commit, push
18
- yarn v, update-version # Update version (package.json + versions.json)
19
-
20
- BUILD & TESTING:
21
- yarn build # TypeScript check (no build needed)
22
- yarn dev # Start development mode (watch)
23
- yarn real # Build for production to real vault
24
- yarn lint, lint:fix # ESLint verification/correction
25
-
26
- INJECTION (Development phase):
27
- yarn inject-prompt <path> # Interactive injection (recommended)
28
- yarn inject-path <path> --yes # Direct injection with auto-confirm
29
- yarn inject <path> --sass # Injection with SASS support
30
- yarn check-plugin <path> # Verification only (dry-run)
31
-
32
- NPM PUBLISHING (all-in-one - no acp needed before):
33
- yarn npm-publish # Full workflow (7 steps):
34
- # 0. NPM auth check
35
- # 1. version bump
36
- # 2. update exports
37
- # 3. generate bin
38
- # 4. verify package
39
- # 5. commit + push
40
- # 6. publish to NPM
41
- # 7. offer global CLI update
42
- yarn build-npm # Alias for npm-publish
43
-
44
- UPGRADE:
45
- yarn upgrade-all # yarn upgrade + sync template deps
46
-
47
- HELP:
48
- yarn help, h # This help
49
-
50
- ═══════════════════════════════════════════════════════════════════
51
-
52
- 📦 EXPORTS SYSTEM
53
-
54
- The package exposes a single entry point:
55
- obsidian-plugin-config # Main entry — re-exports all modules
56
-
57
- Src modules (auto-exported via src/index.ts):
58
- modals, tools, utils
59
-
60
- After adding a new module to src/, run:
61
- yarn update-exports # Regenerates src/index.ts
62
-
63
- ═══════════════════════════════════════════════════════════════════
64
-
65
- 🏗️ ARCHITECTURE
66
-
67
- TWO DISTINCT ROLES:
68
- Root (src/, scripts/) # Local plugin + NPM snippet exports
69
- templates/ # Source of truth for injection
70
-
71
- templates/ → what gets injected:
72
- templates/package.json # Base deps/scripts for target plugins
73
- templates/package-sass.json # Extra deps when --sass is used
74
- templates/tsconfig.json # TypeScript config for target plugins
75
- templates/scripts/* # Scripts copied to <target>/scripts/
76
- templates/eslint.config.mts # ESLint config for target plugins
77
-
78
- inject-core.ts — shared injection logic:
79
- updatePackageJson() # Reads templates/package.json (not hardcoded)
80
- injectScripts() # Copies templates/ files to target
81
- performInjection() # Main orchestration function
82
-
83
- inject-path.ts — CLI entry point:
84
- Parses --yes, --dry-run, --sass flags
85
-
86
- inject-prompt.ts — interactive entry point:
87
- Prompts for target path interactively
88
-
89
- ═══════════════════════════════════════════════════════════════════
90
-
91
- 🔧 DEVELOPMENT WORKFLOWS
92
-
93
- Plugin Config Development:
94
- 1. yarn i # Install dependencies
95
- 2. yarn update-exports # Update exports
96
- 3. yarn dev # Test as plugin (optional)
97
- 4. yarn lint:fix # Fix code issues
98
- 5. yarn v # Update version + commit + push
99
- 6. yarn npm-publish # Publish to NPM
100
-
101
- Injection Usage:
102
- Usage (from plugin directory or by path):
103
- obsidian-inject # Inject in current dir
104
- obsidian-inject ../my-plugin # Inject by path
105
- obsidian-inject ../my-plugin --sass # With SASS
106
-
107
- Or with local yarn commands:
108
- yarn inject-prompt # Interactive
109
- yarn inject-path ../my-plugin # Direct injection
110
- yarn check-plugin ../my-plugin # Dry-run only
111
-
112
- SASS Support (--sass flag):
113
- What gets added to the target plugin:
114
- ✅ esbuild-sass-plugin dependency
115
- ✅ Automatic .scss file detection (src/styles.scss priority)
116
- ✅ CSS cleanup after compilation
117
-
118
- The standard esbuild.config.ts handles SASS via dynamic import —
119
- no separate template needed.
120
-
121
- ═══════════════════════════════════════════════════════════════════
122
-
123
- 🚀 COMPLETE WORKFLOWS
124
-
125
- STANDARD DEVELOPMENT WORKFLOW:
126
- 1. yarn i # Install dependencies
127
- 2. Make changes to src/ or templates/
128
- 3. yarn lint:fix # Fix any linting issues
129
- 4. yarn npm-publish # Does EVERYTHING:
130
- # → Ask for version bump type
131
- # → Update exports
132
- # → Generate bin file
133
- # → Verify package
134
- # → Commit + push to GitHub
135
- # → Publish to NPM
136
-
137
- Note: yarn acp is only needed for intermediate commits
138
- (not required before npm-publish).
139
-
140
- AFTER NPM PUBLISH - Update global CLI:
141
- npm install -g obsidian-plugin-config@latest --force
142
- obsidian-inject # Test in current plugin dir
143
- obsidian-inject ../test-plugin --sass
144
-
145
- TESTING AS PLUGIN (Optional):
146
- 1. Configure .env with TEST_VAULT and REAL_VAULT paths
147
- 2. yarn dev # Watch mode for development
148
- 3. yarn real # Install to real vault
149
-
150
- ═══════════════════════════════════════════════════════════════════
151
-
152
- `);
1
+ #!/usr/bin/env tsx
2
+
3
+ console.log(`
4
+ 🎯 Obsidian Plugin Config - Quick Help
5
+ Injection system for autonomous Obsidian plugins
6
+
7
+ ═══════════════════════════════════════════════════════════════════
8
+
9
+ 📋 PLUGIN CONFIG COMMANDS
10
+
11
+ INSTALLATION & SETUP:
12
+ yarn i, install # Install dependencies
13
+ yarn update-exports, ue # Update package.json exports
14
+
15
+ GIT & VERSION MANAGEMENT:
16
+ yarn acp # Add, commit, push
17
+ yarn bacp # Build + add, commit, push
18
+ yarn v, update-version # Update version (package.json + versions.json)
19
+
20
+ BUILD & TESTING:
21
+ yarn build # TypeScript check (no build needed)
22
+ yarn dev # Start development mode (watch)
23
+ yarn real # Build for production to real vault
24
+ yarn lint, lint:fix # ESLint verification/correction
25
+
26
+ INJECTION (Development phase):
27
+ yarn inject-prompt <path> # Interactive injection (recommended)
28
+ yarn inject-path <path> --yes # Direct injection with auto-confirm
29
+ yarn inject <path> --sass # Injection with SASS support
30
+ yarn check-plugin <path> # Verification only (dry-run)
31
+
32
+ NPM PUBLISHING (all-in-one - no acp needed before):
33
+ yarn npm-publish # Full workflow (7 steps):
34
+ # 0. NPM auth check
35
+ # 1. version bump
36
+ # 2. update exports
37
+ # 3. generate bin
38
+ # 4. verify package
39
+ # 5. commit + push
40
+ # 6. publish to NPM
41
+ # 7. offer global CLI update
42
+ yarn build-npm # Alias for npm-publish
43
+
44
+ UPGRADE:
45
+ yarn upgrade-all # yarn upgrade + sync template deps
46
+
47
+ HELP:
48
+ yarn help, h # This help
49
+
50
+ ═══════════════════════════════════════════════════════════════════
51
+
52
+ 📦 EXPORTS SYSTEM
53
+
54
+ The package exposes a single entry point:
55
+ obsidian-plugin-config # Main entry — re-exports all modules
56
+
57
+ Src modules (auto-exported via src/index.ts):
58
+ modals, tools, utils
59
+
60
+ After adding a new module to src/, run:
61
+ yarn update-exports # Regenerates src/index.ts
62
+
63
+ ═══════════════════════════════════════════════════════════════════
64
+
65
+ 🏗️ ARCHITECTURE
66
+
67
+ TWO DISTINCT ROLES:
68
+ Root (src/, scripts/) # Local plugin + NPM snippet exports
69
+ templates/ # Source of truth for injection
70
+
71
+ templates/ → what gets injected:
72
+ templates/package.json # Base deps/scripts for target plugins
73
+ templates/package-sass.json # Extra deps when --sass is used
74
+ templates/tsconfig.json # TypeScript config for target plugins
75
+ templates/scripts/* # Scripts copied to <target>/scripts/
76
+ templates/eslint.config.mts # ESLint config for target plugins
77
+
78
+ inject-core.ts — shared injection logic:
79
+ updatePackageJson() # Reads templates/package.json (not hardcoded)
80
+ injectScripts() # Copies templates/ files to target
81
+ performInjection() # Main orchestration function
82
+
83
+ inject-path.ts — CLI entry point:
84
+ Parses --yes, --dry-run, --sass flags
85
+
86
+ inject-prompt.ts — interactive entry point:
87
+ Prompts for target path interactively
88
+
89
+ ═══════════════════════════════════════════════════════════════════
90
+
91
+ 🔧 DEVELOPMENT WORKFLOWS
92
+
93
+ Plugin Config Development:
94
+ 1. yarn i # Install dependencies
95
+ 2. yarn update-exports # Update exports
96
+ 3. yarn dev # Test as plugin (optional)
97
+ 4. yarn lint:fix # Fix code issues
98
+ 5. yarn v # Update version + commit + push
99
+ 6. yarn npm-publish # Publish to NPM
100
+
101
+ Injection Usage:
102
+ Usage (from plugin directory or by path):
103
+ obsidian-inject # Inject in current dir
104
+ obsidian-inject ../my-plugin # Inject by path
105
+ obsidian-inject ../my-plugin --sass # With SASS
106
+
107
+ Or with local yarn commands:
108
+ yarn inject-prompt # Interactive
109
+ yarn inject-path ../my-plugin # Direct injection
110
+ yarn check-plugin ../my-plugin # Dry-run only
111
+
112
+ SASS Support (--sass flag):
113
+ What gets added to the target plugin:
114
+ ✅ esbuild-sass-plugin dependency
115
+ ✅ Automatic .scss file detection (src/styles.scss priority)
116
+ ✅ CSS cleanup after compilation
117
+
118
+ The standard esbuild.config.ts handles SASS via dynamic import —
119
+ no separate template needed.
120
+
121
+ ═══════════════════════════════════════════════════════════════════
122
+
123
+ 🚀 COMPLETE WORKFLOWS
124
+
125
+ STANDARD DEVELOPMENT WORKFLOW:
126
+ 1. yarn i # Install dependencies
127
+ 2. Make changes to src/ or templates/
128
+ 3. yarn lint:fix # Fix any linting issues
129
+ 4. yarn npm-publish # Does EVERYTHING:
130
+ # → Ask for version bump type
131
+ # → Update exports
132
+ # → Generate bin file
133
+ # → Verify package
134
+ # → Commit + push to GitHub
135
+ # → Publish to NPM
136
+
137
+ Note: yarn acp is only needed for intermediate commits
138
+ (not required before npm-publish).
139
+
140
+ AFTER NPM PUBLISH - Update global CLI:
141
+ npm install -g obsidian-plugin-config@latest --force
142
+ obsidian-inject # Test in current plugin dir
143
+ obsidian-inject ../test-plugin --sass
144
+
145
+ TESTING AS PLUGIN (Optional):
146
+ 1. Configure .env with TEST_VAULT and REAL_VAULT paths
147
+ 2. yarn dev # Watch mode for development
148
+ 3. yarn real # Install to real vault
149
+
150
+ ═══════════════════════════════════════════════════════════════════
151
+
152
+ `);
package/scripts/utils.ts CHANGED
@@ -1,151 +1,151 @@
1
- import { access, mkdir, copyFile, rm } from 'fs/promises';
2
- import path from 'path';
3
- import * as readline from 'readline';
4
- import { execSync } from 'child_process';
5
-
6
- export function createReadlineInterface(): readline.Interface {
7
- return readline.createInterface({
8
- input: process.stdin as NodeJS.ReadableStream,
9
- output: process.stdout as NodeJS.WritableStream
10
- });
11
- }
12
-
13
- export const askQuestion = async (
14
- question: string,
15
- rl: readline.Interface
16
- ): Promise<string> => {
17
- try {
18
- return await new Promise((resolve) =>
19
- rl.question(question, (input) => resolve(input.trim()))
20
- );
21
- } catch (error) {
22
- console.error('Error asking question:', error);
23
- throw error;
24
- }
25
- };
26
-
27
- /**
28
- * Ask a yes/no confirmation question with standardized logic
29
- * Accepts: y, yes, Y, YES, or empty (default to yes)
30
- * Rejects: n, no, N, NO
31
- * Invalid input defaults to no for safety
32
- */
33
- export const askConfirmation = async (
34
- question: string,
35
- rl: readline.Interface
36
- ): Promise<boolean> => {
37
- const answer = await askQuestion(`${question} [Y/n]: `, rl);
38
- const response = answer.toLowerCase();
39
-
40
- // Accept: y, yes, Y, YES, or empty (default to yes)
41
- // Reject: n, no, N, NO
42
- const isYes = response === '' || response === 'y' || response === 'yes';
43
- const isNo = response === 'n' || response === 'no';
44
-
45
- if (isNo) {
46
- return false;
47
- } else if (isYes) {
48
- return true;
49
- } else {
50
- console.log('Please answer Y (yes) or n (no). Defaulting to no for safety.');
51
- return false;
52
- }
53
- };
54
-
55
- export const cleanInput = (inputStr: string): string => {
56
- if (!inputStr) return '';
57
- return inputStr.trim().replace(/["`]/g, "'").replace(/\r\n/g, '\n');
58
- };
59
-
60
- export const isValidPath = async (pathToCheck: string): Promise<boolean> => {
61
- if (!pathToCheck) return false;
62
-
63
- try {
64
- // Using async fs.access is preferred over synchronous existsSync
65
- // as it doesn't block the main thread/event loop
66
- await access(pathToCheck.trim());
67
- return true;
68
- } catch {
69
- return false;
70
- }
71
- };
72
-
73
- export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
74
- const pluginDir = process.cwd();
75
- const manifestSrc = path.join(pluginDir, 'manifest.json');
76
- const manifestDest = path.join(buildPath, 'manifest.json');
77
- const cssDest = path.join(buildPath, 'styles.css');
78
- const folderToRemove = path.join(buildPath, '_.._');
79
-
80
- try {
81
- await mkdir(buildPath, { recursive: true });
82
- } catch (error: unknown) {
83
- if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
84
- console.error(`Error creating directory: ${(error as Error).message}`);
85
- }
86
- }
87
-
88
- // Copy manifest
89
- try {
90
- await copyFile(manifestSrc, manifestDest);
91
- } catch (error: unknown) {
92
- console.error(`Error copying manifest: ${(error as Error).message}`);
93
- }
94
-
95
- // Copy CSS
96
- try {
97
- const srcStylesPath = path.join(pluginDir, 'src/styles.css');
98
- const rootStylesPath = path.join(pluginDir, 'styles.css');
99
-
100
- // First check if CSS exists in src/styles.css
101
- if (await isValidPath(srcStylesPath)) {
102
- await copyFile(srcStylesPath, cssDest);
103
- }
104
- // Otherwise, check if it exists in the root
105
- else if (await isValidPath(rootStylesPath)) {
106
- await copyFile(rootStylesPath, cssDest);
107
- if (await isValidPath(folderToRemove)) {
108
- await rm(folderToRemove, { recursive: true });
109
- }
110
- } else {
111
- return;
112
- }
113
- } catch (error: unknown) {
114
- console.error(`Error copying CSS: ${(error as Error).message}`);
115
- }
116
- }
117
-
118
- export function gitExec(command: string): void {
119
- try {
120
- execSync(command, { stdio: 'inherit' });
121
- } catch (error: unknown) {
122
- console.error(`Error executing '${command}':`, (error as Error).message);
123
- throw error;
124
- }
125
- }
126
-
127
- /**
128
- * Ensure Git repository is synchronized with remote before pushing
129
- */
130
- export async function ensureGitSync(): Promise<void> {
131
- try {
132
- console.log('🔄 Checking Git synchronization...');
133
-
134
- // Fetch latest changes from remote
135
- execSync('git fetch origin', { stdio: 'pipe' });
136
-
137
- // Check if branch is behind remote
138
- const status = execSync('git status --porcelain -b', { encoding: 'utf8' });
139
-
140
- if (status.includes('behind')) {
141
- console.log('📥 Branch behind remote. Pulling changes...');
142
- execSync('git pull', { stdio: 'inherit' });
143
- console.log('✅ Successfully pulled remote changes');
144
- } else {
145
- console.log('✅ Repository is synchronized with remote');
146
- }
147
- } catch (error: unknown) {
148
- console.error(`❌ Git sync failed: ${(error as Error).message}`);
149
- throw error;
150
- }
151
- }
1
+ import { access, mkdir, copyFile, rm } from 'fs/promises';
2
+ import path from 'path';
3
+ import * as readline from 'readline';
4
+ import { execSync } from 'child_process';
5
+
6
+ export function createReadlineInterface(): readline.Interface {
7
+ return readline.createInterface({
8
+ input: process.stdin as NodeJS.ReadableStream,
9
+ output: process.stdout as NodeJS.WritableStream
10
+ });
11
+ }
12
+
13
+ export const askQuestion = async (
14
+ question: string,
15
+ rl: readline.Interface
16
+ ): Promise<string> => {
17
+ try {
18
+ return await new Promise((resolve) =>
19
+ rl.question(question, (input) => resolve(input.trim()))
20
+ );
21
+ } catch (error) {
22
+ console.error('Error asking question:', error);
23
+ throw error;
24
+ }
25
+ };
26
+
27
+ /**
28
+ * Ask a yes/no confirmation question with standardized logic
29
+ * Accepts: y, yes, Y, YES, or empty (default to yes)
30
+ * Rejects: n, no, N, NO
31
+ * Invalid input defaults to no for safety
32
+ */
33
+ export const askConfirmation = async (
34
+ question: string,
35
+ rl: readline.Interface
36
+ ): Promise<boolean> => {
37
+ const answer = await askQuestion(`${question} [Y/n]: `, rl);
38
+ const response = answer.toLowerCase();
39
+
40
+ // Accept: y, yes, Y, YES, or empty (default to yes)
41
+ // Reject: n, no, N, NO
42
+ const isYes = response === '' || response === 'y' || response === 'yes';
43
+ const isNo = response === 'n' || response === 'no';
44
+
45
+ if (isNo) {
46
+ return false;
47
+ } else if (isYes) {
48
+ return true;
49
+ } else {
50
+ console.log('Please answer Y (yes) or n (no). Defaulting to no for safety.');
51
+ return false;
52
+ }
53
+ };
54
+
55
+ export const cleanInput = (inputStr: string): string => {
56
+ if (!inputStr) return '';
57
+ return inputStr.trim().replace(/["`]/g, "'").replace(/\r\n/g, '\n');
58
+ };
59
+
60
+ export const isValidPath = async (pathToCheck: string): Promise<boolean> => {
61
+ if (!pathToCheck) return false;
62
+
63
+ try {
64
+ // Using async fs.access is preferred over synchronous existsSync
65
+ // as it doesn't block the main thread/event loop
66
+ await access(pathToCheck.trim());
67
+ return true;
68
+ } catch {
69
+ return false;
70
+ }
71
+ };
72
+
73
+ export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
74
+ const pluginDir = process.cwd();
75
+ const manifestSrc = path.join(pluginDir, 'manifest.json');
76
+ const manifestDest = path.join(buildPath, 'manifest.json');
77
+ const cssDest = path.join(buildPath, 'styles.css');
78
+ const folderToRemove = path.join(buildPath, '_.._');
79
+
80
+ try {
81
+ await mkdir(buildPath, { recursive: true });
82
+ } catch (error: unknown) {
83
+ if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
84
+ console.error(`Error creating directory: ${(error as Error).message}`);
85
+ }
86
+ }
87
+
88
+ // Copy manifest
89
+ try {
90
+ await copyFile(manifestSrc, manifestDest);
91
+ } catch (error: unknown) {
92
+ console.error(`Error copying manifest: ${(error as Error).message}`);
93
+ }
94
+
95
+ // Copy CSS
96
+ try {
97
+ const srcStylesPath = path.join(pluginDir, 'src/styles.css');
98
+ const rootStylesPath = path.join(pluginDir, 'styles.css');
99
+
100
+ // First check if CSS exists in src/styles.css
101
+ if (await isValidPath(srcStylesPath)) {
102
+ await copyFile(srcStylesPath, cssDest);
103
+ }
104
+ // Otherwise, check if it exists in the root
105
+ else if (await isValidPath(rootStylesPath)) {
106
+ await copyFile(rootStylesPath, cssDest);
107
+ if (await isValidPath(folderToRemove)) {
108
+ await rm(folderToRemove, { recursive: true });
109
+ }
110
+ } else {
111
+ return;
112
+ }
113
+ } catch (error: unknown) {
114
+ console.error(`Error copying CSS: ${(error as Error).message}`);
115
+ }
116
+ }
117
+
118
+ export function gitExec(command: string): void {
119
+ try {
120
+ execSync(command, { stdio: 'inherit' });
121
+ } catch (error: unknown) {
122
+ console.error(`Error executing '${command}':`, (error as Error).message);
123
+ throw error;
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Ensure Git repository is synchronized with remote before pushing
129
+ */
130
+ export async function ensureGitSync(): Promise<void> {
131
+ try {
132
+ console.log('🔄 Checking Git synchronization...');
133
+
134
+ // Fetch latest changes from remote
135
+ execSync('git fetch origin', { stdio: 'pipe' });
136
+
137
+ // Check if branch is behind remote
138
+ const status = execSync('git status --porcelain -b', { encoding: 'utf8' });
139
+
140
+ if (status.includes('behind')) {
141
+ console.log('📥 Branch behind remote. Pulling changes...');
142
+ execSync('git pull', { stdio: 'inherit' });
143
+ console.log('✅ Successfully pulled remote changes');
144
+ } else {
145
+ console.log('✅ Repository is synchronized with remote');
146
+ }
147
+ } catch (error: unknown) {
148
+ console.error(`❌ Git sync failed: ${(error as Error).message}`);
149
+ throw error;
150
+ }
151
+ }
@@ -41,6 +41,14 @@
41
41
  "presentation": { "reveal": "always", "panel": "shared" },
42
42
  "problemMatcher": ["$tsc"]
43
43
  },
44
+ {
45
+ "label": "Obsidian Inject",
46
+ "type": "shell",
47
+ "command": "obsidian-inject",
48
+ "group": "build",
49
+ "presentation": { "reveal": "always", "panel": "shared" },
50
+ "problemMatcher": []
51
+ },
44
52
  {
45
53
  "label": "Cleanup: Lint + Prettier + Build",
46
54
  "dependsOrder": "sequence",
@@ -41,6 +41,6 @@
41
41
  "prettier": "latest",
42
42
  "semver": "latest",
43
43
  "tsx": "latest",
44
- "typescript": "latest"
44
+ "typescript": "^5.8.2"
45
45
  }
46
46
  }