obsidian-plugin-config 1.1.15 → 1.1.17
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 +26 -0
- package/bin/obsidian-inject.js +1 -1
- package/package.json +2 -1
- package/scripts/build-npm.ts +1 -1
- package/scripts/help.ts +2 -0
- package/scripts/inject-path.ts +22 -11
- package/templates/package-versions-sass.json +29 -0
- package/templates/scripts/esbuild.config-sass.ts +294 -0
- package/templates/scripts/esbuild.config.ts +86 -49
- package/templates/scripts/utils.ts +15 -0
- package/versions.json +3 -1
package/README.md
CHANGED
|
@@ -62,6 +62,9 @@ yarn inject-prompt "../my-plugin"
|
|
|
62
62
|
obsidian-inject ../my-plugin --yes
|
|
63
63
|
yarn inject-path ../my-plugin --yes
|
|
64
64
|
|
|
65
|
+
# SASS injection (includes esbuild-sass-plugin)
|
|
66
|
+
yarn inject-sass ../my-plugin --yes
|
|
67
|
+
|
|
65
68
|
# Verification only
|
|
66
69
|
yarn check-plugin ../my-plugin
|
|
67
70
|
```
|
|
@@ -73,6 +76,7 @@ yarn check-plugin ../my-plugin
|
|
|
73
76
|
- ✅ **tsconfig.json template**: modern optimized TypeScript configuration
|
|
74
77
|
- ✅ **Automatic installation** of dependencies with yarn
|
|
75
78
|
- ✅ **Traceability file**: `.injection-info.json` (version, injection date)
|
|
79
|
+
- 🎨 **SASS support**: Optional SASS/SCSS compilation with `--sass` option
|
|
76
80
|
|
|
77
81
|
## Commands available after injection
|
|
78
82
|
|
|
@@ -88,6 +92,28 @@ yarn release # GitHub release
|
|
|
88
92
|
yarn help # Full help
|
|
89
93
|
```
|
|
90
94
|
|
|
95
|
+
## SASS Support
|
|
96
|
+
|
|
97
|
+
For plugins that use SASS/SCSS styling:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Inject with SASS support
|
|
101
|
+
yarn inject-sass ../my-plugin --yes
|
|
102
|
+
|
|
103
|
+
# What gets added:
|
|
104
|
+
# - esbuild-sass-plugin dependency
|
|
105
|
+
# - SASS compilation in esbuild.config.ts
|
|
106
|
+
# - Automatic .scss file detection
|
|
107
|
+
# - CSS cleanup after compilation
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**SASS Features:**
|
|
111
|
+
|
|
112
|
+
- ✅ **Automatic detection** of `.scss` files in `src/` directory
|
|
113
|
+
- ✅ **Priority order**: `src/styles.scss` > `src/styles.css` > `styles.css`
|
|
114
|
+
- ✅ **Clean compilation** with automatic main.css removal
|
|
115
|
+
- ✅ **Error handling** with helpful messages
|
|
116
|
+
|
|
91
117
|
## Architecture
|
|
92
118
|
|
|
93
119
|
The plugin becomes **100% STANDALONE** after injection:
|
package/bin/obsidian-inject.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "obsidian-plugin-config",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "Système d'injection pour plugins Obsidian autonomes",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"lint": "eslint . --ext .ts",
|
|
33
33
|
"lint:fix": "eslint . --ext .ts --fix",
|
|
34
34
|
"inject-path": "tsx scripts/inject-path.ts",
|
|
35
|
+
"inject-sass": "tsx scripts/inject-path.ts --sass",
|
|
35
36
|
"inject-prompt": "tsx scripts/inject-prompt.ts",
|
|
36
37
|
"inject": "tsx scripts/inject-prompt.ts",
|
|
37
38
|
"check-plugin": "tsx scripts/inject-path.ts --dry-run",
|
package/scripts/build-npm.ts
CHANGED
|
@@ -201,7 +201,7 @@ function buildAndPublishNpm(): void {
|
|
|
201
201
|
console.log(`\n📤 Step 2/6: Committing and pushing changes...`);
|
|
202
202
|
try {
|
|
203
203
|
execSync('echo "Prepare NPM package publication" | tsx scripts/acp.ts -b', { stdio: 'inherit' });
|
|
204
|
-
} catch
|
|
204
|
+
} catch {
|
|
205
205
|
console.log(` ℹ️ No additional changes to commit`);
|
|
206
206
|
}
|
|
207
207
|
|
package/scripts/help.ts
CHANGED
|
@@ -26,6 +26,7 @@ BUILD & TESTING:
|
|
|
26
26
|
INJECTION (Development phase):
|
|
27
27
|
yarn inject-prompt <path> # Interactive injection (recommended)
|
|
28
28
|
yarn inject-path <path> --yes # Direct injection with auto-confirm
|
|
29
|
+
yarn inject-sass <path> --yes # Injection with SASS support
|
|
29
30
|
yarn inject, check-plugin # Injection shortcuts
|
|
30
31
|
|
|
31
32
|
NPM PUBLISHING:
|
|
@@ -57,6 +58,7 @@ Injection Usage (Development phase):
|
|
|
57
58
|
Usage:
|
|
58
59
|
yarn inject-prompt ../my-plugin # Interactive (recommended)
|
|
59
60
|
yarn inject-path ../my-plugin # Direct injection
|
|
61
|
+
yarn inject-sass ../my-plugin # Injection with SASS support
|
|
60
62
|
yarn check-plugin ../my-plugin # Verification only
|
|
61
63
|
|
|
62
64
|
═══════════════════════════════════════════════════════════════════
|
package/scripts/inject-path.ts
CHANGED
|
@@ -67,13 +67,14 @@ async function analyzePlugin(pluginPath: string): Promise<InjectionPlan> {
|
|
|
67
67
|
/**
|
|
68
68
|
* Display injection plan and ask for confirmation
|
|
69
69
|
*/
|
|
70
|
-
async function showInjectionPlan(plan: InjectionPlan, autoConfirm: boolean = false): Promise<boolean> {
|
|
70
|
+
async function showInjectionPlan(plan: InjectionPlan, autoConfirm: boolean = false, useSass: boolean = false): Promise<boolean> {
|
|
71
71
|
console.log(`\n🎯 Injection Plan for: ${plan.targetPath}`);
|
|
72
72
|
console.log(`📁 Target: ${path.basename(plan.targetPath)}`);
|
|
73
73
|
console.log(`📦 Package.json: ${plan.hasPackageJson ? '✅' : '❌'}`);
|
|
74
74
|
console.log(`📋 Manifest.json: ${plan.hasManifest ? '✅' : '❌'}`);
|
|
75
75
|
console.log(`📂 Scripts folder: ${plan.hasScriptsFolder ? '✅ (will be updated)' : '❌ (will be created)'}`);
|
|
76
76
|
console.log(`🔌 Obsidian plugin: ${plan.isObsidianPlugin ? '✅' : '❌'}`);
|
|
77
|
+
console.log(`🎨 SASS support: ${useSass ? '✅ (esbuild-sass-plugin will be added)' : '❌'}`);
|
|
77
78
|
|
|
78
79
|
if (!plan.isObsidianPlugin) {
|
|
79
80
|
console.log(`\n⚠️ Warning: This doesn't appear to be a valid Obsidian plugin`);
|
|
@@ -246,7 +247,7 @@ async function cleanOldLintFiles(targetPath: string): Promise<void> {
|
|
|
246
247
|
/**
|
|
247
248
|
* Inject scripts from local files
|
|
248
249
|
*/
|
|
249
|
-
async function injectScripts(targetPath: string): Promise<void> {
|
|
250
|
+
async function injectScripts(targetPath: string, useSass: boolean = false): Promise<void> {
|
|
250
251
|
const scriptsPath = path.join(targetPath, "scripts");
|
|
251
252
|
|
|
252
253
|
// Create scripts directory if it doesn't exist
|
|
@@ -263,7 +264,7 @@ async function injectScripts(targetPath: string): Promise<void> {
|
|
|
263
264
|
|
|
264
265
|
const scriptFiles = [
|
|
265
266
|
"templates/scripts/utils.ts",
|
|
266
|
-
"templates/scripts/esbuild.config.ts",
|
|
267
|
+
useSass ? "templates/scripts/esbuild.config-sass.ts" : "templates/scripts/esbuild.config.ts",
|
|
267
268
|
"templates/scripts/acp.ts",
|
|
268
269
|
"templates/scripts/update-version.ts",
|
|
269
270
|
"templates/scripts/release.ts",
|
|
@@ -286,7 +287,13 @@ async function injectScripts(targetPath: string): Promise<void> {
|
|
|
286
287
|
for (const scriptFile of scriptFiles) {
|
|
287
288
|
try {
|
|
288
289
|
const content = copyFromLocal(scriptFile);
|
|
289
|
-
|
|
290
|
+
let fileName = path.basename(scriptFile);
|
|
291
|
+
|
|
292
|
+
// Handle SASS template renaming
|
|
293
|
+
if (fileName === 'esbuild.config-sass.ts') {
|
|
294
|
+
fileName = 'esbuild.config.ts';
|
|
295
|
+
}
|
|
296
|
+
|
|
290
297
|
const targetFile = path.join(scriptsPath, fileName);
|
|
291
298
|
|
|
292
299
|
fs.writeFileSync(targetFile, content, 'utf8');
|
|
@@ -353,7 +360,7 @@ async function injectScripts(targetPath: string): Promise<void> {
|
|
|
353
360
|
/**
|
|
354
361
|
* Update package.json with autonomous configuration
|
|
355
362
|
*/
|
|
356
|
-
async function updatePackageJson(targetPath: string): Promise<void> {
|
|
363
|
+
async function updatePackageJson(targetPath: string, useSass: boolean = false): Promise<void> {
|
|
357
364
|
const packageJsonPath = path.join(targetPath, "package.json");
|
|
358
365
|
|
|
359
366
|
if (!await isValidPath(packageJsonPath)) {
|
|
@@ -411,7 +418,8 @@ async function updatePackageJson(targetPath: string): Promise<void> {
|
|
|
411
418
|
"obsidian-typings": "^3.9.5",
|
|
412
419
|
"semver": "^7.7.2",
|
|
413
420
|
"tsx": "^4.19.4",
|
|
414
|
-
"typescript": "^5.8.2"
|
|
421
|
+
"typescript": "^5.8.2",
|
|
422
|
+
...(useSass ? { "esbuild-sass-plugin": "^3.3.1" } : {})
|
|
415
423
|
};
|
|
416
424
|
|
|
417
425
|
// Force update TypeScript to compatible version
|
|
@@ -669,7 +677,7 @@ async function runYarnInstall(targetPath: string): Promise<void> {
|
|
|
669
677
|
/**
|
|
670
678
|
* Main injection function
|
|
671
679
|
*/
|
|
672
|
-
export async function performInjection(targetPath: string): Promise<void> {
|
|
680
|
+
export async function performInjection(targetPath: string, useSass: boolean = false): Promise<void> {
|
|
673
681
|
console.log(`\n🚀 Starting injection process...`);
|
|
674
682
|
|
|
675
683
|
try {
|
|
@@ -680,11 +688,11 @@ export async function performInjection(targetPath: string): Promise<void> {
|
|
|
680
688
|
await ensureTsxInstalled(targetPath);
|
|
681
689
|
|
|
682
690
|
// Step 3: Inject scripts
|
|
683
|
-
await injectScripts(targetPath);
|
|
691
|
+
await injectScripts(targetPath, useSass);
|
|
684
692
|
|
|
685
693
|
// Step 4: Update package.json
|
|
686
694
|
console.log(`\n📦 Updating package.json...`);
|
|
687
|
-
await updatePackageJson(targetPath);
|
|
695
|
+
await updatePackageJson(targetPath, useSass);
|
|
688
696
|
|
|
689
697
|
// Step 5: Analyze centralized imports (without modifying)
|
|
690
698
|
await analyzeCentralizedImports(targetPath);
|
|
@@ -731,6 +739,7 @@ async function main(): Promise<void> {
|
|
|
731
739
|
const args = process.argv.slice(2);
|
|
732
740
|
const autoConfirm = args.includes('--yes') || args.includes('-y');
|
|
733
741
|
const dryRun = args.includes('--dry-run') || args.includes('--check');
|
|
742
|
+
const useSass = args.includes('--sass');
|
|
734
743
|
const targetPath = args.find(arg => !arg.startsWith('-'));
|
|
735
744
|
|
|
736
745
|
if (!targetPath) {
|
|
@@ -739,6 +748,7 @@ async function main(): Promise<void> {
|
|
|
739
748
|
console.error(` Options:`);
|
|
740
749
|
console.error(` --yes, -y Auto-confirm injection`);
|
|
741
750
|
console.error(` --dry-run Check only (no injection)`);
|
|
751
|
+
console.error(` --sass Use SASS templates (includes esbuild-sass-plugin)`);
|
|
742
752
|
console.error(` Shortcuts:`);
|
|
743
753
|
console.error(` yarn check-plugin ../plugin # Verification only`);
|
|
744
754
|
console.error(` yarn verify-plugin ../plugin # Alias pour check-plugin`);
|
|
@@ -767,6 +777,7 @@ async function main(): Promise<void> {
|
|
|
767
777
|
console.log(`📋 Manifest.json: ${plan.hasManifest ? '✅' : '❌'}`);
|
|
768
778
|
console.log(`📂 Scripts folder: ${plan.hasScriptsFolder ? '✅ (will be updated)' : '❌ (will be created)'}`);
|
|
769
779
|
console.log(`🔌 Obsidian plugin: ${plan.isObsidianPlugin ? '✅' : '❌'}`);
|
|
780
|
+
console.log(`🎨 SASS support: ${useSass ? '✅ (esbuild-sass-plugin will be added)' : '❌'}`);
|
|
770
781
|
|
|
771
782
|
if (!plan.isObsidianPlugin) {
|
|
772
783
|
console.log(`\n⚠️ Warning: This doesn't appear to be a valid Obsidian plugin`);
|
|
@@ -824,7 +835,7 @@ async function main(): Promise<void> {
|
|
|
824
835
|
console.log(`\n🔍 Checking plugin-config repository status...`);
|
|
825
836
|
await ensurePluginConfigClean();
|
|
826
837
|
|
|
827
|
-
const confirmed = await showInjectionPlan(plan, autoConfirm);
|
|
838
|
+
const confirmed = await showInjectionPlan(plan, autoConfirm, useSass);
|
|
828
839
|
|
|
829
840
|
if (!confirmed) {
|
|
830
841
|
console.log(`❌ Injection cancelled by user`);
|
|
@@ -832,7 +843,7 @@ async function main(): Promise<void> {
|
|
|
832
843
|
}
|
|
833
844
|
|
|
834
845
|
// Perform injection
|
|
835
|
-
await performInjection(resolvedPath);
|
|
846
|
+
await performInjection(resolvedPath, useSass);
|
|
836
847
|
|
|
837
848
|
} catch (error) {
|
|
838
849
|
console.error(`💥 Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"devDependencies": {
|
|
3
|
+
"@types/node": "^16.11.6",
|
|
4
|
+
"eslint": "^9.0.0",
|
|
5
|
+
"obsidian": "latest",
|
|
6
|
+
"obsidian-typings": "latest",
|
|
7
|
+
"typescript": "^5.8.2",
|
|
8
|
+
"tsx": "^4.19.4",
|
|
9
|
+
"esbuild-sass-plugin": "^3.3.1"
|
|
10
|
+
},
|
|
11
|
+
"engines": {
|
|
12
|
+
"npm": "please-use-yarn",
|
|
13
|
+
"yarn": ">=1.22.0"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"start": "yarn install && yarn dev",
|
|
17
|
+
"dev": "tsx ../obsidian-plugin-config/scripts/esbuild.config.ts",
|
|
18
|
+
"build": "tsc -noEmit -skipLibCheck && tsx ../obsidian-plugin-config/scripts/esbuild.config.ts production",
|
|
19
|
+
"real": "tsx ../obsidian-plugin-config/scripts/esbuild.config.ts production real",
|
|
20
|
+
"acp": "tsx ../obsidian-plugin-config/scripts/acp.ts",
|
|
21
|
+
"bacp": "tsx ../obsidian-plugin-config/scripts/acp.ts -b",
|
|
22
|
+
"update-version": "tsx ../obsidian-plugin-config/scripts/update-version.ts",
|
|
23
|
+
"v": "tsx ../obsidian-plugin-config/scripts/update-version.ts",
|
|
24
|
+
"release": "tsx ../obsidian-plugin-config/scripts/release.ts",
|
|
25
|
+
"r": "tsx ../obsidian-plugin-config/scripts/release.ts",
|
|
26
|
+
"help": "tsx ../obsidian-plugin-config/templates/help-plugin.ts",
|
|
27
|
+
"h": "tsx ../obsidian-plugin-config/templates/help-plugin.ts"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import esbuild from "esbuild";
|
|
2
|
+
import process from "process";
|
|
3
|
+
import builtins from "builtin-modules";
|
|
4
|
+
import { config } from "dotenv";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { rm } from "fs/promises";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
// @ts-ignore - esbuild-sass-plugin is installed during SASS injection
|
|
10
|
+
import { sassPlugin } from "esbuild-sass-plugin";
|
|
11
|
+
import { isValidPath, copyFilesToTargetDir, askQuestion, createReadlineInterface, removeMainCss } from "./utils.js";
|
|
12
|
+
|
|
13
|
+
// Determine the plugin directory (where the script is called from)
|
|
14
|
+
const pluginDir = process.cwd();
|
|
15
|
+
|
|
16
|
+
// Create readline interface for prompts
|
|
17
|
+
const rl = createReadlineInterface();
|
|
18
|
+
|
|
19
|
+
async function promptForVaultPath(envKey: string): Promise<string> {
|
|
20
|
+
const vaultType = envKey === "REAL_VAULT" ? "real" : "test";
|
|
21
|
+
const usage = envKey === "REAL_VAULT"
|
|
22
|
+
? "for final plugin installation"
|
|
23
|
+
: "for development and testing";
|
|
24
|
+
|
|
25
|
+
console.log(`❓ ${envKey} path is required ${usage}`);
|
|
26
|
+
const path = await askQuestion(`📝 Enter your ${vaultType} vault path (or Ctrl+C to cancel): `, rl);
|
|
27
|
+
|
|
28
|
+
if (!path) {
|
|
29
|
+
console.log('❌ No path provided, exiting...');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return path;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async function updateEnvFile(envKey: string, vaultPath: string): Promise<void> {
|
|
39
|
+
const envPath = path.join(pluginDir, '.env');
|
|
40
|
+
let envContent = '';
|
|
41
|
+
|
|
42
|
+
// Read existing .env if it exists
|
|
43
|
+
try {
|
|
44
|
+
envContent = readFileSync(envPath, 'utf8');
|
|
45
|
+
} catch {
|
|
46
|
+
// File doesn't exist, start with empty content
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Update or add the variable
|
|
50
|
+
const regex = new RegExp(`^${envKey}=.*$`, 'm');
|
|
51
|
+
const newLine = `${envKey}=${vaultPath}`;
|
|
52
|
+
|
|
53
|
+
if (regex.test(envContent)) {
|
|
54
|
+
envContent = envContent.replace(regex, newLine);
|
|
55
|
+
} else {
|
|
56
|
+
if (envContent.length > 0 && !envContent.endsWith('\n')) {
|
|
57
|
+
envContent += '\n';
|
|
58
|
+
}
|
|
59
|
+
envContent += newLine + '\n';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Write back to .env
|
|
63
|
+
fs.writeFileSync(envPath, envContent);
|
|
64
|
+
console.log(`✅ Updated ${envKey} in .env file`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function validateVaultPath(vaultPath: string): boolean {
|
|
68
|
+
// Check if the path contains .obsidian directory
|
|
69
|
+
const obsidianPath = path.join(vaultPath, ".obsidian");
|
|
70
|
+
const pluginsPath = path.join(vaultPath, ".obsidian", "plugins");
|
|
71
|
+
|
|
72
|
+
return fs.existsSync(obsidianPath) && fs.existsSync(pluginsPath);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getVaultPath(vaultPath: string): string {
|
|
76
|
+
// Validate that this is a proper vault path
|
|
77
|
+
if (!validateVaultPath(vaultPath)) {
|
|
78
|
+
console.error(`❌ Invalid vault path: ${vaultPath}`);
|
|
79
|
+
console.error(` The path must contain a .obsidian/plugins directory`);
|
|
80
|
+
console.error(` Please enter a valid Obsidian vault path`);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if the path already contains the plugins directory path
|
|
85
|
+
const pluginsPath = path.join(".obsidian", "plugins");
|
|
86
|
+
if (vaultPath.includes(pluginsPath)) {
|
|
87
|
+
return path.join(vaultPath, manifest.id);
|
|
88
|
+
} else {
|
|
89
|
+
return path.join(vaultPath, ".obsidian", "plugins", manifest.id);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const manifestPath = path.join(pluginDir, "manifest.json");
|
|
94
|
+
|
|
95
|
+
// Check if manifest exists (for plugin-config itself, it might not exist)
|
|
96
|
+
if (!fs.existsSync(manifestPath)) {
|
|
97
|
+
console.log("⚠️ No manifest.json found - this script is designed for Obsidian plugins");
|
|
98
|
+
console.log(" If you're building plugin-config itself, use 'tsc' instead");
|
|
99
|
+
process.exit(0);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
103
|
+
|
|
104
|
+
config();
|
|
105
|
+
|
|
106
|
+
const EXTERNAL_DEPS = [
|
|
107
|
+
"obsidian",
|
|
108
|
+
"electron",
|
|
109
|
+
"@codemirror/autocomplete",
|
|
110
|
+
"@codemirror/collab",
|
|
111
|
+
"@codemirror/commands",
|
|
112
|
+
"@codemirror/language",
|
|
113
|
+
"@codemirror/lint",
|
|
114
|
+
"@codemirror/search",
|
|
115
|
+
"@codemirror/state",
|
|
116
|
+
"@codemirror/view",
|
|
117
|
+
"@lezer/common",
|
|
118
|
+
"@lezer/highlight",
|
|
119
|
+
"@lezer/lr",
|
|
120
|
+
...builtins
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const BANNER = `/*
|
|
124
|
+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
125
|
+
if you want to view the source, please visit the github repository of this plugin
|
|
126
|
+
*/`;
|
|
127
|
+
|
|
128
|
+
async function validateEnvironment(): Promise<void> {
|
|
129
|
+
const srcMainPath = path.join(pluginDir, "src/main.ts");
|
|
130
|
+
if (!await isValidPath(srcMainPath)) {
|
|
131
|
+
throw new Error("Invalid path for src/main.ts. main.ts must be in the src directory");
|
|
132
|
+
}
|
|
133
|
+
if (!await isValidPath(manifestPath)) {
|
|
134
|
+
throw new Error("Invalid path for manifest.json");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function getBuildPath(isProd: boolean): Promise<string> {
|
|
139
|
+
// Check if we should use real vault (either -r flag or "real" argument)
|
|
140
|
+
const useRealVault = process.argv.includes("-r") || process.argv.includes("real");
|
|
141
|
+
|
|
142
|
+
// If production build without redirection, return plugin directory
|
|
143
|
+
if (isProd && !useRealVault) {
|
|
144
|
+
return pluginDir;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Determine which path to use
|
|
148
|
+
const envKey = useRealVault ? "REAL_VAULT" : "TEST_VAULT";
|
|
149
|
+
const vaultPath = process.env[envKey]?.trim();
|
|
150
|
+
|
|
151
|
+
// If empty or undefined, we're already in the plugin folder
|
|
152
|
+
if (!vaultPath) {
|
|
153
|
+
// Check if we're in Obsidian plugins folder
|
|
154
|
+
const currentPath = process.cwd();
|
|
155
|
+
const isInObsidianPlugins = currentPath.includes('.obsidian/plugins') ||
|
|
156
|
+
currentPath.includes('.obsidian\\plugins');
|
|
157
|
+
|
|
158
|
+
if (isInObsidianPlugins) {
|
|
159
|
+
// In obsidian/plugins: allow in-place development
|
|
160
|
+
console.log(`ℹ️ Building in Obsidian plugins folder (in-place development)`);
|
|
161
|
+
return pluginDir;
|
|
162
|
+
} else {
|
|
163
|
+
// External development: prompt for missing vault path
|
|
164
|
+
const newPath = await promptForVaultPath(envKey);
|
|
165
|
+
await updateEnvFile(envKey, newPath);
|
|
166
|
+
config();
|
|
167
|
+
return getVaultPath(newPath);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// If we reach here, use the vault path directly
|
|
172
|
+
return getVaultPath(vaultPath);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async function createBuildContext(buildPath: string, isProd: boolean, entryPoints: string[], hasSass: boolean): Promise<esbuild.BuildContext> {
|
|
176
|
+
const plugins = [
|
|
177
|
+
// Add SASS plugin if SCSS files are detected
|
|
178
|
+
...(hasSass ? [
|
|
179
|
+
sassPlugin({
|
|
180
|
+
syntax: 'scss',
|
|
181
|
+
style: 'expanded',
|
|
182
|
+
}),
|
|
183
|
+
{
|
|
184
|
+
name: 'remove-main-css',
|
|
185
|
+
setup(build: esbuild.PluginBuild): void {
|
|
186
|
+
build.onEnd(async (result) => {
|
|
187
|
+
if (result.errors.length === 0) {
|
|
188
|
+
await removeMainCss(buildPath);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
] : []),
|
|
194
|
+
// Plugin pour gérer les alias de chemin
|
|
195
|
+
{
|
|
196
|
+
name: "path-alias",
|
|
197
|
+
setup: (build: esbuild.PluginBuild): void => {
|
|
198
|
+
build.onResolve({ filter: /^@config\// }, (args) => {
|
|
199
|
+
const relativePath = args.path.replace(/^@config\//, "");
|
|
200
|
+
return {
|
|
201
|
+
path: path.resolve("../obsidian-plugin-config/src", relativePath)
|
|
202
|
+
};
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
build.onResolve({ filter: /^@config-scripts\// }, (args) => {
|
|
206
|
+
const relativePath = args.path.replace(/^@config-scripts\//, "");
|
|
207
|
+
return {
|
|
208
|
+
path: path.resolve("../obsidian-plugin-config/scripts", relativePath)
|
|
209
|
+
};
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: "copy-to-plugins-folder",
|
|
215
|
+
setup: (build: esbuild.PluginBuild): void => {
|
|
216
|
+
build.onEnd(async () => {
|
|
217
|
+
// if real or build
|
|
218
|
+
if (isProd) {
|
|
219
|
+
if (process.argv.includes("-r") || process.argv.includes("real")) {
|
|
220
|
+
await copyFilesToTargetDir(buildPath);
|
|
221
|
+
console.log(`Successfully installed in ${buildPath}`);
|
|
222
|
+
} else {
|
|
223
|
+
const folderToRemove = path.join(buildPath, "_.._");
|
|
224
|
+
if (await isValidPath(folderToRemove)) {
|
|
225
|
+
await rm(folderToRemove, { recursive: true });
|
|
226
|
+
}
|
|
227
|
+
console.log("Built done in initial folder");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// if watch (dev)
|
|
231
|
+
else {
|
|
232
|
+
await copyFilesToTargetDir(buildPath);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
];
|
|
238
|
+
|
|
239
|
+
return await esbuild.context({
|
|
240
|
+
banner: { js: BANNER },
|
|
241
|
+
minify: isProd,
|
|
242
|
+
entryPoints,
|
|
243
|
+
bundle: true,
|
|
244
|
+
external: EXTERNAL_DEPS,
|
|
245
|
+
format: "cjs",
|
|
246
|
+
target: "esNext",
|
|
247
|
+
platform: "node",
|
|
248
|
+
logLevel: "info",
|
|
249
|
+
sourcemap: isProd ? false : "inline",
|
|
250
|
+
treeShaking: true,
|
|
251
|
+
outdir: buildPath,
|
|
252
|
+
outbase: path.join(pluginDir, "src"),
|
|
253
|
+
plugins
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function main(): Promise<void> {
|
|
258
|
+
try {
|
|
259
|
+
await validateEnvironment();
|
|
260
|
+
const isProd = process.argv[2] === "production";
|
|
261
|
+
const buildPath = await getBuildPath(isProd);
|
|
262
|
+
console.log(buildPath === pluginDir
|
|
263
|
+
? "Building in initial folder"
|
|
264
|
+
: `Building in ${buildPath}`);
|
|
265
|
+
|
|
266
|
+
// Check for SCSS first, then CSS in src, then in root
|
|
267
|
+
const srcStylesScssPath = path.join(pluginDir, "src/styles.scss");
|
|
268
|
+
const srcStylesPath = path.join(pluginDir, "src/styles.css");
|
|
269
|
+
const rootStylesPath = path.join(pluginDir, "styles.css");
|
|
270
|
+
|
|
271
|
+
const scssExists = await isValidPath(srcStylesScssPath);
|
|
272
|
+
const stylePath = scssExists ? srcStylesScssPath :
|
|
273
|
+
await isValidPath(srcStylesPath) ? srcStylesPath :
|
|
274
|
+
await isValidPath(rootStylesPath) ? rootStylesPath : "";
|
|
275
|
+
|
|
276
|
+
const mainTsPath = path.join(pluginDir, "src/main.ts");
|
|
277
|
+
const entryPoints = stylePath ? [mainTsPath, stylePath] : [mainTsPath];
|
|
278
|
+
const context = await createBuildContext(buildPath, isProd, entryPoints, scssExists);
|
|
279
|
+
|
|
280
|
+
if (isProd) {
|
|
281
|
+
await context.rebuild();
|
|
282
|
+
rl.close();
|
|
283
|
+
process.exit(0);
|
|
284
|
+
} else {
|
|
285
|
+
await context.watch();
|
|
286
|
+
}
|
|
287
|
+
} catch (error) {
|
|
288
|
+
console.error("Build failed:", error);
|
|
289
|
+
rl.close();
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
main().catch(console.error);
|
|
@@ -6,7 +6,7 @@ import path from "path";
|
|
|
6
6
|
import { readFileSync } from "fs";
|
|
7
7
|
import { rm } from "fs/promises";
|
|
8
8
|
import fs from "fs";
|
|
9
|
-
import { isValidPath, copyFilesToTargetDir, askQuestion, createReadlineInterface } from "./utils.js";
|
|
9
|
+
import { isValidPath, copyFilesToTargetDir, askQuestion, createReadlineInterface, removeMainCss } from "./utils.js";
|
|
10
10
|
|
|
11
11
|
// Determine the plugin directory (where the script is called from)
|
|
12
12
|
const pluginDir = process.cwd();
|
|
@@ -167,7 +167,80 @@ async function getBuildPath(isProd: boolean): Promise<string> {
|
|
|
167
167
|
return getVaultPath(vaultPath);
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
-
async function createBuildContext(buildPath: string, isProd: boolean, entryPoints: string[]): Promise<esbuild.BuildContext> {
|
|
170
|
+
async function createBuildContext(buildPath: string, isProd: boolean, entryPoints: string[], hasSass: boolean): Promise<esbuild.BuildContext> {
|
|
171
|
+
const plugins = [
|
|
172
|
+
// Add SASS plugin if SCSS files are detected
|
|
173
|
+
...(hasSass ? [
|
|
174
|
+
// Dynamic import for SASS plugin to avoid dependency issues when not needed
|
|
175
|
+
await (async () => {
|
|
176
|
+
try {
|
|
177
|
+
// @ts-ignore - esbuild-sass-plugin is installed during injection
|
|
178
|
+
const { sassPlugin } = await import('esbuild-sass-plugin');
|
|
179
|
+
return sassPlugin({
|
|
180
|
+
syntax: 'scss',
|
|
181
|
+
style: 'expanded',
|
|
182
|
+
});
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.warn('⚠️ esbuild-sass-plugin not found. Install it with: yarn add -D esbuild-sass-plugin');
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
})(),
|
|
188
|
+
{
|
|
189
|
+
name: 'remove-main-css',
|
|
190
|
+
setup(build: esbuild.PluginBuild): void {
|
|
191
|
+
build.onEnd(async (result) => {
|
|
192
|
+
if (result.errors.length === 0) {
|
|
193
|
+
await removeMainCss(buildPath);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
] : []),
|
|
199
|
+
// Plugin pour gérer les alias de chemin
|
|
200
|
+
{
|
|
201
|
+
name: "path-alias",
|
|
202
|
+
setup: (build: esbuild.PluginBuild): void => {
|
|
203
|
+
build.onResolve({ filter: /^@config\// }, (args) => {
|
|
204
|
+
const relativePath = args.path.replace(/^@config\//, "");
|
|
205
|
+
return {
|
|
206
|
+
path: path.resolve("../obsidian-plugin-config/src", relativePath)
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
build.onResolve({ filter: /^@config-scripts\// }, (args) => {
|
|
211
|
+
const relativePath = args.path.replace(/^@config-scripts\//, "");
|
|
212
|
+
return {
|
|
213
|
+
path: path.resolve("../obsidian-plugin-config/scripts", relativePath)
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: "copy-to-plugins-folder",
|
|
220
|
+
setup: (build: esbuild.PluginBuild): void => {
|
|
221
|
+
build.onEnd(async () => {
|
|
222
|
+
// if real or build
|
|
223
|
+
if (isProd) {
|
|
224
|
+
if (process.argv.includes("-r") || process.argv.includes("real")) {
|
|
225
|
+
await copyFilesToTargetDir(buildPath);
|
|
226
|
+
console.log(`Successfully installed in ${buildPath}`);
|
|
227
|
+
} else {
|
|
228
|
+
const folderToRemove = path.join(buildPath, "_.._");
|
|
229
|
+
if (await isValidPath(folderToRemove)) {
|
|
230
|
+
await rm(folderToRemove, { recursive: true });
|
|
231
|
+
}
|
|
232
|
+
console.log("Built done in initial folder");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// if watch (dev)
|
|
236
|
+
else {
|
|
237
|
+
await copyFilesToTargetDir(buildPath);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
];
|
|
243
|
+
|
|
171
244
|
return await esbuild.context({
|
|
172
245
|
banner: { js: BANNER },
|
|
173
246
|
minify: isProd,
|
|
@@ -182,51 +255,7 @@ async function createBuildContext(buildPath: string, isProd: boolean, entryPoint
|
|
|
182
255
|
treeShaking: true,
|
|
183
256
|
outdir: buildPath,
|
|
184
257
|
outbase: path.join(pluginDir, "src"),
|
|
185
|
-
plugins
|
|
186
|
-
// Plugin pour gérer les alias de chemin
|
|
187
|
-
{
|
|
188
|
-
name: "path-alias",
|
|
189
|
-
setup: (build): void => {
|
|
190
|
-
build.onResolve({ filter: /^@config\// }, (args) => {
|
|
191
|
-
const relativePath = args.path.replace(/^@config\//, "");
|
|
192
|
-
return {
|
|
193
|
-
path: path.resolve("../obsidian-plugin-config/src", relativePath)
|
|
194
|
-
};
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
build.onResolve({ filter: /^@config-scripts\// }, (args) => {
|
|
198
|
-
const relativePath = args.path.replace(/^@config-scripts\//, "");
|
|
199
|
-
return {
|
|
200
|
-
path: path.resolve("../obsidian-plugin-config/scripts", relativePath)
|
|
201
|
-
};
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
name: "copy-to-plugins-folder",
|
|
207
|
-
setup: (build): void => {
|
|
208
|
-
build.onEnd(async () => {
|
|
209
|
-
// if real or build
|
|
210
|
-
if (isProd) {
|
|
211
|
-
if (process.argv.includes("-r") || process.argv.includes("real")) {
|
|
212
|
-
await copyFilesToTargetDir(buildPath);
|
|
213
|
-
console.log(`Successfully installed in ${buildPath}`);
|
|
214
|
-
} else {
|
|
215
|
-
const folderToRemove = path.join(buildPath, "_.._");
|
|
216
|
-
if (await isValidPath(folderToRemove)) {
|
|
217
|
-
await rm(folderToRemove, { recursive: true });
|
|
218
|
-
}
|
|
219
|
-
console.log("Built done in initial folder");
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
// if watch (dev)
|
|
223
|
-
else {
|
|
224
|
-
await copyFilesToTargetDir(buildPath);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
]
|
|
258
|
+
plugins
|
|
230
259
|
});
|
|
231
260
|
}
|
|
232
261
|
|
|
@@ -238,12 +267,20 @@ async function main(): Promise<void> {
|
|
|
238
267
|
console.log(buildPath === pluginDir
|
|
239
268
|
? "Building in initial folder"
|
|
240
269
|
: `Building in ${buildPath}`);
|
|
270
|
+
|
|
271
|
+
// Check for SCSS first, then CSS in src, then in root
|
|
272
|
+
const srcStylesScssPath = path.join(pluginDir, "src/styles.scss");
|
|
241
273
|
const srcStylesPath = path.join(pluginDir, "src/styles.css");
|
|
242
274
|
const rootStylesPath = path.join(pluginDir, "styles.css");
|
|
243
|
-
|
|
275
|
+
|
|
276
|
+
const scssExists = await isValidPath(srcStylesScssPath);
|
|
277
|
+
const stylePath = scssExists ? srcStylesScssPath :
|
|
278
|
+
await isValidPath(srcStylesPath) ? srcStylesPath :
|
|
279
|
+
await isValidPath(rootStylesPath) ? rootStylesPath : "";
|
|
280
|
+
|
|
244
281
|
const mainTsPath = path.join(pluginDir, "src/main.ts");
|
|
245
282
|
const entryPoints = stylePath ? [mainTsPath, stylePath] : [mainTsPath];
|
|
246
|
-
const context = await createBuildContext(buildPath, isProd, entryPoints);
|
|
283
|
+
const context = await createBuildContext(buildPath, isProd, entryPoints, scssExists);
|
|
247
284
|
|
|
248
285
|
if (isProd) {
|
|
249
286
|
await context.rebuild();
|
|
@@ -145,4 +145,19 @@ export async function ensureGitSync(): Promise<void> {
|
|
|
145
145
|
console.error(`❌ Git sync failed: ${error.message}`);
|
|
146
146
|
throw error;
|
|
147
147
|
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Remove main.css file generated by esbuild when compiling SCSS
|
|
152
|
+
* This prevents the unwanted main.css from being included in the plugin
|
|
153
|
+
*/
|
|
154
|
+
export async function removeMainCss(outdir: string): Promise<void> {
|
|
155
|
+
const mainCssPath = path.join(outdir, 'main.css');
|
|
156
|
+
try {
|
|
157
|
+
await rm(mainCssPath);
|
|
158
|
+
} catch (error: any) {
|
|
159
|
+
if (error.code !== 'ENOENT') {
|
|
160
|
+
console.warn(`Warning: Could not remove main.css: ${error.message}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
148
163
|
}
|