@reliverse/pathkit 1.1.5 → 1.1.6

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.
@@ -0,0 +1,27 @@
1
+ export interface ImportExportSpecifier {
2
+ type: "named" | "default" | "namespace" | "all";
3
+ name: string;
4
+ alias?: string;
5
+ isType?: boolean;
6
+ }
7
+ export interface ImportExportInfo {
8
+ statement: string;
9
+ type: "static" | "dynamic";
10
+ kind: "import" | "export";
11
+ source?: string;
12
+ pathType?: "alias" | "relative" | "absolute" | "bare" | "module";
13
+ pathTypeSymbol?: string;
14
+ isTypeOnly?: boolean;
15
+ specifiers?: ImportExportSpecifier[];
16
+ start: number;
17
+ end: number;
18
+ }
19
+ export interface GetFileImportsExportsOptions {
20
+ kind?: "import" | "export" | "all";
21
+ pathTypes?: ("alias" | "relative" | "absolute" | "bare" | "module")[];
22
+ limitPerType?: number;
23
+ }
24
+ /**
25
+ * analyzes a file's content to extract import and export statements
26
+ */
27
+ export declare function getFileImportsExports(content: string, options?: GetFileImportsExportsOptions): ImportExportInfo[];
@@ -0,0 +1,189 @@
1
+ export function getFileImportsExports(content, options = {}) {
2
+ const {
3
+ kind = "all",
4
+ pathTypes = ["alias", "relative", "absolute", "bare", "module"],
5
+ limitPerType
6
+ } = options;
7
+ const results = [];
8
+ const patterns = {
9
+ // import statements with from clause
10
+ staticImport: /import\s+(?:type\s+)?(?:(?:\w+)(?:\s*,\s*)?)?(?:\{[^}]*\}|\*\s+as\s+\w+)?\s+from\s+['"]([^'"]+)['"]|import\s+(?:type\s+)?(\w+)\s+from\s+['"]([^'"]+)['"]/g,
11
+ // dynamic imports
12
+ dynamicImport: /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
13
+ // export statements with from clause
14
+ staticExport: /export\s+(?:type\s+)?(?:\{[^}]*\}|\*(?:\s+as\s+\w+)?)\s+from\s+['"]([^'"]+)['"]/g,
15
+ // default exports without from
16
+ defaultExport: /export\s+default\s+(?:\w+|\{[^}]*\}|class\s+\w+|function\s+\w+)/g,
17
+ // named exports without from
18
+ namedExport: /export\s+(?:const|let|var|function|class|enum|interface|type)\s+(\w+)/g
19
+ };
20
+ function getPathType(path) {
21
+ if (path.startsWith(".")) return "relative";
22
+ if (path.startsWith("/")) return "absolute";
23
+ if (path.startsWith("@") || path.startsWith("~")) return "alias";
24
+ if (path.startsWith("http://") || path.startsWith("https://"))
25
+ return "module";
26
+ return "bare";
27
+ }
28
+ function extractSpecifiers(statement) {
29
+ const specifiers = [];
30
+ const isTypeOnly = statement.includes("import type") || statement.includes("export type");
31
+ const namespaceMatch = /(?:import|export)\s+(?:type\s+)?\*\s+as\s+(\w+)/.exec(statement);
32
+ if (namespaceMatch) {
33
+ specifiers.push({
34
+ type: "namespace",
35
+ name: namespaceMatch[1],
36
+ isType: isTypeOnly
37
+ });
38
+ return specifiers;
39
+ }
40
+ const defaultMatch = /import\s+(?:type\s+)?(\w+)(?:\s*,|\s+from)/.exec(
41
+ statement
42
+ );
43
+ if (defaultMatch && !statement.includes("{")) {
44
+ specifiers.push({
45
+ type: "default",
46
+ name: defaultMatch[1],
47
+ isType: isTypeOnly
48
+ });
49
+ }
50
+ const namedMatch = /{([^}]*)}/.exec(statement);
51
+ if (namedMatch) {
52
+ const items = namedMatch[1].split(",").map((item) => item.trim()).filter((item) => item.length > 0);
53
+ for (const item of items) {
54
+ const typeMatch = /^type\s+(.+)/.exec(item);
55
+ const actualItem = typeMatch ? typeMatch[1] : item;
56
+ const isItemType = !!typeMatch || isTypeOnly;
57
+ if (actualItem.includes(" as ")) {
58
+ const [name, alias] = actualItem.split(" as ").map((p) => p.trim());
59
+ specifiers.push({
60
+ type: "named",
61
+ name,
62
+ alias,
63
+ isType: isItemType
64
+ });
65
+ } else {
66
+ specifiers.push({
67
+ type: "named",
68
+ name: actualItem,
69
+ isType: isItemType
70
+ });
71
+ }
72
+ }
73
+ }
74
+ return specifiers;
75
+ }
76
+ if (kind === "import" || kind === "all") {
77
+ const importMatches = [...content.matchAll(patterns.staticImport)];
78
+ for (const match of importMatches) {
79
+ const source = match[1] || match[3];
80
+ if (!source) continue;
81
+ const pathType = getPathType(source);
82
+ if (!pathTypes.includes(pathType)) continue;
83
+ const info = {
84
+ statement: match[0],
85
+ type: "static",
86
+ kind: "import",
87
+ source,
88
+ pathType,
89
+ pathTypeSymbol: pathType === "alias" ? /^[@~]/.exec(source)?.[0] : void 0,
90
+ isTypeOnly: match[0].includes("import type"),
91
+ specifiers: extractSpecifiers(match[0]),
92
+ start: match.index,
93
+ end: match.index + match[0].length
94
+ };
95
+ results.push(info);
96
+ }
97
+ const dynamicMatches = [...content.matchAll(patterns.dynamicImport)];
98
+ for (const match of dynamicMatches) {
99
+ const source = match[1];
100
+ if (!source) continue;
101
+ const pathType = getPathType(source);
102
+ if (!pathTypes.includes(pathType)) continue;
103
+ const info = {
104
+ statement: match[0],
105
+ type: "dynamic",
106
+ kind: "import",
107
+ source,
108
+ pathType,
109
+ pathTypeSymbol: pathType === "alias" ? /^[@~]/.exec(source)?.[0] : void 0,
110
+ isTypeOnly: false,
111
+ specifiers: [],
112
+ start: match.index,
113
+ end: match.index + match[0].length
114
+ };
115
+ results.push(info);
116
+ }
117
+ }
118
+ if (kind === "export" || kind === "all") {
119
+ const exportMatches = [...content.matchAll(patterns.staticExport)];
120
+ for (const match of exportMatches) {
121
+ const source = match[1];
122
+ if (!source) continue;
123
+ const pathType = getPathType(source);
124
+ if (!pathTypes.includes(pathType)) continue;
125
+ const info = {
126
+ statement: match[0],
127
+ type: "static",
128
+ kind: "export",
129
+ source,
130
+ pathType,
131
+ pathTypeSymbol: pathType === "alias" ? /^[@~]/.exec(source)?.[0] : void 0,
132
+ isTypeOnly: match[0].includes("export type"),
133
+ specifiers: extractSpecifiers(match[0]),
134
+ start: match.index,
135
+ end: match.index + match[0].length
136
+ };
137
+ results.push(info);
138
+ }
139
+ const defaultMatches = [...content.matchAll(patterns.defaultExport)];
140
+ for (const match of defaultMatches) {
141
+ const info = {
142
+ statement: match[0],
143
+ type: "static",
144
+ kind: "export",
145
+ source: void 0,
146
+ pathType: void 0,
147
+ pathTypeSymbol: void 0,
148
+ isTypeOnly: false,
149
+ specifiers: [{ type: "default", name: "default" }],
150
+ start: match.index,
151
+ end: match.index + match[0].length
152
+ };
153
+ results.push(info);
154
+ }
155
+ const namedMatches = [...content.matchAll(patterns.namedExport)];
156
+ for (const match of namedMatches) {
157
+ const name = match[1];
158
+ if (!name) continue;
159
+ const info = {
160
+ statement: match[0],
161
+ type: "static",
162
+ kind: "export",
163
+ source: void 0,
164
+ pathType: void 0,
165
+ pathTypeSymbol: void 0,
166
+ isTypeOnly: match[0].includes("export type"),
167
+ specifiers: [{ type: "named", name }],
168
+ start: match.index,
169
+ end: match.index + match[0].length
170
+ };
171
+ results.push(info);
172
+ }
173
+ }
174
+ if (limitPerType) {
175
+ const groupedByType = results.reduce(
176
+ (acc, curr) => {
177
+ const key = `${curr.kind}-${curr.pathType || "none"}`;
178
+ if (!acc[key]) acc[key] = [];
179
+ acc[key].push(curr);
180
+ return acc;
181
+ },
182
+ {}
183
+ );
184
+ return Object.values(groupedByType).flatMap(
185
+ (group) => group.slice(0, limitPerType)
186
+ );
187
+ }
188
+ return results;
189
+ }
package/bin/mod.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { PlatformPath } from "node:path";
2
+ import { getFileImportsExports, type ImportExportInfo, type ImportExportSpecifier, type GetFileImportsExportsOptions } from "./impl/getFileImportsExports.js";
2
3
  declare const normalizedAliasSymbol: unique symbol;
