obsidian-plugin-config 1.7.3 → 1.7.5

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/README.md CHANGED
@@ -28,9 +28,9 @@ obsidian-inject
28
28
  # Prompts for confirmation before replacing each existing file
29
29
  obsidian-inject ../my-plugin
30
30
 
31
- # Inject without confirmation
32
- # Auto-confirms all file replacements (no prompts)
33
- obsidian-inject ../my-plugin --no
31
+ # Inject without confirmation
32
+ # Auto-confirms all file replacements (no prompts)
33
+ obsidian-inject ../my-plugin --yes
34
34
 
35
35
  # Verification only (dry-run)
36
36
  # Shows what would be injected without making any changes
@@ -40,10 +40,10 @@ obsidian-inject ../my-plugin --dry-run
40
40
  obsidian-inject --help
41
41
  ```
42
42
 
43
- ## CLI Options
44
-
45
- - `--no`, `-n` - Skip confirmation prompts (auto-confirm)
46
- - `--dry-run` - Verification only (no changes)
43
+ ## CLI Options
44
+
45
+ - `--yes`, `-y` - Skip confirmation prompts (auto-confirm)
46
+ - `--dry-run` - Verification only (no changes)
47
47
 
48
48
  ## What is injected
49
49
 
@@ -3,13 +3,13 @@
3
3
  /**
4
4
  * Obsidian Plugin Config - CLI Entry Point
5
5
  * Global command: obsidian-inject
6
- * Version: 1.7.3
6
+ * Version: 1.7.5
7
7
  */
8
8
 
9
9
  import { execSync } from 'child_process';
10
10
  import { fileURLToPath } from 'url';
11
11
  import { dirname, join, isAbsolute, resolve } from 'path';
12
- import fs from 'fs';
12
+ import { readFile, access, unlink, rm } from 'fs/promises';
13
13
 
14
14
  // Get the directory of this script
15
15
  const __filename = fileURLToPath(import.meta.url);
@@ -19,6 +19,15 @@ const packageRoot = dirname(__dirname);
19
19
  // Path to the injection script
20
20
  const injectScriptPath = join(packageRoot, 'scripts', 'inject-path.ts');
21
21
 
22
+ async function pathExists(p) {
23
+ try {
24
+ await access(p);
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+
22
31
  function showHelp() {
23
32
  console.log(`
24
33
  Obsidian Plugin Config - Global CLI
@@ -56,7 +65,7 @@ More info: https://github.com/3C0D/obsidian-plugin-config
56
65
  `);
57
66
  }
58
67
 
59
- function main() {
68
+ async function main() {
60
69
  const args = process.argv.slice(2);
61
70
 
62
71
  // Handle help flags
@@ -66,7 +75,7 @@ function main() {
66
75
  }
67
76
 
68
77
  // Check if injection script exists
69
- if (!fs.existsSync(injectScriptPath)) {
78
+ if (!(await pathExists(injectScriptPath))) {
70
79
  console.error(`❌ Error: Injection script not found at ${injectScriptPath}`);
71
80
  console.error(` Make sure obsidian-plugin-config is properly installed.`);
72
81
  process.exit(1);
@@ -94,14 +103,14 @@ function main() {
94
103
  try {
95
104
  // Check if target directory has package.json
96
105
  const targetPackageJson = join(targetPath, 'package.json');
97
- if (!fs.existsSync(targetPackageJson)) {
106
+ if (!(await pathExists(targetPackageJson))) {
98
107
  console.error(`❌ Error: package.json not found in ${targetPath}`);
99
108
  console.error(` Make sure this is a valid Node.js project.`);
100
109
  process.exit(1);
101
110
  }
102
111
 
103
112
  // Prevent injecting into obsidian-plugin-config itself
104
- const pkg = JSON.parse(fs.readFileSync(targetPackageJson, 'utf8'));
113
+ const pkg = JSON.parse(await readFile(targetPackageJson, 'utf8'));
105
114
  if (pkg.name === 'obsidian-plugin-config') {
106
115
  console.error(`❌ Cannot inject into obsidian-plugin-config itself.`);
107
116
  process.exit(1);
@@ -109,25 +118,25 @@ function main() {
109
118
 
110
119
  // Clean NPM artifacts if package-lock.json exists
111
120
  const packageLockPath = join(targetPath, 'package-lock.json');
112
- if (fs.existsSync(packageLockPath)) {
121
+ if (await pathExists(packageLockPath)) {
113
122
  console.log(`🧹 NPM installation detected, cleaning...`);
114
123
 
115
124
  try {
116
125
  // Remove package-lock.json
117
- fs.unlinkSync(packageLockPath);
126
+ await unlink(packageLockPath);
118
127
  console.log(` 🗑️ package-lock.json removed`);
119
128
 
120
129
  // Remove node_modules if it exists
121
130
  const nodeModulesPath = join(targetPath, 'node_modules');
122
- if (fs.existsSync(nodeModulesPath)) {
123
- fs.rmSync(nodeModulesPath, { recursive: true, force: true });
131
+ if (await pathExists(nodeModulesPath)) {
132
+ await rm(nodeModulesPath, { recursive: true, force: true });
124
133
  console.log(` 🗑️ node_modules removed (will be reinstalled with Yarn)`);
125
134
  }
126
135
 
127
136
  console.log(` ✅ NPM artifacts cleaned to avoid Yarn conflicts`);
128
137
 
129
138
  } catch (cleanError) {
130
- console.error(` ❌ Cleanup failed:`, cleanError.message);
139
+ console.error(` ❌ Cleanup failed:`, cleanError instanceof Error ? cleanError.message : String(cleanError));
131
140
  console.log(` 💡 Manually remove package-lock.json and node_modules`);
132
141
  }
133
142
  }
@@ -174,5 +183,4 @@ function main() {
174
183
  }
175
184
  }
176
185
 
177
- // Run the CLI
178
- main();
186
+ main().catch(console.error);
@@ -1,76 +1,67 @@
1
- # Injection interactive
1
+ # Interactive Injection
2
2
 
3
- L'injection est **interactive par défaut** : elle compare chaque fichier du template
4
- avec le fichier existant de la cible et ne demande confirmation que lorsque le contenu
5
- diffère.
3
+ Injection is **interactive by default**: it compares each template file with the target's existing file and only prompts for confirmation when the content differs.
6
4
 
7
- ## Points d'entrée
5
+ ## Entry Points
8
6
 
9
7
  ```bash
