tsl-dx 0.4.0 → 0.5.1
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 +10 -12
- package/dist/index.js +87 -45
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as tsl from "tsl";
|
|
2
2
|
|
|
3
|
-
//#region src/rules/consistent-nullish-comparison.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* Rule to enforce the use of `== null` or `!= null` for nullish comparisons.
|
|
6
|
-
*
|
|
7
|
-
* @since 0.0.0
|
|
8
|
-
*/
|
|
9
|
-
declare const consistentNullishComparison: (options?: "off" | undefined) => tsl0.Rule<unknown>;
|
|
10
|
-
//#endregion
|
|
11
3
|
//#region src/rules/no-duplicate-exports.d.ts
|
|
12
4
|
/**
|
|
13
5
|
* Rule to detect and merge duplicate `export from` statements from the same module.
|
|
@@ -25,7 +17,7 @@ declare const consistentNullishComparison: (options?: "off" | undefined) => tsl0
|
|
|
25
17
|
* export { A, B } from 'module';
|
|
26
18
|
* ```
|
|
27
19
|
*/
|
|
28
|
-
declare const noDuplicateExports: (options?: "off" | undefined) =>
|
|
20
|
+
declare const noDuplicateExports: (options?: "off" | undefined) => tsl.Rule<unknown>;
|
|
29
21
|
//#endregion
|
|
30
22
|
//#region src/rules/no-duplicate-imports.d.ts
|
|
31
23
|
/**
|
|
@@ -44,6 +36,12 @@ declare const noDuplicateExports: (options?: "off" | undefined) => tsl0.Rule<unk
|
|
|
44
36
|
* import { A, B } from 'module';
|
|
45
37
|
* ```
|
|
46
38
|
*/
|
|
47
|
-
declare const noDuplicateImports: (options?: "off" | undefined) =>
|
|
39
|
+
declare const noDuplicateImports: (options?: "off" | undefined) => tsl.Rule<unknown>;
|
|
40
|
+
//#endregion
|
|
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?: "off" | undefined) => tsl.Rule<unknown>;
|
|
48
46
|
//#endregion
|
|
49
|
-
export {
|
|
47
|
+
export { noDuplicateExports, noDuplicateImports, noMultilineTemplateExpressionsWithoutAutoDedent, nullish };
|
package/dist/index.js
CHANGED
|
@@ -1,46 +1,9 @@
|
|
|
1
|
-
import { P, match } from "ts-pattern";
|
|
2
1
|
import { defineRule } from "tsl";
|
|
3
2
|
import ts, { SyntaxKind } from "typescript";
|
|
3
|
+
import { P, match } from "ts-pattern";
|
|
4
4
|
|
|
5
|
-
//#region src/rules/consistent-nullish-comparison.ts
|
|
6
|
-
/**
|
|
7
|
-
* Rule to enforce the use of `== null` or `!= null` for nullish comparisons.
|
|
8
|
-
*
|
|
9
|
-
* @since 0.0.0
|
|
10
|
-
*/
|
|
11
|
-
const consistentNullishComparison = defineRule(() => ({
|
|
12
|
-
name: "local/consistentNullishComparison",
|
|
13
|
-
visitor: { BinaryExpression(context, node) {
|
|
14
|
-
const newOperatorText = match(node.operatorToken.kind).with(SyntaxKind.EqualsEqualsEqualsToken, () => "==").with(SyntaxKind.ExclamationEqualsEqualsToken, () => "!=").otherwise(() => null);
|
|
15
|
-
if (newOperatorText == null) return;
|
|
16
|
-
const offendingChild = [node.left, node.right].find((n) => {
|
|
17
|
-
switch (n.kind) {
|
|
18
|
-
case SyntaxKind.NullKeyword: return true;
|
|
19
|
-
case SyntaxKind.Identifier: return n.escapedText === "undefined";
|
|
20
|
-
default: return false;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
if (offendingChild == null) return;
|
|
24
|
-
context.report({
|
|
25
|
-
message: `Use '${newOperatorText}' for nullish comparison.`,
|
|
26
|
-
node,
|
|
27
|
-
suggestions: [{
|
|
28
|
-
message: offendingChild === node.left ? `Replace with 'null ${newOperatorText} ${node.right.getText()}'.` : `Replace with '${node.left.getText()} ${newOperatorText} null'.`,
|
|
29
|
-
changes: [{
|
|
30
|
-
node: node.operatorToken,
|
|
31
|
-
newText: newOperatorText
|
|
32
|
-
}, {
|
|
33
|
-
node: offendingChild,
|
|
34
|
-
newText: "null"
|
|
35
|
-
}]
|
|
36
|
-
}]
|
|
37
|
-
});
|
|
38
|
-
} }
|
|
39
|
-
}));
|
|
40
|
-
|
|
41
|
-
//#endregion
|
|
42
5
|
//#region src/rules/no-duplicate-exports.ts
|
|
43
|
-
const messages$
|
|
6
|
+
const messages$3 = { default: (p) => `Duplicate export from module ${p.source}.` };
|
|
44
7
|
function isReExportDeclaration(node) {
|
|
45
8
|
return node.exportClause != null && node.moduleSpecifier != null;
|
|
46
9
|
}
|
|
@@ -62,7 +25,7 @@ function isReExportDeclaration(node) {
|
|
|
62
25
|
*/
|
|
63
26
|
const noDuplicateExports = defineRule(() => {
|
|
64
27
|
return {
|
|
65
|
-
name: "
|
|
28
|
+
name: "dx/no-duplicate-exports",
|
|
66
29
|
createData() {
|
|
67
30
|
return { exports: [] };
|
|
68
31
|
},
|
|
@@ -73,7 +36,7 @@ const noDuplicateExports = defineRule(() => {
|
|
|
73
36
|
if (duplicateExport != null) {
|
|
74
37
|
ctx.report({
|
|
75
38
|
node,
|
|
76
|
-
message: messages$
|
|
39
|
+
message: messages$3.default({ source }),
|
|
77
40
|
suggestions: buildSuggestions(duplicateExport, node)
|
|
78
41
|
});
|
|
79
42
|
return;
|
|
@@ -224,7 +187,7 @@ const compose = dual(2, (ab, bc) => (a) => bc(ab(a)));
|
|
|
224
187
|
|
|
225
188
|
//#endregion
|
|
226
189
|
//#region src/rules/no-duplicate-imports.ts
|
|
227
|
-
const messages = {
|
|
190
|
+
const messages$2 = { default: (p) => `Duplicate import from module ${p.source}.` };
|
|
228
191
|
/**
|
|
229
192
|
* Rule to detect and merge duplicate `import from` statements from the same module.
|
|
230
193
|
*
|
|
@@ -243,7 +206,7 @@ const messages = { noDuplicateImports: (p) => `Duplicate import from module ${p.
|
|
|
243
206
|
*/
|
|
244
207
|
const noDuplicateImports = defineRule(() => {
|
|
245
208
|
return {
|
|
246
|
-
name: "
|
|
209
|
+
name: "dx/no-duplicate-imports",
|
|
247
210
|
createData() {
|
|
248
211
|
return { imports: [
|
|
249
212
|
[],
|
|
@@ -265,7 +228,7 @@ const noDuplicateImports = defineRule(() => {
|
|
|
265
228
|
if (duplicateImport != null) {
|
|
266
229
|
ctx.report({
|
|
267
230
|
node,
|
|
268
|
-
message: messages.
|
|
231
|
+
message: messages$2.default({ source: importInfo.source }),
|
|
269
232
|
suggestions: importKind > 1 ? [] : [{
|
|
270
233
|
message: "Merge duplicate imports",
|
|
271
234
|
changes: [{
|
|
@@ -306,4 +269,83 @@ function buildMergedImport(a, b) {
|
|
|
306
269
|
}
|
|
307
270
|
|
|
308
271
|
//#endregion
|
|
309
|
-
|
|
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({
|
|
287
|
+
node,
|
|
288
|
+
message: messages$1.default()
|
|
289
|
+
});
|
|
290
|
+
} }
|
|
291
|
+
}));
|
|
292
|
+
|
|
293
|
+
//#endregion
|
|
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(() => ({
|
|
301
|
+
name: "dx/nullish",
|
|
302
|
+
visitor: {
|
|
303
|
+
UndefinedKeyword(ctx, node) {
|
|
304
|
+
if (node.getSourceFile().isDeclarationFile) return;
|
|
305
|
+
ctx.report({
|
|
306
|
+
node,
|
|
307
|
+
message: messages.useUnitForUndefined,
|
|
308
|
+
suggestions: [{
|
|
309
|
+
message: suggestions.replaceWithExpression({ expr: "unit" }),
|
|
310
|
+
changes: [{
|
|
311
|
+
node,
|
|
312
|
+
newText: "unit"
|
|
313
|
+
}, {
|
|
314
|
+
start: 0,
|
|
315
|
+
end: 0,
|
|
316
|
+
newText: "import { unit } from '@local/eff';\n"
|
|
317
|
+
}]
|
|
318
|
+
}]
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
BinaryExpression(ctx, node) {
|
|
322
|
+
const newOperatorText = match(node.operatorToken.kind).with(SyntaxKind.EqualsEqualsEqualsToken, () => "==").with(SyntaxKind.ExclamationEqualsEqualsToken, () => "!=").otherwise(() => null);
|
|
323
|
+
if (newOperatorText == null) return;
|
|
324
|
+
const offendingChild = [node.left, node.right].find((n) => {
|
|
325
|
+
switch (n.kind) {
|
|
326
|
+
case SyntaxKind.NullKeyword: return true;
|
|
327
|
+
case SyntaxKind.Identifier: return n.escapedText === "undefined";
|
|
328
|
+
default: return false;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
if (offendingChild == null) return;
|
|
332
|
+
ctx.report({
|
|
333
|
+
message: messages.useLooseNullishComparison({ op: newOperatorText }),
|
|
334
|
+
node,
|
|
335
|
+
suggestions: [{
|
|
336
|
+
message: suggestions.replaceWithExpression({ expr: offendingChild === node.left ? `null ${newOperatorText} ${node.right.getText()}` : `${node.left.getText()} ${newOperatorText} null` }),
|
|
337
|
+
changes: [{
|
|
338
|
+
node: node.operatorToken,
|
|
339
|
+
newText: newOperatorText
|
|
340
|
+
}, {
|
|
341
|
+
node: offendingChild,
|
|
342
|
+
newText: "null"
|
|
343
|
+
}]
|
|
344
|
+
}]
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}));
|
|
349
|
+
|
|
350
|
+
//#endregion
|
|
351
|
+
export { noDuplicateExports, noDuplicateImports, noMultilineTemplateExpressionsWithoutAutoDedent, nullish };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsl-dx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
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",
|