obsidian-plugin-config 1.5.12 → 1.6.1

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 (43) hide show
  1. package/.vscode/tasks.json +5 -69
  2. package/DONE.md +60 -0
  3. package/FINAL_SUMMARY.md +163 -0
  4. package/README.md +70 -35
  5. package/bin/obsidian-inject.js +1 -1
  6. package/docs/APPLIED_MODIFS.md +104 -0
  7. package/docs/INTERACTIVE_INJECTION.md +137 -0
  8. package/docs/LLM-GUIDE.md +60 -50
  9. package/docs/TECHNICAL_NOTES.md +43 -0
  10. package/docs/implementation_plan.md +127 -0
  11. package/docs/modifs.md +434 -0
  12. package/package.json +3 -29
  13. package/scripts/acp.ts +7 -11
  14. package/scripts/build-npm.ts +78 -75
  15. package/scripts/help.ts +45 -107
  16. package/scripts/inject-core.ts +74 -36
  17. package/scripts/inject-options.ts +139 -0
  18. package/scripts/inject-path.ts +18 -4
  19. package/scripts/inject-prompt.ts +2 -1
  20. package/scripts/update-version-config.ts +2 -5
  21. package/templates/.gitattributes +4 -0
  22. package/templates/.github/workflows/release.yml +1 -1
  23. package/templates/.prettierignore +6 -0
  24. package/templates/.vscode/extensions.json +8 -0
  25. package/templates/.vscode/settings.json +0 -1
  26. package/templates/package.json +3 -2
  27. package/templates/scripts/esbuild.config.ts +16 -21
  28. package/tsconfig.json +2 -8
  29. package/.injection-info.json +0 -5
  30. package/docs/EXPORTS-EXPLAINED.md +0 -164
  31. package/manifest.json +0 -11
  32. package/scripts/esbuild.config.ts +0 -268
  33. package/scripts/sync-template-deps.ts +0 -59
  34. package/scripts/update-exports.js +0 -82
  35. package/src/index.ts +0 -6
  36. package/src/main.ts +0 -117
  37. package/src/modals/GenericConfirmModal.ts +0 -79
  38. package/src/modals/index.ts +0 -7
  39. package/src/tools/index.ts +0 -9
  40. package/src/utils/NoticeHelper.ts +0 -85
  41. package/src/utils/SettingsHelper.ts +0 -170
  42. package/src/utils/index.ts +0 -3
  43. package/versions.json +0 -64
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env tsx
2
+
3
+ import type { Interface } from 'readline';
4
+
5
+ export interface InjectionOptions {
6
+ scripts: boolean;
7
+ packageJson: boolean;
8
+ tsconfig: boolean;
9
+ eslint: boolean;
10
+ prettier: boolean;
11
+ editorconfig: boolean;
12
+ vscode: boolean;
13
+ github: boolean;
14
+ gitignore: boolean;
15
+ env: boolean;
16
+ }
17
+
18
+ export const DEFAULT_OPTIONS: InjectionOptions = {
19
+ scripts: true,
20
+ packageJson: true,
21
+ tsconfig: true,
22
+ eslint: true,
23
+ prettier: true,
24
+ editorconfig: true,
25
+ vscode: true,
26
+ github: true,
27
+ gitignore: true,
28
+ env: true
29
+ };
30
+
31
+ const OPTION_DESCRIPTIONS: Record<keyof InjectionOptions, string> = {
32
+ scripts: 'Scripts (esbuild.config.ts, acp.ts, utils.ts, etc.)',
33
+ packageJson: 'package.json (scripts & dependencies)',
34
+ tsconfig: 'tsconfig.json',
35
+ eslint: 'eslint.config.mts',
36
+ prettier: '.prettierrc & .prettierignore',
37
+ editorconfig: '.editorconfig',
38
+ vscode: '.vscode/ (settings.json, tasks.json, extensions.json)',
39
+ github: '.github/workflows/ (release workflow)',
40
+ gitignore: '.gitignore',
41
+ env: '.env (template)'
42
+ };
43
+
44
+ /**
45
+ * Ask user to select which files to inject
46
+ */
47
+ export async function askInjectionOptions(
48
+ rl: Interface
49
+ ): Promise<InjectionOptions> {
50
+ const { askConfirmation } = await import('./utils.js');
51
+
52
+ console.log(`\nšŸŽÆ Injection Options`);
53
+ console.log(`Select what you want to inject (default: all)\n`);
54
+
55
+ const useDefaults = await askConfirmation(
56
+ 'Use default options (inject everything)?',
57
+ rl
58
+ );
59
+
60
+ if (useDefaults) {
61
+ console.log(`āœ… Using default options (all files will be injected)`);
62
+ return DEFAULT_OPTIONS;
63
+ }
64
+
65
+ console.log(`\nšŸ“‹ Select individual options:\n`);
66
+
67
+ const options: InjectionOptions = { ...DEFAULT_OPTIONS };
68
+
69
+ for (const [key, description] of Object.entries(OPTION_DESCRIPTIONS)) {
70
+ const optionKey = key as keyof InjectionOptions;
71
+ const answer = await askConfirmation(`Inject ${description}?`, rl);
72
+ options[optionKey] = answer;
73
+ }
74
+
75
+ // Display summary
76
+ console.log(`\nšŸ“‹ Selected options:`);
77
+ for (const [key, value] of Object.entries(options)) {
78
+ const optionKey = key as keyof InjectionOptions;
79
+ const icon = value ? 'āœ…' : 'āŒ';
80
+ console.log(` ${icon} ${OPTION_DESCRIPTIONS[optionKey]}`);
81
+ }
82
+
83
+ const confirm = await askConfirmation('\nProceed with these options?', rl);
84
+ if (!confirm) {
85
+ console.log('āŒ Injection cancelled');
86
+ process.exit(0);
87
+ }
88
+
89
+ return options;
90
+ }
91
+
92
+ /**
93
+ * Get quick preset options
94
+ */
95
+ export function getPresetOptions(preset: string): InjectionOptions {
96
+ switch (preset) {
97
+ case 'minimal':
98
+ return {
99
+ scripts: true,
100
+ packageJson: true,
101
+ tsconfig: false,
102
+ eslint: false,
103
+ prettier: false,
104
+ editorconfig: false,
105
+ vscode: false,
106
+ github: false,
107
+ gitignore: false,
108
+ env: true
109
+ };
110
+ case 'scripts-only':
111
+ return {
112
+ scripts: true,
113
+ packageJson: false,
114
+ tsconfig: false,
115
+ eslint: false,
116
+ prettier: false,
117
+ editorconfig: false,
118
+ vscode: false,
119
+ github: false,
120
+ gitignore: false,
121
+ env: false
122
+ };
123
+ case 'config-only':
124
+ return {
125
+ scripts: false,
126
+ packageJson: false,
127
+ tsconfig: true,
128
+ eslint: true,
129
+ prettier: true,
130
+ editorconfig: true,
131
+ vscode: true,
132
+ github: false,
133
+ gitignore: true,
134
+ env: false
135
+ };
136
+ default:
137
+ return DEFAULT_OPTIONS;
138
+ }
139
+ }
@@ -11,6 +11,7 @@ import {
11
11
  showInjectionPlan
12
12
  } from './inject-core.js';