10
- # CLI globale
11
- obsidian-inject # Injection dans le dossier courant
12
- obsidian-inject ../my-plugin # Injection par chemin
13
-
14
- # Scripts locaux (développement de ce repo)
15
- yarn inject-prompt # Demande le chemin du plugin cible, puis injecte
16
- yarn inject-path ../my-plugin # Injection directe par chemin
17
- yarn check-plugin ../my-plugin # Dry-run (vérification seule, aucune modification)
8
+ # Global CLI
9
+ obsidian-inject # Inject in current directory
10
+ obsidian-inject ../my-plugin # Inject by path
11
+
12
+ # Local scripts (development of this repo)
13
+ yarn inject-prompt # Prompts for target plugin path, then injects
14
+ yarn inject-path ../my-plugin # Direct injection by path
15
+ yarn check-plugin ../my-plugin # Dry-run (verification only, no modifications)
18
16
  ```
19
17
 
20
- ## Comportement fichier par fichier
18
+ ## File-by-File Behavior
21
19
 
22
- Pendant l'injection, chaque fichier est traité ainsi :
20
+ During injection, each file is handled as follows:
23
21
 
24
- - **La cible n'existe pas encore** → le fichier est injecté sans demander.
25
- - **Contenu identique** → ignoré silencieusement (`✅ ... (unchanged)`).
26
- - **Contenu différent** → l'outil demande `Update <fichier>? (content differs)`.
27
- - `y` → le fichier est remplacé.
28
- - `n` → le fichier existant est conservé (`⏭️ Kept existing ...`).
22
+ - **Target does not exist yet** → the file is injected without asking.
23
+ - **Identical content** → silently ignored (`✅ ... (unchanged)`).
24
+ - **Different content** → the tool asks `Update <file>? (content differs)`.
25
+ - `y` → the file is replaced.
26
+ - `n` → the existing file is kept (`⏭️ Kept existing ...`).
29
27
 
30
- Cas particuliers :
28
+ Special cases:
31
29
 
32
- - `.env` est toujours **fusionné** : le template est réécrit en préservant les
33
- valeurs déjà renseignées (chemins de vault, etc.).
34
- - `.npmrc` est toujours injecté (protection Yarn).
35
- - `eslint.config.mts` est approuvé automatiquement si un ancien `.eslintrc*`
36
- est détecté (migration depuis l'ancien format).
30
+ - `.env` is always **merged**: the template is rewritten while preserving existing values (vault paths, etc.).
31
+ - `.npmrc` is always injected (Yarn protection).
32
+ - `eslint.config.mts` is automatically approved if an old `.eslintrc*` is detected (migration from the old format).
37
33
 
38
34
  ## Options
39
35
 
40
36
  ```bash
