@qodalis/cli-files 2.0.0-beta.8 → 2.0.0-rc.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/package.json +2 -2
- package/public-api.d.mts +229 -60
- package/public-api.d.ts +229 -60
- package/public-api.js +2115 -902
- package/public-api.js.map +1 -1
- package/public-api.mjs +2110 -904
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +1230 -417
package/umd/index.global.js
CHANGED
|
@@ -8,7 +8,11 @@ var files = (() => {
|
|
|
8
8
|
var __getProtoOf = Object.getPrototypeOf;
|
|
9
9
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
10
|
var __commonJS = (cb, mod) => function __require() {
|
|
11
|
-
|
|
11
|
+
try {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
throw mod = 0, e;
|
|
15
|
+
}
|
|
12
16
|
};
|
|
13
17
|
var __copyProps = (to, from, except, desc) => {
|
|
14
18
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -27,7 +31,7 @@ var files = (() => {
|
|
|
27
31
|
mod
|
|
28
32
|
));
|
|
29
33
|
var require_constants = __commonJS({
|
|
30
|
-
"../../node_modules/.pnpm/semver@7.
|
|
34
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/constants.js"(exports, module2) {
|
|
31
35
|
var SEMVER_SPEC_VERSION = "2.0.0";
|
|
32
36
|
var MAX_LENGTH = 256;
|
|
33
37
|
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || /* istanbul ignore next */
|
|
@@ -56,26 +60,26 @@ var files = (() => {
|
|
|
56
60
|
}
|
|
57
61
|
});
|
|
58
62
|
var require_debug = __commonJS({
|
|
59
|
-
"../../node_modules/.pnpm/semver@7.
|
|
63
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/debug.js"(exports, module2) {
|
|
60
64
|
var debug = typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error("SEMVER", ...args) : () => {
|
|
61
65
|
};
|
|
62
66
|
module2.exports = debug;
|
|
63
67
|
}
|
|
64
68
|
});
|
|
65
69
|
var require_re = __commonJS({
|
|
66
|
-
"../../node_modules/.pnpm/semver@7.
|
|
70
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/re.js"(exports, module2) {
|
|
67
71
|
var {
|
|
68
72
|
MAX_SAFE_COMPONENT_LENGTH,
|
|
69
73
|
MAX_SAFE_BUILD_LENGTH,
|
|
70
74
|
MAX_LENGTH
|
|
71
75
|
} = require_constants();
|
|
72
76
|
var debug = require_debug();
|
|
73
|
-
exports
|
|
74
|
-
var re = exports
|
|
75
|
-
var safeRe = exports
|
|
76
|
-
var src = exports
|
|
77
|
-
var safeSrc = exports
|
|
78
|
-
var t = exports
|
|
77
|
+
exports = module2.exports = {};
|
|
78
|
+
var re = exports.re = [];
|
|
79
|
+
var safeRe = exports.safeRe = [];
|
|
80
|
+
var src = exports.src = [];
|
|
81
|
+
var safeSrc = exports.safeSrc = [];
|
|
82
|
+
var t = exports.t = {};
|
|
79
83
|
var R = 0;
|
|
80
84
|
var LETTERDASHNUMBER = "[a-zA-Z0-9-]";
|
|
81
85
|
var safeRegexReplacements = [
|
|
@@ -128,18 +132,18 @@ var files = (() => {
|
|
|
128
132
|
createToken("COERCERTLFULL", src[t.COERCEFULL], true);
|
|
129
133
|
createToken("LONETILDE", "(?:~>?)");
|
|
130
134
|
createToken("TILDETRIM", `(\\s*)${src[t.LONETILDE]}\\s+`, true);
|
|
131
|
-
exports
|
|
135
|
+
exports.tildeTrimReplace = "$1~";
|
|
132
136
|
createToken("TILDE", `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`);
|
|
133
137
|
createToken("TILDELOOSE", `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
134
138
|
createToken("LONECARET", "(?:\\^)");
|
|
135
139
|
createToken("CARETTRIM", `(\\s*)${src[t.LONECARET]}\\s+`, true);
|
|
136
|
-
exports
|
|
140
|
+
exports.caretTrimReplace = "$1^";
|
|
137
141
|
createToken("CARET", `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`);
|
|
138
142
|
createToken("CARETLOOSE", `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`);
|
|
139
143
|
createToken("COMPARATORLOOSE", `^${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]})$|^$`);
|
|
140
144
|
createToken("COMPARATOR", `^${src[t.GTLT]}\\s*(${src[t.FULLPLAIN]})$|^$`);
|
|
141
145
|
createToken("COMPARATORTRIM", `(\\s*)${src[t.GTLT]}\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true);
|
|
142
|
-
exports
|
|
146
|
+
exports.comparatorTrimReplace = "$1$2$3";
|
|
143
147
|
createToken("HYPHENRANGE", `^\\s*(${src[t.XRANGEPLAIN]})\\s+-\\s+(${src[t.XRANGEPLAIN]})\\s*$`);
|
|
144
148
|
createToken("HYPHENRANGELOOSE", `^\\s*(${src[t.XRANGEPLAINLOOSE]})\\s+-\\s+(${src[t.XRANGEPLAINLOOSE]})\\s*$`);
|
|
145
149
|
createToken("STAR", "(<|>)?=?\\s*\\*");
|
|
@@ -148,7 +152,7 @@ var files = (() => {
|
|
|
148
152
|
}
|
|
149
153
|
});
|
|
150
154
|
var require_parse_options = __commonJS({
|
|
151
|
-
"../../node_modules/.pnpm/semver@7.
|
|
155
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/parse-options.js"(exports, module2) {
|
|
152
156
|
var looseOption = Object.freeze({ loose: true });
|
|
153
157
|
var emptyOpts = Object.freeze({});
|
|
154
158
|
var parseOptions = (options) => {
|
|
@@ -164,7 +168,7 @@ var files = (() => {
|
|
|
164
168
|
}
|
|
165
169
|
});
|
|
166
170
|
var require_identifiers = __commonJS({
|
|
167
|
-
"../../node_modules/.pnpm/semver@7.
|
|
171
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/identifiers.js"(exports, module2) {
|
|
168
172
|
var numeric = /^[0-9]+$/;
|
|
169
173
|
var compareIdentifiers = (a, b) => {
|
|
170
174
|
if (typeof a === "number" && typeof b === "number") {
|
|
@@ -186,12 +190,24 @@ var files = (() => {
|
|
|
186
190
|
}
|
|
187
191
|
});
|
|
188
192
|
var require_semver = __commonJS({
|
|
189
|
-
"../../node_modules/.pnpm/semver@7.
|
|
193
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/classes/semver.js"(exports, module2) {
|
|
190
194
|
var debug = require_debug();
|
|
191
195
|
var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants();
|
|
192
196
|
var { safeRe: re, t } = require_re();
|
|
193
197
|
var parseOptions = require_parse_options();
|
|
194
198
|
var { compareIdentifiers } = require_identifiers();
|
|
199
|
+
var isPrereleaseIdentifier = (prerelease, identifier) => {
|
|
200
|
+
const identifiers = identifier.split(".");
|
|
201
|
+
if (identifiers.length > prerelease.length) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
for (let i = 0; i < identifiers.length; i++) {
|
|
205
|
+
if (compareIdentifiers(prerelease[i], identifiers[i]) !== 0) {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return true;
|
|
210
|
+
};
|
|
195
211
|
var SemVer = class _SemVer {
|
|
196
212
|
constructor(version, options) {
|
|
197
213
|
options = parseOptions(options);
|
|
@@ -438,8 +454,9 @@ var files = (() => {
|
|
|
438
454
|
if (identifierBase === false) {
|
|
439
455
|
prerelease = [identifier];
|
|
440
456
|
}
|
|
441
|
-
if (
|
|
442
|
-
|
|
457
|
+
if (isPrereleaseIdentifier(this.prerelease, identifier)) {
|
|
458
|
+
const prereleaseBase = this.prerelease[identifier.split(".").length];
|
|
459
|
+
if (isNaN(prereleaseBase)) {
|
|
443
460
|
this.prerelease = prerelease;
|
|
444
461
|
}
|
|
445
462
|
} else {
|
|
@@ -462,7 +479,7 @@ var files = (() => {
|
|
|
462
479
|
}
|
|
463
480
|
});
|
|
464
481
|
var require_parse = __commonJS({
|
|
465
|
-
"../../node_modules/.pnpm/semver@7.
|
|
482
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/parse.js"(exports, module2) {
|
|
466
483
|
var SemVer = require_semver();
|
|
467
484
|
var parse = (version, options, throwErrors = false) => {
|
|
468
485
|
if (version instanceof SemVer) {
|
|
@@ -481,7 +498,7 @@ var files = (() => {
|
|
|
481
498
|
}
|
|
482
499
|
});
|
|
483
500
|
var require_valid = __commonJS({
|
|
484
|
-
"../../node_modules/.pnpm/semver@7.
|
|
501
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/valid.js"(exports, module2) {
|
|
485
502
|
var parse = require_parse();
|
|
486
503
|
var valid2 = (version, options) => {
|
|
487
504
|
const v = parse(version, options);
|
|
@@ -491,7 +508,7 @@ var files = (() => {
|
|
|
491
508
|
}
|
|
492
509
|
});
|
|
493
510
|
var require_clean = __commonJS({
|
|
494
|
-
"../../node_modules/.pnpm/semver@7.
|
|
511
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/clean.js"(exports, module2) {
|
|
495
512
|
var parse = require_parse();
|
|
496
513
|
var clean = (version, options) => {
|
|
497
514
|
const s = parse(version.trim().replace(/^[=v]+/, ""), options);
|
|
@@ -501,7 +518,7 @@ var files = (() => {
|
|
|
501
518
|
}
|
|
502
519
|
});
|
|
503
520
|
var require_inc = __commonJS({
|
|
504
|
-
"../../node_modules/.pnpm/semver@7.
|
|
521
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/inc.js"(exports, module2) {
|
|
505
522
|
var SemVer = require_semver();
|
|
506
523
|
var inc = (version, release, options, identifier, identifierBase) => {
|
|
507
524
|
if (typeof options === "string") {
|
|
@@ -522,7 +539,7 @@ var files = (() => {
|
|
|
522
539
|
}
|
|
523
540
|
});
|
|
524
541
|
var require_diff = __commonJS({
|
|
525
|
-
"../../node_modules/.pnpm/semver@7.
|
|
542
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/diff.js"(exports, module2) {
|
|
526
543
|
var parse = require_parse();
|
|
527
544
|
var diff = (version1, version2) => {
|
|
528
545
|
const v1 = parse(version1, null, true);
|
|
@@ -563,28 +580,28 @@ var files = (() => {
|
|
|
563
580
|
}
|
|
564
581
|
});
|
|
565
582
|
var require_major = __commonJS({
|
|
566
|
-
"../../node_modules/.pnpm/semver@7.
|
|
583
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/major.js"(exports, module2) {
|
|
567
584
|
var SemVer = require_semver();
|
|
568
585
|
var major = (a, loose) => new SemVer(a, loose).major;
|
|
569
586
|
module2.exports = major;
|
|
570
587
|
}
|
|
571
588
|
});
|
|
572
589
|
var require_minor = __commonJS({
|
|
573
|
-
"../../node_modules/.pnpm/semver@7.
|
|
590
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/minor.js"(exports, module2) {
|
|
574
591
|
var SemVer = require_semver();
|
|
575
592
|
var minor = (a, loose) => new SemVer(a, loose).minor;
|
|
576
593
|
module2.exports = minor;
|
|
577
594
|
}
|
|
578
595
|
});
|
|
579
596
|
var require_patch = __commonJS({
|
|
580
|
-
"../../node_modules/.pnpm/semver@7.
|
|
597
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/patch.js"(exports, module2) {
|
|
581
598
|
var SemVer = require_semver();
|
|
582
599
|
var patch = (a, loose) => new SemVer(a, loose).patch;
|
|
583
600
|
module2.exports = patch;
|
|
584
601
|
}
|
|
585
602
|
});
|
|
586
603
|
var require_prerelease = __commonJS({
|
|
587
|
-
"../../node_modules/.pnpm/semver@7.
|
|
604
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/prerelease.js"(exports, module2) {
|
|
588
605
|
var parse = require_parse();
|
|
589
606
|
var prerelease = (version, options) => {
|
|
590
607
|
const parsed = parse(version, options);
|
|
@@ -594,28 +611,28 @@ var files = (() => {
|
|
|
594
611
|
}
|
|
595
612
|
});
|
|
596
613
|
var require_compare = __commonJS({
|
|
597
|
-
"../../node_modules/.pnpm/semver@7.
|
|
614
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/compare.js"(exports, module2) {
|
|
598
615
|
var SemVer = require_semver();
|
|
599
616
|
var compare2 = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose));
|
|
600
617
|
module2.exports = compare2;
|
|
601
618
|
}
|
|
602
619
|
});
|
|
603
620
|
var require_rcompare = __commonJS({
|
|
604
|
-
"../../node_modules/.pnpm/semver@7.
|
|
621
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/rcompare.js"(exports, module2) {
|
|
605
622
|
var compare2 = require_compare();
|
|
606
623
|
var rcompare = (a, b, loose) => compare2(b, a, loose);
|
|
607
624
|
module2.exports = rcompare;
|
|
608
625
|
}
|
|
609
626
|
});
|
|
610
627
|
var require_compare_loose = __commonJS({
|
|
611
|
-
"../../node_modules/.pnpm/semver@7.
|
|
628
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/compare-loose.js"(exports, module2) {
|
|
612
629
|
var compare2 = require_compare();
|
|
613
630
|
var compareLoose = (a, b) => compare2(a, b, true);
|
|
614
631
|
module2.exports = compareLoose;
|
|
615
632
|
}
|
|
616
633
|
});
|
|
617
634
|
var require_compare_build = __commonJS({
|
|
618
|
-
"../../node_modules/.pnpm/semver@7.
|
|
635
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/compare-build.js"(exports, module2) {
|
|
619
636
|
var SemVer = require_semver();
|
|
620
637
|
var compareBuild = (a, b, loose) => {
|
|
621
638
|
const versionA = new SemVer(a, loose);
|
|
@@ -626,63 +643,63 @@ var files = (() => {
|
|
|
626
643
|
}
|
|
627
644
|
});
|
|
628
645
|
var require_sort = __commonJS({
|
|
629
|
-
"../../node_modules/.pnpm/semver@7.
|
|
646
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/sort.js"(exports, module2) {
|
|
630
647
|
var compareBuild = require_compare_build();
|
|
631
|
-
var sort = (
|
|
648
|
+
var sort = (list2, loose) => list2.sort((a, b) => compareBuild(a, b, loose));
|
|
632
649
|
module2.exports = sort;
|
|
633
650
|
}
|
|
634
651
|
});
|
|
635
652
|
var require_rsort = __commonJS({
|
|
636
|
-
"../../node_modules/.pnpm/semver@7.
|
|
653
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/rsort.js"(exports, module2) {
|
|
637
654
|
var compareBuild = require_compare_build();
|
|
638
|
-
var rsort = (
|
|
655
|
+
var rsort = (list2, loose) => list2.sort((a, b) => compareBuild(b, a, loose));
|
|
639
656
|
module2.exports = rsort;
|
|
640
657
|
}
|
|
641
658
|
});
|
|
642
659
|
var require_gt = __commonJS({
|
|
643
|
-
"../../node_modules/.pnpm/semver@7.
|
|
660
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/gt.js"(exports, module2) {
|
|
644
661
|
var compare2 = require_compare();
|
|
645
662
|
var gt = (a, b, loose) => compare2(a, b, loose) > 0;
|
|
646
663
|
module2.exports = gt;
|
|
647
664
|
}
|
|
648
665
|
});
|
|
649
666
|
var require_lt = __commonJS({
|
|
650
|
-
"../../node_modules/.pnpm/semver@7.
|
|
667
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/lt.js"(exports, module2) {
|
|
651
668
|
var compare2 = require_compare();
|
|
652
669
|
var lt = (a, b, loose) => compare2(a, b, loose) < 0;
|
|
653
670
|
module2.exports = lt;
|
|
654
671
|
}
|
|
655
672
|
});
|
|
656
673
|
var require_eq = __commonJS({
|
|
657
|
-
"../../node_modules/.pnpm/semver@7.
|
|
674
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/eq.js"(exports, module2) {
|
|
658
675
|
var compare2 = require_compare();
|
|
659
676
|
var eq = (a, b, loose) => compare2(a, b, loose) === 0;
|
|
660
677
|
module2.exports = eq;
|
|
661
678
|
}
|
|
662
679
|
});
|
|
663
680
|
var require_neq = __commonJS({
|
|
664
|
-
"../../node_modules/.pnpm/semver@7.
|
|
681
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/neq.js"(exports, module2) {
|
|
665
682
|
var compare2 = require_compare();
|
|
666
683
|
var neq = (a, b, loose) => compare2(a, b, loose) !== 0;
|
|
667
684
|
module2.exports = neq;
|
|
668
685
|
}
|
|
669
686
|
});
|
|
670
687
|
var require_gte = __commonJS({
|
|
671
|
-
"../../node_modules/.pnpm/semver@7.
|
|
688
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/gte.js"(exports, module2) {
|
|
672
689
|
var compare2 = require_compare();
|
|
673
690
|
var gte2 = (a, b, loose) => compare2(a, b, loose) >= 0;
|
|
674
691
|
module2.exports = gte2;
|
|
675
692
|
}
|
|
676
693
|
});
|
|
677
694
|
var require_lte = __commonJS({
|
|
678
|
-
"../../node_modules/.pnpm/semver@7.
|
|
695
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/lte.js"(exports, module2) {
|
|
679
696
|
var compare2 = require_compare();
|
|
680
697
|
var lte = (a, b, loose) => compare2(a, b, loose) <= 0;
|
|
681
698
|
module2.exports = lte;
|
|
682
699
|
}
|
|
683
700
|
});
|
|
684
701
|
var require_cmp = __commonJS({
|
|
685
|
-
"../../node_modules/.pnpm/semver@7.
|
|
702
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/cmp.js"(exports, module2) {
|
|
686
703
|
var eq = require_eq();
|
|
687
704
|
var neq = require_neq();
|
|
688
705
|
var gt = require_gt();
|
|
@@ -729,7 +746,7 @@ var files = (() => {
|
|
|
729
746
|
}
|
|
730
747
|
});
|
|
731
748
|
var require_coerce = __commonJS({
|
|
732
|
-
"../../node_modules/.pnpm/semver@7.
|
|
749
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/coerce.js"(exports, module2) {
|
|
733
750
|
var SemVer = require_semver();
|
|
734
751
|
var parse = require_parse();
|
|
735
752
|
var { safeRe: re, t } = require_re();
|
|
@@ -771,8 +788,46 @@ var files = (() => {
|
|
|
771
788
|
module2.exports = coerce2;
|
|
772
789
|
}
|
|
773
790
|
});
|
|
791
|
+
var require_truncate = __commonJS({
|
|
792
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/truncate.js"(exports, module2) {
|
|
793
|
+
var parse = require_parse();
|
|
794
|
+
var constants2 = require_constants();
|
|
795
|
+
var SemVer = require_semver();
|
|
796
|
+
var truncate = (version, truncation, options) => {
|
|
797
|
+
if (!constants2.RELEASE_TYPES.includes(truncation)) {
|
|
798
|
+
return null;
|
|
799
|
+
}
|
|
800
|
+
const clonedVersion = cloneInputVersion(version, options);
|
|
801
|
+
return clonedVersion && doTruncation(clonedVersion, truncation);
|
|
802
|
+
};
|
|
803
|
+
var cloneInputVersion = (version, options) => {
|
|
804
|
+
const versionStringToParse = version instanceof SemVer ? version.version : version;
|
|
805
|
+
return parse(versionStringToParse, options);
|
|
806
|
+
};
|
|
807
|
+
var doTruncation = (version, truncation) => {
|
|
808
|
+
if (isPrerelease(truncation)) {
|
|
809
|
+
return version.version;
|
|
810
|
+
}
|
|
811
|
+
version.prerelease = [];
|
|
812
|
+
switch (truncation) {
|
|
813
|
+
case "major":
|
|
814
|
+
version.minor = 0;
|
|
815
|
+
version.patch = 0;
|
|
816
|
+
break;
|
|
817
|
+
case "minor":
|
|
818
|
+
version.patch = 0;
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
return version.format();
|
|
822
|
+
};
|
|
823
|
+
var isPrerelease = (type) => {
|
|
824
|
+
return type.startsWith("pre");
|
|
825
|
+
};
|
|
826
|
+
module2.exports = truncate;
|
|
827
|
+
}
|
|
828
|
+
});
|
|
774
829
|
var require_lrucache = __commonJS({
|
|
775
|
-
"../../node_modules/.pnpm/semver@7.
|
|
830
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/internal/lrucache.js"(exports, module2) {
|
|
776
831
|
var LRUCache = class {
|
|
777
832
|
constructor() {
|
|
778
833
|
this.max = 1e3;
|
|
@@ -807,7 +862,7 @@ var files = (() => {
|
|
|
807
862
|
}
|
|
808
863
|
});
|
|
809
864
|
var require_range = __commonJS({
|
|
810
|
-
"../../node_modules/.pnpm/semver@7.
|
|
865
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/classes/range.js"(exports, module2) {
|
|
811
866
|
var SPACE_CHARACTERS = /\s+/g;
|
|
812
867
|
var Range = class _Range {
|
|
813
868
|
constructor(range, options) {
|
|
@@ -874,6 +929,7 @@ var files = (() => {
|
|
|
874
929
|
return this.range;
|
|
875
930
|
}
|
|
876
931
|
parseRange(range) {
|
|
932
|
+
range = range.replace(BUILDSTRIPRE, "");
|
|
877
933
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
878
934
|
const memoKey = memoOpts + ":" + range;
|
|
879
935
|
const cached = cache.get(memoKey);
|
|
@@ -956,12 +1012,14 @@ var files = (() => {
|
|
|
956
1012
|
var SemVer = require_semver();
|
|
957
1013
|
var {
|
|
958
1014
|
safeRe: re,
|
|
1015
|
+
src,
|
|
959
1016
|
t,
|
|
960
1017
|
comparatorTrimReplace,
|
|
961
1018
|
tildeTrimReplace,
|
|
962
1019
|
caretTrimReplace
|
|
963
1020
|
} = require_re();
|
|
964
1021
|
var { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require_constants();
|
|
1022
|
+
var BUILDSTRIPRE = new RegExp(src[t.BUILD], "g");
|
|
965
1023
|
var isNullSet = (c) => c.value === "<0.0.0-0";
|
|
966
1024
|
var isAny = (c) => c.value === "";
|
|
967
1025
|
var isSatisfiable = (comparators, options) => {
|
|
@@ -990,20 +1048,22 @@ var files = (() => {
|
|
|
990
1048
|
return comp;
|
|
991
1049
|
};
|
|
992
1050
|
var isX = (id) => !id || id.toLowerCase() === "x" || id === "*";
|
|
1051
|
+
var invalidXRangeOrder = (M, m, p) => isX(M) && !isX(m) || isX(m) && p && !isX(p);
|
|
993
1052
|
var replaceTildes = (comp, options) => {
|
|
994
1053
|
return comp.trim().split(/\s+/).map((c) => replaceTilde(c, options)).join(" ");
|
|
995
1054
|
};
|
|
996
1055
|
var replaceTilde = (comp, options) => {
|
|
997
1056
|
const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];
|
|
1057
|
+
const z = options.includePrerelease ? "-0" : "";
|
|
998
1058
|
return comp.replace(r, (_, M, m, p, pr) => {
|
|
999
1059
|
debug("tilde", comp, _, M, m, p, pr);
|
|
1000
1060
|
let ret;
|
|
1001
1061
|
if (isX(M)) {
|
|
1002
1062
|
ret = "";
|
|
1003
1063
|
} else if (isX(m)) {
|
|
1004
|
-
ret = `>=${M}.0.0 <${+M + 1}.0.0-0`;
|
|
1064
|
+
ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`;
|
|
1005
1065
|
} else if (isX(p)) {
|
|
1006
|
-
ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`;
|
|
1066
|
+
ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`;
|
|
1007
1067
|
} else if (pr) {
|
|
1008
1068
|
debug("replaceTilde pr", pr);
|
|
1009
1069
|
ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;
|
|
@@ -1049,9 +1109,9 @@ var files = (() => {
|
|
|
1049
1109
|
debug("no pr");
|
|
1050
1110
|
if (M === "0") {
|
|
1051
1111
|
if (m === "0") {
|
|
1052
|
-
ret = `>=${M}.${m}.${p}
|
|
1112
|
+
ret = `>=${M}.${m}.${p} <${M}.${m}.${+p + 1}-0`;
|
|
1053
1113
|
} else {
|
|
1054
|
-
ret = `>=${M}.${m}.${p}
|
|
1114
|
+
ret = `>=${M}.${m}.${p} <${M}.${+m + 1}.0-0`;
|
|
1055
1115
|
}
|
|
1056
1116
|
} else {
|
|
1057
1117
|
ret = `>=${M}.${m}.${p} <${+M + 1}.0.0-0`;
|
|
@@ -1070,6 +1130,9 @@ var files = (() => {
|
|
|
1070
1130
|
const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE];
|
|
1071
1131
|
return comp.replace(r, (ret, gtlt, M, m, p, pr) => {
|
|
1072
1132
|
debug("xRange", comp, ret, gtlt, M, m, p, pr);
|
|
1133
|
+
if (invalidXRangeOrder(M, m, p)) {
|
|
1134
|
+
return comp;
|
|
1135
|
+
}
|
|
1073
1136
|
const xM = isX(M);
|
|
1074
1137
|
const xm = xM || isX(m);
|
|
1075
1138
|
const xp = xm || isX(p);
|
|
@@ -1181,7 +1244,7 @@ var files = (() => {
|
|
|
1181
1244
|
}
|
|
1182
1245
|
});
|
|
1183
1246
|
var require_comparator = __commonJS({
|
|
1184
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1247
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/classes/comparator.js"(exports, module2) {
|
|
1185
1248
|
var ANY = /* @__PURE__ */ Symbol("SemVer ANY");
|
|
1186
1249
|
var Comparator = class _Comparator {
|
|
1187
1250
|
static get ANY() {
|
|
@@ -1291,7 +1354,7 @@ var files = (() => {
|
|
|
1291
1354
|
}
|
|
1292
1355
|
});
|
|
1293
1356
|
var require_satisfies = __commonJS({
|
|
1294
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1357
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/functions/satisfies.js"(exports, module2) {
|
|
1295
1358
|
var Range = require_range();
|
|
1296
1359
|
var satisfies2 = (version, range, options) => {
|
|
1297
1360
|
try {
|
|
@@ -1305,14 +1368,14 @@ var files = (() => {
|
|
|
1305
1368
|
}
|
|
1306
1369
|
});
|
|
1307
1370
|
var require_to_comparators = __commonJS({
|
|
1308
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1371
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/to-comparators.js"(exports, module2) {
|
|
1309
1372
|
var Range = require_range();
|
|
1310
1373
|
var toComparators = (range, options) => new Range(range, options).set.map((comp) => comp.map((c) => c.value).join(" ").trim().split(" "));
|
|
1311
1374
|
module2.exports = toComparators;
|
|
1312
1375
|
}
|
|
1313
1376
|
});
|
|
1314
1377
|
var require_max_satisfying = __commonJS({
|
|
1315
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1378
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/max-satisfying.js"(exports, module2) {
|
|
1316
1379
|
var SemVer = require_semver();
|
|
1317
1380
|
var Range = require_range();
|
|
1318
1381
|
var maxSatisfying = (versions, range, options) => {
|
|
@@ -1338,7 +1401,7 @@ var files = (() => {
|
|
|
1338
1401
|
}
|
|
1339
1402
|
});
|
|
1340
1403
|
var require_min_satisfying = __commonJS({
|
|
1341
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1404
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/min-satisfying.js"(exports, module2) {
|
|
1342
1405
|
var SemVer = require_semver();
|
|
1343
1406
|
var Range = require_range();
|
|
1344
1407
|
var minSatisfying = (versions, range, options) => {
|
|
@@ -1364,7 +1427,7 @@ var files = (() => {
|
|
|
1364
1427
|
}
|
|
1365
1428
|
});
|
|
1366
1429
|
var require_min_version = __commonJS({
|
|
1367
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1430
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/min-version.js"(exports, module2) {
|
|
1368
1431
|
var SemVer = require_semver();
|
|
1369
1432
|
var Range = require_range();
|
|
1370
1433
|
var gt = require_gt();
|
|
@@ -1420,7 +1483,7 @@ var files = (() => {
|
|
|
1420
1483
|
}
|
|
1421
1484
|
});
|
|
1422
1485
|
var require_valid2 = __commonJS({
|
|
1423
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1486
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/valid.js"(exports, module2) {
|
|
1424
1487
|
var Range = require_range();
|
|
1425
1488
|
var validRange = (range, options) => {
|
|
1426
1489
|
try {
|
|
@@ -1433,7 +1496,7 @@ var files = (() => {
|
|
|
1433
1496
|
}
|
|
1434
1497
|
});
|
|
1435
1498
|
var require_outside = __commonJS({
|
|
1436
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1499
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/outside.js"(exports, module2) {
|
|
1437
1500
|
var SemVer = require_semver();
|
|
1438
1501
|
var Comparator = require_comparator();
|
|
1439
1502
|
var { ANY } = Comparator;
|
|
@@ -1499,21 +1562,21 @@ var files = (() => {
|
|
|
1499
1562
|
}
|
|
1500
1563
|
});
|
|
1501
1564
|
var require_gtr = __commonJS({
|
|
1502
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1565
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/gtr.js"(exports, module2) {
|
|
1503
1566
|
var outside = require_outside();
|
|
1504
1567
|
var gtr = (version, range, options) => outside(version, range, ">", options);
|
|
1505
1568
|
module2.exports = gtr;
|
|
1506
1569
|
}
|
|
1507
1570
|
});
|
|
1508
1571
|
var require_ltr = __commonJS({
|
|
1509
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1572
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/ltr.js"(exports, module2) {
|
|
1510
1573
|
var outside = require_outside();
|
|
1511
1574
|
var ltr = (version, range, options) => outside(version, range, "<", options);
|
|
1512
1575
|
module2.exports = ltr;
|
|
1513
1576
|
}
|
|
1514
1577
|
});
|
|
1515
1578
|
var require_intersects = __commonJS({
|
|
1516
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1579
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/intersects.js"(exports, module2) {
|
|
1517
1580
|
var Range = require_range();
|
|
1518
1581
|
var intersects = (r1, r2, options) => {
|
|
1519
1582
|
r1 = new Range(r1, options);
|
|
@@ -1524,7 +1587,7 @@ var files = (() => {
|
|
|
1524
1587
|
}
|
|
1525
1588
|
});
|
|
1526
1589
|
var require_simplify = __commonJS({
|
|
1527
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1590
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/simplify.js"(exports, module2) {
|
|
1528
1591
|
var satisfies2 = require_satisfies();
|
|
1529
1592
|
var compare2 = require_compare();
|
|
1530
1593
|
module2.exports = (versions, range, options) => {
|
|
@@ -1571,7 +1634,7 @@ var files = (() => {
|
|
|
1571
1634
|
}
|
|
1572
1635
|
});
|
|
1573
1636
|
var require_subset = __commonJS({
|
|
1574
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1637
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/ranges/subset.js"(exports, module2) {
|
|
1575
1638
|
var Range = require_range();
|
|
1576
1639
|
var Comparator = require_comparator();
|
|
1577
1640
|
var { ANY } = Comparator;
|
|
@@ -1678,7 +1741,7 @@ var files = (() => {
|
|
|
1678
1741
|
if (higher === c && higher !== gt) {
|
|
1679
1742
|
return false;
|
|
1680
1743
|
}
|
|
1681
|
-
} else if (gt.operator === ">=" && !
|
|
1744
|
+
} else if (gt.operator === ">=" && !c.test(gt.semver)) {
|
|
1682
1745
|
return false;
|
|
1683
1746
|
}
|
|
1684
1747
|
}
|
|
@@ -1693,7 +1756,7 @@ var files = (() => {
|
|
|
1693
1756
|
if (lower === c && lower !== lt) {
|
|
1694
1757
|
return false;
|
|
1695
1758
|
}
|
|
1696
|
-
} else if (lt.operator === "<=" && !
|
|
1759
|
+
} else if (lt.operator === "<=" && !c.test(lt.semver)) {
|
|
1697
1760
|
return false;
|
|
1698
1761
|
}
|
|
1699
1762
|
}
|
|
@@ -1730,7 +1793,7 @@ var files = (() => {
|
|
|
1730
1793
|
}
|
|
1731
1794
|
});
|
|
1732
1795
|
var require_semver2 = __commonJS({
|
|
1733
|
-
"../../node_modules/.pnpm/semver@7.
|
|
1796
|
+
"../../node_modules/.pnpm/semver@7.8.5/node_modules/semver/index.js"(exports, module2) {
|
|
1734
1797
|
var internalRe = require_re();
|
|
1735
1798
|
var constants2 = require_constants();
|
|
1736
1799
|
var SemVer = require_semver();
|
|
@@ -1758,6 +1821,7 @@ var files = (() => {
|
|
|
1758
1821
|
var lte = require_lte();
|
|
1759
1822
|
var cmp = require_cmp();
|
|
1760
1823
|
var coerce2 = require_coerce();
|
|
1824
|
+
var truncate = require_truncate();
|
|
1761
1825
|
var Comparator = require_comparator();
|
|
1762
1826
|
var Range = require_range();
|
|
1763
1827
|
var satisfies2 = require_satisfies();
|
|
@@ -1796,6 +1860,7 @@ var files = (() => {
|
|
|
1796
1860
|
lte,
|
|
1797
1861
|
cmp,
|
|
1798
1862
|
coerce: coerce2,
|
|
1863
|
+
truncate,
|
|
1799
1864
|
Comparator,
|
|
1800
1865
|
Range,
|
|
1801
1866
|
satisfies: satisfies2,
|
|
@@ -1833,15 +1898,100 @@ var files = (() => {
|
|
|
1833
1898
|
CliForegroundColor2["Reset"] = "\x1B[0m";
|
|
1834
1899
|
return CliForegroundColor2;
|
|
1835
1900
|
})(CliForegroundColor || {});
|
|
1836
|
-
|
|
1901
|
+
function createCliToken(name) {
|
|
1902
|
+
return name;
|
|
1903
|
+
}
|
|
1904
|
+
var ICliUserSessionService_TOKEN = createCliToken("cli-user-session-service");
|
|
1905
|
+
var ICliUsersStoreService_TOKEN = createCliToken("cli-users-store-service");
|
|
1906
|
+
var ICliGroupsStoreService_TOKEN = createCliToken("cli-groups-store-service");
|
|
1907
|
+
var ICliAuthService_TOKEN = createCliToken("cli-auth-service");
|
|
1908
|
+
var ICliCompletionProvider_TOKEN = createCliToken("cli-completion-provider");
|
|
1909
|
+
var ICliDragDropService_TOKEN = createCliToken("cli-drag-drop-service");
|
|
1910
|
+
var ICliFileTransferService_TOKEN = createCliToken("cli-file-transfer-service");
|
|
1911
|
+
var ICliTranslationService_TOKEN = createCliToken("cli-translation-service");
|
|
1912
|
+
var ICliPermissionService_TOKEN = createCliToken("cli-permission-service");
|
|
1913
|
+
var ICliFilePickerProvider_TOKEN = createCliToken("cli-file-picker-provider");
|
|
1914
|
+
var ICliHttpClient_TOKEN = createCliToken("cli-http-client");
|
|
1915
|
+
var ICliUserEventService_TOKEN = createCliToken("cli-user-event-service");
|
|
1916
|
+
var ICliAuditService_TOKEN = createCliToken("cli-audit-service");
|
|
1917
|
+
var ICliAuthorizationService_TOKEN = createCliToken("cli-authorization-service");
|
|
1918
|
+
var ICliPermissionRegistry_TOKEN = createCliToken("cli-permission-registry");
|
|
1919
|
+
var ICliSessionsService_TOKEN = createCliToken("cli-sessions-service");
|
|
1920
|
+
var ICliKeyValueStore_TOKEN = createCliToken("cli-key-value-store");
|
|
1921
|
+
var ICliServerAuthTokenProvider_TOKEN = createCliToken("cli-server-auth-token-provider");
|
|
1922
|
+
var ICliServerAuthService_TOKEN = createCliToken("cli-server-auth-service");
|
|
1923
|
+
var ICliServerManager_TOKEN = createCliToken("cli-server-manager");
|
|
1924
|
+
function resolveHeaders(provider) {
|
|
1925
|
+
if (!provider) return {};
|
|
1926
|
+
return typeof provider === "function" ? provider() : provider;
|
|
1927
|
+
}
|
|
1928
|
+
var ICliCommandGuard_TOKEN = createCliToken("cli-command-guard");
|
|
1929
|
+
var CliAccessDeniedError = class _CliAccessDeniedError extends Error {
|
|
1930
|
+
constructor(message = "permission denied") {
|
|
1931
|
+
super(message);
|
|
1932
|
+
this.code = "EACCES";
|
|
1933
|
+
this.name = "CliAccessDeniedError";
|
|
1934
|
+
Object.setPrototypeOf(this, _CliAccessDeniedError.prototype);
|
|
1935
|
+
}
|
|
1936
|
+
};
|
|
1937
|
+
function isCliAccessDeniedError(error) {
|
|
1938
|
+
return error instanceof CliAccessDeniedError || !!error && typeof error === "object" && error.name === "CliAccessDeniedError";
|
|
1939
|
+
}
|
|
1940
|
+
var ICliEventBus_TOKEN = createCliToken("cli-event-bus");
|
|
1837
1941
|
var DefaultLibraryAuthor = {
|
|
1838
1942
|
name: "Nicolae Lupei",
|
|
1839
1943
|
email: "nicolae.lupei@qodalis.com"
|
|
1840
1944
|
};
|
|
1945
|
+
function splitShellWords(text) {
|
|
1946
|
+
const words = [];
|
|
1947
|
+
let current = "";
|
|
1948
|
+
let inWord = false;
|
|
1949
|
+
for (let i = 0; i < text.length; i++) {
|
|
1950
|
+
const ch = text[i];
|
|
1951
|
+
if (ch === "\\" && i + 1 < text.length) {
|
|
1952
|
+
current += text[++i];
|
|
1953
|
+
inWord = true;
|
|
1954
|
+
} else if (ch === "'" && text.indexOf("'", i + 1) !== -1) {
|
|
1955
|
+
const end = text.indexOf("'", i + 1);
|
|
1956
|
+
current += text.slice(i + 1, end);
|
|
1957
|
+
inWord = true;
|
|
1958
|
+
i = end;
|
|
1959
|
+
} else if (ch === '"' && closingDoubleQuote(text, i) !== -1) {
|
|
1960
|
+
const end = closingDoubleQuote(text, i);
|
|
1961
|
+
current += unescapeDoubleQuoted(text.slice(i + 1, end));
|
|
1962
|
+
inWord = true;
|
|
1963
|
+
i = end;
|
|
1964
|
+
} else if (/\s/.test(ch)) {
|
|
1965
|
+
if (inWord) words.push(current);
|
|
1966
|
+
current = "";
|
|
1967
|
+
inWord = false;
|
|
1968
|
+
} else {
|
|
1969
|
+
current += ch;
|
|
1970
|
+
inWord = true;
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
if (inWord) words.push(current);
|
|
1974
|
+
return words;
|
|
1975
|
+
}
|
|
1976
|
+
function joinShellWords(text) {
|
|
1977
|
+
return splitShellWords(text).join(" ");
|
|
1978
|
+
}
|
|
1979
|
+
function closingDoubleQuote(text, start) {
|
|
1980
|
+
for (let i = start + 1; i < text.length; i++) {
|
|
1981
|
+
if (text[i] === "\\") i++;
|
|
1982
|
+
else if (text[i] === '"') return i;
|
|
1983
|
+
}
|
|
1984
|
+
return -1;
|
|
1985
|
+
}
|
|
1986
|
+
function unescapeDoubleQuoted(text) {
|
|
1987
|
+
return text.replace(/\\(["\\$`])/g, "$1");
|
|
1988
|
+
}
|
|
1841
1989
|
var semver = __toESM(require_semver2());
|
|
1990
|
+
var API_VERSION = 2;
|
|
1991
|
+
var VERSIONS_ENDPOINT = "/api/qcli/versions";
|
|
1842
1992
|
var ServerVersionNegotiator = class {
|
|
1843
1993
|
static {
|
|
1844
|
-
this.CLIENT_SUPPORTED_VERSIONS = [
|
|
1994
|
+
this.CLIENT_SUPPORTED_VERSIONS = [API_VERSION];
|
|
1845
1995
|
}
|
|
1846
1996
|
/**
|
|
1847
1997
|
* Given a server's version info, pick the highest mutually compatible version.
|
|
@@ -1858,9 +2008,18 @@ var files = (() => {
|
|
|
1858
2008
|
* Returns the negotiated API version and the base path for all subsequent calls,
|
|
1859
2009
|
* or null if the server is unreachable or incompatible.
|
|
1860
2010
|
*/
|
|
1861
|
-
static async discover(baseUrl) {
|
|
2011
|
+
static async discover(baseUrl, headers, options) {
|
|
2012
|
+
let response;
|
|
2013
|
+
try {
|
|
2014
|
+
const resolved = resolveHeaders(headers);
|
|
2015
|
+
response = await fetch(`${baseUrl}${VERSIONS_ENDPOINT}`, {
|
|
2016
|
+
headers: Object.keys(resolved).length > 0 ? resolved : void 0
|
|
2017
|
+
});
|
|
2018
|
+
} catch (e) {
|
|
2019
|
+
if (options?.rethrowNetworkErrors) throw e;
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
1862
2022
|
try {
|
|
1863
|
-
const response = await fetch(`${baseUrl}/api/qcli/versions`);
|
|
1864
2023
|
if (!response.ok) return null;
|
|
1865
2024
|
const info = await response.json();
|
|
1866
2025
|
const version = this.negotiate(info);
|
|
@@ -1874,6 +2033,60 @@ var files = (() => {
|
|
|
1874
2033
|
}
|
|
1875
2034
|
}
|
|
1876
2035
|
};
|
|
2036
|
+
function writeColumns(context, rows, formatLeft, formatRight) {
|
|
2037
|
+
const width = Math.max(...rows.map(([left]) => left.length)) + 2;
|
|
2038
|
+
for (const [left, right] of rows) {
|
|
2039
|
+
context.writer.writeln(
|
|
2040
|
+
` ${formatLeft(left.padEnd(width))}${formatRight(right)}`
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
function writeUsage(context, rows) {
|
|
2045
|
+
const { writer, translator } = context;
|
|
2046
|
+
writer.writeln(`\u{1F4CB} ${translator.t("cli.common.usage", "Usage:")}`);
|
|
2047
|
+
writeColumns(
|
|
2048
|
+
context,
|
|
2049
|
+
rows,
|
|
2050
|
+
(cmd) => writer.wrapInColor(
|
|
2051
|
+
cmd,
|
|
2052
|
+
"\x1B[36m"
|
|
2053
|
+
/* Cyan */
|
|
2054
|
+
),
|
|
2055
|
+
(text) => text
|
|
2056
|
+
);
|
|
2057
|
+
}
|
|
2058
|
+
function writeExamples(context, rows) {
|
|
2059
|
+
const { writer, translator } = context;
|
|
2060
|
+
writer.writeln(`\u{1F4DD} ${translator.t("cli.common.examples", "Examples:")}`);
|
|
2061
|
+
writeColumns(
|
|
2062
|
+
context,
|
|
2063
|
+
rows,
|
|
2064
|
+
(cmd) => cmd,
|
|
2065
|
+
(comment) => writer.wrapInColor(
|
|
2066
|
+
`# ${comment}`,
|
|
2067
|
+
"\x1B[32m"
|
|
2068
|
+
/* Green */
|
|
2069
|
+
)
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
function writeWrapped(context, text, indent = 0) {
|
|
2073
|
+
const cols = context.terminal?.cols ?? 80;
|
|
2074
|
+
const width = Math.max(20, Math.min(cols - 1, 100) - indent);
|
|
2075
|
+
const pad = " ".repeat(indent);
|
|
2076
|
+
let line = "";
|
|
2077
|
+
for (const word of text.split(/\s+/).filter(Boolean)) {
|
|
2078
|
+
if (line && visibleLength2(line) + 1 + visibleLength2(word) > width) {
|
|
2079
|
+
context.writer.writeln(pad + line);
|
|
2080
|
+
line = word;
|
|
2081
|
+
} else {
|
|
2082
|
+
line = line ? `${line} ${word}` : word;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
if (line) context.writer.writeln(pad + line);
|
|
2086
|
+
}
|
|
2087
|
+
function visibleLength2(text) {
|
|
2088
|
+
return text.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
2089
|
+
}
|
|
1877
2090
|
var bootCliModule = async (module2) => {
|
|
1878
2091
|
if (typeof window !== "undefined" && window.__cliModuleRegistry) {
|
|
1879
2092
|
await window.__cliModuleRegistry.register(module2);
|
|
@@ -2692,11 +2905,11 @@ var files = (() => {
|
|
|
2692
2905
|
};
|
|
2693
2906
|
|
|
2694
2907
|
// src/lib/version.ts
|
|
2695
|
-
var LIBRARY_VERSION = "2.0.0-
|
|
2696
|
-
var
|
|
2908
|
+
var LIBRARY_VERSION = "2.0.0-rc.1";
|
|
2909
|
+
var API_VERSION2 = 2;
|
|
2697
2910
|
|
|
2698
2911
|
// src/lib/interfaces/i-file-system-service.ts
|
|
2699
|
-
var IFileSystemService_TOKEN = "cli-file-system-service";
|
|
2912
|
+
var IFileSystemService_TOKEN = createCliToken("cli-file-system-service");
|
|
2700
2913
|
|
|
2701
2914
|
// src/lib/services/indexed-db-file-system.service.ts
|
|
2702
2915
|
var DB_NAME = "qodalis-cli-filesystem";
|
|
@@ -2705,6 +2918,7 @@ var files = (() => {
|
|
|
2705
2918
|
var CWD_KEY = "cwd";
|
|
2706
2919
|
var HOME_KEY = "home";
|
|
2707
2920
|
var DEFAULT_HOME = "/";
|
|
2921
|
+
var ANONYMOUS_OWNERSHIP = { uid: "nobody", gid: "nogroup" };
|
|
2708
2922
|
function createSeedFileSystem() {
|
|
2709
2923
|
const now = Date.now();
|
|
2710
2924
|
return {
|
|
@@ -2752,6 +2966,88 @@ var files = (() => {
|
|
|
2752
2966
|
this.homePath = DEFAULT_HOME;
|
|
2753
2967
|
this.currentUid = null;
|
|
2754
2968
|
this.currentGroups = [];
|
|
2969
|
+
this.systemDepth = 0;
|
|
2970
|
+
}
|
|
2971
|
+
// --- Access control ---
|
|
2972
|
+
setAccessPolicy(policy) {
|
|
2973
|
+
this.accessPolicy = policy;
|
|
2974
|
+
}
|
|
2975
|
+
runAsSystem(fn) {
|
|
2976
|
+
this.systemDepth++;
|
|
2977
|
+
try {
|
|
2978
|
+
return fn();
|
|
2979
|
+
} finally {
|
|
2980
|
+
this.systemDepth--;
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
reassignOwner(fromUid, toUid) {
|
|
2984
|
+
const from = fromUid.toLowerCase();
|
|
2985
|
+
if (!from || !toUid) return 0;
|
|
2986
|
+
let changed = 0;
|
|
2987
|
+
const visit = (node) => {
|
|
2988
|
+
if (node.ownership && node.ownership.uid.toLowerCase() === from) {
|
|
2989
|
+
node.ownership = { ...node.ownership, uid: toUid };
|
|
2990
|
+
changed++;
|
|
2991
|
+
}
|
|
2992
|
+
node.children?.forEach(visit);
|
|
2993
|
+
};
|
|
2994
|
+
visit(this.root);
|
|
2995
|
+
return changed;
|
|
2996
|
+
}
|
|
2997
|
+
canTraverse(path) {
|
|
2998
|
+
try {
|
|
2999
|
+
this.assertTraverse(this.resolvePath(path), "stat", path);
|
|
3000
|
+
return true;
|
|
3001
|
+
} catch {
|
|
3002
|
+
return false;
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
get enforcing() {
|
|
3006
|
+
return !!this.accessPolicy && this.systemDepth === 0;
|
|
3007
|
+
}
|
|
3008
|
+
deny(op, path, reason = "Permission denied") {
|
|
3009
|
+
throw new CliAccessDeniedError(`${op}: ${path}: ${reason}`);
|
|
3010
|
+
}
|
|
3011
|
+
/** `x` on every existing directory on the way to `resolved` (excluding the target). */
|
|
3012
|
+
assertTraverse(resolved, op, display) {
|
|
3013
|
+
if (!this.enforcing) return;
|
|
3014
|
+
const parts = resolved.split("/").filter(Boolean);
|
|
3015
|
+
let current = this.root;
|
|
3016
|
+
for (let i = 0; i < parts.length; i++) {
|
|
3017
|
+
if (!current || current.type !== "directory") return;
|
|
3018
|
+
if (!this.accessPolicy.canAccess(current, "execute")) this.deny(op, display);
|
|
3019
|
+
current = current.children?.find((c) => c.name === parts[i]);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
assertAccess(node, action, op, display) {
|
|
3023
|
+
if (this.enforcing && !this.accessPolicy.canAccess(node, action)) this.deny(op, display);
|
|
3024
|
+
}
|
|
3025
|
+
/** Recursive delete: every directory inside must allow removing its entries (`w` + `x`, readable). */
|
|
3026
|
+
assertRemovableTree(dir, dirPath, display) {
|
|
3027
|
+
if (!this.enforcing) return;
|
|
3028
|
+
this.assertAccess(dir, "read", "rm", display);
|
|
3029
|
+
this.assertAccess(dir, "execute", "rm", display);
|
|
3030
|
+
if ((dir.children?.length ?? 0) > 0) this.assertAccess(dir, "write", "rm", display);
|
|
3031
|
+
for (const child of dir.children ?? []) {
|
|
3032
|
+
if (child.type === "directory") this.assertRemovableTree(child, `${dirPath}/${child.name}`, display);
|
|
3033
|
+
}
|
|
3034
|
+
}
|
|
3035
|
+
/** Copying reads everything it copies: `r` on every file, `r` + `x` on every directory. */
|
|
3036
|
+
assertReadableTree(node, display) {
|
|
3037
|
+
if (!this.enforcing) return;
|
|
3038
|
+
this.assertAccess(node, "read", "cp", display);
|
|
3039
|
+
if (node.type !== "directory") return;
|
|
3040
|
+
this.assertAccess(node, "execute", "cp", display);
|
|
3041
|
+
for (const child of node.children ?? []) {
|
|
3042
|
+
this.assertReadableTree(child, `${display.replace(/\/+$/, "")}/${child.name}`);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
/** Creating/removing entries needs `w` and `x` on the containing directory. */
|
|
3046
|
+
assertModifyDir(dir, dirPath, op, display) {
|
|
3047
|
+
if (!this.enforcing) return;
|
|
3048
|
+
this.assertTraverse(dirPath, op, display);
|
|
3049
|
+
this.assertAccess(dir, "execute", op, display);
|
|
3050
|
+
this.assertAccess(dir, "write", op, display);
|
|
2755
3051
|
}
|
|
2756
3052
|
// --- User context ---
|
|
2757
3053
|
setCurrentUser(uid, groups) {
|
|
@@ -2759,7 +3055,9 @@ var files = (() => {
|
|
|
2759
3055
|
this.currentGroups = groups;
|
|
2760
3056
|
}
|
|
2761
3057
|
getDefaultOwnership() {
|
|
2762
|
-
if (!this.currentUid)
|
|
3058
|
+
if (!this.currentUid) {
|
|
3059
|
+
return this.accessPolicy ? { ...ANONYMOUS_OWNERSHIP } : void 0;
|
|
3060
|
+
}
|
|
2763
3061
|
return {
|
|
2764
3062
|
uid: this.currentUid,
|
|
2765
3063
|
gid: this.currentGroups[0] || "users"
|
|
@@ -2778,6 +3076,8 @@ var files = (() => {
|
|
|
2778
3076
|
if (node.type !== "directory") {
|
|
2779
3077
|
throw new Error(`cd: ${path}: Not a directory`);
|
|
2780
3078
|
}
|
|
3079
|
+
this.assertTraverse(resolved, "cd", path);
|
|
3080
|
+
this.assertAccess(node, "execute", "cd", path);
|
|
2781
3081
|
this.cwd = resolved;
|
|
2782
3082
|
}
|
|
2783
3083
|
getHomePath() {
|
|
@@ -2834,6 +3134,8 @@ var files = (() => {
|
|
|
2834
3134
|
if (node.type !== "directory") {
|
|
2835
3135
|
throw new Error(`ls: ${path}: Not a directory`);
|
|
2836
3136
|
}
|
|
3137
|
+
this.assertTraverse(this.resolvePath(path), "ls", path);
|
|
3138
|
+
this.assertAccess(node, "read", "ls", path);
|
|
2837
3139
|
return node.children || [];
|
|
2838
3140
|
}
|
|
2839
3141
|
readFile(path) {
|
|
@@ -2844,6 +3146,8 @@ var files = (() => {
|
|
|
2844
3146
|
if (node.type === "directory") {
|
|
2845
3147
|
throw new Error(`cat: ${path}: Is a directory`);
|
|
2846
3148
|
}
|
|
3149
|
+
this.assertTraverse(this.resolvePath(path), "cat", path);
|
|
3150
|
+
this.assertAccess(node, "read", "cat", path);
|
|
2847
3151
|
return node.content ?? "";
|
|
2848
3152
|
}
|
|
2849
3153
|
exists(path) {
|
|
@@ -2868,6 +3172,10 @@ var files = (() => {
|
|
|
2868
3172
|
}
|
|
2869
3173
|
let child = current.children.find((c) => c.name === part);
|
|
2870
3174
|
if (!child) {
|
|
3175
|
+
if (this.enforcing) {
|
|
3176
|
+
this.assertAccess(current, "execute", "mkdir", path);
|
|
3177
|
+
this.assertAccess(current, "write", "mkdir", path);
|
|
3178
|
+
}
|
|
2871
3179
|
const now = Date.now();
|
|
2872
3180
|
child = {
|
|
2873
3181
|
name: part,
|
|
@@ -2883,6 +3191,8 @@ var files = (() => {
|
|
|
2883
3191
|
current.modifiedAt = now;
|
|
2884
3192
|
} else if (child.type !== "directory") {
|
|
2885
3193
|
throw new Error(`mkdir: ${part}: Not a directory`);
|
|
3194
|
+
} else {
|
|
3195
|
+
this.assertAccess(child, "execute", "mkdir", path);
|
|
2886
3196
|
}
|
|
2887
3197
|
current = child;
|
|
2888
3198
|
}
|
|
@@ -2901,6 +3211,7 @@ var files = (() => {
|
|
|
2901
3211
|
if (parent.children?.find((c) => c.name === dirName)) {
|
|
2902
3212
|
throw new Error(`mkdir: ${path}: File exists`);
|
|
2903
3213
|
}
|
|
3214
|
+
this.assertModifyDir(parent, parentPath, "mkdir", path);
|
|
2904
3215
|
const now = Date.now();
|
|
2905
3216
|
if (!parent.children) {
|
|
2906
3217
|
parent.children = [];
|
|
@@ -2935,6 +3246,12 @@ var files = (() => {
|
|
|
2935
3246
|
}
|
|
2936
3247
|
const existing = parent.children?.find((c) => c.name === fileName);
|
|
2937
3248
|
const now = Date.now();
|
|
3249
|
+
if (existing) {
|
|
3250
|
+
this.assertTraverse(resolved, "touch", path);
|
|
3251
|
+
this.assertAccess(existing, "write", "touch", path);
|
|
3252
|
+
} else {
|
|
3253
|
+
this.assertModifyDir(parent, parentPath, "touch", path);
|
|
3254
|
+
}
|
|
2938
3255
|
if (existing) {
|
|
2939
3256
|
existing.modifiedAt = now;
|
|
2940
3257
|
} else {
|
|
@@ -2961,6 +3278,8 @@ var files = (() => {
|
|
|
2961
3278
|
if (node.type === "directory") {
|
|
2962
3279
|
throw new Error(`write: ${path}: Is a directory`);
|
|
2963
3280
|
}
|
|
3281
|
+
this.assertTraverse(resolved, "write", path);
|
|
3282
|
+
this.assertAccess(node, "write", "write", path);
|
|
2964
3283
|
const now = Date.now();
|
|
2965
3284
|
node.content = append ? (node.content ?? "") + content : content;
|
|
2966
3285
|
node.size = new Blob([node.content]).size;
|
|
@@ -2989,6 +3308,8 @@ var files = (() => {
|
|
|
2989
3308
|
if (target.type === "directory" && !recursive) {
|
|
2990
3309
|
throw new Error(`rm: ${path}: Is a directory`);
|
|
2991
3310
|
}
|
|
3311
|
+
this.assertModifyDir(parent, parentPath, "rm", path);
|
|
3312
|
+
if (target.type === "directory") this.assertRemovableTree(target, resolved, path);
|
|
2992
3313
|
parent.children.splice(index, 1);
|
|
2993
3314
|
parent.modifiedAt = Date.now();
|
|
2994
3315
|
}
|
|
@@ -3003,10 +3324,13 @@ var files = (() => {
|
|
|
3003
3324
|
`cp: -r not specified; omitting directory '${src}'`
|
|
3004
3325
|
);
|
|
3005
3326
|
}
|
|
3327
|
+
this.assertTraverse(srcResolved, "cp", src);
|
|
3328
|
+
this.assertReadableTree(srcNode, src);
|
|
3006
3329
|
const destResolved = this.resolvePath(dest);
|
|
3007
3330
|
const destNode = this.getNode(destResolved);
|
|
3008
3331
|
if (destNode && destNode.type === "directory") {
|
|
3009
|
-
|
|
3332
|
+
this.assertModifyDir(destNode, destResolved, "cp", dest);
|
|
3333
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
3010
3334
|
if (!destNode.children) {
|
|
3011
3335
|
destNode.children = [];
|
|
3012
3336
|
}
|
|
@@ -3026,7 +3350,8 @@ var files = (() => {
|
|
|
3026
3350
|
if (!parent || parent.type !== "directory") {
|
|
3027
3351
|
throw new Error(`cp: ${parentPath}: No such file or directory`);
|
|
3028
3352
|
}
|
|
3029
|
-
|
|
3353
|
+
this.assertModifyDir(parent, parentPath, "cp", dest);
|
|
3354
|
+
const clone = this.ownedByCurrentUser(this.cloneNode(srcNode));
|
|
3030
3355
|
clone.name = newName;
|
|
3031
3356
|
if (!parent.children) {
|
|
3032
3357
|
parent.children = [];
|
|
@@ -3052,16 +3377,23 @@ var files = (() => {
|
|
|
3052
3377
|
}
|
|
3053
3378
|
const destResolved = this.resolvePath(dest);
|
|
3054
3379
|
const destNode = this.getNode(destResolved);
|
|
3380
|
+
if (srcNode.type === "directory" && (destResolved === srcResolved || destResolved.startsWith(srcResolved + "/"))) {
|
|
3381
|
+
throw new Error(
|
|
3382
|
+
`mv: cannot move '${src}' to a subdirectory of itself, '${dest}'`
|
|
3383
|
+
);
|
|
3384
|
+
}
|
|
3055
3385
|
const srcParts = srcResolved.split("/").filter(Boolean);
|
|
3056
3386
|
const srcParentPath = "/" + srcParts.slice(0, -1).join("/");
|
|
3057
3387
|
const srcParent = this.getNode(srcParentPath);
|
|
3058
3388
|
if (!srcParent || !srcParent.children) {
|
|
3059
3389
|
throw new Error(`mv: ${src}: No such file or directory`);
|
|
3060
3390
|
}
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3391
|
+
this.assertModifyDir(srcParent, srcParentPath, "mv", src);
|
|
3392
|
+
if (destResolved === srcResolved || destNode && destNode.type === "directory" && destNode === srcParent) {
|
|
3393
|
+
throw new Error(`mv: '${src}' and '${dest}' are the same file`);
|
|
3394
|
+
}
|
|
3064
3395
|
if (destNode && destNode.type === "directory") {
|
|
3396
|
+
this.assertModifyDir(destNode, destResolved, "mv", dest);
|
|
3065
3397
|
if (!destNode.children) {
|
|
3066
3398
|
destNode.children = [];
|
|
3067
3399
|
}
|
|
@@ -3071,7 +3403,7 @@ var files = (() => {
|
|
|
3071
3403
|
if (existingIdx !== -1) {
|
|
3072
3404
|
destNode.children.splice(existingIdx, 1);
|
|
3073
3405
|
}
|
|
3074
|
-
srcParent.children.splice(
|
|
3406
|
+
srcParent.children.splice(srcParent.children.indexOf(srcNode), 1);
|
|
3075
3407
|
destNode.children.push(srcNode);
|
|
3076
3408
|
destNode.modifiedAt = Date.now();
|
|
3077
3409
|
} else {
|
|
@@ -3084,7 +3416,8 @@ var files = (() => {
|
|
|
3084
3416
|
`mv: ${destParentPath}: No such file or directory`
|
|
3085
3417
|
);
|
|
3086
3418
|
}
|
|
3087
|
-
|
|
3419
|
+
this.assertModifyDir(destParent, destParentPath, "mv", dest);
|
|
3420
|
+
srcParent.children.splice(srcParent.children.indexOf(srcNode), 1);
|
|
3088
3421
|
srcNode.name = newName;
|
|
3089
3422
|
if (!destParent.children) {
|
|
3090
3423
|
destParent.children = [];
|
|
@@ -3107,6 +3440,9 @@ var files = (() => {
|
|
|
3107
3440
|
if (!node) {
|
|
3108
3441
|
throw new Error(`chmod: ${path}: No such file or directory`);
|
|
3109
3442
|
}
|
|
3443
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node)) {
|
|
3444
|
+
this.deny("chmod", path, "Operation not permitted");
|
|
3445
|
+
}
|
|
3110
3446
|
node.permissions = permissions;
|
|
3111
3447
|
}
|
|
3112
3448
|
chown(path, ownership) {
|
|
@@ -3115,6 +3451,9 @@ var files = (() => {
|
|
|
3115
3451
|
if (!node) {
|
|
3116
3452
|
throw new Error(`chown: ${path}: No such file or directory`);
|
|
3117
3453
|
}
|
|
3454
|
+
if (this.enforcing && !this.accessPolicy.canChangeOwnership(node, ownership)) {
|
|
3455
|
+
this.deny("chown", path, "Operation not permitted");
|
|
3456
|
+
}
|
|
3118
3457
|
node.ownership = ownership;
|
|
3119
3458
|
}
|
|
3120
3459
|
// --- Persistence ---
|
|
@@ -3145,8 +3484,10 @@ var files = (() => {
|
|
|
3145
3484
|
const tx = db.transaction(STORE_NAME, "readwrite");
|
|
3146
3485
|
const store = tx.objectStore(STORE_NAME);
|
|
3147
3486
|
store.put(this.root, ROOT_KEY);
|
|
3148
|
-
|
|
3149
|
-
|
|
3487
|
+
if (!this.currentUid) {
|
|
3488
|
+
store.put(this.cwd, CWD_KEY);
|
|
3489
|
+
store.put(this.homePath, HOME_KEY);
|
|
3490
|
+
}
|
|
3150
3491
|
await new Promise((resolve, reject) => {
|
|
3151
3492
|
tx.oncomplete = () => resolve();
|
|
3152
3493
|
tx.onerror = () => reject(tx.error);
|
|
@@ -3156,6 +3497,18 @@ var files = (() => {
|
|
|
3156
3497
|
}
|
|
3157
3498
|
}
|
|
3158
3499
|
// --- Private helpers ---
|
|
3500
|
+
/** A copy belongs to whoever made it (like `cp` without `-p`) */
|
|
3501
|
+
ownedByCurrentUser(node) {
|
|
3502
|
+
const owner = this.getDefaultOwnership();
|
|
3503
|
+
if (owner) {
|
|
3504
|
+
const apply = (n) => {
|
|
3505
|
+
n.ownership = { ...owner };
|
|
3506
|
+
n.children?.forEach(apply);
|
|
3507
|
+
};
|
|
3508
|
+
apply(node);
|
|
3509
|
+
}
|
|
3510
|
+
return node;
|
|
3511
|
+
}
|
|
3159
3512
|
cloneNode(node) {
|
|
3160
3513
|
const now = Date.now();
|
|
3161
3514
|
const clone = {
|
|
@@ -3217,7 +3570,26 @@ var files = (() => {
|
|
|
3217
3570
|
"find",
|
|
3218
3571
|
"head",
|
|
3219
3572
|
"tail",
|
|
3220
|
-
"wc"
|
|
3573
|
+
"wc",
|
|
3574
|
+
"sort",
|
|
3575
|
+
"uniq",
|
|
3576
|
+
"cut",
|
|
3577
|
+
"paste",
|
|
3578
|
+
"tac",
|
|
3579
|
+
"diff",
|
|
3580
|
+
"sed",
|
|
3581
|
+
"awk",
|
|
3582
|
+
"du",
|
|
3583
|
+
"stat",
|
|
3584
|
+
"chmod",
|
|
3585
|
+
"chown",
|
|
3586
|
+
"ln",
|
|
3587
|
+
"tee",
|
|
3588
|
+
"basename",
|
|
3589
|
+
"dirname",
|
|
3590
|
+
"sh",
|
|
3591
|
+
"source",
|
|
3592
|
+
"xargs"
|
|
3221
3593
|
]);
|
|
3222
3594
|
var FilePathCompletionProvider = class {
|
|
3223
3595
|
constructor(fs) {
|
|
@@ -3236,7 +3608,14 @@ var files = (() => {
|
|
|
3236
3608
|
if (token.startsWith("-")) {
|
|
3237
3609
|
return [];
|
|
3238
3610
|
}
|
|
3239
|
-
|
|
3611
|
+
const quote = token.startsWith('"') || token.startsWith("'") ? token[0] : "";
|
|
3612
|
+
const partial = quote ? token.slice(1).replace(new RegExp(`${quote}$`), "") : token;
|
|
3613
|
+
const paths = this.completePath(partial);
|
|
3614
|
+
if (!quote && !paths.some((p) => /\s/.test(p))) {
|
|
3615
|
+
return paths;
|
|
3616
|
+
}
|
|
3617
|
+
const q = quote || '"';
|
|
3618
|
+
return paths.map((p) => p.endsWith("/") ? `${q}${p}` : `${q}${p}${q}`);
|
|
3240
3619
|
}
|
|
3241
3620
|
completePath(partial) {
|
|
3242
3621
|
let dirPath;
|
|
@@ -3280,6 +3659,11 @@ var files = (() => {
|
|
|
3280
3659
|
}
|
|
3281
3660
|
};
|
|
3282
3661
|
|
|
3662
|
+
// src/lib/utils/split-args.ts
|
|
3663
|
+
function splitArgs(raw) {
|
|
3664
|
+
return splitShellWords(raw);
|
|
3665
|
+
}
|
|
3666
|
+
|
|
3283
3667
|
// src/lib/processors/cli-ls-command-processor.ts
|
|
3284
3668
|
var CliLsCommandProcessor = class {
|
|
3285
3669
|
constructor() {
|
|
@@ -3303,41 +3687,63 @@ var files = (() => {
|
|
|
3303
3687
|
description: "Use long listing format",
|
|
3304
3688
|
required: false,
|
|
3305
3689
|
type: "boolean"
|
|
3690
|
+
},
|
|
3691
|
+
{
|
|
3692
|
+
name: "human-readable",
|
|
3693
|
+
aliases: ["h"],
|
|
3694
|
+
description: "With -l, print sizes like 1.5K and 2M",
|
|
3695
|
+
required: false,
|
|
3696
|
+
type: "boolean"
|
|
3306
3697
|
}
|
|
3307
3698
|
];
|
|
3699
|
+
this.humanReadable = false;
|
|
3308
3700
|
}
|
|
3309
3701
|
async processCommand(command, context) {
|
|
3310
|
-
const fs = context.services.
|
|
3702
|
+
const fs = context.services.getRequired(
|
|
3311
3703
|
IFileSystemService_TOKEN
|
|
3312
3704
|
);
|
|
3313
|
-
const
|
|
3705
|
+
const paths = splitArgs(command.value || "");
|
|
3314
3706
|
const showAll = command.args["all"] || command.args["a"];
|
|
3315
3707
|
const longFormat = command.args["long"] || command.args["l"];
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3708
|
+
this.humanReadable = !!(command.args["human-readable"] || command.args["h"]);
|
|
3709
|
+
const targets = paths.length > 0 ? paths : [fs.getCurrentDirectory()];
|
|
3710
|
+
const piped = [];
|
|
3711
|
+
targets.forEach((targetPath, index) => {
|
|
3712
|
+
try {
|
|
3713
|
+
const node = fs.getNode(targetPath);
|
|
3714
|
+
const entries = node && node.type !== "directory" ? [{ ...node, name: targetPath }] : fs.listDirectory(targetPath);
|
|
3715
|
+
const filtered = showAll ? entries : entries.filter((e) => !e.name.startsWith("."));
|
|
3716
|
+
if (targets.length > 1) {
|
|
3717
|
+
if (index > 0) context.writer.writeln();
|
|
3718
|
+
context.writer.writeln(`${targetPath}:`);
|
|
3325
3719
|
}
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3720
|
+
if (filtered.length === 0) {
|
|
3721
|
+
return;
|
|
3722
|
+
}
|
|
3723
|
+
filtered.sort((a, b) => {
|
|
3724
|
+
if (a.type !== b.type) {
|
|
3725
|
+
return a.type === "directory" ? -1 : 1;
|
|
3726
|
+
}
|
|
3727
|
+
return a.name.localeCompare(b.name);
|
|
3728
|
+
});
|
|
3729
|
+
if (longFormat) {
|
|
3730
|
+
this.writeLongFormat(filtered, context);
|
|
3731
|
+
} else {
|
|
3732
|
+
this.writeShortFormat(filtered, context);
|
|
3733
|
+
piped.push(...filtered.map((e) => e.name));
|
|
3734
|
+
}
|
|
3735
|
+
} catch (e) {
|
|
3736
|
+
context.writer.writeError(e.message);
|
|
3332
3737
|
}
|
|
3333
|
-
}
|
|
3334
|
-
|
|
3738
|
+
});
|
|
3739
|
+
if (!longFormat && piped.length > 0) {
|
|
3740
|
+
context.process.output(piped.join("\n"));
|
|
3335
3741
|
}
|
|
3336
3742
|
}
|
|
3337
3743
|
writeDescription(context) {
|
|
3338
3744
|
context.writer.writeln(this.description);
|
|
3339
3745
|
context.writer.writeln();
|
|
3340
|
-
context.writer.writeln("Usage: ls [path] [
|
|
3746
|
+
context.writer.writeln("Usage: ls [path...] [-a|--all] [-l|--long] [-h|--human-readable]");
|
|
3341
3747
|
}
|
|
3342
3748
|
writeLongFormat(entries, context) {
|
|
3343
3749
|
const { writer } = context;
|
|
@@ -3346,7 +3752,7 @@ var files = (() => {
|
|
|
3346
3752
|
const perms = entry.permissions || (entry.type === "directory" ? "rwxr-xr-x" : "rw-r--r--");
|
|
3347
3753
|
const owner = entry.ownership?.uid || "-";
|
|
3348
3754
|
const group = entry.ownership?.gid || "-";
|
|
3349
|
-
const size = entry.type
|
|
3755
|
+
const size = entry.type !== "file" ? "-" : this.humanReadable ? this.formatSize(entry.size) : entry.size.toString();
|
|
3350
3756
|
const date = new Date(entry.modifiedAt);
|
|
3351
3757
|
const dateStr = date.toLocaleDateString("en-US", {
|
|
3352
3758
|
month: "short",
|
|
@@ -3360,6 +3766,17 @@ var files = (() => {
|
|
|
3360
3766
|
);
|
|
3361
3767
|
}
|
|
3362
3768
|
}
|
|
3769
|
+
formatSize(bytes) {
|
|
3770
|
+
const units = ["K", "M", "G", "T"];
|
|
3771
|
+
let size = bytes;
|
|
3772
|
+
let unit = "";
|
|
3773
|
+
for (const next of units) {
|
|
3774
|
+
if (size < 1024) break;
|
|
3775
|
+
size /= 1024;
|
|
3776
|
+
unit = next;
|
|
3777
|
+
}
|
|
3778
|
+
return unit ? `${size < 10 ? size.toFixed(1) : Math.round(size)}${unit}` : String(bytes);
|
|
3779
|
+
}
|
|
3363
3780
|
writeShortFormat(entries, context) {
|
|
3364
3781
|
const { writer } = context;
|
|
3365
3782
|
const names = entries.map(
|
|
@@ -3379,11 +3796,30 @@ var files = (() => {
|
|
|
3379
3796
|
this.acceptsRawInput = true;
|
|
3380
3797
|
this.metadata = { icon: "\u{1F4C1}", module: "file management" };
|
|
3381
3798
|
}
|
|
3799
|
+
writeDescription(context) {
|
|
3800
|
+
const t = context.translator;
|
|
3801
|
+
writeWrapped(
|
|
3802
|
+
context,
|
|
3803
|
+
t.t("cli.cd.help.change_current_directory_without", "Change the current directory. Without a path it goes to your home directory. Paths can be absolute (/...), relative to where you are, or start with ~ for home.")
|
|
3804
|
+
);
|
|
3805
|
+
context.writer.writeln();
|
|
3806
|
+
writeUsage(context, [
|
|
3807
|
+
["cd", t.t("cli.cd.help.go_home_directory", "Go to your home directory")],
|
|
3808
|
+
["cd <dir>", t.t("cli.cd.help.go_directory", "Go into a directory")],
|
|
3809
|
+
["cd ..", t.t("cli.cd.help.go_up_one_level", "Go up one level")]
|
|
3810
|
+
]);
|
|
3811
|
+
context.writer.writeln();
|
|
3812
|
+
writeExamples(context, [
|
|
3813
|
+
["cd ~/docs", t.t("cli.cd.help.go_docs_home", "Go to docs in your home")],
|
|
3814
|
+
["cd ../projects", t.t("cli.cd.help.go_sibling_directory", "Go to a sibling directory")],
|
|
3815
|
+
["cd /", t.t("cli.cd.help.go_root", "Go to the root")]
|
|
3816
|
+
]);
|
|
3817
|
+
}
|
|
3382
3818
|
async processCommand(command, context) {
|
|
3383
|
-
const fs = context.services.
|
|
3819
|
+
const fs = context.services.getRequired(
|
|
3384
3820
|
IFileSystemService_TOKEN
|
|
3385
3821
|
);
|
|
3386
|
-
const target = command.value || "~";
|
|
3822
|
+
const target = splitArgs(command.value || "").join(" ") || "~";
|
|
3387
3823
|
try {
|
|
3388
3824
|
fs.setCurrentDirectory(target);
|
|
3389
3825
|
await fs.persist();
|
|
@@ -3402,8 +3838,24 @@ var files = (() => {
|
|
|
3402
3838
|
this.version = LIBRARY_VERSION;
|
|
3403
3839
|
this.metadata = { icon: "\u{1F4C2}", module: "file management" };
|
|
3404
3840
|
}
|
|
3841
|
+
writeDescription(context) {
|
|
3842
|
+
const t = context.translator;
|
|
3843
|
+
writeWrapped(
|
|
3844
|
+
context,
|
|
3845
|
+
t.t("cli.pwd.help.print_full_path_directory", "Print the full path of the directory you are in. Relative paths in other commands start from here.")
|
|
3846
|
+
);
|
|
3847
|
+
context.writer.writeln();
|
|
3848
|
+
writeUsage(context, [
|
|
3849
|
+
["pwd", t.t("cli.pwd.help.show_current_directory", "Show the current directory")]
|
|
3850
|
+
]);
|
|
3851
|
+
context.writer.writeln();
|
|
3852
|
+
writeExamples(context, [
|
|
3853
|
+
["pwd", t.t("cli.pwd.help.example_home_user", "For example /home/user")],
|
|
3854
|
+
["cd ~/docs; pwd", t.t("cli.pwd.help.prints_home_user_docs", "Prints /home/user/docs")]
|
|
3855
|
+
]);
|
|
3856
|
+
}
|
|
3405
3857
|
async processCommand(command, context) {
|
|
3406
|
-
const fs = context.services.
|
|
3858
|
+
const fs = context.services.getRequired(
|
|
3407
3859
|
IFileSystemService_TOKEN
|
|
3408
3860
|
);
|
|
3409
3861
|
context.writer.writeln(fs.getCurrentDirectory());
|
|
@@ -3430,22 +3882,44 @@ var files = (() => {
|
|
|
3430
3882
|
}
|
|
3431
3883
|
];
|
|
3432
3884
|
}
|
|
3885
|
+
writeDescription(context) {
|
|
3886
|
+
const t = context.translator;
|
|
3887
|
+
writeWrapped(
|
|
3888
|
+
context,
|
|
3889
|
+
t.t("cli.mkdir.help.create_new_directory_p", "Create a new directory. With -p, any missing parent directories are created too.")
|
|
3890
|
+
);
|
|
3891
|
+
context.writer.writeln();
|
|
3892
|
+
writeUsage(context, [
|
|
3893
|
+
["mkdir <dir...>", t.t("cli.mkdir.help.create_one_more_directories", "Create one or more directories")],
|
|
3894
|
+
["mkdir -p <path>", t.t("cli.mkdir.help.create_directory_missing_parents", "Create a directory and its missing parents")]
|
|
3895
|
+
]);
|
|
3896
|
+
context.writer.writeln();
|
|
3897
|
+
writeExamples(context, [
|
|
3898
|
+
["mkdir projects", t.t("cli.mkdir.help.create_projects_current_directory", "Create projects in the current directory")],
|
|
3899
|
+
["mkdir -p ~/docs/2026/notes", t.t("cli.mkdir.help.create_whole_path_once", "Create the whole path at once")]
|
|
3900
|
+
]);
|
|
3901
|
+
}
|
|
3433
3902
|
async processCommand(command, context) {
|
|
3434
|
-
const fs = context.services.
|
|
3903
|
+
const fs = context.services.getRequired(
|
|
3435
3904
|
IFileSystemService_TOKEN
|
|
3436
3905
|
);
|
|
3437
|
-
const
|
|
3906
|
+
const paths = splitArgs(command.value || "");
|
|
3438
3907
|
const recursive = command.args["parents"] || command.args["p"];
|
|
3439
|
-
if (
|
|
3908
|
+
if (paths.length === 0) {
|
|
3440
3909
|
context.writer.writeError("mkdir: missing operand");
|
|
3441
3910
|
return;
|
|
3442
3911
|
}
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3912
|
+
let changed = false;
|
|
3913
|
+
for (const path of paths) {
|
|
3914
|
+
try {
|
|
3915
|
+
if (recursive && fs.isDirectory(path)) continue;
|
|
3916
|
+
fs.createDirectory(path, recursive);
|
|
3917
|
+
changed = true;
|
|
3918
|
+
} catch (e) {
|
|
3919
|
+
context.writer.writeError(e.message);
|
|
3920
|
+
}
|
|
3448
3921
|
}
|
|
3922
|
+
if (changed) await fs.persist();
|
|
3449
3923
|
}
|
|
3450
3924
|
};
|
|
3451
3925
|
|
|
@@ -3460,38 +3934,58 @@ var files = (() => {
|
|
|
3460
3934
|
this.valueRequired = true;
|
|
3461
3935
|
this.metadata = { icon: "\u{1F5D1}", module: "file management" };
|
|
3462
3936
|
}
|
|
3937
|
+
writeDescription(context) {
|
|
3938
|
+
const t = context.translator;
|
|
3939
|
+
writeWrapped(
|
|
3940
|
+
context,
|
|
3941
|
+
t.t("cli.rmdir.help.remove_empty_directory_refuses", "Remove an empty directory. It refuses to remove a directory that still contains files; use rm -r for that.")
|
|
3942
|
+
);
|
|
3943
|
+
context.writer.writeln();
|
|
3944
|
+
writeUsage(context, [
|
|
3945
|
+
["rmdir <dir...>", t.t("cli.rmdir.help.remove_empty_directories", "Remove empty directories")]
|
|
3946
|
+
]);
|
|
3947
|
+
context.writer.writeln();
|
|
3948
|
+
writeExamples(context, [
|
|
3949
|
+
["rmdir empty-folder", t.t("cli.rmdir.help.remove_directory_current_one", "Remove a directory in the current one")],
|
|
3950
|
+
["rmdir ~/docs/old", t.t("cli.rmdir.help.remove_full_path", "Remove by full path")]
|
|
3951
|
+
]);
|
|
3952
|
+
}
|
|
3463
3953
|
async processCommand(command, context) {
|
|
3464
|
-
const fs = context.services.
|
|
3954
|
+
const fs = context.services.getRequired(
|
|
3465
3955
|
IFileSystemService_TOKEN
|
|
3466
3956
|
);
|
|
3467
|
-
const
|
|
3468
|
-
if (
|
|
3957
|
+
const paths = splitArgs(command.value || "");
|
|
3958
|
+
if (paths.length === 0) {
|
|
3469
3959
|
context.writer.writeError("rmdir: missing operand");
|
|
3470
3960
|
return;
|
|
3471
3961
|
}
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3962
|
+
let changed = false;
|
|
3963
|
+
for (const path of paths) {
|
|
3964
|
+
try {
|
|
3965
|
+
const node = fs.getNode(path);
|
|
3966
|
+
if (!node) {
|
|
3967
|
+
context.writer.writeError(
|
|
3968
|
+
`rmdir: ${path}: No such file or directory`
|
|
3969
|
+
);
|
|
3970
|
+
continue;
|
|
3971
|
+
}
|
|
3972
|
+
if (node.type !== "directory") {
|
|
3973
|
+
context.writer.writeError(`rmdir: ${path}: Not a directory`);
|
|
3974
|
+
continue;
|
|
3975
|
+
}
|
|
3976
|
+
if (node.children && node.children.length > 0) {
|
|
3977
|
+
context.writer.writeError(
|
|
3978
|
+
`rmdir: ${path}: Directory not empty`
|
|
3979
|
+
);
|
|
3980
|
+
continue;
|
|
3981
|
+
}
|
|
3982
|
+
fs.remove(path, true);
|
|
3983
|
+
changed = true;
|
|
3984
|
+
} catch (e) {
|
|
3985
|
+
context.writer.writeError(e.message);
|
|
3489
3986
|
}
|
|
3490
|
-
fs.remove(path);
|
|
3491
|
-
await fs.persist();
|
|
3492
|
-
} catch (e) {
|
|
3493
|
-
context.writer.writeError(e.message);
|
|
3494
3987
|
}
|
|
3988
|
+
if (changed) await fs.persist();
|
|
3495
3989
|
}
|
|
3496
3990
|
};
|
|
3497
3991
|
|
|
@@ -3506,24 +4000,55 @@ var files = (() => {
|
|
|
3506
4000
|
this.valueRequired = true;
|
|
3507
4001
|
this.metadata = { icon: "\u{1F4C4}", module: "file management" };
|
|
3508
4002
|
}
|
|
4003
|
+
writeDescription(context) {
|
|
4004
|
+
const t = context.translator;
|
|
4005
|
+
writeWrapped(
|
|
4006
|
+
context,
|
|
4007
|
+
t.t("cli.touch.help.create_empty_file_update", "Create an empty file, or update the modified time of a file that already exists. The parent directory must already exist.")
|
|
4008
|
+
);
|
|
4009
|
+
context.writer.writeln();
|
|
4010
|
+
writeUsage(context, [
|
|
4011
|
+
["touch <file...>", t.t("cli.touch.help.create_files_refresh_their", "Create the files, or refresh their timestamps")]
|
|
4012
|
+
]);
|
|
4013
|
+
context.writer.writeln();
|
|
4014
|
+
writeExamples(context, [
|
|
4015
|
+
["touch notes.txt", t.t("cli.touch.help.create_empty_notes_txt", "Create an empty notes.txt")],
|
|
4016
|
+
["touch ~/docs/todo.md", t.t("cli.touch.help.create_file_docs", "Create a file in ~/docs")]
|
|
4017
|
+
]);
|
|
4018
|
+
}
|
|
3509
4019
|
async processCommand(command, context) {
|
|
3510
|
-
const fs = context.services.
|
|
4020
|
+
const fs = context.services.getRequired(
|
|
3511
4021
|
IFileSystemService_TOKEN
|
|
3512
4022
|
);
|
|
3513
|
-
const
|
|
3514
|
-
if (
|
|
4023
|
+
const paths = splitArgs(command.value || "");
|
|
4024
|
+
if (paths.length === 0) {
|
|
3515
4025
|
context.writer.writeError("touch: missing file operand");
|
|
3516
4026
|
return;
|
|
3517
4027
|
}
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
4028
|
+
let changed = false;
|
|
4029
|
+
for (const path of paths) {
|
|
4030
|
+
try {
|
|
4031
|
+
fs.createFile(path);
|
|
4032
|
+
changed = true;
|
|
4033
|
+
} catch (e) {
|
|
4034
|
+
context.writer.writeError(e.message);
|
|
4035
|
+
}
|
|
3523
4036
|
}
|
|
4037
|
+
if (changed) await fs.persist();
|
|
3524
4038
|
}
|
|
3525
4039
|
};
|
|
3526
4040
|
|
|
4041
|
+
// src/lib/utils/lines.ts
|
|
4042
|
+
function splitLines(content) {
|
|
4043
|
+
if (content === "") return [];
|
|
4044
|
+
const lines = content.split("\n");
|
|
4045
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
4046
|
+
return lines;
|
|
4047
|
+
}
|
|
4048
|
+
function pipedText(data) {
|
|
4049
|
+
return typeof data === "string" ? data : JSON.stringify(data);
|
|
4050
|
+
}
|
|
4051
|
+
|
|
3527
4052
|
// src/lib/processors/cli-cat-command-processor.ts
|
|
3528
4053
|
var CliCatCommandProcessor = class {
|
|
3529
4054
|
constructor() {
|
|
@@ -3535,22 +4060,58 @@ var files = (() => {
|
|
|
3535
4060
|
this.valueRequired = true;
|
|
3536
4061
|
this.metadata = { icon: "\u{1F4D6}", module: "file management" };
|
|
3537
4062
|
}
|
|
4063
|
+
writeDescription(context) {
|
|
4064
|
+
const t = context.translator;
|
|
4065
|
+
writeWrapped(
|
|
4066
|
+
context,
|
|
4067
|
+
t.t("cli.cat.help.print_contents_one_more", "Print the contents of one or more files, joined in order, or of piped input. Pipe the output into other commands to search, sort or count it.")
|
|
4068
|
+
);
|
|
4069
|
+
context.writer.writeln();
|
|
4070
|
+
writeUsage(context, [
|
|
4071
|
+
["cat <file...>", t.t("cli.cat.help.print_files_one_after", "Print files one after another")],
|
|
4072
|
+
["cat <file> | <command>", t.t("cli.cat.help.send_file_another_command", "Send a file to another command")]
|
|
4073
|
+
]);
|
|
4074
|
+
context.writer.writeln();
|
|
4075
|
+
writeExamples(context, [
|
|
4076
|
+
["cat notes.txt", t.t("cli.cat.help.show_whole_file", "Show the whole file")],
|
|
4077
|
+
["cat app.log | grep error", t.t("cli.cat.help.show_only_lines_error", "Show only lines with error")],
|
|
4078
|
+
["cat names.txt | sort", t.t("cli.cat.help.print_lines_sorted", "Print the lines sorted")]
|
|
4079
|
+
]);
|
|
4080
|
+
}
|
|
3538
4081
|
async processCommand(command, context) {
|
|
3539
|
-
const fs = context.services.
|
|
4082
|
+
const fs = context.services.getRequired(
|
|
3540
4083
|
IFileSystemService_TOKEN
|
|
3541
4084
|
);
|
|
3542
|
-
const
|
|
3543
|
-
if (
|
|
4085
|
+
const paths = splitArgs(command.value || "");
|
|
4086
|
+
if (paths.length === 0) {
|
|
4087
|
+
if (command.data != null) {
|
|
4088
|
+
context.writer.writeln(pipedText(command.data));
|
|
4089
|
+
return;
|
|
4090
|
+
}
|
|
3544
4091
|
context.writer.writeError("cat: missing file operand");
|
|
3545
4092
|
return;
|
|
3546
4093
|
}
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
4094
|
+
let output = "";
|
|
4095
|
+
for (const path of paths) {
|
|
4096
|
+
try {
|
|
4097
|
+
if (fs.isDirectory(path)) {
|
|
4098
|
+
context.writer.writeError(`cat: ${path}: Is a directory`);
|
|
4099
|
+
continue;
|
|
4100
|
+
}
|
|
4101
|
+
const content = fs.readFile(path);
|
|
4102
|
+
if (content === null) {
|
|
4103
|
+
context.writer.writeError(
|
|
4104
|
+
`cat: ${path}: No such file or directory`
|
|
4105
|
+
);
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
output += content;
|
|
4109
|
+
} catch (e) {
|
|
4110
|
+
context.writer.writeError(e.message);
|
|
3551
4111
|
}
|
|
3552
|
-
}
|
|
3553
|
-
|
|
4112
|
+
}
|
|
4113
|
+
if (output !== "") {
|
|
4114
|
+
context.writer.writeln(output.replace(/\n$/, ""));
|
|
3554
4115
|
}
|
|
3555
4116
|
}
|
|
3556
4117
|
};
|
|
@@ -3566,60 +4127,33 @@ var files = (() => {
|
|
|
3566
4127
|
this.extendsProcessor = true;
|
|
3567
4128
|
this.metadata = { icon: "\u{1F4AC}", module: "file management" };
|
|
3568
4129
|
}
|
|
4130
|
+
writeDescription(context) {
|
|
4131
|
+
const t = context.translator;
|
|
4132
|
+
writeWrapped(
|
|
4133
|
+
context,
|
|
4134
|
+
t.t("cli.echo.help.print_text_terminal_add", "Print text to the terminal. Add > file to save it to a file (replacing it) or >> file to add it to the end.")
|
|
4135
|
+
);
|
|
4136
|
+
context.writer.writeln();
|
|
4137
|
+
writeUsage(context, [
|
|
4138
|
+
["echo <text>", t.t("cli.echo.help.print_text", "Print text")],
|
|
4139
|
+
["echo <text> > <file>", t.t("cli.echo.help.write_text_file", "Write text to a file")],
|
|
4140
|
+
["echo <text> >> <file>", t.t("cli.echo.help.append_text_file", "Append text to a file")]
|
|
4141
|
+
]);
|
|
4142
|
+
context.writer.writeln();
|
|
4143
|
+
writeExamples(context, [
|
|
4144
|
+
["echo Hello world", t.t("cli.echo.help.print_greeting", "Print a greeting")],
|
|
4145
|
+
["echo first line > notes.txt", t.t("cli.echo.help.create_replace_notes_txt", "Create or replace notes.txt")],
|
|
4146
|
+
["echo another line >> notes.txt", t.t("cli.echo.help.add_line", "Add a line to it")]
|
|
4147
|
+
]);
|
|
4148
|
+
}
|
|
3569
4149
|
async processCommand(command, context) {
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
if (!hasRedirection) {
|
|
3573
|
-
if (this.originalProcessor) {
|
|
3574
|
-
await this.originalProcessor.processCommand(command, context);
|
|
3575
|
-
} else {
|
|
3576
|
-
context.writer.writeln(afterEcho);
|
|
3577
|
-
}
|
|
4150
|
+
if (this.originalProcessor) {
|
|
4151
|
+
await this.originalProcessor.processCommand(command, context);
|
|
3578
4152
|
return;
|
|
3579
4153
|
}
|
|
3580
|
-
const
|
|
3581
|
-
|
|
3582
|
-
);
|
|
3583
|
-
let text;
|
|
3584
|
-
let filePath;
|
|
3585
|
-
let append = false;
|
|
3586
|
-
const appendMatch = afterEcho.match(/^(.*?)\s*>>\s*(.+)$/);
|
|
3587
|
-
const overwriteMatch = afterEcho.match(/^(.*?)\s*>\s*(.+)$/);
|
|
3588
|
-
if (appendMatch) {
|
|
3589
|
-
text = appendMatch[1].trim();
|
|
3590
|
-
filePath = appendMatch[2].trim();
|
|
3591
|
-
append = true;
|
|
3592
|
-
} else {
|
|
3593
|
-
text = overwriteMatch[1].trim();
|
|
3594
|
-
filePath = overwriteMatch[2].trim();
|
|
3595
|
-
}
|
|
3596
|
-
if (text.startsWith('"') && text.endsWith('"') || text.startsWith("'") && text.endsWith("'")) {
|
|
3597
|
-
text = text.slice(1, -1);
|
|
3598
|
-
}
|
|
3599
|
-
text = text.replace(/\\([\\nrtv0])/g, (_, ch) => {
|
|
3600
|
-
switch (ch) {
|
|
3601
|
-
case "n":
|
|
3602
|
-
return "\n";
|
|
3603
|
-
case "t":
|
|
3604
|
-
return " ";
|
|
3605
|
-
case "r":
|
|
3606
|
-
return "\r";
|
|
3607
|
-
case "v":
|
|
3608
|
-
return "\v";
|
|
3609
|
-
case "0":
|
|
3610
|
-
return "\0";
|
|
3611
|
-
case "\\":
|
|
3612
|
-
return "\\";
|
|
3613
|
-
default:
|
|
3614
|
-
return ch;
|
|
3615
|
-
}
|
|
3616
|
-
});
|
|
3617
|
-
try {
|
|
3618
|
-
fs.writeFile(filePath, text + "\n", append);
|
|
3619
|
-
await fs.persist();
|
|
3620
|
-
} catch (e) {
|
|
3621
|
-
context.writer.writeError(e.message);
|
|
3622
|
-
}
|
|
4154
|
+
const text = joinShellWords(command.value || "");
|
|
4155
|
+
context.writer.writeln(text);
|
|
4156
|
+
context.process.output(text);
|
|
3623
4157
|
}
|
|
3624
4158
|
};
|
|
3625
4159
|
|
|
@@ -3650,35 +4184,58 @@ var files = (() => {
|
|
|
3650
4184
|
}
|
|
3651
4185
|
];
|
|
3652
4186
|
}
|
|
4187
|
+
writeDescription(context) {
|
|
4188
|
+
const t = context.translator;
|
|
4189
|
+
writeWrapped(
|
|
4190
|
+
context,
|
|
4191
|
+
t.t("cli.rm.help.delete_file_directories_only", "Delete a file. Directories are only removed with -r, which deletes everything inside them. Deleted files cannot be recovered.")
|
|
4192
|
+
);
|
|
4193
|
+
context.writer.writeln();
|
|
4194
|
+
writeUsage(context, [
|
|
4195
|
+
["rm <file...>", t.t("cli.rm.help.delete_one_more_files", "Delete one or more files")],
|
|
4196
|
+
["rm -r <dir>", t.t("cli.rm.help.delete_directory_contents", "Delete a directory and its contents")],
|
|
4197
|
+
["rm -f <file>", t.t("cli.rm.help.delete_without_error_if", "Delete without an error if it is missing")]
|
|
4198
|
+
]);
|
|
4199
|
+
context.writer.writeln();
|
|
4200
|
+
writeExamples(context, [
|
|
4201
|
+
["rm notes.bak", t.t("cli.rm.help.delete_one_file", "Delete one file")],
|
|
4202
|
+
["rm -r old-project", t.t("cli.rm.help.delete_whole_directory", "Delete a whole directory")],
|
|
4203
|
+
["rm -f maybe.txt", t.t("cli.rm.help.quiet_if_file_does", "Quiet if the file does not exist")]
|
|
4204
|
+
]);
|
|
4205
|
+
}
|
|
3653
4206
|
async processCommand(command, context) {
|
|
3654
|
-
const fs = context.services.
|
|
4207
|
+
const fs = context.services.getRequired(
|
|
3655
4208
|
IFileSystemService_TOKEN
|
|
3656
4209
|
);
|
|
3657
|
-
const
|
|
4210
|
+
const paths = splitArgs(command.value || "");
|
|
3658
4211
|
const recursive = command.args["recursive"] || command.args["r"] || command.args["R"];
|
|
3659
4212
|
const force = command.args["force"] || command.args["f"];
|
|
3660
|
-
if (
|
|
3661
|
-
context.writer.writeError("rm: missing operand");
|
|
4213
|
+
if (paths.length === 0) {
|
|
4214
|
+
if (!force) context.writer.writeError("rm: missing operand");
|
|
3662
4215
|
return;
|
|
3663
4216
|
}
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
4217
|
+
let changed = false;
|
|
4218
|
+
for (const path of paths) {
|
|
4219
|
+
try {
|
|
4220
|
+
if (!fs.exists(path)) {
|
|
4221
|
+
if (!force) {
|
|
4222
|
+
context.writer.writeError(
|
|
4223
|
+
`rm: ${path}: No such file or directory`
|
|
4224
|
+
);
|
|
4225
|
+
}
|
|
4226
|
+
continue;
|
|
3670
4227
|
}
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
4228
|
+
if (fs.isDirectory(path) && !recursive) {
|
|
4229
|
+
context.writer.writeError(`rm: ${path}: Is a directory`);
|
|
4230
|
+
continue;
|
|
4231
|
+
}
|
|
4232
|
+
fs.remove(path, recursive);
|
|
4233
|
+
changed = true;
|
|
4234
|
+
} catch (e) {
|
|
4235
|
+
context.writer.writeError(e.message);
|
|
3676
4236
|
}
|
|
3677
|
-
fs.remove(path, recursive);
|
|
3678
|
-
await fs.persist();
|
|
3679
|
-
} catch (e) {
|
|
3680
|
-
context.writer.writeError(e.message);
|
|
3681
4237
|
}
|
|
4238
|
+
if (changed) await fs.persist();
|
|
3682
4239
|
}
|
|
3683
4240
|
};
|
|
3684
4241
|
|
|
@@ -3698,11 +4255,37 @@ var files = (() => {
|
|
|
3698
4255
|
description: "Copy directories recursively",
|
|
3699
4256
|
required: false,
|
|
3700
4257
|
type: "boolean"
|
|
4258
|
+
},
|
|
4259
|
+
{
|
|
4260
|
+
name: "force",
|
|
4261
|
+
aliases: ["f"],
|
|
4262
|
+
description: "Overwrite existing files (always done; accepted for -rf)",
|
|
4263
|
+
required: false,
|
|
4264
|
+
type: "boolean"
|
|
3701
4265
|
}
|
|
3702
4266
|
];
|
|
3703
4267
|
}
|
|
4268
|
+
writeDescription(context) {
|
|
4269
|
+
const t = context.translator;
|
|
4270
|
+
writeWrapped(
|
|
4271
|
+
context,
|
|
4272
|
+
t.t("cli.cp.help.copy_file_new_path", "Copy a file to a new path, or into an existing directory. Copying a directory needs -r, which copies everything inside it. A file already at the destination is replaced.")
|
|
4273
|
+
);
|
|
4274
|
+
context.writer.writeln();
|
|
4275
|
+
writeUsage(context, [
|
|
4276
|
+
["cp <source> <dest>", t.t("cli.cp.help.copy_file_new_name", "Copy a file to a new name")],
|
|
4277
|
+
["cp <source...> <dir>", t.t("cli.cp.help.copy_files_directory", "Copy files into a directory")],
|
|
4278
|
+
["cp -r <dir> <dest>", t.t("cli.cp.help.copy_directory_contents", "Copy a directory and its contents")]
|
|
4279
|
+
]);
|
|
4280
|
+
context.writer.writeln();
|
|
4281
|
+
writeExamples(context, [
|
|
4282
|
+
["cp notes.txt notes.bak", t.t("cli.cp.help.make_backup_copy", "Make a backup copy")],
|
|
4283
|
+
["cp report.txt ~/docs", t.t("cli.cp.help.copy_docs", "Copy into ~/docs")],
|
|
4284
|
+
["cp -r project project-copy", t.t("cli.cp.help.duplicate_whole_directory", "Duplicate a whole directory")]
|
|
4285
|
+
]);
|
|
4286
|
+
}
|
|
3704
4287
|
async processCommand(command, context) {
|
|
3705
|
-
const fs = context.services.
|
|
4288
|
+
const fs = context.services.getRequired(
|
|
3706
4289
|
IFileSystemService_TOKEN
|
|
3707
4290
|
);
|
|
3708
4291
|
const recursive = command.args["recursive"] || command.args["r"] || command.args["R"];
|
|
@@ -3714,18 +4297,26 @@ var files = (() => {
|
|
|
3714
4297
|
);
|
|
3715
4298
|
return;
|
|
3716
4299
|
}
|
|
3717
|
-
const
|
|
3718
|
-
const
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
} catch (e) {
|
|
3723
|
-
context.writer.writeError(e.message);
|
|
4300
|
+
const dest = parts[parts.length - 1];
|
|
4301
|
+
const sources = parts.slice(0, -1);
|
|
4302
|
+
if (sources.length > 1 && !fs.isDirectory(dest)) {
|
|
4303
|
+
context.writer.writeError(`cp: target '${dest}' is not a directory`);
|
|
4304
|
+
return;
|
|
3724
4305
|
}
|
|
4306
|
+
let changed = false;
|
|
4307
|
+
for (const src of sources) {
|
|
4308
|
+
try {
|
|
4309
|
+
fs.copy(src, dest, recursive);
|
|
4310
|
+
changed = true;
|
|
4311
|
+
} catch (e) {
|
|
4312
|
+
context.writer.writeError(e.message);
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
if (changed) await fs.persist();
|
|
3725
4316
|
}
|
|
3726
4317
|
parseArgs(command) {
|
|
3727
4318
|
const raw = command.value || "";
|
|
3728
|
-
return raw
|
|
4319
|
+
return splitArgs(raw).filter(Boolean);
|
|
3729
4320
|
}
|
|
3730
4321
|
};
|
|
3731
4322
|
|
|
@@ -3739,8 +4330,26 @@ var files = (() => {
|
|
|
3739
4330
|
this.acceptsRawInput = true;
|
|
3740
4331
|
this.metadata = { icon: "\u{1F4E6}", module: "file management" };
|
|
3741
4332
|
}
|
|
4333
|
+
writeDescription(context) {
|
|
4334
|
+
const t = context.translator;
|
|
4335
|
+
writeWrapped(
|
|
4336
|
+
context,
|
|
4337
|
+
t.t("cli.mv.help.move_rename_file_directory", "Move or rename a file or directory. If the destination is an existing directory, the source is moved into it; otherwise it is renamed. A file already at the destination is replaced.")
|
|
4338
|
+
);
|
|
4339
|
+
context.writer.writeln();
|
|
4340
|
+
writeUsage(context, [
|
|
4341
|
+
["mv <source> <dest>", t.t("cli.mv.help.rename_file_directory", "Rename a file or directory")],
|
|
4342
|
+
["mv <source...> <dir>", t.t("cli.mv.help.move_them_directory", "Move them into a directory")]
|
|
4343
|
+
]);
|
|
4344
|
+
context.writer.writeln();
|
|
4345
|
+
writeExamples(context, [
|
|
4346
|
+
["mv draft.txt final.txt", t.t("cli.mv.help.rename_file", "Rename a file")],
|
|
4347
|
+
["mv final.txt ~/docs", t.t("cli.mv.help.move_docs", "Move it into ~/docs")],
|
|
4348
|
+
["mv old-dir new-dir", t.t("cli.mv.help.rename_directory", "Rename a directory")]
|
|
4349
|
+
]);
|
|
4350
|
+
}
|
|
3742
4351
|
async processCommand(command, context) {
|
|
3743
|
-
const fs = context.services.
|
|
4352
|
+
const fs = context.services.getRequired(
|
|
3744
4353
|
IFileSystemService_TOKEN
|
|
3745
4354
|
);
|
|
3746
4355
|
const parts = this.parseArgs(command);
|
|
@@ -3749,21 +4358,39 @@ var files = (() => {
|
|
|
3749
4358
|
context.writer.writeln("Usage: mv <source> <destination>");
|
|
3750
4359
|
return;
|
|
3751
4360
|
}
|
|
3752
|
-
const
|
|
3753
|
-
const
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
} catch (e) {
|
|
3758
|
-
context.writer.writeError(e.message);
|
|
4361
|
+
const dest = parts[parts.length - 1];
|
|
4362
|
+
const sources = parts.slice(0, -1);
|
|
4363
|
+
if (sources.length > 1 && !fs.isDirectory(dest)) {
|
|
4364
|
+
context.writer.writeError(`mv: target '${dest}' is not a directory`);
|
|
4365
|
+
return;
|
|
3759
4366
|
}
|
|
4367
|
+
let changed = false;
|
|
4368
|
+
for (const src of sources) {
|
|
4369
|
+
try {
|
|
4370
|
+
fs.move(src, dest);
|
|
4371
|
+
changed = true;
|
|
4372
|
+
} catch (e) {
|
|
4373
|
+
context.writer.writeError(e.message);
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
if (changed) await fs.persist();
|
|
3760
4377
|
}
|
|
3761
4378
|
parseArgs(command) {
|
|
3762
4379
|
const raw = command.value || "";
|
|
3763
|
-
return raw
|
|
4380
|
+
return splitArgs(raw).filter(Boolean);
|
|
3764
4381
|
}
|
|
3765
4382
|
};
|
|
3766
4383
|
|
|
4384
|
+
// src/lib/utils/readable-children.ts
|
|
4385
|
+
function readableChildren(fs, path) {
|
|
4386
|
+
try {
|
|
4387
|
+
return fs.listDirectory(path);
|
|
4388
|
+
} catch (e) {
|
|
4389
|
+
if (isCliAccessDeniedError(e)) return null;
|
|
4390
|
+
throw e;
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
|
|
3767
4394
|
// src/lib/processors/cli-tree-command-processor.ts
|
|
3768
4395
|
var CliTreeCommandProcessor = class {
|
|
3769
4396
|
constructor() {
|
|
@@ -3783,11 +4410,29 @@ var files = (() => {
|
|
|
3783
4410
|
}
|
|
3784
4411
|
];
|
|
3785
4412
|
}
|
|
4413
|
+
writeDescription(context) {
|
|
4414
|
+
const t = context.translator;
|
|
4415
|
+
writeWrapped(
|
|
4416
|
+
context,
|
|
4417
|
+
t.t("cli.tree.help.draw_directory_everything_below", "Draw a directory and everything below it as a tree, directories first, followed by a count of directories and files. Defaults to the current directory.")
|
|
4418
|
+
);
|
|
4419
|
+
context.writer.writeln();
|
|
4420
|
+
writeUsage(context, [
|
|
4421
|
+
["tree [dir]", t.t("cli.tree.help.show_whole_tree", "Show the whole tree")],
|
|
4422
|
+
["tree -L <n> [dir]", t.t("cli.tree.help.only_levels_deep", "Only <n> levels deep")]
|
|
4423
|
+
]);
|
|
4424
|
+
context.writer.writeln();
|
|
4425
|
+
writeExamples(context, [
|
|
4426
|
+
["tree", t.t("cli.tree.help.tree_current_directory", "Tree of the current directory")],
|
|
4427
|
+
["tree ~/docs", t.t("cli.tree.help.tree_docs", "Tree of ~/docs")],
|
|
4428
|
+
["tree -L 2", t.t("cli.tree.help.top_two_levels_only", "Top two levels only")]
|
|
4429
|
+
]);
|
|
4430
|
+
}
|
|
3786
4431
|
async processCommand(command, context) {
|
|
3787
|
-
const fs = context.services.
|
|
4432
|
+
const fs = context.services.getRequired(
|
|
3788
4433
|
IFileSystemService_TOKEN
|
|
3789
4434
|
);
|
|
3790
|
-
const targetPath = command.value || fs.getCurrentDirectory();
|
|
4435
|
+
const targetPath = splitArgs(command.value || "").join(" ") || fs.getCurrentDirectory();
|
|
3791
4436
|
const maxDepth = command.args["depth"] ? parseInt(command.args["depth"]) : command.args["L"] ? parseInt(command.args["L"]) : Infinity;
|
|
3792
4437
|
try {
|
|
3793
4438
|
const node = fs.getNode(targetPath);
|
|
@@ -3811,7 +4456,8 @@ var files = (() => {
|
|
|
3811
4456
|
)
|
|
3812
4457
|
);
|
|
3813
4458
|
const counts = { dirs: 0, files: 0 };
|
|
3814
|
-
this.
|
|
4459
|
+
this.fs = fs;
|
|
4460
|
+
this.printTree(node, "", true, 0, maxDepth, context, counts, resolvedPath);
|
|
3815
4461
|
context.writer.writeln();
|
|
3816
4462
|
context.writer.writeln(
|
|
3817
4463
|
`${counts.dirs} directories, ${counts.files} files`
|
|
@@ -3820,11 +4466,15 @@ var files = (() => {
|
|
|
3820
4466
|
context.writer.writeError(e.message);
|
|
3821
4467
|
}
|
|
3822
4468
|
}
|
|
3823
|
-
printTree(node, prefix, isRoot, depth, maxDepth, context, counts) {
|
|
3824
|
-
if (
|
|
4469
|
+
printTree(node, prefix, isRoot, depth, maxDepth, context, counts, path = "/") {
|
|
4470
|
+
if (depth >= maxDepth) {
|
|
3825
4471
|
return;
|
|
3826
4472
|
}
|
|
3827
|
-
const
|
|
4473
|
+
const visible = this.fs ? readableChildren(this.fs, path) : node.children;
|
|
4474
|
+
if (!visible) {
|
|
4475
|
+
return;
|
|
4476
|
+
}
|
|
4477
|
+
const children = [...visible].sort((a, b) => {
|
|
3828
4478
|
if (a.type !== b.type) {
|
|
3829
4479
|
return a.type === "directory" ? -1 : 1;
|
|
3830
4480
|
}
|
|
@@ -3849,7 +4499,8 @@ var files = (() => {
|
|
|
3849
4499
|
depth + 1,
|
|
3850
4500
|
maxDepth,
|
|
3851
4501
|
context,
|
|
3852
|
-
counts
|
|
4502
|
+
counts,
|
|
4503
|
+
path === "/" ? `/${child.name}` : `${path}/${child.name}`
|
|
3853
4504
|
);
|
|
3854
4505
|
} else {
|
|
3855
4506
|
counts.files++;
|
|
@@ -3878,21 +4529,40 @@ var files = (() => {
|
|
|
3878
4529
|
}
|
|
3879
4530
|
];
|
|
3880
4531
|
}
|
|
4532
|
+
writeDescription(context) {
|
|
4533
|
+
const t = context.translator;
|
|
4534
|
+
writeWrapped(
|
|
4535
|
+
context,
|
|
4536
|
+
t.t("cli.head.help.print_first_lines_file", "Print the first lines of a file, 10 by default. Works on piped input too. With several files, each one gets a ==> name <== header.")
|
|
4537
|
+
);
|
|
4538
|
+
context.writer.writeln();
|
|
4539
|
+
writeUsage(context, [
|
|
4540
|
+
["head <file>", t.t("cli.head.help.first_10_lines", "First 10 lines")],
|
|
4541
|
+
["head -n <count> <file>", t.t("cli.head.help.first_lines", "First <count> lines")],
|
|
4542
|
+
["<command> | head", t.t("cli.head.help.first_lines_piped_input", "First lines of piped input")]
|
|
4543
|
+
]);
|
|
4544
|
+
context.writer.writeln();
|
|
4545
|
+
writeExamples(context, [
|
|
4546
|
+
["head notes.txt", t.t("cli.head.help.show_start_file", "Show the start of a file")],
|
|
4547
|
+
["head -n 3 a.txt b.txt", t.t("cli.head.help.first_3_lines_each", "First 3 lines of each file")],
|
|
4548
|
+
["cat app.log | head -n 20", t.t("cli.head.help.first_20_lines_log", "First 20 lines of the log")]
|
|
4549
|
+
]);
|
|
4550
|
+
}
|
|
3881
4551
|
async processCommand(command, context) {
|
|
3882
|
-
const fs = context.services.
|
|
4552
|
+
const fs = context.services.getRequired(
|
|
3883
4553
|
IFileSystemService_TOKEN
|
|
3884
4554
|
);
|
|
3885
|
-
const
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
);
|
|
4555
|
+
const countArg = command.args["lines"] ?? command.args["n"] ?? Object.keys(command.args).find((k) => /^\d+$/.test(k));
|
|
4556
|
+
const parsedCount = parseInt(String(countArg ?? "10"), 10);
|
|
4557
|
+
const count = isNaN(parsedCount) ? 10 : Math.abs(parsedCount);
|
|
3889
4558
|
const paths = this.parsePaths(command);
|
|
3890
4559
|
if (paths.length === 0) {
|
|
3891
4560
|
if (command.data != null) {
|
|
3892
|
-
const
|
|
3893
|
-
const lines = content.split("\n");
|
|
4561
|
+
const lines = splitLines(pipedText(command.data));
|
|
3894
4562
|
const selected = lines.slice(0, count);
|
|
3895
|
-
|
|
4563
|
+
if (selected.length > 0) {
|
|
4564
|
+
context.writer.writeln(selected.join("\n"));
|
|
4565
|
+
}
|
|
3896
4566
|
return;
|
|
3897
4567
|
}
|
|
3898
4568
|
context.writer.writeError("head: missing file operand");
|
|
@@ -3911,9 +4581,11 @@ var files = (() => {
|
|
|
3911
4581
|
if (i > 0) context.writer.writeln();
|
|
3912
4582
|
context.writer.writeln(`==> ${path} <==`);
|
|
3913
4583
|
}
|
|
3914
|
-
const lines = content
|
|
4584
|
+
const lines = splitLines(content);
|
|
3915
4585
|
const selected = lines.slice(0, count);
|
|
3916
|
-
|
|
4586
|
+
if (selected.length > 0) {
|
|
4587
|
+
context.writer.writeln(selected.join("\n"));
|
|
4588
|
+
}
|
|
3917
4589
|
} catch (e) {
|
|
3918
4590
|
context.writer.writeError(`head: ${e.message}`);
|
|
3919
4591
|
}
|
|
@@ -3921,7 +4593,7 @@ var files = (() => {
|
|
|
3921
4593
|
}
|
|
3922
4594
|
parsePaths(command) {
|
|
3923
4595
|
const raw = command.value || "";
|
|
3924
|
-
return raw
|
|
4596
|
+
return splitArgs(raw).filter(Boolean);
|
|
3925
4597
|
}
|
|
3926
4598
|
};
|
|
3927
4599
|
|
|
@@ -3945,21 +4617,40 @@ var files = (() => {
|
|
|
3945
4617
|
}
|
|
3946
4618
|
];
|
|
3947
4619
|
}
|
|
4620
|
+
writeDescription(context) {
|
|
4621
|
+
const t = context.translator;
|
|
4622
|
+
writeWrapped(
|
|
4623
|
+
context,
|
|
4624
|
+
t.t("cli.tail.help.print_last_lines_file", "Print the last lines of a file, 10 by default. Works on piped input too. With several files, each one gets a ==> name <== header.")
|
|
4625
|
+
);
|
|
4626
|
+
context.writer.writeln();
|
|
4627
|
+
writeUsage(context, [
|
|
4628
|
+
["tail <file>", t.t("cli.tail.help.last_10_lines", "Last 10 lines")],
|
|
4629
|
+
["tail -n <count> <file>", t.t("cli.tail.help.last_lines", "Last <count> lines")],
|
|
4630
|
+
["<command> | tail", t.t("cli.tail.help.last_lines_piped_input", "Last lines of piped input")]
|
|
4631
|
+
]);
|
|
4632
|
+
context.writer.writeln();
|
|
4633
|
+
writeExamples(context, [
|
|
4634
|
+
["tail app.log", t.t("cli.tail.help.show_end_log", "Show the end of a log")],
|
|
4635
|
+
["tail -n 5 notes.txt", t.t("cli.tail.help.last_5_lines", "Last 5 lines")],
|
|
4636
|
+
["cat app.log | tail -n 20", t.t("cli.tail.help.last_20_lines_log", "Last 20 lines of the log")]
|
|
4637
|
+
]);
|
|
4638
|
+
}
|
|
3948
4639
|
async processCommand(command, context) {
|
|
3949
|
-
const fs = context.services.
|
|
4640
|
+
const fs = context.services.getRequired(
|
|
3950
4641
|
IFileSystemService_TOKEN
|
|
3951
4642
|
);
|
|
3952
|
-
const
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
);
|
|
4643
|
+
const countArg = command.args["lines"] ?? command.args["n"] ?? Object.keys(command.args).find((k) => /^\d+$/.test(k));
|
|
4644
|
+
const parsedCount = parseInt(String(countArg ?? "10"), 10);
|
|
4645
|
+
const count = isNaN(parsedCount) ? 10 : Math.abs(parsedCount);
|
|
3956
4646
|
const paths = this.parsePaths(command);
|
|
3957
4647
|
if (paths.length === 0) {
|
|
3958
4648
|
if (command.data != null) {
|
|
3959
|
-
const
|
|
3960
|
-
const
|
|
3961
|
-
|
|
3962
|
-
|
|
4649
|
+
const lines = splitLines(pipedText(command.data));
|
|
4650
|
+
const selected = count > 0 ? lines.slice(-count) : [];
|
|
4651
|
+
if (selected.length > 0) {
|
|
4652
|
+
context.writer.writeln(selected.join("\n"));
|
|
4653
|
+
}
|
|
3963
4654
|
return;
|
|
3964
4655
|
}
|
|
3965
4656
|
context.writer.writeError("tail: missing file operand");
|
|
@@ -3978,9 +4669,11 @@ var files = (() => {
|
|
|
3978
4669
|
if (i > 0) context.writer.writeln();
|
|
3979
4670
|
context.writer.writeln(`==> ${path} <==`);
|
|
3980
4671
|
}
|
|
3981
|
-
const lines = content
|
|
3982
|
-
const selected = lines.slice(-count);
|
|
3983
|
-
|
|
4672
|
+
const lines = splitLines(content);
|
|
4673
|
+
const selected = count > 0 ? lines.slice(-count) : [];
|
|
4674
|
+
if (selected.length > 0) {
|
|
4675
|
+
context.writer.writeln(selected.join("\n"));
|
|
4676
|
+
}
|
|
3984
4677
|
} catch (e) {
|
|
3985
4678
|
context.writer.writeError(`tail: ${e.message}`);
|
|
3986
4679
|
}
|
|
@@ -3988,7 +4681,7 @@ var files = (() => {
|
|
|
3988
4681
|
}
|
|
3989
4682
|
parsePaths(command) {
|
|
3990
4683
|
const raw = command.value || "";
|
|
3991
|
-
return raw
|
|
4684
|
+
return splitArgs(raw).filter(Boolean);
|
|
3992
4685
|
}
|
|
3993
4686
|
};
|
|
3994
4687
|
|
|
@@ -4026,8 +4719,30 @@ var files = (() => {
|
|
|
4026
4719
|
}
|
|
4027
4720
|
];
|
|
4028
4721
|
}
|
|
4722
|
+
writeDescription(context) {
|
|
4723
|
+
const t = context.translator;
|
|
4724
|
+
writeWrapped(
|
|
4725
|
+
context,
|
|
4726
|
+
t.t("cli.wc.help.count_lines_words_characters", "Count lines, words and characters in files or piped input. With several files, a total line is printed at the end.")
|
|
4727
|
+
);
|
|
4728
|
+
context.writer.writeln();
|
|
4729
|
+
writeUsage(context, [
|
|
4730
|
+
["wc <file...>", t.t("cli.wc.help.lines_words_characters", "Lines, words and characters")],
|
|
4731
|
+
["wc -l <file>", t.t("cli.wc.help.only_line_count", "Only the line count")],
|
|
4732
|
+
["<command> | wc", t.t("cli.wc.help.count_piped_input", "Count piped input")]
|
|
4733
|
+
]);
|
|
4734
|
+
context.writer.writeln();
|
|
4735
|
+
writeExamples(context, [
|
|
4736
|
+
["wc notes.txt", t.t("cli.wc.help.all_three_counts", "All three counts")],
|
|
4737
|
+
["wc -l a.txt b.txt", t.t("cli.wc.help.line_counts_total", "Line counts with a total")],
|
|
4738
|
+
[
|
|
4739
|
+
"cat app.log | grep error | wc -l",
|
|
4740
|
+
t.t("cli.wc.help.how_many_lines_mention", "How many lines mention error")
|
|
4741
|
+
]
|
|
4742
|
+
]);
|
|
4743
|
+
}
|
|
4029
4744
|
async processCommand(command, context) {
|
|
4030
|
-
const fs = context.services.
|
|
4745
|
+
const fs = context.services.getRequired(
|
|
4031
4746
|
IFileSystemService_TOKEN
|
|
4032
4747
|
);
|
|
4033
4748
|
const showLines = command.args["lines"] || command.args["l"] || false;
|
|
@@ -4037,10 +4752,9 @@ var files = (() => {
|
|
|
4037
4752
|
const paths = this.parsePaths(command);
|
|
4038
4753
|
if (paths.length === 0) {
|
|
4039
4754
|
if (command.data != null) {
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
const
|
|
4043
|
-
const charCount = content.length;
|
|
4755
|
+
let content = pipedText(command.data);
|
|
4756
|
+
if (content !== "" && !content.endsWith("\n")) content += "\n";
|
|
4757
|
+
const { lineCount, wordCount, charCount } = this.count(content);
|
|
4044
4758
|
const parts = [];
|
|
4045
4759
|
if (showAll || showLines) parts.push(String(lineCount).padStart(8));
|
|
4046
4760
|
if (showAll || showWords) parts.push(String(wordCount).padStart(8));
|
|
@@ -4061,9 +4775,7 @@ var files = (() => {
|
|
|
4061
4775
|
continue;
|
|
4062
4776
|
}
|
|
4063
4777
|
const content = fs.readFile(path) ?? "";
|
|
4064
|
-
const lineCount
|
|
4065
|
-
const wordCount = content.trim() === "" ? 0 : content.trim().split(/\s+/).length;
|
|
4066
|
-
const charCount = content.length;
|
|
4778
|
+
const { lineCount, wordCount, charCount } = this.count(content);
|
|
4067
4779
|
totalLines += lineCount;
|
|
4068
4780
|
totalWords += wordCount;
|
|
4069
4781
|
totalChars += charCount;
|
|
@@ -4086,9 +4798,17 @@ var files = (() => {
|
|
|
4086
4798
|
context.writer.writeln(parts.join(""));
|
|
4087
4799
|
}
|
|
4088
4800
|
}
|
|
4801
|
+
/** Counts like Unix wc: lines are newline characters. */
|
|
4802
|
+
count(content) {
|
|
4803
|
+
return {
|
|
4804
|
+
lineCount: (content.match(/\n/g) ?? []).length,
|
|
4805
|
+
wordCount: content.trim() === "" ? 0 : content.trim().split(/\s+/).length,
|
|
4806
|
+
charCount: content.length
|
|
4807
|
+
};
|
|
4808
|
+
}
|
|
4089
4809
|
parsePaths(command) {
|
|
4090
4810
|
const raw = command.value || "";
|
|
4091
|
-
return raw
|
|
4811
|
+
return splitArgs(raw).filter(Boolean);
|
|
4092
4812
|
}
|
|
4093
4813
|
};
|
|
4094
4814
|
|
|
@@ -4104,7 +4824,13 @@ var files = (() => {
|
|
|
4104
4824
|
this.parameters = [
|
|
4105
4825
|
{
|
|
4106
4826
|
name: "name",
|
|
4107
|
-
description: "Match filename pattern (glob: * and ? supported)",
|
|
4827
|
+
description: "Match filename pattern (glob: * and ? supported), case-sensitive",
|
|
4828
|
+
required: false,
|
|
4829
|
+
type: "string"
|
|
4830
|
+
},
|
|
4831
|
+
{
|
|
4832
|
+
name: "iname",
|
|
4833
|
+
description: "Like --name, but case-insensitive",
|
|
4108
4834
|
required: false,
|
|
4109
4835
|
type: "string"
|
|
4110
4836
|
},
|
|
@@ -4116,20 +4842,42 @@ var files = (() => {
|
|
|
4116
4842
|
},
|
|
4117
4843
|
{
|
|
4118
4844
|
name: "maxdepth",
|
|
4119
|
-
description: "Maximum
|
|
4845
|
+
description: "Maximum depth: 0 is only the start path, 1 its direct children",
|
|
4120
4846
|
required: false,
|
|
4121
4847
|
type: "number"
|
|
4122
4848
|
}
|
|
4123
4849
|
];
|
|
4124
4850
|
}
|
|
4851
|
+
writeDescription(context) {
|
|
4852
|
+
const t = context.translator;
|
|
4853
|
+
writeWrapped(
|
|
4854
|
+
context,
|
|
4855
|
+
t.t("cli.find.help.list_files_directories_under", "List files and directories under a path (the current directory by default), searching all subdirectories. The start path itself is listed first. Filter by name with a glob pattern (* and ?; --name is case-sensitive, --iname is not) or by type.")
|
|
4856
|
+
);
|
|
4857
|
+
context.writer.writeln();
|
|
4858
|
+
writeUsage(context, [
|
|
4859
|
+
["find [path]", t.t("cli.find.help.list_everything_under_path", "List everything under a path")],
|
|
4860
|
+
["find [path] --name <pattern>", t.t("cli.find.help.match_names_against_glob", "Match names against a glob")],
|
|
4861
|
+
["find [path] --iname <pattern>", t.t("cli.find.help.same_ignoring_case", "Same, ignoring case")],
|
|
4862
|
+
["find [path] --type f|d", t.t("cli.find.help.only_files_f_directories", "Only files (f) or directories (d)")]
|
|
4863
|
+
]);
|
|
4864
|
+
context.writer.writeln();
|
|
4865
|
+
writeExamples(context, [
|
|
4866
|
+
["find ~/docs", t.t("cli.find.help.list_everything_docs", "List everything in ~/docs")],
|
|
4867
|
+
['find . --name "*.txt"', t.t("cli.find.help.find_all_txt_files", "Find all .txt files")],
|
|
4868
|
+
["find . --type d --maxdepth 1", t.t("cli.find.help.directories_near_top", "Directories near the top")],
|
|
4869
|
+
['find . --name "*.tmp" | xargs rm', t.t("cli.find.help.delete_all_tmp_files", "Delete all .tmp files")]
|
|
4870
|
+
]);
|
|
4871
|
+
}
|
|
4125
4872
|
async processCommand(command, context) {
|
|
4126
|
-
const fs = context.services.
|
|
4873
|
+
const fs = context.services.getRequired(
|
|
4127
4874
|
IFileSystemService_TOKEN
|
|
4128
4875
|
);
|
|
4129
4876
|
const searchPath = this.parseSearchPath(command) || fs.getCurrentDirectory();
|
|
4130
|
-
const namePattern = command.args["name"] || null;
|
|
4131
4877
|
const typeFilter = command.args["type"] || null;
|
|
4132
|
-
const
|
|
4878
|
+
const maxDepthArg = command.args["maxdepth"];
|
|
4879
|
+
const parsedDepth = parseInt(String(maxDepthArg ?? ""), 10);
|
|
4880
|
+
const maxDepth = maxDepthArg != null && maxDepthArg !== true && !isNaN(parsedDepth) ? parsedDepth : Infinity;
|
|
4133
4881
|
try {
|
|
4134
4882
|
const node = fs.getNode(searchPath);
|
|
4135
4883
|
if (!node) {
|
|
@@ -4138,24 +4886,25 @@ var files = (() => {
|
|
|
4138
4886
|
);
|
|
4139
4887
|
return;
|
|
4140
4888
|
}
|
|
4141
|
-
if (node.type !== "directory") {
|
|
4142
|
-
context.writer.writeError(
|
|
4143
|
-
`find: '${searchPath}': Not a directory`
|
|
4144
|
-
);
|
|
4145
|
-
return;
|
|
4146
|
-
}
|
|
4147
4889
|
const resolvedBase = fs.resolvePath(searchPath);
|
|
4148
|
-
const nameRegex =
|
|
4890
|
+
const nameRegex = this.nameRegex(command);
|
|
4149
4891
|
const results = [];
|
|
4150
|
-
this.
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4892
|
+
this.fs = fs;
|
|
4893
|
+
const baseName = resolvedBase.split("/").filter(Boolean).pop() ?? "/";
|
|
4894
|
+
if (this.matches(baseName, node.type, nameRegex, typeFilter)) {
|
|
4895
|
+
results.push(resolvedBase);
|
|
4896
|
+
}
|
|
4897
|
+
if (node.type === "directory" && maxDepth > 0) {
|
|
4898
|
+
this.walk(
|
|
4899
|
+
node,
|
|
4900
|
+
resolvedBase,
|
|
4901
|
+
1,
|
|
4902
|
+
maxDepth,
|
|
4903
|
+
nameRegex,
|
|
4904
|
+
typeFilter,
|
|
4905
|
+
results
|
|
4906
|
+
);
|
|
4907
|
+
}
|
|
4159
4908
|
for (const r of results) {
|
|
4160
4909
|
context.writer.writeln(r);
|
|
4161
4910
|
}
|
|
@@ -4163,31 +4912,41 @@ var files = (() => {
|
|
|
4163
4912
|
context.writer.writeError(`find: ${e.message}`);
|
|
4164
4913
|
}
|
|
4165
4914
|
}
|
|
4915
|
+
/** `--name` matches case-sensitively, `--iname` ignoring case. */
|
|
4916
|
+
nameRegex(command) {
|
|
4917
|
+
const name = command.args["name"];
|
|
4918
|
+
if (name != null && name !== true) {
|
|
4919
|
+
return this.globToRegex(String(name), false);
|
|
4920
|
+
}
|
|
4921
|
+
const iname = command.args["iname"];
|
|
4922
|
+
if (iname != null && iname !== true) {
|
|
4923
|
+
return this.globToRegex(String(iname), true);
|
|
4924
|
+
}
|
|
4925
|
+
return null;
|
|
4926
|
+
}
|
|
4927
|
+
matches(name, type, nameRegex, typeFilter) {
|
|
4928
|
+
if (nameRegex && !nameRegex.test(name)) return false;
|
|
4929
|
+
if (typeFilter === "f" && type !== "file") return false;
|
|
4930
|
+
if (typeFilter === "d" && type !== "directory") return false;
|
|
4931
|
+
return true;
|
|
4932
|
+
}
|
|
4166
4933
|
parseSearchPath(command) {
|
|
4167
4934
|
const raw = command.value || "";
|
|
4168
|
-
const tokens = raw
|
|
4935
|
+
const tokens = splitArgs(raw).filter(Boolean);
|
|
4169
4936
|
return tokens.length > 0 ? tokens[0] : null;
|
|
4170
4937
|
}
|
|
4171
|
-
globToRegex(pattern) {
|
|
4938
|
+
globToRegex(pattern, ignoreCase) {
|
|
4172
4939
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
4173
4940
|
const regexStr = escaped.replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
4174
|
-
return new RegExp(`^${regexStr}$`, "i");
|
|
4941
|
+
return new RegExp(`^${regexStr}$`, ignoreCase ? "i" : "");
|
|
4175
4942
|
}
|
|
4943
|
+
/** Lists the children of `node`, which are at `depth` (1 = direct children). */
|
|
4176
4944
|
walk(node, currentPath, depth, maxDepth, nameRegex, typeFilter, results) {
|
|
4177
|
-
|
|
4178
|
-
|
|
4945
|
+
const children = this.fs ? readableChildren(this.fs, currentPath) : node.children;
|
|
4946
|
+
if (!children) return;
|
|
4947
|
+
for (const child of children) {
|
|
4179
4948
|
const childPath = currentPath === "/" ? `/${child.name}` : `${currentPath}/${child.name}`;
|
|
4180
|
-
|
|
4181
|
-
if (nameRegex && !nameRegex.test(child.name)) {
|
|
4182
|
-
matches = false;
|
|
4183
|
-
}
|
|
4184
|
-
if (typeFilter === "f" && child.type !== "file") {
|
|
4185
|
-
matches = false;
|
|
4186
|
-
}
|
|
4187
|
-
if (typeFilter === "d" && child.type !== "directory") {
|
|
4188
|
-
matches = false;
|
|
4189
|
-
}
|
|
4190
|
-
if (matches) {
|
|
4949
|
+
if (this.matches(child.name, child.type, nameRegex, typeFilter)) {
|
|
4191
4950
|
results.push(childPath);
|
|
4192
4951
|
}
|
|
4193
4952
|
if (child.type === "directory" && depth < maxDepth) {
|
|
@@ -4243,6 +5002,13 @@ var files = (() => {
|
|
|
4243
5002
|
required: false,
|
|
4244
5003
|
type: "boolean"
|
|
4245
5004
|
},
|
|
5005
|
+
{
|
|
5006
|
+
name: "quiet",
|
|
5007
|
+
aliases: ["q"],
|
|
5008
|
+
description: "Print nothing; only the exit status tells whether a line matched",
|
|
5009
|
+
required: false,
|
|
5010
|
+
type: "boolean"
|
|
5011
|
+
},
|
|
4246
5012
|
{
|
|
4247
5013
|
name: "files-with-matches",
|
|
4248
5014
|
aliases: ["l"],
|
|
@@ -4256,11 +5022,52 @@ var files = (() => {
|
|
|
4256
5022
|
description: "Select non-matching lines",
|
|
4257
5023
|
required: false,
|
|
4258
5024
|
type: "boolean"
|
|
5025
|
+
},
|
|
5026
|
+
{
|
|
5027
|
+
name: "word-regexp",
|
|
5028
|
+
aliases: ["w"],
|
|
5029
|
+
description: "Match only whole words",
|
|
5030
|
+
required: false,
|
|
5031
|
+
type: "boolean"
|
|
5032
|
+
},
|
|
5033
|
+
{
|
|
5034
|
+
name: "only-matching",
|
|
5035
|
+
aliases: ["o"],
|
|
5036
|
+
description: "Print only the matched parts, one per line",
|
|
5037
|
+
required: false,
|
|
5038
|
+
type: "boolean"
|
|
5039
|
+
},
|
|
5040
|
+
{
|
|
5041
|
+
name: "extended-regexp",
|
|
5042
|
+
aliases: ["E"],
|
|
5043
|
+
description: "Extended regular expressions (patterns always are)",
|
|
5044
|
+
required: false,
|
|
5045
|
+
type: "boolean"
|
|
4259
5046
|
}
|
|
4260
5047
|
];
|
|
4261
5048
|
}
|
|
5049
|
+
writeDescription(context) {
|
|
5050
|
+
const t = context.translator;
|
|
5051
|
+
writeWrapped(
|
|
5052
|
+
context,
|
|
5053
|
+
t.t("cli.grep.help.print_lines_match_pattern", "Print the lines that match a pattern. The pattern is a regular expression, matches are highlighted, and the input can be files, directories (with -r) or piped text.")
|
|
5054
|
+
);
|
|
5055
|
+
context.writer.writeln();
|
|
5056
|
+
writeUsage(context, [
|
|
5057
|
+
["grep <pattern> <file...>", t.t("cli.grep.help.search_one_more_files", "Search one or more files")],
|
|
5058
|
+
["grep -r <pattern> <dir>", t.t("cli.grep.help.search_every_file_under", "Search every file under a directory")],
|
|
5059
|
+
["<command> | grep <pattern>", t.t("cli.grep.help.filter_piped_input", "Filter piped input")]
|
|
5060
|
+
]);
|
|
5061
|
+
context.writer.writeln();
|
|
5062
|
+
writeExamples(context, [
|
|
5063
|
+
["grep -i error app.log", t.t("cli.grep.help.case_insensitive_search", "Case-insensitive search")],
|
|
5064
|
+
["grep -r -n TODO src", t.t("cli.grep.help.find_todos_line_numbers", "Find TODOs with line numbers")],
|
|
5065
|
+
["grep -v ^# config.txt", t.t("cli.grep.help.hide_comment_lines", "Hide comment lines")],
|
|
5066
|
+
["cat app.log | grep -c ERROR", t.t("cli.grep.help.count_matching_lines", "Count matching lines")]
|
|
5067
|
+
]);
|
|
5068
|
+
}
|
|
4262
5069
|
async processCommand(command, context) {
|
|
4263
|
-
const fs = context.services.
|
|
5070
|
+
const fs = context.services.getRequired(
|
|
4264
5071
|
IFileSystemService_TOKEN
|
|
4265
5072
|
);
|
|
4266
5073
|
const ignoreCase = command.args["ignore-case"] || command.args["i"] || false;
|
|
@@ -4269,51 +5076,56 @@ var files = (() => {
|
|
|
4269
5076
|
const countOnly = command.args["count"] || command.args["c"] || false;
|
|
4270
5077
|
const filesOnly = command.args["files-with-matches"] || command.args["l"] || false;
|
|
4271
5078
|
const invert = command.args["invert-match"] || command.args["v"] || false;
|
|
5079
|
+
const wordRegexp = command.args["word-regexp"] || command.args["w"] || false;
|
|
5080
|
+
const onlyMatching = command.args["only-matching"] || command.args["o"] || false;
|
|
5081
|
+
const quiet = command.args["quiet"] || command.args["q"] || false;
|
|
4272
5082
|
const { pattern, paths } = this.parseArgs(command);
|
|
4273
5083
|
if (!pattern) {
|
|
4274
5084
|
context.writer.writeError(
|
|
4275
5085
|
"grep: missing pattern. Usage: grep [options] <pattern> <file>"
|
|
4276
5086
|
);
|
|
5087
|
+
context.process.exit(2, { silent: true });
|
|
5088
|
+
return;
|
|
5089
|
+
}
|
|
5090
|
+
let regex;
|
|
5091
|
+
try {
|
|
5092
|
+
const source = wordRegexp ? `(?<!\\w)(?:${pattern})(?!\\w)` : pattern;
|
|
5093
|
+
regex = new RegExp(source, ignoreCase ? "gi" : "g");
|
|
5094
|
+
} catch {
|
|
5095
|
+
context.writer.writeError(`grep: invalid pattern '${pattern}'`);
|
|
5096
|
+
context.process.exit(2, { silent: true });
|
|
4277
5097
|
return;
|
|
4278
5098
|
}
|
|
4279
5099
|
if (paths.length === 0) {
|
|
4280
5100
|
if (command.data != null) {
|
|
4281
|
-
let regex2;
|
|
4282
|
-
try {
|
|
4283
|
-
regex2 = new RegExp(pattern, ignoreCase ? "gi" : "g");
|
|
4284
|
-
} catch {
|
|
4285
|
-
context.writer.writeError(`grep: invalid pattern '${pattern}'`);
|
|
4286
|
-
return;
|
|
4287
|
-
}
|
|
4288
5101
|
const content = typeof command.data === "string" ? command.data : JSON.stringify(command.data);
|
|
4289
|
-
this.grepContent(content, null,
|
|
5102
|
+
const found2 = this.grepContent(content, null, regex, {
|
|
4290
5103
|
ignoreCase,
|
|
4291
5104
|
showLineNum,
|
|
4292
5105
|
countOnly,
|
|
4293
5106
|
filesOnly,
|
|
4294
|
-
invert
|
|
5107
|
+
invert,
|
|
5108
|
+
onlyMatching,
|
|
5109
|
+
quiet
|
|
4295
5110
|
}, context, false);
|
|
5111
|
+
this.exitStatus(context, found2, false);
|
|
4296
5112
|
return;
|
|
4297
5113
|
}
|
|
4298
5114
|
context.writer.writeError(
|
|
4299
5115
|
"grep: missing file operand. Usage: grep [options] <pattern> <file>"
|
|
4300
5116
|
);
|
|
4301
|
-
|
|
4302
|
-
}
|
|
4303
|
-
let regex;
|
|
4304
|
-
try {
|
|
4305
|
-
regex = new RegExp(pattern, ignoreCase ? "gi" : "g");
|
|
4306
|
-
} catch {
|
|
4307
|
-
context.writer.writeError(`grep: invalid pattern '${pattern}'`);
|
|
5117
|
+
context.process.exit(2, { silent: true });
|
|
4308
5118
|
return;
|
|
4309
5119
|
}
|
|
4310
5120
|
const filePaths = [];
|
|
5121
|
+
let failed = false;
|
|
4311
5122
|
for (const p of paths) {
|
|
4312
5123
|
try {
|
|
4313
5124
|
if (!fs.exists(p)) {
|
|
4314
5125
|
context.writer.writeError(
|
|
4315
5126
|
`grep: ${p}: No such file or directory`
|
|
4316
5127
|
);
|
|
5128
|
+
failed = true;
|
|
4317
5129
|
continue;
|
|
4318
5130
|
}
|
|
4319
5131
|
if (fs.isDirectory(p)) {
|
|
@@ -4321,6 +5133,7 @@ var files = (() => {
|
|
|
4321
5133
|
context.writer.writeError(
|
|
4322
5134
|
`grep: ${p}: Is a directory`
|
|
4323
5135
|
);
|
|
5136
|
+
failed = true;
|
|
4324
5137
|
continue;
|
|
4325
5138
|
}
|
|
4326
5139
|
this.collectFiles(fs, fs.resolvePath(p), fs.getNode(p), filePaths);
|
|
@@ -4329,26 +5142,40 @@ var files = (() => {
|
|
|
4329
5142
|
}
|
|
4330
5143
|
} catch (e) {
|
|
4331
5144
|
context.writer.writeError(`grep: ${e.message}`);
|
|
5145
|
+
failed = true;
|
|
4332
5146
|
}
|
|
4333
5147
|
}
|
|
4334
5148
|
const multiFile = filePaths.length > 1;
|
|
5149
|
+
let found = 0;
|
|
4335
5150
|
for (const filePath of filePaths) {
|
|
4336
5151
|
try {
|
|
4337
5152
|
const content = fs.readFile(filePath) ?? "";
|
|
4338
|
-
this.grepContent(content, filePath, regex, {
|
|
5153
|
+
found += this.grepContent(content, filePath, regex, {
|
|
4339
5154
|
ignoreCase,
|
|
4340
5155
|
showLineNum,
|
|
4341
5156
|
countOnly,
|
|
4342
5157
|
filesOnly,
|
|
4343
|
-
invert
|
|
5158
|
+
invert,
|
|
5159
|
+
onlyMatching,
|
|
5160
|
+
quiet
|
|
4344
5161
|
}, context, multiFile);
|
|
4345
5162
|
} catch (e) {
|
|
4346
5163
|
context.writer.writeError(`grep: ${filePath}: ${e.message}`);
|
|
5164
|
+
failed = true;
|
|
4347
5165
|
}
|
|
4348
5166
|
}
|
|
5167
|
+
this.exitStatus(context, found, failed);
|
|
5168
|
+
}
|
|
5169
|
+
/**
|
|
5170
|
+
* As Unix grep: 0 when a line matched, 1 when none did, 2 after an
|
|
5171
|
+
* error (so `if grep -q ...` and `grep x f && ...` work).
|
|
5172
|
+
*/
|
|
5173
|
+
exitStatus(context, found, failed) {
|
|
5174
|
+
if (found > 0) return;
|
|
5175
|
+
context.process.exit(failed ? 2 : 1, { silent: true });
|
|
4349
5176
|
}
|
|
4350
5177
|
grepContent(content, filePath, regex, options, context, multiFile) {
|
|
4351
|
-
const lines = content
|
|
5178
|
+
const lines = splitLines(content);
|
|
4352
5179
|
let matchCount = 0;
|
|
4353
5180
|
const matchingLines = [];
|
|
4354
5181
|
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
@@ -4361,6 +5188,7 @@ var files = (() => {
|
|
|
4361
5188
|
matchingLines.push({ num: lineIdx + 1, text: line });
|
|
4362
5189
|
}
|
|
4363
5190
|
}
|
|
5191
|
+
if (options.quiet) return matchCount;
|
|
4364
5192
|
if (options.filesOnly) {
|
|
4365
5193
|
if (matchCount > 0 && filePath) {
|
|
4366
5194
|
context.writer.writeln(filePath);
|
|
@@ -4379,6 +5207,18 @@ var files = (() => {
|
|
|
4379
5207
|
parts.push(context.writer.wrapInColor(String(m.num), CliForegroundColor.Green));
|
|
4380
5208
|
parts.push(":");
|
|
4381
5209
|
}
|
|
5210
|
+
if (options.onlyMatching && !options.invert) {
|
|
5211
|
+
regex.lastIndex = 0;
|
|
5212
|
+
const prefix = parts.join("");
|
|
5213
|
+
for (const match of m.text.match(regex) ?? []) {
|
|
5214
|
+
if (match !== "") {
|
|
5215
|
+
context.writer.writeln(
|
|
5216
|
+
prefix + context.writer.wrapInColor(match, CliForegroundColor.Red)
|
|
5217
|
+
);
|
|
5218
|
+
}
|
|
5219
|
+
}
|
|
5220
|
+
continue;
|
|
5221
|
+
}
|
|
4382
5222
|
if (!options.invert) {
|
|
4383
5223
|
regex.lastIndex = 0;
|
|
4384
5224
|
const highlighted = m.text.replace(
|
|
@@ -4392,10 +5232,11 @@ var files = (() => {
|
|
|
4392
5232
|
context.writer.writeln(parts.join(""));
|
|
4393
5233
|
}
|
|
4394
5234
|
}
|
|
5235
|
+
return matchCount;
|
|
4395
5236
|
}
|
|
4396
5237
|
parseArgs(command) {
|
|
4397
5238
|
const raw = command.value || "";
|
|
4398
|
-
const tokens = raw
|
|
5239
|
+
const tokens = splitArgs(raw).filter(Boolean);
|
|
4399
5240
|
if (tokens.length === 0) {
|
|
4400
5241
|
return { pattern: null, paths: [] };
|
|
4401
5242
|
}
|
|
@@ -4408,8 +5249,9 @@ var files = (() => {
|
|
|
4408
5249
|
};
|
|
4409
5250
|
}
|
|
4410
5251
|
collectFiles(fs, basePath, node, result) {
|
|
4411
|
-
|
|
4412
|
-
|
|
5252
|
+
const children = readableChildren(fs, basePath);
|
|
5253
|
+
if (!children) return;
|
|
5254
|
+
for (const child of children) {
|
|
4413
5255
|
const childPath = basePath === "/" ? `/${child.name}` : `${basePath}/${child.name}`;
|
|
4414
5256
|
if (child.type === "file") {
|
|
4415
5257
|
result.push(childPath);
|
|
@@ -4441,17 +5283,14 @@ var files = (() => {
|
|
|
4441
5283
|
];
|
|
4442
5284
|
}
|
|
4443
5285
|
async processCommand(command, context) {
|
|
4444
|
-
const fs = context.services.
|
|
5286
|
+
const fs = context.services.getRequired(
|
|
4445
5287
|
IFileSystemService_TOKEN
|
|
4446
5288
|
);
|
|
4447
|
-
let
|
|
4448
|
-
if (
|
|
4449
|
-
|
|
4450
|
-
const firstSpace = raw.indexOf(" ");
|
|
4451
|
-
if (firstSpace > -1) {
|
|
4452
|
-
filePath = raw.slice(firstSpace + 1).trim();
|
|
4453
|
-
}
|
|
5289
|
+
let words = splitArgs(command.value || "");
|
|
5290
|
+
if (words.length === 0 && command.rawCommand) {
|
|
5291
|
+
words = splitArgs(command.rawCommand).slice(1).filter((w) => !w.startsWith("-"));
|
|
4454
5292
|
}
|
|
5293
|
+
const filePath = words[0] ?? "";
|
|
4455
5294
|
if (!filePath) {
|
|
4456
5295
|
context.writer.writeError("sh: missing file operand");
|
|
4457
5296
|
context.process.exit(1, { silent: true });
|
|
@@ -4484,10 +5323,10 @@ var files = (() => {
|
|
|
4484
5323
|
await executeScript(content, context);
|
|
4485
5324
|
}
|
|
4486
5325
|
writeDescription(context) {
|
|
4487
|
-
const { writer } = context;
|
|
4488
|
-
writer.writeln(this.description);
|
|
5326
|
+
const { writer, translator: t } = context;
|
|
5327
|
+
writer.writeln(t.t("cli.sh.description", this.description));
|
|
4489
5328
|
writer.writeln();
|
|
4490
|
-
writer.writeln("Usage:");
|
|
5329
|
+
writer.writeln(t.t("cli.common.usage", "Usage:"));
|
|
4491
5330
|
writer.writeln(
|
|
4492
5331
|
` ${writer.wrapInColor("sh <script.sh>", CliForegroundColor.Cyan)}`
|
|
4493
5332
|
);
|
|
@@ -4498,80 +5337,53 @@ var files = (() => {
|
|
|
4498
5337
|
` ${writer.wrapInColor(". <script.sh>", CliForegroundColor.Cyan)}`
|
|
4499
5338
|
);
|
|
4500
5339
|
writer.writeln(
|
|
4501
|
-
` ${writer.wrapInColor("./script.sh", CliForegroundColor.Cyan)} (requires execute permission)`
|
|
5340
|
+
` ${writer.wrapInColor("./script.sh", CliForegroundColor.Cyan)} ${t.t("cli.sh.help.requires_execute", "(requires execute permission)")}`
|
|
4502
5341
|
);
|
|
4503
5342
|
writer.writeln();
|
|
4504
|
-
writer.writeln("Script syntax:");
|
|
4505
|
-
writer.writeln(
|
|
4506
|
-
writer.writeln(
|
|
4507
|
-
writer.writeln(
|
|
4508
|
-
writer.writeln(
|
|
4509
|
-
writer.writeln(
|
|
5343
|
+
writer.writeln(t.t("cli.sh.help.script_syntax", "Script syntax:"));
|
|
5344
|
+
writer.writeln(` # ${t.t("cli.sh.help.comments", "Lines starting with # are comments")}`);
|
|
5345
|
+
writer.writeln(` cmd1; cmd2 # ${t.t("cli.sh.help.several_commands", "Several commands on one line")}`);
|
|
5346
|
+
writer.writeln(` VAR=value # ${t.t("cli.sh.help.assignment", "Variable assignment")}`);
|
|
5347
|
+
writer.writeln(` echo $VAR # ${t.t("cli.sh.help.substitution", "Variable substitution")}`);
|
|
5348
|
+
writer.writeln(` set -e # ${t.t("cli.sh.help.stop_on_error", "Stop on error (default)")}`);
|
|
5349
|
+
writer.writeln(` set +e # ${t.t("cli.sh.help.continue_on_errors", "Continue on errors")}`);
|
|
5350
|
+
writer.writeln(` exit [n] # ${t.t("cli.sh.help.exit", "Stop the script with status n")}`);
|
|
5351
|
+
writer.writeln();
|
|
5352
|
+
writer.writeln(t.t("cli.sh.help.control_flow", "Control flow:"));
|
|
5353
|
+
writer.writeln(" if cmd; then ...; elif cmd; then ...; else ...; fi");
|
|
5354
|
+
writer.writeln(" for NAME in a b *.txt; do ...; done");
|
|
5355
|
+
writer.writeln(` while cmd; do ...; done ${t.t("cli.sh.help.until", "(until cmd: the opposite)")}`);
|
|
5356
|
+
writer.writeln(` break / continue [n] # ${t.t("cli.sh.help.break_continue", "Leave / skip in a loop")}`);
|
|
5357
|
+
writer.writeln(` ! cmd # ${t.t("cli.sh.help.negate", "Negate the exit status")}`);
|
|
5358
|
+
writer.writeln(
|
|
5359
|
+
` ${t.t("cli.sh.help.conditions", "Conditions are commands:")} ${writer.wrapInColor("[ -f file ]", CliForegroundColor.Cyan)}, ${writer.wrapInColor('test "$A" = b', CliForegroundColor.Cyan)}, ${writer.wrapInColor("true", CliForegroundColor.Cyan)}, ${writer.wrapInColor("grep x file", CliForegroundColor.Cyan)}`
|
|
5360
|
+
);
|
|
5361
|
+
writer.writeln(` ${t.t("cli.sh.help.conditions_status", "(status 0 = true; see help test). Loops stop after 10000 iterations")}`);
|
|
5362
|
+
writer.writeln(` ${t.t("cli.sh.help.conditions_loops", "of while/until; Ctrl+C stops the script.")}`);
|
|
4510
5363
|
writer.writeln();
|
|
4511
|
-
writer.writeln("Example script:");
|
|
5364
|
+
writer.writeln(t.t("cli.sh.help.example_script", "Example script:"));
|
|
4512
5365
|
writer.writeln(
|
|
4513
5366
|
writer.wrapInColor(
|
|
4514
|
-
" #!/bin/sh\n # Setup script\n NAME=world\n echo Hello $NAME\n mkdir -p /tmp/test\n echo done > /tmp/test/status.txt",
|
|
5367
|
+
" #!/bin/sh\n # Setup script\n NAME=world\n echo Hello $NAME\n mkdir -p /tmp/test\n for f in a b c; do\n echo $f > /tmp/test/$f.txt\n done\n if [ -f /tmp/test/a.txt ]; then\n echo done > /tmp/test/status.txt\n fi",
|
|
4515
5368
|
CliForegroundColor.Green
|
|
4516
5369
|
)
|
|
4517
5370
|
);
|
|
4518
5371
|
}
|
|
4519
5372
|
};
|
|
5373
|
+
var SCRIPT_RUNNER_TOKEN = "cli-script-runner";
|
|
4520
5374
|
async function executeScript(content, context) {
|
|
4521
|
-
const
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
if (!line || line.startsWith("#")) {
|
|
4527
|
-
continue;
|
|
4528
|
-
}
|
|
4529
|
-
if (line === "set -e") {
|
|
4530
|
-
stopOnError = true;
|
|
4531
|
-
continue;
|
|
4532
|
-
}
|
|
4533
|
-
if (line === "set +e") {
|
|
4534
|
-
stopOnError = false;
|
|
4535
|
-
continue;
|
|
4536
|
-
}
|
|
4537
|
-
const assignMatch = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
4538
|
-
if (assignMatch) {
|
|
4539
|
-
const varName = assignMatch[1];
|
|
4540
|
-
let varValue = assignMatch[2];
|
|
4541
|
-
if (varValue.startsWith('"') && varValue.endsWith('"') || varValue.startsWith("'") && varValue.endsWith("'")) {
|
|
4542
|
-
varValue = varValue.slice(1, -1);
|
|
4543
|
-
}
|
|
4544
|
-
varValue = substituteVariables(varValue, variables);
|
|
4545
|
-
variables[varName] = varValue;
|
|
4546
|
-
continue;
|
|
4547
|
-
}
|
|
4548
|
-
const expanded = substituteVariables(line, variables);
|
|
4549
|
-
await context.executor.executeCommand(expanded, context);
|
|
4550
|
-
const exitCode = context.process.exitCode;
|
|
4551
|
-
if (stopOnError && exitCode !== void 0 && exitCode !== 0) {
|
|
4552
|
-
context.writer.writeError(
|
|
4553
|
-
`sh: script aborted at line: ${line}`
|
|
4554
|
-
);
|
|
4555
|
-
return;
|
|
4556
|
-
}
|
|
5375
|
+
const runner = context.services.get(SCRIPT_RUNNER_TOKEN);
|
|
5376
|
+
if (!runner) {
|
|
5377
|
+
context.writer.writeError("sh: script runner not available (update @qodalis/cli)");
|
|
5378
|
+
context.process.exit(1, { silent: true });
|
|
5379
|
+
return;
|
|
4557
5380
|
}
|
|
4558
|
-
|
|
4559
|
-
function substituteVariables(input, variables) {
|
|
4560
|
-
let result = input.replace(
|
|
4561
|
-
/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,
|
|
4562
|
-
(_, name) => variables[name] ?? ""
|
|
4563
|
-
);
|
|
4564
|
-
result = result.replace(
|
|
4565
|
-
/\$([A-Za-z_][A-Za-z0-9_]*)/g,
|
|
4566
|
-
(_, name) => variables[name] ?? ""
|
|
4567
|
-
);
|
|
4568
|
-
return result;
|
|
5381
|
+
await runner.run(content, context, { name: "sh" });
|
|
4569
5382
|
}
|
|
4570
5383
|
|
|
4571
5384
|
// src/cli-entrypoint.ts
|
|
4572
|
-
var fsService = new IndexedDbFileSystemService();
|
|
4573
5385
|
var module = {
|
|
4574
|
-
apiVersion:
|
|
5386
|
+
apiVersion: API_VERSION2,
|
|
4575
5387
|
name: "@qodalis/cli-files",
|
|
4576
5388
|
processors: [
|
|
4577
5389
|
new CliLsCommandProcessor(),
|
|
@@ -4596,16 +5408,17 @@ var files = (() => {
|
|
|
4596
5408
|
services: [
|
|
4597
5409
|
{
|
|
4598
5410
|
provide: IFileSystemService_TOKEN,
|
|
4599
|
-
|
|
5411
|
+
useClass: IndexedDbFileSystemService
|
|
4600
5412
|
},
|
|
4601
5413
|
{
|
|
4602
5414
|
provide: ICliCompletionProvider_TOKEN,
|
|
4603
|
-
|
|
5415
|
+
useClass: FilePathCompletionProvider,
|
|
5416
|
+
deps: [IFileSystemService_TOKEN],
|
|
4604
5417
|
multi: true
|
|
4605
5418
|
}
|
|
4606
5419
|
],
|
|
4607
5420
|
async onInit(context) {
|
|
4608
|
-
const fs = context.services.
|
|
5421
|
+
const fs = context.services.getRequired(
|
|
4609
5422
|
IFileSystemService_TOKEN
|
|
4610
5423
|
);
|
|
4611
5424
|
await fs.initialize();
|