@jujulego/jill 2.4.0-alpha.6 → 2.5.0

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.
Files changed (32) hide show
  1. package/dist/commons/logger/thread.gateway.d.ts +1 -1
  2. package/dist/{core.plugin-fx8ZOGe-.js → core.plugin-D2E-d42P.js} +18 -19
  3. package/dist/{core.plugin-fx8ZOGe-.js.map → core.plugin-D2E-d42P.js.map} +1 -1
  4. package/dist/index.d.ts +0 -4
  5. package/dist/index.js +6 -7
  6. package/dist/index.js.map +1 -1
  7. package/dist/ink-command-libMC9Gc.js +2083 -0
  8. package/dist/ink-command-libMC9Gc.js.map +1 -0
  9. package/dist/inversify.config.d.ts +1 -1
  10. package/dist/jill.application-CFM4p02J.js +636 -0
  11. package/dist/jill.application-CFM4p02J.js.map +1 -0
  12. package/dist/main.js +6 -7
  13. package/dist/main.js.map +1 -1
  14. package/dist/tsconfig.build.tsbuildinfo +1 -1
  15. package/dist/ui/hooks/useFlatTaskTree.d.ts +14 -0
  16. package/dist/ui/hooks/useIsVerbose.d.ts +1 -0
  17. package/dist/ui/hooks/useStdoutDimensions.d.ts +4 -0
  18. package/dist/ui/task-tree-completed.d.ts +5 -0
  19. package/dist/ui/task-tree-full-spinner.d.ts +5 -0
  20. package/dist/ui/task-tree-scrollable-spinner.d.ts +5 -0
  21. package/dist/ui/task-tree-spinner.d.ts +5 -0
  22. package/dist/ui/task-tree-stats.d.ts +5 -0
  23. package/dist/{workspace-tree-YMFiEGQk.js → workspace-tree-RzT8Bsb2.js} +25 -19
  24. package/dist/workspace-tree-RzT8Bsb2.js.map +1 -0
  25. package/package.json +24 -24
  26. package/dist/ink-command-OuyNSTxT.js +0 -1134
  27. package/dist/ink-command-OuyNSTxT.js.map +0 -1
  28. package/dist/jill.application-JCJSgP36.js +0 -266
  29. package/dist/jill.application-JCJSgP36.js.map +0 -1
  30. package/dist/ui/group-task-spinner.d.ts +0 -5
  31. package/dist/ui/task-manager-spinner.d.ts +0 -5
  32. package/dist/workspace-tree-YMFiEGQk.js.map +0 -1
