obsidian-plugin-config 1.7.1 → 1.7.3
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 +205 -205
- package/bin/obsidian-inject.js +1 -1
- package/docs/INTERACTIVE_INJECTION.md +1 -1
- package/docs/LLM-GUIDE.md +131 -130
- package/docs/SCSS-FLOW.md +273 -0
- package/docs/audit.md +39 -0
- package/package.json +7 -1
- package/scripts/acp.ts +5 -2
- package/scripts/build-npm.ts +393 -393
- package/scripts/help.ts +87 -87
- package/scripts/inject-core.ts +898 -897
- package/scripts/inject-path.ts +156 -156
- package/scripts/inject-prompt.ts +104 -104
- package/scripts/utils.ts +151 -151
- package/templates/.github/workflows/release.yml +2 -2
- package/templates/{package.json → package.json.template} +1 -1
- package/templates/scripts/acp.ts +5 -2
- package/templates/scripts/esbuild.config.ts +3 -3
- package/templates/scripts/utils.ts +13 -12
- package/tsconfig.json +4 -4
- /package/templates/{tsconfig.json → tsconfig.json.template} +0 -0
package/scripts/utils.ts
CHANGED
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
import { access, mkdir, copyFile, rm } from 'fs/promises';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import * as readline from 'readline';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
|
-
|
|
6
|
-
export function createReadlineInterface(): readline.Interface {
|
|
7
|
-
return readline.createInterface({
|
|
8
|
-
input: process.stdin as NodeJS.ReadableStream,
|
|
9
|
-
output: process.stdout as NodeJS.WritableStream
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const askQuestion = async (
|
|
14
|
-
question: string,
|
|
15
|
-
rl: readline.Interface
|
|
16
|
-
): Promise<string> => {
|
|
17
|
-
try {
|
|
18
|
-
return await new Promise((resolve) =>
|
|
19
|
-
rl.question(question, (input) => resolve(input.trim()))
|
|
20
|
-
);
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error('Error asking question:', error);
|
|
23
|
-
throw error;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Ask a yes/no confirmation question with standardized logic
|
|
29
|
-
* Accepts: y, yes, Y, YES, or empty (default to yes)
|
|
30
|
-
* Rejects: n, no, N, NO
|
|
31
|
-
* Invalid input defaults to no for safety
|
|
32
|
-
*/
|
|
33
|
-
export const askConfirmation = async (
|
|
34
|
-
question: string,
|
|
35
|
-
rl: readline.Interface
|
|
36
|
-
): Promise<boolean> => {
|
|
37
|
-
const answer = await askQuestion(`${question} [Y/n]: `, rl);
|
|
38
|
-
const response = answer.toLowerCase();
|
|
39
|
-
|
|
40
|
-
// Accept: y, yes, Y, YES, or empty (default to yes)
|
|
41
|
-
// Reject: n, no, N, NO
|
|
42
|
-
const isYes = response === '' || response === 'y' || response === 'yes';
|
|
43
|
-
const isNo = response === 'n' || response === 'no';
|
|
44
|
-
|
|
45
|
-
if (isNo) {
|
|
46
|
-
return false;
|
|
47
|
-
} else if (isYes) {
|
|
48
|
-
return true;
|
|
49
|
-
} else {
|
|
50
|
-
console.log('Please answer Y (yes) or n (no). Defaulting to no for safety.');
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const cleanInput = (inputStr: string): string => {
|
|
56
|
-
if (!inputStr) return '';
|
|
57
|
-
return inputStr.trim().replace(/["`]/g, "'").replace(/\r\n/g, '\n');
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export const isValidPath = async (pathToCheck: string): Promise<boolean> => {
|
|
61
|
-
if (!pathToCheck) return false;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
// Using async fs.access is preferred over synchronous existsSync
|
|
65
|
-
// as it doesn't block the main thread/event loop
|
|
66
|
-
await access(pathToCheck.trim());
|
|
67
|
-
return true;
|
|
68
|
-
} catch {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
|
|
74
|
-
const pluginDir = process.cwd();
|
|
75
|
-
const manifestSrc = path.join(pluginDir, 'manifest.json');
|
|
76
|
-
const manifestDest = path.join(buildPath, 'manifest.json');
|
|
77
|
-
const cssDest = path.join(buildPath, 'styles.css');
|
|
78
|
-
const folderToRemove = path.join(buildPath, '_.._');
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
await mkdir(buildPath, { recursive: true });
|
|
82
|
-
} catch (error: unknown) {
|
|
83
|
-
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
|
|
84
|
-
console.error(`Error creating directory: ${(error as Error).message}`);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Copy manifest
|
|
89
|
-
try {
|
|
90
|
-
await copyFile(manifestSrc, manifestDest);
|
|
91
|
-
} catch (error: unknown) {
|
|
92
|
-
console.error(`Error copying manifest: ${(error as Error).message}`);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Copy CSS
|
|
96
|
-
try {
|
|
97
|
-
const srcStylesPath = path.join(pluginDir, 'src/styles.css');
|
|
98
|
-
const rootStylesPath = path.join(pluginDir, 'styles.css');
|
|
99
|
-
|
|
100
|
-
// First check if CSS exists in src/styles.css
|
|
101
|
-
if (await isValidPath(srcStylesPath)) {
|
|
102
|
-
await copyFile(srcStylesPath, cssDest);
|
|
103
|
-
}
|
|
104
|
-
// Otherwise, check if it exists in the root
|
|
105
|
-
else if (await isValidPath(rootStylesPath)) {
|
|
106
|
-
await copyFile(rootStylesPath, cssDest);
|
|
107
|
-
if (await isValidPath(folderToRemove)) {
|
|
108
|
-
await rm(folderToRemove, { recursive: true });
|
|
109
|
-
}
|
|
110
|
-
} else {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
} catch (error: unknown) {
|
|
114
|
-
console.error(`Error copying CSS: ${(error as Error).message}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function gitExec(command: string): void {
|
|
119
|
-
try {
|
|
120
|
-
execSync(command, { stdio: 'inherit' });
|
|
121
|
-
} catch (error: unknown) {
|
|
122
|
-
console.error(`Error executing '${command}':`, (error as Error).message);
|
|
123
|
-
throw error;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Ensure Git repository is synchronized with remote before pushing
|
|
129
|
-
*/
|
|
130
|
-
export async function ensureGitSync(): Promise<void> {
|
|
131
|
-
try {
|
|
132
|
-
console.log('🔄 Checking Git synchronization...');
|
|
133
|
-
|
|
134
|
-
// Fetch latest changes from remote
|
|
135
|
-
execSync('git fetch origin', { stdio: 'pipe' });
|
|
136
|
-
|
|
137
|
-
// Check if branch is behind remote
|
|
138
|
-
const status = execSync('git status --porcelain -b', { encoding: 'utf8' });
|
|
139
|
-
|
|
140
|
-
if (status.includes('behind')) {
|
|
141
|
-
console.log('📥 Branch behind remote. Pulling changes...');
|
|
142
|
-
execSync('git pull', { stdio: 'inherit' });
|
|
143
|
-
console.log('✅ Successfully pulled remote changes');
|
|
144
|
-
} else {
|
|
145
|
-
console.log('✅ Repository is synchronized with remote');
|
|
146
|
-
}
|
|
147
|
-
} catch (error: unknown) {
|
|
148
|
-
console.error(`❌ Git sync failed: ${(error as Error).message}`);
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
1
|
+
import { access, mkdir, copyFile, rm } from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import * as readline from 'readline';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
|
|
6
|
+
export function createReadlineInterface(): readline.Interface {
|
|
7
|
+
return readline.createInterface({
|
|
8
|
+
input: process.stdin as NodeJS.ReadableStream,
|
|
9
|
+
output: process.stdout as NodeJS.WritableStream
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const askQuestion = async (
|
|
14
|
+
question: string,
|
|
15
|
+
rl: readline.Interface
|
|
16
|
+
): Promise<string> => {
|
|
17
|
+
try {
|
|
18
|
+
return await new Promise((resolve) =>
|
|
19
|
+
rl.question(question, (input) => resolve(input.trim()))
|
|
20
|
+
);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Error asking question:', error);
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Ask a yes/no confirmation question with standardized logic
|
|
29
|
+
* Accepts: y, yes, Y, YES, or empty (default to yes)
|
|
30
|
+
* Rejects: n, no, N, NO
|
|
31
|
+
* Invalid input defaults to no for safety
|
|
32
|
+
*/
|
|
33
|
+
export const askConfirmation = async (
|
|
34
|
+
question: string,
|
|
35
|
+
rl: readline.Interface
|
|
36
|
+
): Promise<boolean> => {
|
|
37
|
+
const answer = await askQuestion(`${question} [Y/n]: `, rl);
|
|
38
|
+
const response = answer.toLowerCase();
|
|
39
|
+
|
|
40
|
+
// Accept: y, yes, Y, YES, or empty (default to yes)
|
|
41
|
+
// Reject: n, no, N, NO
|
|
42
|
+
const isYes = response === '' || response === 'y' || response === 'yes';
|
|
43
|
+
const isNo = response === 'n' || response === 'no';
|
|
44
|
+
|
|
45
|
+
if (isNo) {
|
|
46
|
+
return false;
|
|
47
|
+
} else if (isYes) {
|
|
48
|
+
return true;
|
|
49
|
+
} else {
|
|
50
|
+
console.log('Please answer Y (yes) or n (no). Defaulting to no for safety.');
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const cleanInput = (inputStr: string): string => {
|
|
56
|
+
if (!inputStr) return '';
|
|
57
|
+
return inputStr.trim().replace(/["`]/g, "'").replace(/\r\n/g, '\n');
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const isValidPath = async (pathToCheck: string): Promise<boolean> => {
|
|
61
|
+
if (!pathToCheck) return false;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
// Using async fs.access is preferred over synchronous existsSync
|
|
65
|
+
// as it doesn't block the main thread/event loop
|
|
66
|
+
await access(pathToCheck.trim());
|
|
67
|
+
return true;
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
|
|
74
|
+
const pluginDir = process.cwd();
|
|
75
|
+
const manifestSrc = path.join(pluginDir, 'manifest.json');
|
|
76
|
+
const manifestDest = path.join(buildPath, 'manifest.json');
|
|
77
|
+
const cssDest = path.join(buildPath, 'styles.css');
|
|
78
|
+
const folderToRemove = path.join(buildPath, '_.._');
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await mkdir(buildPath, { recursive: true });
|
|
82
|
+
} catch (error: unknown) {
|
|
83
|
+
if ((error as NodeJS.ErrnoException).code !== 'EEXIST') {
|
|
84
|
+
console.error(`Error creating directory: ${(error as Error).message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Copy manifest
|
|
89
|
+
try {
|
|
90
|
+
await copyFile(manifestSrc, manifestDest);
|
|
91
|
+
} catch (error: unknown) {
|
|
92
|
+
console.error(`Error copying manifest: ${(error as Error).message}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Copy CSS
|
|
96
|
+
try {
|
|
97
|
+
const srcStylesPath = path.join(pluginDir, 'src/styles.css');
|
|
98
|
+
const rootStylesPath = path.join(pluginDir, 'styles.css');
|
|
99
|
+
|
|
100
|
+
// First check if CSS exists in src/styles.css
|
|
101
|
+
if (await isValidPath(srcStylesPath)) {
|
|
102
|
+
await copyFile(srcStylesPath, cssDest);
|
|
103
|
+
}
|
|
104
|
+
// Otherwise, check if it exists in the root
|
|
105
|
+
else if (await isValidPath(rootStylesPath)) {
|
|
106
|
+
await copyFile(rootStylesPath, cssDest);
|
|
107
|
+
if (await isValidPath(folderToRemove)) {
|
|
108
|
+
await rm(folderToRemove, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
} catch (error: unknown) {
|
|
114
|
+
console.error(`Error copying CSS: ${(error as Error).message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function gitExec(command: string, cwd?: string): void {
|
|
119
|
+
try {
|
|
120
|
+
execSync(command, { stdio: 'inherit', ...(cwd ? { cwd } : {}) });
|
|
121
|
+
} catch (error: unknown) {
|
|
122
|
+
console.error(`Error executing '${command}':`, (error as Error).message);
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Ensure Git repository is synchronized with remote before pushing
|
|
129
|
+
*/
|
|
130
|
+
export async function ensureGitSync(): Promise<void> {
|
|
131
|
+
try {
|
|
132
|
+
console.log('🔄 Checking Git synchronization...');
|
|
133
|
+
|
|
134
|
+
// Fetch latest changes from remote
|
|
135
|
+
execSync('git fetch origin', { stdio: 'pipe' });
|
|
136
|
+
|
|
137
|
+
// Check if branch is behind remote
|
|
138
|
+
const status = execSync('git status --porcelain -b', { encoding: 'utf8' });
|
|
139
|
+
|
|
140
|
+
if (status.includes('behind')) {
|
|
141
|
+
console.log('📥 Branch behind remote. Pulling changes...');
|
|
142
|
+
execSync('git pull', { stdio: 'inherit' });
|
|
143
|
+
console.log('✅ Successfully pulled remote changes');
|
|
144
|
+
} else {
|
|
145
|
+
console.log('✅ Repository is synchronized with remote');
|
|
146
|
+
}
|
|
147
|
+
} catch (error: unknown) {
|
|
148
|
+
console.error(`❌ Git sync failed: ${(error as Error).message}`);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
package/templates/scripts/acp.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
1
|
+
import { execSync, spawnSync } from 'child_process';
|
|
2
2
|
import {
|
|
3
3
|
askQuestion,
|
|
4
4
|
cleanInput,
|
|
@@ -23,7 +23,10 @@ async function main(): Promise<void> {
|
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
25
|
gitExec('git add -A');
|
|
26
|
-
|
|
26
|
+
const result = spawnSync('git', ['commit', '-m', cleanedInput], { stdio: 'inherit' });
|
|
27
|
+
if (result.status !== 0) {
|
|
28
|
+
throw new Error('Commit failed');
|
|
29
|
+
}
|
|
27
30
|
} catch {
|
|
28
31
|
console.log('Commit already exists or failed.');
|
|
29
32
|
return;
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
copyFilesToTargetDir,
|
|
17
17
|
createReadlineInterface,
|
|
18
18
|
isValidPath,
|
|
19
|
-
|
|
19
|
+
renameMainCss
|
|
20
20
|
} from './utils.ts';
|
|
21
21
|
import { reloadObsidian } from './reload.ts';
|
|
22
22
|
|
|
@@ -56,11 +56,11 @@ async function createBuildContext(
|
|
|
56
56
|
}
|
|
57
57
|
})(),
|
|
58
58
|
{
|
|
59
|
-
name: '
|
|
59
|
+
name: 'rename-main-css',
|
|
60
60
|
setup(build: esbuild.PluginBuild): void {
|
|
61
61
|
build.onEnd(async (result) => {
|
|
62
62
|
if (result.errors.length === 0) {
|
|
63
|
-
await
|
|
63
|
+
await renameMainCss(buildPath);
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { access, mkdir, copyFile, rm, writeFile } from 'fs/promises';
|
|
1
|
+
import { access, mkdir, copyFile, rm, writeFile, rename } from 'fs/promises';
|
|
2
2
|
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import * as readline from 'readline';
|
|
@@ -122,9 +122,9 @@ export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
export function gitExec(command: string): void {
|
|
125
|
+
export function gitExec(command: string, cwd?: string): void {
|
|
126
126
|
try {
|
|
127
|
-
execSync(command, { stdio: 'inherit' });
|
|
127
|
+
execSync(command, { stdio: 'inherit', ...(cwd ? { cwd } : {}) });
|
|
128
128
|
} catch (error: unknown) {
|
|
129
129
|
console.error(
|
|
130
130
|
`Error executing '${command}':`,
|
|
@@ -163,19 +163,20 @@ export async function ensureGitSync(): Promise<void> {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
|
-
*
|
|
167
|
-
* This
|
|
166
|
+
* Rename main.css file generated by esbuild when compiling SCSS to styles.css
|
|
167
|
+
* This ensures the compiled CSS is correctly recognized by Obsidian
|
|
168
168
|
*/
|
|
169
|
-
export async function
|
|
169
|
+
export async function renameMainCss(outdir: string): Promise<void> {
|
|
170
170
|
const mainCssPath = path.join(outdir, 'main.css');
|
|
171
|
+
const stylesCssPath = path.join(outdir, 'styles.css');
|
|
171
172
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
|
|
175
|
-
console.warn(
|
|
176
|
-
`Warning: Could not remove main.css: ${error instanceof Error ? error.message : String(error)}`
|
|
177
|
-
);
|
|
173
|
+
if (existsSync(mainCssPath)) {
|
|
174
|
+
await rename(mainCssPath, stylesCssPath);
|
|
178
175
|
}
|
|
176
|
+
} catch (error: unknown) {
|
|
177
|
+
console.warn(
|
|
178
|
+
`Warning: Could not rename main.css to styles.css: ${error instanceof Error ? error.message : String(error)}`
|
|
179
|
+
);
|
|
179
180
|
}
|
|
180
181
|
}
|
|
181
182
|
|
package/tsconfig.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"inlineSources": true,
|
|
6
6
|
"module": "NodeNext",
|
|
7
7
|
"moduleResolution": "NodeNext",
|
|
8
|
-
"target": "
|
|
8
|
+
"target": "ES2022",
|
|
9
9
|
"allowJs": true,
|
|
10
10
|
"noImplicitAny": true,
|
|
11
11
|
"importHelpers": true,
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"forceConsistentCasingInFileNames": true,
|
|
18
18
|
"strictNullChecks": true,
|
|
19
19
|
"resolveJsonModule": true,
|
|
20
|
-
"lib": ["DOM", "
|
|
20
|
+
"lib": ["DOM", "ES2024"]
|
|
21
21
|
},
|
|
22
|
-
"include": ["./scripts/**/*.ts"],
|
|
23
|
-
"exclude": ["node_modules", "eslint.config.ts"
|
|
22
|
+
"include": ["./scripts/**/*.ts", "templates/**/*.ts"],
|
|
23
|
+
"exclude": ["node_modules", "eslint.config.ts"]
|
|
24
24
|
}
|
|
File without changes
|