@ankhorage/devtools 1.0.3 → 1.0.5

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/README.md CHANGED
@@ -7,6 +7,7 @@ Shared ESLint, Prettier, and Knip configuration for modern TypeScript projects.
7
7
  - Consistent linting across repos
8
8
  - Zero-config Prettier setup
9
9
  - Shared Knip static-analysis defaults
10
+ - Bundled tool binaries for ESLint, Prettier, and Knip
10
11
  - Strict TypeScript rules without compromise
11
12
  - One source of truth for tooling
12
13
 
@@ -16,6 +17,7 @@ Shared ESLint, Prettier, and Knip configuration for modern TypeScript projects.
16
17
  - Preconfigured plugin ecosystem
17
18
  - Prettier integration
18
19
  - Shared Knip config factory
20
+ - `ankhorage-eslint`, `ankhorage-prettier`, and `ankhorage-knip` binaries
19
21
  - Monorepo-friendly
20
22
 
21
23
  ## Installation
@@ -24,28 +26,52 @@ Shared ESLint, Prettier, and Knip configuration for modern TypeScript projects.
24
26
  bun add -D @ankhorage/devtools
25
27
  ```
26
28
 
27
- Install the tools used by your local scripts as development dependencies:
28
-
29
- ```bash
30
- bun add -D eslint prettier knip
31
- ```
29
+ The package owns the ESLint, Prettier, and Knip toolchain. Consuming repos should not install `eslint`, `prettier`, or `knip` directly unless they intentionally need a different version from the shared Ankhorage toolchain.
32
30
 
33
31
  ## Usage
34
32
 
33
+ ### Scripts
34
+
35
+ Use the devtools-owned binaries in package scripts:
36
+
37
+ ```json
38
+ {
39
+ "scripts": {
40
+ "lint": "ankhorage-eslint . --max-warnings=0",
41
+ "lint:fix": "ankhorage-eslint . --fix --max-warnings=0",
42
+ "format": "ankhorage-prettier --write .",
43
+ "format:check": "ankhorage-prettier --check .",
44
+ "knip": "ankhorage-knip"
45
+ }
46
+ }
47
+ ```
48
+
35
49
  ### ESLint
36
50
 
51
+ Create an `eslint.config.js` file:
52
+
37
53
  ```js
38
- import config from '@ankhorage/devtools/eslint';
54
+ import { createConfig } from '@ankhorage/devtools/eslint';
39
55
 
40
- export default config();
56
+ export default createConfig({
57
+ files: ['src/**/*.{ts,tsx}'],
58
+ project: ['./tsconfig.json'],
59
+ tsconfigRootDir: import.meta.dirname,
60
+ });
41
61
  ```
42
62
 
43
63
  ### Prettier
44
64
 
45
- ```json
46
- {
47
- "extends": "@ankhorage/devtools/prettier"
48
- }
65
+ Create a Prettier config file:
66
+
67
+ ```js
68
+ export { default } from '@ankhorage/devtools/prettier';
69
+ ```
70
+
71
+ CommonJS repos can use:
72
+
73
+ ```js
74
+ module.exports = require('@ankhorage/devtools/prettier');
49
75
  ```
50
76
 
51
77
  ### Knip
@@ -58,16 +84,6 @@ import { createKnipConfig } from '@ankhorage/devtools/knip';
58
84
  export default createKnipConfig();
59
85
  ```
60
86
 
61
- Add a package script:
62
-
63
- ```json
64
- {
65
- "scripts": {
66
- "knip": "knip"
67
- }
68
- }
69
- ```
70
-
71
87
  Repos can add narrow repo-specific patterns when needed:
72
88
 
73
89
  ```ts
@@ -77,16 +93,24 @@ export default createKnipConfig({
77
93
  entry: ['scripts/release.ts'],
78
94
  project: ['scripts/**/*.ts'],
79
95
  ignore: ['fixtures/**'],
96
+ ignoreBinaries: ['custom-tool'],
97
+ ignoreFiles: ['examples/fixture.ts'],
80
98
  });
81
99
  ```
82
100
 
83
- The shared config intentionally keeps defaults narrow so Knip does not fail on unmatched optional paths. Prefer explicit `entry`, `project`, or Knip plugin configuration over broad ignores when tool config files are reported as unused.
101
+ The shared config intentionally keeps defaults narrow so Knip can use its own zero-config package discovery. Prefer explicit `entry`, `project`, `ignoreBinaries`, `ignoreDependencies`, or `ignoreFiles` over broad ignores.
84
102
 
85
103
  ### CI
86
104
 
87
- Run Knip in CI after dependencies are installed:
105
+ Run the scripts in CI after dependencies are installed:
88
106
 
89
107
  ```yaml
108
+ - name: Run lint
109
+ run: bun run lint
110
+
111
+ - name: Run format check
112
+ run: bun run format:check
113
+
90
114
  - name: Run Knip
91
115
  run: bun run knip
