minidev-buildconfig-cli 0.0.1

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/dist/cli.js ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const generate_config_ts_1 = require("./core/generate-config.js");
5
+ function printUsage() {
6
+ console.error('Usage: minidev-buildconfig generate --env <env> [--cwd <path>] [--lang ts|js]');
7
+ }
8
+ function parseGenerateArgs(argv) {
9
+ const options = {};
10
+ for (let index = 0; index < argv.length; index += 1) {
11
+ const arg = argv[index];
12
+ const value = argv[index + 1];
13
+ if (arg === '--env') {
14
+ options.env = value;
15
+ index += 1;
16
+ continue;
17
+ }
18
+ if (arg === '--cwd') {
19
+ options.cwd = value;
20
+ index += 1;
21
+ continue;
22
+ }
23
+ if (arg === '--platform') {
24
+ options.platform = value;
25
+ index += 1;
26
+ continue;
27
+ }
28
+ if (arg === '--miniprogramRoot') {
29
+ options.miniprogramRoot = value;
30
+ index += 1;
31
+ continue;
32
+ }
33
+ if (arg === '--output') {
34
+ options.output = value;
35
+ index += 1;
36
+ continue;
37
+ }
38
+ if (arg === '--lang') {
39
+ if (value !== 'ts' && value !== 'js') {
40
+ throw new Error(`Invalid --lang: ${value}. Must be ts or js.`);
41
+ }
42
+ options.lang = value;
43
+ index += 1;
44
+ continue;
45
+ }
46
+ throw new Error(`Unknown argument: ${arg}`);
47
+ }
48
+ if (!options.env) {
49
+ throw new Error('Missing required option: --env');
50
+ }
51
+ return options;
52
+ }
53
+ async function main() {
54
+ const [, , command, ...rest] = process.argv;
55
+ if (command !== 'generate') {
56
+ printUsage();
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+ try {
61
+ const options = parseGenerateArgs(rest);
62
+ const result = await (0, generate_config_ts_1.generateConfig)(options);
63
+ console.log(`Generated configs for ${result.env}:`);
64
+ for (const output of result.outputs) {
65
+ console.log(` ${output.configName}: ${output.outputPath}`);
66
+ }
67
+ }
68
+ catch (error) {
69
+ const message = error instanceof Error ? error.message : String(error);
70
+ console.error(message);
71
+ process.exitCode = 1;
72
+ }
73
+ }
74
+ void main();
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.normalizeMiniprogramRoot = normalizeMiniprogramRoot;
7
+ exports.detectPlatformFromJsonFile = detectPlatformFromJsonFile;
8
+ exports.detectPlatformCandidates = detectPlatformCandidates;
9
+ exports.detectPlatforms = detectPlatforms;
10
+ exports.detectLang = detectLang;
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const promises_1 = require("node:fs/promises");
13
+ function normalizeMiniprogramRoot(value) {
14
+ if (typeof value !== 'string') {
15
+ return null;
16
+ }
17
+ const normalized = value.replace(/\/+$/, '');
18
+ return normalized.length > 0 ? normalized : null;
19
+ }
20
+ async function detectPlatformFromJsonFile(options) {
21
+ const configPath = node_path_1.default.join(options.cwd, options.configFile);
22
+ let content;
23
+ try {
24
+ const { readFile } = await import('node:fs/promises');
25
+ content = await readFile(configPath, 'utf8');
26
+ }
27
+ catch (error) {
28
+ const errorCode = typeof error === 'object' && error !== null && 'code' in error
29
+ ? error.code
30
+ : undefined;
31
+ if (errorCode === 'ENOENT') {
32
+ return null;
33
+ }
34
+ throw error;
35
+ }
36
+ const config = JSON.parse(content);
37
+ const miniprogramRoot = normalizeMiniprogramRoot(config.miniprogramRoot);
38
+ if (!miniprogramRoot) {
39
+ return null;
40
+ }
41
+ return {
42
+ platform: options.platform,
43
+ miniprogramRoot,
44
+ configFile: options.configFile,
45
+ configPath,
46
+ };
47
+ }
48
+ // Conflict resolution order is stable and explicit:
49
+ // WeChat first, then Alipay, then TT, matching current fixture expectations
50
+ // and giving downstream CLI code a deterministic candidate list for messages.
51
+ const PLATFORM_DETECTORS = [
52
+ { platform: 'wechat', configFile: 'project.config.json' },
53
+ { platform: 'alipay', configFile: 'mini.project.json' },
54
+ { platform: 'tt', configFile: 'project.tt.json' },
55
+ ];
56
+ async function detectPlatformCandidates(cwd) {
57
+ const candidates = [];
58
+ for (const detector of PLATFORM_DETECTORS) {
59
+ const candidate = await detectPlatformFromJsonFile({
60
+ cwd,
61
+ platform: detector.platform,
62
+ configFile: detector.configFile,
63
+ });
64
+ if (candidate) {
65
+ candidates.push(candidate);
66
+ }
67
+ }
68
+ return candidates;
69
+ }
70
+ async function detectPlatforms(cwd) {
71
+ const candidates = await detectPlatformCandidates(cwd);
72
+ return candidates.map(({ platform, miniprogramRoot }) => ({ platform, miniprogramRoot }));
73
+ }
74
+ /**
75
+ * Detect project language by checking for app.ts vs app.js in miniprogramRoot.
76
+ * Defaults to 'ts' if neither is found (assumes TypeScript project).
77
+ */
78
+ async function detectLang(options) {
79
+ const entries = [];
80
+ try {
81
+ const appTsPath = node_path_1.default.join(options.cwd, options.miniprogramRoot, 'app.ts');
82
+ await (0, promises_1.access)(appTsPath);
83
+ entries.push('ts');
84
+ }
85
+ catch {
86
+ // app.ts not found
87
+ }
88
+ try {
89
+ const appJsPath = node_path_1.default.join(options.cwd, options.miniprogramRoot, 'app.js');
90
+ await (0, promises_1.access)(appJsPath);
91
+ entries.push('js');
92
+ }
93
+ catch {
94
+ // app.js not found
95
+ }
96
+ if (entries.includes('ts'))
97
+ return 'ts';
98
+ if (entries.includes('js'))
99
+ return 'js';
100
+ return 'ts';
101
+ }
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.generateConfig = generateConfig;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const detect_platform_ts_1 = require("./detect-platform.js");
10
+ const load_env_config_ts_1 = require("./load-env-config.js");
11
+ const load_user_config_ts_1 = require("./load-user-config.js");
12
+ const resolve_output_ts_1 = require("./resolve-output.js");
13
+ function renderTsModule(config) {
14
+ return `const config = ${JSON.stringify(config, null, 2)} as const
15
+
16
+ export type AppConfig = typeof config
17
+
18
+ export default config
19
+ `;
20
+ }
21
+ function renderJsModule(config) {
22
+ return `const config = ${JSON.stringify(config, null, 2)}
23
+
24
+ module.exports = config
25
+ `;
26
+ }
27
+ function renderConfigModule(config, lang) {
28
+ return lang === 'ts' ? renderTsModule(config) : renderJsModule(config);
29
+ }
30
+ function resolveCandidate(options) {
31
+ const requestedPlatform = options.platform;
32
+ const matchingCandidates = requestedPlatform
33
+ ? options.candidates.filter((candidate) => candidate.platform === requestedPlatform)
34
+ : options.candidates;
35
+ if (matchingCandidates.length === 1) {
36
+ return matchingCandidates[0];
37
+ }
38
+ if (matchingCandidates.length > 1) {
39
+ const platforms = matchingCandidates.map((candidate) => candidate.platform).join(', ');
40
+ throw new Error(`Multiple platforms detected: ${platforms}. Pass --platform <name> to disambiguate.`);
41
+ }
42
+ if (requestedPlatform) {
43
+ throw new Error(`Unable to detect platform: ${requestedPlatform}`);
44
+ }
45
+ throw new Error('Unable to detect miniprogramRoot. Set minidevBuildConfig.miniprogramRoot in package.json.');
46
+ }
47
+ async function generateConfig(options) {
48
+ const cwd = options.cwd ?? process.cwd();
49
+ const userConfig = await (0, load_user_config_ts_1.loadUserConfig)(cwd);
50
+ const envConfigs = await (0, load_env_config_ts_1.loadAllEnvConfigs)({
51
+ cwd,
52
+ env: options.env,
53
+ configDir: userConfig.configDir,
54
+ });
55
+ const candidates = await (0, detect_platform_ts_1.detectPlatformCandidates)(cwd);
56
+ const platform = options.platform ?? userConfig.platform;
57
+ const explicitMiniprogramRoot = options.miniprogramRoot ?? userConfig.miniprogramRoot;
58
+ const miniprogramRoot = explicitMiniprogramRoot ??
59
+ resolveCandidate({
60
+ candidates,
61
+ platform,
62
+ }).miniprogramRoot;
63
+ const detectedCandidate = candidates.find((candidate) => candidate.miniprogramRoot === miniprogramRoot) ??
64
+ (platform
65
+ ? candidates.find((candidate) => candidate.platform === platform)
66
+ : undefined);
67
+ const lang = options.lang ??
68
+ userConfig.lang ??
69
+ (await (0, detect_platform_ts_1.detectLang)({ cwd, miniprogramRoot }));
70
+ const outputs = [];
71
+ for (const [configName, configData] of Object.entries(envConfigs)) {
72
+ const configWithEnv = { env: options.env, ...configData };
73
+ const { outputFile, outputPath } = (0, resolve_output_ts_1.resolveNamedOutput)({
74
+ cwd,
75
+ miniprogramRoot,
76
+ configName,
77
+ lang,
78
+ });
79
+ const content = renderConfigModule(configWithEnv, lang);
80
+ await (0, promises_1.mkdir)(node_path_1.default.dirname(outputPath), { recursive: true });
81
+ await (0, promises_1.writeFile)(outputPath, content);
82
+ outputs.push({ configName, outputFile, outputPath });
83
+ }
84
+ return {
85
+ cwd,
86
+ env: options.env,
87
+ platform: platform ?? detectedCandidate?.platform,
88
+ miniprogramRoot,
89
+ lang,
90
+ outputs,
91
+ };
92
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadAllEnvConfigs = loadAllEnvConfigs;
7
+ exports.loadEnvConfig = loadEnvConfig;
8
+ const promises_1 = require("node:fs/promises");
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const json5_1 = __importDefault(require("json5"));
11
+ function validateEnvName(env) {
12
+ if (!/^[A-Za-z0-9_-]+$/.test(env)) {
13
+ throw new Error(`Invalid env: ${env}`);
14
+ }
15
+ }
16
+ function extractConfigName(filename, env) {
17
+ // Pattern: <configName>.<env>.json5 → configName
18
+ const suffix = `.${env}.json5`;
19
+ if (filename.endsWith(suffix)) {
20
+ const prefix = filename.slice(0, -suffix.length);
21
+ if (prefix.length > 0) {
22
+ return prefix;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ async function loadAllEnvConfigs(options) {
28
+ validateEnvName(options.env);
29
+ const configDir = options.configDir ?? 'configs';
30
+ const configDirPath = node_path_1.default.join(options.cwd, configDir);
31
+ const entries = await (0, promises_1.readdir)(configDirPath, { withFileTypes: true });
32
+ const configs = {};
33
+ for (const entry of entries) {
34
+ if (!entry.isFile())
35
+ continue;
36
+ const configName = extractConfigName(entry.name, options.env);
37
+ if (configName === null)
38
+ continue;
39
+ const configPath = node_path_1.default.join(configDirPath, entry.name);
40
+ const configContent = await (0, promises_1.readFile)(configPath, 'utf8');
41
+ configs[configName] = json5_1.default.parse(configContent);
42
+ }
43
+ return configs;
44
+ }
45
+ /**
46
+ * @deprecated Use loadAllEnvConfigs for multi-file config support.
47
+ * Loads a single config file: <configDir>/<env>.json5
48
+ */
49
+ async function loadEnvConfig(options) {
50
+ validateEnvName(options.env);
51
+ const configDir = options.configDir ?? 'configs';
52
+ const configPath = node_path_1.default.join(options.cwd, configDir, `${options.env}.json5`);
53
+ const configContent = await (0, promises_1.readFile)(configPath, 'utf8');
54
+ return json5_1.default.parse(configContent);
55
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.loadUserConfig = loadUserConfig;
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ function readOptionalString(source, key) {
10
+ const value = source[key];
11
+ return typeof value === 'string' ? value : undefined;
12
+ }
13
+ async function loadUserConfig(cwd) {
14
+ const packageJsonPath = node_path_1.default.join(cwd, 'package.json');
15
+ let packageJsonContent;
16
+ try {
17
+ packageJsonContent = await (0, promises_1.readFile)(packageJsonPath, 'utf8');
18
+ }
19
+ catch (error) {
20
+ const errorCode = typeof error === 'object' && error !== null && 'code' in error
21
+ ? error.code
22
+ : undefined;
23
+ if (errorCode === 'ENOENT') {
24
+ return {
25
+ configDir: undefined,
26
+ platform: undefined,
27
+ miniprogramRoot: undefined,
28
+ lang: undefined,
29
+ };
30
+ }
31
+ throw error;
32
+ }
33
+ const packageJson = JSON.parse(packageJsonContent);
34
+ const rawConfig = packageJson.minidevBuildConfig ?? {};
35
+ const langValue = readOptionalString(rawConfig, 'lang');
36
+ const lang = langValue === 'ts' || langValue === 'js' ? langValue : undefined;
37
+ return {
38
+ configDir: readOptionalString(rawConfig, 'configDir'),
39
+ platform: readOptionalString(rawConfig, 'platform'),
40
+ miniprogramRoot: readOptionalString(rawConfig, 'miniprogramRoot'),
41
+ lang,
42
+ };
43
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveOutput = resolveOutput;
7
+ exports.resolveNamedOutput = resolveNamedOutput;
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ function normalizeRelativePath(value) {
10
+ const normalized = value.replace(/\\/g, '/').replace(/^\.\/+/, '').replace(/\/+$/, '');
11
+ return normalized.length > 0 ? normalized : '';
12
+ }
13
+ function resolveOutput(options) {
14
+ const miniprogramRoot = normalizeRelativePath(options.miniprogramRoot);
15
+ const output = normalizeRelativePath(options.output ?? 'generated/config.ts');
16
+ const outputFile = node_path_1.default.posix.join(miniprogramRoot, output);
17
+ return {
18
+ outputFile,
19
+ outputPath: node_path_1.default.resolve(options.cwd, outputFile),
20
+ };
21
+ }
22
+ function resolveNamedOutput(options) {
23
+ const miniprogramRoot = normalizeRelativePath(options.miniprogramRoot);
24
+ const ext = options.lang ?? 'ts';
25
+ const outputFile = node_path_1.default.posix.join(miniprogramRoot, 'generated', `${options.configName}.${ext}`);
26
+ return {
27
+ outputFile,
28
+ outputPath: node_path_1.default.resolve(options.cwd, outputFile),
29
+ };
30
+ }
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadUserConfig = exports.loadEnvConfig = exports.loadAllEnvConfigs = exports.detectPlatforms = exports.detectLang = exports.resolveNamedOutput = exports.resolveOutput = exports.generateConfig = void 0;
4
+ var generate_config_ts_1 = require("./core/generate-config.js");
5
+ Object.defineProperty(exports, "generateConfig", { enumerable: true, get: function () { return generate_config_ts_1.generateConfig; } });
6
+ var resolve_output_ts_1 = require("./core/resolve-output.js");
7
+ Object.defineProperty(exports, "resolveOutput", { enumerable: true, get: function () { return resolve_output_ts_1.resolveOutput; } });
8
+ Object.defineProperty(exports, "resolveNamedOutput", { enumerable: true, get: function () { return resolve_output_ts_1.resolveNamedOutput; } });
9
+ var detect_platform_ts_1 = require("./core/detect-platform.js");
10
+ Object.defineProperty(exports, "detectLang", { enumerable: true, get: function () { return detect_platform_ts_1.detectLang; } });
11
+ Object.defineProperty(exports, "detectPlatforms", { enumerable: true, get: function () { return detect_platform_ts_1.detectPlatforms; } });
12
+ var load_env_config_ts_1 = require("./core/load-env-config.js");
13
+ Object.defineProperty(exports, "loadAllEnvConfigs", { enumerable: true, get: function () { return load_env_config_ts_1.loadAllEnvConfigs; } });
14
+ Object.defineProperty(exports, "loadEnvConfig", { enumerable: true, get: function () { return load_env_config_ts_1.loadEnvConfig; } });
15
+ var load_user_config_ts_1 = require("./core/load-user-config.js");
16
+ Object.defineProperty(exports, "loadUserConfig", { enumerable: true, get: function () { return load_user_config_ts_1.loadUserConfig; } });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectAlipayProject = detectAlipayProject;
4
+ const detect_platform_ts_1 = require("../core/detect-platform.js");
5
+ async function detectAlipayProject(cwd) {
6
+ return (0, detect_platform_ts_1.detectPlatformFromJsonFile)({
7
+ cwd,
8
+ platform: 'alipay',
9
+ configFile: 'mini.project.json',
10
+ });
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectTtProject = detectTtProject;
4
+ const detect_platform_ts_1 = require("../core/detect-platform.js");
5
+ async function detectTtProject(cwd) {
6
+ return (0, detect_platform_ts_1.detectPlatformFromJsonFile)({
7
+ cwd,
8
+ platform: 'tt',
9
+ configFile: 'project.tt.json',
10
+ });
11
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectWechatProject = detectWechatProject;
4
+ const detect_platform_ts_1 = require("../core/detect-platform.js");
5
+ async function detectWechatProject(cwd) {
6
+ return (0, detect_platform_ts_1.detectPlatformFromJsonFile)({
7
+ cwd,
8
+ platform: 'wechat',
9
+ configFile: 'project.config.json',
10
+ });
11
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "minidev-buildconfig-cli",
3
+ "version": "0.0.1",
4
+ "description": "CLI tool for generating mini program multi-environment config files",
5
+ "license": "MIT",
6
+ "author": "xesam",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/xesam/minidev-buildconfig-cli"
10
+ },
11
+ "keywords": [
12
+ "miniprogram",
13
+ "wechat",
14
+ "alipay",
15
+ "douyin",
16
+ "build-config",
17
+ "multi-environment",
18
+ "cli"
19
+ ],
20
+ "bin": {
21
+ "minidev-buildconfig": "dist/cli.js"
22
+ },
23
+ "main": "dist/index.js",
24
+ "engines": {
25
+ "node": ">=18.0.0"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.build.json",
29
+ "test": "node --experimental-strip-types --test tests/*.test.js"
30
+ },
31
+ "dependencies": {
32
+ "json5": "^2.2.3"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.15.30",
36
+ "typescript": "^5.8.3"
37
+ },
38
+ "files": [
39
+ "dist/"
40
+ ]
41
+ }