@infly/libs 2.0.38 → 2.0.42

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.
@@ -0,0 +1,124 @@
1
+ const assert = require("node:assert/strict");
2
+ const path = require("node:path");
3
+ const { spawnSync } = require("node:child_process");
4
+ const test = require("node:test");
5
+
6
+ const cliPath = path.resolve(__dirname, "../../bin/cli.js");
7
+
8
+ function parseArgsInChildProcess(argv) {
9
+ const source = `
10
+ const { parseArgs } = require(${JSON.stringify(cliPath)});
11
+ process.stdout.write(JSON.stringify(parseArgs(${JSON.stringify(argv)})));
12
+ `;
13
+ return spawnSync(process.execPath, ["-e", source], {
14
+ encoding: "utf-8",
15
+ });
16
+ }
17
+
18
+ test("parseArgs keeps existing defaults and options", () => {
19
+ const result = parseArgsInChildProcess(["--local", "--env", "dev", "--dry-run"]);
20
+
21
+ assert.equal(result.status, 0, result.stderr);
22
+ assert.deepEqual(JSON.parse(result.stdout), {
23
+ env: "dev",
24
+ local: true,
25
+ dryRun: true,
26
+ });
27
+ });
28
+
29
+ test("parseArgs accepts spaced and equals cicd URL forms", () => {
30
+ const url = "https://cicd.sutpay.com/view/积分商城/";
31
+ const spaced = parseArgsInChildProcess(["--cicd-url", url]);
32
+ const equals = parseArgsInChildProcess([`--cicd-url=${url}`]);
33
+
34
+ assert.equal(spaced.status, 0, spaced.stderr);
35
+ assert.equal(equals.status, 0, equals.stderr);
36
+ assert.equal(JSON.parse(spaced.stdout).cicdUrl, url);
37
+ assert.equal(JSON.parse(equals.stdout).cicdUrl, url);
38
+ });
39
+
40
+ test("parseArgs accepts Docker Compose release options", () => {
41
+ const result = parseArgsInChildProcess([
42
+ "--project-dir",
43
+ "apps/deploy",
44
+ "--file=docker-compose.yaml",
45
+ "--bump",
46
+ "patch",
47
+ "--push",
48
+ "--config",
49
+ "docker.targets.js",
50
+ "--target=qdxy",
51
+ "--dry-run",
52
+ ]);
53
+
54
+ assert.equal(result.status, 0, result.stderr);
55
+ assert.deepEqual(JSON.parse(result.stdout), {
56
+ env: "prod",
57
+ local: false,
58
+ dryRun: true,
59
+ projectDir: "apps/deploy",
60
+ file: "docker-compose.yaml",
61
+ bump: "patch",
62
+ push: true,
63
+ config: "docker.targets.js",
64
+ target: "qdxy",
65
+ });
66
+ });
67
+ test("parseProjectArgs leaves environment unset for interactive selection", () => {
68
+ const source = `
69
+ const { parseProjectArgs } = require(${JSON.stringify(cliPath)});
70
+ process.stdout.write(JSON.stringify({
71
+ interactive: parseProjectArgs([]),
72
+ explicit: parseProjectArgs(["--env", "stage", "--target", "qdxy"]),
73
+ }));
74
+ `;
75
+ const result = spawnSync(process.execPath, ["-e", source], { encoding: "utf-8" });
76
+
77
+ assert.equal(result.status, 0, result.stderr);
78
+ assert.deepEqual(JSON.parse(result.stdout), {
79
+ interactive: { dryRun: false },
80
+ explicit: { dryRun: false, env: "stage", target: "qdxy" },
81
+ });
82
+ });
83
+ test("parseArgs rejects cicd URL without a value", () => {
84
+ const result = parseArgsInChildProcess(["--cicd-url"]);
85
+
86
+ assert.notEqual(result.status, 0);
87
+ assert.match(result.stderr, /--cicd-url/);
88
+ });
89
+
90
+ test("CLI keeps the existing unknown command output", () => {
91
+ const result = spawnSync(process.execPath, [cliPath, "unknown-command"], {
92
+ encoding: "utf-8",
93
+ });
94
+
95
+ assert.equal(result.status, 1);
96
+ assert.match(result.stderr, /未知命令: unknown-command/);
97
+ assert.match(result.stdout, /可用命令:/);
98
+ });
99
+
100
+ test("formatCicdLink returns no output when option is absent", () => {
101
+ const { formatCicdLink } = require("./docker-build-push");
102
+
103
+ assert.equal(formatCicdLink(), "");
104
+ });
105
+
106
+ test("formatCicdLink normalizes encoded Chinese URL and colors it blue", () => {
107
+ const { formatCicdLink } = require("./docker-build-push");
108
+ const result = formatCicdLink(
109
+ "https://cicd.sutpay.com/view/%E7%A7%AF%E5%88%86%E5%95%86%E5%9F%8E/"
110
+ );
111
+
112
+ assert.equal(
113
+ result,
114
+ "发布系统:\x1b[34mhttps://cicd.sutpay.com/view/积分商城/\x1b[0m"
115
+ );
116
+ });
117
+
118
+ test("formatCicdLink rejects unsafe URL values", () => {
119
+ const { formatCicdLink } = require("./docker-build-push");
120
+
121
+ assert.throws(() => formatCicdLink("ftp://cicd.sutpay.com/build"), /HTTP\/HTTPS/);
122
+ assert.throws(() => formatCicdLink("https://user:secret@cicd.sutpay.com/"), /凭据/);
123
+ assert.throws(() => formatCicdLink("https://cicd.sutpay.com/\nnext"), /控制字符/);
124
+ });
package/module/Uts.js CHANGED
@@ -5285,7 +5285,7 @@ true
5285
5285
  isDevMode() {
5286
5286
  if (
5287
5287
  window.location.href.indexOf("http://localhost") != 0 &&
5288
- window.location.href.indexOf("http://192.168.4") != 0 &&
5288
+ window.location.href.indexOf("http://192.168") != 0 &&
5289
5289
  window.location.href.indexOf("dev=open") == -1
5290
5290
  ) {
5291
5291
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infly/libs",
3
- "version": "2.0.38",
3
+ "version": "2.0.42",
4
4
  "description": "工具组件库",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,7 +20,8 @@
20
20
  "./dataInit/*": "./dataInit/*",
21
21
  "./tools/*": "./tools/*",
22
22
  "./store/*": "./store/*",
23
- "./build/*": "./build/*"
23
+ "./build/*": "./build/*",
24
+ "./script/build/*": "./script/build/*"
24
25
  },
25
26
  "repository": {
26
27
  "type": "git",
@@ -33,7 +34,10 @@
33
34
  ],
34
35
  "author": "Kahal",
35
36
  "license": "ISC",
36
- "dependencies": {},
37
+ "dependencies": {
38
+ "enquirer": "^2.4.1",
39
+ "path-browserify": "^1.0.1"
40
+ },
37
41
  "devDependencies": {
38
42
  "@babel/core": "^7.23.3",
39
43
  "@babel/preset-env": "^7.23.3",
@@ -63,7 +67,7 @@
63
67
  "enablePreview": "[是否启用项目预览] eg: true",
64
68
  "enableClipboard": "[是否启用粘贴板粘贴git信息] eg: true",
65
69
  "openExplorer": "[是否自动打开资源管理器] eg: true",
66
- "webhookUrl": "[消息推送机器人链接配置] eg: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=2417edd3-8f74-4c30-a7a8-5a72826d40d2",
70
+ "webhookUrl": "[消息推送机器人链接配置] eg: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=",
67
71
  "webhookAtUser": [
68
72
  "@人手机号"
69
73
  ],
@@ -0,0 +1,63 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ /**
5
+ * 从项目的 webpack/vite 等构建配置中解析对兄弟 app 的依赖。
6
+ *
7
+ * 规则:如果 vue.config.js / next.config.* 的 alias 中存在指向 ../ 的路径,
8
+ * 则认为当前项目依赖该兄弟 app,构建前需要确保兄弟 app 源码是最新的。
9
+ *
10
+ * 示例(vue.config.js):
11
+ * alias: {
12
+ * "@postal-benefits-platform": projectResolve("../postal-benefits-platform/src")
13
+ * }
14
+ *
15
+ * @param {string} appDir - 当前 app 目录的绝对路径
16
+ * @returns {string[]} 兄弟 app 根目录(含 package.json)的绝对路径列表
17
+ */
18
+ function resolveSiblingAppDeps(appDir) {
19
+ const siblings = [];
20
+ const configFiles = [
21
+ "vue.config.js",
22
+ "next.config.js",
23
+ "next.config.mjs",
24
+ "next.config.ts"
25
+ ];
26
+
27
+ for (const configFile of configFiles) {
28
+ const configPath = path.join(appDir, configFile);
29
+ if (!fs.existsSync(configPath)) continue;
30
+
31
+ const content = fs.readFileSync(configPath, "utf8");
32
+
33
+ // 匹配 alias 中指向 ../ 兄弟目录的值,兼容以下写法:
34
+ // "@foo": projectResolve("../foo/src")
35
+ // "@foo": resolve("../foo/src")
36
+ // "@foo": path.resolve(__dirname, "../foo/src")
37
+ const aliasPattern = /["'](@[^"']+)["']\s*:\s*(?:projectResolve|resolve|path\.resolve\s*\(\s*__dirname\s*,)\s*\(\s*["'](\.\.\/[^"']+)["']/g;
38
+
39
+ let match;
40
+ while ((match = aliasPattern.exec(content)) !== null) {
41
+ const [, , relativePath] = match;
42
+ const resolved = path.resolve(appDir, relativePath);
43
+
44
+ // 向上查找含 package.json 的目录,即 app 根目录
45
+ let current = resolved;
46
+ for (let i = 0; i < 5; i++) {
47
+ if (fs.existsSync(path.join(current, "package.json"))) {
48
+ if (current !== appDir && !siblings.includes(current)) {
49
+ siblings.push(current);
50
+ }
51
+ break;
52
+ }
53
+ const parent = path.dirname(current);
54
+ if (parent === current) break;
55
+ current = parent;
56
+ }
57
+ }
58
+ }
59
+
60
+ return siblings;
61
+ }
62
+
63
+ module.exports = { resolveSiblingAppDeps };
@@ -521,8 +521,8 @@ function checkAndUpdateRootPackages(packagesDir, targetBranch = "master") {
521
521
  stdio: "inherit"
522
522
  });
523
523
 
524
- // 使用 merge-from-master.sh 脚本进行安全合并
525
- const mergeScriptPath = path.join(rootDir, "script", "merge-from-master.sh");
524
+ // 只同步共享内容,保留当前分支配置和子模块集合
525
+ const mergeScriptPath = path.join(rootDir, "script", "sync-from-branch.sh");
526
526
  if (fs.existsSync(mergeScriptPath)) {
527
527
  execSync(`bash "${mergeScriptPath}" ${targetBranch}`, {
528
528
  cwd: rootDir,
@@ -699,42 +699,6 @@ async function checkAndUpdatePackages(outPackagesDir, targetBranch = "master") {
699
699
  console.log(global.logColor.warning, `\n⚠️ 有 ${failedUpdates.length} 个模块更新失败,但可以继续执行`);
700
700
  }
701
701
 
702
- // 4. 检查和更新 postal-benefits-platform(如果当前是 postal-benefits-platform-level)
703
- const currentProjectName = require(path.resolve(process.cwd(), "package.json")).name;
704
- if (currentProjectName === "postal-benefits-platform-level") {
705
- // console.log(global.logColor.info, `\n🚀 开始检查和更新 postal-benefits-platform...`);
706
-
707
- // 获取 postal-benefits-platform 的路径
708
- const appsDir = path.resolve(packagesDir, "..", "apps");
709
- const postalPlatformDir = path.join(appsDir, "postal-benefits-platform");
710
-
711
- // 获取 postal-benefits-platform-level 当前分支
712
- const currentLevelBranch = execSync("git rev-parse --abbrev-ref HEAD", {
713
- cwd: process.cwd(),
714
- encoding: "utf8"
715
- }).trim();
716
-
717
- // 检查 postal-benefits-platform 是否有未提交的更改
718
- const platformCheckResult = checkSingleDirGitStatus(postalPlatformDir, "postal-benefits-platform");
719
-
720
- if (platformCheckResult.hasUncommitted) {
721
- console.log(global.logColor.error, `\n❌ postal-benefits-platform 存在未提交的更改`);
722
- console.log(global.logColor.error, `\n请先提交或储藏这些更改后再继续执行!`);
723
- process.exit(1);
724
- }
725
-
726
- // 切换到与 postal-benefits-platform-level 相同的分支并拉取最新代码
727
- const platformUpdateResult = pullSingleDirFromBranch(
728
- postalPlatformDir,
729
- "postal-benefits-platform",
730
- currentLevelBranch
731
- );
732
-
733
- if (!platformUpdateResult.success) {
734
- console.log(global.logColor.warning, `\n⚠️ postal-benefits-platform 更新失败,但可以继续执行`);
735
- }
736
- }
737
-
738
702
  // console.log(global.logColor.success, `\n🎉 packages 检查和更新流程完成!`);
739
703
  return updateResults;
740
704
  } catch (error) {
@@ -68,7 +68,7 @@ function postVersionFileAndMsg(publishText, extraParams = {}) {
68
68
  const { branch, commitMsg, author } = gitInfo || {};
69
69
  const webhookMessage = getWebhookMessage();
70
70
  const GITPATH = `https://gitee.com/gdinfly_1/${projectName}/blob/${branch}/${newFileName}`;
71
- const UPLOADURL = `https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=08ea37af-c6f5-47dc-8fab-0833707c70b8&type=file`;
71
+ const UPLOADURL = `https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=&type=file`;
72
72
  /* const data = {
73
73
  msgtype: "markdown",
74
74
  markdown: {
@@ -0,0 +1,194 @@
1
+ const { execFileSync } = require("node:child_process");
2
+ const fs = require("node:fs");
3
+ const path = require("node:path");
4
+
5
+ const {
6
+ EXIT_SELECTION,
7
+ selectOption: defaultSelectOption,
8
+ } = require("./select-option");
9
+
10
+ function loadConfig(cwd = process.cwd()) {
11
+ const packagePath = path.resolve(cwd, "package.json");
12
+ if (!fs.existsSync(packagePath)) {
13
+ throw new Error(`Project package not found: ${packagePath}.`);
14
+ }
15
+ delete require.cache[require.resolve(packagePath)];
16
+ const inflyConfig = require(packagePath).infly;
17
+ if (!inflyConfig?.dev && !inflyConfig?.build) {
18
+ throw new Error(`Project config is missing in ${packagePath}. Add infly.dev or infly.build.`);
19
+ }
20
+ return {
21
+ config: {
22
+ targets: inflyConfig.targets,
23
+ dev: inflyConfig.dev,
24
+ build: inflyConfig.build,
25
+ },
26
+ configDir: path.dirname(packagePath),
27
+ };
28
+ }
29
+
30
+ function normalizeTargets(targets) {
31
+ if (Array.isArray(targets)) {
32
+ return Object.fromEntries(targets.map((target) => [target, {}]));
33
+ }
34
+ if (targets && typeof targets === "object") return targets;
35
+ throw new Error("Project targets must be a non-empty array or object.");
36
+ }
37
+
38
+ function normalizeEnvironments(environments) {
39
+ if (Array.isArray(environments)) {
40
+ return Object.fromEntries(environments.map((entry) => {
41
+ const separatorIndex = entry.indexOf(":");
42
+ const environment = separatorIndex < 0 ? entry : entry.slice(0, separatorIndex);
43
+ const mode = separatorIndex < 0 ? entry : entry.slice(separatorIndex + 1);
44
+ if (!environment || !mode) {
45
+ throw new Error(`Invalid build environment mapping: ${entry}`);
46
+ }
47
+ return [environment, { mode, args: ["--mode", mode] }];
48
+ }));
49
+ }
50
+ if (environments && typeof environments === "object") return environments;
51
+ throw new Error("Build environments must be an array or object.");
52
+ }
53
+
54
+ function resolveBuildPlatforms(targets, buildConfig, targetName) {
55
+ const normalizedTargets = normalizeTargets(targets);
56
+ if (normalizedTargets[targetName]) return [targetName];
57
+
58
+ const preset = buildConfig.presets?.[targetName];
59
+ if (!preset) throw new Error(`Unknown build target: ${targetName}`);
60
+
61
+ return preset.targets.map((name) => {
62
+ if (!normalizedTargets[name]) {
63
+ throw new Error(`Unknown build target in preset ${targetName}: ${name}`);
64
+ }
65
+ return name;
66
+ });
67
+ }
68
+
69
+ function commandParts(command) {
70
+ const parts = typeof command === "string"
71
+ ? command.trim().split(/\s+/)
72
+ : command;
73
+ if (!Array.isArray(parts) || parts.length === 0 || !parts[0]) {
74
+ throw new Error("Command configuration must be a non-empty string or array.");
75
+ }
76
+ return { command: parts[0], args: parts.slice(1) };
77
+ }
78
+
79
+ function defaultRunCommand(command, args, options) {
80
+ execFileSync(command, args, {
81
+ cwd: options.cwd,
82
+ env: options.env,
83
+ stdio: "inherit",
84
+ });
85
+ }
86
+
87
+ function printDryRun(command, args, env) {
88
+ const platform = env.VUE_APP_PLATFORM ? `VUE_APP_PLATFORM=${env.VUE_APP_PLATFORM} ` : "";
89
+ console.log(`[dry-run] ${platform}${command} ${args.join(" ")}`.trim());
90
+ }
91
+
92
+ async function choose(selectOption, message, entries) {
93
+ return selectOption(
94
+ message,
95
+ entries.map(([value, item]) => ({ value, label: item.label || value })),
96
+ );
97
+ }
98
+
99
+ async function runProjectCommand(options = {}, dependencies = {}) {
100
+ if (typeof options.config === "string") {
101
+ throw new Error("--config is not supported for project commands; use package.json infly config.");
102
+ }
103
+
104
+ const configObject = options.configObject
105
+ || (options.config && typeof options.config === "object" ? options.config : undefined);
106
+ const loaded = configObject
107
+ ? { config: configObject, configDir: options.configDir }
108
+ : loadConfig(options.cwd || process.cwd());
109
+ const config = loaded.config;
110
+ const configDir = options.configDir || loaded.configDir || process.cwd();
111
+ if (!config) throw new Error("Project command config is required.");
112
+ const targets = normalizeTargets(config.targets);
113
+
114
+ const selectOption = dependencies.selectOption || defaultSelectOption;
115
+ const runCommand = dependencies.runCommand || defaultRunCommand;
116
+ const log = dependencies.log || console.log;
117
+ const exitIfSelected = (selection) => {
118
+ if (selection !== EXIT_SELECTION) return false;
119
+ log("已退出,未执行任何操作。");
120
+ return true;
121
+ };
122
+ const action = options.action || await selectOption("请选择操作", [
123
+ { value: "dev", label: "启动开发环境" },
124
+ { value: "build", label: "构建项目" },
125
+ ]);
126
+ if (exitIfSelected(action)) return { cancelled: true };
127
+
128
+ if (action === "dev") {
129
+ const devConfig = config.dev;
130
+ if (!devConfig) throw new Error("Dev configuration is missing.");
131
+ const targetName = options.target || await choose(
132
+ selectOption,
133
+ "请选择目标平台",
134
+ Object.entries(targets),
135
+ );
136
+ if (exitIfSelected(targetName)) return { cancelled: true };
137
+ const target = targets[targetName];
138
+ if (!target) throw new Error(`Unknown dev target: ${targetName}`);
139
+ const parts = commandParts(devConfig.command);
140
+ const env = { ...process.env, VUE_APP_PLATFORM: targetName };
141
+ if (options.dryRun) printDryRun(parts.command, parts.args, env);
142
+ else runCommand(parts.command, parts.args, { cwd: configDir, env });
143
+ return { action, target: targetName };
144
+ }
145
+
146
+ if (action !== "build") throw new Error(`Unknown project action: ${action}`);
147
+ const buildConfig = config.build;
148
+ if (!buildConfig) throw new Error("Build configuration is missing.");
149
+ const environments = normalizeEnvironments(buildConfig.environments);
150
+ const environment = options.env || await choose(
151
+ selectOption,
152
+ "请选择构建环境",
153
+ Object.entries(environments),
154
+ );
155
+ if (exitIfSelected(environment)) return { cancelled: true };
156
+ const environmentConfig = environments[environment];
157
+ if (!environmentConfig) throw new Error(`Unknown build environment: ${environment}`);
158
+ const targetEntries = [
159
+ ...Object.entries(targets),
160
+ ...Object.entries(buildConfig.presets || {}),
161
+ ];
162
+ const targetName = options.target || await choose(
163
+ selectOption,
164
+ "请选择目标平台",
165
+ targetEntries,
166
+ );
167
+ if (exitIfSelected(targetName)) return { cancelled: true };
168
+ const platforms = resolveBuildPlatforms(targets, buildConfig, targetName);
169
+
170
+ for (const platform of platforms) {
171
+ const env = { ...process.env, VUE_APP_PLATFORM: platform };
172
+ const lifecycleArgs = environmentConfig.mode ? ["--mode", environmentConfig.mode] : [];
173
+ const steps = [
174
+ { command: buildConfig.before, extraArgs: lifecycleArgs },
175
+ { command: buildConfig.command, extraArgs: environmentConfig.args || [] },
176
+ { command: buildConfig.after, extraArgs: lifecycleArgs },
177
+ ];
178
+
179
+ for (const step of steps) {
180
+ const parts = commandParts(step.command);
181
+ const args = [...parts.args, ...step.extraArgs];
182
+ if (options.dryRun) printDryRun(parts.command, args, env);
183
+ else runCommand(parts.command, args, { cwd: configDir, env });
184
+ }
185
+ }
186
+
187
+ return { action, environment, target: targetName, platforms };
188
+ }
189
+
190
+ module.exports = {
191
+ loadConfig,
192
+ resolveBuildPlatforms,
193
+ runProjectCommand,
194
+ };