@idajs/create-mod 0.2.15-dev.19 → 0.2.15-dev.37
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 +6 -0
- package/_project.config/archive.js +107 -0
- package/_project.config/build.js +22 -37
- package/_project.config/package.template.json +6 -6
- package/_project.config/remote.js +6 -20
- package/index.js +90 -1
- package/install.js +154 -45
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,12 @@ npx @idajs/create-mod
|
|
|
24
24
|
|
|
25
25
|
The tool will guide you through the setup process with interactive prompts.
|
|
26
26
|
|
|
27
|
+
Refresh scaffolder-managed files in an existing mod project:
|
|
28
|
+
|
|
29
|
+
```pwsh
|
|
30
|
+
npx @idajs/create-mod --update
|
|
31
|
+
```
|
|
32
|
+
|
|
27
33
|
## Usage
|
|
28
34
|
|
|
29
35
|
```pwsh
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const yazl = require("yazl");
|
|
4
|
+
|
|
5
|
+
function normalizeZipPath(value) {
|
|
6
|
+
return String(value || "")
|
|
7
|
+
.split(path.sep)
|
|
8
|
+
.join("/")
|
|
9
|
+
.replace(/\/+/g, "/")
|
|
10
|
+
.replace(/^\/+/, "")
|
|
11
|
+
.replace(/\/+$/, "");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async function collectDirectoryEntries(sourceDir, zipRoot) {
|
|
15
|
+
const dirents = await fs.promises.readdir(sourceDir, { withFileTypes: true });
|
|
16
|
+
const sortedDirents = dirents.slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
17
|
+
const entries = [];
|
|
18
|
+
|
|
19
|
+
if (sortedDirents.length === 0 && zipRoot) {
|
|
20
|
+
entries.push({
|
|
21
|
+
type: "directory",
|
|
22
|
+
metadataPath: normalizeZipPath(zipRoot),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const dirent of sortedDirents) {
|
|
27
|
+
const sourcePath = path.join(sourceDir, dirent.name);
|
|
28
|
+
const metadataPath = normalizeZipPath(path.posix.join(zipRoot, dirent.name));
|
|
29
|
+
|
|
30
|
+
if (dirent.isDirectory()) {
|
|
31
|
+
entries.push(...(await collectDirectoryEntries(sourcePath, metadataPath)));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (dirent.isFile()) {
|
|
36
|
+
entries.push({
|
|
37
|
+
type: "file",
|
|
38
|
+
sourcePath,
|
|
39
|
+
metadataPath,
|
|
40
|
+
});
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error(`Unsupported entry type in archive source: ${sourcePath}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return entries;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function createZipFromDirectories(zipPath, mappings, options = {}) {
|
|
51
|
+
const zipfile = new yazl.ZipFile();
|
|
52
|
+
const output = fs.createWriteStream(zipPath);
|
|
53
|
+
const zipOptions = {};
|
|
54
|
+
|
|
55
|
+
if (typeof options.compressionLevel === "number") {
|
|
56
|
+
zipOptions.compressionLevel = options.compressionLevel;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const collectedEntries = [];
|
|
60
|
+
for (const mapping of mappings) {
|
|
61
|
+
if (!fs.existsSync(mapping.sourceDir)) {
|
|
62
|
+
throw new Error(`Source directory not found: ${mapping.sourceDir}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
collectedEntries.push(...(await collectDirectoryEntries(mapping.sourceDir, mapping.zipRoot)));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
let settled = false;
|
|
70
|
+
|
|
71
|
+
function finish(error) {
|
|
72
|
+
if (settled) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
settled = true;
|
|
76
|
+
if (error) {
|
|
77
|
+
reject(error);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
resolve();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
output.on("close", () => finish());
|
|
84
|
+
output.on("error", finish);
|
|
85
|
+
zipfile.outputStream.on("error", finish);
|
|
86
|
+
|
|
87
|
+
zipfile.outputStream.pipe(output);
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
for (const entry of collectedEntries) {
|
|
91
|
+
if (entry.type === "directory") {
|
|
92
|
+
zipfile.addEmptyDirectory(entry.metadataPath);
|
|
93
|
+
} else {
|
|
94
|
+
zipfile.addFile(entry.sourcePath, entry.metadataPath, zipOptions);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
zipfile.end();
|
|
99
|
+
} catch (error) {
|
|
100
|
+
finish(error);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
createZipFromDirectories,
|
|
107
|
+
};
|
package/_project.config/build.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
const { execSync } = require("child_process");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
|
-
const
|
|
4
|
+
const { createZipFromDirectories } = require("./archive");
|
|
5
|
+
const { getPackageName } = require("./project");
|
|
5
6
|
|
|
6
7
|
// Get mod name from command line argument
|
|
7
|
-
const modName = process.argv[2];
|
|
8
|
+
const modName = process.argv[2] || getPackageName();
|
|
8
9
|
|
|
9
10
|
if (!modName) {
|
|
10
11
|
console.error("Error: Mod name is required as an argument");
|
|
11
|
-
console.error("Usage: node build.js
|
|
12
|
+
console.error("Usage: node build.js [mod-name]");
|
|
12
13
|
process.exit(1);
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -61,47 +62,31 @@ if (!fs.existsSync(buildFolder)) {
|
|
|
61
62
|
|
|
62
63
|
// Create zip file
|
|
63
64
|
const zipPath = path.join(buildFolder, `${modName}.zip`);
|
|
64
|
-
const output = fs.createWriteStream(zipPath);
|
|
65
|
-
const archive = archiver("zip", {
|
|
66
|
-
zlib: { level: 9 }, // Maximum compression
|
|
67
|
-
});
|
|
68
65
|
|
|
69
|
-
|
|
66
|
+
async function main() {
|
|
67
|
+
console.log(`Creating ${zipPath}...`);
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
output.on("close", () => {
|
|
73
|
-
const sizeInKB = (archive.pointer() / 1024).toFixed(2);
|
|
74
|
-
console.log(`✓ Build complete: ${zipPath} (${sizeInKB} KB)`);
|
|
75
|
-
});
|
|
69
|
+
const mappings = [{ sourceDir: sourceFolder, zipRoot: modName }];
|
|
76
70
|
|
|
77
|
-
|
|
78
|
-
console.error("Error creating archive:", err);
|
|
79
|
-
process.exit(1);
|
|
80
|
-
});
|
|
71
|
+
console.log(`Adding ${sourceFolder}/ → ${modName}/`);
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
console.
|
|
73
|
+
const mediaFolder = "media";
|
|
74
|
+
if (fs.existsSync(mediaFolder)) {
|
|
75
|
+
console.log(`Adding ${mediaFolder}/ → ${modName}/media/`);
|
|
76
|
+
mappings.push({ sourceDir: mediaFolder, zipRoot: `${modName}/media` });
|
|
85
77
|
} else {
|
|
86
|
-
|
|
78
|
+
console.log("No media folder found, skipping");
|
|
87
79
|
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// Pipe archive data to the file
|
|
91
|
-
archive.pipe(output);
|
|
92
80
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
await createZipFromDirectories(zipPath, mappings, {
|
|
82
|
+
compressionLevel: 9,
|
|
83
|
+
});
|
|
96
84
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (fs.existsSync(mediaFolder)) {
|
|
100
|
-
console.log(`Adding ${mediaFolder}/ → ${modName}/media/`);
|
|
101
|
-
archive.directory(mediaFolder, `${modName}/media`);
|
|
102
|
-
} else {
|
|
103
|
-
console.log("No media folder found, skipping");
|
|
85
|
+
const sizeInKB = (fs.statSync(zipPath).size / 1024).toFixed(2);
|
|
86
|
+
console.log(`✓ Build complete: ${zipPath} (${sizeInKB} KB)`);
|
|
104
87
|
}
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
main().catch((error) => {
|
|
90
|
+
console.error("Error creating archive:", error);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
"watch": "node watch.js",
|
|
7
7
|
"sync": "node sync.js",
|
|
8
8
|
"start": "node start.js",
|
|
9
|
-
"build": "node build.js
|
|
9
|
+
"build": "node build.js",
|
|
10
10
|
"update:types": "npm update @idajs/types"
|
|
11
11
|
},
|
|
12
|
-
"devDependencies": {
|
|
13
|
-
"
|
|
14
|
-
"chokidar-cli": "^3.0.0",
|
|
15
|
-
"@idajs/types": "^0.2.0",
|
|
16
|
-
"@idajs/sync": "^1.1.0",
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"yazl": "^3.3.1",
|
|
14
|
+
"chokidar-cli": "^3.0.0",
|
|
15
|
+
"@idajs/types": "^0.2.0",
|
|
16
|
+
"@idajs/sync": "^1.1.0",
|
|
17
17
|
"typescript": "^5.9.3"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const archiver = require("archiver");
|
|
2
1
|
const fs = require("fs");
|
|
3
2
|
const http = require("http");
|
|
4
3
|
const https = require("https");
|
|
5
4
|
const path = require("path");
|
|
6
5
|
const { spawn } = require("child_process");
|
|
7
6
|
|
|
7
|
+
const { createZipFromDirectories } = require("./archive");
|
|
8
8
|
const { getPackageName } = require("./project");
|
|
9
9
|
|
|
10
10
|
function runNodeScript(scriptName, args = []) {
|
|
@@ -27,25 +27,11 @@ function runNodeScript(scriptName, args = []) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
function createZip(zipPath, sourceDir, rootName) {
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
output.on("close", resolve);
|
|
37
|
-
output.on("error", reject);
|
|
38
|
-
archive.on("error", reject);
|
|
39
|
-
archive.on("warning", (error) => {
|
|
40
|
-
if (error.code !== "ENOENT") {
|
|
41
|
-
reject(error);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
archive.pipe(output);
|
|
46
|
-
archive.directory(sourceDir, rootName);
|
|
47
|
-
archive.finalize();
|
|
48
|
-
});
|
|
30
|
+
return createZipFromDirectories(
|
|
31
|
+
zipPath,
|
|
32
|
+
[{ sourceDir, zipRoot: rootName }],
|
|
33
|
+
{ compressionLevel: 0 }
|
|
34
|
+
);
|
|
49
35
|
}
|
|
50
36
|
|
|
51
37
|
function request(server, method, requestPath, body, headers = {}) {
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require("fs");
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const { execSync } = require("child_process");
|
|
7
|
+
const readline = require("readline");
|
|
7
8
|
const IdaSync = require("@idajs/sync");
|
|
8
9
|
|
|
9
10
|
// Parse command line arguments
|
|
@@ -26,7 +27,9 @@ const idajsDir = getArgValue("--idajs-dir") || getArgValue("--idajs");
|
|
|
26
27
|
const useTypeScript = args.includes("--typescript") || args.includes("--ts");
|
|
27
28
|
const useJavaScript = args.includes("--javascript") || args.includes("--js");
|
|
28
29
|
const skipInstall = args.includes("--skip-install");
|
|
30
|
+
const updateMode = args.includes("--update");
|
|
29
31
|
const helpRequested = args.includes("--help") || args.includes("-h");
|
|
32
|
+
const requiredUpdatePackages = ["@idajs/types", "@idajs/sync"];
|
|
30
33
|
|
|
31
34
|
// Show help if requested
|
|
32
35
|
if (helpRequested) {
|
|
@@ -41,7 +44,8 @@ Options:
|
|
|
41
44
|
--idajs-dir, --idajs <path> IdaJS installation directory
|
|
42
45
|
--typescript, --ts Use TypeScript
|
|
43
46
|
--javascript, --js Use JavaScript
|
|
44
|
-
--
|
|
47
|
+
--update Refresh scaffolder-managed files in the current mod folder
|
|
48
|
+
--skip-install Skip npm install (and type update in --update mode)
|
|
45
49
|
-h, --help Show this help message
|
|
46
50
|
|
|
47
51
|
Examples:
|
|
@@ -50,6 +54,7 @@ Examples:
|
|
|
50
54
|
npx @idajs/create-mod my-mod --typescript
|
|
51
55
|
npx @idajs/create-mod my-mod --dir ./projects/my-mod --idajs C:/Projects/idajs --js
|
|
52
56
|
npx @idajs/create-mod my-mod --skip-install
|
|
57
|
+
npx @idajs/create-mod --update
|
|
53
58
|
`);
|
|
54
59
|
process.exit(0);
|
|
55
60
|
}
|
|
@@ -101,9 +106,93 @@ function parseIdaConnection(value) {
|
|
|
101
106
|
};
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
function loadJson(filePath) {
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
112
|
+
} catch (error) {
|
|
113
|
+
throw new Error(`Failed to parse JSON file: ${filePath}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function isInteractiveTerminal() {
|
|
118
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function askYesNo(question) {
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
const rl = readline.createInterface({
|
|
124
|
+
input: process.stdin,
|
|
125
|
+
output: process.stdout,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
rl.question(question, (answer) => {
|
|
129
|
+
rl.close();
|
|
130
|
+
const normalized = String(answer || "").trim().toLowerCase();
|
|
131
|
+
resolve(normalized === "y" || normalized === "yes");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function runUpdateMode() {
|
|
137
|
+
const targetDir = process.cwd();
|
|
138
|
+
const packageJsonPath = path.join(targetDir, "package.json");
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
141
|
+
console.error(`\n❌ Error: No package.json found in ${targetDir}`);
|
|
142
|
+
console.error("Run this command from inside an existing IdaJS mod folder.");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const packageJson = loadJson(packageJsonPath);
|
|
147
|
+
const devDependencies = packageJson.devDependencies || {};
|
|
148
|
+
const missingPackages = requiredUpdatePackages.filter((name) => !devDependencies[name]);
|
|
149
|
+
|
|
150
|
+
if (missingPackages.length > 0) {
|
|
151
|
+
console.warn(
|
|
152
|
+
`\n⚠️ Warning: Missing IdaJS devDependencies: ${missingPackages.join(", ")}.`
|
|
153
|
+
);
|
|
154
|
+
console.warn("This may not be an IdaJS mod, or the project may differ significantly from the scaffold.");
|
|
155
|
+
|
|
156
|
+
if (!isInteractiveTerminal()) {
|
|
157
|
+
console.error("\n❌ Error: Confirmation required. Rerun this command in an interactive terminal to continue.");
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const confirmed = await askYesNo("Continue with scaffolder update? [y/N] ");
|
|
162
|
+
if (!confirmed) {
|
|
163
|
+
console.log("\nUpdate cancelled.");
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(`\nUpdating IdaJS mod in ${targetDir}...`);
|
|
169
|
+
|
|
170
|
+
const installScript = path.join(__dirname, "install.js");
|
|
171
|
+
const installArgs = [installScript, targetDir, "--update"];
|
|
172
|
+
|
|
173
|
+
if (skipInstall) {
|
|
174
|
+
installArgs.push("--skip-install");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
execSync(`node ${installArgs.map((arg) => `"${arg}"`).join(" ")}`, {
|
|
179
|
+
stdio: "inherit",
|
|
180
|
+
});
|
|
181
|
+
console.log("\n✅ Scaffolder update completed successfully.");
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.error(`\n❌ Error updating project: ${error.message}`);
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
104
188
|
async function main() {
|
|
105
189
|
console.log("Welcome to IdaJS Mod Creator!\n");
|
|
106
190
|
|
|
191
|
+
if (updateMode) {
|
|
192
|
+
await runUpdateMode();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
107
196
|
// Determine if we need prompts
|
|
108
197
|
const needsPrompts =
|
|
109
198
|
!projectName || (!useTypeScript && !useJavaScript) || (!idajsDir && !getIdaJsDirFromConfig());
|
package/install.js
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const { exec } = require("child_process");
|
|
5
|
+
const { exec, execSync } = require("child_process");
|
|
6
6
|
|
|
7
7
|
// Get configuration from arguments or defaults
|
|
8
8
|
const args = process.argv.slice(2);
|
|
9
9
|
const targetDirArg = args.find((arg) => !arg.startsWith("--"));
|
|
10
10
|
const skipInstall = args.includes("--skip-install");
|
|
11
|
+
const updateMode = args.includes("--update");
|
|
11
12
|
const idaRootArg = args.find((arg) => arg.startsWith("--ida-root="));
|
|
12
13
|
|
|
13
14
|
// Get the directory where this script was called from or use provided argument
|
|
@@ -30,48 +31,34 @@ const isTypeScriptProject = (() => {
|
|
|
30
31
|
const files = fs.readdirSync(srcDir);
|
|
31
32
|
return files.some((file) => file.endsWith(".ts"));
|
|
32
33
|
})();
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const protectedUpdateFields = new Set([
|
|
35
|
+
"name",
|
|
36
|
+
"description",
|
|
37
|
+
"version",
|
|
38
|
+
"author",
|
|
39
|
+
"private",
|
|
40
|
+
"license",
|
|
41
|
+
]);
|
|
42
|
+
const obsoleteScaffolderDevDependencies = ["archiver"];
|
|
43
|
+
|
|
44
|
+
console.log(`${updateMode ? "Updating" : "Installing"} development environment in: ${targetDir}`);
|
|
35
45
|
if (idaRoot) {
|
|
36
46
|
console.log(`Ida root: ${idaRoot}`);
|
|
37
47
|
} else {
|
|
38
48
|
console.log(`Running in standalone mode`);
|
|
39
49
|
}
|
|
40
50
|
|
|
41
|
-
|
|
42
|
-
function mergePackageJson() {
|
|
43
|
-
const packagePath = path.join(targetDir, "package.json");
|
|
44
|
-
const globalTemplatePath = path.join(configDir, "package.template.json");
|
|
45
|
-
const sampleTemplatePath = path.join(targetDir, "package.template.json");
|
|
46
|
-
|
|
47
|
-
if (!fs.existsSync(globalTemplatePath)) {
|
|
48
|
-
console.error("Error: package.template.json not found in config directory");
|
|
49
|
-
process.exit(1);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!fs.existsSync(sampleTemplatePath)) {
|
|
53
|
-
console.error("Error: package.template.json not found in sample directory");
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
console.log("Merging package.template.json files to create package.json...");
|
|
58
|
-
|
|
59
|
-
// Start with global template
|
|
60
|
-
const packageJson = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
|
|
61
|
-
const sampleTemplate = JSON.parse(fs.readFileSync(sampleTemplatePath, "utf8"));
|
|
62
|
-
|
|
63
|
-
// Get version from version.js or package.json (standalone mode)
|
|
51
|
+
function getPackageVersion() {
|
|
64
52
|
let version = null;
|
|
53
|
+
|
|
65
54
|
if (versionScriptPath && fs.existsSync(versionScriptPath)) {
|
|
66
55
|
try {
|
|
67
|
-
const { execSync } = require("child_process");
|
|
68
56
|
version = execSync(`node "${versionScriptPath}"`, { encoding: "utf8" }).trim();
|
|
69
57
|
console.log(`Using version from version.js: ${version}`);
|
|
70
58
|
} catch (error) {
|
|
71
59
|
console.warn("Warning: Could not read version from version.js");
|
|
72
60
|
}
|
|
73
61
|
} else {
|
|
74
|
-
// Standalone mode: get version from package.json in the same directory as this script
|
|
75
62
|
const localPackagePath = path.join(__dirname, "package.json");
|
|
76
63
|
if (fs.existsSync(localPackagePath)) {
|
|
77
64
|
try {
|
|
@@ -84,7 +71,51 @@ function mergePackageJson() {
|
|
|
84
71
|
}
|
|
85
72
|
}
|
|
86
73
|
|
|
87
|
-
|
|
74
|
+
return version;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function orderPackageJson(packageJson) {
|
|
78
|
+
const orderedPackageJson = {};
|
|
79
|
+
const propertyOrder = ["name", "description", "version", "author", "license", "private", "scripts"];
|
|
80
|
+
|
|
81
|
+
propertyOrder.forEach((key) => {
|
|
82
|
+
if (packageJson[key] !== undefined) {
|
|
83
|
+
orderedPackageJson[key] = packageJson[key];
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
Object.keys(packageJson).forEach((key) => {
|
|
88
|
+
if (!propertyOrder.includes(key)) {
|
|
89
|
+
orderedPackageJson[key] = packageJson[key];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return orderedPackageJson;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Step 1: Merge package.template.json files to create package.json
|
|
97
|
+
function mergePackageJsonForCreate() {
|
|
98
|
+
const packagePath = path.join(targetDir, "package.json");
|
|
99
|
+
const globalTemplatePath = path.join(configDir, "package.template.json");
|
|
100
|
+
const sampleTemplatePath = path.join(targetDir, "package.template.json");
|
|
101
|
+
|
|
102
|
+
if (!fs.existsSync(globalTemplatePath)) {
|
|
103
|
+
console.error("Error: package.template.json not found in config directory");
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(sampleTemplatePath)) {
|
|
108
|
+
console.error("Error: package.template.json not found in sample directory");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
console.log("Merging package.template.json files to create package.json...");
|
|
113
|
+
|
|
114
|
+
// Start with global template
|
|
115
|
+
const packageJson = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
|
|
116
|
+
const sampleTemplate = JSON.parse(fs.readFileSync(sampleTemplatePath, "utf8"));
|
|
117
|
+
|
|
118
|
+
const version = getPackageVersion();
|
|
88
119
|
if (version) {
|
|
89
120
|
packageJson.version = version;
|
|
90
121
|
}
|
|
@@ -116,31 +147,71 @@ function mergePackageJson() {
|
|
|
116
147
|
packageJson.dependencies = { ...packageJson.dependencies, ...sampleTemplate.dependencies };
|
|
117
148
|
}
|
|
118
149
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
150
|
+
fs.writeFileSync(packagePath, JSON.stringify(orderPackageJson(packageJson), null, 2) + "\n");
|
|
151
|
+
console.log("✓ Package.json created successfully");
|
|
152
|
+
}
|
|
122
153
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
154
|
+
function mergePackageJsonForUpdate() {
|
|
155
|
+
const packagePath = path.join(targetDir, "package.json");
|
|
156
|
+
const globalTemplatePath = path.join(configDir, "package.template.json");
|
|
157
|
+
|
|
158
|
+
if (!fs.existsSync(globalTemplatePath)) {
|
|
159
|
+
console.error("Error: package.template.json not found in config directory");
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!fs.existsSync(packagePath)) {
|
|
164
|
+
console.error("Error: package.json not found in target directory");
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log("Refreshing package.json from scaffolder template...");
|
|
169
|
+
|
|
170
|
+
const existingPackageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
171
|
+
const configTemplate = JSON.parse(fs.readFileSync(globalTemplatePath, "utf8"));
|
|
172
|
+
const packageJson = { ...existingPackageJson };
|
|
173
|
+
const existingDevDependencies = existingPackageJson.devDependencies || {};
|
|
174
|
+
|
|
175
|
+
Object.entries(configTemplate).forEach(([key, value]) => {
|
|
176
|
+
if (protectedUpdateFields.has(key)) {
|
|
177
|
+
return;
|
|
127
178
|
}
|
|
128
|
-
});
|
|
129
179
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
180
|
+
if (key === "scripts" || key === "devDependencies") {
|
|
181
|
+
const templateValue = { ...value };
|
|
182
|
+
|
|
183
|
+
if (
|
|
184
|
+
key === "devDependencies" &&
|
|
185
|
+
!isTypeScriptProject &&
|
|
186
|
+
!Object.prototype.hasOwnProperty.call(existingDevDependencies, "typescript")
|
|
187
|
+
) {
|
|
188
|
+
delete templateValue.typescript;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
packageJson[key] = {
|
|
192
|
+
...(existingPackageJson[key] || {}),
|
|
193
|
+
...templateValue,
|
|
194
|
+
};
|
|
195
|
+
return;
|
|
134
196
|
}
|
|
197
|
+
|
|
198
|
+
packageJson[key] = value;
|
|
135
199
|
});
|
|
136
200
|
|
|
137
|
-
|
|
138
|
-
|
|
201
|
+
if (packageJson.devDependencies) {
|
|
202
|
+
obsoleteScaffolderDevDependencies.forEach((dependency) => {
|
|
203
|
+
delete packageJson.devDependencies[dependency];
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
fs.writeFileSync(packagePath, JSON.stringify(orderPackageJson(packageJson), null, 2) + "\n");
|
|
208
|
+
console.log("✓ Package.json refreshed successfully");
|
|
139
209
|
}
|
|
140
210
|
|
|
141
211
|
// Step 2: Copy necessary files
|
|
142
212
|
function copyFiles() {
|
|
143
213
|
const filesToCopy = [
|
|
214
|
+
{ source: "archive.js" },
|
|
144
215
|
{ source: "project.js" },
|
|
145
216
|
{ source: "remote.js" },
|
|
146
217
|
{ source: "run.ps1" },
|
|
@@ -204,11 +275,49 @@ function runNpmInstall() {
|
|
|
204
275
|
npmProcess.stderr.pipe(process.stderr);
|
|
205
276
|
}
|
|
206
277
|
|
|
278
|
+
function runCommand(command, errorMessage) {
|
|
279
|
+
try {
|
|
280
|
+
execSync(command, {
|
|
281
|
+
cwd: targetDir,
|
|
282
|
+
stdio: "inherit",
|
|
283
|
+
});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error(errorMessage);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function runUpdatePostInstall() {
|
|
291
|
+
if (skipInstall) {
|
|
292
|
+
console.log("\nSkipped npm install and update:types");
|
|
293
|
+
console.log("\nInfrastructure update complete.");
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
console.log("Running npm install...");
|
|
298
|
+
runCommand("npm install", "Error running npm install");
|
|
299
|
+
console.log("✓ npm install completed successfully");
|
|
300
|
+
|
|
301
|
+
console.log("Running npm run update:types...");
|
|
302
|
+
runCommand(
|
|
303
|
+
"npm run update:types",
|
|
304
|
+
"Error running npm run update:types. Infrastructure refresh and npm install already completed."
|
|
305
|
+
);
|
|
306
|
+
console.log("✓ npm run update:types completed successfully");
|
|
307
|
+
console.log("\nInfrastructure update complete! You can now use the refreshed development scripts.");
|
|
308
|
+
}
|
|
309
|
+
|
|
207
310
|
// Main execution
|
|
208
311
|
try {
|
|
209
|
-
|
|
312
|
+
if (updateMode) {
|
|
313
|
+
mergePackageJsonForUpdate();
|
|
314
|
+
} else {
|
|
315
|
+
mergePackageJsonForCreate();
|
|
316
|
+
}
|
|
210
317
|
copyFiles();
|
|
211
|
-
if (
|
|
318
|
+
if (updateMode) {
|
|
319
|
+
runUpdatePostInstall();
|
|
320
|
+
} else if (!skipInstall) {
|
|
212
321
|
runNpmInstall();
|
|
213
322
|
} else {
|
|
214
323
|
console.log("\nSkipped npm install");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idajs/create-mod",
|
|
3
|
-
"version": "0.2.15-dev.
|
|
3
|
+
"version": "0.2.15-dev.37",
|
|
4
4
|
"description": "Scaffolding tool for creating IdaJS game mods for Little Big Adventure 2. Use with: npx @idajs/create-mod",
|
|
5
5
|
"author": "Andriy Tevelyev",
|
|
6
6
|
"license": "GPL-2.0",
|