@adamhl8/configs 0.18.2 → 0.19.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/README.md CHANGED
@@ -51,11 +51,3 @@ import { defineConfig } from "tsdown"
51
51
 
52
52
  export default defineConfig(tsdownConfig({ ... }))
53
53
  ```
54
-
55
- ### prettier
56
-
57
- ```js
58
- import { prettierConfig } from "@adamhl8/configs"
59
-
60
- export default prettierConfig({ ... })
61
- ```
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
  import path from "node:path";
3
3
  import process from "node:process";
4
- const KNIP_PREPROCESSOR_PATH = `${path.resolve(import.meta.dir, "../configs/knip-preprocessor")}`;
4
+ //#region src/adamhl8-knip/index.ts
5
+ const KNIP_PREPROCESSOR_PATH = `${path.resolve(import.meta.dir, "./knip-preprocessor")}`;
5
6
  const knipPreprocessorPath = `${KNIP_PREPROCESSOR_PATH}${await Bun.file(`${KNIP_PREPROCESSOR_PATH}.ts`).exists() ? ".ts" : ".js"}`;
6
7
  process.exitCode = Bun.spawnSync({
7
8
  cmd: [
@@ -13,4 +14,5 @@ process.exitCode = Bun.spawnSync({
13
14
  stdout: "inherit",
14
15
  stderr: "inherit"
15
16
  }).exitCode;
17
+ //#endregion
16
18
  export {};
@@ -0,0 +1,55 @@
1
+ import { mergeWith } from "es-toolkit";
2
+ import { clone } from "remeda";
3
+ //#region src/utils.ts
4
+ /**
5
+ * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays.
6
+ */
7
+ function merge(target, source) {
8
+ return mergeWith(target, source, (objValue, srcValue) => Array.isArray(objValue) ? objValue.concat(srcValue) : void 0);
9
+ }
10
+ /**
11
+ * Creates a config merge function with proper type overloads for merging with a base config.
12
+ */
13
+ function createMergeConfigFn(baseConfig) {
14
+ const mergeConfigFn = (userConfig) => {
15
+ if (userConfig === void 0) return baseConfig;
16
+ return merge(clone(baseConfig), clone(userConfig));
17
+ };
18
+ return mergeConfigFn;
19
+ }
20
+ //#endregion
21
+ //#region src/configs/knip.ts
22
+ const DEFAULT_ENTRIES = [
23
+ "./src/index.ts",
24
+ "**/*.test.ts",
25
+ "./tsdown.config.ts"
26
+ ];
27
+ createMergeConfigFn({
28
+ entry: DEFAULT_ENTRIES,
29
+ project: ["**"],
30
+ tsdown: false
31
+ });
32
+ //#endregion
33
+ //#region src/adamhl8-knip/knip-preprocessor.ts
34
+ /**
35
+ * Modifies issues based on the provided map function.
36
+ *
37
+ * This is needed because we also need to update `options.counters` after modifying issues.
38
+ */
39
+ function modifyIssues(options, issueType, mapFn) {
40
+ const originalIssues = options.issues[issueType];
41
+ const modifiedIssueEntries = Object.entries(originalIssues).map(([key, issueRecord]) => [key, Object.entries(issueRecord)]).map(([key, issueRecordEntries]) => [key, Object.fromEntries(mapFn([key, issueRecordEntries]))]);
42
+ const modifiedIssues = Object.fromEntries(modifiedIssueEntries);
43
+ const countIssues = (issueRecords) => Object.values(issueRecords).map((issueRecord) => Object.keys(issueRecord).length).reduce((acc, curr) => acc + curr, 0);
44
+ const originalIssueCount = countIssues(originalIssues);
45
+ const issuesRemovedCount = originalIssueCount - countIssues(modifiedIssues);
46
+ options.counters[issueType] = originalIssueCount - issuesRemovedCount;
47
+ options.issues[issueType] = modifiedIssues;
48
+ }
49
+ const preprocess = (options) => {
50
+ options.configurationHints = options.configurationHints.filter((hint) => !(DEFAULT_ENTRIES.some((entry) => typeof hint.identifier === "string" && hint.identifier.includes(entry)) && (hint.type === "entry-empty" || hint.type === "entry-redundant")));
51
+ modifyIssues(options, "unlisted", ([, issueRecordEntries]) => issueRecordEntries.filter(([key]) => !key.includes("prettier")));
52
+ return options;
53
+ };
54
+ //#endregion
55
+ export { preprocess as default };
@@ -6,25 +6,6 @@
6
6
  "clientKind": "git",
7
7
  "useIgnoreFile": true
8
8
  },
9
- "formatter": {
10
- "indentStyle": "space",
11
- "lineWidth": 120
12
- },
13
- "javascript": {
14
- "formatter": {
15
- "semicolons": "asNeeded"
16
- }
17
- },
18
- "json": {
19
- "formatter": {
20
- "expand": "auto"
21
- }
22
- },
23
- "css": {
24
- "parser": {
25
- "tailwindDirectives": true
26
- }
27
- },
28
9
  "assist": {
29
10
  "enabled": true,
30
11
  "actions": {
@@ -33,7 +14,7 @@
33
14
  "level": "on",
34
15
  "options": {
35
16
  "groups": [
36
- [":NODE:", ":BUN:", ":URL:", ":PACKAGE_WITH_PROTOCOL:", ":PACKAGE:"],
17
+ [":NODE:", ":BUN:", ":PACKAGE_WITH_PROTOCOL:", ":URL:", ":PACKAGE:"],
37
18
  ":BLANK_LINE:",
38
19
  [":ALIAS:", ":PATH:"]
39
20
  ]
@@ -44,7 +25,7 @@
44
25
  },
45
26
  "overrides": [
46
27
  {
47
- "includes": ["**/*.tsx", "./knip.ts", "./prettier.config.js", "tsdown.config.ts", "astro.config.ts"],
28
+ "includes": ["**/*.tsx", "knip.ts", "prettier.config.js", "tsdown.config.ts", "astro.config.ts"],
48
29
  "linter": {
49
30
  "rules": {
50
31
  "style": {
@@ -54,6 +35,35 @@
54
35
  }
55
36
  }
56
37
  ],
38
+ "formatter": {
39
+ "indentStyle": "space",
40
+ "lineWidth": 120
41
+ },
42
+ "javascript": {
43
+ "formatter": {
44
+ "semicolons": "asNeeded"
45
+ }
46
+ },
47
+ "json": {
48
+ "formatter": {
49
+ "expand": "auto"
50
+ }
51
+ },
52
+ "css": {
53
+ "parser": {
54
+ "cssModules": true,
55
+ "tailwindDirectives": true
56
+ },
57
+ "formatter": {
58
+ "enabled": true
59
+ }
60
+ },
61
+ "html": {
62
+ "experimentalFullSupportEnabled": true,
63
+ "formatter": {
64
+ "enabled": true
65
+ }
66
+ },
57
67
  "linter": {
58
68
  "rules": {
59
69
  "a11y": {
@@ -96,22 +106,25 @@
96
106
  "useValidLang": "error"
97
107
  },
98
108
  "complexity": {
109
+ "noExcessiveCognitiveComplexity": "off",
110
+ "noExcessiveLinesPerFunction": "off",
111
+ "noForEach": "off",
112
+ "noVoid": "off",
113
+ "useLiteralKeys": "off",
99
114
  "noAdjacentSpacesInRegex": "error",
100
115
  "noArguments": "error",
101
116
  "noBannedTypes": "error",
102
117
  "noCommaOperator": "error",
103
118
  "noEmptyTypeParameters": "error",
104
- "noExcessiveCognitiveComplexity": "off",
105
- "noExcessiveLinesPerFunction": "off",
106
119
  "noExcessiveNestedTestSuites": "error",
107
120
  "noExtraBooleanCast": "error",
108
121
  "noFlatMapIdentity": "error",
109
- "noForEach": "off",
110
122
  "noImplicitCoercions": "error",
111
123
  "noImportantStyles": "error",
112
124
  "noStaticOnlyClass": "error",
113
125
  "noThisInStatic": "error",
114
126
  "noUselessCatch": "error",
127
+ "noUselessCatchBinding": "error",
115
128
  "noUselessConstructor": "error",
116
129
  "noUselessContinue": "error",
117
130
  "noUselessEmptyExport": "error",
@@ -126,13 +139,13 @@
126
139
  "noUselessTernary": "error",
127
140
  "noUselessThisAlias": "error",
128
141
  "noUselessTypeConstraint": "error",
142
+ "noUselessUndefined": "error",
129
143
  "noUselessUndefinedInitialization": "error",
130
- "noVoid": "off",
131
144
  "useArrowFunction": "error",
132
145
  "useDateNow": "error",
133
146
  "useFlatMap": "error",
134
147
  "useIndexOf": "error",
135
- "useLiteralKeys": "off",
148
+ "useMaxParams": "error",
136
149
  "useNumericLiterals": "error",
137
150
  "useOptionalChain": "error",
138
151
  "useRegexLiterals": "error",
@@ -141,10 +154,23 @@
141
154
  "useWhile": "error"
142
155
  },
143
156
  "correctness": {
157
+ "noNodejsModules": "off",
158
+ "noQwikUseVisibleTask": "off",
159
+ "noSolidDestructuredProps": "off",
160
+ "noUndeclaredDependencies": "off",
161
+ "noUndeclaredVariables": "off",
162
+ "noUnresolvedImports": "off",
163
+ "noVueDataObjectDeclaration": "off",
164
+ "noVueDuplicateKeys": "off",
165
+ "noVueReservedKeys": "off",
166
+ "noVueReservedProps": "off",
167
+ "useQwikClasslist": "off",
168
+ "useQwikMethodUsage": "off",
169
+ "useQwikValidLexicalScope": "off",
144
170
  "noChildrenProp": "error",
145
- "noConstAssign": "error",
146
171
  "noConstantCondition": "error",
147
172
  "noConstantMathMinMaxClamp": "error",
173
+ "noConstAssign": "error",
148
174
  "noConstructorReturn": "error",
149
175
  "noEmptyCharacterClassInRegex": "error",
150
176
  "noEmptyPattern": "error",
@@ -159,22 +185,18 @@
159
185
  "noInvalidUseBeforeDeclaration": "error",
160
186
  "noMissingVarFunction": "error",
161
187
  "noNestedComponentDefinitions": "error",
162
- "noNodejsModules": "off",
188
+ "noNextAsyncClientComponent": "error",
163
189
  "noNonoctalDecimalEscape": "error",
164
190
  "noPrecisionLoss": "error",
165
191
  "noPrivateImports": "error",
166
192
  "noProcessGlobal": "error",
167
- "noQwikUseVisibleTask": "off",
168
193
  "noReactPropAssignments": "error",
169
194
  "noRenderReturnValue": "error",
170
195
  "noRestrictedElements": "error",
171
196
  "noSelfAssign": "error",
172
197
  "noSetterReturn": "error",
173
- "noSolidDestructuredProps": "off",
174
198
  "noStringCaseMismatch": "error",
175
199
  "noSwitchDeclarations": "error",
176
- "noUndeclaredDependencies": "off",
177
- "noUndeclaredVariables": "off",
178
200
  "noUnknownFunction": "error",
179
201
  "noUnknownMediaFeatureName": "error",
180
202
  "noUnknownProperty": "error",
@@ -194,6 +216,7 @@
194
216
  "noUnusedVariables": "error",
195
217
  "noVoidElementsWithChildren": "error",
196
218
  "noVoidTypeReturn": "error",
219
+ "noVueSetupPropsReactivityLoss": "error",
197
220
  "useExhaustiveDependencies": "error",
198
221
  "useGraphqlNamedOperations": "error",
199
222
  "useHookAtTopLevel": "error",
@@ -203,7 +226,6 @@
203
226
  "useJsonImportAttributes": "error",
204
227
  "useJsxKeyInIterable": "error",
205
228
  "useParseIntRadix": "error",
206
- "useQwikClasslist": "off",
207
229
  "useSingleJsDocAsterisk": "error",
208
230
  "useUniqueElementIds": "error",
209
231
  "useValidForDirection": "error",
@@ -211,139 +233,203 @@
211
233
  "useYield": "error"
212
234
  },
213
235
  "nursery": {
236
+ "noContinue": "off",
237
+ "noExcessiveClassesPerFile": "off",
238
+ "noExcessiveLinesPerFile": "off",
239
+ "noIncrementDecrement": "off",
240
+ "noSyncScripts": "off",
241
+ "noTernary": "off",
242
+ "noVueVIfWithVFor": "off",
243
+ "useAwaitThenable": "off",
244
+ "useExplicitReturnType": "off",
245
+ "useExplicitType": "off",
246
+ "useSortedClasses": {
247
+ "level": "error",
248
+ "fix": "safe"
249
+ },
250
+ "useVueDefineMacrosOrder": "off",
251
+ "useVueHyphenatedAttributes": "off",
252
+ "useVueMultiWordComponentNames": "off",
253
+ "useVueValidVBind": "off",
254
+ "useVueValidVElse": "off",
255
+ "useVueValidVElseIf": "off",
256
+ "useVueValidVHtml": "off",
257
+ "useVueValidVIf": "off",
258
+ "useVueValidVOn": "off",
259
+ "useVueValidVText": "off",
214
260
  "noAmbiguousAnchorText": "error",
215
261
  "noBeforeInteractiveScriptOutsideDocument": "error",
216
- "noContinue": "off",
217
- "noDeprecatedImports": "error",
262
+ "noComponentHookFactories": "error",
263
+ "noConditionalExpect": "error",
264
+ "noDeprecatedMediaType": "error",
218
265
  "noDivRegex": "error",
266
+ "noDrizzleDeleteWithoutWhere": "error",
267
+ "noDrizzleUpdateWithoutWhere": "error",
219
268
  "noDuplicateArgumentNames": "error",
220
269
  "noDuplicateAttributes": "error",
221
- "noDuplicateDependencies": "error",
270
+ "noDuplicatedSpreadProps": "error",
222
271
  "noDuplicateEnumValueNames": "error",
223
272
  "noDuplicateEnumValues": "error",
224
273
  "noDuplicateFieldDefinitionNames": "error",
225
274
  "noDuplicateGraphqlOperationName": "error",
226
275
  "noDuplicateInputFieldNames": "error",
276
+ "noDuplicateSelectors": "error",
227
277
  "noDuplicateVariableNames": "error",
228
- "noDuplicatedSpreadProps": "error",
229
- "noEmptySource": "error",
278
+ "noEmptyObjectKeys": "error",
230
279
  "noEqualsToNull": "error",
231
- "noExcessiveClassesPerFile": "off",
232
- "noExcessiveLinesPerFile": "off",
280
+ "noExcessiveSelectorClasses": "error",
233
281
  "noFloatingClasses": "error",
234
282
  "noFloatingPromises": "error",
235
283
  "noForIn": "error",
236
- "noImportCycles": "error",
237
- "noIncrementDecrement": "off",
238
- "noJsxLiterals": "off",
284
+ "noHexColors": "error",
285
+ "noIdenticalTestTitle": "error",
286
+ "noImpliedEval": "error",
287
+ "noInlineStyles": "error",
288
+ "noJsxLeakedDollar": "error",
289
+ "noJsxNamespace": "error",
239
290
  "noJsxPropsBind": "error",
240
291
  "noLeakedRender": "error",
292
+ "noLoopFunc": "error",
293
+ "noMisleadingReturnType": "error",
241
294
  "noMisusedPromises": "error",
242
295
  "noMultiAssign": "error",
243
296
  "noMultiStr": "error",
244
- "noNextAsyncClientComponent": "error",
297
+ "noNestedPromises": "error",
245
298
  "noParametersOnlyUsedInRecursion": "error",
299
+ "noPlaywrightElementHandle": "error",
300
+ "noPlaywrightEval": "error",
301
+ "noPlaywrightForceOption": "error",
302
+ "noPlaywrightMissingAwait": "error",
303
+ "noPlaywrightNetworkidle": "error",
304
+ "noPlaywrightPagePause": "error",
305
+ "noPlaywrightUselessAwait": "error",
306
+ "noPlaywrightWaitForNavigation": "error",
307
+ "noPlaywrightWaitForSelector": "error",
308
+ "noPlaywrightWaitForTimeout": "error",
246
309
  "noProto": "error",
247
- "noReactForwardRef": "error",
310
+ "noReactNativeDeepImports": "error",
311
+ "noReactNativeLiteralColors": "error",
312
+ "noReactNativeRawText": "error",
313
+ "noRedundantDefaultExport": "error",
248
314
  "noReturnAssign": "error",
249
315
  "noRootType": "error",
250
316
  "noScriptUrl": "error",
251
317
  "noShadow": "error",
252
- "noSyncScripts": "off",
253
- "noTernary": "off",
318
+ "noTopLevelLiterals": "error",
254
319
  "noUndeclaredEnvVars": "error",
255
320
  "noUnknownAttribute": "error",
256
321
  "noUnnecessaryConditions": "error",
257
- "noUnresolvedImports": "off",
258
- "noUnusedExpressions": "error",
259
- "noUselessCatchBinding": "error",
260
- "noUselessUndefined": "error",
261
- "noVueDataObjectDeclaration": "off",
262
- "noVueDuplicateKeys": "off",
322
+ "noUnnecessaryTemplateExpression": "error",
323
+ "noUnsafePlusOperands": "error",
324
+ "noUntrustedLicenses": "error",
325
+ "noUselessReturn": "error",
326
+ "noUselessTypeConversion": "error",
327
+ "noVueArrowFuncInWatch": "error",
263
328
  "noVueOptionsApi": "error",
264
- "noVueReservedKeys": "off",
265
- "noVueReservedProps": "off",
266
- "noVueSetupPropsReactivityLoss": "error",
267
- "noVueVIfWithVFor": "off",
329
+ "noVueRefAsOperand": "error",
330
+ "useArraySome": "error",
268
331
  "useArraySortCompare": "error",
269
- "useAwaitThenable": "off",
270
- "useConsistentArrowReturn": "error",
332
+ "useBaseline": "error",
333
+ "useConsistentEnumValueType": "error",
271
334
  "useConsistentGraphqlDescriptions": "error",
272
- "useDeprecatedDate": "error",
335
+ "useConsistentMethodSignatures": "error",
336
+ "useConsistentTestIt": "error",
273
337
  "useDestructuring": "error",
338
+ "useDisposables": "error",
339
+ "useDomNodeTextContent": "error",
340
+ "useDomQuerySelector": "error",
274
341
  "useErrorCause": "error",
275
342
  "useExhaustiveSwitchCases": "error",
276
- "useExplicitType": "off",
343
+ "useExpect": "error",
277
344
  "useFind": "error",
345
+ "useGlobalThis": "error",
346
+ "useIframeSandbox": "error",
347
+ "useImportsFirst": "error",
278
348
  "useInlineScriptId": "error",
349
+ "useInputName": "error",
279
350
  "useLoneAnonymousOperation": "error",
280
351
  "useLoneExecutableDefinition": "error",
281
- "useMaxParams": "error",
282
- "useQwikMethodUsage": "off",
283
- "useQwikValidLexicalScope": "off",
352
+ "useNamedCaptureGroup": "error",
353
+ "useNullishCoalescing": "error",
354
+ "usePlaywrightValidDescribeCallback": "error",
355
+ "useQwikLoaderLocation": "error",
356
+ "useReactAsyncServerFunction": "error",
357
+ "useReactNativePlatformComponents": "error",
358
+ "useReduceTypeParameter": "error",
284
359
  "useRegexpExec": "error",
360
+ "useRegexpTest": "error",
285
361
  "useRequiredScripts": "error",
286
- "useSortedClasses": "error",
362
+ "useScopedStyles": "error",
287
363
  "useSpread": "error",
364
+ "useStringStartsEndsWith": "error",
365
+ "useUnicodeRegex": "error",
366
+ "useVarsOnTop": "error",
288
367
  "useVueConsistentDefinePropsDeclaration": "error",
289
368
  "useVueConsistentVBindStyle": "error",
290
369
  "useVueConsistentVOnStyle": "error",
291
- "useVueDefineMacrosOrder": "off",
292
- "useVueHyphenatedAttributes": "off",
293
- "useVueMultiWordComponentNames": "off",
294
- "useVueVForKey": "error",
295
370
  "useVueValidTemplateRoot": "error",
296
- "useVueValidVBind": "off",
297
371
  "useVueValidVCloak": "error",
298
- "useVueValidVElse": "off",
299
- "useVueValidVElseIf": "off",
300
- "useVueValidVHtml": "off",
301
- "useVueValidVIf": "off",
302
- "useVueValidVOn": "off",
303
372
  "useVueValidVOnce": "error",
304
373
  "useVueValidVPre": "error",
305
- "useVueValidVText": "off",
306
- "useVueVapor": "error"
374
+ "useVueVapor": "error",
375
+ "useVueVForKey": "error"
307
376
  },
308
377
  "performance": {
378
+ "noBarrelFile": "off",
379
+ "noNamespaceImport": "off",
380
+ "useSolidForComponent": "off",
309
381
  "noAccumulatingSpread": "error",
310
382
  "noAwaitInLoops": "error",
311
- "noBarrelFile": "off",
312
383
  "noDelete": "error",
313
384
  "noDynamicNamespaceImportAccess": "error",
314
385
  "noImgElement": "error",
315
- "noNamespaceImport": "off",
316
386
  "noReExportAll": "error",
317
387
  "noUnwantedPolyfillio": "error",
318
388
  "useGoogleFontPreconnect": "error",
319
- "useSolidForComponent": "off",
320
389
  "useTopLevelRegex": "error"
321
390
  },
322
391
  "security": {
392
+ "noSecrets": "off",
323
393
  "noBlankTarget": "error",
324
394
  "noDangerouslySetInnerHtml": "error",
325
395
  "noDangerouslySetInnerHtmlWithChildren": "error",
326
- "noGlobalEval": "error",
327
- "noSecrets": "off"
396
+ "noGlobalEval": "error"
328
397
  },
329
398
  "style": {
399
+ "noEnum": "off",
400
+ "noHeadElement": "off",
401
+ "noJsxLiterals": "off",
402
+ "noMagicNumbers": "off",
403
+ "noProcessEnv": "off",
404
+ "useBlockStatements": "off",
405
+ "useConsistentMemberAccessibility": {
406
+ "level": "error",
407
+ "options": {
408
+ "accessibility": "explicit"
409
+ }
410
+ },
411
+ "useExportsLast": "off",
412
+ "useFilenamingConvention": "off",
413
+ "useImportType": {
414
+ "level": "error",
415
+ "options": {
416
+ "style": "separatedType"
417
+ }
418
+ },
419
+ "useNamingConvention": "off",
330
420
  "noCommonJs": "error",
331
421
  "noDefaultExport": "error",
332
422
  "noDescendingSpecificity": "error",
333
423
  "noDoneCallback": "error",
334
- "noEnum": "off",
335
424
  "noExportedImports": "error",
336
- "noHeadElement": "off",
337
425
  "noImplicitBoolean": "error",
338
426
  "noInferrableTypes": "error",
339
- "noMagicNumbers": "off",
340
427
  "noNamespace": "error",
341
428
  "noNegationElse": "error",
342
429
  "noNestedTernary": "error",
343
430
  "noNonNullAssertion": "error",
344
431
  "noParameterAssign": "error",
345
432
  "noParameterProperties": "error",
346
- "noProcessEnv": "off",
347
433
  "noRestrictedGlobals": "error",
348
434
  "noRestrictedImports": "error",
349
435
  "noRestrictedTypes": "error",
@@ -356,19 +442,13 @@
356
442
  "useArrayLiterals": "error",
357
443
  "useAsConstAssertion": "error",
358
444
  "useAtIndex": "error",
359
- "useBlockStatements": "off",
360
445
  "useCollapsedElseIf": "error",
361
446
  "useCollapsedIf": "error",
362
447
  "useComponentExportOnlyModules": "error",
363
448
  "useConsistentArrayType": "error",
449
+ "useConsistentArrowReturn": "error",
364
450
  "useConsistentBuiltinInstantiation": "error",
365
451
  "useConsistentCurlyBraces": "error",
366
- "useConsistentMemberAccessibility": {
367
- "level": "error",
368
- "options": {
369
- "accessibility": "explicit"
370
- }
371
- },
372
452
  "useConsistentObjectDefinitions": "error",
373
453
  "useConsistentTypeDefinitions": "error",
374
454
  "useConst": "error",
@@ -379,20 +459,11 @@
379
459
  "useExplicitLengthCheck": "error",
380
460
  "useExponentiationOperator": "error",
381
461
  "useExportType": "error",
382
- "useExportsLast": "off",
383
- "useFilenamingConvention": "off",
384
462
  "useForOf": "error",
385
463
  "useFragmentSyntax": "error",
386
464
  "useGraphqlNamingConvention": "error",
387
465
  "useGroupedAccessorPairs": "error",
388
- "useImportType": {
389
- "level": "error",
390
- "options": {
391
- "style": "separatedType"
392
- }
393
- },
394
466
  "useLiteralEnumMembers": "error",
395
- "useNamingConvention": "off",
396
467
  "useNodeAssertStrict": "error",
397
468
  "useNodejsImportProtocol": "error",
398
469
  "useNumberNamespace": "error",
@@ -412,6 +483,8 @@
412
483
  "useUnifiedTypeSignatures": "error"
413
484
  },
414
485
  "suspicious": {
486
+ "noConsole": "off",
487
+ "noReactSpecificProps": "off",
415
488
  "noAlert": "error",
416
489
  "noApproximativeNumericConstant": "error",
417
490
  "noArrayIndexKey": "error",
@@ -425,11 +498,11 @@
425
498
  "noCompareNegZero": "error",
426
499
  "noConfusingLabels": "error",
427
500
  "noConfusingVoidType": "error",
428
- "noConsole": "off",
429
- "noConstEnum": "error",
430
501
  "noConstantBinaryExpressions": "error",
502
+ "noConstEnum": "error",
431
503
  "noControlCharactersInRegex": "error",
432
504
  "noDebugger": "error",
505
+ "noDeprecatedImports": "error",
433
506
  "noDocumentCookie": "error",
434
507
  "noDocumentImportInPage": "error",
435
508
  "noDoubleEquals": "error",
@@ -437,6 +510,7 @@
437
510
  "noDuplicateCase": "error",
438
511
  "noDuplicateClassMembers": "error",
439
512
  "noDuplicateCustomProperties": "error",
513
+ "noDuplicateDependencies": "error",
440
514
  "noDuplicateElseIf": "error",
441
515
  "noDuplicateFields": "error",
442
516
  "noDuplicateFontNames": "error",
@@ -449,6 +523,7 @@
449
523
  "noEmptyBlock": "error",
450
524
  "noEmptyBlockStatements": "error",
451
525
  "noEmptyInterface": "error",
526
+ "noEmptySource": "error",
452
527
  "noEvolvingTypes": "error",
453
528
  "noExplicitAny": "error",
454
529
  "noExportsInTest": "error",
@@ -461,8 +536,9 @@
461
536
  "noGlobalIsNan": "error",
462
537
  "noHeadImportInDocument": "error",
463
538
  "noImplicitAnyLet": "error",
464
- "noImportAssign": "error",
465
539
  "noImportantInKeyframe": "error",
540
+ "noImportAssign": "error",
541
+ "noImportCycles": "error",
466
542
  "noIrregularWhitespace": "error",
467
543
  "noLabelVar": "error",
468
544
  "noMisleadingCharacterClass": "error",
@@ -473,7 +549,7 @@
473
549
  "noOctalEscape": "error",
474
550
  "noPrototypeBuiltins": "error",
475
551
  "noQuickfixBiome": "error",
476
- "noReactSpecificProps": "off",
552
+ "noReactForwardRef": "error",
477
553
  "noRedeclare": "error",
478
554
  "noRedundantUseStrict": "error",
479
555
  "noSelfCompare": "error",
@@ -489,6 +565,7 @@
489
565
  "noUnknownAtRules": "error",
490
566
  "noUnsafeDeclarationMerging": "error",
491
567
  "noUnsafeNegation": "error",
568
+ "noUnusedExpressions": "error",
492
569
  "noUselessEscapeInString": "error",
493
570
  "noUselessRegexBackrefs": "error",
494
571
  "noVar": "error",
@@ -497,6 +574,7 @@
497
574
  "useAwait": "error",
498
575
  "useBiomeIgnoreFolder": "error",
499
576
  "useDefaultSwitchClauseLast": "error",
577
+ "useDeprecatedDate": "error",
500
578
  "useErrorMessage": "error",
501
579
  "useGetterReturn": "error",
502
580
  "useGoogleFontDisplay": "error",
@@ -1,13 +1,13 @@
1
- import { RawConfigurationOrFn } from "../node_modules/knip/dist/types/config.js";
2
- import { OptionalMergeConfigFn } from "./utils.js";
1
+ import { OptionalMergeConfigFn } from "../utils.js";
2
+ import { KnipConfig } from "knip";
3
3
 
4
4
  //#region src/configs/knip.d.ts
5
5
  declare const baseConfig: {
6
- readonly entry: ["./src/index.ts", "**/*.test.ts", "./tsdown.config.ts"];
6
+ readonly entry: string[];
7
7
  readonly project: ["**"];
8
8
  readonly tsdown: false;
9
9
  };
10
- declare const knipConfig: OptionalMergeConfigFn<RawConfigurationOrFn, typeof baseConfig>;
10
+ declare const knipConfig: OptionalMergeConfigFn<KnipConfig, typeof baseConfig>;
11
11
  //#endregion
12
12
  export { knipConfig };
13
13
  //# sourceMappingURL=knip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"knip.d.ts","names":[],"sources":["../../src/configs/knip.ts"],"mappings":";;;;cASM,UAAA;EAAA;;;;cAMO,UAAA,EAAY,qBAAA,CAAsB,oBAAA,SAAmB,UAAA"}
1
+ {"version":3,"file":"knip.d.ts","names":[],"sources":["../../src/configs/knip.ts"],"mappings":";;;;cAWM,UAAA;EAAA;;;;cAMO,UAAA,EAAY,qBAAA,CAAsB,UAAA,SAAmB,UAAA"}
@@ -1,4 +1,4 @@
1
- import { createMergeConfigFn } from "./utils.js";
1
+ import { createMergeConfigFn } from "../utils.js";
2
2
  const knipConfig = createMergeConfigFn({
3
3
  entry: [
4
4
  "./src/index.ts",
@@ -8,6 +8,7 @@ const knipConfig = createMergeConfigFn({
8
8
  project: ["**"],
9
9
  tsdown: false
10
10
  });
11
+ //#endregion
11
12
  export { knipConfig };
12
13
 
13
14
  //# sourceMappingURL=knip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"knip.js","names":[],"sources":["../../src/configs/knip.ts"],"sourcesContent":["import type { KnipConfig } from \"knip\"\n\nimport type { OptionalMergeConfigFn } from \"./utils.ts\"\nimport { createMergeConfigFn } from \"./utils.ts\"\n\n// Normally, specifying the `./src/index.ts` entry would cause knip to complain about a redundant entry because it gets automatically included via the tsdown plugin.\n// However, in projects that _don't_ use tsdown, the `./src/index.ts` entry would be missing entirely.\n// To handle this, we specify it and disable the tsdown plugin. This makes knip work in both cases.\n\nconst baseConfig = {\n entry: [\"./src/index.ts\", \"**/*.test.ts\", \"./tsdown.config.ts\"],\n project: [\"**\"],\n tsdown: false,\n} as const satisfies KnipConfig\n\nexport const knipConfig: OptionalMergeConfigFn<KnipConfig, typeof baseConfig> = createMergeConfigFn(baseConfig)\n"],"mappings":";AAeA,MAAa,aAAmE,oBAN7D;CACjB,OAAO;EAAC;EAAkB;EAAgB;EAAqB;CAC/D,SAAS,CAAC,KAAK;CACf,QAAQ;CACT,CAE8G"}
1
+ {"version":3,"file":"knip.js","names":[],"sources":["../../src/configs/knip.ts"],"sourcesContent":["import type { KnipConfig } from \"knip\"\n\nimport type { OptionalMergeConfigFn } from \"../utils.ts\"\nimport { createMergeConfigFn } from \"../utils.ts\"\n\n// Normally, specifying the `./src/index.ts` entry would cause knip to complain about a redundant entry because it gets automatically included via the tsdown plugin.\n// However, in projects that _don't_ use tsdown, the `./src/index.ts` entry would be missing entirely.\n// To handle this, we specify it and disable the tsdown plugin. This makes knip work in both cases.\n\nexport const DEFAULT_ENTRIES = [\"./src/index.ts\", \"**/*.test.ts\", \"./tsdown.config.ts\"]\n\nconst baseConfig = {\n entry: DEFAULT_ENTRIES,\n project: [\"**\"],\n tsdown: false,\n} as const satisfies KnipConfig\n\nexport const knipConfig: OptionalMergeConfigFn<KnipConfig, typeof baseConfig> = createMergeConfigFn(baseConfig)\n"],"mappings":";AAiBA,MAAa,aAAmE,oBAAoB;CALlG,OAAO;EAHuB;EAAkB;EAAgB;EAGzD;CACP,SAAS,CAAC,KAAK;CACf,QAAQ;CAG0F,CAAW"}
@@ -3,15 +3,14 @@
3
3
  "include": ["${configDir}/**/*", "${configDir}/**/.*/**/*"],
4
4
  "exclude": ["${configDir}/dist/"],
5
5
  "compilerOptions": {
6
+ "types": ["bun"],
7
+ "lib": ["ESNext"],
6
8
  "target": "ESNext",
7
9
  "jsx": "react-jsx",
8
10
  "module": "preserve",
9
11
  "moduleResolution": "bundler",
10
12
  "moduleDetection": "force",
11
- "isolatedModules": true,
12
13
  "verbatimModuleSyntax": true,
13
- "esModuleInterop": false,
14
- "allowSyntheticDefaultImports": true,
15
14
  "allowImportingTsExtensions": true,
16
15
  "resolveJsonModule": true,
17
16
  "allowJs": true,
@@ -19,7 +18,6 @@
19
18
  "skipLibCheck": true,
20
19
  "noEmit": true,
21
20
 
22
- "strict": true,
23
21
  "allowUnreachableCode": false,
24
22
  "allowUnusedLabels": false,
25
23
  "exactOptionalPropertyTypes": true,
@@ -30,8 +28,6 @@
30
28
  "noUncheckedIndexedAccess": true,
31
29
  "noUnusedLocals": true,
32
30
  "noUnusedParameters": true,
33
- "forceConsistentCasingInFileNames": true,
34
- "noUncheckedSideEffectImports": true,
35
31
 
36
32
  "paths": {
37
33
  "~/*": ["${configDir}/src/*"]
@@ -1,4 +1,4 @@
1
- import { MergeConfigFn, OptionalMergeConfigFn } from "./utils.js";
1
+ import { MergeConfigFn, OptionalMergeConfigFn } from "../utils.js";
2
2
  import { SetRequired } from "type-fest";
3
3
  import { UserConfig } from "tsdown";
4
4
 
@@ -35,11 +35,11 @@ declare const binConfig: {
35
35
  readonly sourcemap: false;
36
36
  readonly dts: false;
37
37
  readonly attw: false;
38
- readonly publint: false;
39
38
  readonly target: false;
40
39
  readonly fixedExtension: false;
41
40
  readonly minify: "dce-only";
42
41
  readonly hash: false;
42
+ readonly publint: true;
43
43
  readonly failOnWarn: true;
44
44
  };
45
45
  declare const tsdownConfig: MergeConfigFn<StrictUserConfig, typeof baseConfig>;
@@ -1 +1 @@
1
- {"version":3,"file":"tsdown.d.ts","names":[],"sources":["../../src/configs/tsdown.ts"],"mappings":";;;;;KAOK,gBAAA,GAAmB,WAAA,CAAY,UAAA;AAAA,cAE9B,UAAA;EAAA;;;;;;;;;;;;;;;;;;;;cAsBA,SAAA;EAAA;;;;;;;;;;;;;;;;cAYO,YAAA,EAAc,aAAA,CAAc,gBAAA,SAAyB,UAAA;AAAA,cACrD,eAAA,EAAiB,qBAAA,CAAsB,UAAA,SAAmB,SAAA"}
1
+ {"version":3,"file":"tsdown.d.ts","names":[],"sources":["../../src/configs/tsdown.ts"],"mappings":";;;;;KAOK,gBAAA,GAAmB,WAAA,CAAY,UAAA;AAAA,cAE9B,UAAA;EAAA;;;;;;;;;;;;;;;;;;;;cAsBA,SAAA;EAAA;;;;;;;;;;;;;;;;cAWO,YAAA,EAAc,aAAA,CAAc,gBAAA,SAAyB,UAAA;AAAA,cACrD,eAAA,EAAiB,qBAAA,CAAsB,UAAA,SAAmB,SAAA"}
@@ -1,4 +1,5 @@
1
- import { createMergeConfigFn } from "./utils.js";
1
+ import { createMergeConfigFn } from "../utils.js";
2
+ //#region src/configs/tsdown.ts
2
3
  const baseConfig = {
3
4
  entry: ["./src/index.ts"],
4
5
  unbundle: true,
@@ -28,11 +29,11 @@ const binConfig = {
28
29
  unbundle: false,
29
30
  sourcemap: false,
30
31
  dts: false,
31
- attw: false,
32
- publint: false
32
+ attw: false
33
33
  };
34
34
  const tsdownConfig = createMergeConfigFn(baseConfig);
35
35
  const tsdownBinConfig = createMergeConfigFn(binConfig);
36
+ //#endregion
36
37
  export { tsdownBinConfig, tsdownConfig };
37
38
 
38
39
  //# sourceMappingURL=tsdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tsdown.js","names":[],"sources":["../../src/configs/tsdown.ts"],"sourcesContent":["import type { UserConfig } from \"tsdown\"\nimport type { SetRequired } from \"type-fest\"\n\nimport type { MergeConfigFn, OptionalMergeConfigFn } from \"./utils.ts\"\nimport { createMergeConfigFn } from \"./utils.ts\"\n\n// force projects to specify platform\ntype StrictUserConfig = SetRequired<UserConfig, \"platform\">\n\nconst baseConfig = {\n entry: [\"./src/index.ts\"],\n unbundle: true,\n target: false,\n platform: \"neutral\",\n fixedExtension: false,\n minify: \"dce-only\",\n sourcemap: true,\n hash: false,\n dts: {\n resolver: \"tsc\",\n newContext: true,\n sourcemap: true,\n },\n attw: {\n level: \"error\",\n profile: \"esm-only\",\n },\n publint: true,\n failOnWarn: true,\n} as const satisfies StrictUserConfig\n\nconst binConfig = {\n ...baseConfig,\n entry: [],\n platform: \"node\",\n outExtensions: () => ({ js: \"\" }),\n unbundle: false,\n sourcemap: false,\n dts: false,\n attw: false,\n publint: false,\n} as const satisfies UserConfig\n\nexport const tsdownConfig: MergeConfigFn<StrictUserConfig, typeof baseConfig> = createMergeConfigFn(baseConfig)\nexport const tsdownBinConfig: OptionalMergeConfigFn<UserConfig, typeof binConfig> = createMergeConfigFn(binConfig)\n"],"mappings":";AASA,MAAM,aAAa;CACjB,OAAO,CAAC,iBAAiB;CACzB,UAAU;CACV,QAAQ;CACR,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,WAAW;CACX,MAAM;CACN,KAAK;EACH,UAAU;EACV,YAAY;EACZ,WAAW;EACZ;CACD,MAAM;EACJ,OAAO;EACP,SAAS;EACV;CACD,SAAS;CACT,YAAY;CACb;AAED,MAAM,YAAY;CAChB,GAAG;CACH,OAAO,EAAE;CACT,UAAU;CACV,sBAAsB,EAAE,IAAI,IAAI;CAChC,UAAU;CACV,WAAW;CACX,KAAK;CACL,MAAM;CACN,SAAS;CACV;AAED,MAAa,eAAmE,oBAAoB,WAAW;AAC/G,MAAa,kBAAuE,oBAAoB,UAAU"}
1
+ {"version":3,"file":"tsdown.js","names":[],"sources":["../../src/configs/tsdown.ts"],"sourcesContent":["import type { UserConfig } from \"tsdown\"\nimport type { SetRequired } from \"type-fest\"\n\nimport type { MergeConfigFn, OptionalMergeConfigFn } from \"../utils.ts\"\nimport { createMergeConfigFn } from \"../utils.ts\"\n\n// force projects to specify platform\ntype StrictUserConfig = SetRequired<UserConfig, \"platform\">\n\nconst baseConfig = {\n entry: [\"./src/index.ts\"],\n unbundle: true,\n target: false,\n platform: \"neutral\",\n fixedExtension: false,\n minify: \"dce-only\",\n sourcemap: true,\n hash: false,\n dts: {\n resolver: \"tsc\",\n newContext: true,\n sourcemap: true,\n },\n attw: {\n level: \"error\",\n profile: \"esm-only\",\n },\n publint: true,\n failOnWarn: true,\n} as const satisfies StrictUserConfig\n\nconst binConfig = {\n ...baseConfig,\n entry: [],\n platform: \"node\",\n outExtensions: () => ({ js: \"\" }),\n unbundle: false,\n sourcemap: false,\n dts: false,\n attw: false,\n} as const satisfies UserConfig\n\nexport const tsdownConfig: MergeConfigFn<StrictUserConfig, typeof baseConfig> = createMergeConfigFn(baseConfig)\nexport const tsdownBinConfig: OptionalMergeConfigFn<UserConfig, typeof binConfig> = createMergeConfigFn(binConfig)\n"],"mappings":";;AASA,MAAM,aAAa;CACjB,OAAO,CAAC,iBAAiB;CACzB,UAAU;CACV,QAAQ;CACR,UAAU;CACV,gBAAgB;CAChB,QAAQ;CACR,WAAW;CACX,MAAM;CACN,KAAK;EACH,UAAU;EACV,YAAY;EACZ,WAAW;EACZ;CACD,MAAM;EACJ,OAAO;EACP,SAAS;EACV;CACD,SAAS;CACT,YAAY;CACb;AAED,MAAM,YAAY;CAChB,GAAG;CACH,OAAO,EAAE;CACT,UAAU;CACV,sBAAsB,EAAE,IAAI,IAAI;CAChC,UAAU;CACV,WAAW;CACX,KAAK;CACL,MAAM;CACP;AAED,MAAa,eAAmE,oBAAoB,WAAW;AAC/G,MAAa,kBAAuE,oBAAoB,UAAU"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  import { knipConfig } from "./configs/knip.js";
2
- import { prettierConfig } from "./configs/prettier.js";
3
2
  import { tsdownBinConfig, tsdownConfig } from "./configs/tsdown.js";
4
- export { knipConfig, prettierConfig, tsdownBinConfig, tsdownConfig };
3
+ export { knipConfig, tsdownBinConfig, tsdownConfig };
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  import { knipConfig } from "./configs/knip.js";
2
- import { prettierConfig } from "./configs/prettier.js";
3
2
  import { tsdownBinConfig, tsdownConfig } from "./configs/tsdown.js";
4
- export { knipConfig, prettierConfig, tsdownBinConfig, tsdownConfig };
3
+ export { knipConfig, tsdownBinConfig, tsdownConfig };
@@ -1,6 +1,6 @@
1
1
  import { MergeDeep } from "type-fest";
2
2
 
3
- //#region src/configs/utils.d.ts
3
+ //#region src/utils.d.ts
4
4
  /**
5
5
  * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.
6
6
  */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","names":[],"sources":["../src/utils.ts"],"mappings":";;;;AAkBA;;UAAiB,aAAA;EAAA,2BAEY,UAAA,EACzB,UAAA,EAAY,iBAAA,GACX,SAAA,CAAU,UAAA,EAAY,iBAAA;IAAqB,cAAA;EAAA;AAAA;;;;;;;;UAW/B,qBAAA,iCAAsD,aAAA,CAAc,UAAA,EAAY,UAAA;EAAA,IAC3F,UAAA;AAAA"}
@@ -1,8 +1,15 @@
1
1
  import { mergeWith } from "es-toolkit";
2
2
  import { clone } from "remeda";
3
+ //#region src/utils.ts
4
+ /**
5
+ * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays.
6
+ */
3
7
  function merge(target, source) {
4
8
  return mergeWith(target, source, (objValue, srcValue) => Array.isArray(objValue) ? objValue.concat(srcValue) : void 0);
5
9
  }
10
+ /**
11
+ * Creates a config merge function with proper type overloads for merging with a base config.
12
+ */
6
13
  function createMergeConfigFn(baseConfig) {
7
14
  const mergeConfigFn = (userConfig) => {
8
15
  if (userConfig === void 0) return baseConfig;
@@ -10,6 +17,7 @@ function createMergeConfigFn(baseConfig) {
10
17
  };
11
18
  return mergeConfigFn;
12
19
  }
20
+ //#endregion
13
21
  export { createMergeConfigFn };
14
22
 
15
23
  //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import { mergeWith } from \"es-toolkit\"\nimport { clone } from \"remeda\"\nimport type { MergeDeep } from \"type-fest\"\n\ntype AnyObj = object\n\n/**\n * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays.\n */\nfunction merge<T extends AnyObj, S extends AnyObj>(target: T, source: S): T & S {\n return mergeWith(target, source, (objValue: unknown, srcValue: unknown) =>\n Array.isArray(objValue) ? objValue.concat(srcValue) : undefined,\n )\n}\n\n/**\n * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.\n */\nexport interface MergeConfigFn<UserConfig, BaseConfig> {\n // biome-ignore lint/style/useShorthandFunctionType: need to use call signature type\n <UserConfigToMerge extends UserConfig>(\n userConfig: UserConfigToMerge,\n ): MergeDeep<BaseConfig, UserConfigToMerge, { arrayMergeMode: \"spread\" }>\n // instead of returning `BaseConfig & UserConfig` (from `merge`), return a more friendly type using `MergeDeep`\n}\n\n/**\n * The optional merge config function, where the `userConfig` argument is optional.\n * - if `UserConfig` is not provided, the return type is `BaseConfig`\n * - if `UserConfig` is provided, the return type is the merged type of `BaseConfig` and `UserConfig`.\n *\n * Note that this extends `MergeConfigFn`, so this type has both function signatures on it.\n */\nexport interface OptionalMergeConfigFn<UserConfig, BaseConfig> extends MergeConfigFn<UserConfig, BaseConfig> {\n (): BaseConfig\n}\n\n/**\n * Creates a config merge function with proper type overloads for merging with a base config.\n */\nexport function createMergeConfigFn<UserConfig extends AnyObj, BaseConfig extends UserConfig>(baseConfig: BaseConfig) {\n // we don't care about the specific type of userConfig here because we assert mergeConfigFn as the correct type below\n const mergeConfigFn = (userConfig?: AnyObj) => {\n if (userConfig === undefined) return baseConfig\n // clone both target and source so we never mutate the original objects\n return merge(clone(baseConfig), clone(userConfig))\n }\n\n return mergeConfigFn as MergeConfigFn<UserConfig, BaseConfig> & OptionalMergeConfigFn<UserConfig, BaseConfig>\n}\n"],"mappings":";;;;;;AASA,SAAS,MAA0C,QAAW,QAAkB;AAC9E,QAAO,UAAU,QAAQ,SAAS,UAAmB,aACnD,MAAM,QAAQ,SAAS,GAAG,SAAS,OAAO,SAAS,GAAG,KAAA,EACvD;;;;;AA4BH,SAAgB,oBAA8E,YAAwB;CAEpH,MAAM,iBAAiB,eAAwB;AAC7C,MAAI,eAAe,KAAA,EAAW,QAAO;AAErC,SAAO,MAAM,MAAM,WAAW,EAAE,MAAM,WAAW,CAAC;;AAGpD,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adamhl8/configs",
3
- "version": "0.18.2",
3
+ "version": "0.19.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,8 +17,7 @@
17
17
  },
18
18
  "license": "MIT",
19
19
  "bin": {
20
- "adamhl8-knip": "./dist/adamhl8-knip/index",
21
- "ts-import-fix": "./dist/ts-import-fix/index"
20
+ "adamhl8-knip": "./dist/adamhl8-knip/index"
22
21
  },
23
22
  "exports": {
24
23
  "./tsconfig": "./dist/configs/tsconfig.base.json",
@@ -31,38 +30,28 @@
31
30
  "files": ["./dist/"],
32
31
  "scripts": {
33
32
  "bundle": "bun lint && tsdown",
34
- "lint": "bun ./generate-biome-rules.ts && markdown-toc -i --bullets '-' --maxdepth 3 ./README.md && ./src/ts-import-fix/index.ts -w --skip-alias && tsc --noEmit && biome check --write && ./src/adamhl8-knip/index.ts",
33
+ "lint": "bun ./generate-biome-rules.ts && markdown-toc -i --bullets '-' --maxdepth 3 ./README.md && tsc --noEmit && biome check --write && ./src/adamhl8-knip/index.ts",
35
34
  "prepare": "find .githooks -type f -exec ln -srf {} .git/hooks/ \\; || true",
36
- "prepublishOnly": "bun bundle"
35
+ "prepublishOnly": "bun bundle",
36
+ "postinstall": "bun ./patch-knip.ts"
37
37
  },
38
38
  "peerDependencies": {
39
- "typescript": "^5.0.0"
39
+ "typescript": "^6.0.0"
40
40
  },
41
41
  "dependencies": {
42
- "@optique/core": "^0.9.1",
43
- "@optique/run": "^0.9.1",
44
- "@prettier/plugin-xml": "^3.4.2",
45
- "es-toolkit": "^1.44.0",
46
- "get-tsconfig": "^4.13.0",
47
- "picocolors": "^1.1.1",
48
- "prettier-plugin-astro": "^0.14.1",
49
- "prettier-plugin-sh": "^0.18.0",
50
- "prettier-plugin-tailwindcss": "^0.7.2",
51
- "prettier-plugin-toml": "^2.0.6",
52
- "remeda": "^2.33.4",
53
- "ts-explicit-errors": "^4.1.1",
54
- "type-fest": "^5.4.1"
42
+ "es-toolkit": "^1.46.0",
43
+ "remeda": "^2.33.7",
44
+ "type-fest": "^5.6.0"
55
45
  },
56
46
  "devDependencies": {
57
47
  "@arethetypeswrong/core": "^0.18.2",
58
- "@biomejs/biome": "^2.3.12",
59
- "@types/bun": "^1.3.6",
60
- "knip": "^5.82.1",
48
+ "@biomejs/biome": "^2.4.13",
49
+ "@types/bun": "^1.3.13",
50
+ "knip": "^6.7.0",
61
51
  "markdown-toc": "^1.2.0",
62
- "prettier": "^3.8.1",
63
- "publint": "^0.3.17",
64
- "tsdown": "^0.20.1",
65
- "typescript": "^5.9.3"
52
+ "publint": "^0.3.18",
53
+ "tsdown": "^0.21.10",
54
+ "typescript": "^6.0.3"
66
55
  },
67
56
  "publishConfig": {
68
57
  "access": "public"
@@ -1,7 +0,0 @@
1
- import { Preprocessor } from "../node_modules/knip/dist/types/issues.js";
2
-
3
- //#region src/configs/knip-preprocessor.d.ts
4
- declare const preprocess: Preprocessor;
5
- //#endregion
6
- export { preprocess as default };
7
- //# sourceMappingURL=knip-preprocessor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"knip-preprocessor.d.ts","names":[],"sources":["../../src/configs/knip-preprocessor.ts"],"mappings":";;;cA4FM,UAAA,EAAY,YAAA"}
@@ -1,26 +0,0 @@
1
- import { knipConfig } from "./knip.js";
2
- function modifyIssues(options, issueType, mapFn) {
3
- const originalIssues = options.issues[issueType];
4
- const modifiedIssueEntries = Object.entries(originalIssues).map(([key, issueRecord]) => [key, Object.entries(issueRecord)]).map(([key, issueRecordEntries]) => [key, Object.fromEntries(mapFn([key, issueRecordEntries]))]);
5
- const modifiedIssues = Object.fromEntries(modifiedIssueEntries);
6
- const countIssues = (issueRecords) => Object.values(issueRecords).map((issueRecord) => Object.keys(issueRecord).length).reduce((acc, curr) => acc + curr, 0);
7
- const originalIssueCount = countIssues(originalIssues);
8
- const issuesRemovedCount = originalIssueCount - countIssues(modifiedIssues);
9
- options.counters[issueType] = originalIssueCount - issuesRemovedCount;
10
- options.issues[issueType] = modifiedIssues;
11
- }
12
- const entries = knipConfig().entry;
13
- const preprocess = (options) => {
14
- options.configurationHints = options.configurationHints.filter((hint) => !(entries.some((entry) => typeof hint.identifier === "string" && hint.identifier.includes(entry)) && (hint.type === "entry-empty" || hint.type === "entry-redundant")));
15
- modifyIssues(options, "unlisted", ([, issueRecordEntries]) => issueRecordEntries.filter(([key]) => !key.includes("prettier")));
16
- modifyIssues(options, "types", ([filePath, issueRecordEntries]) => {
17
- if (filePath !== "src/configs/utils.ts") return issueRecordEntries;
18
- const expectedTypeNames = ["MergeConfigFn", "OptionalMergeConfigFn"];
19
- return issueRecordEntries.filter(([key]) => !expectedTypeNames.includes(key));
20
- });
21
- return options;
22
- };
23
- var knip_preprocessor_default = preprocess;
24
- export { knip_preprocessor_default as default };
25
-
26
- //# sourceMappingURL=knip-preprocessor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"knip-preprocessor.js","names":[],"sources":["../../src/configs/knip-preprocessor.ts"],"sourcesContent":["import type {\n IssueRecords,\n Preprocessor,\n ReporterOptions,\n SymbolIssueType,\n} from \"../../node_modules/knip/dist/types/issues.d.ts\"\nimport { knipConfig } from \"./knip.ts\"\n\n/*\n * The `IssueRecords` type represents an object where each key is the file path and the value is an object containing each issue object.\n *\n * For example:\n *\n * ```ts\n * {\n * \"path/to/file/with/issues.ts\": {\n * \"issue1\": { ... },\n * \"issue2\": { ... },\n * },\n * // ...\n * }\n * ```\n */\n\n/** The object containing all the issues for the given file path. */\ntype IssueRecord = IssueRecords[keyof IssueRecords]\ntype IssueRecordEntry = [keyof IssueRecord, IssueRecord[keyof IssueRecord]]\n\n/**\n * We transform `IssueRecords` into object entries where where the _value_ is an array of the object entries from each `IssueRecord`.\n *\n * For example, we're going from this:\n *\n * ```ts\n * {\n * \"path/to/file/with/issues.ts\": {\n * \"issue1\": { ... },\n * \"issue2\": { ... },\n * },\n * // ...\n * }\n * ```\n *\n * to this:\n *\n * ```ts\n * [\n * [\"path/to/file/with/issues.ts\", [[\"issue1\", { ... }], [\"issue2\", { ... }]]],\n * // ...\n * ]\n * ```\n */\ntype IssueRecordsEntry = [keyof IssueRecords, IssueRecordEntry[]]\n\n/**\n * Modifies issues based on the provided map function.\n *\n * This is needed because we also need to update `options.counters` after modifying issues.\n */\nfunction modifyIssues(\n options: ReporterOptions,\n issueType: SymbolIssueType,\n mapFn: (issueRecordsEntry: IssueRecordsEntry) => IssueRecordEntry[], // The mapFn should return the entries for the individual issues. We want to make the key (which is the file path) available, but we don't want to allow modification of the key.\n) {\n const originalIssues: IssueRecords = options.issues[issueType]\n const originalIssueEntries: IssueRecordsEntry[] = Object.entries(originalIssues).map(([key, issueRecord]) => [\n key,\n Object.entries(issueRecord),\n ])\n\n const modifiedIssueEntries = originalIssueEntries.map(\n // The map function receives something like `[\"path/to/file.ts\", [[\"issue1\", { ... }], [\"issue2\", { ... }]]]`\n // It then returns *only* the entries for the individual issues: `[[\"issue1\", { ... }], [\"issue2\", { ... }]]`\n ([key, issueRecordEntries]) => [key, Object.fromEntries(mapFn([key, issueRecordEntries]))] as const,\n )\n const modifiedIssues: IssueRecords = Object.fromEntries(modifiedIssueEntries)\n\n const countIssues = (issueRecords: IssueRecords) =>\n Object.values(issueRecords)\n .map((issueRecord) => Object.keys(issueRecord).length) // count the number of issues in each issue record\n .reduce((acc, curr) => acc + curr, 0)\n\n const originalIssueCount = countIssues(originalIssues)\n const modifiedIssueCount = countIssues(modifiedIssues)\n const issuesRemovedCount = originalIssueCount - modifiedIssueCount\n\n options.counters[issueType] = originalIssueCount - issuesRemovedCount\n options.issues[issueType] = modifiedIssues\n}\n\nconst entries = knipConfig().entry as string[]\n\nconst preprocess: Preprocessor = (options) => {\n // ignore the \"Refine entry pattern (no matches)\" configuration hints for entries in the base config\n options.configurationHints = options.configurationHints.filter(\n (hint) =>\n !(\n entries.some((entry) => typeof hint.identifier === \"string\" && hint.identifier.includes(entry)) &&\n (hint.type === \"entry-empty\" || hint.type === \"entry-redundant\")\n ),\n )\n\n modifyIssues(options, \"unlisted\", ([, issueRecordEntries]) =>\n issueRecordEntries.filter(([key]) => !key.includes(\"prettier\")),\n )\n\n modifyIssues(options, \"types\", ([filePath, issueRecordEntries]) => {\n if (filePath !== \"src/configs/utils.ts\") return issueRecordEntries\n // We need to bring these types into scope of each merge config module: https://github.com/microsoft/TypeScript/issues/5711\n const expectedTypeNames = [\"MergeConfigFn\", \"OptionalMergeConfigFn\"]\n return issueRecordEntries.filter(([key]) => !expectedTypeNames.includes(key))\n })\n\n return options\n}\n\nexport default preprocess\n"],"mappings":";AA2DA,SAAS,aACP,SACA,WACA,OACA;CACA,MAAM,iBAA+B,QAAQ,OAAO;CAMpD,MAAM,uBAL4C,OAAO,QAAQ,eAAe,CAAC,KAAK,CAAC,KAAK,iBAAiB,CAC3G,KACA,OAAO,QAAQ,YAAY,CAC5B,CAAC,CAEgD,KAG/C,CAAC,KAAK,wBAAwB,CAAC,KAAK,OAAO,YAAY,MAAM,CAAC,KAAK,mBAAmB,CAAC,CAAC,CAAC,CAC3F;CACD,MAAM,iBAA+B,OAAO,YAAY,qBAAqB;CAE7E,MAAM,eAAe,iBACnB,OAAO,OAAO,aAAa,CACxB,KAAK,gBAAgB,OAAO,KAAK,YAAY,CAAC,OAAO,CACrD,QAAQ,KAAK,SAAS,MAAM,MAAM,EAAE;CAEzC,MAAM,qBAAqB,YAAY,eAAe;CAEtD,MAAM,qBAAqB,qBADA,YAAY,eAAe;AAGtD,SAAQ,SAAS,aAAa,qBAAqB;AACnD,SAAQ,OAAO,aAAa;;AAG9B,MAAM,UAAU,YAAY,CAAC;AAE7B,MAAM,cAA4B,YAAY;AAE5C,SAAQ,qBAAqB,QAAQ,mBAAmB,QACrD,SACC,EACE,QAAQ,MAAM,UAAU,OAAO,KAAK,eAAe,YAAY,KAAK,WAAW,SAAS,MAAM,CAAC,KAC9F,KAAK,SAAS,iBAAiB,KAAK,SAAS,oBAEnD;AAED,cAAa,SAAS,aAAa,GAAG,wBACpC,mBAAmB,QAAQ,CAAC,SAAS,CAAC,IAAI,SAAS,WAAW,CAAC,CAChE;AAED,cAAa,SAAS,UAAU,CAAC,UAAU,wBAAwB;AACjE,MAAI,aAAa,uBAAwB,QAAO;EAEhD,MAAM,oBAAoB,CAAC,iBAAiB,wBAAwB;AACpE,SAAO,mBAAmB,QAAQ,CAAC,SAAS,CAAC,kBAAkB,SAAS,IAAI,CAAC;GAC7E;AAEF,QAAO;;AAGT,IAAA,4BAAe"}
@@ -1,27 +0,0 @@
1
- import { OptionalMergeConfigFn } from "./utils.js";
2
- import { Simplify } from "type-fest";
3
- import { Config } from "prettier";
4
-
5
- //#region src/configs/prettier.d.ts
6
- type PrettierConfig = Simplify<Config>;
7
- declare const baseConfig: {
8
- readonly printWidth: 120;
9
- readonly semi: false;
10
- readonly plugins: ["@prettier/plugin-xml", "prettier-plugin-sh", "prettier-plugin-toml", "prettier-plugin-astro", "prettier-plugin-tailwindcss"];
11
- readonly tailwindStylesheet: "./src/global.css";
12
- readonly overrides: [{
13
- readonly files: "*.jsonc";
14
- readonly options: {
15
- readonly trailingComma: "none";
16
- };
17
- }, {
18
- readonly files: "*.astro";
19
- readonly options: {
20
- readonly parser: "astro";
21
- };
22
- }];
23
- };
24
- declare const prettierConfig: OptionalMergeConfigFn<PrettierConfig, typeof baseConfig>;
25
- //#endregion
26
- export { prettierConfig };
27
- //# sourceMappingURL=prettier.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prettier.d.ts","names":[],"sources":["../../src/configs/prettier.ts"],"mappings":";;;;;KAOK,cAAA,GAAiB,QAAA,CAAS,MAAA;AAAA,cAEzB,UAAA;EAAA;;;;;;;;;;;;;;;;cA4BO,cAAA,EAAgB,qBAAA,CAAsB,cAAA,SAAuB,UAAA"}
@@ -1,23 +0,0 @@
1
- import { createMergeConfigFn } from "./utils.js";
2
- const prettierConfig = createMergeConfigFn({
3
- printWidth: 120,
4
- semi: false,
5
- plugins: [
6
- "@prettier/plugin-xml",
7
- "prettier-plugin-sh",
8
- "prettier-plugin-toml",
9
- "prettier-plugin-astro",
10
- "prettier-plugin-tailwindcss"
11
- ],
12
- tailwindStylesheet: "./src/global.css",
13
- overrides: [{
14
- files: "*.jsonc",
15
- options: { trailingComma: "none" }
16
- }, {
17
- files: "*.astro",
18
- options: { parser: "astro" }
19
- }]
20
- });
21
- export { prettierConfig };
22
-
23
- //# sourceMappingURL=prettier.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"prettier.js","names":[],"sources":["../../src/configs/prettier.ts"],"sourcesContent":["import type { Config } from \"prettier\"\nimport type { Simplify } from \"type-fest\"\n\nimport type { OptionalMergeConfigFn } from \"./utils.ts\"\nimport { createMergeConfigFn } from \"./utils.ts\"\n\n// for some reason the Config type from prettier doesn't satisfy AnyObj unless we simplify it\ntype PrettierConfig = Simplify<Config>\n\nconst baseConfig = {\n printWidth: 120,\n semi: false,\n plugins: [\n \"@prettier/plugin-xml\",\n \"prettier-plugin-sh\",\n \"prettier-plugin-toml\",\n \"prettier-plugin-astro\",\n \"prettier-plugin-tailwindcss\",\n ],\n tailwindStylesheet: \"./src/global.css\",\n overrides: [\n {\n // https://github.com/prettier/prettier/issues/15956\n files: \"*.jsonc\",\n options: {\n trailingComma: \"none\",\n },\n },\n {\n files: \"*.astro\",\n options: {\n parser: \"astro\",\n },\n },\n ],\n} as const satisfies PrettierConfig\n\nexport const prettierConfig: OptionalMergeConfigFn<PrettierConfig, typeof baseConfig> = createMergeConfigFn(baseConfig)\n"],"mappings":";AAqCA,MAAa,iBAA2E,oBA5BrE;CACjB,YAAY;CACZ,MAAM;CACN,SAAS;EACP;EACA;EACA;EACA;EACA;EACD;CACD,oBAAoB;CACpB,WAAW,CACT;EAEE,OAAO;EACP,SAAS,EACP,eAAe,QAChB;EACF,EACD;EACE,OAAO;EACP,SAAS,EACP,QAAQ,SACT;EACF,CACF;CACF,CAEsH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/configs/utils.ts"],"mappings":";;;;AAkBA;;UAAiB,aAAA;EAAA,2BAEY,UAAA,EACzB,UAAA,EAAY,iBAAA,GACX,SAAA,CAAU,UAAA,EAAY,iBAAA;IAAqB,cAAA;EAAA;AAAA;;;;;;;;UAW/B,qBAAA,iCAAsD,aAAA,CAAc,UAAA,EAAY,UAAA;EAAA,IAC3F,UAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../src/configs/utils.ts"],"sourcesContent":["import { mergeWith } from \"es-toolkit\"\nimport { clone } from \"remeda\"\nimport type { MergeDeep } from \"type-fest\"\n\ntype AnyObj = object\n\n/**\n * A wrapper around es-toolkit's `mergeWith` with a custom merge function that concatenates arrays.\n */\nfunction merge<T extends AnyObj, S extends AnyObj>(target: T, source: S): T & S {\n return mergeWith(target, source, (objValue: unknown, srcValue: unknown) =>\n Array.isArray(objValue) ? objValue.concat(srcValue) : undefined,\n )\n}\n\n/**\n * The merge config function, where the `UserConfig` passed in is merged with `BaseConfig`.\n */\nexport interface MergeConfigFn<UserConfig, BaseConfig> {\n // biome-ignore lint/style/useShorthandFunctionType: need to use call signature type\n <UserConfigToMerge extends UserConfig>(\n userConfig: UserConfigToMerge,\n ): MergeDeep<BaseConfig, UserConfigToMerge, { arrayMergeMode: \"spread\" }>\n // instead of returning `BaseConfig & UserConfig` (from `merge`), return a more friendly type using `MergeDeep`\n}\n\n/**\n * The optional merge config function, where the `userConfig` argument is optional.\n * - if `UserConfig` is not provided, the return type is `BaseConfig`\n * - if `UserConfig` is provided, the return type is the merged type of `BaseConfig` and `UserConfig`.\n *\n * Note that this extends `MergeConfigFn`, so this type has both function signatures on it.\n */\nexport interface OptionalMergeConfigFn<UserConfig, BaseConfig> extends MergeConfigFn<UserConfig, BaseConfig> {\n (): BaseConfig\n}\n\n/**\n * Creates a config merge function with proper type overloads for merging with a base config.\n */\nexport function createMergeConfigFn<UserConfig extends AnyObj, BaseConfig extends UserConfig>(baseConfig: BaseConfig) {\n // we don't care about the specific type of userConfig here because we assert mergeConfigFn as the correct type below\n const mergeConfigFn = (userConfig?: AnyObj) => {\n if (userConfig === undefined) return baseConfig\n // clone both target and source so we never mutate the original objects\n return merge(clone(baseConfig), clone(userConfig))\n }\n\n return mergeConfigFn as MergeConfigFn<UserConfig, BaseConfig> & OptionalMergeConfigFn<UserConfig, BaseConfig>\n}\n"],"mappings":";;AASA,SAAS,MAA0C,QAAW,QAAkB;AAC9E,QAAO,UAAU,QAAQ,SAAS,UAAmB,aACnD,MAAM,QAAQ,SAAS,GAAG,SAAS,OAAO,SAAS,GAAG,KAAA,EACvD;;AA4BH,SAAgB,oBAA8E,YAAwB;CAEpH,MAAM,iBAAiB,eAAwB;AAC7C,MAAI,eAAe,KAAA,EAAW,QAAO;AAErC,SAAO,MAAM,MAAM,WAAW,EAAE,MAAM,WAAW,CAAC;;AAGpD,QAAO"}
@@ -1,201 +0,0 @@
1
- #!/usr/bin/env node
2
- import path from "node:path";
3
- import process from "node:process";
4
- import fs from "node:fs/promises";
5
- import pc from "picocolors";
6
- import { attempt, err, isErr } from "ts-explicit-errors";
7
- import { message, multiple, object, option, string } from "@optique/core";
8
- import { run } from "@optique/run";
9
- import ts from "typescript";
10
- import fss from "node:fs";
11
- import { getTsconfig } from "get-tsconfig";
12
- function cli() {
13
- return run(object({
14
- write: option("-w", "--write", { description: message`Write changes to files` }),
15
- skipAlias: option("--skip-alias", { description: message`Skip transforming relative imports to use an alias` }),
16
- fileIgnorePatterns: multiple(option("-f", "--file-ignore", string({ metavar: "PATTERN" }), { description: message`Additional glob patterns for files to ignore` })),
17
- importIgnoreStrings: multiple(option("-i", "--import-ignore", string(), { description: message`An import path *containing* the given string will be ignored` }))
18
- }), {
19
- programName: "ts-import-fix",
20
- help: "option",
21
- showDefault: { prefix: " [default: " }
22
- });
23
- }
24
- async function checkExports(filePaths) {
25
- const EXPORT_ERRORS = [];
26
- const exportCheckResult = await attempt(() => {
27
- const filePromises = filePaths.map(async (filePath) => {
28
- const filePathParts = path.parse(filePath);
29
- if (filePathParts.name === "index") return;
30
- const sourceCode = await fs.readFile(filePath, "utf8");
31
- const sourceFile = ts.createSourceFile(filePathParts.base, sourceCode, ts.ScriptTarget.Latest, true);
32
- const exportDeclarations = [];
33
- const visit = (node) => {
34
- if (ts.isExportDeclaration(node)) exportDeclarations.push(node);
35
- ts.forEachChild(node, visit);
36
- };
37
- visit(sourceFile);
38
- if (exportDeclarations.length === 0) return;
39
- const exportDeclarationText = exportDeclarations.map((declaration) => declaration.getText()).join("\n");
40
- EXPORT_ERRORS.push(`${pc.redBright("✗")} ${pc.blue(filePath)}\n${pc.dim(exportDeclarationText)}\n`);
41
- });
42
- return Promise.all(filePromises);
43
- });
44
- if (isErr(exportCheckResult)) return err("something went wrong when checking exports", exportCheckResult);
45
- if (EXPORT_ERRORS.length > 0) return err(`found export declarations:\n${EXPORT_ERRORS.join("\n")}`, void 0);
46
- }
47
- const IMPORT_PATTERN = /(?:import|from)\s+['"]([^'"]+)['"]$/gm;
48
- function getPathsMap() {
49
- const tsconfig = getTsconfig();
50
- if (!tsconfig) return err("failed to load tsconfig", void 0);
51
- const pathsMap = {};
52
- for (let [alias, [aliasDir]] of Object.entries(tsconfig.config.compilerOptions?.paths ?? {})) {
53
- if (!alias.endsWith("/*")) continue;
54
- if (!aliasDir?.endsWith("/*")) continue;
55
- alias = alias.slice(0, -1);
56
- aliasDir = aliasDir.slice(0, -1);
57
- pathsMap[alias] = aliasDir;
58
- }
59
- return pathsMap;
60
- }
61
- function resolveImportPath(importPath, filePath, pathsMap) {
62
- const fileDir = path.dirname(filePath);
63
- const sortedAliases = Object.keys(pathsMap).sort((a, b) => b.length - a.length);
64
- for (const alias of sortedAliases) {
65
- if (!importPath.startsWith(alias)) continue;
66
- const aliasDir = pathsMap[alias];
67
- if (!aliasDir) continue;
68
- const relativePath = importPath.slice(alias.length);
69
- return path.resolve(aliasDir, relativePath);
70
- }
71
- return path.resolve(fileDir, importPath);
72
- }
73
- function changeExtension(importParts, newExtension) {
74
- return {
75
- ...importParts,
76
- ext: newExtension,
77
- base: ""
78
- };
79
- }
80
- const ALLOWED_EXTENSIONS = [
81
- ".ts",
82
- ".tsx",
83
- ".d.ts"
84
- ];
85
- function getNewExtensionPathParts(importParts) {
86
- const tsExtensionLookups = [
87
- "",
88
- ".js",
89
- ".jsx",
90
- ".ts",
91
- ".tsx"
92
- ];
93
- if (!tsExtensionLookups.includes(importParts.ext)) return {
94
- ext: importParts.ext,
95
- base: importParts.base
96
- };
97
- if (tsExtensionLookups.includes(importParts.ext)) for (const allowedExtension of ALLOWED_EXTENSIONS) {
98
- const targetPathParts = changeExtension(importParts, allowedExtension);
99
- const targetPath = path.format(targetPathParts);
100
- if (fss.existsSync(targetPath)) return {
101
- ext: targetPathParts.ext,
102
- base: targetPathParts.base
103
- };
104
- }
105
- }
106
- function getAliasPathParts(importParts, pathsMap) {
107
- const importPath = path.format(importParts);
108
- for (const [alias, aliasDir] of Object.entries(pathsMap)) {
109
- const relativeToAliasDir = path.relative(aliasDir, importPath);
110
- if (relativeToAliasDir.startsWith("..")) continue;
111
- return { dir: path.parse(`${alias}${relativeToAliasDir}`).dir };
112
- }
113
- }
114
- async function fixImports(filePaths, { write, importIgnoreStrings, skipAlias }) {
115
- const IMPORT_ERRORS = [];
116
- const TRANSFORMED_IMPORTS = [];
117
- const pathsMap = getPathsMap();
118
- if (isErr(pathsMap)) return pathsMap;
119
- const importFixResult = await attempt(() => {
120
- const filePromises = filePaths.map(async (filePath) => {
121
- const content = await fs.readFile(filePath, "utf8");
122
- const importErrorsForFile = [];
123
- const transformedImportsForFile = [];
124
- const transformedContent = content.replace(IMPORT_PATTERN, (match, importPath) => {
125
- const isRelativeImport = importPath.startsWith("./") || importPath.startsWith("../");
126
- const isAliasImport = Object.keys(pathsMap).some((alias) => importPath.startsWith(alias));
127
- if (!(isRelativeImport || isAliasImport)) return match;
128
- if (importIgnoreStrings.some((ignoreString) => importPath.includes(ignoreString))) return match;
129
- let newImportParts = path.parse(importPath);
130
- const resolvedImportPath = resolveImportPath(importPath, filePath, pathsMap);
131
- const resolvedImportParts = path.parse(resolvedImportPath);
132
- const transformExtensionResult = getNewExtensionPathParts(resolvedImportParts);
133
- if (transformExtensionResult) newImportParts = {
134
- ...newImportParts,
135
- ...transformExtensionResult
136
- };
137
- else {
138
- const targetFilePath = `${path.format(changeExtension(resolvedImportParts, ""))}.{${ALLOWED_EXTENSIONS.map((ext) => ext.replace(".", "")).join()}}`;
139
- importErrorsForFile.push(`skipped extension transform of '${importPath}': target file not found (looking for '${targetFilePath}')`);
140
- }
141
- if (isRelativeImport && !skipAlias) {
142
- const transformToAliasImportResult = getAliasPathParts(resolvedImportParts, pathsMap);
143
- if (transformToAliasImportResult) newImportParts = {
144
- ...newImportParts,
145
- ...transformToAliasImportResult
146
- };
147
- else importErrorsForFile.push(`skipped transforming relative import path '${importPath}': could not find appropriate alias`);
148
- }
149
- const newImportPath = path.format(newImportParts);
150
- if (newImportPath === importPath) return match;
151
- const { ext: originalExt } = path.parse(importPath);
152
- const { ext: newExt } = newImportParts;
153
- let newImportPathString = newImportPath;
154
- if (newExt !== originalExt) newImportPathString = `${path.format(changeExtension(newImportParts, ""))}${pc.greenBright(newExt)}`;
155
- transformedImportsForFile.push(`'${importPath}' -> '${newImportPathString}'`);
156
- return match.replace(importPath, newImportPath);
157
- });
158
- if (importErrorsForFile.length > 0) IMPORT_ERRORS.push(`${pc.redBright("✗")} ${pc.blue(filePath)}\n${importErrorsForFile.join("\n")}\n`);
159
- if (transformedImportsForFile.length > 0) TRANSFORMED_IMPORTS.push(`${pc.greenBright("✓")} ${pc.blue(filePath)}\n${transformedImportsForFile.join("\n")}\n`);
160
- if (transformedContent === content) return;
161
- if (write) await fs.writeFile(filePath, transformedContent);
162
- });
163
- return Promise.all(filePromises);
164
- });
165
- if (TRANSFORMED_IMPORTS.length > 0) console.log(`${pc.greenBright("[ts-import-fix]")} transformed imports:\n${TRANSFORMED_IMPORTS.join("\n")}`);
166
- if (isErr(importFixResult)) return err("something went wrong when transforming imports", importFixResult);
167
- if (IMPORT_ERRORS.length > 0) return err(`failed to transform some imports:\n${IMPORT_ERRORS.join("\n")}`, void 0);
168
- }
169
- const FILES_GLOB = "**/*.{ts,tsx,js,jsx,astro}";
170
- const BASE_IGNORE_PATTERNS = [
171
- ".git/",
172
- "node_modules/",
173
- "dist/"
174
- ];
175
- async function tsImportFix() {
176
- const { fileIgnorePatterns, ...fixImportsOptions } = cli();
177
- const errors = [];
178
- const allFileIgnorePatterns = [
179
- ...BASE_IGNORE_PATTERNS,
180
- "astro.config.ts",
181
- ...fileIgnorePatterns
182
- ];
183
- const filePaths = await Array.fromAsync(fs.glob(FILES_GLOB, { exclude: allFileIgnorePatterns }));
184
- const fixImportsResult = await fixImports(filePaths, fixImportsOptions);
185
- if (isErr(fixImportsResult)) errors.push(fixImportsResult);
186
- const checkExportsResult = await checkExports(filePaths);
187
- if (isErr(checkExportsResult)) errors.push(checkExportsResult);
188
- return errors;
189
- }
190
- async function main() {
191
- const errors = await tsImportFix();
192
- if (errors.length === 0) {
193
- console.log(`${pc.greenBright("[ts-import-fix]")} Done`);
194
- return 0;
195
- }
196
- const errorMessage = errors.map((error) => `${pc.redBright("[ts-import-fix]")} ${error.messageChain}`).join("\n\n");
197
- process.stderr.write(`${errorMessage}\n`);
198
- return 1;
199
- }
200
- if (import.meta.main) process.exitCode = await main();
201
- export {};