@zokugun/artifact 0.5.0 → 0.5.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/lib/cli.js +1 -1
- package/lib/routes/command.js +25 -30
- package/lib/steps/read-files.js +1 -0
- package/lib/utils/command/dedupe-strings.js +12 -0
- package/lib/utils/command/index.js +11 -1
- package/lib/utils/command/merge-and-chains.js +91 -0
- package/lib/utils/command/merge-command-records.js +82 -0
- package/lib/utils/command/merge-flag-tokens.js +14 -0
- package/lib/utils/command/merge-flags-as-string.js +10 -0
- package/lib/utils/command/merge-or-segments.js +85 -0
- package/lib/utils/command/merge-parts-by-prefix.js +25 -0
- package/lib/utils/command/merge-semicolon-segments.js +127 -0
- package/lib/utils/command/merge-with-semicolon-mix.js +48 -0
- package/lib/utils/command/prefix-of-command.js +7 -0
- package/lib/utils/command/split-chain.js +6 -0
- package/lib/utils/command/split-prefix-and-flags.js +29 -0
- package/lib/utils/command/split-segments.js +6 -0
- package/package.json +2 -2
package/lib/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const commander_1 = require("commander");
|
|
6
|
+
const commander_1 = require("@zokugun/cli-utils/commander");
|
|
7
7
|
const package_json_1 = __importDefault(require("../package.json"));
|
|
8
8
|
const commands_1 = require("./commands");
|
|
9
9
|
const program = new commander_1.Command();
|
package/lib/routes/command.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.command = command;
|
|
4
4
|
const command_1 = require("../utils/command");
|
|
5
|
-
const list_concat_1 = require("./list-concat");
|
|
6
5
|
function command({ current, incoming }) {
|
|
7
6
|
if (!incoming) {
|
|
8
7
|
return current ?? '';
|
|
@@ -10,35 +9,31 @@ function command({ current, incoming }) {
|
|
|
10
9
|
if (!current) {
|
|
11
10
|
return incoming;
|
|
12
11
|
}
|
|
12
|
+
const trueAndMatch = /^true\s*&&\s*(.+)$/.exec(incoming);
|
|
13
|
+
const currentSegments = new Set(current.split(/;|&&|\|\|/).map((s) => s.trim()).filter(Boolean));
|
|
14
|
+
if (currentSegments.has(incoming)) {
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
if (trueAndMatch) {
|
|
18
|
+
const incomingCommand = trueAndMatch[1].trim();
|
|
19
|
+
return currentSegments.has(incomingCommand) ? current : `${current} && ${incomingCommand}`;
|
|
20
|
+
}
|
|
21
|
+
const mixed = (0, command_1.mergeWithSemicolonMix)(current, incoming);
|
|
22
|
+
if (mixed) {
|
|
23
|
+
return mixed;
|
|
24
|
+
}
|
|
25
|
+
const andMerged = (0, command_1.mergeAndChains)(current, incoming);
|
|
26
|
+
if (andMerged) {
|
|
27
|
+
return andMerged;
|
|
28
|
+
}
|
|
29
|
+
if (incoming.includes('||')) {
|
|
30
|
+
return (0, command_1.mergeOrSegments)(current, incoming);
|
|
31
|
+
}
|
|
32
|
+
if (incoming.includes(';')) {
|
|
33
|
+
return (0, command_1.mergeSemicolonSegments)(current, incoming);
|
|
34
|
+
}
|
|
13
35
|
const currentCommand = (0, command_1.splitCommand)(current);
|
|
14
36
|
const incomingCommand = (0, command_1.splitCommand)(incoming);
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
if (currentCommand[name]) {
|
|
18
|
-
result[name] = [];
|
|
19
|
-
for (const [index, instance] of instances.entries()) {
|
|
20
|
-
if (currentCommand[name][index]) {
|
|
21
|
-
const currentInstance = currentCommand[name][index];
|
|
22
|
-
result[name].push({
|
|
23
|
-
args: (0, list_concat_1.listConcat)({
|
|
24
|
-
current: currentInstance.args,
|
|
25
|
-
incoming: instance.args,
|
|
26
|
-
}),
|
|
27
|
-
env: (0, list_concat_1.listConcat)({
|
|
28
|
-
current: currentInstance.env,
|
|
29
|
-
incoming: instance.env,
|
|
30
|
-
}),
|
|
31
|
-
separator: instance.separator ?? currentInstance.separator,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
result[name].push(instance);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
result[name] = instances;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return (0, command_1.joinCommand)(result);
|
|
37
|
+
const merged = (0, command_1.mergeCommandRecords)(currentCommand, incomingCommand, current);
|
|
38
|
+
return (0, command_1.joinCommand)(merged);
|
|
44
39
|
}
|
package/lib/steps/read-files.js
CHANGED
|
@@ -17,6 +17,7 @@ async function readFiles({ incomingPath, textFiles, binaryFiles, options }) {
|
|
|
17
17
|
});
|
|
18
18
|
for (const file of files) {
|
|
19
19
|
const filePath = path_1.default.join(cwd, file);
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
20
21
|
if ((0, istextorbinary_1.isText)(file) || (0, istextorbinary_1.getEncoding)(await (0, read_buffer_1.readBuffer)(filePath, 24)) === 'utf8') {
|
|
21
22
|
const data = await fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
22
23
|
const finalNewLine = data.endsWith('\n');
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dedupeStrings = dedupeStrings;
|
|
4
|
+
function dedupeStrings(items) {
|
|
5
|
+
const result = [];
|
|
6
|
+
for (const item of items) {
|
|
7
|
+
if (!result.includes(item)) {
|
|
8
|
+
result.push(item);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.splitCommand = exports.joinCommand = void 0;
|
|
3
|
+
exports.splitCommand = exports.mergeWithSemicolonMix = exports.mergeSemicolonSegments = exports.mergeOrSegments = exports.mergeCommandRecords = exports.mergeAndChains = exports.joinCommand = void 0;
|
|
4
4
|
var join_command_1 = require("./join-command");
|
|
5
5
|
Object.defineProperty(exports, "joinCommand", { enumerable: true, get: function () { return join_command_1.joinCommand; } });
|
|
6
|
+
var merge_and_chains_1 = require("./merge-and-chains");
|
|
7
|
+
Object.defineProperty(exports, "mergeAndChains", { enumerable: true, get: function () { return merge_and_chains_1.mergeAndChains; } });
|
|
8
|
+
var merge_command_records_1 = require("./merge-command-records");
|
|
9
|
+
Object.defineProperty(exports, "mergeCommandRecords", { enumerable: true, get: function () { return merge_command_records_1.mergeCommandRecords; } });
|
|
10
|
+
var merge_or_segments_1 = require("./merge-or-segments");
|
|
11
|
+
Object.defineProperty(exports, "mergeOrSegments", { enumerable: true, get: function () { return merge_or_segments_1.mergeOrSegments; } });
|
|
12
|
+
var merge_semicolon_segments_1 = require("./merge-semicolon-segments");
|
|
13
|
+
Object.defineProperty(exports, "mergeSemicolonSegments", { enumerable: true, get: function () { return merge_semicolon_segments_1.mergeSemicolonSegments; } });
|
|
14
|
+
var merge_with_semicolon_mix_1 = require("./merge-with-semicolon-mix");
|
|
15
|
+
Object.defineProperty(exports, "mergeWithSemicolonMix", { enumerable: true, get: function () { return merge_with_semicolon_mix_1.mergeWithSemicolonMix; } });
|
|
6
16
|
var split_command_1 = require("./split-command");
|
|
7
17
|
Object.defineProperty(exports, "splitCommand", { enumerable: true, get: function () { return split_command_1.splitCommand; } });
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeAndChains = mergeAndChains;
|
|
4
|
+
const dedupe_strings_1 = require("./dedupe-strings");
|
|
5
|
+
const merge_flags_as_string_1 = require("./merge-flags-as-string");
|
|
6
|
+
const merge_parts_by_prefix_1 = require("./merge-parts-by-prefix");
|
|
7
|
+
const prefix_of_command_1 = require("./prefix-of-command");
|
|
8
|
+
const split_chain_1 = require("./split-chain");
|
|
9
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
10
|
+
const split_segments_1 = require("./split-segments");
|
|
11
|
+
function mergeAndChains(current, incoming) {
|
|
12
|
+
if (!(incoming.includes('&&') && current.includes('&&'))) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const currentMain = (current.split(';')[0] || '').trim();
|
|
16
|
+
const incomingMain = (incoming.split(';')[0] || '').trim();
|
|
17
|
+
const currentAnd = (0, split_chain_1.splitChain)(currentMain, '&&');
|
|
18
|
+
const incomingAnd = (0, split_chain_1.splitChain)(incomingMain, '&&');
|
|
19
|
+
// Consider positional match primarily by the first segment's prefix
|
|
20
|
+
const firstCurrent = currentAnd[0] || '';
|
|
21
|
+
const firstIncoming = incomingAnd[0] || '';
|
|
22
|
+
const positionalMatch = (0, prefix_of_command_1.prefixOfCommand)(firstCurrent) === (0, prefix_of_command_1.prefixOfCommand)(firstIncoming);
|
|
23
|
+
if (!positionalMatch) {
|
|
24
|
+
// Merge by matching prefixes across current segments, append unmatched incoming segments.
|
|
25
|
+
const merged = (0, merge_parts_by_prefix_1.mergePartsByPrefix)(currentAnd, incomingAnd);
|
|
26
|
+
return merged.join('; ');
|
|
27
|
+
}
|
|
28
|
+
// Positional merge: iterate positions, merge flags when prefixes equal, otherwise
|
|
29
|
+
// decide ordering: if incoming's semicolon tail contains current segment, prefer incoming in chain and move current to tail;
|
|
30
|
+
// else keep current in chain then append incoming segment after it.
|
|
31
|
+
const incomingTail = (0, split_segments_1.splitSegments)(incoming).slice(1);
|
|
32
|
+
const currentTail = (0, split_segments_1.splitSegments)(current).slice(1);
|
|
33
|
+
const maxLength = Math.max(currentAnd.length, incomingAnd.length);
|
|
34
|
+
const chainResult = [];
|
|
35
|
+
const tailResult = [];
|
|
36
|
+
for (let i = 0; i < maxLength; i++) {
|
|
37
|
+
const currentPart = currentAnd[i];
|
|
38
|
+
const incomingPart = incomingAnd[i];
|
|
39
|
+
if (currentPart && incomingPart) {
|
|
40
|
+
const cPref = (0, prefix_of_command_1.prefixOfCommand)(currentPart);
|
|
41
|
+
const nPref = (0, prefix_of_command_1.prefixOfCommand)(incomingPart);
|
|
42
|
+
if (cPref && nPref && cPref === nPref) {
|
|
43
|
+
if (incomingTail.length > 0) {
|
|
44
|
+
chainResult.push((0, merge_flags_as_string_1.mergeFlagsAsString)(incomingPart, (0, split_prefix_and_flags_1.splitPrefixAndFlags)(currentPart)));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
chainResult.push((0, merge_flags_as_string_1.mergeFlagsAsString)(currentPart, (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incomingPart)));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// prefixes differ
|
|
52
|
+
if (incomingTail.some((t) => t === currentPart || t.startsWith(`${currentPart} `))) {
|
|
53
|
+
// incoming already includes current as a semicolon tail -> prefer incoming in chain
|
|
54
|
+
chainResult.push(incomingPart);
|
|
55
|
+
tailResult.push(currentPart);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// keep current in chain, then include incoming after
|
|
59
|
+
chainResult.push(currentPart);
|
|
60
|
+
const coveredByCurrentTail = currentTail.some((t) => t.startsWith(`${incomingPart} `));
|
|
61
|
+
if (!coveredByCurrentTail) {
|
|
62
|
+
chainResult.push(incomingPart);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (currentPart) {
|
|
68
|
+
chainResult.push(currentPart);
|
|
69
|
+
}
|
|
70
|
+
else if (incomingPart) {
|
|
71
|
+
chainResult.push(incomingPart);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const dedupedChain = (0, dedupe_strings_1.dedupeStrings)(chainResult);
|
|
75
|
+
// Append any remaining semicolon tails from current and incoming (preserve incoming tail order)
|
|
76
|
+
// remove any tail entries that are already present in the chainResult (by prefix)
|
|
77
|
+
const chainPrefixes = new Set(dedupedChain.map(prefix_of_command_1.prefixOfCommand).filter(Boolean));
|
|
78
|
+
const combined = [...tailResult, ...currentTail, ...incomingTail].filter((t) => {
|
|
79
|
+
const tp = (0, prefix_of_command_1.prefixOfCommand)(t) || t;
|
|
80
|
+
return !chainPrefixes.has(tp);
|
|
81
|
+
});
|
|
82
|
+
const seen = new Set();
|
|
83
|
+
const remainingTail = [];
|
|
84
|
+
for (const t of combined) {
|
|
85
|
+
if (!seen.has(t)) {
|
|
86
|
+
seen.add(t);
|
|
87
|
+
remainingTail.push(t);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return dedupedChain.join(' && ') + (remainingTail.length > 0 ? '; ' + remainingTail.join('; ') : '');
|
|
91
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeCommandRecords = mergeCommandRecords;
|
|
4
|
+
const lodash_1 = require("lodash");
|
|
5
|
+
const list_concat_1 = require("../../routes/list-concat");
|
|
6
|
+
function mergeCommandRecords(currentCommand, incomingCommand, currentString) {
|
|
7
|
+
const result = {};
|
|
8
|
+
// Start with current commands to preserve ordering
|
|
9
|
+
for (const [name, instances] of Object.entries(currentCommand)) {
|
|
10
|
+
result[name] = instances.slice();
|
|
11
|
+
}
|
|
12
|
+
// Merge incoming into existing result, preserving order
|
|
13
|
+
for (const [name, instances] of Object.entries(incomingCommand)) {
|
|
14
|
+
if (result[name]) {
|
|
15
|
+
for (const [idx, instance] of instances.entries()) {
|
|
16
|
+
if (result[name][idx]) {
|
|
17
|
+
const currentInstance = result[name][idx];
|
|
18
|
+
const hasFlags = (array) => array.some((a) => a.startsWith('-') || a.includes('='));
|
|
19
|
+
const getPrefix = (array) => {
|
|
20
|
+
const ii = array.findIndex((a) => a.startsWith('-'));
|
|
21
|
+
if (ii === -1) {
|
|
22
|
+
return array.join(' ').trim();
|
|
23
|
+
}
|
|
24
|
+
return array.slice(0, ii).join(' ').trim();
|
|
25
|
+
};
|
|
26
|
+
const currentPrefix = getPrefix(currentInstance.args);
|
|
27
|
+
const incomingPrefix = getPrefix(instance.args);
|
|
28
|
+
const shouldMerge = currentPrefix && incomingPrefix && currentPrefix === incomingPrefix && (hasFlags(currentInstance.args) || hasFlags(instance.args) || (currentInstance.env.length > 0) || (instance.env.length > 0));
|
|
29
|
+
if (shouldMerge) {
|
|
30
|
+
// replace with merged instance
|
|
31
|
+
result[name][idx] = {
|
|
32
|
+
args: (0, list_concat_1.listConcat)({ current: currentInstance.args, incoming: instance.args }),
|
|
33
|
+
env: (0, list_concat_1.listConcat)({ current: currentInstance.env, incoming: instance.env }),
|
|
34
|
+
separator: instance.separator ?? currentInstance.separator,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
// If incoming instance is empty (no args/env), skip it to avoid duplicates
|
|
39
|
+
if ((instance.args.length === 0) && (instance.env.length === 0)) {
|
|
40
|
+
// keep current as-is
|
|
41
|
+
result[name][idx] = currentInstance;
|
|
42
|
+
}
|
|
43
|
+
else if ((0, lodash_1.isEqual)(currentInstance.env, instance.env)
|
|
44
|
+
&& instance.args.length > 0
|
|
45
|
+
&& instance.args.every((arg) => currentInstance.args.includes(arg))) {
|
|
46
|
+
// Incoming is a strict subset of current args for the same command/env.
|
|
47
|
+
result[name][idx] = currentInstance;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// avoid inserting exact duplicate instances
|
|
51
|
+
const duplicateExists = result[name].some((r) => (0, lodash_1.isEqual)(r.args, instance.args) && (0, lodash_1.isEqual)(r.env, instance.env));
|
|
52
|
+
if (duplicateExists) {
|
|
53
|
+
// nothing to do, keep current ordering
|
|
54
|
+
result[name][idx] = currentInstance;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// insert incoming as separate after current
|
|
58
|
+
const currentWithSep = { ...currentInstance, separator: currentInstance.separator ?? (currentString.includes('&&') ? '&&' : ';') };
|
|
59
|
+
result[name][idx] = currentWithSep;
|
|
60
|
+
result[name].splice(idx + 1, 0, instance);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
result[name].push(instance);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
// incoming-only: append
|
|
72
|
+
result[name] = instances.slice();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Include current-only entries that weren't present in incoming
|
|
76
|
+
for (const [name, instances] of Object.entries(currentCommand)) {
|
|
77
|
+
if (!result[name]) {
|
|
78
|
+
result[name] = instances;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeFlagTokens = mergeFlagTokens;
|
|
4
|
+
function mergeFlagTokens(currentFlags, incomingFlags) {
|
|
5
|
+
const mergedFlags = currentFlags.slice();
|
|
6
|
+
for (const flag of incomingFlags) {
|
|
7
|
+
const name = flag.split(/\s+/)[0];
|
|
8
|
+
const exists = mergedFlags.some((existing) => existing.split(/\s+/)[0] === name);
|
|
9
|
+
if (!exists) {
|
|
10
|
+
mergedFlags.push(flag);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return mergedFlags;
|
|
14
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeFlagsAsString = mergeFlagsAsString;
|
|
4
|
+
const merge_flag_tokens_1 = require("./merge-flag-tokens");
|
|
5
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
6
|
+
function mergeFlagsAsString(current, incoming) {
|
|
7
|
+
const currentPrefix = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(current);
|
|
8
|
+
const mergedFlags = (0, merge_flag_tokens_1.mergeFlagTokens)(currentPrefix.flags, incoming.flags);
|
|
9
|
+
return currentPrefix.prefix + (mergedFlags.length > 0 ? ' ' + mergedFlags.join(' ') : '');
|
|
10
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeOrSegments = mergeOrSegments;
|
|
4
|
+
const dedupe_strings_1 = require("./dedupe-strings");
|
|
5
|
+
const merge_flags_as_string_1 = require("./merge-flags-as-string");
|
|
6
|
+
const merge_semicolon_segments_1 = require("./merge-semicolon-segments");
|
|
7
|
+
const prefix_of_command_1 = require("./prefix-of-command");
|
|
8
|
+
const split_chain_1 = require("./split-chain");
|
|
9
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
10
|
+
const split_segments_1 = require("./split-segments");
|
|
11
|
+
function mergeOrSegments(current, incoming) {
|
|
12
|
+
const currentSegments = (0, split_segments_1.splitSegments)(current);
|
|
13
|
+
const incomingSegments = (0, split_segments_1.splitSegments)(incoming);
|
|
14
|
+
const currentOrIdx = currentSegments.findIndex((s) => s.includes('||'));
|
|
15
|
+
const incomingOrIdx = incomingSegments.findIndex((s) => s.includes('||'));
|
|
16
|
+
if (currentOrIdx === -1 || incomingOrIdx === -1) {
|
|
17
|
+
return (0, merge_semicolon_segments_1.mergeSemicolonSegments)(current, incoming);
|
|
18
|
+
}
|
|
19
|
+
const currentParts = (0, split_chain_1.splitChain)(currentSegments[currentOrIdx], '||');
|
|
20
|
+
const incomingParts = (0, split_chain_1.splitChain)(incomingSegments[incomingOrIdx], '||');
|
|
21
|
+
const currentTail = currentSegments.filter((_, idx) => idx !== currentOrIdx);
|
|
22
|
+
const incomingTail = incomingSegments.filter((_, idx) => idx !== incomingOrIdx);
|
|
23
|
+
const maxLength = Math.max(currentParts.length, incomingParts.length);
|
|
24
|
+
const chainResult = [];
|
|
25
|
+
const movedToTail = [];
|
|
26
|
+
for (let i = 0; i < maxLength; i++) {
|
|
27
|
+
const currentPart = currentParts[i];
|
|
28
|
+
const incomingPart = incomingParts[i];
|
|
29
|
+
if (currentPart && incomingPart) {
|
|
30
|
+
const cPref = (0, prefix_of_command_1.prefixOfCommand)(currentPart);
|
|
31
|
+
const nPref = (0, prefix_of_command_1.prefixOfCommand)(incomingPart);
|
|
32
|
+
if (cPref && nPref && cPref === nPref) {
|
|
33
|
+
if (incomingTail.length > 0) {
|
|
34
|
+
chainResult.push((0, merge_flags_as_string_1.mergeFlagsAsString)(incomingPart, (0, split_prefix_and_flags_1.splitPrefixAndFlags)(currentPart)));
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
chainResult.push((0, merge_flags_as_string_1.mergeFlagsAsString)(currentPart, (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incomingPart)));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (incomingTail.some((t) => t === currentPart || t.startsWith(`${currentPart} `))) {
|
|
41
|
+
chainResult.push(incomingPart);
|
|
42
|
+
movedToTail.push(currentPart);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
chainResult.push(currentPart);
|
|
46
|
+
const coveredByCurrentTail = currentTail.some((t) => t.startsWith(`${incomingPart} `));
|
|
47
|
+
if (!coveredByCurrentTail) {
|
|
48
|
+
chainResult.push(incomingPart);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
else if (currentPart) {
|
|
53
|
+
chainResult.push(currentPart);
|
|
54
|
+
}
|
|
55
|
+
else if (incomingPart) {
|
|
56
|
+
chainResult.push(incomingPart);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const dedupedChain = [];
|
|
60
|
+
for (const part of chainResult) {
|
|
61
|
+
if (!dedupedChain.includes(part)) {
|
|
62
|
+
dedupedChain.push(part);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const chainParts = new Set(dedupedChain);
|
|
66
|
+
const rawTail = [...currentTail, ...movedToTail, ...incomingTail];
|
|
67
|
+
const filteredTail = rawTail.filter((tail, idx) => {
|
|
68
|
+
if (chainParts.has(tail)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Keep only the most specific tail when two tails share a prefix.
|
|
72
|
+
return !rawTail.some((other, otherIdx) => otherIdx !== idx && other.startsWith(`${tail} `));
|
|
73
|
+
});
|
|
74
|
+
const mergedChain = dedupedChain.join(' || ');
|
|
75
|
+
const chainPrefixes = new Set(dedupedChain.map(prefix_of_command_1.prefixOfCommand).filter(Boolean));
|
|
76
|
+
const mergedSegs = currentSegments
|
|
77
|
+
.map((seg, idx) => (idx === currentOrIdx ? mergedChain : seg))
|
|
78
|
+
.filter((seg, idx) => idx === currentOrIdx || !chainPrefixes.has((0, prefix_of_command_1.prefixOfCommand)(seg)));
|
|
79
|
+
for (const tail of (0, dedupe_strings_1.dedupeStrings)(filteredTail)) {
|
|
80
|
+
if (!mergedSegs.includes(tail)) {
|
|
81
|
+
mergedSegs.push(tail);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return (0, dedupe_strings_1.dedupeStrings)(mergedSegs).join('; ');
|
|
85
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergePartsByPrefix = mergePartsByPrefix;
|
|
4
|
+
const merge_flag_tokens_1 = require("./merge-flag-tokens");
|
|
5
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
6
|
+
function mergePartsByPrefix(currentParts, incomingParts) {
|
|
7
|
+
const result = currentParts.slice();
|
|
8
|
+
for (const incomingPart of incomingParts) {
|
|
9
|
+
const incomingPrefix = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incomingPart);
|
|
10
|
+
let merged = false;
|
|
11
|
+
for (let k = 0; k < result.length; k++) {
|
|
12
|
+
const currentPrefix = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(result[k]);
|
|
13
|
+
if (currentPrefix.prefix && incomingPrefix.prefix && currentPrefix.prefix === incomingPrefix.prefix) {
|
|
14
|
+
const mergedFlags = (0, merge_flag_tokens_1.mergeFlagTokens)(currentPrefix.flags, incomingPrefix.flags);
|
|
15
|
+
result[k] = currentPrefix.prefix + (mergedFlags.length > 0 ? ' ' + mergedFlags.join(' ') : '');
|
|
16
|
+
merged = true;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (!merged) {
|
|
21
|
+
result.push(incomingPart);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeSemicolonSegments = mergeSemicolonSegments;
|
|
4
|
+
const merge_flag_tokens_1 = require("./merge-flag-tokens");
|
|
5
|
+
const merge_flags_as_string_1 = require("./merge-flags-as-string");
|
|
6
|
+
const merge_parts_by_prefix_1 = require("./merge-parts-by-prefix");
|
|
7
|
+
const prefix_of_command_1 = require("./prefix-of-command");
|
|
8
|
+
const split_chain_1 = require("./split-chain");
|
|
9
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
10
|
+
const split_segments_1 = require("./split-segments");
|
|
11
|
+
function mergeSemicolonSegments(current, incoming) {
|
|
12
|
+
let currentSegments = (0, split_segments_1.splitSegments)(current);
|
|
13
|
+
const incomingSegments = (0, split_segments_1.splitSegments)(incoming);
|
|
14
|
+
for (const incomingSegment of incomingSegments) {
|
|
15
|
+
// If the incoming segment is itself a chain (&& or ||), merge subparts accordingly
|
|
16
|
+
if (incomingSegment.includes('||')) {
|
|
17
|
+
const incomingParts = incomingSegment.split('||').map((s) => s.trim()).filter(Boolean);
|
|
18
|
+
let mergedIntoCurrent = false;
|
|
19
|
+
for (let j = 0; j < currentSegments.length; j++) {
|
|
20
|
+
if (currentSegments[j].includes('||')) {
|
|
21
|
+
const currentParts = (0, split_chain_1.splitChain)(currentSegments[j], '||');
|
|
22
|
+
const newParts = (0, merge_parts_by_prefix_1.mergePartsByPrefix)(currentParts, incomingParts);
|
|
23
|
+
currentSegments[j] = newParts.join(' || ');
|
|
24
|
+
// remove duplicates that were absorbed
|
|
25
|
+
currentSegments = currentSegments.filter((s, idx) => {
|
|
26
|
+
if (idx === j) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
for (const np of newParts) {
|
|
30
|
+
if (s === np) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
});
|
|
36
|
+
mergedIntoCurrent = true;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (!mergedIntoCurrent) {
|
|
41
|
+
currentSegments.push(incomingSegment);
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (incomingSegment.includes('&&')) {
|
|
46
|
+
const incomingParts = (0, split_chain_1.splitChain)(incomingSegment, '&&');
|
|
47
|
+
let mergedIntoCurrent = false;
|
|
48
|
+
for (let j = 0; j < currentSegments.length; j++) {
|
|
49
|
+
if (currentSegments[j].includes('&&')) {
|
|
50
|
+
const currentParts = (0, split_chain_1.splitChain)(currentSegments[j], '&&');
|
|
51
|
+
// If first prefixes align, do positional merge preferring incoming flags first
|
|
52
|
+
let newParts = [];
|
|
53
|
+
if (currentParts.length > 0 && incomingParts.length > 0 && (0, prefix_of_command_1.prefixOfCommand)(currentParts[0]) === (0, prefix_of_command_1.prefixOfCommand)(incomingParts[0])) {
|
|
54
|
+
const maxLength = Math.max(currentParts.length, incomingParts.length);
|
|
55
|
+
for (let i = 0; i < maxLength; i++) {
|
|
56
|
+
const curPart = currentParts[i];
|
|
57
|
+
const incPart = incomingParts[i];
|
|
58
|
+
if (curPart && incPart) {
|
|
59
|
+
const curP = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(curPart);
|
|
60
|
+
const incP = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incPart);
|
|
61
|
+
if (curP.prefix && incP.prefix && curP.prefix === incP.prefix) {
|
|
62
|
+
// keep current flags first, then append incoming flags if missing
|
|
63
|
+
const mergedFlags = (0, merge_flag_tokens_1.mergeFlagTokens)(curP.flags, incP.flags);
|
|
64
|
+
newParts.push(curP.prefix + (mergedFlags.length > 0 ? ' ' + mergedFlags.join(' ') : ''));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (curPart) {
|
|
69
|
+
newParts.push(curPart);
|
|
70
|
+
}
|
|
71
|
+
if (!curPart && incPart) {
|
|
72
|
+
newParts.push(incPart);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
currentSegments[j] = newParts.join(' && ');
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
newParts = (0, merge_parts_by_prefix_1.mergePartsByPrefix)(currentParts, incomingParts);
|
|
79
|
+
currentSegments[j] = newParts.join(' && ');
|
|
80
|
+
}
|
|
81
|
+
// remove duplicates that were absorbed — compare by prefix to avoid formatting mismatches
|
|
82
|
+
const newPrefixes = new Set(newParts.map(prefix_of_command_1.prefixOfCommand).filter(Boolean));
|
|
83
|
+
currentSegments = currentSegments.filter((s, idx) => {
|
|
84
|
+
if (idx === j) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
const sp = (0, prefix_of_command_1.prefixOfCommand)(s);
|
|
88
|
+
if (sp && newPrefixes.has(sp)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
});
|
|
93
|
+
mergedIntoCurrent = true;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (!mergedIntoCurrent) {
|
|
98
|
+
currentSegments.push(incomingSegment);
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const incomingPartsObject = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incomingSegment);
|
|
103
|
+
let matched = false;
|
|
104
|
+
for (let i = 0; i < currentSegments.length; i++) {
|
|
105
|
+
const currentPartsObject = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(currentSegments[i]);
|
|
106
|
+
if (currentPartsObject.prefix && incomingPartsObject.prefix && currentPartsObject.prefix === incomingPartsObject.prefix) {
|
|
107
|
+
currentSegments[i] = (0, merge_flags_as_string_1.mergeFlagsAsString)(currentSegments[i], incomingPartsObject);
|
|
108
|
+
matched = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (!matched) {
|
|
113
|
+
currentSegments.push(incomingSegment);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Deduplicate top-level semicolon segments by prefix, preserving first occurrence
|
|
117
|
+
const seen = [];
|
|
118
|
+
const deduped = [];
|
|
119
|
+
for (const s of currentSegments) {
|
|
120
|
+
const p = (0, prefix_of_command_1.prefixOfCommand)(s) || s;
|
|
121
|
+
if (!seen.includes(p)) {
|
|
122
|
+
seen.push(p);
|
|
123
|
+
deduped.push(s);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return deduped.join('; ');
|
|
127
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeWithSemicolonMix = mergeWithSemicolonMix;
|
|
4
|
+
const merge_flags_as_string_1 = require("./merge-flags-as-string");
|
|
5
|
+
const split_chain_1 = require("./split-chain");
|
|
6
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
7
|
+
function mergeWithSemicolonMix(current, incoming) {
|
|
8
|
+
if (!(incoming.includes('&&') && current.includes(';'))) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const allSegments = current.split(/;|&&/).map((s) => s.trim()).filter(Boolean);
|
|
12
|
+
const chainPart = current.split(';')[0] || '';
|
|
13
|
+
const chainCount = chainPart ? (0, split_chain_1.splitChain)(chainPart, '&&').length : 0;
|
|
14
|
+
const currentChain = allSegments.slice(0, chainCount);
|
|
15
|
+
const tail = allSegments.slice(chainCount);
|
|
16
|
+
const incomingAnd = (0, split_chain_1.splitChain)(incoming, '&&');
|
|
17
|
+
const chainResult = currentChain.slice();
|
|
18
|
+
const appendedTailIdxs = [];
|
|
19
|
+
for (const incomingSegment of incomingAnd) {
|
|
20
|
+
const incomingParts = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(incomingSegment);
|
|
21
|
+
let matched = false;
|
|
22
|
+
for (const [i, allSegment] of allSegments.entries()) {
|
|
23
|
+
const currentParts = (0, split_prefix_and_flags_1.splitPrefixAndFlags)(allSegment);
|
|
24
|
+
if (currentParts.prefix && incomingParts.prefix && currentParts.prefix === incomingParts.prefix) {
|
|
25
|
+
if (i < chainCount) {
|
|
26
|
+
// merge into existing chain position
|
|
27
|
+
const idx = i;
|
|
28
|
+
chainResult[idx] = (0, merge_flags_as_string_1.mergeFlagsAsString)(chainResult[idx], incomingParts);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
// append matching tail segment into chain if not already appended
|
|
32
|
+
if (!appendedTailIdxs.includes(i)) {
|
|
33
|
+
chainResult.push((0, merge_flags_as_string_1.mergeFlagsAsString)(allSegment, incomingParts));
|
|
34
|
+
appendedTailIdxs.push(i);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
matched = true;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!matched) {
|
|
42
|
+
chainResult.push(incomingSegment);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Build remaining tail excluding appended indices
|
|
46
|
+
const remainingTail = tail.filter((_, idx) => !appendedTailIdxs.includes(chainCount + idx));
|
|
47
|
+
return chainResult.join(' && ') + (remainingTail.length > 0 ? '; ' + remainingTail.join('; ') : '');
|
|
48
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prefixOfCommand = prefixOfCommand;
|
|
4
|
+
const split_prefix_and_flags_1 = require("./split-prefix-and-flags");
|
|
5
|
+
function prefixOfCommand(command) {
|
|
6
|
+
return (0, split_prefix_and_flags_1.splitPrefixAndFlags)(command).prefix;
|
|
7
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.splitPrefixAndFlags = splitPrefixAndFlags;
|
|
4
|
+
function splitPrefixAndFlags(command) {
|
|
5
|
+
const tokens = command.split(/\s+/).filter(Boolean);
|
|
6
|
+
let idx = tokens.findIndex((t) => t.startsWith('-'));
|
|
7
|
+
if (idx === -1) {
|
|
8
|
+
idx = tokens.length;
|
|
9
|
+
}
|
|
10
|
+
const prefix = tokens.slice(0, idx).join(' ');
|
|
11
|
+
const rest = tokens.slice(idx);
|
|
12
|
+
const flags = [];
|
|
13
|
+
for (let i = 0; i < rest.length; i++) {
|
|
14
|
+
const t = rest[i];
|
|
15
|
+
if (t.startsWith('-')) {
|
|
16
|
+
if (i + 1 < rest.length && !rest[i + 1].startsWith('-')) {
|
|
17
|
+
flags.push(`${t} ${rest[i + 1]}`);
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
flags.push(t);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
flags.push(t);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { prefix, flags };
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zokugun/artifact",
|
|
3
3
|
"description": "Boilerplate your project & keep your configurations up to date",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Baptiste Augrain",
|
|
7
7
|
"email": "daiyam@zokugun.org"
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"watch:test": "tsc-watch -p test"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@zokugun/cli-utils": "^0.2.0",
|
|
35
36
|
"@zokugun/configdotts-merge": "^0.2.0",
|
|
36
37
|
"ansi-colors": "^4.1.1",
|
|
37
|
-
"commander": "^9.0.0",
|
|
38
38
|
"dayjs": "^1.11.13",
|
|
39
39
|
"detect-indent": "^6.1.0",
|
|
40
40
|
"editorconfig": "^0.15.3",
|