obsidian-plugin-config 1.0.2
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/.vscode/settings.json +4 -0
- package/README.md +45 -0
- package/bin/obsidian-inject.js +98 -0
- package/obsidian-plugin-config-1.0.2.tgz +0 -0
- package/package.json +88 -0
- package/scripts/acp.ts +71 -0
- package/scripts/build-npm.ts +137 -0
- package/scripts/esbuild.config.ts +311 -0
- package/scripts/help.ts +46 -0
- package/scripts/inject-path.ts +487 -0
- package/scripts/inject-prompt.ts +399 -0
- package/scripts/open-editor.mjs +18 -0
- package/scripts/release.ts +97 -0
- package/scripts/update-exports.js +91 -0
- package/scripts/update-version-config.ts +98 -0
- package/scripts/update-version.ts +102 -0
- package/scripts/utils.ts +117 -0
- package/src/index.ts +6 -0
- package/src/main_test.ts +106 -0
- package/src/modals/GenericConfirmModal.ts +67 -0
- package/src/modals/index.ts +3 -0
- package/src/test-centralized-utils.ts +23 -0
- package/src/tools/index.ts +9 -0
- package/src/utils/NoticeHelper.ts +102 -0
- package/src/utils/SettingsHelper.ts +180 -0
- package/src/utils/index.ts +3 -0
- package/templates/.vscode/settings.json +4 -0
- package/templates/eslint.config.ts +48 -0
- package/templates/help-plugin.ts +39 -0
- package/templates/package-versions.json +28 -0
- package/templates/tsconfig.json +37 -0
- package/test-plugin/manifest.json +10 -0
- package/test-plugin/package.json +38 -0
- package/test-plugin/scripts/acp.ts +71 -0
- package/test-plugin/scripts/esbuild.config.ts +165 -0
- package/test-plugin/scripts/help.ts +29 -0
- package/test-plugin/scripts/release.ts +97 -0
- package/test-plugin/scripts/update-version.ts +102 -0
- package/test-plugin/scripts/utils.ts +117 -0
- package/test-plugin/src/main.ts +11 -0
- package/test-plugin/yarn.lock +386 -0
- package/test-plugin-v2/main.js +5 -0
- package/test-plugin-v2/manifest.json +10 -0
- package/test-plugin-v2/package.json +40 -0
- package/test-plugin-v2/scripts/acp.ts +71 -0
- package/test-plugin-v2/scripts/esbuild.config.ts +165 -0
- package/test-plugin-v2/scripts/help.ts +29 -0
- package/test-plugin-v2/scripts/release.ts +97 -0
- package/test-plugin-v2/scripts/update-version.ts +102 -0
- package/test-plugin-v2/scripts/utils.ts +117 -0
- package/test-plugin-v2/src/main.ts +11 -0
- package/test-plugin-v2/tsconfig.json +31 -0
- package/test-plugin-v2/yarn.lock +1986 -0
- package/tsconfig.json +38 -0
- package/versions.json +5 -0
|
@@ -0,0 +1,165 @@
|
|
|
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 { isValidPath, copyFilesToTargetDir } from "./utils.ts";
|
|
9
|
+
|
|
10
|
+
// Determine the plugin directory (where the script is called from)
|
|
11
|
+
const pluginDir = process.cwd();
|
|
12
|
+
const manifestPath = path.join(pluginDir, "manifest.json");
|
|
13
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
14
|
+
|
|
15
|
+
config();
|
|
16
|
+
|
|
17
|
+
const EXTERNAL_DEPS = [
|
|
18
|
+
"obsidian",
|
|
19
|
+
"electron",
|
|
20
|
+
"@codemirror/autocomplete",
|
|
21
|
+
"@codemirror/collab",
|
|
22
|
+
"@codemirror/commands",
|
|
23
|
+
"@codemirror/language",
|
|
24
|
+
"@codemirror/lint",
|
|
25
|
+
"@codemirror/search",
|
|
26
|
+
"@codemirror/state",
|
|
27
|
+
"@codemirror/view",
|
|
28
|
+
"@lezer/common",
|
|
29
|
+
"@lezer/highlight",
|
|
30
|
+
"@lezer/lr",
|
|
31
|
+
...builtins
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const BANNER = `/*
|
|
35
|
+
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
36
|
+
if you want to view the source, please visit the github repository of this plugin
|
|
37
|
+
*/`;
|
|
38
|
+
|
|
39
|
+
async function validateEnvironment(): Promise<void> {
|
|
40
|
+
const srcMainPath = path.join(pluginDir, "src/main.ts");
|
|
41
|
+
if (!await isValidPath(srcMainPath)) {
|
|
42
|
+
throw new Error("Invalid path for src/main.ts. main.ts must be in the src directory");
|
|
43
|
+
}
|
|
44
|
+
if (!await isValidPath(manifestPath)) {
|
|
45
|
+
throw new Error("Invalid path for manifest.json");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getBuildPath(isProd: boolean): string {
|
|
50
|
+
// If production build without redirection, return plugin directory
|
|
51
|
+
if (isProd && !process.argv.includes("-r")) {
|
|
52
|
+
return pluginDir;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Determine which path to use
|
|
56
|
+
const envKey = process.argv.includes("-r") ? "REAL_VAULT" : "TEST_VAULT";
|
|
57
|
+
const vaultPath = process.env[envKey]?.trim();
|
|
58
|
+
|
|
59
|
+
// If empty or undefined, we're already in the plugin folder
|
|
60
|
+
if (!vaultPath) {
|
|
61
|
+
return pluginDir;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check if the path already contains the plugins directory path
|
|
65
|
+
const pluginsPath = path.join(".obsidian", "plugins");
|
|
66
|
+
if (vaultPath.includes(pluginsPath)) {
|
|
67
|
+
// Just add the manifest id to complete the path
|
|
68
|
+
return path.join(vaultPath, manifest.id);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Otherwise, complete the full path
|
|
72
|
+
return path.join(vaultPath, ".obsidian", "plugins", manifest.id);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function createBuildContext(buildPath: string, isProd: boolean, entryPoints: string[]): Promise<esbuild.BuildContext> {
|
|
76
|
+
return await esbuild.context({
|
|
77
|
+
banner: { js: BANNER },
|
|
78
|
+
minify: isProd,
|
|
79
|
+
entryPoints,
|
|
80
|
+
bundle: true,
|
|
81
|
+
external: EXTERNAL_DEPS,
|
|
82
|
+
format: "cjs",
|
|
83
|
+
target: "esNext",
|
|
84
|
+
platform: "node",
|
|
85
|
+
logLevel: "info",
|
|
86
|
+
sourcemap: isProd ? false : "inline",
|
|
87
|
+
treeShaking: true,
|
|
88
|
+
outdir: buildPath,
|
|
89
|
+
outbase: path.join(pluginDir, "src"),
|
|
90
|
+
plugins: [
|
|
91
|
+
// Plugin pour gérer les alias de chemin
|
|
92
|
+
{
|
|
93
|
+
name: "path-alias",
|
|
94
|
+
setup: (build): void => {
|
|
95
|
+
build.onResolve({ filter: /^@config\// }, (args) => {
|
|
96
|
+
const relativePath = args.path.replace(/^@config\//, "");
|
|
97
|
+
return {
|
|
98
|
+
path: path.resolve("../obsidian-plugin-config/src", relativePath)
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
build.onResolve({ filter: /^@config-scripts\// }, (args) => {
|
|
103
|
+
const relativePath = args.path.replace(/^@config-scripts\//, "");
|
|
104
|
+
return {
|
|
105
|
+
path: path.resolve("../obsidian-plugin-config/scripts", relativePath)
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "copy-to-plugins-folder",
|
|
112
|
+
setup: (build): void => {
|
|
113
|
+
build.onEnd(async () => {
|
|
114
|
+
// if real or build
|
|
115
|
+
if (isProd) {
|
|
116
|
+
if (process.argv.includes("-r")) {
|
|
117
|
+
await copyFilesToTargetDir(buildPath);
|
|
118
|
+
console.log(`Successfully installed in ${buildPath}`);
|
|
119
|
+
} else {
|
|
120
|
+
const folderToRemove = path.join(buildPath, "_.._");
|
|
121
|
+
if (await isValidPath(folderToRemove)) {
|
|
122
|
+
await rm(folderToRemove, { recursive: true });
|
|
123
|
+
}
|
|
124
|
+
console.log("Built done in initial folder");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// if watch (dev)
|
|
128
|
+
else {
|
|
129
|
+
await copyFilesToTargetDir(buildPath);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function main(): Promise<void> {
|
|
139
|
+
try {
|
|
140
|
+
await validateEnvironment();
|
|
141
|
+
const isProd = process.argv[2] === "production";
|
|
142
|
+
const buildPath = getBuildPath(isProd);
|
|
143
|
+
console.log(buildPath === pluginDir
|
|
144
|
+
? "Building in initial folder"
|
|
145
|
+
: `Building in ${buildPath}`);
|
|
146
|
+
const srcStylesPath = path.join(pluginDir, "src/styles.css");
|
|
147
|
+
const rootStylesPath = path.join(pluginDir, "styles.css");
|
|
148
|
+
const stylePath = await isValidPath(srcStylesPath) ? srcStylesPath : await isValidPath(rootStylesPath) ? rootStylesPath : "";
|
|
149
|
+
const mainTsPath = path.join(pluginDir, "src/main.ts");
|
|
150
|
+
const entryPoints = stylePath ? [mainTsPath, stylePath] : [mainTsPath];
|
|
151
|
+
const context = await createBuildContext(buildPath, isProd, entryPoints);
|
|
152
|
+
|
|
153
|
+
if (isProd) {
|
|
154
|
+
await context.rebuild();
|
|
155
|
+
process.exit(0);
|
|
156
|
+
} else {
|
|
157
|
+
await context.watch();
|
|
158
|
+
}
|
|
159
|
+
} catch (error) {
|
|
160
|
+
console.error("Build failed:", error);
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
console.log(`
|
|
4
|
+
Obsidian Plugin Config - Command Reference
|
|
5
|
+
(Run these commands from obsidian-plugin-config directory)
|
|
6
|
+
|
|
7
|
+
MIGRATION:
|
|
8
|
+
yarn migrate, m <path> Migrate plugin to centralized architecture
|
|
9
|
+
yarn migrate --dry-run Preview changes without applying (debugging)
|
|
10
|
+
yarn migrate -i, --interactive Interactive plugin selection
|
|
11
|
+
|
|
12
|
+
MAINTENANCE:
|
|
13
|
+
yarn start Install dependencies and update exports
|
|
14
|
+
yarn acp Add, commit, and push changes (with exports update)
|
|
15
|
+
yarn acp -ne, --no-exports Add, commit, and push without updating exports
|
|
16
|
+
yarn update-version, v Update version in centralized config
|
|
17
|
+
yarn help, h Show this help
|
|
18
|
+
|
|
19
|
+
USAGE EXAMPLES:
|
|
20
|
+
yarn migrate "C:\\Users\\dev\\plugins\\my-plugin"
|
|
21
|
+
yarn migrate ../existing-plugin --dry-run
|
|
22
|
+
yarn m -i # Short interactive mode
|
|
23
|
+
|
|
24
|
+
PATH CONVENTIONS:
|
|
25
|
+
- Windows absolute paths: Use quotes "C:\\path\\to\\plugin"
|
|
26
|
+
- Relative paths: No quotes needed ../plugin-name
|
|
27
|
+
|
|
28
|
+
For detailed documentation: ARCHITECTURE-SUMMARY.md
|
|
29
|
+
`);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeFile,
|
|
3
|
+
stat
|
|
4
|
+
} from "fs/promises";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
import dedent from "dedent";
|
|
7
|
+
import {
|
|
8
|
+
askQuestion,
|
|
9
|
+
askConfirmation,
|
|
10
|
+
createReadlineInterface
|
|
11
|
+
} from "./utils.ts";
|
|
12
|
+
|
|
13
|
+
const rl = createReadlineInterface();
|
|
14
|
+
|
|
15
|
+
const body = ".github/workflows/release-body.md";
|
|
16
|
+
|
|
17
|
+
async function checkOrCreateFile(filename: string): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
await stat(filename);
|
|
20
|
+
} catch {
|
|
21
|
+
console.log(`Creating ${filename} because it doesn't exist. Avoid deleting it.`);
|
|
22
|
+
await writeFile(filename, "");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function createReleaseNotesFile(tagMessage: string, tag: string): Promise<void> {
|
|
27
|
+
await writeFile(body, tagMessage);
|
|
28
|
+
console.log(`Release notes for tag ${tag} have been written to release-body.md`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function handleExistingTag(tag: string): Promise<boolean> {
|
|
32
|
+
const confirmed = await askConfirmation(`Tag ${tag} already exists. Do you want to replace it?`, rl);
|
|
33
|
+
|
|
34
|
+
if (!confirmed) {
|
|
35
|
+
console.log("Operation aborted");
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
execSync(`git tag -d ${tag}`);
|
|
40
|
+
execSync(`git push origin :refs/tags/${tag}`);
|
|
41
|
+
console.log(`Deleted existing tag ${tag} locally and remotely.`);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function createTag(): Promise<void> {
|
|
46
|
+
const currentVersion = process.env.npm_package_version;
|
|
47
|
+
const tag = `${currentVersion}`;
|
|
48
|
+
|
|
49
|
+
await checkOrCreateFile(body);
|
|
50
|
+
const exists = execSync("git ls-remote --tags origin").toString().includes(`refs/tags/${tag}`);
|
|
51
|
+
|
|
52
|
+
if (exists && !(await handleExistingTag(tag))) {
|
|
53
|
+
rl.close();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
await doCommit(currentVersion, tag);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
async function doCommit(currentVersion: string | undefined, tag: string): Promise<void> {
|
|
62
|
+
rl.question(`Enter the commit message for version ${currentVersion}: `, async (message) => {
|
|
63
|
+
doNextSteps(message, tag);
|
|
64
|
+
rl.close();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function doNextSteps(message: string, tag: string): Promise<void> {
|
|
69
|
+
const messages = message.split("\\n");
|
|
70
|
+
const toShow = message.replace(/\\n/g, "\n");
|
|
71
|
+
await createReleaseNotesFile(toShow, tag);
|
|
72
|
+
const tagMessage = messages.map(m => `-m "${m}"`).join(" ");
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
execSync("git add -A");
|
|
76
|
+
execSync("git commit -m \"update tag description\"");
|
|
77
|
+
execSync("git push");
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
console.error("Error:", error.message);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
execSync(`git tag -a ${tag} ${tagMessage}`);
|
|
83
|
+
} catch {
|
|
84
|
+
execSync(`git tag -d ${tag}`);
|
|
85
|
+
execSync(`git push origin :refs/tags/${tag}`);
|
|
86
|
+
console.log("Fixed");
|
|
87
|
+
execSync(`git tag -a ${tag} ${tagMessage}`);
|
|
88
|
+
}
|
|
89
|
+
execSync(`git push origin ${tag}`);
|
|
90
|
+
console.log(`Release ${tag} pushed to repo.`);
|
|
91
|
+
console.log(dedent`
|
|
92
|
+
with message:
|
|
93
|
+
${toShow}
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
createTag().catch(console.error);
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { readFile, writeFile } from "fs/promises";
|
|
2
|
+
import dedent from "dedent";
|
|
3
|
+
import { inc, valid } from "semver";
|
|
4
|
+
import { askQuestion, createReadlineInterface, gitExec } from "./utils.ts";
|
|
5
|
+
|
|
6
|
+
const rl = createReadlineInterface();
|
|
7
|
+
|
|
8
|
+
async function getTargetVersion(currentVersion: string): Promise<string> {
|
|
9
|
+
const updateType = await askQuestion(dedent`
|
|
10
|
+
Current version: ${currentVersion}
|
|
11
|
+
Kind of update:
|
|
12
|
+
patch(1.0.1) -> type 1 or p
|
|
13
|
+
minor(1.1.0) -> type 2 or min
|
|
14
|
+
major(2.0.0) -> type 3 or maj
|
|
15
|
+
or version number (e.g. 2.0.0)
|
|
16
|
+
Enter choice: `, rl);
|
|
17
|
+
|
|
18
|
+
switch (updateType.trim()) {
|
|
19
|
+
case "p":
|
|
20
|
+
case "1":
|
|
21
|
+
return inc(currentVersion, "patch") || "";
|
|
22
|
+
case "min":
|
|
23
|
+
case "2":
|
|
24
|
+
return inc(currentVersion, "minor") || "";
|
|
25
|
+
case "maj":
|
|
26
|
+
case "3":
|
|
27
|
+
return inc(currentVersion, "major") || "";
|
|
28
|
+
default:
|
|
29
|
+
return valid(updateType.trim()) || "";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function updateJsonFile(filename: string, updateFn: (json: any) => void): Promise<void> {
|
|
34
|
+
try {
|
|
35
|
+
const content = JSON.parse(await readFile(filename, "utf8"));
|
|
36
|
+
updateFn(content);
|
|
37
|
+
await writeFile(filename, JSON.stringify(content, null, "\t"));
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error(`Error updating ${filename}:`, error instanceof Error ? error.message : String(error));
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function updateManifestVersions(targetVersion: string): Promise<void> {
|
|
45
|
+
try {
|
|
46
|
+
const manifest = JSON.parse(await readFile("manifest.json", "utf8"));
|
|
47
|
+
const { minAppVersion } = manifest;
|
|
48
|
+
|
|
49
|
+
await Promise.all([
|
|
50
|
+
updateJsonFile("manifest.json", json => json.version = targetVersion),
|
|
51
|
+
updateJsonFile("versions.json", json => json[targetVersion] = minAppVersion),
|
|
52
|
+
updateJsonFile("package.json", json => json.version = targetVersion),
|
|
53
|
+
// updateJsonFile("package-lock.json", json => json.version = targetVersion)
|
|
54
|
+
]);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("Error updating manifest versions:", error instanceof Error ? error.message : String(error));
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function updateVersion(): Promise<void> {
|
|
62
|
+
try {
|
|
63
|
+
const currentVersion = process.env.npm_package_version || "1.0.0";
|
|
64
|
+
const targetVersion = await getTargetVersion(currentVersion);
|
|
65
|
+
|
|
66
|
+
if (!targetVersion) {
|
|
67
|
+
console.log("Invalid version");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// Update all files first
|
|
73
|
+
await updateManifestVersions(targetVersion);
|
|
74
|
+
console.log(`Files updated to version ${targetVersion}`);
|
|
75
|
+
|
|
76
|
+
// Add files to git
|
|
77
|
+
gitExec("git add manifest.json package.json versions.json");
|
|
78
|
+
gitExec(`git commit -m "Updated to version ${targetVersion}"`);
|
|
79
|
+
console.log("Changes committed");
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error("Error during update or commit:", error instanceof Error ? error.message : String(error));
|
|
82
|
+
console.log("Operation failed.");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
gitExec("git push");
|
|
88
|
+
console.log(`Version successfully updated to ${targetVersion} and pushed.`);
|
|
89
|
+
} catch (pushError) {
|
|
90
|
+
console.error("Failed to push version update:", pushError instanceof Error ? pushError.message : String(pushError));
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
94
|
+
} finally {
|
|
95
|
+
rl.close();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
updateVersion().catch(console.error).finally(() => {
|
|
100
|
+
console.log("Exiting...");
|
|
101
|
+
process.exit();
|
|
102
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
access,
|
|
3
|
+
mkdir,
|
|
4
|
+
copyFile,
|
|
5
|
+
rm
|
|
6
|
+
} from "fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import * as readline from "readline";
|
|
9
|
+
import { execSync } from "child_process";
|
|
10
|
+
|
|
11
|
+
export function createReadlineInterface(): readline.Interface {
|
|
12
|
+
return readline.createInterface({
|
|
13
|
+
input: process.stdin as NodeJS.ReadableStream,
|
|
14
|
+
output: process.stdout as NodeJS.WritableStream,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const askQuestion = async (question: string, rl: readline.Interface): Promise<string> => {
|
|
19
|
+
try {
|
|
20
|
+
return await new Promise(resolve => rl.question(question, input => resolve(input.trim())));
|
|
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 (question: string, rl: readline.Interface): Promise<boolean> => {
|
|
34
|
+
const answer = await askQuestion(`${question} [Y/n]: `, rl);
|
|
35
|
+
const response = answer.toLowerCase();
|
|
36
|
+
|
|
37
|
+
// Accept: y, yes, Y, YES, or empty (default to yes)
|
|
38
|
+
// Reject: n, no, N, NO
|
|
39
|
+
const isYes = response === '' || response === 'y' || response === 'yes';
|
|
40
|
+
const isNo = response === 'n' || response === 'no';
|
|
41
|
+
|
|
42
|
+
if (isNo) {
|
|
43
|
+
return false;
|
|
44
|
+
} else if (isYes) {
|
|
45
|
+
return true;
|
|
46
|
+
} else {
|
|
47
|
+
console.log("Please answer Y (yes) or n (no). Defaulting to no for safety.");
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const cleanInput = (inputStr: string): string => {
|
|
53
|
+
if (!inputStr) return "";
|
|
54
|
+
return inputStr.trim().replace(/["`]/g, "'").replace(/\r\n/g, "\n");
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const isValidPath = async (pathToCheck: string): Promise<boolean> => {
|
|
58
|
+
if (!pathToCheck) return false;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
// Using async fs.access is preferred over synchronous existsSync
|
|
62
|
+
// as it doesn't block the main thread/event loop
|
|
63
|
+
await access(pathToCheck.trim());
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export async function copyFilesToTargetDir(buildPath: string): Promise<void> {
|
|
71
|
+
const manifestDest = path.join(buildPath, "manifest.json");
|
|
72
|
+
const cssDest = path.join(buildPath, "styles.css");
|
|
73
|
+
const folderToRemove = path.join(buildPath, "_.._");
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
await mkdir(buildPath);
|
|
77
|
+
} catch (error: any) {
|
|
78
|
+
if (error.code !== "EEXIST") {
|
|
79
|
+
console.error(`Error creating directory: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Copy manifest
|
|
84
|
+
try {
|
|
85
|
+
await copyFile("./manifest.json", manifestDest);
|
|
86
|
+
} catch (error: any) {
|
|
87
|
+
console.error(`Error copying manifest: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Copy CSS
|
|
91
|
+
try {
|
|
92
|
+
// First check if CSS exists in src/styles.css
|
|
93
|
+
if (await isValidPath("./src/styles.css")) {
|
|
94
|
+
await copyFile("./src/styles.css", cssDest);
|
|
95
|
+
}
|
|
96
|
+
// Otherwise, check if it exists in the root
|
|
97
|
+
else if (await isValidPath("./styles.css")) {
|
|
98
|
+
await copyFile("./styles.css", cssDest);
|
|
99
|
+
if (await isValidPath(folderToRemove)) {
|
|
100
|
+
await rm(folderToRemove, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
} else {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
} catch (error: any) {
|
|
106
|
+
console.error(`Error copying CSS: ${error.message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function gitExec(command: string): void {
|
|
111
|
+
try {
|
|
112
|
+
execSync(command, { stdio: "inherit" });
|
|
113
|
+
} catch (error: any) {
|
|
114
|
+
console.error(`Error executing '${command}':`, error.message);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": ".",
|
|
4
|
+
"strict": true,
|
|
5
|
+
"strictPropertyInitialization": false,
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"importHelpers": true,
|
|
10
|
+
"lib": [
|
|
11
|
+
"DOM",
|
|
12
|
+
"ES2020"
|
|
13
|
+
],
|
|
14
|
+
"types": [
|
|
15
|
+
"node"
|
|
16
|
+
],
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"module": "ESNext",
|
|
19
|
+
"moduleResolution": "node",
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"noEmit": true,
|
|
22
|
+
"target": "ES2018",
|
|
23
|
+
"skipLibCheck": true
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"./src/**/*.ts"
|
|
27
|
+
],
|
|
28
|
+
"exclude": [
|
|
29
|
+
"node_modules"
|
|
30
|
+
]
|
|
31
|
+
}
|