eslint-plugin-fast-import 1.0.0-beta2

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.
Files changed (83) hide show
  1. package/.prettierrc.json +6 -0
  2. package/.vscode/launch.json +39 -0
  3. package/LICENSE +21 -0
  4. package/README.md +3 -0
  5. package/dist/module/computeAnalyzedInfo.d.ts +3 -0
  6. package/dist/module/computeAnalyzedInfo.js +297 -0
  7. package/dist/module/computeAnalyzedInfo.js.map +1 -0
  8. package/dist/module/computeBaseInfo.d.ts +24 -0
  9. package/dist/module/computeBaseInfo.js +564 -0
  10. package/dist/module/computeBaseInfo.js.map +1 -0
  11. package/dist/module/computeResolvedInfo.d.ts +7 -0
  12. package/dist/module/computeResolvedInfo.js +361 -0
  13. package/dist/module/computeResolvedInfo.js.map +1 -0
  14. package/dist/module/module.d.ts +20 -0
  15. package/dist/module/module.js +224 -0
  16. package/dist/module/module.js.map +1 -0
  17. package/dist/module/util.d.ts +44 -0
  18. package/dist/module/util.js +67 -0
  19. package/dist/module/util.js.map +1 -0
  20. package/dist/plugin.d.ts +19 -0
  21. package/dist/plugin.js +57 -0
  22. package/dist/plugin.js.map +1 -0
  23. package/dist/rules/circular/circular.d.ts +2 -0
  24. package/dist/rules/circular/circular.js +107 -0
  25. package/dist/rules/circular/circular.js.map +1 -0
  26. package/dist/rules/entryPoint/entryPoint.d.ts +1 -0
  27. package/dist/rules/entryPoint/entryPoint.js +38 -0
  28. package/dist/rules/entryPoint/entryPoint.js.map +1 -0
  29. package/dist/rules/externalBarrelReexports/externalBarrelReexports.d.ts +1 -0
  30. package/dist/rules/externalBarrelReexports/externalBarrelReexports.js +41 -0
  31. package/dist/rules/externalBarrelReexports/externalBarrelReexports.js.map +1 -0
  32. package/dist/rules/missing/missing.d.ts +1 -0
  33. package/dist/rules/missing/missing.js +59 -0
  34. package/dist/rules/missing/missing.js.map +1 -0
  35. package/dist/rules/testInProd/testInProd.d.ts +1 -0
  36. package/dist/rules/testInProd/testInProd.js +42 -0
  37. package/dist/rules/testInProd/testInProd.js.map +1 -0
  38. package/dist/rules/unused/unused.d.ts +3 -0
  39. package/dist/rules/unused/unused.js +77 -0
  40. package/dist/rules/unused/unused.js.map +1 -0
  41. package/dist/rules/util.d.ts +11 -0
  42. package/dist/rules/util.js +107 -0
  43. package/dist/rules/util.js.map +1 -0
  44. package/dist/settings/settings.d.ts +12 -0
  45. package/dist/settings/settings.js +123 -0
  46. package/dist/settings/settings.js.map +1 -0
  47. package/dist/settings/typescript.d.ts +3 -0
  48. package/dist/settings/typescript.js +39 -0
  49. package/dist/settings/typescript.js.map +1 -0
  50. package/dist/settings/user.d.ts +45 -0
  51. package/dist/settings/user.js +52 -0
  52. package/dist/settings/user.js.map +1 -0
  53. package/dist/settings/util.d.ts +2 -0
  54. package/dist/settings/util.js +33 -0
  55. package/dist/settings/util.js.map +1 -0
  56. package/dist/types/analyzed.d.ts +120 -0
  57. package/dist/types/analyzed.js +2 -0
  58. package/dist/types/analyzed.js.map +1 -0
  59. package/dist/types/base.d.ts +230 -0
  60. package/dist/types/base.js +2 -0
  61. package/dist/types/base.js.map +1 -0
  62. package/dist/types/context.d.ts +2 -0
  63. package/dist/types/context.js +2 -0
  64. package/dist/types/context.js.map +1 -0
  65. package/dist/types/resolved.d.ts +60 -0
  66. package/dist/types/resolved.js +2 -0
  67. package/dist/types/resolved.js.map +1 -0
  68. package/dist/util/code.d.ts +1 -0
  69. package/dist/util/code.js +6 -0
  70. package/dist/util/code.js.map +1 -0
  71. package/dist/util/error.d.ts +14 -0
  72. package/dist/util/error.js +19 -0
  73. package/dist/util/error.js.map +1 -0
  74. package/dist/util/files.d.ts +10 -0
  75. package/dist/util/files.js +122 -0
  76. package/dist/util/files.js.map +1 -0
  77. package/dist/util/logging.d.ts +5 -0
  78. package/dist/util/logging.js +19 -0
  79. package/dist/util/logging.js.map +1 -0
  80. package/eslint.config.mjs +85 -0
  81. package/jest.config.ts +10 -0
  82. package/package.json +49 -0
  83. package/tsconfig.json +31 -0