13
13
  import { createReadlineInterface, isValidPath } from './utils.js';
14
+ import { askInjectionOptions, DEFAULT_OPTIONS, getPresetOptions } from './inject-options.js';
14
15
 
15
16
  const rl = createReadlineInterface();
16
17
 
@@ -23,15 +24,19 @@ async function main(): Promise<void> {
23
24
  const autoConfirm = args.includes('--yes') || args.includes('-y');
24
25
  const dryRun = args.includes('--dry-run') || args.includes('--check');
25
26
  const useSass = args.includes('--sass');
27
+ const interactive = args.includes('--interactive') || args.includes('-i');
28
+ const preset = args.find(arg => arg.startsWith('--preset='))?.split('=')[1];
26
29
  const targetPath = args.find((arg) => !arg.startsWith('-'));
27
30
 
28
31
  if (!targetPath) {
29
32
  console.error(`āŒ Usage: yarn inject-path <plugin-directory> [options]`);
30
33
  console.error(` Example: yarn inject-path ../my-obsidian-plugin`);
31
34
  console.error(` Options:`);
32
- console.error(` --yes, -y Auto-confirm injection`);
33
- console.error(` --dry-run Check only (no injection)`);
34
- console.error(` --sass Add esbuild-sass-plugin dependency`);
35
+ console.error(` --yes, -y Auto-confirm injection`);
36
+ console.error(` --dry-run Check only (no injection)`);
37
+ console.error(` --sass Add esbuild-sass-plugin dependency`);
38
+ console.error(` --interactive, -i Choose what to inject`);
39
+ console.error(` --preset=<name> Use preset (minimal, scripts-only, config-only)`);
35
40
  console.error(` Shortcuts:`);
36
41
  console.error(` yarn check-plugin ../plugin # Verification only`);
37
42
  process.exit(1);
@@ -150,7 +155,16 @@ async function main(): Promise<void> {
150
155
  process.exit(0);
151
156
  }
152
157
 
153
- await performInjection(resolvedPath, useSass);
158
+ // Get injection options
159
+ let options = DEFAULT_OPTIONS;
160
+ if (preset) {
161
+ options = getPresetOptions(preset);
162
+ console.log(`\nšŸŽÆ Using preset: ${preset}`);
163
+ } else if (interactive) {
164
+ options = await askInjectionOptions(rl);
165
+ }
166
+
167
+ await performInjection(resolvedPath, options, useSass);
154
168
  } catch (error) {
155
169
  console.error(
156
170
  `šŸ’„ Error: ${error instanceof Error ? error.message : String(error)}`
@@ -14,6 +14,7 @@ import {
14
14
  createReadlineInterface,
15
15
  isValidPath
16
16
  } from './utils.js';
17
+ import { DEFAULT_OPTIONS } from './inject-options.js';
17
18
 
18
19
  const rl = createReadlineInterface();
19
20
 
@@ -95,7 +96,7 @@ async function main(): Promise<void> {
95
96
  process.exit(0);
96
97
  }
97
98
 
98
- await performInjection(targetPath, useSass);
99
+ await performInjection(targetPath, DEFAULT_OPTIONS, useSass);
99
100
  } catch (error) {
100
101
  console.error(
101
102
  `šŸ’„ Error: ${error instanceof Error ? error.message : String(error)}`
@@ -52,10 +52,7 @@ async function updateJsonFile(
52
52
 
53
53
  async function updateConfigVersions(targetVersion: string): Promise<void> {
54
54
  try {
55
- await Promise.all([
56
- updateJsonFile('package.json', (json) => (json.version = targetVersion)),
57
- updateJsonFile('versions.json', (json) => (json[targetVersion] = '1.8.9'))
58
- ]);
55
+ await updateJsonFile('package.json', (json) => (json.version = targetVersion));
59
56
  } catch (error) {
60
57
  console.error(
61
58
  'Error updating config versions:',
@@ -81,7 +78,7 @@ async function updateVersion(): Promise<void> {
81
78
  console.log(`Files updated to version ${targetVersion}`);
82
79
 
83
80
  // Add files to git
84
- gitExec('git add package.json versions.json');
81
+ gitExec('git add package.json');
85
82
  gitExec(`git commit -m "Updated to version ${targetVersion}"`);
86
83
  console.log('Changes committed');
87
84
  } catch (error) {
@@ -0,0 +1,4 @@
1
+ # On Windows, git defaults to core.autocrlf=true which converts LF to CRLF and creates false modifications
2
+ * text=auto eol=lf
3
+ *.ts text eol=lf
4
+ *.json text eol=lf
@@ -16,7 +16,7 @@ jobs:
16
16
  - name: Use Node.js
17
17
  uses: actions/setup-node@v3
18
18
  with:
19
- node-version: "20.x"
19
+ node-version: "22.x"
20
20
 
21
21
  # Setup Yarn
22
22
  - name: Setup Yarn
@@ -0,0 +1,6 @@
1
+ # Build output
2
+ dist/
3
+ main.js
4
+
5
+ # Dependencies
6
+ node_modules/
@@ -0,0 +1,8 @@
1
+ {
2
+ "recommendations": [
3
+ "esbenp.prettier-vscode",
4
+ "dbaeumer.vscode-eslint",
5
+ "editorconfig.editorconfig",
6
+ "yzhang.markdown-all-in-one"
7
+ ]
8
+ }
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "npm.packageManager": "yarn",
3
- // "js/ts.preferences.includePackageJsonAutoImports": "off",
4
3
  "[typescript]": {
5
4
  "editor.defaultFormatter": "esbenp.prettier-vscode"
6
5
  },
@@ -19,8 +19,8 @@
19
19
  "h": "tsx scripts/help.ts",
20
20
  "lint": "eslint . --ext .ts",
21
21
  "lint:fix": "eslint . --ext .ts --fix",
22
- "prettier": "npx prettier --check '**/*.{ts,json}'",
23
- "prettier:fix": "npx prettier --write '**/*.{ts,json}'"
22
+ "prettier": "prettier --check '**/*.{ts,json}'",
23
+ "prettier:fix": "prettier --write '**/*.{ts,json}'"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/eslint": "latest",
@@ -38,6 +38,7 @@
38
38
  "obsidian": "*",
39
39
  "obsidian-typings": "latest",
40
40
  "prettier": "latest",
41
+ "tslib": "2.4.0",
41
42
  "semver": "latest",
42
43
  "tsx": "^4.21.0",
43
44
  "typescript": "^5.8.2"
@@ -143,7 +143,16 @@ async function validateEnvironment(): Promise<void> {
143
143
  }
144
144
 
145
145
  async function getBuildPath(isProd: boolean): Promise<string> {
146
- // Check if we should use real vault (either -r flag or "real" argument)
146
+ // Check if we're already inside an Obsidian plugins folder
147
+ const pluginsPath = path.join('.obsidian', 'plugins');
148
+ const isInPluginsFolder = pluginDir.includes(pluginsPath);
149
+
150
+ if (isInPluginsFolder) {
151
+ console.log('ā„¹ļø Building in Obsidian plugins folder (in-place development)');
152
+ return pluginDir;
153
+ }
154
+
155
+ // External development: check for vault paths
147
156
  const useRealVault = process.argv.includes('-r') || process.argv.includes('real');
148
157
 
149
158
  // If production build without redirection, return plugin directory
@@ -155,28 +164,14 @@ async function getBuildPath(isProd: boolean): Promise<string> {
155
164
  const envKey = useRealVault ? 'REAL_VAULT' : 'TEST_VAULT';
156
165
  const vaultPath = process.env[envKey]?.trim();
157
166
 
158
- // If empty or undefined, we're already in the plugin folder
159
- if (!vaultPath) {
160
- // Check if we're in Obsidian plugins folder
161
- const currentPath = process.cwd();
162
- const isInObsidianPlugins =
163
- currentPath.includes('.obsidian/plugins') ||
164
- currentPath.includes('.obsidian\\plugins');
165
-
166
- if (isInObsidianPlugins) {
167
- // In obsidian/plugins: allow in-place development
168
- console.log(`ā„¹ļø Building in Obsidian plugins folder (in-place development)`);
169
- return pluginDir;
170
- } else {
171
- // External development: prompt for missing vault path
172
- const newPath = await promptForVaultPath(envKey);
173
- await updateEnvFile(envKey, newPath);
174
- config();
175
- return getVaultPath(newPath);
176
- }
167
+ // If empty or undefined, prompt for vault path
168
+ if (!vaultPath || vaultPath.startsWith('/path/to/your/')) {
169
+ const newPath = await promptForVaultPath(envKey);
170
+ await updateEnvFile(envKey, newPath);
171
+ config();
172
+ return getVaultPath(newPath);
177
173
  }
178
174
 
179
- // If we reach here, use the vault path directly
180
175
  return getVaultPath(vaultPath);
181
176
  }
182
177
 
package/tsconfig.json CHANGED
@@ -1,12 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "types": ["obsidian-typings"],
4
- "paths": {
5
- "obsidian-typings/implementations": [
6
- "./node_modules/obsidian-typings/dist/cjs/implementations.d.cts",
7
- "./node_modules/obsidian-typings/dist/esm/implementations.mjs"
8
- ]
9
- },
3
+ "types": ["node"],
10
4
  "inlineSourceMap": true,
11
5
  "inlineSources": true,
12
6
  "module": "NodeNext",
@@ -25,6 +19,6 @@
25
19
  "resolveJsonModule": true,
26
20
  "lib": ["DOM", "ES2021"]
27
21
  },
28
- "include": ["./src/**/*.ts", "./scripts/**/*.ts"],
22
+ "include": ["./scripts/**/*.ts"],
29
23
  "exclude": ["node_modules", "eslint.config.ts"]
30
24
  }
@@ -1,5 +0,0 @@
1
- {
2
- "injectorVersion": "1.1.20",
3
- "injectionDate": "2025-07-18T22:04:30.392Z",
4
- "injectorName": "obsidian-plugin-config"
5
- }
@@ -1,164 +0,0 @@
1
- # NPM Exports — How it works
2
-
3
- ## The two roles of this repo
4
-
5
- ### 1. Injection system (primary)
6
-
7
- The injection system copies scripts and config files
8
- **directly into target plugins**. After injection,
9
- the plugin is **100% standalone**.
10
-
11
- ```
12
- templates/ → target-plugin/
13
- scripts/utils.ts → scripts/utils.ts
14
- scripts/esbuild... → scripts/esbuild...
15
- tsconfig.json → tsconfig.json
16
- .gitignore → .gitignore
17
- ...
18
- ```
19
-
20
- ### 2. Exportable snippets (complementary)
21
-
22
- The `src/` directory contains reusable code
23
- (modals, helpers, utilities) that can be imported
24
- by other plugins via the NPM package.
25
-
26
- **These two systems are complementary, not opposed.**
27
- Injection provides the base infrastructure.
28
- Exports provide optional reusable components.
29
-
30
- ---
31
-
32
- ## How NPM exports work
33
-
34
- The `exports` field in `package.json`:
35
- ```json
36
- {
37
- "exports": {
38
- ".": "./src/index.ts"
39
- }
40
- }
41
- ```
42
-
43
- This single entry is enough. `src/index.ts`
44
- re-exports everything from all submodules.
45
-
46
- ### Importing in another plugin
47
-
48
- ```ts
49
- // Import what you need
50
- import {
51
- showConfirmModal,
52
- NoticeHelper,
53
- SettingsHelper
54
- } from "obsidian-plugin-config";
55
- ```
56
-
57
- That's it. One import path covers everything.
58
-
59
- ### What `update-exports` does
60
-
61
- Running `yarn update-exports` (or `yarn ue`):
62
-
63
- 1. **Scans `src/` subdirectories** for folders
64
- containing an `index.ts` file
65
- 2. **Regenerates `src/index.ts`** with
66
- `export * from` for each found module
67
- 3. **Updates `package.json` `exports`** field
68
-
69
- Example: Adding `src/components/index.ts` and
70
- running `update-exports` will add:
71
- ```ts
72
- // In src/index.ts:
73
- export * from './components/index.js';
74
- ```
75
-
76
- ---
77
-
78
- ## Local development
79
-
80
- This repo also works as an Obsidian plugin for
81
- testing purposes. The `src/main.ts` loads a
82
- sample plugin that exercises the exportable code.
83
-
84
- ### Why keep obsidian + obsidian-typings locally?
85
-
86
- The snippets in `src/` use Obsidian's API (modals,
87
- settings, notices). To develop and test these
88
- snippets, you need the Obsidian types available.
89
-
90
- You can:
91
- - Run `yarn build` to check for type errors
92
- - Run `yarn dev` to test in a vault
93
- - **Never** release this as a real plugin
94
-
95
- ### Workflow for adding new snippets
96
-
97
- 1. Create your module in `src/mymodule/`
98
- 2. Add an `index.ts` that exports everything
99
- 3. Run `yarn update-exports` to update the barrel
100
- 4. Test locally with `yarn dev`
101
- 5. When ready, publish via `yarn npm-publish`
102
-
103
- ---
104
-
105
- ## Injection scripts explained
106
-
107
- ### `inject-path.ts` — Direct injection
108
-
109
- Options:
110
- - `--yes` / `-y` : Skip confirmation
111
- - `--sass` : Include SASS support
112
- - `--dry-run` / `--check` : Preview only
113
-
114
- ### `inject-prompt.ts` — Interactive injection
115
-
116
- Prompts for target path and confirmation.
117
-
118
- ### `obsidian-inject` CLI (global)
119
-
120
- ```bash
121
- npm install -g obsidian-plugin-config
122
- obsidian-inject # Current dir
123
- obsidian-inject ../my-plugin # By path
124
- obsidian-inject ../my-plugin --sass # With SASS
125
- ```
126
-
127
- ### `build-npm.ts` — NPM publish workflow
128
-
129
- Automates: version → commit → push → exports →
130
- bin → publish.
131
-
132
- > **Tip**: Run `npm login` first, or visit
133
- > https://www.npmjs.com/ to get your auth token.
134
-
135
- ### `update-exports.js` — Refresh exports
136
-
137
- Scans `src/` and regenerates `src/index.ts` and
138
- the `exports` field in `package.json`.
139
-
140
- ---
141
-
142
- ## SASS support
143
-
144
- The template `esbuild.config.ts` handles SASS
145
- automatically via dynamic import:
146
- ```ts
147
- const { sassPlugin } =
148
- await import('esbuild-sass-plugin');
149
- ```
150
-
151
- If `.scss` files are detected in `src/`, the SASS
152
- plugin is loaded. If not installed, it warns you.
153
-
154
- The `--sass` injection flag adds
155
- `esbuild-sass-plugin` to the target's dependencies.
156
-
157
- ---
158
-
159
- ## Svelte support (planned)
160
-
161
- Not yet implemented. Would require:
162
- - `esbuild-svelte` package
163
- - `svelte` compiler
164
- - Detection of `.svelte` files in esbuild config
package/manifest.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "id": "obsidian-plugin-config",
3
- "name": "Obsidian Plugin Config",
4
- "version": "1.0.0",
5
- "minAppVersion": "0.15.0",
6
- "description": "Development and testing environment for obsidian-plugin-config NPM exports and injection system",
7
- "author": "3C0D",
8
- "authorUrl": "",
9
- "fundingUrl": "",
10
- "isDesktopOnly": false
11
- }