@imagexmedia/cli 0.0.2 → 0.0.4-beta.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.
@@ -1,2 +1,2 @@
1
1
  import type { Command } from 'commander';
2
- export default function execute(app: Command): void;
2
+ export default function register(app: Command): void;
@@ -1,16 +1,17 @@
1
1
  import { $ } from 'execa';
2
2
  import { getFile } from "../utils/helpers.js";
3
- export default function execute(app) {
3
+ export default function register(app) {
4
4
  app
5
5
  .command('build')
6
6
  .description('Build frontend components')
7
7
  .option('--production', 'Use production mode')
8
8
  .option('--watch', 'Use watch mode')
9
- .action(async (options) => {
10
- const config = getFile('vite.config.js');
11
- const cmd = ['npx', 'vite', 'build', '-c', config, '-m', options.production ? 'production' : 'dev'];
12
- if (options.watch)
13
- cmd.push('--watch');
14
- await $({ stdio: 'inherit' }) `${cmd}`;
15
- });
9
+ .action(execute);
10
+ }
11
+ async function execute(options) {
12
+ const config = getFile('vite.config.js');
13
+ const cmd = ['npx', 'vite', 'build', '-c', config, '-m', options.production ? 'production' : 'dev'];
14
+ if (options.watch)
15
+ cmd.push('--watch');
16
+ await $({ stdio: 'inherit' }) `${cmd}`;
16
17
  }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export default function register(app: Command): void;
@@ -0,0 +1,71 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { Argument } from 'commander';
5
+ import { $ } from 'execa';
6
+ import { getRepoRoot } from "../utils/helpers.js";
7
+ const types = {
8
+ composer: 'composer.lock',
9
+ npm: 'package-lock.json',
10
+ };
11
+ export default function register(app) {
12
+ app
13
+ .command('diff')
14
+ .description('Generate lock file version diffs')
15
+ .addArgument(new Argument('<lock>', 'Type of lock file').choices(Object.keys(types)))
16
+ .argument('[hash]', 'An optional commit hash to compare against', 'HEAD')
17
+ .option('--no-color', 'Disable colors', true)
18
+ .action(execute);
19
+ }
20
+ async function execute(lock, hash, options) {
21
+ const data = getData(lock, hash);
22
+ const changes = [];
23
+ for (const [name, newPackage] of Object.entries(data.newPackages)) {
24
+ const oldPackage = data.oldPackages[name];
25
+ // Ignore unchanged and unversioned packages.
26
+ if (!newPackage.version || (oldPackage && oldPackage.version === newPackage.version))
27
+ continue;
28
+ changes.push({ name, from: oldPackage?.version, to: newPackage.version });
29
+ }
30
+ if (!options.color)
31
+ chalk.level = 0;
32
+ changes.forEach((change) => {
33
+ if (change.from) {
34
+ console.log(''
35
+ + `${chalk.cyan('+')} ${chalk.bold(change.name)} `
36
+ + `${chalk.dim(`${change.from} to`)} ${chalk.cyan(change.to)}`);
37
+ }
38
+ else {
39
+ console.log(''
40
+ + `${chalk.green('+')} ${chalk.bold(change.name)} `
41
+ + `${chalk.green(change.to)}`);
42
+ }
43
+ });
44
+ }
45
+ function getData(lock, hash) {
46
+ const data = { oldPackages: {}, newPackages: {} };
47
+ try {
48
+ const oldLock = JSON.parse($.sync `git show ${hash}:${types[lock]}`.stdout);
49
+ const newLock = JSON.parse(fs.readFileSync(path.join(getRepoRoot(), types[lock]), 'utf8'));
50
+ data.oldPackages = normalize(lock, oldLock.packages) || {};
51
+ data.newPackages = normalize(lock, newLock.packages) || {};
52
+ }
53
+ catch {
54
+ console.warn(chalk.red(`Unable to compare ${types[lock]} from commit ${hash}.`));
55
+ }
56
+ return data;
57
+ }
58
+ function normalize(lock, data) {
59
+ const packages = {};
60
+ if (lock === 'composer') {
61
+ data.forEach((value) => {
62
+ packages[value.name] = { version: value.version };
63
+ });
64
+ }
65
+ else if (lock === 'npm') {
66
+ Object.entries(data).forEach(([key, value]) => {
67
+ packages[key.replace(/^node_modules\//, '')] = { version: value.version };
68
+ });
69
+ }
70
+ return packages;
71
+ }
@@ -1,2 +1,2 @@
1
1
  import type { Command } from 'commander';
2
- export default function execute(app: Command): void;
2
+ export default function register(app: Command): void;
@@ -5,80 +5,81 @@ import { $ } from 'execa';
5
5
  import { Listr } from 'listr2';
6
6
  import { getFile } from "../utils/helpers.js";
7
7
  const types = ['all', 'eslint', 'stylelint', 'typescript'];
8
- export default function execute(app) {
8
+ export default function register(app) {
9
9
  app
10
10
  .command('lint')
11
11
  .description('Run linters')
12
12
  .addArgument(new Argument('[type]', 'Type of linter to run').choices(types).default('all'))
13
13
  .option('--fix', 'Attempt to automatically fix issues')
14
- .action(async (type, options) => {
15
- const ops = {};
16
- // ESLint.
17
- try {
18
- const config = getFile('eslint.config.js', true);
19
- ops.eslint = async () => {
20
- const cmd = ['npx', 'eslint', '-c', config, '--no-error-on-unmatched-pattern', '--color'];
21
- if (options.fix === true)
22
- cmd.push('--fix');
23
- await $ `${cmd} **/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,html,xml,svg,json,jsonc,yml,yaml,toml}`;
24
- };
25
- }
26
- catch { }
27
- // Stylelint.
28
- try {
29
- const config = getFile('stylelint.config.js', true);
30
- ops.stylelint = async () => {
31
- const cmd = ['npx', 'stylelint', '-c', config, '-i', '.gitignore', '--allow-empty-input', '--color'];
32
- if (options.fix === true)
33
- cmd.push('--fix');
34
- await $ `${cmd} **/*.{css,scss}`;
35
- };
14
+ .action(execute);
15
+ }
16
+ async function execute(type, options) {
17
+ const ops = {};
18
+ // ESLint.
19
+ try {
20
+ const config = getFile('eslint.config.js', true);
21
+ ops.eslint = async () => {
22
+ const cmd = ['npx', 'eslint', '-c', config, '--no-error-on-unmatched-pattern', '--color'];
23
+ if (options.fix === true)
24
+ cmd.push('--fix');
25
+ await $ `${cmd} **/*.{js,ts,jsx,tsx,cjs,cts,mjs,mts,vue,html,xml,svg,json,jsonc,yml,yaml,toml}`;
26
+ };
27
+ }
28
+ catch { }
29
+ // Stylelint.
30
+ try {
31
+ const config = getFile('stylelint.config.js', true);
32
+ ops.stylelint = async () => {
33
+ const cmd = ['npx', 'stylelint', '-c', config, '-i', '.gitignore', '--allow-empty-input', '--color'];
34
+ if (options.fix === true)
35
+ cmd.push('--fix');
36
+ await $ `${cmd} **/*.{css,scss}`;
37
+ };
38
+ }
39
+ catch { }
40
+ // TypeScript.
41
+ try {
42
+ const config = getFile('tsconfig.json');
43
+ ops.typescript = async () => {
44
+ const cmd = ['npx', 'tsc', '-p', config, '--noEmit', '--pretty'];
45
+ await $ `${cmd}`;
46
+ };
47
+ }
48
+ catch { }
49
+ // Run all linters in parallel.
50
+ if (type === 'all') {
51
+ const tasks = new Listr([], {
52
+ collectErrors: 'minimal',
53
+ concurrent: true,
54
+ exitOnError: false,
55
+ rendererOptions: { showErrorMessage: false },
56
+ });
57
+ Object.entries(ops).forEach(([title, func]) => {
58
+ tasks.add([{ title, task: async () => func() }]);
59
+ });
60
+ await tasks.run();
61
+ if (tasks.errors.length > 0) {
62
+ tasks.errors.forEach((listrError) => {
63
+ const error = listrError.error;
64
+ let lines = (error.stdout || error.stderr || error.message).trim().split(/\r\n?|\n/);
65
+ if (listrError.task.title.includes('eslint'))
66
+ lines = lines.slice(1, -1);
67
+ console.error(chalk.yellow(`\n${listrError.task.title}`));
68
+ console.error(chalk.yellow(`${'='.repeat(listrError.task.title.length)}\n`));
69
+ console.error(lines.join('\n'));
70
+ });
71
+ process.exit(1);
36
72
  }
37
- catch { }
38
- // TypeScript.
73
+ }
74
+ // Run individual linter.
75
+ else {
39
76
  try {
40
- const config = getFile('tsconfig.json');
41
- ops.typescript = async () => {
42
- const cmd = ['npx', 'tsc', '-p', config, '--noEmit', '--pretty'];
43
- await $ `${cmd}`;
44
- };
45
- }
46
- catch { }
47
- // Run all linters in parallel.
48
- if (type === 'all') {
49
- const tasks = new Listr([], {
50
- collectErrors: 'minimal',
51
- concurrent: true,
52
- exitOnError: false,
53
- rendererOptions: { showErrorMessage: false },
54
- });
55
- Object.entries(ops).forEach(([title, func]) => {
56
- tasks.add([{ title, task: async () => func() }]);
57
- });
58
- await tasks.run();
59
- if (tasks.errors.length > 0) {
60
- tasks.errors.forEach((listrError) => {
61
- const error = listrError.error;
62
- let lines = (error.stdout || error.stderr || error.message).trim().split(/\r\n?|\n/);
63
- if (listrError.task.title.includes('eslint'))
64
- lines = lines.slice(1, -1);
65
- console.error(chalk.yellow(`\n${listrError.task.title}`));
66
- console.error(chalk.yellow(`${'='.repeat(listrError.task.title.length)}\n`));
67
- console.error(lines.join('\n'));
68
- });
69
- process.exit(1);
70
- }
77
+ if (Object.keys(ops).includes(type))
78
+ await ops[type]();
71
79
  }
72
- // Run individual linter.
73
- else {
74
- try {
75
- if (Object.keys(ops).includes(type))
76
- await ops[type]();
77
- }
78
- catch (error) {
79
- console.error(error.stderr || error.stdout || error.message);
80
- process.exit(1);
81
- }
80
+ catch (error) {
81
+ console.error(error.stderr || error.stdout || error.message);
82
+ process.exit(1);
82
83
  }
83
- });
84
+ }
84
85
  }
@@ -1,2 +1,2 @@
1
1
  import type { Command } from 'commander';
2
- export default function execute(app: Command): void;
2
+ export default function register(app: Command): void;
@@ -1,5 +1,5 @@
1
1
  import { $ } from 'execa';
2
- export default function execute(app) {
2
+ export default function register(app) {
3
3
  app
4
4
  .command('turbo')
5
5
  .description('Run turbo tasks')
@@ -8,22 +8,26 @@ export default function execute(app) {
8
8
  .option('--force', 'Ignore cache')
9
9
  .option('--production', 'Use production mode')
10
10
  .option('--watch', 'Use watch mode')
11
- .action(async (task, workspace, options) => {
12
- const cmd = ['npx', 'turbo', 'run', task];
13
- const opt = [];
14
- // Set default workspace when using watch mode.
15
- if (options.watch && !workspace)
16
- workspace = '@theme/global';
17
- if (workspace)
18
- cmd.push('--filter', workspace);
19
- if (options.force)
20
- cmd.push('--force');
21
- if (!options.production)
22
- cmd.push('--continue');
23
- if (options.production)
24
- opt.push('--production');
25
- if (options.watch)
26
- opt.push('--watch');
27
- await $({ stdio: 'inherit' }) `${cmd} -- ${opt}`;
28
- });
11
+ .option('--tui', 'Use TUI')
12
+ .action(execute);
13
+ }
14
+ async function execute(task, workspace, options) {
15
+ const cmd = ['npx', 'turbo', 'run', task];
16
+ const opt = [];
17
+ // Set default workspace when using watch mode.
18
+ if (options.watch && !workspace)
19
+ workspace = '@theme/global';
20
+ if (workspace)
21
+ cmd.push('--filter', workspace);
22
+ if (options.force)
23
+ cmd.push('--force');
24
+ if (!options.production)
25
+ cmd.push('--continue');
26
+ if (options.production)
27
+ opt.push('--production');
28
+ if (options.watch)
29
+ opt.push('--watch');
30
+ if (options.tui)
31
+ cmd.push('--ui', 'tui');
32
+ await $({ stdio: 'inherit' }) `${cmd} -- ${opt}`;
29
33
  }
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
  import registerBuild from "./commands/build.js";
3
+ import registerDiff from "./commands/diff.js";
3
4
  import registerLint from "./commands/lint.js";
4
5
  import registerTurbo from "./commands/turbo.js";
5
6
  export default async function execute() {
@@ -8,6 +9,7 @@ export default async function execute() {
8
9
  .helpOption('-h, --help', 'Show help')
9
10
  .helpCommand(false);
10
11
  registerBuild(app);
12
+ registerDiff(app);
11
13
  registerLint(app);
12
14
  registerTurbo(app);
13
15
  await app.parseAsync();
@@ -1 +1,2 @@
1
1
  export declare function getFile(name: string, rootOnly?: boolean): string;
2
+ export declare function getRepoRoot(): string;
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import process from 'node:process';
4
+ import { $ } from 'execa';
4
5
  export function getFile(name, rootOnly = false) {
5
6
  const root = String(process.env.npm_config_local_prefix || process.env.PWD);
6
7
  const workspace = String(process.env.INIT_CWD || process.env.PWD);
@@ -15,3 +16,6 @@ export function getFile(name, rootOnly = false) {
15
16
  throw new Error(`Missing ${name} file.`);
16
17
  return filepath;
17
18
  }
19
+ export function getRepoRoot() {
20
+ return $.sync `git rev-parse --show-toplevel`.stdout;
21
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@imagexmedia/cli",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.4-beta.1",
5
5
  "description": "The ImageX SWAT CLI package.",
6
6
  "author": "ImageX Media",
7
7
  "license": "MIT",
@@ -21,6 +21,9 @@
21
21
  "configs",
22
22
  "dist"
23
23
  ],
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
24
27
  "scripts": {
25
28
  "build": "rm -rf dist && tsc -b && chmod +x dist/bin/*.js && mkdir -p packs && npm pack --pack-destination packs"
26
29
  },
@@ -28,6 +31,6 @@
28
31
  "chalk": "^5.6.2",
29
32
  "commander": "^14.0.2",
30
33
  "execa": "^9.6.1",
31
- "listr2": "^9.0.5"
34
+ "listr2": "^10.1.0"
32
35
  }
33
36
  }