@somewhatabstract/x 0.0.1 → 0.1.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.
package/src/x-impl.ts CHANGED
@@ -1,5 +1,96 @@
1
+ import {discoverPackages} from "./discover-packages";
2
+ import {HandledError} from "./errors";
3
+ import {executeScript} from "./execute-script";
4
+ import {findMatchingBins} from "./find-matching-bins";
5
+ import {findWorkspaceRoot} from "./find-workspace-root";
1
6
 
2
- export function xImpl(): void {
3
- const x: string = "Hello, world!";
4
- console.log(x);
5
- };
7
+ export interface XOptions {
8
+ dryRun?: boolean;
9
+ }
10
+
11
+ export interface XResult {
12
+ exitCode: number;
13
+ }
14
+
15
+ /**
16
+ * Main implementation of the x command.
17
+ * Finds and executes a bin script from any package in the workspace.
18
+ *
19
+ * @param scriptName - Name of the bin script to execute
20
+ * @param args - Arguments to pass to the script
21
+ * @param options - Additional options
22
+ * @returns Result object with exit code
23
+ */
24
+ export async function xImpl(
25
+ scriptName: string,
26
+ args: string[] = [],
27
+ options: XOptions = {},
28
+ ): Promise<XResult> {
29
+ try {
30
+ if (!scriptName || !scriptName.trim()) {
31
+ throw new HandledError("Script name cannot be empty");
32
+ }
33
+ if (scriptName.includes("/") || scriptName.includes("\\")) {
34
+ throw new HandledError(
35
+ "Script name cannot contain path separators",
36
+ );
37
+ }
38
+
39
+ // Find workspace root
40
+ const workspaceRoot = await findWorkspaceRoot();
41
+
42
+ // Discover all packages
43
+ const packages = await discoverPackages(workspaceRoot);
44
+
45
+ if (packages.length === 0) {
46
+ throw new HandledError(
47
+ "No packages found in workspace. Is this a valid monorepo?",
48
+ );
49
+ }
50
+
51
+ // Find matching bins
52
+ const matchingBins = await findMatchingBins(packages, scriptName);
53
+
54
+ if (matchingBins.length === 0) {
55
+ throw new HandledError(
56
+ `No bin script named "${scriptName}" found in any workspace package.`,
57
+ );
58
+ }
59
+
60
+ if (matchingBins.length > 1) {
61
+ console.error(
62
+ `Multiple packages provide bin "${scriptName}". Please be more specific.`,
63
+ );
64
+ console.error("\nMatching packages:");
65
+ matchingBins.forEach((bin) => {
66
+ console.error(` - ${bin.packageName} (${bin.packagePath})`);
67
+ });
68
+ throw new HandledError(
69
+ `Ambiguous bin name "${scriptName}". Found ${matchingBins.length} matches.`,
70
+ );
71
+ }
72
+
73
+ const bin = matchingBins[0];
74
+
75
+ // Dry run mode - just show what would be executed
76
+ if (options.dryRun) {
77
+ console.log(
78
+ `Would execute: ${bin.binName} from ${bin.packageName}`,
79
+ );
80
+ console.log(` Binary: ${bin.binPath}`);
81
+ console.log(` Arguments: ${args.join(" ")}`);
82
+ return {exitCode: 0};
83
+ }
84
+
85
+ // Execute the script
86
+ const exitCode = await executeScript(bin, args, workspaceRoot);
87
+
88
+ return {exitCode};
89
+ } catch (error) {
90
+ if (error instanceof HandledError) {
91
+ console.error(`Error: ${error.message}`);
92
+ return {exitCode: 1};
93
+ }
94
+ throw error;
95
+ }
96
+ }
@@ -1,7 +1,5 @@
1
1
  /* Visit https://aka.ms/tsconfig to read more about this file */
2
2
  {
3
3
  "extends": "./tsconfig.json",
4
- "exclude": [
5
- "**/*.test.ts",
6
- ],
7
- }
4
+ "exclude": ["**/*.test.ts"]
5
+ }
package/tsconfig.json CHANGED
@@ -1,19 +1,13 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  "target": "esnext",
4
- "lib": [
5
- "es2023"
6
- ],
4
+ "lib": ["es2023"],
7
5
  "moduleDetection": "force",
8
6
  "module": "preserve",
9
7
  "moduleResolution": "bundler",
10
8
  "resolveJsonModule": true,
11
- "types": [
12
- "node"
13
- ],
14
- "typeRoots": [
15
- "./node_modules/@types"
16
- ],
9
+ "types": ["node"],
10
+ "typeRoots": ["./node_modules/@types"],
17
11
  "strict": true,
18
12
  "noUnusedLocals": true,
19
13
  "declaration": true,
@@ -23,7 +17,5 @@
23
17
  "verbatimModuleSyntax": true,
24
18
  "skipLibCheck": true
25
19
  },
26
- "include": [
27
- "src"
28
- ]
29
- }
20
+ "include": ["src"]
21
+ }
package/tsdown.config.ts CHANGED
@@ -7,7 +7,7 @@ export default defineConfig({
7
7
  sourcemap: false,
8
8
  dts: {
9
9
  oxc: true,
10
- tsconfig: "tsconfig-types.json"
10
+ tsconfig: "tsconfig-types.json",
11
11
  },
12
12
  plugins: [
13
13
  process.env.CODECOV_TOKEN
package/vitest.config.ts CHANGED
@@ -3,6 +3,7 @@ import {defineConfig} from "vitest/config";
3
3
  export default defineConfig({
4
4
  test: {
5
5
  coverage: {
6
+ include: ["src/**/*.ts"],
6
7
  reporter: ["text", "json"],
7
8
  },
8
9
  },