@jujulego/jill 2.4.0-alpha.2 → 2.4.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1152 @@
1
+ import { Logger, withLabel } from '@jujulego/logger';
2
+ import { S as Service, v as TASK_MANAGER, o as lazyInject, C as CONFIG, n as container, r as CommandTask, u as ScriptTask, M as Middleware, F as ContextService, m as CURRENT, p as lazyInjectNamed, E as ExitException, j as getRegistry, l as setModule } from './ink-command-SIxVoU_e.js';
3
+ import { inject, injectable, ContainerModule, id } from 'inversify';
4
+ import symbols from 'log-symbols';
5
+ import path from 'node:path';
6
+ import { satisfies } from 'semver';
7
+ import { off$, once$, iterate$ } from '@jujulego/event-tree';
8
+ import { SpawnTask, ParallelGroup, FallbackGroup, SequenceGroup } from '@jujulego/tasks';
9
+ import { Lock } from '@jujulego/utils';
10
+ import { Glob } from 'glob';
11
+ import fs from 'node:fs';
12
+ import normalize from 'normalize-package-data';
13
+ import { PathScurry } from 'path-scurry';
14
+ import fs$1 from 'node:fs/promises';
15
+ import moo from 'moo';
16
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
17
+ import { Text, Newline } from 'ink';
18
+ import { useState, useEffect } from 'react';
19
+
20
+ // Utils
21
+ async function* combine(...generators) {
22
+ for (const gen of generators){
23
+ yield* gen;
24
+ }
25
+ }
26
+ async function* streamLines(task, stream) {
27
+ // Abort
28
+ const off = off$();
29
+ once$(task, "completed", off);
30
+ // Stream
31
+ let current = "";
32
+ try {
33
+ for await (const chunk of iterate$(task, `stream.${stream}`, {
34
+ off
35
+ })){
36
+ const data = current + chunk.data.toString("utf-8");
37
+ const lines = data.split(/\r?\n/);
38
+ current = lines.pop() ?? "";
39
+ for (const line of lines){
40
+ yield line;
41
+ }
42
+ }
43
+ } catch (err) {
44
+ if (err.message !== "Unsubscribed !") {
45
+ throw err;
46
+ }
47
+ if (current) {
48
+ yield current;
49
+ }
50
+ }
51
+ }
52
+
53
+ function _ts_decorate$7(decorators, target, key, desc) {
54
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
55
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
56
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
57
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
58
+ }
59
+ function _ts_param$4(paramIndex, decorator) {
60
+ return function(target, key) {
61
+ decorator(target, key, paramIndex);
62
+ };
63
+ }
64
+ let GitService = class GitService {
65
+ // Constructor
66
+ constructor(manager, logger){
67
+ this.manager = manager;
68
+ this.logger = logger;
69
+ }
70
+ // Methods
71
+ /**
72
+ * Runs a git command inside a SpawnTask
73
+ *
74
+ * @param cmd
75
+ * @param args
76
+ * @param options
77
+ */ command(cmd, args, options = {}) {
78
+ const opts = {
79
+ logger: this.logger,
80
+ ...options
81
+ };
82
+ // Create task
83
+ const task = new SpawnTask("git", [
84
+ cmd,
85
+ ...args
86
+ ], {
87
+ command: cmd,
88
+ hidden: true
89
+ }, opts);
90
+ task.on("stream", ({ data })=>opts.logger.debug(data.toString("utf-8")));
91
+ this.manager.add(task);
92
+ return task;
93
+ }
94
+ /**
95
+ * Runs git branch
96
+ *
97
+ * @param args
98
+ * @param options
99
+ */ branch(args, options) {
100
+ return this.command("branch", args, options);
101
+ }
102
+ /**
103
+ * Runs git diff
104
+ *
105
+ * @param args
106
+ * @param options
107
+ */ diff(args, options) {
108
+ return this.command("diff", args, options);
109
+ }
110
+ /**
111
+ * Runs git tag
112
+ *
113
+ * @param args
114
+ * @param options
115
+ */ tag(args, options) {
116
+ return this.command("tag", args, options);
117
+ }
118
+ /**
119
+ * Uses git diff to detect if given files have been affected since given reference
120
+ *
121
+ * @param reference
122
+ * @param files
123
+ * @param opts
124
+ */ isAffected(reference, files = [], opts) {
125
+ return new Promise((resolve, reject)=>{
126
+ const task = this.diff([
127
+ "--quiet",
128
+ reference,
129
+ "--",
130
+ ...files
131
+ ], opts);
132
+ once$(task, "status.done", ()=>resolve(false));
133
+ once$(task, "status.failed", ()=>{
134
+ if (task.exitCode) {
135
+ resolve(true);
136
+ } else {
137
+ reject(new Error(`Task ${task.name} failed`));
138
+ }
139
+ });
140
+ });
141
+ }
142
+ /**
143
+ * List git branches
144
+ *
145
+ * @param args
146
+ * @param opts
147
+ */ async listBranches(args = [], opts) {
148
+ const task = this.branch([
149
+ "-l",
150
+ ...args
151
+ ], opts);
152
+ const result = [];
153
+ for await (const line of streamLines(task, "stdout")){
154
+ result.push(line.replace(/^[ *] /, ""));
155
+ }
156
+ return result;
157
+ }
158
+ /**
159
+ * List git tags
160
+ *
161
+ * @param args
162
+ * @param opts
163
+ */ async listTags(args = [], opts) {
164
+ const task = this.tag([
165
+ "-l",
166
+ ...args
167
+ ], opts);
168
+ const result = [];
169
+ for await (const line of streamLines(task, "stdout")){
170
+ result.push(line);
171
+ }
172
+ return result;
173
+ }
174
+ };
175
+ GitService = _ts_decorate$7([
176
+ Service(),
177
+ _ts_param$4(0, inject(TASK_MANAGER)),
178
+ _ts_param$4(1, inject(Logger))
179
+ ], GitService);
180
+
181
+ function _ts_decorate$6(decorators, target, key, desc) {
182
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
183
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
184
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
185
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
186
+ }
187
+ // Class
188
+ class AffectedFilter {
189
+ // Constructor
190
+ constructor(format, fallback, sort){
191
+ this.format = format;
192
+ this.fallback = fallback;
193
+ this.sort = sort;
194
+ }
195
+ // Methods
196
+ async _formatRevision(wks) {
197
+ const logger = this._logger.child(withLabel(wks.name));
198
+ // Format revision
199
+ let result = this.format;
200
+ result = result.replace(/(?<!\\)((?:\\\\)*)%name/g, `$1${wks.name}`);
201
+ result = result.replace(/\\(.)/g, "$1");
202
+ // Ask git to complete it
203
+ const sortArgs = this.sort ? [
204
+ "--sort",
205
+ this.sort
206
+ ] : [];
207
+ // - search in branches
208
+ if (result.includes("*")) {
209
+ const branches = await this._git.listBranches([
210
+ ...sortArgs,
211
+ result
212
+ ], {
213
+ cwd: wks.cwd,
214
+ logger: logger
215
+ });
216
+ if (branches.length > 0) {
217
+ result = branches[branches.length - 1];
218
+ }
219
+ }
220
+ // - search in tags
221
+ if (result.includes("*")) {
222
+ const tags = await this._git.listTags([
223
+ ...sortArgs,
224
+ result
225
+ ], {
226
+ cwd: wks.cwd,
227
+ logger: logger
228
+ });
229
+ if (tags.length > 0) {
230
+ result = tags[tags.length - 1];
231
+ }
232
+ }
233
+ if (result !== this.format) {
234
+ logger.verbose`Resolved ${this.format} into ${result}`;
235
+ }
236
+ if (result.includes("*")) {
237
+ logger.warning(`No revision found matching ${result}, using fallback ${this.fallback}`);
238
+ return this.fallback;
239
+ }
240
+ return result;
241
+ }
242
+ async test(workspace) {
243
+ const rev = await this._formatRevision(workspace);
244
+ return await workspace.isAffected(rev);
245
+ }
246
+ }
247
+ _ts_decorate$6([
248
+ lazyInject(Logger)
249
+ ], AffectedFilter.prototype, "_logger", void 0);
250
+ _ts_decorate$6([
251
+ lazyInject(GitService)
252
+ ], AffectedFilter.prototype, "_git", void 0);
253
+
254
+ // Class
255
+ class Pipeline {
256
+ // Methods
257
+ add(filter) {
258
+ this._filters.push(filter);
259
+ }
260
+ async _test(workspace) {
261
+ for (const filter of this._filters){
262
+ const res = await filter.test(workspace);
263
+ if (!res) {
264
+ return false;
265
+ }
266
+ }
267
+ return true;
268
+ }
269
+ async *filter(workspaces) {
270
+ for await (const wks of workspaces){
271
+ if (await this._test(wks)) {
272
+ yield wks;
273
+ }
274
+ }
275
+ }
276
+ constructor(){
277
+ // Attributes
278
+ this._filters = [];
279
+ }
280
+ }
281
+
282
+ // Filter
283
+ class PrivateFilter {
284
+ // Constructor
285
+ constructor(value){
286
+ this.value = value;
287
+ }
288
+ // Methods
289
+ test(workspace) {
290
+ return (workspace.manifest.private ?? false) === this.value;
291
+ }
292
+ }
293
+
294
+ // Filter
295
+ class ScriptsFilter {
296
+ // Constructor
297
+ constructor(scripts){
298
+ this.scripts = scripts;
299
+ }
300
+ // Methods
301
+ test(workspace) {
302
+ const scripts = Object.keys(workspace.manifest.scripts || {});
303
+ return this.scripts.some((scr)=>scripts.includes(scr));
304
+ }
305
+ }
306
+
307
+ function _ts_decorate$5(decorators, target, key, desc) {
308
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
309
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
310
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
311
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
312
+ }
313
+ let Workspace = class Workspace {
314
+ // Constructor
315
+ constructor(_cwd, manifest, project){
316
+ this._cwd = _cwd;
317
+ this.manifest = manifest;
318
+ this.project = project;
319
+ this._affectedCache = new Map();
320
+ this._tasks = new Map();
321
+ const logger = container.get(Logger);
322
+ this._logger = logger.child(withLabel(this.manifest.name));
323
+ }
324
+ // Methods
325
+ _satisfies(from, range) {
326
+ if (range.startsWith("file:")) {
327
+ return path.resolve(from.cwd, range.substring(5)) === this.cwd;
328
+ }
329
+ if (range.startsWith("workspace:")) {
330
+ range = range.substring(10);
331
+ }
332
+ return !this.version || satisfies(this.version, range);
333
+ }
334
+ async _buildDependencies(task, opts) {
335
+ // Generators
336
+ const generators = [];
337
+ switch(opts.buildDeps ?? "all"){
338
+ case "all":
339
+ generators.unshift(this.devDependencies());
340
+ // eslint-disable-next no-fallthrough
341
+ case "prod":
342
+ generators.unshift(this.dependencies());
343
+ }
344
+ // Build deps
345
+ for await (const dep of combine(...generators)){
346
+ const build = await dep.build(opts);
347
+ if (build) {
348
+ task.dependsOn(build);
349
+ }
350
+ }
351
+ }
352
+ async _isAffected(reference) {
353
+ const isAffected = await this._git.isAffected(reference, [
354
+ this.cwd
355
+ ], {
356
+ cwd: this.project.root,
357
+ logger: this._logger
358
+ });
359
+ if (isAffected) {
360
+ return true;
361
+ }
362
+ // Test dependencies
363
+ const proms = [];
364
+ for await (const dep of combine(this.dependencies(), this.devDependencies())){
365
+ proms.push(dep.isAffected(reference));
366
+ }
367
+ const results = await Promise.all(proms);
368
+ return results.some((r)=>r);
369
+ }
370
+ async isAffected(reference) {
371
+ let isAffected = this._affectedCache.get(reference);
372
+ if (!isAffected) {
373
+ isAffected = this._isAffected(reference);
374
+ this._affectedCache.set(reference, isAffected);
375
+ }
376
+ return await isAffected;
377
+ }
378
+ async *_loadDependencies(dependencies, kind) {
379
+ for (const [dep, range] of Object.entries(dependencies)){
380
+ const ws = await this.project.workspace(dep);
381
+ if (ws) {
382
+ if (ws._satisfies(this, range)) {
383
+ yield ws;
384
+ } else {
385
+ this._logger.warning(`Ignoring ${kind} ${ws.reference} as it does not match requirement ${range}`);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ async *dependencies() {
391
+ if (!this.manifest.dependencies) return;
392
+ for await (const ws of this._loadDependencies(this.manifest.dependencies, "dependency")){
393
+ yield ws;
394
+ }
395
+ }
396
+ async *devDependencies() {
397
+ if (!this.manifest.devDependencies) return;
398
+ for await (const ws of this._loadDependencies(this.manifest.devDependencies, "devDependency")){
399
+ yield ws;
400
+ }
401
+ }
402
+ async exec(command, args = [], opts = {}) {
403
+ const pm = await this.project.packageManager();
404
+ const task = new CommandTask(this, command, args, {
405
+ ...opts,
406
+ logger: this._logger.child(withLabel(`${this.name}$${command}`)),
407
+ superCommand: pm === "yarn" ? [
408
+ "yarn",
409
+ "exec"
410
+ ] : undefined
411
+ });
412
+ await this._buildDependencies(task, opts);
413
+ return task;
414
+ }
415
+ async run(script, args = [], opts = {}) {
416
+ // Script not found
417
+ if (!this.getScript(script)) {
418
+ return null;
419
+ }
420
+ // Create task if it doesn't exist yet
421
+ let task = this._tasks.get(script);
422
+ if (!task) {
423
+ task = new ScriptTask(this, script, args, {
424
+ ...opts,
425
+ logger: this._logger.child(withLabel(`${this.name}#${script}`)),
426
+ runHooks: this._config.hooks
427
+ });
428
+ await task.prepare();
429
+ await this._buildDependencies(task, opts);
430
+ this._tasks.set(script, task);
431
+ }
432
+ return task;
433
+ }
434
+ async build(opts = {}) {
435
+ const task = await this.run(opts?.buildScript ?? "build", [], opts);
436
+ if (!task) {
437
+ this._logger.warning("Will not be built (no build script)");
438
+ }
439
+ return task;
440
+ }
441
+ getScript(script) {
442
+ const { scripts = {} } = this.manifest;
443
+ return scripts[script] || null;
444
+ }
445
+ toJSON() {
446
+ return {
447
+ name: this.name,
448
+ version: this.version,
449
+ cwd: this.cwd
450
+ };
451
+ }
452
+ // Properties
453
+ get name() {
454
+ return this.manifest.name;
455
+ }
456
+ get version() {
457
+ return this.manifest.version;
458
+ }
459
+ get reference() {
460
+ return this.version ? `${this.name}@${this.version}` : this.name;
461
+ }
462
+ get cwd() {
463
+ return path.resolve(this.project.root, this._cwd);
464
+ }
465
+ };
466
+ _ts_decorate$5([
467
+ lazyInject(GitService)
468
+ ], Workspace.prototype, "_git", void 0);
469
+ _ts_decorate$5([
470
+ lazyInject(CONFIG)
471
+ ], Workspace.prototype, "_config", void 0);
472
+ Workspace = _ts_decorate$5([
473
+ injectable()
474
+ ], Workspace);
475
+
476
+ function _ts_decorate$4(decorators, target, key, desc) {
477
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
478
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
479
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
480
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
481
+ }
482
+ let Project = class Project {
483
+ // Constructor
484
+ constructor(_root, _logger, opts = {}){
485
+ this._root = _root;
486
+ this._logger = _logger;
487
+ this._names = new Map();
488
+ this._workspaces = new Map();
489
+ this._isFullyLoaded = false;
490
+ this._lock = new Lock();
491
+ this._scurry = new PathScurry(this.root, {
492
+ fs
493
+ });
494
+ if (opts.packageManager) {
495
+ this._logger.debug`Forced use of ${opts.packageManager} in #!cwd:${this.root}`;
496
+ this._packageManager = opts.packageManager;
497
+ }
498
+ }
499
+ // Methods
500
+ async _loadManifest(dir) {
501
+ const file = path.resolve(this.root, dir, "package.json");
502
+ const relative = path.relative(this.root, path.dirname(file));
503
+ const logger = this._logger.child(withLabel(relative ? `project@${relative}` : "project"));
504
+ logger.debug("Loading package.json ...");
505
+ const data = await fs.promises.readFile(file, "utf-8");
506
+ const mnf = JSON.parse(data);
507
+ normalize(mnf, (msg)=>logger.verbose(msg));
508
+ return mnf;
509
+ }
510
+ async _loadWorkspace(dir) {
511
+ return await this._lock.with(async ()=>{
512
+ let wks = this._workspaces.get(dir);
513
+ if (!wks) {
514
+ const manifest = await this._loadManifest(dir);
515
+ wks = new Workspace(dir, manifest, this);
516
+ this._workspaces.set(dir, wks);
517
+ this._names.set(wks.name, wks);
518
+ }
519
+ return wks;
520
+ });
521
+ }
522
+ async packageManager() {
523
+ if (!this._packageManager) {
524
+ const files = await this._scurry.readdir(this.root, {
525
+ withFileTypes: false
526
+ });
527
+ if (files.includes("yarn.lock")) {
528
+ this._logger.debug`Detected yarn in #!cwd:${this.root}`;
529
+ this._packageManager = "yarn";
530
+ } else if (files.includes("package-lock.json")) {
531
+ this._logger.debug`Detected npm in #!cwd:${this.root}`;
532
+ this._packageManager = "npm";
533
+ } else {
534
+ this._logger.debug`No package manager recognized in #!cwd:${this.root}, defaults to npm`;
535
+ this._packageManager = "npm";
536
+ }
537
+ }
538
+ return this._packageManager;
539
+ }
540
+ async mainWorkspace() {
541
+ if (!this._mainWorkspace) {
542
+ const manifest = await this._loadManifest(".");
543
+ this._mainWorkspace = new Workspace(".", manifest, this);
544
+ this._names.set(this._mainWorkspace.name, this._mainWorkspace);
545
+ }
546
+ return this._mainWorkspace;
547
+ }
548
+ async currentWorkspace(cwd = process.cwd()) {
549
+ let workspace = null;
550
+ cwd = path.resolve(cwd);
551
+ for await (const wks of this.workspaces()){
552
+ if (cwd.startsWith(wks.cwd)) {
553
+ workspace = wks;
554
+ if (wks.cwd !== this.root) return wks;
555
+ }
556
+ }
557
+ return workspace;
558
+ }
559
+ async *workspaces() {
560
+ const main = await this.mainWorkspace();
561
+ yield main;
562
+ if (this._isFullyLoaded) {
563
+ for (const wks of this._names.values()){
564
+ if (wks.name !== main.name) yield wks;
565
+ }
566
+ } else {
567
+ // Load child workspaces
568
+ const { workspaces = [] } = main.manifest;
569
+ this._workspaceGlob ??= new Glob(workspaces, {
570
+ scurry: this._scurry,
571
+ withFileTypes: true
572
+ });
573
+ for await (const dir of this._workspaceGlob){
574
+ try {
575
+ // Check if dir is a directory
576
+ if (dir.isDirectory()) {
577
+ yield await this._loadWorkspace(dir.fullpath());
578
+ }
579
+ } catch (error) {
580
+ if (error.code === "ENOENT") {
581
+ continue;
582
+ }
583
+ throw error;
584
+ }
585
+ }
586
+ this._isFullyLoaded = true;
587
+ }
588
+ }
589
+ async workspace(name) {
590
+ // With current directory
591
+ if (!name) {
592
+ const dir = path.relative(this.root, process.cwd());
593
+ return this._loadWorkspace(dir);
594
+ }
595
+ // Try name index
596
+ const wks = this._names.get(name);
597
+ if (wks) {
598
+ return wks;
599
+ }
600
+ // Load workspaces
601
+ if (!this._isFullyLoaded) {
602
+ for await (const ws of this.workspaces()){
603
+ if (ws.name === name) {
604
+ return ws;
605
+ }
606
+ }
607
+ this._isFullyLoaded = true;
608
+ }
609
+ return null;
610
+ }
611
+ // Properties
612
+ get root() {
613
+ return path.resolve(this._root);
614
+ }
615
+ };
616
+ Project = _ts_decorate$4([
617
+ injectable()
618
+ ], Project);
619
+
620
+ function _ts_decorate$3(decorators, target, key, desc) {
621
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
622
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
623
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
624
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
625
+ }
626
+ function _ts_param$3(paramIndex, decorator) {
627
+ return function(target, key) {
628
+ decorator(target, key, paramIndex);
629
+ };
630
+ }
631
+ // Constants
632
+ const MANIFEST = "package.json";
633
+ const LOCK_FILES = [
634
+ "package-lock.json",
635
+ "yarn.lock"
636
+ ];
637
+ let ProjectRepository = class ProjectRepository {
638
+ // Constructor
639
+ constructor(logger){
640
+ this._cache = new Map();
641
+ this._roots = new Map();
642
+ this._logger = logger.child(withLabel("projects"));
643
+ }
644
+ // Methods
645
+ async isProjectRoot(dir) {
646
+ const files = await fs$1.readdir(dir);
647
+ return {
648
+ hasManifest: files.includes(MANIFEST),
649
+ hasLockFile: LOCK_FILES.some((lock)=>files.includes(lock))
650
+ };
651
+ }
652
+ async searchProjectRoot(directory) {
653
+ directory = path.resolve(directory);
654
+ // Test all ancestors
655
+ const steps = [];
656
+ let foundManifest = false;
657
+ let projectRoot = directory;
658
+ let dir = directory;
659
+ let prev = dir;
660
+ do {
661
+ // Check cache
662
+ const root = this._roots.get(dir);
663
+ if (root) {
664
+ projectRoot = root;
665
+ foundManifest = true;
666
+ break;
667
+ }
668
+ // Look for files
669
+ const { hasManifest, hasLockFile } = await this.isProjectRoot(dir);
670
+ steps.push(dir);
671
+ if (hasManifest) {
672
+ projectRoot = dir;
673
+ foundManifest = true;
674
+ }
675
+ if (hasLockFile) {
676
+ break;
677
+ }
678
+ prev = dir;
679
+ dir = path.dirname(dir);
680
+ }while (prev !== dir);
681
+ // Cache result
682
+ for (const dir of steps){
683
+ if (dir.startsWith(projectRoot)) {
684
+ this._roots.set(dir, projectRoot);
685
+ }
686
+ }
687
+ // Log it
688
+ if (foundManifest) {
689
+ this._logger.debug`Project root found at #!cwd:${projectRoot}`;
690
+ } else {
691
+ this._logger.debug`Project root not found, keeping #!cwd:${projectRoot}`;
692
+ }
693
+ return projectRoot;
694
+ }
695
+ getProject(root, opts) {
696
+ let project = this._cache.get(root);
697
+ if (!project) {
698
+ project = new Project(root, this._logger, opts);
699
+ this._cache.set(root, project);
700
+ }
701
+ return project;
702
+ }
703
+ };
704
+ ProjectRepository = _ts_decorate$3([
705
+ Service(),
706
+ _ts_param$3(0, inject(Logger))
707
+ ], ProjectRepository);
708
+
709
+ function _ts_decorate$2(decorators, target, key, desc) {
710
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
711
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
712
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
713
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
714
+ }
715
+ function _ts_param$2(paramIndex, decorator) {
716
+ return function(target, key) {
717
+ decorator(target, key, paramIndex);
718
+ };
719
+ }
720
+ let LoadProject = class LoadProject {
721
+ // Constructor
722
+ constructor(projects, context){
723
+ this.projects = projects;
724
+ this.context = context;
725
+ }
726
+ // Methods
727
+ builder(parser) {
728
+ return parser.option("project", {
729
+ alias: "p",
730
+ type: "string",
731
+ description: "Project root directory"
732
+ }).option("package-manager", {
733
+ choices: [
734
+ "yarn",
735
+ "npm"
736
+ ],
737
+ type: "string",
738
+ description: "Force package manager"
739
+ });
740
+ }
741
+ async handler(args) {
742
+ if (!this.context.project || args.project) {
743
+ args.project = await this.projects.searchProjectRoot(args.project ?? process.cwd());
744
+ this.context.project = this.projects.getProject(args.project, {
745
+ packageManager: args.packageManager
746
+ });
747
+ } else {
748
+ args.project = this.context.project.root;
749
+ }
750
+ }
751
+ };
752
+ LoadProject = _ts_decorate$2([
753
+ Middleware(),
754
+ _ts_param$2(0, inject(ProjectRepository)),
755
+ _ts_param$2(1, inject(ContextService))
756
+ ], LoadProject);
757
+ // Lazy injection
758
+ function LazyCurrentProject() {
759
+ return lazyInjectNamed(Project, CURRENT);
760
+ }
761
+ container.bind(Project).toDynamicValue(({ container })=>{
762
+ const ctx = container.get(ContextService);
763
+ const prj = ctx.project;
764
+ if (!prj) {
765
+ throw new Error("Cannot inject current project, it not yet defined");
766
+ }
767
+ return prj;
768
+ }).whenTargetNamed(CURRENT);
769
+
770
+ function _ts_decorate$1(decorators, target, key, desc) {
771
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
772
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
773
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
774
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
775
+ }
776
+ function _ts_param$1(paramIndex, decorator) {
777
+ return function(target, key) {
778
+ decorator(target, key, paramIndex);
779
+ };
780
+ }
781
+ let LoadWorkspace = class LoadWorkspace {
782
+ // Constructor
783
+ constructor(context, logger){
784
+ this.context = context;
785
+ this.logger = logger;
786
+ }
787
+ // Methods
788
+ builder(parser) {
789
+ return parser.option("workspace", {
790
+ alias: "w",
791
+ type: "string",
792
+ desc: "Workspace to use"
793
+ });
794
+ }
795
+ async handler(args) {
796
+ let workspace = this.context.workspace ?? null;
797
+ if (!workspace || args.workspace) {
798
+ if (args.workspace) {
799
+ workspace = await this.project.workspace(args.workspace);
800
+ } else if (process.cwd().startsWith(this.project.root)) {
801
+ workspace = await this.project.currentWorkspace();
802
+ } else {
803
+ workspace = await this.project.mainWorkspace();
804
+ }
805
+ }
806
+ if (!workspace) {
807
+ this.logger.error(`${symbols.error} Workspace "${args.workspace || "."}" not found`);
808
+ throw new ExitException(1, "Workspace not found");
809
+ } else {
810
+ this.context.workspace = workspace;
811
+ }
812
+ }
813
+ };
814
+ _ts_decorate$1([
815
+ LazyCurrentProject()
816
+ ], LoadWorkspace.prototype, "project", void 0);
817
+ LoadWorkspace = _ts_decorate$1([
818
+ Middleware(),
819
+ _ts_param$1(0, inject(ContextService)),
820
+ _ts_param$1(1, inject(Logger))
821
+ ], LoadWorkspace);
822
+ // Decorators
823
+ function LazyCurrentWorkspace() {
824
+ return lazyInjectNamed(Workspace, CURRENT);
825
+ }
826
+ container.bind(Workspace).toDynamicValue(({ container })=>{
827
+ const ctx = container.get(ContextService);
828
+ const wks = ctx.workspace;
829
+ if (!wks) {
830
+ throw new Error("Cannot inject current workspace, it not yet defined");
831
+ }
832
+ return wks;
833
+ }).whenTargetNamed(CURRENT);
834
+
835
+ class PluginModule extends ContainerModule {
836
+ // Constructor
837
+ constructor(name, commands){
838
+ super((...args)=>{
839
+ for (const command of this.commands){
840
+ const registry = getRegistry(command);
841
+ registry(...args);
842
+ }
843
+ });
844
+ this.name = name;
845
+ this.commands = commands;
846
+ this.id = id();
847
+ }
848
+ }
849
+ // Decorator
850
+ function Plugin(opts) {
851
+ return (target)=>{
852
+ const name = opts.name ?? target.name;
853
+ const module = new PluginModule(name, opts.commands);
854
+ setModule(target, module);
855
+ };
856
+ }
857
+
858
+ function _ts_decorate(decorators, target, key, desc) {
859
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
860
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
861
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
862
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
863
+ }
864
+ function _ts_param(paramIndex, decorator) {
865
+ return function(target, key) {
866
+ decorator(target, key, paramIndex);
867
+ };
868
+ }
869
+ let TaskExprService = class TaskExprService1 {
870
+ // Statics
871
+ static isTaskNode(node) {
872
+ return "script" in node;
873
+ }
874
+ // Constructor
875
+ constructor(_logger){
876
+ this._logger = _logger;
877
+ }
878
+ // Methods
879
+ _lexer() {
880
+ return moo.states({
881
+ task: {
882
+ lparen: "(",
883
+ whitespace: /[ \t]+/,
884
+ script: {
885
+ match: /[-_:a-zA-Z0-9]+/,
886
+ push: "operatorOrArgument"
887
+ },
888
+ string: [
889
+ {
890
+ match: /'(?:\\['\\]|[^\r\n'\\])+'/,
891
+ push: "operator",
892
+ value: (x)=>x.slice(1, -1).replace(/\\(['\\])/g, "$1")
893
+ },
894
+ {
895
+ match: /"(?:\\["\\]|[^\r\n"\\])+"/,
896
+ push: "operator",
897
+ value: (x)=>x.slice(1, -1).replace(/\\(["\\])/g, "$1")
898
+ }
899
+ ]
900
+ },
901
+ operator: {
902
+ rparen: ")",
903
+ whitespace: /[ \t]+/,
904
+ operator: {
905
+ match: [
906
+ "->",
907
+ "//",
908
+ "||"
909
+ ],
910
+ pop: 1
911
+ }
912
+ },
913
+ operatorOrArgument: {
914
+ rparen: ")",
915
+ whitespace: /[ \t]+/,
916
+ operator: {
917
+ match: [
918
+ "->",
919
+ "//",
920
+ "||"
921
+ ],
922
+ pop: 1
923
+ },
924
+ argument: [
925
+ {
926
+ match: /[-_:a-zA-Z0-9]+/
927
+ },
928
+ {
929
+ match: /'(?:\\['\\]|[^\r\n'\\])+'/,
930
+ value: (x)=>x.slice(1, -1).replace(/\\(['\\])/g, "$1")
931
+ },
932
+ {
933
+ match: /"(?:\\["\\]|[^\r\n"\\])+"/,
934
+ value: (x)=>x.slice(1, -1).replace(/\\(["\\])/g, "$1")
935
+ }
936
+ ]
937
+ }
938
+ });
939
+ }
940
+ _nextNode(lexer, i = 0) {
941
+ let node = null;
942
+ for (const token of lexer){
943
+ // Ignore whitespaces
944
+ if (token.type === "whitespace") {
945
+ continue;
946
+ }
947
+ // rparen = end of group
948
+ if (token.type === "rparen") {
949
+ break;
950
+ }
951
+ // Handle argument
952
+ if (token.type === "argument") {
953
+ if (!node) {
954
+ throw new Error(lexer.formatError(token, "Unexpected argument"));
955
+ } else if (TaskExprService.isTaskNode(node)) {
956
+ node.args.push(token.value);
957
+ } else {
958
+ const lastTask = node.tasks[node.tasks.length - 1];
959
+ if (!lastTask || !TaskExprService.isTaskNode(lastTask)) {
960
+ throw new Error(lexer.formatError(token, "Unexpected argument"));
961
+ } else {
962
+ lastTask.args.push(token.value);
963
+ }
964
+ }
965
+ continue;
966
+ }
967
+ // Handle operator
968
+ if (token.type === "operator") {
969
+ const operator = token.value;
970
+ if (!node) {
971
+ throw new Error(lexer.formatError(token, "Unexpected operator"));
972
+ } else if (TaskExprService.isTaskNode(node)) {
973
+ node = {
974
+ operator,
975
+ tasks: [
976
+ node
977
+ ]
978
+ };
979
+ continue;
980
+ } else {
981
+ if (node.operator !== operator) {
982
+ node = {
983
+ operator,
984
+ tasks: [
985
+ node
986
+ ]
987
+ };
988
+ }
989
+ continue;
990
+ }
991
+ }
992
+ // Build "child"
993
+ let child;
994
+ if (token.type === "script") {
995
+ child = {
996
+ script: token.value,
997
+ args: []
998
+ };
999
+ } else if (token.type === "string") {
1000
+ const [script, ...args] = token.value.split(/ +/);
1001
+ child = {
1002
+ script,
1003
+ args
1004
+ };
1005
+ } else if (token.type === "lparen") {
1006
+ const res = this._nextNode(lexer, i + 1);
1007
+ if (!res) {
1008
+ throw new Error(lexer.formatError(token, "Empty group found"));
1009
+ }
1010
+ child = res;
1011
+ } else {
1012
+ throw new Error(lexer.formatError(token, "Unexpected token"));
1013
+ }
1014
+ if (!node) {
1015
+ node = child;
1016
+ } else if (TaskExprService.isTaskNode(node)) {
1017
+ throw new Error(lexer.formatError(token, "Unexpected token, expected an operator"));
1018
+ } else {
1019
+ node.tasks.push(child);
1020
+ }
1021
+ }
1022
+ return node;
1023
+ }
1024
+ parse(expr) {
1025
+ const lexer = this._lexer().reset(expr);
1026
+ const tree = {
1027
+ roots: []
1028
+ };
1029
+ // eslint-disable-next-line no-constant-condition
1030
+ while(true){
1031
+ const node = this._nextNode(lexer);
1032
+ if (node) {
1033
+ tree.roots.push(node);
1034
+ } else {
1035
+ break;
1036
+ }
1037
+ }
1038
+ return tree;
1039
+ }
1040
+ async buildTask(node, workspace, opts) {
1041
+ if (TaskExprService.isTaskNode(node)) {
1042
+ const task = await workspace.run(node.script, node.args, opts);
1043
+ if (!task) {
1044
+ throw new Error(`Workspace ${workspace.name} have no ${node.script} script`);
1045
+ }
1046
+ return task;
1047
+ } else {
1048
+ let group;
1049
+ if (node.operator === "//") {
1050
+ group = new ParallelGroup("In parallel", {}, {
1051
+ logger: this._logger
1052
+ });
1053
+ } else if (node.operator === "||") {
1054
+ group = new FallbackGroup("Fallbacks", {}, {
1055
+ logger: this._logger
1056
+ });
1057
+ } else {
1058
+ group = new SequenceGroup("In sequence", {}, {
1059
+ logger: this._logger
1060
+ });
1061
+ }
1062
+ for (const child of node.tasks){
1063
+ group.add(await this.buildTask(child, workspace, opts));
1064
+ }
1065
+ return group;
1066
+ }
1067
+ }
1068
+ };
1069
+ TaskExprService = _ts_decorate([
1070
+ Service(),
1071
+ _ts_param(0, inject(Logger))
1072
+ ], TaskExprService);
1073
+
1074
+ // Utils
1075
+ const style = (dev)=>({
1076
+ color: dev ? "blue" : ""
1077
+ });
1078
+ // Component
1079
+ function WorkspaceTree(props) {
1080
+ const { workspace: wks, dev = false, level = "" } = props;
1081
+ // State
1082
+ const [deps, setDeps] = useState([]);
1083
+ // Effects
1084
+ useEffect(()=>void (async ()=>{
1085
+ const deps = [];
1086
+ for await (const dep of wks.dependencies()){
1087
+ deps.push([
1088
+ dep,
1089
+ null
1090
+ ]);
1091
+ }
1092
+ for await (const dep of wks.devDependencies()){
1093
+ deps.push([
1094
+ dep,
1095
+ true
1096
+ ]);
1097
+ }
1098
+ setDeps(deps);
1099
+ })(), [
1100
+ wks
1101
+ ]);
1102
+ // Render
1103
+ return /*#__PURE__*/ jsxs(Text, {
1104
+ children: [
1105
+ /*#__PURE__*/ jsx(Text, {
1106
+ ...style(dev),
1107
+ children: wks.name
1108
+ }),
1109
+ wks.version && /*#__PURE__*/ jsxs(Text, {
1110
+ color: "grey",
1111
+ children: [
1112
+ "@",
1113
+ wks.version
1114
+ ]
1115
+ }),
1116
+ deps.length > 0 && /*#__PURE__*/ jsx(Newline, {}),
1117
+ deps.map(([dep, isDev], idx)=>/*#__PURE__*/ jsxs(Text, {
1118
+ children: [
1119
+ level,
1120
+ /*#__PURE__*/ jsxs(Text, {
1121
+ ...style(dev),
1122
+ children: [
1123
+ idx === deps.length - 1 ? "└" : "├",
1124
+ "─",
1125
+ " "
1126
+ ]
1127
+ }),
1128
+ /*#__PURE__*/ jsx(WorkspaceTree, {
1129
+ workspace: dep,
1130
+ dev: isDev ?? dev,
1131
+ level: /*#__PURE__*/ jsxs(Fragment, {
1132
+ children: [
1133
+ level,
1134
+ /*#__PURE__*/ jsxs(Text, {
1135
+ ...style(dev),
1136
+ children: [
1137
+ idx === deps.length - 1 ? " " : "│",
1138
+ " "
1139
+ ]
1140
+ })
1141
+ ]
1142
+ })
1143
+ }),
1144
+ idx < deps.length - 1 && /*#__PURE__*/ jsx(Newline, {})
1145
+ ]
1146
+ }, dep.name))
1147
+ ]
1148
+ });
1149
+ }
1150
+
1151
+ export { AffectedFilter as A, GitService as G, LoadProject as L, Pipeline as P, ScriptsFilter as S, TaskExprService as T, WorkspaceTree as W, PrivateFilter as a, LazyCurrentProject as b, LoadWorkspace as c, LazyCurrentWorkspace as d, PluginModule as e, Plugin as f, Project as g, ProjectRepository as h, Workspace as i, combine as j, streamLines as s };
1152
+ //# sourceMappingURL=workspace-tree-9cXaezk-.js.map