tsl-dx 0.5.0 → 0.5.2
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/dist/index.d.ts +9 -13
- package/dist/index.js +82 -42
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tsl from "tsl";
|
|
2
2
|
|
|
3
3
|
//#region src/rules/no-duplicate-exports.d.ts
|
|
4
4
|
/**
|
|
@@ -17,7 +17,7 @@ import * as tsl0 from "tsl";
|
|
|
17
17
|
* export { A, B } from 'module';
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
|
-
declare const noDuplicateExports: (options?: "off" | undefined) =>
|
|
20
|
+
declare const noDuplicateExports: (options?: "off" | undefined) => tsl.Rule<unknown>;
|
|
21
21
|
//#endregion
|
|
22
22
|
//#region src/rules/no-duplicate-imports.d.ts
|
|
23
23
|
/**
|
|
@@ -36,16 +36,12 @@ declare const noDuplicateExports: (options?: "off" | undefined) => tsl0.Rule<unk
|
|
|
36
36
|
* import { A, B } from 'module';
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
declare const noDuplicateImports: (options?: "off" | undefined) =>
|
|
39
|
+
declare const noDuplicateImports: (options?: "off" | undefined) => tsl.Rule<unknown>;
|
|
40
40
|
//#endregion
|
|
41
|
-
//#region src/rules/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* In TypeScript, using '==' and '!=' for nullish comparisons is a common practice because it checks for both null and undefined values
|
|
47
|
-
* This rule promotes consistency in codebases by ensuring that developers use the appropriate operators for nullish checks
|
|
48
|
-
*/
|
|
49
|
-
declare const nullishComparison: (options?: "off" | undefined) => tsl0.Rule<unknown>;
|
|
41
|
+
//#region src/rules/no-multiline-template-expressions-without-auto-dedent.d.ts
|
|
42
|
+
declare const noMultilineTemplateExpressionsWithoutAutoDedent: (options?: "off" | undefined) => tsl.Rule<unknown>;
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/rules/nullish.d.ts
|
|
45
|
+
declare const nullish: (options?: Record<string, unknown> | "off" | undefined) => tsl.Rule<unknown>;
|
|
50
46
|
//#endregion
|
|
51
|
-
export { noDuplicateExports, noDuplicateImports,
|
|
47
|
+
export { noDuplicateExports, noDuplicateImports, noMultilineTemplateExpressionsWithoutAutoDedent, nullish };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import ts, { SyntaxKind } from "typescript";
|
|
|
3
3
|
import { P, match } from "ts-pattern";
|
|
4
4
|
|
|
5
5
|
//#region src/rules/no-duplicate-exports.ts
|
|
6
|
-
const messages$
|
|
6
|
+
const messages$3 = { default: (p) => `Duplicate export from module ${p.source}.` };
|
|
7
7
|
function isReExportDeclaration(node) {
|
|
8
8
|
return node.exportClause != null && node.moduleSpecifier != null;
|
|
9
9
|
}
|
|
@@ -36,7 +36,7 @@ const noDuplicateExports = defineRule(() => {
|
|
|
36
36
|
if (duplicateExport != null) {
|
|
37
37
|
ctx.report({
|
|
38
38
|
node,
|
|
39
|
-
message: messages$
|
|
39
|
+
message: messages$3.default({ source }),
|
|
40
40
|
suggestions: buildSuggestions(duplicateExport, node)
|
|
41
41
|
});
|
|
42
42
|
return;
|
|
@@ -187,7 +187,7 @@ const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
|
|
|
187
187
|
|
|
188
188
|
//#endregion
|
|
189
189
|
//#region src/rules/no-duplicate-imports.ts
|
|
190
|
-
const messages$
|
|
190
|
+
const messages$2 = { default: (p) => `Duplicate import from module ${p.source}.` };
|
|
191
191
|
/**
|
|
192
192
|
* Rule to detect and merge duplicate `import from` statements from the same module.
|
|
193
193
|
*
|
|
@@ -228,7 +228,7 @@ const noDuplicateImports = defineRule(() => {
|
|
|
228
228
|
if (duplicateImport != null) {
|
|
229
229
|
ctx.report({
|
|
230
230
|
node,
|
|
231
|
-
message: messages$
|
|
231
|
+
message: messages$2.default({ source: importInfo.source }),
|
|
232
232
|
suggestions: importKind > 1 ? [] : [{
|
|
233
233
|
message: "Merge duplicate imports",
|
|
234
234
|
changes: [{
|
|
@@ -269,47 +269,87 @@ function buildMergedImport(a, b) {
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
//#endregion
|
|
272
|
-
//#region src/
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
const newOperatorText = match(node.operatorToken.kind).with(SyntaxKind.EqualsEqualsEqualsToken, () => "==").with(SyntaxKind.ExclamationEqualsEqualsToken, () => "!=").otherwise(() => null);
|
|
288
|
-
if (newOperatorText == null) return;
|
|
289
|
-
const offendingChild = [node.left, node.right].find((n) => {
|
|
290
|
-
switch (n.kind) {
|
|
291
|
-
case SyntaxKind.NullKeyword: return true;
|
|
292
|
-
case SyntaxKind.Identifier: return n.escapedText === "undefined";
|
|
293
|
-
default: return false;
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
if (offendingChild == null) return;
|
|
297
|
-
context.report({
|
|
298
|
-
message: messages.default({ op: newOperatorText }),
|
|
272
|
+
//#region src/utils/source-file.ts
|
|
273
|
+
function getLine(node) {
|
|
274
|
+
const sourceFile = node.getSourceFile();
|
|
275
|
+
return [sourceFile.getLineAndCharacterOfPosition(node.getStart()).line, sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line];
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/rules/no-multiline-template-expressions-without-auto-dedent.ts
|
|
280
|
+
const messages$1 = { default: () => `Avoid using multiline template expressions without auto-dedent` };
|
|
281
|
+
const noMultilineTemplateExpressionsWithoutAutoDedent = defineRule(() => ({
|
|
282
|
+
name: "dx/no-multiline-template-expressions-without-auto-dedent",
|
|
283
|
+
visitor: { NoSubstitutionTemplateLiteral(ctx, node) {
|
|
284
|
+
if (node.parent.kind === SyntaxKind.TaggedTemplateExpression) return;
|
|
285
|
+
const [startLine, endLine] = getLine(node);
|
|
286
|
+
if (startLine !== endLine) ctx.report({
|
|
299
287
|
node,
|
|
300
|
-
|
|
301
|
-
message: messages.replace({ expr: offendingChild === node.left ? `null ${newOperatorText} ${node.right.getText()}` : `${node.left.getText()} ${newOperatorText} null` }),
|
|
302
|
-
changes: [{
|
|
303
|
-
node: node.operatorToken,
|
|
304
|
-
newText: newOperatorText
|
|
305
|
-
}, {
|
|
306
|
-
node: offendingChild,
|
|
307
|
-
newText: "null"
|
|
308
|
-
}]
|
|
309
|
-
}]
|
|
288
|
+
message: messages$1.default()
|
|
310
289
|
});
|
|
311
290
|
} }
|
|
312
291
|
}));
|
|
313
292
|
|
|
314
293
|
//#endregion
|
|
315
|
-
|
|
294
|
+
//#region src/rules/nullish.ts
|
|
295
|
+
const messages = {
|
|
296
|
+
useUnitForUndefined: "Use 'unit' instead of 'undefined'.",
|
|
297
|
+
useLooseNullishComparison: (p) => `Use '${p.op}' for nullish comparison.`
|
|
298
|
+
};
|
|
299
|
+
const suggestions = { replaceWithExpression: (p) => `Replace with '${p.expr}'.` };
|
|
300
|
+
const nullish = defineRule((options) => ({
|
|
301
|
+
name: "dx/nullish",
|
|
302
|
+
createData(ctx) {
|
|
303
|
+
return { runtimeLibrary: options?.runtimeLibrary ?? "@local/eff" };
|
|
304
|
+
},
|
|
305
|
+
visitor: {
|
|
306
|
+
UndefinedKeyword(ctx, node) {
|
|
307
|
+
if (node.getSourceFile().isDeclarationFile) return;
|
|
308
|
+
ctx.report({
|
|
309
|
+
node,
|
|
310
|
+
message: messages.useUnitForUndefined,
|
|
311
|
+
suggestions: [{
|
|
312
|
+
message: suggestions.replaceWithExpression({ expr: "unit" }),
|
|
313
|
+
changes: [{
|
|
314
|
+
node,
|
|
315
|
+
newText: "unit"
|
|
316
|
+
}, {
|
|
317
|
+
start: 0,
|
|
318
|
+
end: 0,
|
|
319
|
+
newText: `import { unit } from '${ctx.data.runtimeLibrary}';\n`
|
|
320
|
+
}]
|
|
321
|
+
}]
|
|
322
|
+
});
|
|
323
|
+
},
|
|
324
|
+
BinaryExpression(ctx, node) {
|
|
325
|
+
if (node.getSourceFile().isDeclarationFile) return;
|
|
326
|
+
const newOperatorText = match(node.operatorToken.kind).with(SyntaxKind.EqualsEqualsEqualsToken, () => "==").with(SyntaxKind.ExclamationEqualsEqualsToken, () => "!=").otherwise(() => null);
|
|
327
|
+
if (newOperatorText == null) return;
|
|
328
|
+
const offendingChild = [node.left, node.right].find((n) => {
|
|
329
|
+
switch (n.kind) {
|
|
330
|
+
case SyntaxKind.NullKeyword: return true;
|
|
331
|
+
case SyntaxKind.Identifier: return n.escapedText === "undefined";
|
|
332
|
+
default: return false;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
if (offendingChild == null) return;
|
|
336
|
+
ctx.report({
|
|
337
|
+
message: messages.useLooseNullishComparison({ op: newOperatorText }),
|
|
338
|
+
node,
|
|
339
|
+
suggestions: [{
|
|
340
|
+
message: suggestions.replaceWithExpression({ expr: offendingChild === node.left ? `null ${newOperatorText} ${node.right.getText()}` : `${node.left.getText()} ${newOperatorText} null` }),
|
|
341
|
+
changes: [{
|
|
342
|
+
node: node.operatorToken,
|
|
343
|
+
newText: newOperatorText
|
|
344
|
+
}, {
|
|
345
|
+
node: offendingChild,
|
|
346
|
+
newText: "null"
|
|
347
|
+
}]
|
|
348
|
+
}]
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}));
|
|
353
|
+
|
|
354
|
+
//#endregion
|
|
355
|
+
export { noDuplicateExports, noDuplicateImports, noMultilineTemplateExpressionsWithoutAutoDedent, nullish };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsl-dx",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "A tsl plugin for better JavaScript/TypeScript DX.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tsl",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"dedent": "^1.7.1",
|
|
28
|
-
"tsdown": "^0.20.
|
|
28
|
+
"tsdown": "^0.20.3",
|
|
29
29
|
"tsl": "^1.0.28",
|
|
30
30
|
"vitest": "^4.0.18",
|
|
31
31
|
"@local/configs": "0.0.0",
|