obsidian-plugin-config 1.7.3 → 1.7.6
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 +7 -7
- package/bin/obsidian-inject.js +21 -13
- package/docs/INTERACTIVE_INJECTION.md +41 -50
- package/docs/SCSS-FLOW.md +92 -88
- package/package.json +1 -1
- package/scripts/acp.ts +10 -12
- package/scripts/build-npm.ts +397 -393
- package/scripts/help.ts +87 -87
- package/scripts/inject-core.ts +870 -898
- package/scripts/inject-path.ts +157 -156
- package/scripts/inject-prompt.ts +104 -104
- package/scripts/utils.ts +173 -151
- package/templates/.vscode/tasks.json +1 -1
- package/templates/scripts/acp.ts +3 -6
- package/templates/scripts/env.ts +4 -5
- package/templates/scripts/esbuild.config.ts +1 -2
- package/templates/scripts/release.ts +22 -21
- package/templates/scripts/utils.ts +33 -17
- package/docs/audit.md +0 -39
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 --
|
|
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
|
-
- `--
|
|
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
|
|
package/bin/obsidian-inject.js
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Obsidian Plugin Config - CLI Entry Point
|
|
5
5
|
* Global command: obsidian-inject
|
|
6
|
-
* Version: 1.7.
|
|
6
|
+
* Version: 1.7.6
|
|
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
|
|
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 (!
|
|
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 (!
|
|
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(
|
|
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 (
|
|
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
|
-
|
|
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 (
|
|
123
|
-
|
|
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
|
-
|
|
178
|
-
main();
|
|
186
|
+
main().catch(console.error);
|
|
@@ -1,76 +1,67 @@
|
|
|
1
|
-
# Injection
|
|
1
|
+
# Interactive Injection
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
5
|
+
## Entry Points
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
|
-
# CLI
|
|
11
|
-
obsidian-inject #
|
|
12
|
-
obsidian-inject ../my-plugin #
|
|
13
|
-
|
|
14
|
-
#
|
|
15
|
-
yarn inject-prompt #
|
|
16
|
-
yarn inject-path ../my-plugin #
|
|
17
|
-
yarn check-plugin ../my-plugin # Dry-run (
|
|
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
|
-
##
|
|
18
|
+
## File-by-File Behavior
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
During injection, each file is handled as follows:
|
|
23
21
|
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- `y` →
|
|
28
|
-
- `n` →
|
|
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
|
-
|
|
28
|
+
Special cases:
|
|
31
29
|
|
|
32
|
-
- `.env`
|
|
33
|
-
|
|
34
|
-
-
|
|
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-
|
|
42
|
-
obsidian-inject ../my-plugin --
|
|
43
|
-
yarn inject-path ../my-plugin --yes
|
|
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
|
-
#
|
|
41
|
+
# Verification only (writes nothing)
|
|
46
42
|
obsidian-inject ../my-plugin --dry-run
|
|
47
43
|
```
|
|
48
44
|
|
|
49
|
-
| Option
|
|
50
|
-
|
|
|
51
|
-
| `--
|
|
52
|
-
| `--yes`, `-y`
|
|
53
|
-
| `--dry-run`
|
|
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
|
-
##
|
|
51
|
+
## What is Injected
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
sélection par composant) :
|
|
53
|
+
All template files are considered during each injection (no component selection):
|
|
59
54
|
|
|
60
|
-
- `templates/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` → `<
|
|
59
|
+
- `templates/gitignore.template` → `<target>/.gitignore`
|
|
66
60
|
|
|
67
|
-
|
|
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
|
-
##
|
|
63
|
+
## Related Files
|
|
72
64
|
|
|
73
|
-
1. **scripts/inject-core.ts** —
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
#
|
|
1
|
+
# How SCSS Works in this Config
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
>
|
|
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.
|
|
9
|
+
## 1. Flow Overview
|
|
10
10
|
|
|
11
11
|
```
|
|
12
12
|
src/styles.scss
|
|
13
13
|
│
|
|
14
|
-
│
|
|
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
|
|
21
|
+
buildPath/
|
|
21
22
|
├── main.js
|
|
22
|
-
└──
|
|
23
|
+
└── styles.css ← produced directly by esbuild+sassPlugin
|
|
23
24
|
│
|
|
24
|
-
│ plugin "
|
|
25
|
-
│
|
|
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
|
|
28
|
-
├── manifest.json (
|
|
28
|
+
buildPath/
|
|
29
|
+
├── manifest.json (copied)
|
|
29
30
|
├── main.js
|
|
30
|
-
└── styles.css ←
|
|
31
|
+
└── styles.css ← already in place, no renaming necessary
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
The two key moments are:
|
|
34
35
|
|
|
35
|
-
1. **
|
|
36
|
-
2. **
|
|
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.
|
|
41
|
+
## 2. SCSS File Path
|
|
41
42
|
|
|
42
|
-
### 2.1
|
|
43
|
+
### 2.1 SCSS File Detection
|
|
43
44
|
|
|
44
|
-
|
|
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
|
-
-
|
|
67
|
-
-
|
|
68
|
-
- `scssExists` (
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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: '
|
|
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
|
|
89
|
+
await renameMainCss(buildPath);
|
|
100
90
|
}
|
|
101
91
|
});
|
|
102
92
|
}
|
|
@@ -105,48 +95,48 @@ const plugins = [
|
|
|
105
95
|
: []),
|
|
106
96
|
```
|
|
107
97
|
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
- esbuild
|
|
111
|
-
-
|
|
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
|
|
103
|
+
### 2.3 Dependency: `esbuild-sass-plugin`
|
|
114
104
|
|
|
115
|
-
|
|
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
|
-
|
|
107
|
+
> `⚠️ esbuild-sass-plugin not found. Install it with: yarn add -D esbuild-sass-plugin`
|
|
119
108
|
|
|
120
|
-
|
|
109
|
+
> **Note**: the `.sass` extension (indented syntax) is not supported. Only `.scss` is detected and compiled.
|
|
121
110
|
|
|
122
111
|
---
|
|
123
112
|
|
|
124
|
-
## 3.
|
|
113
|
+
## 3. How it is Copied to the Plugins Folder
|
|
125
114
|
|
|
126
|
-
### 3.1
|
|
115
|
+
### 3.1 `renameMainCss` — Safety Net (no-op in current SCSS flow)
|
|
127
116
|
|
|
128
|
-
|
|
117
|
+
In `templates/scripts/utils.ts`, `renameMainCss()` function:
|
|
129
118
|
|
|
130
119
|
```ts
|
|
131
|
-
export async function
|
|
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
|
|
135
|
-
|
|
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
|
-
|
|
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
|
|
137
|
+
### 3.2 Copying to the Plugins Folder
|
|
148
138
|
|
|
149
|
-
|
|
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
|
|
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
|
|
171
|
+
### 3.3 Integration into the esbuild Lifecycle
|
|
182
172
|
|
|
183
|
-
|
|
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
|
-
-
|
|
212
|
-
-
|
|
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
|
|
204
|
+
### 3.4 Target: `buildPath`
|
|
215
205
|
|
|
216
|
-
`buildPath`
|
|
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
|
-
|
|
212
|
+
So concretely, the final result for SCSS is:
|
|
223
213
|
|
|
224
|
-
1. `src/styles.scss` →
|
|
225
|
-
2. `main.css`
|
|
226
|
-
3.
|
|
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
|
-
> 💡
|
|
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.
|
|
222
|
+
## 4. Where the Injector Installs Everything in the Target Plugin
|
|
233
223
|
|
|
234
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
263
|
-
|
|
264
|
-
|
|
|
265
|
-
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
|
|
|
269
|
-
|
|
|
270
|
-
|
|
|
271
|
-
|
|
|
272
|
-
|
|
|
273
|
-
| Ignore
|
|
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
package/scripts/acp.ts
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
|
-
import {
|
|
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
|
-
|
|
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 (!
|
|
18
|
+
if (!(await isValidPath(packageJsonPath))) return false;
|
|
18
19
|
|
|
19
|
-
const packageJson = JSON.parse(
|
|
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
|
-
|
|
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 =
|
|
50
|
+
const currentBranch = gitOutput('git rev-parse --abbrev-ref HEAD');
|
|
53
51
|
|
|
54
52
|
// Ensure Git is synchronized before pushing
|
|
55
53
|
await ensureGitSync();
|