tsl-dx 0.11.0 → 0.12.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/dist/index.d.ts +1 -1
- package/dist/index.js +44 -16
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -86,6 +86,6 @@ type nullishOptions = {
|
|
|
86
86
|
* if (x == null) { }
|
|
87
87
|
* ```
|
|
88
88
|
*/
|
|
89
|
-
declare const nullish: (options?: "off" |
|
|
89
|
+
declare const nullish: (options?: nullishOptions | "off" | undefined) => _$tsl.Rule<unknown>;
|
|
90
90
|
//#endregion
|
|
91
91
|
export { noDuplicateExports, noDuplicateImports, noMultilineTemplateExpressionWithoutAutoDedent, nullish };
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,14 @@ import { defineRule } from "tsl";
|
|
|
2
2
|
import ts, { SyntaxKind } from "typescript";
|
|
3
3
|
import { match } from "ts-pattern";
|
|
4
4
|
|
|
5
|
+
//#region src/utils/print-node.ts
|
|
6
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
7
|
+
const dummySourceFile = ts.createSourceFile("", "", ts.ScriptTarget.Latest);
|
|
8
|
+
function printNode(node) {
|
|
9
|
+
return printer.printNode(ts.EmitHint.Unspecified, node, dummySourceFile);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
5
13
|
//#region src/rules/no-duplicate-exports.ts
|
|
6
14
|
const messages$3 = { default: (p) => `Duplicate export from module ${p.source}.` };
|
|
7
15
|
function isReExportDeclaration(node) {
|
|
@@ -48,9 +56,18 @@ const noDuplicateExports = defineRule(() => {
|
|
|
48
56
|
function buildSuggestions$1(existing, incoming) {
|
|
49
57
|
switch (true) {
|
|
50
58
|
case ts.isNamedExports(existing.exportClause) && ts.isNamedExports(incoming.exportClause): {
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
59
|
+
const seen = /* @__PURE__ */ new Set();
|
|
60
|
+
const elements = [];
|
|
61
|
+
for (const el of [...existing.exportClause.elements, ...incoming.exportClause.elements]) {
|
|
62
|
+
const text = el.getText();
|
|
63
|
+
if (seen.has(text)) continue;
|
|
64
|
+
seen.add(text);
|
|
65
|
+
elements.push(ts.factory.createExportSpecifier(el.isTypeOnly, el.propertyName != null ? ts.factory.createIdentifier(el.propertyName.text) : void 0, ts.factory.createIdentifier(el.name.text)));
|
|
66
|
+
}
|
|
67
|
+
const specifierText = existing.moduleSpecifier.getText();
|
|
68
|
+
const isSingleQuote = specifierText.startsWith("'");
|
|
69
|
+
const specifierValue = specifierText.slice(1, -1);
|
|
70
|
+
const exportDecl = ts.factory.createExportDeclaration(void 0, existing.isTypeOnly, ts.factory.createNamedExports(elements), ts.factory.createStringLiteral(specifierValue, isSingleQuote));
|
|
54
71
|
return [{
|
|
55
72
|
message: "Merge duplicate exports",
|
|
56
73
|
changes: [{
|
|
@@ -59,7 +76,7 @@ function buildSuggestions$1(existing, incoming) {
|
|
|
59
76
|
newText: ""
|
|
60
77
|
}, {
|
|
61
78
|
node: existing,
|
|
62
|
-
newText:
|
|
79
|
+
newText: printNode(exportDecl)
|
|
63
80
|
}]
|
|
64
81
|
}];
|
|
65
82
|
}
|
|
@@ -106,13 +123,13 @@ const noDuplicateImports = defineRule(() => {
|
|
|
106
123
|
defaultImport: node.importClause.name?.getText() ?? null,
|
|
107
124
|
bindings: match(node.importClause.namedBindings).with({ kind: ts.SyntaxKind.NamedImports }, (nb) => ({
|
|
108
125
|
kind: "named",
|
|
109
|
-
|
|
126
|
+
elements: nb.elements
|
|
110
127
|
})).with({ kind: ts.SyntaxKind.NamespaceImport }, (nb) => ({
|
|
111
128
|
kind: "namespace",
|
|
112
129
|
name: nb.name.getText()
|
|
113
130
|
})).otherwise(() => ({
|
|
114
131
|
kind: "named",
|
|
115
|
-
|
|
132
|
+
elements: []
|
|
116
133
|
}))
|
|
117
134
|
};
|
|
118
135
|
const existingImports = ctx.data.imports.get(importKind);
|
|
@@ -135,12 +152,19 @@ function buildSuggestions(existing, incoming) {
|
|
|
135
152
|
case existing.defaultImport != null && incoming.defaultImport != null && existing.defaultImport !== incoming.defaultImport: return [];
|
|
136
153
|
default: break;
|
|
137
154
|
}
|
|
138
|
-
const parts = [];
|
|
139
155
|
const defaultImport = existing.defaultImport ?? incoming.defaultImport;
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
const elements = [];
|
|
158
|
+
for (const el of [...existing.bindings.elements, ...incoming.bindings.elements]) {
|
|
159
|
+
const text = el.getText();
|
|
160
|
+
if (seen.has(text)) continue;
|
|
161
|
+
seen.add(text);
|
|
162
|
+
elements.push(ts.factory.createImportSpecifier(el.isTypeOnly, el.propertyName ? ts.factory.createIdentifier(el.propertyName.text) : void 0, ts.factory.createIdentifier(el.name.text)));
|
|
163
|
+
}
|
|
164
|
+
const sourceText = existing.source;
|
|
165
|
+
const isSingleQuote = sourceText.startsWith("'");
|
|
166
|
+
const sourceValue = sourceText.slice(1, -1);
|
|
167
|
+
const importDecl = ts.factory.createImportDeclaration(void 0, ts.factory.createImportClause(incoming.kind === "type", defaultImport != null ? ts.factory.createIdentifier(defaultImport) : void 0, ts.factory.createNamedImports(elements)), ts.factory.createStringLiteral(sourceValue, isSingleQuote));
|
|
144
168
|
return [{
|
|
145
169
|
message: "Merge duplicate imports",
|
|
146
170
|
changes: [{
|
|
@@ -149,7 +173,7 @@ function buildSuggestions(existing, incoming) {
|
|
|
149
173
|
newText: ""
|
|
150
174
|
}, {
|
|
151
175
|
node: existing.node,
|
|
152
|
-
newText:
|
|
176
|
+
newText: printNode(importDecl)
|
|
153
177
|
}]
|
|
154
178
|
}];
|
|
155
179
|
}
|
|
@@ -184,7 +208,9 @@ const messages$1 = {
|
|
|
184
208
|
*/
|
|
185
209
|
const noMultilineTemplateExpressionWithoutAutoDedent = defineRule((options) => {
|
|
186
210
|
const dedentTagNames = options?.dedentTagNames ?? ["dedent"];
|
|
187
|
-
const dedentTagImportCallback = options?.dedentTagImportCallback ?? ((name) =>
|
|
211
|
+
const dedentTagImportCallback = options?.dedentTagImportCallback ?? ((name) => {
|
|
212
|
+
return printNode(ts.factory.createImportDeclaration(void 0, ts.factory.createImportClause(void 0, ts.factory.createIdentifier(name), void 0), ts.factory.createStringLiteral("dedent"))) + "\n";
|
|
213
|
+
});
|
|
188
214
|
function getLine(node) {
|
|
189
215
|
const sourceFile = node.getSourceFile();
|
|
190
216
|
return [sourceFile.getLineAndCharacterOfPosition(node.getStart()).line, sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line];
|
|
@@ -244,6 +270,7 @@ const nullish = defineRule((options) => ({
|
|
|
244
270
|
visitor: { BinaryExpression(ctx, node) {
|
|
245
271
|
const newOperatorText = match(node.operatorToken.kind).with(SyntaxKind.EqualsEqualsEqualsToken, () => "==").with(SyntaxKind.ExclamationEqualsEqualsToken, () => "!=").otherwise(() => null);
|
|
246
272
|
if (newOperatorText == null) return;
|
|
273
|
+
const operatorToken = newOperatorText === "==" ? ts.factory.createToken(ts.SyntaxKind.EqualsEqualsToken) : ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsToken);
|
|
247
274
|
const offendingChild = [node.left, node.right].find((n) => {
|
|
248
275
|
switch (n.kind) {
|
|
249
276
|
case SyntaxKind.NullKeyword: return true;
|
|
@@ -252,17 +279,18 @@ const nullish = defineRule((options) => ({
|
|
|
252
279
|
}
|
|
253
280
|
});
|
|
254
281
|
if (offendingChild == null) return;
|
|
282
|
+
const nullNode = ts.factory.createNull();
|
|
255
283
|
ctx.report({
|
|
256
284
|
message: messages.default({ op: newOperatorText }),
|
|
257
285
|
node,
|
|
258
286
|
suggestions: [{
|
|
259
|
-
message: messages.replace({ expr: offendingChild === node.left ?
|
|
287
|
+
message: messages.replace({ expr: printNode(offendingChild === node.left ? ts.factory.createBinaryExpression(nullNode, operatorToken, node.right) : ts.factory.createBinaryExpression(node.left, operatorToken, nullNode)) }),
|
|
260
288
|
changes: [{
|
|
261
289
|
node: node.operatorToken,
|
|
262
|
-
newText:
|
|
290
|
+
newText: printNode(operatorToken)
|
|
263
291
|
}, {
|
|
264
292
|
node: offendingChild,
|
|
265
|
-
newText:
|
|
293
|
+
newText: printNode(nullNode)
|
|
266
294
|
}]
|
|
267
295
|
}]
|
|
268
296
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tsl-dx",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "A tsl plugin for better JavaScript/TypeScript DX.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tsl",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dedent": "^1.7.2",
|
|
29
29
|
"tsdown": "^0.21.9",
|
|
30
30
|
"tsl": "^1.0.30",
|
|
31
|
-
"vitest": "^4.1.
|
|
31
|
+
"vitest": "^4.1.5",
|
|
32
32
|
"@local/configs": "0.0.0",
|
|
33
33
|
"@local/eff": "0.2.9"
|
|
34
34
|
},
|