Skip to content

Commit 4f9aca6

Browse files
committed
feat(tsl-module): add noDuplicateImport rule to disallow duplicate imports
chore(tsl-module): initialize package.json and add necessary configurations feat(tsl-module): implement no-duplicate-import rule logic docs(tsl-module): add README and documentation for noDuplicateImport variable chore(tsl-module): add TypeScript configuration and build scripts chore: update tsdown to version 0.19.0-beta.2 in pnpm-lock.yaml
1 parent 0d5750d commit 4f9aca6

File tree

15 files changed

+537
-16
lines changed

15 files changed

+537
-16
lines changed

.pkgs/function-rules/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
},
2626
"devDependencies": {
2727
"eslint": "^9.39.2",
28-
"tsdown": "^0.19.0-beta.1"
28+
"tsdown": "^0.19.0-beta.2"
2929
},
3030
"peerDependencies": {
3131
"eslint": "^9.39.2",

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"url": "git+https://github.com/Rel1cx/dx.git"
1313
},
1414
"license": "MIT",
15-
"author": "Rel1cx<rel1cx@proton.me>",
15+
"author": "Rel1cx<let@ik.me>",
1616
"type": "module",
1717
"scripts": {
1818
"build": "pnpm run build:pkgs && pnpm run build:packages",
@@ -52,7 +52,7 @@
5252
"sort-package-json": "^3.6.0",
5353
"tinyglobby": "^0.2.15",
5454
"ts-pattern": "^5.9.0",
55-
"tsdown": "^0.19.0-beta.1",
55+
"tsdown": "^0.19.0-beta.2",
5656
"tsx": "^4.21.0",
5757
"typedoc": "^0.28.15",
5858
"typedoc-plugin-markdown": "^4.9.0",

packages/eff/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"url": "git+https://github.com/Rel1cx/dx.git"
1212
},
1313
"license": "MIT",
14-
"author": "Rel1cx<rel1cx@proton.me>",
14+
"author": "Rel1cx<let@ik.me>",
1515
"type": "module",
1616
"exports": {
1717
".": "./dist/index.js",

packages/eslint-plugin-function-rule/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"url": "git+https://github.com/Rel1cx/dx.git"
1212
},
1313
"license": "MIT",
14-
"author": "Rel1cx<rel1cx@proton.me>",
14+
"author": "Rel1cx<let@ik.me>",
1515
"sideEffects": false,
1616
"type": "module",
1717
"exports": {

packages/eslint-plugin-function/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"url": "git+https://github.com/Rel1cx/dx.git"
1313
},
1414
"license": "MIT",
15-
"author": "Rel1cx<rel1cx@proton.me>",
15+
"author": "Rel1cx<let@ik.me>",
1616
"sideEffects": false,
1717
"type": "module",
1818
"exports": {
@@ -49,7 +49,7 @@
4949
"@typescript-eslint/rule-tester": "^8.51.0",
5050
"dedent": "^1.7.1",
5151
"eslint": "^9.39.2",
52-
"tsdown": "^0.19.0-beta.1"
52+
"tsdown": "^0.19.0-beta.2"
5353
},
5454
"peerDependencies": {
5555
"eslint": "^9.39.2",

packages/tsl-module/docs/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# tsl-module
2+
3+
## Variables
4+
5+
| Variable | Description |
6+
| ------ | ------ |
7+
| [noDuplicateImport](variables/noDuplicateImport.md) | Rule to disallow duplicate imports from the same module. |
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[tsl-module](../README.md) / noDuplicateImport
2+
3+
# Variable: noDuplicateImport()
4+
5+
```ts
6+
const noDuplicateImport: (options?: "off") => Rule<unknown>;
7+
```
8+
9+
Rule to disallow duplicate imports from the same module.
10+
11+
## Parameters
12+
13+
| Parameter | Type |
14+
| ------ | ------ |
15+
| `options?` | `"off"` |
16+
17+
## Returns
18+
19+
`Rule`\<`unknown`\>
20+
21+
## Examples
22+
23+
```ts
24+
// Incorrect
25+
import { A } from 'module';
26+
import { B } from 'module';
27+
```
28+
29+
```ts
30+
// Incorrect
31+
import type { A } from 'module';
32+
import type { B } from 'module';
33+
```
34+
35+
```ts
36+
// Correct
37+
import { A, B } from 'module';
38+
```
39+
40+
```ts
41+
// Correct
42+
import { A } from 'moduleA';
43+
import type { B } from 'moduleA';
44+
```

packages/tsl-module/package.json

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"name": "tsl-module",
3+
"version": "0.1.3",
4+
"description": "A TSL plugin for JavaScript and TypeScript module syntax linting and transformations.",
5+
"keywords": [
6+
"tsl",
7+
"tsl-module"
8+
],
9+
"license": "MIT",
10+
"author": "Rel1cx<let@ik.me>",
11+
"sideEffects": false,
12+
"type": "module",
13+
"exports": {
14+
".": {
15+
"types": "./dist/index.d.ts",
16+
"import": "./dist/index.js"
17+
},
18+
"./package.json": "./package.json"
19+
},
20+
"files": [
21+
"dist",
22+
"./package.json"
23+
],
24+
"scripts": {
25+
"build": "tsdown --dts-resolve",
26+
"build:docs": "typedoc",
27+
"lint:publish": "pnpm publint",
28+
"lint:ts": "tsl",
29+
"publish": "pnpm run build && pnpm run lint:publish"
30+
},
31+
"dependencies": {
32+
"@let/eff": "jsr:^0.1.2"
33+
},
34+
"devDependencies": {
35+
"@local/configs": "workspace:*",
36+
"tsdown": "^0.19.0-beta.2"
37+
},
38+
"peerDependencies": {
39+
"tsl": "^1.0.28",
40+
"typescript": "^4.9.5 || ^5.4.5"
41+
},
42+
"engines": {
43+
"bun": ">=1.2.18",
44+
"node": ">=24.6.0"
45+
},
46+
"publishConfig": {
47+
"access": "public"
48+
}
49+
}