3
4
  interface NormalizedRecord extends Record<string, string> {
4
5
  [normalizedAliasSymbol]?: true;
@@ -219,6 +220,6 @@ declare const path: PlatformPath & {
219
220
  };
220
221
  declare const win32: PlatformPath;
221
222
  declare const delimiter: string;
222
- export type { PlatformPath, PathExtFilter, ImportExtType };
223
- export { _pathBase as posix, win32, basename, delimiter, dirname, extname, filename, format, isAbsolute, join, normalize, parse, relative, resolve, sep, toNamespacedPath, normalizeAliases, resolveAlias, reverseResolveAlias, normalizeWindowsPath, convertStringAliasRelative, convertImportsAliasToRelative, convertImportsExt, stripPathSegments, stripPathSegmentsInDirectory, attachPathSegments, attachPathSegmentsInDirectory, };
223
+ export type { PlatformPath, PathExtFilter, ImportExtType, ImportExportInfo, ImportExportSpecifier, GetFileImportsExportsOptions, };
224
+ export { _pathBase as posix, win32, basename, delimiter, dirname, extname, filename, format, isAbsolute, join, normalize, parse, relative, resolve, sep, toNamespacedPath, normalizeAliases, resolveAlias, reverseResolveAlias, normalizeWindowsPath, convertStringAliasRelative, convertImportsAliasToRelative, convertImportsExt, stripPathSegments, stripPathSegmentsInDirectory, attachPathSegments, attachPathSegmentsInDirectory, getFileImportsExports, };
224
225
  export default path;
package/bin/mod.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import fs from "node:fs/promises";
2
+ import {
3
+ getFileImportsExports
4
+ } from "./impl/getFileImportsExports.js";
2
5
  const log = (msg) => console.log(`\x1B[2m${msg}\x1B[0m`);
3
6
  const logInternal = (msg) => console.log(`\x1B[36;2m${msg}\x1B[0m`);
4
7
  const EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
@@ -583,8 +586,9 @@ async function convertImportsExt({
583
586
  const content = await fs.readFile(fullPath, "utf-8");
584
587
  let updated = content;
585
588
  const changes = [];
586
- const matches = Array.from(content.matchAll(importRegex));
587
- for (const match of matches) {
589
+ let match;
590
+ match = importRegex.exec(content);
591
+ while (match !== null) {
588
592
  const quote = match[1];
589
593
  const importPath = match[2];
590
594
  let replacementPath;
@@ -600,6 +604,7 @@ async function convertImportsExt({
600
604
  const searchStr = `${quote}${importPath}${quote}`;
601
605
  const replaceStr = `${quote}${replacementPath}${quote}`;
602
606
  updated = replaceAllInString(updated, searchStr, replaceStr);
607
+ match = importRegex.exec(updated);
603
608
  }
604
609
  if (content !== updated) {
605
610
  await fs.writeFile(fullPath, updated);
@@ -944,6 +949,7 @@ export {
944
949
  stripPathSegments,
945
950
  stripPathSegmentsInDirectory,
946
951
  attachPathSegments,
947
- attachPathSegmentsInDirectory
952
+ attachPathSegmentsInDirectory,
953
+ getFileImportsExports
948
954
  };
949
955
  export default path;
package/package.json CHANGED
@@ -5,26 +5,8 @@
5
5
  "license": "MIT",
6
6
  "name": "@reliverse/pathkit",
7
7
  "type": "module",
8
- "version": "1.1.5",
9
- "devDependencies": {
10
- "@biomejs/biome": "1.9.4",
11
- "@eslint/js": "^9.27.0",
12
- "@reliverse/dler": "^1.4.6",
13
- "@reliverse/relifso": "^1.2.10",
14
- "@reliverse/relinka": "^1.4.6",
15
- "@reliverse/rematch": "^1.1.0",
16
- "@stylistic/eslint-plugin": "^4.2.0",
17
- "@types/bun": "^1.2.14",
18
- "@types/node": "^22.15.21",
19
- "eslint": "^9.27.0",
20
- "eslint-plugin-no-relative-import-paths": "^1.6.1",
21
- "eslint-plugin-perfectionist": "^4.13.0",
22
- "knip": "^5.57.2",
23
- "magic-string": "^0.30.17",
24
- "p-map": "^7.0.3",
25
- "typescript": "^5.8.3",
26
- "typescript-eslint": "^8.32.1"
27
- },
8
+ "version": "1.1.6",
9
+ "devDependencies": {},
28
10
  "exports": {
29
11
  ".": "./bin/mod.js"
30
12
  },