92
116
  ```
@@ -124,9 +148,9 @@ This package centralizes tooling so all projects stay aligned.
124
148
 
125
149
  Includes:
126
150
 
127
- - ESLint configuration
128
- - Prettier configuration
129
- - Knip configuration
151
+ - ESLint configuration and binary wrapper
152
+ - Prettier configuration and binary wrapper
153
+ - Knip configuration and binary wrapper
130
154
 
131
155
  Excludes:
132
156
 
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runPackageBin } from './internal/runPackageBin.js';
3
+ runPackageBin('eslint', 'eslint');
@@ -0,0 +1 @@
1
+ export declare function runPackageBin(packageName: string, binName: string): void;
@@ -0,0 +1,58 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ const require = createRequire(import.meta.url);
6
+ function isRecord(value) {
7
+ return typeof value === 'object' && value !== null;
8
+ }
9
+ function findPackageJsonPath(packageName) {
10
+ let currentDirectory = dirname(require.resolve(packageName));
11
+ while (currentDirectory !== dirname(currentDirectory)) {
12
+ const packageJsonPath = join(currentDirectory, 'package.json');
13
+ if (existsSync(packageJsonPath)) {
14
+ return packageJsonPath;
15
+ }
16
+ currentDirectory = dirname(currentDirectory);
17
+ }
18
+ throw new Error(`Could not find package metadata for ${packageName}.`);
19
+ }
20
+ function readPackageBinPath(packageName, binName) {
21
+ const packageJsonPath = findPackageJsonPath(packageName);
22
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
23
+ if (!isRecord(packageJson)) {
24
+ throw new Error(`Package metadata for ${packageName} is not an object.`);
25
+ }
26
+ const { bin } = packageJson;
27
+ let relativeBinPath;
28
+ if (typeof bin === 'string') {
29
+ relativeBinPath = bin;
30
+ }
31
+ else if (isRecord(bin)) {
32
+ const namedBin = bin[binName];
33
+ if (typeof namedBin === 'string') {
34
+ relativeBinPath = namedBin;
35
+ }
36
+ }
37
+ if (relativeBinPath === undefined) {
38
+ throw new Error(`Package ${packageName} does not expose a ${binName} binary.`);
39
+ }
40
+ return resolve(dirname(packageJsonPath), relativeBinPath);
41
+ }
42
+ export function runPackageBin(packageName, binName) {
43
+ const binPath = readPackageBinPath(packageName, binName);
44
+ const child = spawn(process.execPath, [binPath, ...process.argv.slice(2)], {
45
+ stdio: 'inherit',
46
+ });
47
+ child.on('error', (error) => {
48
+ console.error(error);
49
+ process.exit(1);
50
+ });
51
+ child.on('exit', (code, signal) => {
52
+ if (signal !== null) {
53
+ console.error(`${binName} exited with signal ${signal}.`);
54
+ process.exit(1);
55
+ }
56
+ process.exit(code ?? 1);
57
+ });
58
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runPackageBin } from './internal/runPackageBin.js';
3
+ runPackageBin('knip', 'knip');
package/dist/knip.d.ts CHANGED
@@ -3,6 +3,7 @@ export interface DevtoolsKnipWorkspaceConfigOptions {
3
3
  entry?: string[];
4
4
  project?: string[];
5
5
  ignore?: string[];
6
+ ignoreBinaries?: string[];
6
7
  ignoreDependencies?: (string | RegExp)[];
7
8
  ignoreFiles?: string[];
8
9
  }
package/dist/knip.js CHANGED
@@ -3,6 +3,7 @@ export function createKnipConfig(options = {}) {
3
3
  ...(options.entry === undefined ? {} : { entry: options.entry }),
4
4
  ...(options.project === undefined ? {} : { project: options.project }),
5
5
  ...(options.ignore === undefined ? {} : { ignore: options.ignore }),
6
+ ...(options.ignoreBinaries === undefined ? {} : { ignoreBinaries: options.ignoreBinaries }),
6
7
  ...(options.ignoreDependencies === undefined
7
8
  ? {}
8
9
  : { ignoreDependencies: options.ignoreDependencies }),
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runPackageBin } from './internal/runPackageBin.js';
3
+ runPackageBin('prettier', 'prettier');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/devtools",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Shared Lint and Format Configuration for Ankhorage",
5
5
  "homepage": "https://github.com/ankhorage/devtools#readme",
6
6
  "bugs": {
@@ -24,6 +24,11 @@
24
24
  "static-analysis",
25
25
  "developer-tools"
26
26
  ],
27
+ "bin": {
28
+ "ankhorage-eslint": "./dist/eslint-cli.js",
29
+ "ankhorage-knip": "./dist/knip-cli.js",
30
+ "ankhorage-prettier": "./dist/prettier-cli.js"
31
+ },
27
32
  "exports": {
28
33
  "./eslint": {
29
34
  "types": "./dist/eslint.d.ts",
@@ -47,6 +52,7 @@
47
52
  "build": "tsc && cp src/prettier.cjs dist/prettier.cjs",
48
53
  "knip": "knip",
49
54
  "lint": "eslint .",
55
+ "lint:fix": "eslint . --fix --max-warnings=0",
50
56
  "format": "prettier --write .",
51
57
  "format:check": "prettier --check .",
52
58
  "test": "bun test",
@@ -60,6 +66,7 @@
60
66
  "eslint-plugin-prettier": "^5.5.5",
61
67
  "eslint-plugin-simple-import-sort": "^12.1.1",
62
68
  "eslint-plugin-unused-imports": "^4.4.1",
69
+ "knip": "^6.12.2",
63
70
  "prettier": "^3.8.1",
64
71
  "typescript-eslint": "^8.24.0"
65
72
  },
@@ -67,7 +74,6 @@
67
74
  "@changesets/cli": "^2.30.0",
68
75
  "@types/bun": "^1.3.13",
69
76
  "@types/node": "^25.2.3",
70
- "knip": "^6.12.2",
71
77
  "typescript": "^5.9.3"
72
78
  },
73
79
  "packageManager": "bun@1.3.13"