pan-stack-cli 0.1.0 → 0.1.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/README.md +9 -0
- package/bin/pan.js +5 -2
- package/lib/discover.js +12 -2
- package/lib/manifest.js +54 -0
- package/lib/run-command.js +16 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -58,12 +58,21 @@ commands:
|
|
|
58
58
|
description: Deploy backend local
|
|
59
59
|
exec: scripts/deploy.sh
|
|
60
60
|
|
|
61
|
+
install:
|
|
62
|
+
alias: i
|
|
63
|
+
description: Cài dependencies (pan i hoặc pan install)
|
|
64
|
+
shell: |
|
|
65
|
+
set -euo pipefail
|
|
66
|
+
pnpm install
|
|
67
|
+
|
|
61
68
|
lint:
|
|
62
69
|
shell: |
|
|
63
70
|
set -euo pipefail
|
|
64
71
|
pnpm lint
|
|
65
72
|
```
|
|
66
73
|
|
|
74
|
+
Alias: `alias: i` hoặc `aliases: i, ins` (cách nhau bằng dấu phẩy).
|
|
75
|
+
|
|
67
76
|
### Schema `.pan.yaml` (workspace root)
|
|
68
77
|
|
|
69
78
|
Lệnh orchestration — `cwd` tương đối workspace root; dùng `PAN_WORKSPACE_ROOT` trong shell:
|
package/bin/pan.js
CHANGED
|
@@ -95,8 +95,10 @@ function printAllCommands(sources) {
|
|
|
95
95
|
const targetHint = command.hasTargets
|
|
96
96
|
? ` [${command.targets.join("|")}]`
|
|
97
97
|
: "";
|
|
98
|
+
const aliasHint =
|
|
99
|
+
command.aliases.length > 0 ? ` (${command.aliases.join(", ")})` : "";
|
|
98
100
|
const desc = command.description ? ` — ${command.description}` : "";
|
|
99
|
-
console.log(` ${command.name}${targetHint}${desc}`);
|
|
101
|
+
console.log(` ${command.name}${aliasHint}${targetHint}${desc}`);
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
}
|
|
@@ -126,12 +128,13 @@ async function main() {
|
|
|
126
128
|
return;
|
|
127
129
|
}
|
|
128
130
|
|
|
131
|
+
const allSources = loadAllCommandSources();
|
|
129
132
|
const matches = findSourcesWithCommand(command);
|
|
130
133
|
if (matches.length > 1 && !project && process.stdin.isTTY) {
|
|
131
134
|
console.log(formatProjectList(matches, command));
|
|
132
135
|
}
|
|
133
136
|
|
|
134
|
-
await runWithProjectResolution(matches, command, args, project);
|
|
137
|
+
await runWithProjectResolution(matches, command, args, project, allSources);
|
|
135
138
|
}
|
|
136
139
|
|
|
137
140
|
main().catch((error) => {
|
package/lib/discover.js
CHANGED
|
@@ -6,6 +6,7 @@ const {
|
|
|
6
6
|
loadManifest,
|
|
7
7
|
loadPanConfig,
|
|
8
8
|
getCommandDefinition,
|
|
9
|
+
commandAliases,
|
|
9
10
|
validateRepo,
|
|
10
11
|
cleanValue,
|
|
11
12
|
} = require("./manifest");
|
|
@@ -166,9 +167,18 @@ function sourceMatchesProject(source, projectFlag) {
|
|
|
166
167
|
);
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
function sourceHasCommand(source, commandName) {
|
|
171
|
+
if (source.commands[commandName]) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
return Object.values(source.commands || {}).some((def) =>
|
|
175
|
+
commandAliases(def).includes(commandName)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
169
179
|
function findSourcesWithCommand(commandName, startDir = process.cwd()) {
|
|
170
|
-
return loadAllCommandSources(startDir).filter(
|
|
171
|
-
(source
|
|
180
|
+
return loadAllCommandSources(startDir).filter((source) =>
|
|
181
|
+
sourceHasCommand(source, commandName)
|
|
172
182
|
);
|
|
173
183
|
}
|
|
174
184
|
|
package/lib/manifest.js
CHANGED
|
@@ -261,6 +261,57 @@ function loadPanConfig(configPath, meta = {}) {
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
function commandAliases(def) {
|
|
265
|
+
if (!def) {
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
const result = [];
|
|
269
|
+
if (def.alias) {
|
|
270
|
+
result.push(cleanValue(def.alias));
|
|
271
|
+
}
|
|
272
|
+
if (def.aliases) {
|
|
273
|
+
const raw = def.aliases;
|
|
274
|
+
if (Array.isArray(raw)) {
|
|
275
|
+
result.push(...raw.map((item) => cleanValue(item)));
|
|
276
|
+
} else {
|
|
277
|
+
const value = cleanValue(raw);
|
|
278
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
279
|
+
result.push(
|
|
280
|
+
...value
|
|
281
|
+
.slice(1, -1)
|
|
282
|
+
.split(",")
|
|
283
|
+
.map((item) => cleanValue(item))
|
|
284
|
+
.filter(Boolean)
|
|
285
|
+
);
|
|
286
|
+
} else if (value.includes(",")) {
|
|
287
|
+
result.push(
|
|
288
|
+
...value
|
|
289
|
+
.split(",")
|
|
290
|
+
.map((item) => cleanValue(item))
|
|
291
|
+
.filter(Boolean)
|
|
292
|
+
);
|
|
293
|
+
} else if (value) {
|
|
294
|
+
result.push(value);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return [...new Set(result.filter(Boolean))];
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function resolveCommandName(sources, commandName) {
|
|
302
|
+
if (sources.some((source) => source.commands[commandName])) {
|
|
303
|
+
return commandName;
|
|
304
|
+
}
|
|
305
|
+
for (const source of sources) {
|
|
306
|
+
for (const [primaryName, def] of Object.entries(source.commands || {})) {
|
|
307
|
+
if (commandAliases(def).includes(commandName)) {
|
|
308
|
+
return primaryName;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return commandName;
|
|
313
|
+
}
|
|
314
|
+
|
|
264
315
|
function getCommandDefinition(source, commandName, subArg) {
|
|
265
316
|
const def = source.commands[commandName];
|
|
266
317
|
if (!def) {
|
|
@@ -287,6 +338,7 @@ function getCommandDefinition(source, commandName, subArg) {
|
|
|
287
338
|
function listCommands(source) {
|
|
288
339
|
return Object.entries(source.commands || {}).map(([name, def]) => ({
|
|
289
340
|
name,
|
|
341
|
+
aliases: commandAliases(def),
|
|
290
342
|
description: def.description || "",
|
|
291
343
|
hasTargets: Boolean(def.targets),
|
|
292
344
|
targets: def.targets ? Object.keys(def.targets) : [],
|
|
@@ -306,6 +358,8 @@ module.exports = {
|
|
|
306
358
|
loadPanConfig,
|
|
307
359
|
manifestRepos,
|
|
308
360
|
validateRepo,
|
|
361
|
+
commandAliases,
|
|
362
|
+
resolveCommandName,
|
|
309
363
|
getCommandDefinition,
|
|
310
364
|
listCommands,
|
|
311
365
|
commandBaseDir,
|
package/lib/run-command.js
CHANGED
|
@@ -2,7 +2,11 @@ const fs = require("fs");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const { spawn, spawnSync } = require("child_process");
|
|
4
4
|
const readline = require("readline");
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
getCommandDefinition,
|
|
7
|
+
commandBaseDir,
|
|
8
|
+
resolveCommandName,
|
|
9
|
+
} = require("./manifest");
|
|
6
10
|
const { sourceMatchesProject } = require("./discover");
|
|
7
11
|
|
|
8
12
|
function needDir(dir) {
|
|
@@ -134,7 +138,15 @@ function promptProjectChoice(matches, commandName) {
|
|
|
134
138
|
});
|
|
135
139
|
}
|
|
136
140
|
|
|
137
|
-
async function runWithProjectResolution(
|
|
141
|
+
async function runWithProjectResolution(
|
|
142
|
+
matches,
|
|
143
|
+
commandName,
|
|
144
|
+
args,
|
|
145
|
+
projectFlag,
|
|
146
|
+
allSources = matches
|
|
147
|
+
) {
|
|
148
|
+
const resolvedName = resolveCommandName(allSources, commandName);
|
|
149
|
+
|
|
138
150
|
if (matches.length === 0) {
|
|
139
151
|
throw new Error(
|
|
140
152
|
`Không tìm thấy lệnh '${commandName}' trong bất kỳ .pan.yaml nào.`
|
|
@@ -152,7 +164,7 @@ async function runWithProjectResolution(matches, commandName, args, projectFlag)
|
|
|
152
164
|
source = matches[0];
|
|
153
165
|
} else {
|
|
154
166
|
const withTargetArg = matches.filter((item) => {
|
|
155
|
-
const def = item.commands[
|
|
167
|
+
const def = item.commands[resolvedName];
|
|
156
168
|
return def?.targets && args[0] && def.targets[args[0]];
|
|
157
169
|
});
|
|
158
170
|
if (withTargetArg.length === 1) {
|
|
@@ -169,7 +181,7 @@ async function runWithProjectResolution(matches, commandName, args, projectFlag)
|
|
|
169
181
|
}
|
|
170
182
|
}
|
|
171
183
|
|
|
172
|
-
runProjectCommand(source,
|
|
184
|
+
runProjectCommand(source, resolvedName, args);
|
|
173
185
|
}
|
|
174
186
|
|
|
175
187
|
function runGitScript(scriptName, args) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pan-stack-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "CLI điều phối PAN Stack — git đa repo và lệnh dự án từ .project.yaml",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -24,4 +24,4 @@
|
|
|
24
24
|
"url": "https://github.com/doiya46/pan-stack.git",
|
|
25
25
|
"directory": ".pan/pan-stack-cli"
|
|
26
26
|
}
|
|
27
|
-
}
|
|
27
|
+
}
|