packages/tsl-module/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { noDuplicateImport } from "./rules/no-duplicate-import";
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { defineRule } from "tsl";
2+
import ts from "typescript";
3+
4+
export const messages = {
5+
noDuplicateImport: (p: { name: string }) => `Duplicate import of module '${p.name}'.`,
6+
} as const;
7+
8+
/**
9+
* Rule to disallow duplicate imports from the same module.
10+
*
11+
* @example
12+
*
13+
* ```ts
14+
* // Incorrect
15+
* import { A } from 'module';
16+
* import { B } from 'module';
17+
* ```
18+
*
19+
* ```ts
20+
* // Incorrect
21+
* import type { A } from 'module';
22+
* import type { B } from 'module';
23+
* ```
24+
*
25+
* @example
26+
*
27+
* ```ts
28+
* // Correct
29+
* import { A, B } from 'module';
30+
* ```
31+
*
32+
* ```ts
33+
* // Correct
34+
* import { A } from 'moduleA';
35+
* import type { B } from 'moduleA';
36+
* ```
37+
*/
38+
export const noDuplicateImport = defineRule(() => {
39+
return {
40+
name: "module/no-duplicate-import",
41+
createData() {
42+
return [new Set<string>(), new Set<string>()] as const;
43+
},
44+
visitor: {
45+
ImportDeclaration(ctx, node) {
46+
const isTypeOnly = node.importClause?.phaseModifier === ts.SyntaxKind.TypeKeyword;
47+
const importSource = node.moduleSpecifier.getText();
48+
const [vImports, tImports] = ctx.data;
49+
const importsSet = isTypeOnly ? tImports : vImports;
50+
if (importsSet.has(importSource)) {
51+
ctx.report({
52+
node: node.moduleSpecifier,
53+
message: messages.noDuplicateImport({ name: importSource }),
54+
});
55+
return;
56+
}
57+
importsSet.add(importSource);
58+
},
59+
},
60+
};
61+
});

0 commit comments

Comments
 (0)