bc-deeplib 4.0.0 → 5.0.0

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.
@@ -51,4 +51,18 @@ declare const IS_DEVEL: boolean;
51
51
  *
52
52
  * `true` when mod is built with `--debug`/`-d`.
53
53
  */
54
- declare const IS_DEBUG: boolean;
54
+ declare const IS_DEBUG: boolean;
55
+
56
+ /**
57
+ * The current Deeplib version.
58
+ *
59
+ * This value is set at build time and configured via `version` field in the `package.json` file of this package.
60
+ */
61
+ declare const DEEPLIB_VERSION: string;
62
+
63
+ /**
64
+ * The current mod info.
65
+ *
66
+ * This value is set at build time and configured via `modInfo` field in the `deeplib.config.js` file.
67
+ */
68
+ declare const MOD_INFO: Omit<import('bondage-club-mod-sdk').ModSDKModInfo, 'version'>;
package/lib/build.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  export declare interface BuildConfig {
2
2
  /** Entry file located in `src/` */
3
- entry?: string,
3
+ entry: string,
4
4
  /** Output file located in `{distDirName}/` */
5
- outfile?: string,
6
- /** Global name of the mod */
7
- globalName: string,
5
+ outfile: string,
6
+ /** Mod info to register with the Mod SDK */
7
+ modInfo: Omit<import('bondage-club-mod-sdk').ModSDKModInfo, 'version'>,
8
8
  /** Directory name of the dist folder, where the mod will be built */
9
9
  distDirName?: string,
10
10
  /** Directory name of the public folder, where the mod assets will be copied */
@@ -12,21 +12,15 @@ export declare interface BuildConfig {
12
12
  /** `node` scripts to run */
13
13
  scripts?: string[],
14
14
  /** URL to the mod on the production server */
15
- prodRemoteURL: string,
15
+ prodRemoteURL?: string,
16
16
  /** URL to the mod on the development server */
17
- devRemoteURL: string,
18
- /** Target version of the build */
19
- target?: string[],
20
- /** Additional esbuild plugins */
21
- plugins?: import('esbuild').Plugin[],
22
- /** Additional esbuild defines (like global variables) */
23
- defines?: {
24
- [key: string]: unknown
25
- },
17
+ devRemoteURL?: string,
26
18
  /** Host of the local dev server */
27
19
  host?: string,
28
20
  /** Port of the local dev server */
29
- port?: number
21
+ port?: number,
22
+ /** Additional esbuild options (target, plugins, define, globalName, etc.) */
23
+ esbuildOptions?: import('esbuild').BuildOptions,
30
24
  }
31
25
 
32
- export declare function defineConfig(config: BuildConfig): BuildConfig;
26
+ export declare function defineConfig(config: BuildConfig, esbuildOptions?: import('esbuild').BuildOptions): BuildConfig;
@@ -6,88 +6,135 @@ import { watch } from 'chokidar';
6
6
  import { build } from 'esbuild';
7
7
  import progress from 'esbuild-plugin-progress';
8
8
  import time from 'esbuild-plugin-time';
9
- import { existsSync, readFileSync, readdirSync, mkdirSync, copyFileSync } from 'fs';
9
+ import { existsSync, readFileSync, readdirSync, mkdirSync, copyFileSync, writeFileSync } from 'fs';
10
10
  import path, { dirname } from 'path';
11
11
  import simpleGit from 'simple-git';
12
12
  import { fileURLToPath, pathToFileURL } from 'url';
13
13
  import { promisify } from 'util';
14
14
  import http from 'http';
15
15
  import serveStatic from 'serve-static';
16
- import finalhandler from 'finalhandler';
16
+ import { Command } from 'commander';
17
17
 
18
18
  const execAsync = promisify(exec);
19
19
 
20
20
  const __filename = fileURLToPath(import.meta.url);
21
21
  const __dirname = dirname(__filename);
22
22
 
23
+ const packageJsonPath = path.resolve(__dirname, '../package.json');
24
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
25
+ const thisVersion = packageJson.version;
26
+
23
27
  /**
24
28
  * @param {import('./build').BuildConfig} config
25
- * @returns {Required<import('./build').BuildConfig>}
29
+ * @param {import('esbuild').BuildOptions} [esbuildOptions]
30
+ * @returns {import('./build').BuildConfig}
26
31
  */
27
- export function defineConfig(config) {
32
+ export function defineConfig(config, esbuildOptions) {
33
+ const defaultEsbuildOptions = {
34
+ target: [],
35
+ plugins: [],
36
+ define: {},
37
+ ...esbuildOptions
38
+ };
39
+
28
40
  return {
29
- entry: 'index.ts',
30
- outfile: 'index.js',
31
41
  distDirName: 'dist',
32
42
  publicDirName: 'public',
33
43
  scripts: [],
34
- target: [],
35
- plugins: [],
36
- defines: {},
37
44
  host: 'localhost',
38
- port: 45000,
39
- ...config
45
+ port: Math.min(3000, Math.floor(Math.random() * 10000)),
46
+ ...config,
47
+ // Merge esbuildOptions from parameter, default, and config
48
+ esbuildOptions: {
49
+ ...defaultEsbuildOptions,
50
+ ...config.esbuildOptions,
51
+ // Deep merge plugins array
52
+ plugins: [
53
+ ...(defaultEsbuildOptions.plugins || []),
54
+ ...(config.esbuildOptions?.plugins || [])
55
+ ],
56
+ // Deep merge define object
57
+ define: {
58
+ ...(defaultEsbuildOptions.define || {}),
59
+ ...(config.esbuildOptions?.define || {})
60
+ }
61
+ }
40
62
  };
41
63
  }
42
64
 
43
- async function runDeeplibBuild() {
65
+ function initConfig() {
66
+ const configPath = path.resolve(process.cwd(), 'deeplib.config.js');
67
+
68
+ if (existsSync(configPath)) {
69
+ console.error('❌ deeplib.config.js already exists in the project root');
70
+ process.exit(1);
71
+ }
72
+
73
+ const defaultConfig = `import { defineConfig } from 'bc-deeplib/build';
74
+
75
+ export default defineConfig({
76
+ entry: 'index.ts',
77
+ outfile: 'index.js',
78
+ modInfo: {
79
+ name: 'ModName',
80
+ fullName: 'ModFullName',
81
+ repository: 'https://github.com/ModAuthor/ModRepository'
82
+ },
83
+ esbuildOptions: {
84
+ globalName: 'ModName',
85
+ target: ['es2020']
86
+ }
87
+ });
88
+ `;
89
+
90
+ writeFileSync(configPath, defaultConfig, 'utf-8');
91
+ console.log('✅ Created deeplib.config.js with default configuration');
92
+ console.log('📝 Please update the following in deeplib.config.js:');
93
+ console.log(' - entry: path to your entry file in src/');
94
+ console.log(' - outfile: name of the output file');
95
+ console.log(' - esbuildOptions.globalName: your mod\'s global name');
96
+ console.log(' - esbuildOptions.target: target JavaScript version(s)');
97
+ console.log(' - Add any additional esbuild options in esbuildOptions');
98
+ }
99
+
100
+ /**
101
+ * @param {{ watch?: boolean, serve?: boolean, libLocal?: boolean, debug?: boolean }} options
102
+ */
103
+ async function runDeeplib(options) {
44
104
  const configPath = path.resolve(process.cwd(), 'deeplib.config.js');
45
105
 
46
106
  if (!existsSync(configPath)) {
47
107
  console.error('❌ Missing deeplib.config.js in project root');
108
+ console.error('💡 Run "deeplib init" to create a default config file');
48
109
  process.exit(1);
49
110
  }
50
111
 
51
112
  const { default: config } = await import(pathToFileURL(configPath).toString());
52
- await buildMod(config);
113
+ await buildMod(config, options);
53
114
  }
54
115
 
55
116
  /**
56
117
  * @param {Required<import('./build').BuildConfig>} config
118
+ * @param {{ watch?: boolean, serve?: boolean, libLocal?: boolean, debug?: boolean }} options
57
119
  */
58
120
  async function buildMod({
59
121
  entry,
60
122
  outfile,
61
- globalName,
123
+ modInfo,
62
124
  distDirName,
63
125
  publicDirName,
64
126
  scripts,
65
127
  prodRemoteURL,
66
128
  devRemoteURL,
67
- target,
68
- plugins,
69
- defines,
70
129
  host,
71
- port
72
- }) {
73
- if (process.argv.includes('--help') || process.argv.includes('-h')) {
74
- console.log(`
75
- Usage: deeplib [options]
76
-
77
- Options:
78
- --help, -h Show this help message
79
- --watch, -w Watch for changes and rebuild
80
- --serve, -s Serve mod on http://${host}:${port}
81
- --lib-local, -l Use local build of deeplib
82
- --debug, -d Enable debug mode
83
- `.replaceAll('\t', ''));
84
- return;
85
- }
130
+ port,
131
+ esbuildOptions = {}
132
+ }, options = {}) {
86
133
  const cliLocal = !process.env.environment;
87
- const cliWatch = process.argv.includes('--watch') || process.argv.includes('-w');
88
- const cliServe = process.argv.includes('--serve') || process.argv.includes('-s');
89
- const cliLibLocal = process.argv.includes('--lib-local') || process.argv.includes('-l');
90
- const cliAllowDebug = process.argv.includes('--debug') || process.argv.includes('-d');
134
+ const cliWatch = options.watch || false;
135
+ const cliServe = options.serve || false;
136
+ const cliLibLocal = options.libLocal || false;
137
+ const cliAllowDebug = options.debug || false;
91
138
 
92
139
  const envMode = process.env.environment || 'production';
93
140
  const mode = cliLocal ? 'local' : envMode;
@@ -105,22 +152,28 @@ async function buildMod({
105
152
  const packageJsonPath = path.resolve(process.cwd(), 'package.json');
106
153
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
107
154
 
108
- const git = simpleGit({ baseDir: process.cwd() });
109
- const VERSION = packageJson.version;
110
- const COMMIT_HASH = (await git.log({ maxCount: 1 }))?.latest?.hash.substring(0, 8);
155
+ const VERSION = packageJson.version;
156
+
157
+ let COMMIT_HASH = '';
158
+ try {
159
+ if (await simpleGit().checkIsRepo()) {
160
+ COMMIT_HASH = (await simpleGit().log({ maxCount: 1 }))?.latest?.hash?.substring(0, 8) ?? '';
161
+ }
162
+ } catch (_) {
163
+ COMMIT_HASH = 'unknown';
164
+ }
111
165
  const VERSION_CAPTION = IS_DEVEL ? `${VERSION} - ${COMMIT_HASH}` : VERSION;
112
166
 
113
167
  /** @type {import('esbuild').BuildOptions} */
114
168
  const buildOptions = {
115
- entryPoints: [`src/${entry}`],
116
- outfile: `${distDirName}/${outfile}`,
117
169
  format: 'iife',
118
- globalName,
119
170
  bundle: true,
120
171
  sourcemap: true,
121
- target,
122
172
  treeShaking: true,
123
173
  keepNames: true,
174
+ ...esbuildOptions,
175
+ entryPoints: [`src/${entry}`],
176
+ outfile: `${distDirName}/${outfile}`,
124
177
  define: {
125
178
  PUBLIC_URL: JSON.stringify(PUBLIC_URL),
126
179
  MOD_VERSION: JSON.stringify(VERSION),
@@ -128,9 +181,10 @@ async function buildMod({
128
181
  MOD_VERSION_CAPTION: JSON.stringify(VERSION_CAPTION),
129
182
  IS_DEVEL: JSON.stringify(IS_DEVEL),
130
183
  IS_DEBUG: JSON.stringify(cliAllowDebug),
131
- ...defines
184
+ MOD_INFO: JSON.stringify(modInfo),
185
+ ...(esbuildOptions.define || {})
132
186
  },
133
- plugins: [progress(), time(), ...plugins],
187
+ plugins: [progress(), time(), ...(esbuildOptions.plugins || [])]
134
188
  };
135
189
 
136
190
  /** @type {NodeJS.Timeout | null} */
@@ -193,13 +247,23 @@ async function buildMod({
193
247
  */
194
248
  function serveWithCORS(dir, port, host) {
195
249
  const serve = serveStatic(dir, {
250
+ /** @param {import('http').ServerResponse} res */
196
251
  setHeaders: (res) => {
197
252
  res.setHeader('Access-Control-Allow-Origin', '*');
198
253
  }
199
254
  });
200
255
 
201
256
  const server = http.createServer((req, res) => {
202
- serve(req, res, finalhandler(req, res));
257
+ serve(req, res, (err) => {
258
+ if (err) {
259
+ res.statusCode = err.statusCode || 500;
260
+ res.end(err.message || 'Internal Server Error');
261
+ return;
262
+ }
263
+
264
+ res.statusCode = 404;
265
+ res.end('Not Found');
266
+ });
203
267
  });
204
268
 
205
269
  server.listen(port, host, () => {
@@ -248,4 +312,28 @@ function relativeToProject(absolutePath) {
248
312
  return path.relative(process.cwd(), absolutePath);
249
313
  }
250
314
 
251
- runDeeplibBuild();
315
+ const program = new Command();
316
+
317
+ program
318
+ .name('deeplib')
319
+ .description('Build tool for BC mods using DeepLib')
320
+ .version(thisVersion);
321
+
322
+ program
323
+ .command('init')
324
+ .description('Create a default deeplib.config.js file')
325
+ .action(() => {
326
+ initConfig();
327
+ });
328
+
329
+ // Build command (default)
330
+ program
331
+ .option('-w, --watch', 'Watch for changes and rebuild')
332
+ .option('-s, --serve', 'Serve mod on local dev server')
333
+ .option('-l, --lib-local', 'Use local build of deeplib')
334
+ .option('-d, --debug', 'Enable debug mode')
335
+ .action(async (options) => {
336
+ await runDeeplib(options);
337
+ });
338
+
339
+ program.parse(process.argv);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bc-deeplib",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "author": "dDeepLb",
5
5
  "description": "Library for easier development of BC mods, which strives to be a framework :D",
6
6
  "license": "MIT",
@@ -17,38 +17,39 @@
17
17
  "import": "./dist/deeplib.js"
18
18
  },
19
19
  "./build": {
20
- "import": "./lib/build.js"
20
+ "import": "./lib/deeplib.js"
21
21
  }
22
22
  },
23
23
  "bin": {
24
- "deeplib": "./lib/build.js"
24
+ "deeplib": "./lib/deeplib.js"
25
25
  },
26
26
  "devDependencies": {
27
- "@eslint/js": "^9.35.0",
28
- "@stylistic/eslint-plugin": "^5.3.1",
29
- "@types/node": "^22.13.10",
30
- "bc-stubs": "121.0.0",
31
- "eslint": "^9.35.0",
32
- "globals": "^16.4.0",
27
+ "@eslint/js": "^10.0.1",
28
+ "@stylistic/eslint-plugin": "^5.10.0",
29
+ "@types/node": "^22.19.19",
30
+ "bc-stubs": "128.0.0",
31
+ "bondage-club-mod-sdk": "^1.2.0",
32
+ "eslint": "^10.4.0",
33
+ "globals": "^17.6.0",
33
34
  "npm-dts": "^1.3.13",
34
- "sass": "^1.92.1",
35
- "typescript": "^5.9.2",
36
- "typescript-eslint": "^8.43.0",
37
- "bondage-club-mod-sdk": "^1.2.0"
35
+ "sass": "^1.99.0",
36
+ "typescript": "^6.0.3",
37
+ "typescript-eslint": "^8.59.4"
38
38
  },
39
39
  "dependencies": {
40
- "serve-static": "^2.2.0",
41
- "simple-git": "^3.28.0",
42
- "finalhandler": "^2.1.0",
43
- "fs-extra": "^11.3.1",
44
- "chokidar": "^4.0.3",
45
- "esbuild": "^0.25.9",
46
- "esbuild-plugin-progress": "^1.3.0",
40
+ "chokidar": "^5.0.0",
41
+ "commander": "^14.0.3",
42
+ "esbuild": "^0.28.0",
43
+ "esbuild-plugin-progress": "^1.3.9",
47
44
  "esbuild-plugin-time": "^1.0.0",
48
- "esbuild-sass-plugin": "^3.3.1"
45
+ "esbuild-sass-plugin": "^3.7.0",
46
+ "fs-extra": "^11.3.5",
47
+ "js-logger": "^1.6.1",
48
+ "serve-static": "^2.2.1",
49
+ "simple-git": "^3.36.0"
49
50
  },
50
51
  "scripts": {
51
- "all": "pnpm type:check && pnpm build && pnpm type:gen && pnpm type:copy && pnpm asset:copy",
52
+ "all": "pnpm lint && pnpm type:check && pnpm build && pnpm type:gen && pnpm type:copy && pnpm asset:copy",
52
53
  "lint": "eslint",
53
54
  "lint:fix": "eslint --fix",
54
55
  "build": "node scripts/build.js",