41
- # Auto-confirmer tous les remplacements (aucune question)
42
- obsidian-inject ../my-plugin --no # CLI globale : --no / -n
43
- yarn inject-path ../my-plugin --yes # Scripts locaux : --yes / -y
37
+ # Auto-confirm all replacements (no questions)
38
+ obsidian-inject ../my-plugin --yes # Global CLI: --yes / -y
39
+ yarn inject-path ../my-plugin --yes # Local scripts: --yes / -y
44
40
 
45
- # Vérification seule (n'écrit rien)
41
+ # Verification only (writes nothing)
46
42
  obsidian-inject ../my-plugin --dry-run
47
43
  ```
48
44
 
49
- | Option | Effet |
50
- | ---------------- | -------------------------------------------------- |
51
- | `--no`, `-n` | (CLI globale) auto-confirme tous les remplacements |
52
- | `--yes`, `-y` | (scripts locaux) auto-confirme tous les remplacements |
53
- | `--dry-run` | vérification seule, aucune modification |
45
+ | Option | Effect |
46
+ | ------------- | ---------------------------------------------- |
47
+ | `--yes`, `-y` | (Global CLI) auto-confirms all replacements |
48
+ | `--yes`, `-y` | (Local scripts) auto-confirms all replacements |
49
+ | `--dry-run` | Verification only, no modifications |
54
50
 
55
- ## Ce qui est injecté
51
+ ## What is Injected
56
52
 
57
- Tous les fichiers du template sont pris en compte à chaque injection (pas de
58
- sélection par composant) :
53
+ All template files are considered during each injection (no component selection):
59
54
 
60
- - `templates/scripts/*` → `<cible>/scripts/`
61
- - `templates/tsconfig.json.template`, `eslint.config.mts`, `.editorconfig`,
62
- `.prettierrc`, `.prettierignore`, `.npmrc`, `.env`
55
+ - `templates/scripts/*` → `<target>/scripts/`
56
+ - `templates/tsconfig.json.template`, `eslint.config.mts`, `.editorconfig`, `.prettierrc`, `.prettierignore`, `.npmrc`, `.env`
63
57
  - `templates/.vscode/*`
64
58
  - `templates/.github/workflows/*`
65
- - `templates/gitignore.template` → `<cible>/.gitignore`
59
+ - `templates/gitignore.template` → `<target>/.gitignore`
66
60
 
67
- La confirmation fichier par fichier permet de conserver un fichier existant
68
- (par exemple un `esbuild.config.ts` personnalisé) en répondant `n` lorsque la
69
- question apparaît.
61
+ File-by-file confirmation allows keeping an existing file (for example, a custom `esbuild.config.ts`) by answering `n` when the prompt appears.
70
62
 
71
- ## Fichiers concernés
63
+ ## Related Files
72
64
 
73
- 1. **scripts/inject-core.ts** — logique d'injection (`diffAndPromptFiles`,
74
- `injectScripts`, `updatePackageJson`, `performInjection`).
75
- 2. **scripts/inject-prompt.ts** — entrée interactive (demande le chemin).
76
- 3. **scripts/inject-path.ts** — entrée CLI (parse `--yes`, `--dry-run`).
65
+ 1. **scripts/inject-core.ts** — injection logic (`diffAndPromptFiles`, `injectScripts`, `updatePackageJson`, `performInjection`).
66
+ 2. **scripts/inject-prompt.ts** — interactive entry (prompts for path).
67
+ 3. **scripts/inject-path.ts** — CLI entry (parses `--yes`, `--dry-run`).
package/docs/SCSS-FLOW.md CHANGED
@@ -1,47 +1,48 @@
1
- # Comment fonctionne SCSS dans cette config
1
+ # How SCSS Works in this Config
2
2
 
3
- Ce document explique de bout en bout comment un fichier `.scss` est détecté, compilé puis copié dans le dossier `plugins` d'Obsidian, en s'appuyant sur le code du dépôt.
3
+ This document explains end-to-end how a `.scss` file is detected, compiled, and then copied into the Obsidian `plugins` folder, based on the repository's code.
4
4
 
5
- > Remarque : la configuration SCSS n'est pas activée dans `obsidian-plugin-config` lui-même. Elle est définie dans les **templates** qui sont copiés dans chaque plugin Obsidian lors de l'injection (`yarn inject` / `obsidian-inject`). Tout le code cité ci-dessous vit donc dans `templates/scripts/`.
5
+ > Note: SCSS configuration is not enabled in `obsidian-plugin-config` itself. It is defined in the **templates** that are copied into each Obsidian plugin during injection (`yarn inject` / `obsidian-inject`). All the code cited below resides in `templates/scripts/`.
6
6
 
7
7
  ---
8
8
 
9
- ## 1. Vue d'ensemble du flux
9
+ ## 1. Flow Overview
10
10
 
11
11
  ```
12
12
  src/styles.scss
13
13
 
14
- détection (esbuild.config.ts → main())
14
+ detection (esbuild.config.ts → main())
15
15
 
16
16
  entryPoints = [src/main.ts, src/styles.scss]
17
17
 
18
18
  │ esbuild.context() + sassPlugin() (esbuild.config.ts → createBuildContext)
19
+ │ outbase: src/ → styles.scss → styles.css (name derived from entry, not main.ts)
19
20
 
20
- buildPath/<id>/
21
+ buildPath/
21
22
  ├── main.js
22
- └── main.css produit par esbuild-sass-plugin
23
+ └── styles.css produced directly by esbuild+sassPlugin
23
24
 
24
- │ plugin "remove-main-css" (esbuild.config.ts) utils.removeMainCss
25
- + plugin "copy-to-plugins-folder" (esbuild.config.ts) → utils.copyFilesToTargetDir
25
+ │ plugin "rename-main-css" → utils.renameMainCss (no-op safety net: main.css does not exist)
26
+ │ plugin "copy-to-plugins-folder" → utils.copyFilesToTargetDir (manifest only if SCSS)
26
27
 
27
- buildPath/<id>/
28
- ├── manifest.json (copié)
28
+ buildPath/
29
+ ├── manifest.json (copied)
29
30
  ├── main.js
30
- └── styles.css ← renommé depuis main.css ? non : voir point 3
31
+ └── styles.css ← already in place, no renaming necessary
31
32
  ```
32
33
 
33
- Les deux moments clés sont :
34
+ The two key moments are:
34
35
 
35
- 1. **Détection et compilation** dans `templates/scripts/esbuild.config.ts`.
36
- 2. **Nettoyage et copie vers le dossier plugins** via les fonctions utilitaires de `templates/scripts/utils.ts`.
36
+ 1. **Detection and compilation** in `templates/scripts/esbuild.config.ts`.
37
+ 2. **Cleanup and copying to the plugins folder** via utility functions in `templates/scripts/utils.ts`.
37
38
 
38
39
  ---
39
40
 
40
- ## 2. passe le fichier SCSS
41
+ ## 2. SCSS File Path
41
42
 
42
- ### 2.1 Détection du fichier SCSS
43
+ ### 2.1 SCSS File Detection
43
44
 
44
- Dans `templates/scripts/esbuild.config.ts`, fonction `main()` (lignes 115-140) :
45
+ In `templates/scripts/esbuild.config.ts`, `main()` function:
45
46
 
46
47
  ```ts
47
48
  // Check for SCSS first, then CSS in src, then in root
@@ -63,40 +64,29 @@ const entryPoints = stylePath ? [mainTsPath, stylePath] : [mainTsPath];
63
64
  const context = await createBuildContext(buildPath, isProd, entryPoints, scssExists);
64
65
  ```
65
66
 
66
- - Le fichier SCSS est donc attendu à `src/styles.scss` (priorité maximale).
67
- - Sinon, fallback sur `src/styles.css` puis `styles.css` à la racine.
68
- - `scssExists` (booléen) sert ensuite à activer ou non le plugin SASS dans esbuild.
67
+ - The SCSS file is expected at `src/styles.scss` (highest priority).
68
+ - Otherwise, it falls back to `src/styles.css` then `styles.css` at the root.
69
+ - `scssExists` (boolean) is then used to enable or disable the SASS plugin in esbuild.
69
70
 
70
71
  ### 2.2 Compilation via esbuild + sassPlugin
71
72
 
72
- Toujours dans `templates/scripts/esbuild.config.ts`, fonction `createBuildContext()` (lignes 33-69) :
73
+ Also in `templates/scripts/esbuild.config.ts`, `createBuildContext()` function:
73
74
 
74
75
  ```ts
75
76
  const plugins = [
76
- // Add SASS plugin if SCSS files are detected
77
77
  ...(hasSass
78
78
  ? [
79
79
  await (async () => {
80
- try {
81
- // @ts-expect-error - esbuild-sass-plugin is installed during injection
82
- const { sassPlugin } = await import('esbuild-sass-plugin');
83
- return sassPlugin({
84
- syntax: 'scss',
85
- style: 'expanded'
86
- });
87
- } catch (error) {
88
- console.warn(
89
- '⚠️ esbuild-sass-plugin not found. Install it with: yarn add -D esbuild-sass-plugin'
90
- );
91
- throw error;
92
- }
80
+ // @ts-expect-error - esbuild-sass-plugin is installed during injection
81
+ const { sassPlugin } = await import('esbuild-sass-plugin');
82
+ return sassPlugin({ syntax: 'scss', style: 'expanded' });
93
83
  })(),
94
84
  {
95
- name: 'remove-main-css',
85
+ name: 'rename-main-css',
96
86
  setup(build: esbuild.PluginBuild): void {
97
87
  build.onEnd(async (result) => {
98
88
  if (result.errors.length === 0) {
99
- await removeMainCss(buildPath);
89
+ await renameMainCss(buildPath);
100
90
  }
101
91
  });
102
92
  }
@@ -105,48 +95,48 @@ const plugins = [
105
95
  : []),
106
96
  ```
107
97
 
108
- - Le `sassPlugin` n'est importé que si `hasSass` est `true` (donc si `src/styles.scss` existe).
109
- - Il est configuré en syntaxe `scss` et style `expanded` (non minifié, lisible).
110
- - esbuild produit un fichier `main.css` à côté de `main.js` dans `outdir` (= `buildPath`).
111
- - Un second plugin esbuild interne, `remove-main-css`, supprime ce `main.css` à la fin du build (voir 3.1).
98
+ - The `sassPlugin` is only imported if `hasSass` is `true`.
99
+ - It is configured with `scss` syntax and `expanded` style (not minified on the Sass side; esbuild applies its own minification if `isProd = true`).
100
+ - **Output filename**: esbuild derives the name from the entry point. With `outbase: src/` and entry `src/styles.scss`, the relative path is `styles.scss` output `buildPath/styles.css`. The name `main.ts` does not interfere.
101
+ - The `rename-main-css` plugin is a **safety net**: in the current configuration, `buildPath/main.css` is never created, so `renameMainCss` is a no-op. It protects against future changes in sassPlugin behavior.
112
102
 
113
- ### 2.3 Dépendance : `esbuild-sass-plugin`
103
+ ### 2.3 Dependency: `esbuild-sass-plugin`
114
104
 
115
- - Import dynamique, donc l'installation de la dépendance n'est pas obligatoire pour les plugins qui n'utilisent pas SCSS.
116
- - Le code affiche un warning et échoue si SCSS est détecté mais que le plugin n'est pas installé :
105
+ Dynamic import: installation is not mandatory for plugins without SCSS. If SCSS is detected but the plugin is missing:
117
106
 
118
- > `⚠️ esbuild-sass-plugin not found. Install it with: yarn add -D esbuild-sass-plugin`
107
+ > `⚠️ esbuild-sass-plugin not found. Install it with: yarn add -D esbuild-sass-plugin`
119
108
 
120
- - Côté utilisateur, la doc le précise : `README.md`, section **SASS Support** (lignes 85-96).
109
+ > **Note**: the `.sass` extension (indented syntax) is not supported. Only `.scss` is detected and compiled.
121
110
 
122
111
  ---
123
112
 
124
- ## 3. Comment c'est copié dans le dossier plugins
113
+ ## 3. How it is Copied to the Plugins Folder
125
114
 
126
- ### 3.1 Nettoyage du `main.css` parasite
115
+ ### 3.1 `renameMainCss` — Safety Net (no-op in current SCSS flow)
127
116
 
128
- Dans `templates/scripts/utils.ts`, fonction `removeMainCss()` (lignes 169-180) :
117
+ In `templates/scripts/utils.ts`, `renameMainCss()` function:
129
118
 
130
119
  ```ts
131
- export async function removeMainCss(outdir: string): Promise<void> {
120
+ export async function renameMainCss(outdir: string): Promise<void> {
132
121
  const mainCssPath = path.join(outdir, 'main.css');
122
+ const stylesCssPath = path.join(outdir, 'styles.css');
133
123
  try {
134
- await rm(mainCssPath);
135
- } catch (error: unknown) {
136
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
137
- console.warn(
138
- `Warning: Could not remove main.css: ${error instanceof Error ? error.message : String(error)}`
139
- );
124
+ if (await isValidPath(mainCssPath)) {
125
+ await rename(mainCssPath, stylesCssPath);
140
126
  }
127
+ } catch (error: unknown) {
128
+ console.warn(`Warning: Could not rename main.css to styles.css: ...`);
141
129
  }
142
130
  }
143
131
  ```
144
132
 
145
- Pourquoi ? Le `sassPlugin` d'esbuild génère un fichier `main.css` parce qu'il hérite du `name` (`main`) de l'entry point. Or Obsidian attend `styles.css` dans le dossier du plugin. `removeMainCss` supprime donc ce fichier temporaire immédiatement après chaque build (uniquement si le build n'a pas d'erreur, cf. `if (result.errors.length === 0)` dans `esbuild.config.ts`).
133
+ With `outbase: src/` and entry `src/styles.scss`, esbuild directly produces `buildPath/styles.css`. `buildPath/main.css` is therefore never created, and the `if (await isValidPath(mainCssPath))` check is always false. This function remains as a safeguard if sassPlugin behavior evolves.
134
+
135
+ > **Context of `_.._`**: for the root CSS case (`styles.css` outside `outbase: src/`), esbuild encodes `../styles.css` as `_.._/styles.css`. This is not related to SCSS. `copyFilesToTargetDir` handles this case separately (manual copy + removal of `_.._/`).
146
136
 
147
- ### 3.2 Copie vers le dossier plugins
137
+ ### 3.2 Copying to the Plugins Folder
148
138
 
149
- Dans `templates/scripts/utils.ts`, fonction `copyFilesToTargetDir()` (lignes 74-123) :
139
+ In `templates/scripts/utils.ts`, `copyFilesToTargetDir()` function:
150
140
 
151
141
  ```ts
152
142
  export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
@@ -176,11 +166,11 @@ export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
176
166
  }
177
167
  ```
178
168
 
179
- > Note importante : `copyFilesToTargetDir` ne copie **que** `manifest.json` et un éventuel `styles.css` / `styles.css` racine. Le `main.css` généré par esbuild-sass-plugin est supprimé à l'étape précédente (3.1).
169
+ > Important Note: `copyFilesToTargetDir` only copies `manifest.json` and any potential `styles.css` at the root. The `main.css` generated by esbuild-sass-plugin is renamed to `styles.css` in the previous step (3.1).
180
170
 
181
- ### 3.3 Branchement sur le cycle de vie esbuild
171
+ ### 3.3 Integration into the esbuild Lifecycle
182
172
 
183
- Toujours dans `templates/scripts/esbuild.config.ts`, le plugin `copy-to-plugins-folder` (lignes 70-94) déclenche la copie après chaque build :
173
+ Also in `templates/scripts/esbuild.config.ts`, the `copy-to-plugins-folder` plugin triggers copying after each build:
184
174
 
185
175
  ```ts
186
176
  {
@@ -208,30 +198,30 @@ Toujours dans `templates/scripts/esbuild.config.ts`, le plugin `copy-to-plugins-
208
198
  }
209
199
  ```
210
200
 
211
- - Mode **dev (`yarn dev`)** : après chaque rebuild (watch), `copyFilesToTargetDir` recopie manifest + CSS vers le vault de test.
212
- - Mode **build prod (`yarn build`)** : rien n'est copié par défaut, sauf si on passe `-r` / `real` (=> copie vers le vault de prod + reload Obsidian).
201
+ - **Dev mode (`yarn dev`)**: after each rebuild (watch), `copyFilesToTargetDir` recopies the manifest + CSS to the test vault.
202
+ - **Prod build mode (`yarn build`)**: nothing is copied by default, unless `-r` / `real` is passed (=> copy to production vault + reload Obsidian).
213
203
 
214
- ### 3.4 Cible : `buildPath`
204
+ ### 3.4 Target: `buildPath`
215
205
 
216
- `buildPath` est calculé par `env.ts` (`getBuildPath`) à partir de `.env` (`TEST_VAULT` / `REAL_VAULT`) ou du dossier courant (développement in-place). Il pointe vers :
206
+ `buildPath` is calculated by `env.ts` (`getBuildPath`) from `.env` (`TEST_VAULT` / `REAL_VAULT`) or the current directory (in-place development). It points to:
217
207
 
218
208
  ```
219
209
  <vault>/.obsidian/plugins/<pluginId>/
220
210
  ```
221
211
 
222
- Donc concrètement, le résultat final pour le SCSS est :
212
+ So concretely, the final result for SCSS is:
223
213
 
224
- 1. `src/styles.scss` → compilé par esbuild-sass-plugin → `buildPath/main.css` (transitoire)
225
- 2. `main.css` renommé en `styles.css` par `renameMainCss`
226
- 3. Le CSS est directement disponible et référencé via `manifest.json` (`"css": "styles.css"`).
214
+ 1. `src/styles.scss` → compiled by esbuild-sass-plugin → `buildPath/main.css` (transient)
215
+ 2. `main.css` renamed to `styles.css` by `renameMainCss`
216
+ 3. The CSS is directly available and referenced via `manifest.json` (`"css": "styles.css"`).
227
217
 
228
- > 💡 Le `styles.css` final est produit automatiquement par ce pipeline en renommant le fichier `main.css` issu de la compilation SCSS. Aucun fichier source `styles.css` n'est nécessaire à la racine si vous utilisez exclusivement du SCSS.
218
+ > 💡 The final `styles.css` is automatically produced by this pipeline by renaming the `main.css` file from the SCSS compilation. No root `styles.css` source file is necessary if you use SCSS exclusively.
229
219
 
230
220
  ---
231
221
 
232
- ## 4. l'injecteur installe tout ça dans le plugin cible
222
+ ## 4. Where the Injector Installs Everything in the Target Plugin
233
223
 
234
- L'injection des templates se fait dans `scripts/inject-core.ts`, fonction `injectScripts()` (lignes 455-612). Le tableau `scriptFiles` (lignes 469-480) liste explicitement les fichiers copiés dans le dossier `scripts/` du plugin cible :
224
+ Template injection happens in `scripts/inject-core.ts`, `injectScripts()` function. The `scriptFiles` array explicitly lists files copied into the target plugin's `scripts/` folder:
235
225
 
236
226
  ```ts
237
227
  const scriptFiles = [
@@ -248,9 +238,9 @@ const scriptFiles = [
248
238
  ];
249
239
  ```
250
240
 
251
- Donc après injection, le plugin Obsidian cible contient `scripts/esbuild.config.ts` (avec la logique SCSS) et `scripts/utils.ts` (avec `removeMainCss` et `copyFilesToTargetDir`).
241
+ So after injection, the target Obsidian plugin contains `scripts/esbuild.config.ts` (with SCSS logic) and `scripts/utils.ts` (with `renameMainCss` and `copyFilesToTargetDir`).
252
242
 
253
- Le `.gitignore` injecté (`templates/gitignore.template`, ligne 25-26) ignore explicitement le fichier intermédiaire :
243
+ The injected `.gitignore` (`templates/gitignore.template`) explicitly ignores the intermediate file:
254
244
 
255
245
  ```
256
246
  # scss result
@@ -259,15 +249,29 @@ main.css
259
249
 
260
250
  ---
261
251
 
262
- ## 5. Récapitulatif des fichiers clés
263
-
264
- | Rôle | Fichier | Fonctions / lignes |
265
- |------|---------|--------------------|
266
- | Détection SCSS + build esbuild | `templates/scripts/esbuild.config.ts` | `main()` ~l. 115-140, `createBuildContext()` ~l. 33-69 |
267
- | Plugin esbuild pour compiler SCSS | `esbuild-sass-plugin` (importé dynamiquement) | `esbuild.config.ts` ~l. 41-58 |
268
- | Suppression du `main.css` transitoire | `templates/scripts/utils.ts` | `removeMainCss()` ~l. 169-180 |
269
- | Copie finale vers le dossier plugins | `templates/scripts/utils.ts` | `copyFilesToTargetDir()` ~l. 74-123 |
270
- | Branchement sur `onEnd` esbuild | `templates/scripts/esbuild.config.ts` | plugin `copy-to-plugins-folder` ~l. 70-94 |
271
- | Copie des templates vers le plugin cible | `scripts/inject-core.ts` | `injectScripts()` ~l. 455-612, `buildFileList()` ~l. 284-353 |
272
- | Dépendance optionnelle | `esbuild-sass-plugin` (ajoutée par l'utilisateur si SCSS) | `README.md` § SASS Support, ~l. 85-96 |
273
- | Ignore du fichier transitoire | `templates/gitignore.template` | `main.css` ligne 25-26 |
252
+ ## 5. Key Files Summary
253
+
254
+ | Role | File | Functions / Lines |
255
+ | -------------------------------------------------------------------- | --------------------------------------------- | ------------------------------------ |
256
+ | SCSS detection + esbuild build | `templates/scripts/esbuild.config.ts` | `main()`, `createBuildContext()` |
257
+ | esbuild plugin to compile SCSS | `esbuild-sass-plugin` (dynamically imported) | `esbuild.config.ts` |
258
+ | Safety net (no-op SCSS): rename `main.css` `styles.css` if present | `templates/scripts/utils.ts` | `renameMainCss()` |
259
+ | Final copy to plugins folder | `templates/scripts/utils.ts` | `copyFilesToTargetDir()` |
260
+ | Hook into esbuild `onEnd` | `templates/scripts/esbuild.config.ts` | `copy-to-plugins-folder` plugin |
261
+ | Copy templates to target plugin | `scripts/inject-core.ts` | `injectScripts()`, `buildFileList()` |
262
+ | Optional dependency | `esbuild-sass-plugin` (added by user if SCSS) | `README.md` § SASS Support |
263
+ | Ignore transient file | `templates/gitignore.template` | `main.css` |
264
+
265
+ ---
266
+
267
+ ## 6. Scenario Coverage
268
+
269
+ | Scenario | `buildPath` | CSS produced by esbuild | In place after build? |
270
+ | ------------------------------------ | --------------------------------- | ----------------------- | --------------------- |
271
+ | Watch, in-place (pluginDir in vault) | `pluginDir` | `pluginDir/styles.css` | ✅ direct |
272
+ | Watch, external → TEST_VAULT | `<vault>/.obsidian/plugins/<id>/` | `buildPath/styles.css` | ✅ direct |
273
+ | Prod + `-r`, external → REAL_VAULT | `<vault>/.obsidian/plugins/<id>/` | `buildPath/styles.css` | ✅ direct |
274
+ | Prod, initial folder (`yarn build`) | `pluginDir` | `pluginDir/styles.css` | ✅ direct |
275
+ | Release (GH Actions, `yarn build`) | `pluginDir` (no vault) | `pluginDir/styles.css` | ✅ direct |
276
+
277
+ In all SCSS scenarios, `copyFilesToTargetDir` does not find a source CSS file (`src/styles.css` absent, no root `styles.css`) and returns early — the CSS is already in `buildPath` directly produced by esbuild. Only `manifest.json` is copied by this function in the SCSS case.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "obsidian-plugin-config",
3
- "version": "1.7.3",
3
+ "version": "1.7.5",
4
4
  "description": "Global CLI injection tool for Obsidian plugins",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/acp.ts CHANGED
@@ -1,22 +1,23 @@
1
- import { execSync, spawnSync } from 'child_process';
2
- import fs from 'fs';
1
+ import { readFile } from 'fs/promises';
3
2
  import path from 'path';
4
3
  import {
5
4
  askQuestion,
6
5
  cleanInput,
7
6
  createReadlineInterface,
8
7
  gitExec,
9
- ensureGitSync
8
+ gitOutput,
9
+ ensureGitSync,
10
+ isValidPath
10
11
  } from './utils.js';
11
12
 
12
13
  const rl = createReadlineInterface();
13
14
 
14
15
  /** Check if we're in the centralized config repo */