@@ -1,1134 +0,0 @@
1
- import { withTimestamp, LogLevel, quick, qlevelColor, toStderr, Logger, logger$, withLabel } from '@jujulego/logger';
2
- import { _ } from '@swc/helpers/_/_ts_decorate';
3
- import { _ as _$1 } from '@swc/helpers/_/_ts_param';
4
- import { Container, decorate, injectable, inject, ContainerModule } from 'inversify';
5
- import { AsyncLocalStorage } from 'node:async_hooks';
6
- import { SpawnTask, GroupTask, TaskSet, TaskManager } from '@jujulego/tasks';
7
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { Box, Text, useStderr, render } from 'ink';
9
- import { useState, useLayoutEffect, useMemo, Fragment as Fragment$1 } from 'react';
10
- import os from 'node:os';
11
- import path from 'node:path';
12
- import Ajv from 'ajv';
13
- import wt, { BroadcastChannel, setEnvironmentData, getEnvironmentData } from 'node:worker_threads';
14
- import yargs from 'yargs';
15
- import { hideBin } from 'yargs/helpers';
16
- import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
17
- import { source$, once$, waitFor$ } from '@jujulego/event-tree';
18
- import Spinner from 'ink-spinner';
19
- import symbols from 'log-symbols';
20
- import ms from 'pretty-ms';
21
- import getDecorators from 'inversify-inject-decorators';
22
- import 'reflect-metadata';
23
- import { flow$, filter$, var$ } from '@jujulego/aegis';
24
- import { qprop } from '@jujulego/quick-tag';
25
- import { chalkTemplateStderr } from 'chalk-template';
26
-
27
- // Utils
28
- async function dynamicImport(filepath) {
29
- return import(/* webpackIgnore: true */ process.platform === "win32" ? `file://${filepath}` : filepath);
30
- }
31
- function fixDefaultExport(mod) {
32
- return "default" in mod ? mod.default : mod;
33
- }
34
-
35
- // Container
36
- const container = new Container();
37
- // Utilities
38
- const { lazyInject, lazyInjectNamed } = fixDefaultExport(getDecorators)(container);
39
-
40
- // Decorators
41
- /**
42
- * Register class as a service
43
- */ function Service() {
44
- return (cls)=>{
45
- decorate(injectable(), cls);
46
- container.bind(cls).toSelf().inSingletonScope().onActivation((ctx, service)=>{
47
- if ("onServiceActivate" in service) {
48
- service.onServiceActivate(ctx);
49
- }
50
- return service;
51
- });
52
- return cls;
53
- };
54
- }
55
-
56
- // Constants
57
- const LOG_BROADCAST_CHANNEL = Symbol.for("jujulego:jill:log-broadcast-channel");
58
- // Parameters
59
- container.bind(LOG_BROADCAST_CHANNEL).toConstantValue("jujulego:jill:logger");
60
-
61
- let ThreadGateway = class ThreadGateway {
62
- // Constructor
63
- constructor(channel){
64
- this._source = source$();
65
- this.subscribe = this._source.subscribe;
66
- this.unsubscribe = this._source.unsubscribe;
67
- this.clear = this._source.clear;
68
- this.channel = new BroadcastChannel(channel);
69
- this.channel.unref();
70
- this.channel.onmessage = (log)=>{
71
- this._source.next(log.data);
72
- };
73
- this.channel.onmessageerror = (data)=>{
74
- this._source.next(withTimestamp()({
75
- level: LogLevel.error,
76
- message: quick.string`Unable to read message: #!json:${data.data}`
77
- }));
78
- };
79
- }
80
- // Methods
81
- next(data) {
82
- this.channel.postMessage(data);
83
- }
84
- };
85
- ThreadGateway = _([
86
- Service(),
87
- _$1(0, inject(LOG_BROADCAST_CHANNEL))
88
- ], ThreadGateway);
89
-
90
- // Utils
91
- const jillLogFormat = qlevelColor(quick.wrap(chalkTemplateStderr).function`#?:${qprop("label")}{grey [#$]} ?#${qprop("message")}#?:${qprop("error")}\n#!error$?#`);
92
- let LogGateway = class LogGateway {
93
- // Lifecycle
94
- onServiceActivate({ container }) {
95
- const threadGtw = container.get(ThreadGateway);
96
- if (wt.isMainThread) {
97
- // Redirect logs to stderr
98
- flow$(this._source, toStderr(jillLogFormat));
99
- // Add thread gateway as input
100
- this.connect(threadGtw);
101
- } else {
102
- // Redirect logs to thread gateway
103
- flow$(this._source, threadGtw);
104
- }
105
- }
106
- connect(origin) {
107
- return flow$(origin, filter$((log)=>log.level >= this.level), this._source);
108
- }
109
- // Properties
110
- get listeners() {
111
- return Array.from(this._source.listeners);
112
- }
113
- get level() {
114
- return this.level$.read();
115
- }
116
- set level(level) {
117
- this.level$.mutate(level);
118
- }
119
- constructor(){
120
- // Attributes
121
- this.level$ = var$(LogLevel.info);
122
- this._source = source$();
123
- // Methods
124
- this.subscribe = this._source.subscribe;
125
- this.unsubscribe = this._source.unsubscribe;
126
- this.clear = this._source.clear;
127
- }
128
- };
129
- LogGateway = _([
130
- Service()
131
- ], LogGateway);
132
-
133
- // Service
134
- container.bind(Logger).toDynamicValue(()=>logger$(withTimestamp())).inSingletonScope().onActivation(({ container }, logger)=>{
135
- const gateway = container.get(LogGateway);
136
- gateway.connect(logger);
137
- return logger;
138
- });
139
-
140
- let ContextService = class ContextService {
141
- // Constructor
142
- constructor(logger){
143
- this._storage = new AsyncLocalStorage();
144
- this._logger = logger.child(withLabel("context"));
145
- this.reset();
146
- }
147
- // Methods
148
- reset(context = {}) {
149
- this._storage.enterWith(context);
150
- }
151
- _getContext() {
152
- const ctx = this._storage.getStore();
153
- if (!ctx) {
154
- this._logger.warning("Trying to access uninitialized context");
155
- return {};
156
- }
157
- return ctx;
158
- }
159
- _updateContext(update) {
160
- Object.assign(this._getContext(), update);
161
- }
162
- // Properties
163
- get application() {
164
- return this._getContext().application;
165
- }
166
- set application(application) {
167
- this._updateContext({
168
- application
169
- });
170
- }
171
- get project() {
172
- return this._getContext().project;
173
- }
174
- set project(project) {
175
- this._updateContext({
176
- project
177
- });
178
- }
179
- get workspace() {
180
- return this._getContext().workspace;
181
- }
182
- set workspace(workspace) {
183
- this._updateContext({
184
- workspace
185
- });
186
- }
187
- };
188
- ContextService = _([
189
- Service(),
190
- _$1(0, inject(Logger))
191
- ], ContextService);
192
-
193
- // Symbols
194
- const CONFIG_OPTIONS = Symbol("jujulego:jill:config-options");
195
- // Constants
196
- const VERBOSITY_LEVEL = {
197
- 1: "verbose",
198
- 2: "debug"
199
- };
200
- // Options
201
- function applyConfigOptions(parser) {
202
- return parser.option("verbose", {
203
- alias: "v",
204
- type: "count",
205
- description: "Set verbosity level",
206
- coerce: (cnt)=>VERBOSITY_LEVEL[Math.min(cnt, 2)]
207
- }).option("jobs", {
208
- alias: "j",
209
- type: "number",
210
- description: "Set maximum parallel job number"
211
- }).option("hooks", {
212
- type: "boolean",
213
- description: "Run hook scripts"
214
- });
215
- }
216
- container.bind(CONFIG_OPTIONS).toDynamicValue(()=>{
217
- const parser = yargs(hideBin(process.argv)).help(false).version(false);
218
- applyConfigOptions(parser);
219
- return parser.parse();
220
- }).inSingletonScope();
221
-
222
- // Constants
223
- const CURRENT = "current";
224
-
225
- // Symbols
226
- const MODULE = Symbol("jujulego:jill:module");
227
- const REGISTRY = Symbol("jujulego:jill:registry");
228
- // Utils
229
- function getRegistry(target) {
230
- const registry = Reflect.getMetadata(REGISTRY, target);
231
- if (typeof registry !== "function") {
232
- throw new Error(`No registry found in ${target.name}`);
233
- }
234
- return registry;
235
- }
236
- function setRegistry(target, registry) {
237
- Reflect.defineMetadata(REGISTRY, registry, target);
238
- }
239
- function getModule(target, assert = false) {
240
- let module = Reflect.getMetadata(MODULE, target);
241
- if (!module || !(module instanceof ContainerModule)) {
242
- const registry = Reflect.getMetadata(REGISTRY, target);
243
- if (typeof registry !== "function") {
244
- if (assert) {
245
- throw new Error(`No module found in ${target.name}`);
246
- }
247
- return null;
248
- }
249
- module = new ContainerModule(registry);
250
- setModule(target, module);
251
- }
252
- return module;
253
- }
254
- function setModule(target, module) {
255
- Reflect.defineMetadata(MODULE, module, target);
256
- }
257
-
258
- // Class
259
- class ExitException extends Error {
260
- // Constructor
261
- constructor(code, message){
262
- super(message);
263
- this.code = code;
264
- }
265
- }
266
-
267
- // Decorator
268
- function Middleware() {
269
- return (target)=>{
270
- decorate(injectable(), target);
271
- container.bind(target).toSelf().inSingletonScope();
272
- };
273
- }
274
- // Utils
275
- function applyMiddlewares(parser, middlewares) {
276
- let tmp = parser;
277
- for (const cls of middlewares){
278
- const middleware = container.get(cls);
279
- if (middleware.builder) {
280
- tmp = middleware.builder(tmp);
281
- }
282
- tmp.middleware((args)=>middleware.handler(args));
283
- }
284
- return tmp;
285
- }
286
-
287
- // Symbols
288
- const COMMAND_OPTS = Symbol("jujulego:jill:command-opts");
289
- const COMMAND = Symbol("jujulego:jill:command");
290
- const COMMAND_MODULE = Symbol("jujulego:jill:command-module");
291
- // Utils
292
- function getCommandOpts(target) {
293
- const opts = Reflect.getMetadata(COMMAND_OPTS, target);
294
- if (typeof opts !== "object") {
295
- throw new Error(`No command options found in ${target.name}`);
296
- }
297
- return opts;
298
- }
299
- function buildCommandModule(cmd, opts) {
300
- return {
301
- command: opts.command,
302
- aliases: opts.aliases,
303
- describe: opts.describe,
304
- deprecated: opts.deprecated,
305
- builder (parser) {
306
- if (opts.middlewares) {
307
- parser = applyMiddlewares(parser, opts.middlewares);
308
- }
309
- if (cmd.builder) {
310
- parser = cmd.builder(parser);
311
- }
312
- return parser;
313
- },
314
- handler: async (args)=>{
315
- try {
316
- await cmd.handler(args);
317
- } catch (err) {
318
- if (err.message) {
319
- const logger = container.get(Logger);
320
- logger.error("Error while running command:", err);
321
- }
322
- throw new ExitException(1);
323
- }
324
- }
325
- };
326
- }
327
- // Decorator
328
- function Command(opts) {
329
- return (target)=>{
330
- decorate(injectable(), target);
331
- Reflect.defineMetadata(COMMAND_OPTS, opts, target);
332
- const cmd = opts.command.split(" ")[0];
333
- setRegistry(target, (bind)=>{
334
- bind(target).toSelf();
335
- bind(COMMAND).toDynamicValue(({ container })=>container.getAsync(target)).whenTargetNamed(cmd);
336
- bind(COMMAND_MODULE).toDynamicValue(async ({ container })=>{
337
- const cmd = await container.getAsync(target);
338
- return buildCommandModule(cmd, opts);
339
- }).whenTargetNamed(cmd);
340
- });
341
- };
342
- }
343
-
344
- // Symbols
345
- const AJV = Symbol("jujulego:jill:Ajv");
346
- // Setup
347
- container.bind(AJV).toDynamicValue(({ container })=>{
348
- const logger = container.get(Logger);
349
- return new Ajv.default({
350
- allErrors: true,
351
- logger: logger.child(withLabel("ajv")),
352
- strict: process.env.NODE_ENV === "development" ? "log" : true
353
- });
354
- }).inSingletonScope();
355
-
356
- function isCacheUpdate(msg) {
357
- return typeof msg === "object" && msg !== null && "key" in msg && "value" in msg;
358
- }
359
- // Chanel
360
- const channel = new BroadcastChannel("jujulego:jill:worker-cache");
361
- channel.unref();
362
- channel.onmessage = (arg)=>{
363
- const msg = arg;
364
- if (isCacheUpdate(msg.data)) {
365
- setEnvironmentData(msg.data.key, msg.data.value);
366
- }
367
- };
368
- // Utils
369
- async function workerCache(key, compute) {
370
- const cache = getEnvironmentData(key);
371
- if (cache !== undefined) return cache;
372
- // Compute it
373
- const result = await compute();
374
- setEnvironmentData(key, result);
375
- channel.postMessage({
376
- key,
377
- value: result
378
- });
379
- return result;
380
- }
381
-
382
- var $schema = "http://json-schema.org/draft-07/schema";
383
- var type = "object";
384
- var additionalProperties = false;
385
- var properties = {
386
- jobs: {
387
- type: "number"
388
- },
389
- hooks: {
390
- type: "boolean",
391
- "default": true,
392
- description: "Run hook scripts"
393
- },
394
- plugins: {
395
- type: "array",
396
- items: {
397
- type: "string"
398
- }
399
- },
400
- verbose: {
401
- type: "string",
402
- "enum": [
403
- "info",
404
- "verbose",
405
- "debug"
406
- ]
407
- }
408
- };
409
- var schema = {
410
- $schema: $schema,
411
- type: type,
412
- additionalProperties: additionalProperties,
413
- properties: properties
414
- };
415
-
416
- // Symbols
417
- const CONFIG_EXPLORER = Symbol("jujulego:jill:config-explorer");
418
- const CONFIG_VALIDATOR = Symbol("jujulego:jill:config-validator");
419
- // Setup
420
- container.bind(CONFIG_VALIDATOR).toDynamicValue(({ container })=>{
421
- const ajv = container.get(AJV);
422
- return ajv.compile(schema);
423
- }).inSingletonScope();
424
- container.bind(CONFIG_EXPLORER).toDynamicValue(()=>{
425
- return cosmiconfig("jill", {
426
- loaders: {
427
- ".cjs": (filepath)=>dynamicImport(filepath).then((mod)=>mod.default),
428
- ".js": (filepath)=>dynamicImport(filepath).then((mod)=>mod.default),
429
- ".json": defaultLoaders[".json"],
430
- ".yaml": defaultLoaders[".yaml"],
431
- ".yml": defaultLoaders[".yml"],
432
- noExt: defaultLoaders.noExt
433
- }
434
- });
435
- }).inSingletonScope();
436
-
437
- // Symbols
438
- const CONFIG = Symbol("jujulego:jill:config");
439
- // Loader
440
- async function configLoader() {
441
- const logger = container.get(Logger).child(withLabel("config"));
442
- const options = container.get(CONFIG_OPTIONS);
443
- const explorer = container.get(CONFIG_EXPLORER);
444
- const validator = container.get(CONFIG_VALIDATOR);
445
- // Load file
446
- const loaded = await explorer.search();
447
- const config = loaded?.config ?? {};
448
- // Apply options from cli
449
- if (options.jobs) config.jobs = options.jobs;
450
- if (options.verbose) config.verbose = options.verbose;
451
- if (options.hooks !== undefined) config.hooks = options.hooks;
452
- // Apply defaults
453
- config.jobs ??= os.cpus().length - 1;
454
- config.hooks ??= true;
455
- // Validate
456
- if (!validator(config)) {
457
- const ajv = container.get(AJV);
458
- const errors = ajv.errorsText(validator.errors, {
459
- separator: "\n- ",
460
- dataVar: "config"
461
- });
462
- logger.error(`Errors in config file:\n- ${errors}`);
463
- throw new ExitException(1);
464
- }
465
- // Apply on logger
466
- if (config.verbose) {
467
- container.get(LogGateway).level = LogLevel[config.verbose];
468
- }
469
- if (loaded) {
470
- // Resolve paths relative to config file
471
- const base = path.dirname(loaded.filepath);
472
- config.plugins = config.plugins?.map((plugin)=>path.resolve(base, plugin));
473
- logger.verbose(`Loaded ${loaded.filepath} config file`);
474
- }
475
- logger.debug`Loaded config:\n#!json:${config}`;
476
- return config;
477
- }
478
- container.bind(CONFIG).toDynamicValue(async ()=>await workerCache("jujulego:jill:config", configLoader)).inSingletonScope();
479
-
480
- let PluginLoaderService = class PluginLoaderService {
481
- // Constructor
482
- constructor(_config, logger){
483
- this._config = _config;
484
- this._logger = logger.child(withLabel("plugin"));
485
- }
486
- // Methods
487
- async _importPlugin(filepath) {
488
- this._logger.verbose`Loading plugin ${filepath}`;
489
- // Load plugin
490
- let plugin = await dynamicImport(filepath);
491
- while(plugin && typeof plugin === "object" && "default" in plugin){
492
- plugin = plugin.default;
493
- }
494
- if (!plugin) {
495
- throw new Error(`Invalid plugin ${filepath}: no plugin class found`);
496
- }
497
- // Load module from plugin
498
- const module = getModule(plugin);
499
- if (!module) {
500
- throw new Error(`Invalid plugin ${filepath}: invalid plugin class`);
501
- }
502
- return module;
503
- }
504
- async loadPlugins(ctn = container) {
505
- if (!this._config.plugins) return;
506
- for (const path of this._config.plugins){
507
- const plugin = await this._importPlugin(path);
508
- ctn.load(plugin);
509
- }
510
- }
511
- };
512
- PluginLoaderService = _([
513
- Service(),
514
- _$1(0, inject(CONFIG)),
515
- _$1(1, inject(Logger))
516
- ], PluginLoaderService);
517
-
518
- // Utils
519
- function linesFrom(task, stream) {
520
- const inner = source$();
521
- if (task.completed) {
522
- return inner;
523
- }
524
- // Listen to stream
525
- let current = "";
526
- const stop = task.on(`stream.${stream}`, (chunk)=>{
527
- const data = current + chunk.data.toString("utf-8");
528
- const lines = data.split(/\r?\n/);
529
- current = lines.pop() ?? "";
530
- for (const line of lines){
531
- inner.next(line);
532
- }
533
- });
534
- // Listen to end of task
535
- once$(task, "completed", ()=>{
536
- stop();
537
- if (current) {
538
- inner.next(current);
539
- }
540
- });
541
- return inner;
542
- }
543
-
544
- // Utils
545
- function isCommandCtx(ctx) {
546
- return "workspace" in ctx && "command" in ctx;
547
- }
548
- // Class
549
- class CommandTask extends SpawnTask {
550
- // Constructor
551
- constructor(workspace, command, args, opts = {}){
552
- let cmd = command;
553
- if (opts.superCommand) {
554
- if (typeof opts.superCommand === "string") {
555
- opts.superCommand = [
556
- opts.superCommand
557
- ];
558
- }
559
- if (opts.superCommand.length > 0) {
560
- cmd = opts.superCommand[0];
561
- args = [
562
- ...opts.superCommand.slice(1),
563
- command,
564
- ...args
565
- ];
566
- }
567
- }
568
- super(cmd, args, {
569
- workspace,
570
- command
571
- }, {
572
- ...opts,
573
- cwd: workspace.cwd,
574
- env: {
575
- FORCE_COLOR: "1",
576
- ...opts.env
577
- }
578
- });
579
- this.workspace = workspace;
580
- this._logStreams();
581
- }
582
- // Methods
583
- _logStreams() {
584
- // TODO: clean up this subscriptions
585
- linesFrom(this, "stdout").subscribe((line)=>this._logger.info(line));
586
- linesFrom(this, "stderr").subscribe((line)=>this._logger.info(line));
587
- }
588
- }
589
-
590
- // Utils
591
- function capitalize(txt) {
592
- return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
593
- }
594
- function splitCommandLine(line) {
595
- line = line.trim();
596
- const parts = [];
597
- let current_cote = "";
598
- let last = 0;
599
- for(let i = 1; i < line.length; ++i){
600
- const c = line[i];
601
- if (current_cote) {
602
- if (c === current_cote) {
603
- current_cote = "";
604
- }
605
- } else {
606
- if ([
607
- '"',
608
- "'"
609
- ].includes(c)) {
610
- current_cote = c;
611
- } else if (c === " ") {
612
- parts.push(line.slice(last, i));
613
- last = i + 1;
614
- }
615
- }
616
- }
617
- parts.push(line.slice(last));
618
- return parts;
619
- }
620
-
621
- // Utils
622
- function isScriptCtx(ctx) {
623
- return "workspace" in ctx && "script" in ctx;
624
- }
625
- // Class
626
- class ScriptTask extends GroupTask {
627
- // Constructor
628
- constructor(workspace, script, args, opts){
629
- super(script, {
630
- workspace,
631
- script
632
- }, opts);
633
- this.workspace = workspace;
634
- this.script = script;
635
- this.args = args;
636
- this._preHookTasks = null;
637
- this._postHookTasks = null;
638
- this._scriptTasks = null;
639
- this._runHooks = opts?.runHooks ?? true;
640
- }
641
- // Methods
642
- async _runScript(script, args) {
643
- const line = this.workspace.getScript(script);
644
- if (!line) {
645
- return null;
646
- }
647
- // Create command task for script
648
- const [command, ...commandArgs] = splitCommandLine(line);
649
- if (command === "jill") {
650
- this._logger.debug(`Interpreting ${line}`);
651
- const argv = commandArgs.map((arg)=>arg.replace(/^["'](.+)["']$/, "$1"));
652
- const { JillApplication } = await import('./jill.application-JCJSgP36.js').then(function (n) { return n.j; });
653
- const app = container.get(JillApplication);
654
- const tasks = await app.tasksOf(argv, {
655
- project: this.project,
656
- workspace: this.workspace
657
- });
658
- if (tasks.length) {
659
- const set = new TaskSet();
660
- for (const tsk of tasks){
661
- set.add(tsk);
662
- }
663
- return set;
664
- }
665
- }
666
- const pm = await this.workspace.project.packageManager();
667
- const set = new TaskSet();
668
- set.add(new CommandTask(this.workspace, command, [
669
- ...commandArgs,
670
- ...args
671
- ], {
672
- logger: this._logger,
673
- superCommand: pm === "yarn" ? [
674
- "yarn",
675
- "exec"
676
- ] : undefined
677
- }));
678
- return set;
679
- }
680
- async prepare() {
681
- // Prepare script run
682
- this._scriptTasks = await this._runScript(this.script, this.args);
683
- if (!this._scriptTasks) {
684
- throw new Error(`No script ${this.script} in ${this.workspace.name}`);
685
- }
686
- // Prepare hooks run
687
- if (this._runHooks) {
688
- this._preHookTasks = await this._runScript(`pre${this.script}`, []);
689
- this._postHookTasks = await this._runScript(`post${this.script}`, []);
690
- }
691
- // Add tasks to group
692
- if (this._preHookTasks) {
693
- this._logger.verbose(`Found pre-hook script "pre${this.script}"`);
694
- for (const tsk of this._preHookTasks){
695
- this.add(tsk);
696
- }
697
- }
698
- for (const tsk of this._scriptTasks){
699
- this.add(tsk);
700
- }
701
- if (this._postHookTasks) {
702
- this._logger.verbose(`Found post-hook script "post${this.script}"`);
703
- for (const tsk of this._postHookTasks){
704
- this.add(tsk);
705
- }
706
- }
707
- }
708
- async *_orchestrate() {
709
- if (!this._scriptTasks) {
710
- throw new Error("ScriptTask needs to be prepared. Call prepare before starting it");
711
- }
712
- // Run pre-hook
713
- if (this._preHookTasks) {
714
- yield* this._preHookTasks;
715
- if (await this._hasFailed(this._preHookTasks)) {
716
- return this.setStatus("failed");
717
- }
718
- }
719
- // Run script
720
- yield* this._scriptTasks;
721
- if (await this._hasFailed(this._scriptTasks)) {
722
- return this.setStatus("failed");
723
- }
724
- // Run post-hook
725
- if (this._postHookTasks) {
726
- yield* this._postHookTasks;
727
- if (await this._hasFailed(this._postHookTasks)) {
728
- return this.setStatus("failed");
729
- }
730
- }
731
- this.setStatus("done");
732
- }
733
- async _hasFailed(set) {
734
- const results = await waitFor$(set, "finished");
735
- return results.failed > 0;
736
- }
737
- _stop() {
738
- if (!this._scriptTasks) return;
739
- for (const tsk of this._scriptTasks){
740
- tsk.stop();
741
- }
742
- }
743
- complexity(cache = new Map()) {
744
- let complexity = super.complexity(cache);
745
- if (this._scriptTasks) {
746
- complexity += this._scriptTasks.tasks.reduce((cpl, tsk)=>cpl + tsk.complexity(cache), 0);
747
- }
748
- cache.set(this.id, complexity);
749
- return complexity;
750
- }
751
- // Properties
752
- get project() {
753
- return this.workspace.project;
754
- }
755
- }
756
-
757
- // Symbols
758
- const TASK_MANAGER = Symbol("jujulego:jill:TaskManager");
759
- // Service
760
- container.bind(TASK_MANAGER).toDynamicValue(({ container })=>{
761
- const config = container.get(CONFIG);
762
- const logger = container.get(Logger);
763
- return new TaskManager({
764
- jobs: config.jobs,
765
- logger
766
- });
767
- }).inSingletonScope();
768
-
769
- // Component
770
- function List({ items, headers }) {
771
- if (items.length === 0) {
772
- return null;
773
- }
774
- return /*#__PURE__*/ jsx(Box, {
775
- children: Object.keys(items[0]).map((key)=>/*#__PURE__*/ jsxs(Box, {
776
- flexDirection: "column",
777
- marginRight: 2,
778
- children: [
779
- headers && /*#__PURE__*/ jsx(Text, {
780
- bold: true,
781
- children: capitalize(key)
782
- }),
783
- items.map((item, idx)=>/*#__PURE__*/ jsx(Text, {
784
- children: item[key] || " "
785
- }, idx))
786
- ]
787
- }, key))
788
- });
789
- }
790
-
791
- // Components
792
- function TaskName({ task }) {
793
- if (isScriptCtx(task.context)) {
794
- return /*#__PURE__*/ jsxs(Text, {
795
- children: [
796
- "Run ",
797
- /*#__PURE__*/ jsx(Text, {
798
- bold: true,
799
- children: task.context.script
800
- }),
801
- " in ",
802
- task.context.workspace.name
803
- ]
804
- });
805
- } else {
806
- return /*#__PURE__*/ jsx(Text, {
807
- children: task.name
808
- });
809
- }
810
- }
811
-
812
- // Components
813
- function TaskSpinner({ task }) {
814
- // State
815
- const [status, setStatus] = useState(task.status);
816
- const [time, setTime] = useState(0);
817
- // Effects
818
- useLayoutEffect(()=>{
819
- return task.on("status", (event)=>{
820
- setStatus(event.status);
821
- });
822
- }, [
823
- task
824
- ]);
825
- useLayoutEffect(()=>{
826
- return task.on("completed", ({ duration })=>{
827
- setTime(duration);
828
- });
829
- }, [
830
- task
831
- ]);
832
- // Render
833
- const isScriptChild = isCommandCtx(task.context) && task.group && isScriptCtx(task.group.context);
834
- switch(status){
835
- case "blocked":
836
- case "ready":
837
- case "starting":
838
- return /*#__PURE__*/ jsxs(Box, {
839
- children: [
840
- /*#__PURE__*/ jsx(Text, {
841
- color: "grey",
842
- children: "\xb7"
843
- }),
844
- /*#__PURE__*/ jsx(Box, {
845
- paddingLeft: 1,
846
- children: /*#__PURE__*/ jsx(Text, {
847
- color: "grey",
848
- wrap: "truncate",
849
- children: /*#__PURE__*/ jsx(TaskName, {
850
- task: task
851
- })
852
- })
853
- })
854
- ]
855
- });
856
- case "running":
857
- return /*#__PURE__*/ jsxs(Box, {
858
- children: [
859
- /*#__PURE__*/ jsx(Text, {
860
- color: isScriptChild ? "dim" : undefined,
861
- children: /*#__PURE__*/ jsx(Spinner, {})
862
- }),
863
- /*#__PURE__*/ jsx(Box, {
864
- paddingLeft: 1,
865
- children: /*#__PURE__*/ jsx(Text, {
866
- color: isScriptChild ? "dim" : undefined,
867
- wrap: "truncate",
868
- children: /*#__PURE__*/ jsx(TaskName, {
869
- task: task
870
- })
871
- })
872
- })
873
- ]
874
- });
875
- case "done":
876
- return /*#__PURE__*/ jsxs(Box, {
877
- children: [
878
- /*#__PURE__*/ jsx(Text, {
879
- color: "green",
880
- children: symbols.success
881
- }),
882
- /*#__PURE__*/ jsx(Box, {
883
- paddingLeft: 1,
884
- children: /*#__PURE__*/ jsx(Text, {
885
- color: isScriptChild ? "dim" : undefined,
886
- wrap: "truncate",
887
- children: /*#__PURE__*/ jsx(TaskName, {
888
- task: task
889
- })
890
- })
891
- }),
892
- /*#__PURE__*/ jsx(Box, {
893
- paddingLeft: 1,
894
- flexShrink: 0,
895
- children: /*#__PURE__*/ jsxs(Text, {
896
- color: isScriptChild ? "grey" : "dim",
897
- children: [
898
- "(took ",
899
- ms(time),
900
- ")"
901
- ]
902
- })
903
- })
904
- ]
905
- });
906
- case "failed":
907
- return /*#__PURE__*/ jsxs(Box, {
908
- children: [
909
- /*#__PURE__*/ jsx(Text, {
910
- color: "red",
911
- children: symbols.error
912
- }),
913
- /*#__PURE__*/ jsx(Box, {
914
- paddingLeft: 1,
915
- children: /*#__PURE__*/ jsx(Text, {
916
- color: isScriptChild ? "dim" : undefined,
917
- wrap: "truncate",
918
- children: /*#__PURE__*/ jsx(TaskName, {
919
- task: task
920
- })
921
- })
922
- }),
923
- /*#__PURE__*/ jsx(Box, {
924
- paddingLeft: 1,
925
- flexShrink: 0,
926
- children: /*#__PURE__*/ jsxs(Text, {
927
- color: isScriptChild ? "grey" : "dim",
928
- children: [
929
- "(took ",
930
- ms(time),
931
- ")"
932
- ]
933
- })
934
- })
935
- ]
936
- });
937
- }
938
- }
939
-
940
- // Components
941
- function GroupTaskSpinner({ group }) {
942
- // State
943
- const [verbose, setVerbose] = useState(false);
944
- const [status, setStatus] = useState(group.status);
945
- const [tasks, setTasks] = useState([
946
- ...group.tasks
947
- ]);
948
- const [canReduce, setCanReduce] = useState(true);
949
- // Memo
950
- const forceExtended = useMemo(()=>verbose || tasks.some((tsk)=>!isCommandCtx(tsk.context)), [
951
- verbose,
952
- tasks
953
- ]);
954
- const isReduced = useMemo(()=>!forceExtended && canReduce, [
955
- forceExtended,
956
- canReduce
957
- ]);
958
- // Effects
959
- useLayoutEffect(()=>{
960
- const config = container.get(CONFIG);
961
- if (config.verbose) {
962
- setVerbose([
963
- "verbose",
964
- "debug"
965
- ].includes(config.verbose));
966
- }
967
- }, []);
968
- useLayoutEffect(()=>{
969
- return group.on("status", (event)=>{
970
- setStatus(event.status);
971
- });
972
- }, [
973
- group
974
- ]);
975
- useLayoutEffect(()=>{
976
- let dirty = false;
977
- return group.on("task.added", ()=>{
978
- if (!dirty) {
979
- dirty = true;
980
- queueMicrotask(()=>{
981
- setTasks([
982
- ...group.tasks
983
- ]);
984
- dirty = false;
985
- });
986
- }
987
- });
988
- }, [
989
- group
990
- ]);
991
- useLayoutEffect(()=>{
992
- if (status === "running") {
993
- setCanReduce(false);
994
- } else if (status === "done") {
995
- setCanReduce(true);
996
- }
997
- }, [
998
- status
999
- ]);
1000
- // Render
1001
- return /*#__PURE__*/ jsxs(Fragment, {
1002
- children: [
1003
- /*#__PURE__*/ jsx(TaskSpinner, {
1004
- task: group
1005
- }),
1006
- isReduced || /*#__PURE__*/ jsx(Box, {
1007
- flexDirection: "column",
1008
- marginLeft: 2,
1009
- children: tasks.map((task)=>/*#__PURE__*/ jsx(Fragment$1, {
1010
- children: task instanceof GroupTask ? /*#__PURE__*/ jsx(GroupTaskSpinner, {
1011
- group: task
1012
- }) : /*#__PURE__*/ jsx(TaskSpinner, {
1013
- task: task
1014
- })
1015
- }, task.id))
1016
- })
1017
- ]
1018
- });
1019
- }
1020
-
1021
- // Utils
1022
- function taskPredicate(task) {
1023
- if (task.group) {
1024
- return false;
1025
- }
1026
- if ("hidden" in task.context && task.context.hidden) {
1027
- return false;
1028
- }
1029
- return true;
1030
- }
1031
- // Components
1032
- function TaskManagerSpinner({ manager }) {
1033
- const [tasks, setTasks] = useState(manager.tasks.filter(taskPredicate));
1034
- useLayoutEffect(()=>{
1035
- let dirty = false;
1036
- return manager.on("added", ()=>{
1037
- if (!dirty) {
1038
- dirty = true;
1039
- queueMicrotask(()=>{
1040
- setTasks(manager.tasks.filter(taskPredicate));
1041
- dirty = false;
1042
- });
1043
- }
1044
- });
1045
- }, [
1046
- manager
1047
- ]);
1048
- return /*#__PURE__*/ jsx(Fragment, {
1049
- children: tasks.map((task)=>task instanceof GroupTask ? /*#__PURE__*/ jsx(GroupTaskSpinner, {
1050
- group: task
1051
- }, task.id) : /*#__PURE__*/ jsx(TaskSpinner, {
1052
- task: task
1053
- }, task.id))
1054
- });
1055
- }
1056
-
1057
- // Utils
1058
- function printJson(data, stream = process.stdout) {
1059
- if (stream.isTTY) {
1060
- stream.write(JSON.stringify(data, null, 2));
1061
- } else {
1062
- stream.write(JSON.stringify(data));
1063
- }
1064
- }
1065
-
1066
- // Component
1067
- function StaticLogs() {
1068
- // State
1069
- const { write } = useStderr();
1070
- // Effect
1071
- useLayoutEffect(()=>{
1072
- const gateway = container.get(LogGateway);
1073
- // Remove Console transport
1074
- const listeners = gateway.listeners;
1075
- gateway.clear();
1076
- // Add custom transport
1077
- const off = gateway.subscribe((log)=>{
1078
- write(jillLogFormat(log) + "\n");
1079
- });
1080
- return ()=>{
1081
- off();
1082
- // Restore previous listeners
1083
- for (const lst of listeners){
1084
- gateway.subscribe(lst);
1085
- }
1086
- };
1087
- }, [
1088
- write
1089
- ]);
1090
- return null;
1091
- }
1092
-
1093
- // Component
1094
- function Layout({ children }) {
1095
- return /*#__PURE__*/ jsxs(Fragment, {
1096
- children: [
1097
- /*#__PURE__*/ jsx(StaticLogs, {}),
1098
- children
1099
- ]
1100
- });
1101
- }
1102
-
1103
- // Constants
1104
- const INK_APP = Symbol.for("jujulego:jill:ink-app");
1105
- // Setup
1106
- container.bind(INK_APP).toDynamicValue(()=>{
1107
- if (!wt.isMainThread) {
1108
- throw new Error("Ink should only be used in main thread");
1109
- }
1110
- return render(/*#__PURE__*/ jsx(Layout, {}));
1111
- }).inSingletonScope();
1112
-
1113
- let InkCommand = class InkCommand {
1114
- builder(parser) {
1115
- return parser;
1116
- }
1117
- async handler(args) {
1118
- for await (const children of this.render(args)){
1119
- this.app.rerender(/*#__PURE__*/ jsx(Layout, {
1120
- children: children
1121
- }));
1122
- }
1123
- await this.app.waitUntilExit();
1124
- }
1125
- };
1126
- _([
1127
- lazyInject(INK_APP)
1128
- ], InkCommand.prototype, "app", void 0);
1129
- InkCommand = _([
1130
- injectable()
1131
- ], InkCommand);
1132
-
1133
- export { capitalize as A, splitCommandLine as B, CONFIG as C, workerCache as D, ExitException as E, ContextService as F, GroupTaskSpinner as G, applyConfigOptions as H, InkCommand as I, Layout as L, Middleware as M, PluginLoaderService as P, Service as S, TaskManagerSpinner as T, List as a, TaskName as b, TaskSpinner as c, COMMAND as d, COMMAND_MODULE as e, buildCommandModule as f, getCommandOpts as g, Command as h, applyMiddlewares as i, getRegistry as j, getModule as k, setModule as l, CURRENT as m, container as n, lazyInject as o, lazyInjectNamed as p, isCommandCtx as q, CommandTask as r, setRegistry as s, isScriptCtx as t, ScriptTask as u, TASK_MANAGER as v, linesFrom as w, dynamicImport as x, fixDefaultExport as y, printJson as z };
1134
- //# sourceMappingURL=ink-command-OuyNSTxT.js.map