@@ -0,0 +1,230 @@
1
+ import type { TSESTree } from '@typescript-eslint/utils';
2
+ type Base = {
3
+ /**
4
+ * The AST node in ESTree format of the complete ESM statement for this entry
5
+ */
6
+ statementNode: TSESTree.Node;
7
+ /**
8
+ * The AST node in ESTree format to report an error on, if one exists.
9
+ *
10
+ * Note: this may not be the node representing the entire ESM statement
11
+ */
12
+ reportNode: TSESTree.Node | TSESTree.Token;
13
+ };
14
+ export type BaseSingleImport = Base & {
15
+ importType: 'single';
16
+ /**
17
+ * Where we're importing from, e.g. `'./bar'` in:
18
+ *
19
+ * ```
20
+ * import { foo } from './bar'
21
+ * ```
22
+ */
23
+ moduleSpecifier: string;
24
+ /**
25
+ * What we're importing, e.g. `foo` in:
26
+ *
27
+ * ```
28
+ * import { foo } from './bar'
29
+ * ```
30
+ */
31
+ importName: string;
32
+ /**
33
+ * What we're calling the import locally. This is usually the same as `importName`, but can sometimes be different. If
34
+ * we do:
35
+ *
36
+ * ```
37
+ * import { foo as alias } from './bar'
38
+ * ```
39
+ *
40
+ * then `importName` equals `foo` and `importAlias` equals `alias`
41
+ */
42
+ importAlias: string;
43
+ /**
44
+ * If true, then this is a TypeScript type import, e.g.
45
+ *
46
+ * ```
47
+ * import type { Foo } from './bar'
48
+ * ```
49
+ */
50
+ isTypeImport: boolean;
51
+ };
52
+ export type BaseBarrelImport = Base & {
53
+ importType: 'barrel';
54
+ /**
55
+ * Where we're importing from, e.g. `'./bar'` in:
56
+ *
57
+ * ```
58
+ * import * as foo from './bar'
59
+ * ```
60
+ */
61
+ moduleSpecifier: string;
62
+ /**
63
+ * What we're calling the import, named for consistency with single imports. If
64
+ * we do:
65
+ *
66
+ * ```
67
+ * import * as foo from './bar'
68
+ * ```
69
+ *
70
+ * then `importAlias` equals `foo`
71
+ */
72
+ importAlias: string;
73
+ /**
74
+ * If true, then this is a TypeScript type import, e.g.
75
+ *
76
+ * ```
77
+ * import type * as Foo from './bar'
78
+ * ```
79
+ */
80
+ isTypeImport: boolean;
81
+ };
82
+ export type BaseDynamicImport = Base & {
83
+ importType: 'dynamic';
84
+ /**
85
+ * Where we're importing from, e.g. `'./bar'` in:
86
+ *
87
+ * ```
88
+ * import('./bar')
89
+ * ```
90
+ *
91
+ * Note: if the value is not a string literal, then this value is `undefined`
92
+ */
93
+ moduleSpecifier: string | undefined;
94
+ };
95
+ export type BaseImport = BaseSingleImport | BaseBarrelImport | BaseDynamicImport;
96
+ export type BaseExport = Base & {
97
+ /**
98
+ * What we're export, e.g. `foo` in:
99
+ *
100
+ * ```
101
+ * export const foo = 10;
102
+ * ```
103
+ */
104
+ exportName: string;
105
+ /**
106
+ * Indicates whether or not this rexport is an entry point for the app. For example, if we're running a Next.js app
107
+ * and this export is `getServerSideProps` in a page file, the we consider this an an entry point export since
108
+ * we'll never see the import itself
109
+ */
110
+ isEntryPoint: boolean;
111
+ /**
112
+ * If true, then this is a TypeScript type import, e.g.
113
+ *
114
+ * ```
115
+ * export type Foo = 10;
116
+ * ```
117
+ */
118
+ isTypeExport: boolean;
119
+ };
120
+ export type BaseSingleReexport = Base & {
121
+ reexportType: 'single';
122
+ /**
123
+ * Where we're reexporting from, e.g. `'./bar'` in:
124
+ *
125
+ * ```
126
+ * export { foo } from './bar'
127
+ * ```
128
+ */
129
+ moduleSpecifier: string;
130
+ /**
131
+ * What we're reexporting, e.g. `foo` in:
132
+ *
133
+ * ```
134
+ * export { foo } from './bar'
135
+ * ```
136
+ */
137
+ importName: string;
138
+ /**
139
+ * What we're naming the reexport. This is usually the same as `importName`, but can sometimes be different. If we do:
140
+ *
141
+ * ```
142
+ * export { foo as alias } from './bar'
143
+ * ```
144
+ *
145
+ * then `importName` equals `foo` and `exportName` equals `alias`
146
+ */
147
+ exportName: string;
148
+ /**
149
+ * If true, then this is a TypeScript type reexport, e.g.
150
+ *
151
+ * ```
152
+ * export type { Foo } from './bar'
153
+ * ```
154
+ */
155
+ isTypeReexport: boolean;
156
+ /**
157
+ * Indicates whether or not this reexport is an entry point for the app. For example, if we're running a Next.js app
158
+ * and this reexport is `getServerSideProps` in a page file, the we consider this an an entry point reexport since
159
+ * we'll never see the import itself
160
+ */
161
+ isEntryPoint: boolean;
162
+ };
163
+ export type BaseBarrelReexport = Base & {
164
+ reexportType: 'barrel';
165
+ /**
166
+ * Where we're reexporting from, e.g. `'./bar'` in:
167
+ *
168
+ * ```
169
+ * export * from './bar'
170
+ * ```
171
+ */
172
+ moduleSpecifier: string;
173
+ /**
174
+ * The name of the rollup object, if specified, e.g. `foo` in:
175
+ *
176
+ * ```
177
+ * export * as foo from './bar'
178
+ * ```
179
+ */
180
+ exportName: string | undefined;
181
+ /**
182
+ * If true, then this is a TypeScript type reexport, e.g.
183
+ *
184
+ * ```
185
+ * export type * from './bar'
186
+ * ```
187
+ */
188
+ isTypeReexport: boolean;
189
+ /**
190
+ * Indicates whether or not this reexport is an entry point for the app. For example, if we're running a Next.js app
191
+ * and this reexport is `getServerSideProps` in a page file, the we consider this an an entry point reexport since
192
+ * we'll never see the import itself
193
+ */
194
+ isEntryPoint: boolean;
195
+ };
196
+ export type BaseReexport = BaseSingleReexport | BaseBarrelReexport;
197
+ /**
198
+ * This represents a file that is imported in ESM code, but is not an ESM file. Examples include importing CSS or JSON
199
+ * files. These files get an entry for bookeeping reasons, but otherwise are not parsed or anlayzed
200
+ */
201
+ export type BaseOtherFileDetails = {
202
+ fileType: 'other';
203
+ };
204
+ /**
205
+ * Represents an ESM file and its imports, exports, and reexports.
206
+ */
207
+ export type BaseCodeFileDetails = {
208
+ fileType: 'code';
209
+ lastUpdatedAt: number;
210
+ imports: BaseImport[];
211
+ exports: BaseExport[];
212
+ reexports: BaseReexport[];
213
+ };
214
+ type BaseFileDetails = BaseOtherFileDetails | BaseCodeFileDetails;
215
+ export type BaseProjectInfo = {
216
+ /**
217
+ * Mapping of _absolute_ file paths to file details
218
+ */
219
+ files: Map<string, BaseFileDetails>;
220
+ /**
221
+ * The root path of source code in the project
222
+ */
223
+ rootDir: string;
224
+ /**
225
+ * If defined, an alias for referencing first party imports absolutely. For example, Next.js defaults to `@`, meaning
226
+ * a file at `src/components/foo` can be imported anywhere with `@/components/foo`
227
+ */
228
+ alias: Record<string, string>;
229
+ };
230
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/types/base.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ import type { RuleContext } from '@typescript-eslint/utils/ts-eslint';
2
+ export type GenericContext = RuleContext<string, readonly unknown[]>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/types/context.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import type { BaseBarrelImport, BaseBarrelReexport, BaseDynamicImport, BaseExport, BaseOtherFileDetails, BaseProjectInfo, BaseSingleImport, BaseSingleReexport } from './base.js';
2
+ export type Resolved = {
3
+ moduleType: 'builtin';
4
+ } | {
5
+ moduleType: 'thirdParty';
6
+ } | {
7
+ moduleType: 'firstPartyCode';
8
+ /**
9
+ * The absolute path of the file that the import/reexport points to. For the statement in a file at
10
+ * `/Users/bryan/myProject/src/foo.ts`:
11
+ *
12
+ * ```
13
+ * import { bar } from './bar';
14
+ * ```
15
+ *
16
+ * then `resolvedModulePath` is `/Users/bryan/myProject/src/bar/index.ts`
17
+ */
18
+ resolvedModulePath: string;
19
+ } | {
20
+ moduleType: 'firstPartyOther';
21
+ /**
22
+ * The absolute path of the file that the import/reexport points to. For the statement in a file at
23
+ * `/Users/bryan/myProject/src/foo.ts`:
24
+ *
25
+ * ```
26
+ * import { bar } from './bar';
27
+ * ```
28
+ *
29
+ * then `resolvedModulePath` is `/Users/bryan/myProject/src/bar/index.ts`
30
+ *
31
+ * Note: value is `undefined` if the import can't be resolved, aka the module specifier isn't valid. While the
32
+ * developer's intentions might have been to import a code file, we can't don't know for sure. Pretending it's
33
+ * always a non-code file is safer
34
+ */
35
+ resolvedModulePath: string | undefined;
36
+ };
37
+ export type ResolvedSingleImport = BaseSingleImport & Resolved;
38
+ export type ResolvedBarrelImport = BaseBarrelImport & Resolved;
39
+ export type ResolvedDynamicImport = BaseDynamicImport & Resolved;
40
+ export type ResolvedImport = ResolvedSingleImport | ResolvedBarrelImport | ResolvedDynamicImport;
41
+ export type ResolvedExport = BaseExport;
42
+ export type ResolvedSingleReexport = BaseSingleReexport & Resolved;
43
+ export type ResolvedBarrelReexport = BaseBarrelReexport & Resolved;
44
+ export type ResolvedReexport = ResolvedSingleReexport | ResolvedBarrelReexport;
45
+ export type ResolvedOtherFileDetails = BaseOtherFileDetails;
46
+ export type ResolvedCodeFileDetails = {
47
+ fileType: 'code';
48
+ lastUpdatedAt: number;
49
+ imports: ResolvedImport[];
50
+ exports: ResolvedExport[];
51
+ reexports: ResolvedReexport[];
52
+ };
53
+ type ResolvedFileDetails = ResolvedOtherFileDetails | ResolvedCodeFileDetails;
54
+ export type ResolvedProjectInfo = Omit<BaseProjectInfo, 'files'> & {
55
+ /**
56
+ * Mapping of _absolute_ file paths to file details
57
+ */
58
+ files: Map<string, ResolvedFileDetails>;
59
+ };
60
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=resolved.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolved.js","sourceRoot":"","sources":["../../src/types/resolved.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export declare function isCodeFile(filePath: string): boolean;
@@ -0,0 +1,6 @@
1
+ import { extname } from 'node:path';
2
+ const VALID_EXTENSIONS = ['.ts', '.tsx', '.mts', '.js', '.jsx', '.mjs'];
3
+ export function isCodeFile(filePath) {
4
+ return VALID_EXTENSIONS.includes(extname(filePath));
5
+ }
6
+ //# sourceMappingURL=code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.js","sourceRoot":"","sources":["../../src/util/code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAExE,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { TSESTree } from '@typescript-eslint/utils';
2
+ type SourceDetails = {
3
+ filePath: string;
4
+ fileContents?: string;
5
+ node: TSESTree.Node;
6
+ };
7
+ /**
8
+ * An error class that adds special formatting for internal errors, including printing out what file and AST node was
9
+ * being processed when the error occured
10
+ */
11
+ export declare class InternalError extends Error {
12
+ constructor(message: string, sourceDetails?: SourceDetails);
13
+ }
14
+ export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * An error class that adds special formatting for internal errors, including printing out what file and AST node was
3
+ * being processed when the error occured
4
+ */
5
+ export class InternalError extends Error {
6
+ constructor(message, sourceDetails) {
7
+ let formattedMessage = `Internal error: ${message}. This is a bug, please report the message and the stack trace to the maintainer at https://github.com/nebrius/fast-import/issues`;
8
+ if (sourceDetails) {
9
+ if (sourceDetails.fileContents) {
10
+ formattedMessage += `\n\nIn ${sourceDetails.filePath}:\n\n${sourceDetails.fileContents.substring(sourceDetails.node.range[0], sourceDetails.node.range[1])}\n`;
11
+ }
12
+ else {
13
+ formattedMessage += `\n\nIn ${sourceDetails.filePath}\n`;
14
+ }
15
+ }
16
+ super(formattedMessage);
17
+ }
18
+ }
19
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/util/error.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe,EAAE,aAA6B;QACxD,IAAI,gBAAgB,GAAG,mBAAmB,OAAO,mIAAmI,CAAC;QACrL,IAAI,aAAa,EAAE,CAAC;YAClB,IAAI,aAAa,CAAC,YAAY,EAAE,CAAC;gBAC/B,gBAAgB,IAAI,UAAU,aAAa,CAAC,QAAQ,QAAQ,aAAa,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACjK,CAAC;iBAAM,CAAC;gBACN,gBAAgB,IAAI,UAAU,aAAa,CAAC,QAAQ,IAAI,CAAC;YAC3D,CAAC;QACH,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,10 @@
1
+ import type { IgnorePattern } from '../settings/settings.js';
2
+ export declare function getFilesSync(rootDir: string, ignorePatterns: IgnorePattern[]): {
3
+ filePath: string;
4
+ latestUpdatedAt: number;
5
+ }[];
6
+ export declare function getFiles(rootDir: string, ignorePatterns: IgnorePattern[]): Promise<{
7
+ filePath: string;
8
+ latestUpdatedAt: number;
9
+ }[]>;
10
+ export declare function isFileIgnored(rootDir: string, filePath: string): boolean;
@@ -0,0 +1,122 @@
1
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
2
+ import { readdir, stat } from 'node:fs/promises';
3
+ import { basename, dirname, join, relative } from 'node:path';
4
+ import ignore from 'ignore';
5
+ import { InternalError } from './error.js';
6
+ export function getFilesSync(rootDir, ignorePatterns) {
7
+ // Read in the files and their stats, and filter out directories
8
+ const potentialFiles = readdirSync(rootDir, {
9
+ recursive: true,
10
+ encoding: 'utf-8',
11
+ })
12
+ .map((f) => join(rootDir, f))
13
+ // Stats will be used for multiple checks later, so we want to cache it now.
14
+ // Unfortunately we need more than what {withFileTypes: true} provides, so
15
+ // we still need to call statSync separately
16
+ .map((filePath) => ({ filePath, stats: statSync(filePath) }))
17
+ // Filter out any directories, so that this is only a file list
18
+ .filter((f) => !f.stats.isDirectory());
19
+ // Return the list of files
20
+ return buildFileList(rootDir, ignorePatterns, potentialFiles.filter(({ filePath }) => basename(filePath) !== '.gitignore'));
21
+ }
22
+ export async function getFiles(rootDir, ignorePatterns) {
23
+ // First, read in the files and convert the results to absolute path
24
+ const potentialFilePaths = (await readdir(rootDir, {
25
+ recursive: true,
26
+ encoding: 'utf-8',
27
+ })).map((f) => join(rootDir, f));
28
+ // Now add the stats to each file
29
+ const potentialFiles = (await Promise.all(potentialFilePaths.map(async (filePath) => {
30
+ const stats = await stat(filePath);
31
+ return { filePath, stats };
32
+ })))
33
+ // Filter out any directories, so that this is only a file list
34
+ .filter((f) => !f.stats.isDirectory());
35
+ // Return the list of files
36
+ return buildFileList(rootDir, ignorePatterns, potentialFiles.filter(({ filePath }) => basename(filePath) !== '.gitignore'));
37
+ }
38
+ let ignores = null;
39
+ export function isFileIgnored(rootDir, filePath) {
40
+ if (!ignores) {
41
+ throw new InternalError(`isFileIgnored called before ignores initialized`);
42
+ }
43
+ if (!filePath.startsWith(rootDir)) {
44
+ return true;
45
+ }
46
+ for (const { dir, ig } of ignores) {
47
+ // Ignore file paths are relative to the directory the ignore file is in,
48
+ // and needs files passed in to check to also be relative to that same
49
+ // directory, so we get the relative path to the ignore file directory
50
+ if (filePath.startsWith(dir) && ig.ignores(relative(dir, filePath))) {
51
+ return true;
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+ function buildFileList(rootDir, ignorePatterns, potentialFiles) {
57
+ // Create the ignore instances for use in filtering
58
+ initializeIgnores(rootDir, ignorePatterns, potentialFiles);
59
+ // Filter out ignored files
60
+ const files = [];
61
+ for (const { filePath, stats } of potentialFiles) {
62
+ if (isFileIgnored(rootDir, filePath)) {
63
+ continue;
64
+ }
65
+ files.push({
66
+ filePath,
67
+ latestUpdatedAt: stats.mtimeMs,
68
+ });
69
+ }
70
+ return files;
71
+ }
72
+ function initializeIgnores(rootDir, ignorePatterns, potentialFiles) {
73
+ if (ignores) {
74
+ return;
75
+ }
76
+ // First, we need to traverse up the folder tree until we find the git root
77
+ // folder. We're often operating in a project where `rootDir` is a `src`
78
+ // folder, or even in a monorepo. In these cases, there is likely a gitignore
79
+ // file(s) futher up the tree
80
+ const extraIgnoreFiles = [];
81
+ const rootDirContents = readdirSync(rootDir);
82
+ if (!rootDirContents.includes('.git')) {
83
+ let currentDir = dirname(rootDir);
84
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
85
+ while (true) {
86
+ const currentDirContents = readdirSync(currentDir);
87
+ if (currentDirContents.includes('.gitignore')) {
88
+ extraIgnoreFiles.push(join(currentDir, '.gitignore'));
89
+ }
90
+ if (
91
+ // If we found the git folder, bail
92
+ currentDirContents.includes('.git') ||
93
+ // If we're at the root folder of the file system, bail. Note: we do the
94
+ // check this way to support both UNIX and Windows filesystems
95
+ currentDir === dirname(rootDir)) {
96
+ break;
97
+ }
98
+ currentDir = dirname(rootDir);
99
+ }
100
+ }
101
+ // Normalize and read in all ignore file contents
102
+ const ignoreFiles = [
103
+ ...extraIgnoreFiles,
104
+ ...potentialFiles
105
+ .filter(({ filePath }) => basename(filePath) === '.gitignore')
106
+ .map(({ filePath }) => filePath),
107
+ ].map((filePath) => ({
108
+ filePath,
109
+ contents: readFileSync(filePath, 'utf-8'),
110
+ }));
111
+ ignores = [
112
+ ...ignorePatterns.map((i) => ({
113
+ dir: i.dir,
114
+ ig: ignore().add(i.contents),
115
+ })),
116
+ ...ignoreFiles.map((i) => ({
117
+ dir: dirname(i.filePath),
118
+ ig: ignore().add(i.contents),
119
+ })),
120
+ ];
121
+ }
122
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/util/files.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE9D,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAO3C,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,cAA+B;IAC3E,gEAAgE;IAChE,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,EAAE;QAC1C,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,OAAO;KAClB,CAAC;SACC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC7B,4EAA4E;QAC5E,0EAA0E;QAC1E,4CAA4C;SAC3C,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE7D,+DAA+D;SAC9D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAEzC,2BAA2B;IAC3B,OAAO,aAAa,CAClB,OAAO,EACP,cAAc,EACd,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAe,EACf,cAA+B;IAE/B,oEAAoE;IACpE,MAAM,kBAAkB,GAAG,CACzB,MAAM,OAAO,CAAC,OAAO,EAAE;QACrB,SAAS,EAAE,IAAI;QACf,QAAQ,EAAE,OAAO;KAClB,CAAC,CACH,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;IAE/B,iCAAiC;IACjC,MAAM,cAAc,GAAG,CACrB,MAAM,OAAO,CAAC,GAAG,CACf,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC,CAAC,CACH,CACF;QACC,+DAA+D;SAC9D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAEzC,2BAA2B;IAC3B,OAAO,aAAa,CAClB,OAAO,EACP,cAAc,EACd,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC,CAC7E,CAAC;AACJ,CAAC;AAED,IAAI,OAAO,GAA8C,IAAI,CAAC;AAC9D,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,QAAgB;IAC7D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,aAAa,CAAC,iDAAiD,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,OAAO,EAAE,CAAC;QAClC,yEAAyE;QACzE,sEAAsE;QACtE,sEAAsE;QACtE,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CACpB,OAAe,EACf,cAA+B,EAC/B,cAA+B;IAE/B,mDAAmD;IACnD,iBAAiB,CAAC,OAAO,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;IAE3D,2BAA2B;IAC3B,MAAM,KAAK,GAGN,EAAE,CAAC;IACR,KAAK,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,cAAc,EAAE,CAAC;QACjD,IAAI,aAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;YACrC,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC;YACT,QAAQ;YACR,eAAe,EAAE,KAAK,CAAC,OAAO;SAC/B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAe,EACf,cAA+B,EAC/B,cAA+B;IAE/B,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO;IACT,CAAC;IAED,2EAA2E;IAC3E,wEAAwE;IACxE,6EAA6E;IAC7E,6BAA6B;IAC7B,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,MAAM,eAAe,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,IAAI,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,uEAAuE;QACvE,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,kBAAkB,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YACnD,IAAI,kBAAkB,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC9C,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;YACxD,CAAC;YACD;YACE,mCAAmC;YACnC,kBAAkB,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACnC,wEAAwE;gBACxE,8DAA8D;gBAC9D,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,EAC/B,CAAC;gBACD,MAAM;YACR,CAAC;YACD,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,MAAM,WAAW,GAAG;QAClB,GAAG,gBAAgB;QACnB,GAAG,cAAc;aACd,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,YAAY,CAAC;aAC7D,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC;KACnC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACnB,QAAQ;QACR,QAAQ,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;KAC1C,CAAC,CAAC,CAAC;IAEJ,OAAO,GAAG;QACR,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5B,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;SAC7B,CAAC,CAAC;QACH,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzB,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;YACxB,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;SAC7B,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare function warn(msg: string): void;
2
+ export declare function error(msg: string): void;
3
+ export declare function setVerbose(verbose: boolean): void;
4
+ export declare function debug(msg: string): void;
5
+ export declare function formatMilliseconds(duration: number): string;
@@ -0,0 +1,19 @@
1
+ export function warn(msg) {
2
+ console.warn(`[Warn] fast-import: ${msg}`);
3
+ }
4
+ export function error(msg) {
5
+ console.error(`[Error] fast-import: ${msg}`);
6
+ }
7
+ let verboseEnabled = false;
8
+ export function setVerbose(verbose) {
9
+ verboseEnabled = verbose;
10
+ }
11
+ export function debug(msg) {
12
+ if (verboseEnabled) {
13
+ console.debug(`[Debug] fast-import: ${msg}`);
14
+ }
15
+ }
16
+ export function formatMilliseconds(duration) {
17
+ return duration.toLocaleString() + 'ms';
18
+ }
19
+ //# sourceMappingURL=logging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../../src/util/logging.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,IAAI,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,IAAI,cAAc,GAAG,KAAK,CAAC;AAC3B,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,cAAc,GAAG,OAAO,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,IAAI,cAAc,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,QAAQ,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,85 @@
1
+ import js from '@eslint/js';
2
+ import { FlatCompat } from '@eslint/eslintrc';
3
+ import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4
+ import tseslint from 'typescript-eslint';
5
+ import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
6
+ import jest from 'eslint-plugin-jest';
7
+ import globals from 'globals';
8
+ import { getDirname } from 'cross-dirname';
9
+ import { includeIgnoreFile } from '@eslint/compat';
10
+ import { join } from 'node:path';
11
+ import fastEsm from './dist/plugin.js';
12
+ import { globalIgnores } from 'eslint/config';
13
+
14
+ const compat = new FlatCompat({
15
+ baseDirectory: getDirname(),
16
+ recommendedConfig: js.configs.recommended,
17
+ allConfig: js.configs.all,
18
+ });
19
+
20
+ export default tseslint.config(
21
+ includeIgnoreFile(join(getDirname(), '.gitignore')),
22
+ globalIgnores(['src/**/__test__/**/project/*', 'jest.config.ts']),
23
+ {
24
+ settings: {
25
+ 'import/resolver-next': [
26
+ createTypeScriptImportResolver({
27
+ alwaysTryTypes: true,
28
+ }),
29
+ ],
30
+ 'fast-import': {
31
+ entryPoints: [
32
+ {
33
+ file: 'plugin.ts',
34
+ symbol: 'default',
35
+ },
36
+ ],
37
+ debugLogging: true,
38
+ },
39
+ },
40
+ files: ['**/*.{js,mjs,jsx,ts,tsx,mts}'],
41
+ languageOptions: {
42
+ globals: globals.node,
43
+ },
44
+ },
45
+ fastEsm.configs.recommended,
46
+ eslintPluginPrettierRecommended,
47
+ ...tseslint.configs.strictTypeChecked.map((r) =>
48
+ r.name === 'typescript-eslint/strict-type-checked'
49
+ ? {
50
+ ...r,
51
+ files: ['**/*.{ts,tsx,mts}'],
52
+ }
53
+ : r
54
+ ),
55
+ {
56
+ files: ['**/*.{ts,tsx,mts}'],
57
+ languageOptions: {
58
+ parserOptions: {
59
+ projectService: true,
60
+ tsconfigRootDir: getDirname(),
61
+ },
62
+ },
63
+ rules: {
64
+ '@typescript-eslint/consistent-type-imports': 'error',
65
+ },
66
+ },
67
+ {
68
+ files: ['**/*.test.ts'],
69
+ ...jest.configs['flat/recommended'],
70
+ },
71
+ {
72
+ // disable type-aware linting on JS files
73
+ files: ['**/*..jsx,mjs}'],
74
+ extends: [tseslint.configs.disableTypeChecked],
75
+ },
76
+ ...compat.extends('eslint:recommended'),
77
+ {
78
+ rules: {
79
+ 'object-shorthand': 'error',
80
+
81
+ // Handled by TypeScript eslint
82
+ 'no-unused-vars': 'off',
83
+ },
84
+ }
85
+ );
package/jest.config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import type { Config } from 'jest';
2
+ import { createDefaultEsmPreset } from 'ts-jest';
3
+
4
+ const presetConfig = createDefaultEsmPreset();
5
+
6
+ export default {
7
+ ...presetConfig,
8
+ resolver: 'ts-jest-resolver',
9
+ setupFilesAfterEnv: ['<rootDir>/src/__test__/setup.ts'],
10
+ } satisfies Config;