15
- function isInCentralizedRepo(): boolean {
16
+ async function isInCentralizedRepo(): Promise<boolean> {
16
17
  const packageJsonPath = path.join(process.cwd(), 'package.json');
17
- if (!fs.existsSync(packageJsonPath)) return false;
18
+ if (!(await isValidPath(packageJsonPath))) return false;
18
19
 
19
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
20
+ const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf8'));
20
21
  return packageJson.name === 'obsidian-plugin-config';
21
22
  }
22
23
 
@@ -25,7 +26,7 @@ async function main(): Promise<void> {
25
26
  if (process.argv.includes('-b')) {
26
27
  console.log('Building...');
27
28
  // For obsidian-plugin-config, just run TypeScript check
28
- if (isInCentralizedRepo()) {
29
+ if (await isInCentralizedRepo()) {
29
30
  gitExec('npx tsc --noEmit');
30
31
  } else {
31
32
  gitExec('yarn build');
@@ -39,17 +40,14 @@ async function main(): Promise<void> {
39
40
 
40
41
  try {
41
42
  gitExec('git add -A');
42
- const result = spawnSync('git', ['commit', '-m', cleanedInput], { stdio: 'inherit' });
43
- if (result.status !== 0) {
44
- throw new Error('Commit failed');
45
- }
43
+ gitExec(`git commit -m "${cleanedInput}"`);
46
44
  } catch {
47
45
  console.log('Commit already exists or failed.');
48
46
  return;
49
47
  }
50
48
 
51
49
  // get current branch name
52
- const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
50
+ const currentBranch = gitOutput('git rev-parse --abbrev-ref HEAD');
53
51
 
54
52
  // Ensure Git is synchronized before pushing
55
53
  await ensureGitSync();