impacted 0.0.6 → 0.0.8

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
@@ -36,7 +36,7 @@ npx impacted --since main -p "test/**/*.test.js" -p "test/**/*.spec.js"
36
36
  - uses: sozua/impacted@v1
37
37
  id: impacted
38
38
  with:
39
- pattern: '**/*.{test,spec}.{js,mjs,cjs,jsx}' # default
39
+ pattern: '**/*.{test,spec}.{js,mjs,cjs,jsx,ts,mts,cts,tsx}' # default
40
40
 
41
41
  - name: Run impacted tests
42
42
  if: steps.impacted.outputs.has-impacted == 'true'
@@ -73,15 +73,21 @@ run({ files });
73
73
 
74
74
  See [examples/05-node-test-run](./examples/05-node-test-run) for a full working example.
75
75
 
76
+ ## TypeScript
77
+
78
+ TypeScript files (`.ts`, `.mts`, `.cts`, `.tsx`) are supported out of the box on Node.js >= 22.7. Type stripping is handled via `node:module.stripTypeScriptTypes()` — no additional dependencies required.
79
+
80
+ Follows Node.js core's TypeScript philosophy: explicit extensions, no `tsconfig.json`, no path aliases.
81
+
76
82
  ## Limitations
77
83
 
78
- - JavaScript only (`.js`, `.mjs`, `.cjs`, `.jsx`)
79
84
  - Static analysis only — dynamic `require(variable)` not supported
80
85
  - Local files only — `node_modules` changes won't trigger tests
86
+ - TypeScript support requires Node.js >= 22.7 (JS analysis works on Node.js >= 18)
81
87
 
82
88
  ## Requirements
83
89
 
84
- - Node.js >= 18
90
+ - Node.js >= 18 (TypeScript support requires >= 22.7)
85
91
 
86
92
  ## License
87
93
 
package/bin/impacted.js CHANGED
@@ -15,7 +15,7 @@ for (let i = 0; i < args.length; i++) {
15
15
  since = args[++i];
16
16
  }
17
17
  }
18
- const pattern = patterns.length > 0 ? patterns : '**/*.{test,spec}.{js,mjs,cjs,jsx}';
18
+ const pattern = patterns.length > 0 ? patterns : '**/*.{test,spec}.{js,mjs,cjs,jsx,ts,mts,cts,tsx}';
19
19
 
20
20
  async function run(changedFiles) {
21
21
  if (changedFiles.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "impacted",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Find test files impacted by code changes using static dependency analysis",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -0,0 +1,3 @@
1
+ export const JS_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.jsx']);
2
+ export const TS_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.tsx']);
3
+ export const SUPPORTED_EXTENSIONS = new Set([...JS_EXTENSIONS, ...TS_EXTENSIONS]);
package/src/graph.js CHANGED
@@ -2,8 +2,7 @@ import { readFileSync } from 'node:fs';
2
2
  import { extname } from 'node:path';
3
3
  import { parseImports } from './parser.js';
4
4
  import { resolveSpecifier } from './resolver.js';
5
-
6
- const SUPPORTED_EXTENSIONS = ['.js', '.mjs', '.cjs', '.jsx'];
5
+ import { SUPPORTED_EXTENSIONS, TS_EXTENSIONS } from './constants.js';
7
6
 
8
7
  /** @typedef {import('./cache.js').ImportCache} ImportCache */
9
8
 
@@ -13,7 +12,7 @@ const SUPPORTED_EXTENSIONS = ['.js', '.mjs', '.cjs', '.jsx'];
13
12
  * @returns {boolean}
14
13
  */
15
14
  function isSupportedFile(filePath) {
16
- return SUPPORTED_EXTENSIONS.includes(extname(filePath));
15
+ return SUPPORTED_EXTENSIONS.has(extname(filePath));
17
16
  }
18
17
 
19
18
  /**
@@ -28,7 +27,8 @@ export function extractImports(filePath) {
28
27
  } catch {
29
28
  return [];
30
29
  }
31
- return parseImports(source);
30
+ const typescript = TS_EXTENSIONS.has(extname(filePath));
31
+ return parseImports(source, { typescript });
32
32
  }
33
33
 
34
34
  const DEFAULT_EXCLUDE_PATHS = ['node_modules', 'dist'];
package/src/index.d.ts CHANGED
@@ -52,8 +52,13 @@ export function invertGraph(
52
52
  graph: Map<string, Set<string>>,
53
53
  ): Map<string, Set<string>>;
54
54
 
55
+ export interface ParseImportsOptions {
56
+ /** Strip TypeScript syntax before parsing (requires Node >= 22.7) */
57
+ typescript?: boolean;
58
+ }
59
+
55
60
  /** Extract import/require specifiers from source code */
56
- export function parseImports(source: string): string[];
61
+ export function parseImports(source: string, options?: ParseImportsOptions): string[];
57
62
 
58
63
  /** Resolve an import specifier to an absolute file path */
59
64
  export function resolveSpecifier(
package/src/parser.js CHANGED
@@ -1,13 +1,34 @@
1
1
  import * as acorn from 'acorn';
2
2
  import * as walk from 'acorn-walk';
3
+ import * as nodeModule from 'node:module';
3
4
 
4
5
  /**
5
6
  * Extract all import/require specifiers from source code
6
7
  * Handles ESM (import/export) and CJS (require) patterns
7
8
  * @param {string} source - The source code
9
+ * @param {Object} [options]
10
+ * @param {boolean} [options.typescript=false] - Strip TypeScript syntax before parsing (requires Node >= 22.7)
8
11
  * @returns {string[]} Array of import specifiers
9
12
  */
10
- export function parseImports(source) {
13
+ export function parseImports(source, { typescript = false } = {}) {
14
+ if (typescript) {
15
+ if (!nodeModule.stripTypeScriptTypes) {
16
+ if (!parseImports._tsWarned) {
17
+ parseImports._tsWarned = true;
18
+ process.emitWarning(
19
+ 'TypeScript support requires Node.js >= 22.7',
20
+ 'UnsupportedWarning',
21
+ );
22
+ }
23
+ return [];
24
+ }
25
+ try {
26
+ source = nodeModule.stripTypeScriptTypes(source);
27
+ } catch {
28
+ return [];
29
+ }
30
+ }
31
+
11
32
  const imports = [];
12
33
 
13
34
  let ast;
package/src/resolver.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createRequire } from 'node:module';
2
2
  import { builtinModules } from 'node:module';
3
- import { readFileSync } from 'node:fs';
4
- import { dirname, join, resolve } from 'node:path';
3
+ import { existsSync, readFileSync } from 'node:fs';
4
+ import { dirname, extname, join, resolve } from 'node:path';
5
+ import { TS_EXTENSIONS } from './constants.js';
5
6
 
6
7
  /**
7
8
  * Find the nearest package.json from a given path
@@ -111,6 +112,14 @@ export function resolveSpecifier(specifier, parentPath) {
111
112
  const require = createRequire(parentPath);
112
113
  return require.resolve(specifier);
113
114
  } catch {
115
+ // require.resolve doesn't handle TS extensions
116
+ // For relative specifiers with explicit TS extensions, try manual resolution
117
+ if (specifier.startsWith('.') && TS_EXTENSIONS.has(extname(specifier))) {
118
+ const resolved = resolve(dirname(parentPath), specifier);
119
+ if (existsSync(resolved)) {
120
+ return resolved;
121
+ }
122
+ }
114
123
  return null;
115
124
  }
116
125
  }