@fenge/eslint-config 0.1.0-beta.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/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/config/gitignore.d.ts +4 -0
- package/dist/config/gitignore.d.ts.map +1 -0
- package/dist/config/gitignore.js +19 -0
- package/dist/config/ignore.d.ts +14 -0
- package/dist/config/ignore.d.ts.map +1 -0
- package/dist/config/ignore.js +22 -0
- package/dist/config/javascript.d.ts +419 -0
- package/dist/config/javascript.d.ts.map +1 -0
- package/dist/config/javascript.js +474 -0
- package/dist/config/packagejson.d.ts +29 -0
- package/dist/config/packagejson.d.ts.map +1 -0
- package/dist/config/packagejson.js +34 -0
- package/dist/config/typescript.d.ts +533 -0
- package/dist/config/typescript.d.ts.map +1 -0
- package/dist/config/typescript.js +238 -0
- package/dist/eslint.config.d.ts +25 -0
- package/dist/eslint.config.d.ts.map +1 -0
- package/dist/eslint.config.js +68 -0
- package/package.json +59 -0
- package/src/config/gitignore.ts +24 -0
- package/src/config/ignore.ts +21 -0
- package/src/config/javascript.spec.ts +31 -0
- package/src/config/javascript.ts +485 -0
- package/src/config/packagejson.ts +34 -0
- package/src/config/typescript.spec.ts +84 -0
- package/src/config/typescript.ts +261 -0
- package/src/eslint.config.spec.ts +32 -0
- package/src/eslint.config.ts +100 -0
- package/src/typing.d.ts +8 -0
- package/test/no-duplicated.spec.ts +61 -0
- package/test/prettier.spec.ts +42 -0
- package/tsconfig.build.json +5 -0
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import * as fengeTsPlugin from "@fenge/eslint-plugin-ts";
|
|
3
|
+
import tsParser from "@typescript-eslint/parser";
|
|
4
|
+
import deprecationPlugin from "eslint-plugin-deprecation";
|
|
5
|
+
import { javascript } from "./javascript.js";
|
|
6
|
+
|
|
7
|
+
export function typescript(project?: string) {
|
|
8
|
+
const jsConfig = javascript()[0];
|
|
9
|
+
|
|
10
|
+
const getTsExtensionRules = () => {
|
|
11
|
+
// https://typescript-eslint.io/rules/?=extension
|
|
12
|
+
const extensionRuleKeys = [
|
|
13
|
+
"block-spacing",
|
|
14
|
+
"brace-style",
|
|
15
|
+
"class-methods-use-this",
|
|
16
|
+
"comma-dangle",
|
|
17
|
+
"comma-spacing",
|
|
18
|
+
"consistent-return",
|
|
19
|
+
"default-param-last",
|
|
20
|
+
"dot-notation",
|
|
21
|
+
"func-call-spacing",
|
|
22
|
+
"indent",
|
|
23
|
+
"init-declarations",
|
|
24
|
+
"key-spacing",
|
|
25
|
+
"keyword-spacing",
|
|
26
|
+
"lines-around-comment",
|
|
27
|
+
"lines-between-class-members",
|
|
28
|
+
"max-params",
|
|
29
|
+
"no-array-constructor",
|
|
30
|
+
"no-dupe-class-members",
|
|
31
|
+
"no-empty-function",
|
|
32
|
+
"no-extra-parens",
|
|
33
|
+
"no-extra-semi",
|
|
34
|
+
"no-implied-eval",
|
|
35
|
+
"no-invalid-this",
|
|
36
|
+
"no-loop-func",
|
|
37
|
+
// "no-loss-of-precision",
|
|
38
|
+
"no-magic-numbers",
|
|
39
|
+
"no-redeclare",
|
|
40
|
+
"no-restricted-imports",
|
|
41
|
+
"no-shadow",
|
|
42
|
+
"no-throw-literal",
|
|
43
|
+
"no-unused-expressions",
|
|
44
|
+
"no-unused-vars",
|
|
45
|
+
"no-use-before-define",
|
|
46
|
+
"no-useless-constructor",
|
|
47
|
+
"object-curly-spacing",
|
|
48
|
+
"only-throw-error", // this rule based on 'eslint/no-throw-literal'
|
|
49
|
+
"padding-line-between-statements",
|
|
50
|
+
"prefer-destructuring",
|
|
51
|
+
"prefer-promise-reject-errors",
|
|
52
|
+
"quotes",
|
|
53
|
+
"require-await",
|
|
54
|
+
"return-await", // this rule based on 'eslint/no-return-await' instead of 'eslint/return-await'
|
|
55
|
+
"semi",
|
|
56
|
+
"space-before-blocks",
|
|
57
|
+
"space-before-function-paren",
|
|
58
|
+
"space-infix-ops",
|
|
59
|
+
] as const;
|
|
60
|
+
type ExtensionRuleKey = (typeof extensionRuleKeys)[number];
|
|
61
|
+
type JsConfigRuleKey = keyof typeof jsConfig.rules;
|
|
62
|
+
|
|
63
|
+
type JsExtensionKey = Extract<ExtensionRuleKey, JsConfigRuleKey>; // Extract
|
|
64
|
+
type TsExtensionKey = `@typescript-eslint/${JsExtensionKey}`;
|
|
65
|
+
|
|
66
|
+
type GetJsKey<T extends TsExtensionKey> =
|
|
67
|
+
T extends `@typescript-eslint/${infer K}` ? K : never;
|
|
68
|
+
type JsResult = {
|
|
69
|
+
[Key in JsExtensionKey]: "off";
|
|
70
|
+
};
|
|
71
|
+
type TsResult = {
|
|
72
|
+
[Key in TsExtensionKey]: (typeof jsConfig.rules)[GetJsKey<Key>];
|
|
73
|
+
};
|
|
74
|
+
type Result = JsResult & TsResult;
|
|
75
|
+
|
|
76
|
+
const extensionRuleKeySet = new Set<string>(extensionRuleKeys);
|
|
77
|
+
return Object.entries(jsConfig.rules)
|
|
78
|
+
.filter(([key]) => extensionRuleKeySet.has(key))
|
|
79
|
+
.reduce(
|
|
80
|
+
(prev, [jsRuleKey, jsRuleValue]) => ({
|
|
81
|
+
...prev,
|
|
82
|
+
[jsRuleKey]: "off",
|
|
83
|
+
[`@typescript-eslint/${jsRuleKey}`]: jsRuleValue,
|
|
84
|
+
}),
|
|
85
|
+
{} as Result,
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return [
|
|
90
|
+
{
|
|
91
|
+
...jsConfig,
|
|
92
|
+
name: "fenge/typescript",
|
|
93
|
+
files: ["**/*.{ts,cts,mts,tsx}"],
|
|
94
|
+
languageOptions: {
|
|
95
|
+
...jsConfig.languageOptions,
|
|
96
|
+
parser: tsParser, // Unfortunately parser cannot be a string. Eslint should support it. https://eslint.org/docs/latest/use/configure/configuration-files-new#configuring-a-custom-parser-and-its-options
|
|
97
|
+
parserOptions: {
|
|
98
|
+
...jsConfig.languageOptions.parserOptions,
|
|
99
|
+
tsconfigRootDir: process.cwd(),
|
|
100
|
+
project: project ?? "tsconfig.json",
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
plugins: {
|
|
104
|
+
...jsConfig.plugins,
|
|
105
|
+
deprecation: deprecationPlugin,
|
|
106
|
+
"@fenge-ts": fengeTsPlugin,
|
|
107
|
+
},
|
|
108
|
+
rules: {
|
|
109
|
+
...jsConfig.rules,
|
|
110
|
+
...getTsExtensionRules(),
|
|
111
|
+
|
|
112
|
+
// deprecation
|
|
113
|
+
"deprecation/deprecation": "error",
|
|
114
|
+
// fenge
|
|
115
|
+
"@fenge-ts/exact-map-set-type": "error",
|
|
116
|
+
"@fenge-ts/no-const-enum": "error",
|
|
117
|
+
"@fenge-ts/no-declares-in-ts-file": "error",
|
|
118
|
+
"@fenge-ts/no-export-assignment": "error",
|
|
119
|
+
"@fenge-ts/no-property-decorator": "error",
|
|
120
|
+
"@fenge-ts/no-untyped-empty-array": "error",
|
|
121
|
+
// typescript
|
|
122
|
+
"@typescript-eslint/adjacent-overload-signatures": "error",
|
|
123
|
+
// "@typescript-eslint/array-type": ["error", 'array-simple'], // The default option is 'array'. Not very sure if we need to change the option. So disabled it.
|
|
124
|
+
"@typescript-eslint/await-thenable": "error",
|
|
125
|
+
"@typescript-eslint/ban-types": "error",
|
|
126
|
+
"@typescript-eslint/consistent-generic-constructors": "error",
|
|
127
|
+
"@typescript-eslint/consistent-indexed-object-style": "error",
|
|
128
|
+
"@typescript-eslint/consistent-type-assertions": [
|
|
129
|
+
"error",
|
|
130
|
+
{
|
|
131
|
+
assertionStyle: "as",
|
|
132
|
+
objectLiteralTypeAssertions: "allow-as-parameter",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
"@typescript-eslint/consistent-type-definitions": [
|
|
136
|
+
"error",
|
|
137
|
+
"interface",
|
|
138
|
+
], // TODO should we change to 'type'?
|
|
139
|
+
"@typescript-eslint/consistent-type-exports": "error",
|
|
140
|
+
// "@typescript-eslint/consistent-type-imports": "error,
|
|
141
|
+
"@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
|
|
142
|
+
"@typescript-eslint/method-signature-style": "error",
|
|
143
|
+
"@typescript-eslint/naming-convention": [
|
|
144
|
+
"error",
|
|
145
|
+
{
|
|
146
|
+
selector: "function",
|
|
147
|
+
format: ["camelCase", "PascalCase"],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
selector: "variable",
|
|
151
|
+
types: ["function"],
|
|
152
|
+
format: ["camelCase", "PascalCase"], // decorators need PascalCase
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
selector: "class",
|
|
156
|
+
format: ["PascalCase"],
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
selector: "interface",
|
|
160
|
+
format: ["PascalCase"],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
selector: "typeAlias",
|
|
164
|
+
format: ["PascalCase"],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
selector: "typeParameter",
|
|
168
|
+
format: ["UPPER_CASE", "PascalCase"],
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
"@typescript-eslint/no-array-delete": "error",
|
|
172
|
+
"@typescript-eslint/no-base-to-string": [
|
|
173
|
+
"error",
|
|
174
|
+
{ ignoredTypeNames: [] },
|
|
175
|
+
],
|
|
176
|
+
"@typescript-eslint/no-confusing-non-null-assertion": "error",
|
|
177
|
+
"@typescript-eslint/no-duplicate-enum-values": "error",
|
|
178
|
+
"@typescript-eslint/no-duplicate-type-constituents": "error",
|
|
179
|
+
"@typescript-eslint/no-empty-object-type": "error",
|
|
180
|
+
"@typescript-eslint/no-extra-non-null-assertion": "error",
|
|
181
|
+
"@typescript-eslint/no-floating-promises": [
|
|
182
|
+
"error",
|
|
183
|
+
{
|
|
184
|
+
ignoreVoid: false,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
"@typescript-eslint/no-for-in-array": "error",
|
|
188
|
+
"@typescript-eslint/no-import-type-side-effects": "error",
|
|
189
|
+
"@typescript-eslint/no-inferrable-types": "error",
|
|
190
|
+
"@typescript-eslint/no-misused-new": "error",
|
|
191
|
+
"@typescript-eslint/no-misused-promises": "error",
|
|
192
|
+
"@typescript-eslint/no-mixed-enums": "error",
|
|
193
|
+
"@typescript-eslint/no-namespace": "error",
|
|
194
|
+
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
|
195
|
+
"@typescript-eslint/no-non-null-assertion": "error",
|
|
196
|
+
"@typescript-eslint/no-require-imports": "error",
|
|
197
|
+
"@typescript-eslint/no-this-alias": "error",
|
|
198
|
+
"@typescript-eslint/no-unnecessary-condition": "error",
|
|
199
|
+
"@typescript-eslint/no-unnecessary-parameter-property-assignment":
|
|
200
|
+
"error",
|
|
201
|
+
"@typescript-eslint/no-unnecessary-template-expression": "error", // js also need this rule
|
|
202
|
+
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
|
203
|
+
"@typescript-eslint/no-unnecessary-type-constraint": "error",
|
|
204
|
+
"@typescript-eslint/no-unsafe-declaration-merging": "error",
|
|
205
|
+
// '@typescript-eslint/no-unsafe-function-type': "error",
|
|
206
|
+
// "@typescript-eslint/no-wrapper-object-types": "error",
|
|
207
|
+
"@typescript-eslint/only-throw-error": "error",
|
|
208
|
+
"@typescript-eslint/prefer-as-const": "error",
|
|
209
|
+
"@typescript-eslint/prefer-function-type": "error",
|
|
210
|
+
"@typescript-eslint/prefer-optional-chain": "error",
|
|
211
|
+
"@typescript-eslint/prefer-readonly": "error",
|
|
212
|
+
"@typescript-eslint/prefer-ts-expect-error": "error",
|
|
213
|
+
"@typescript-eslint/restrict-plus-operands": [
|
|
214
|
+
"error",
|
|
215
|
+
{
|
|
216
|
+
// allowAny: false,
|
|
217
|
+
allowBoolean: false,
|
|
218
|
+
allowNullish: false,
|
|
219
|
+
allowNumberAndString: false,
|
|
220
|
+
allowRegExp: false,
|
|
221
|
+
},
|
|
222
|
+
],
|
|
223
|
+
// "@typescript-eslint/restrict-template-expressions": "error",
|
|
224
|
+
"@typescript-eslint/return-await": ["error", "always"],
|
|
225
|
+
"@typescript-eslint/switch-exhaustiveness-check": [
|
|
226
|
+
"error",
|
|
227
|
+
{ requireDefaultForNonUnion: true },
|
|
228
|
+
],
|
|
229
|
+
"@typescript-eslint/unbound-method": "error",
|
|
230
|
+
"@typescript-eslint/unified-signatures": "error",
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
name: "fenge/typescript/config",
|
|
235
|
+
files: ["**/*.config.{ts,cts,mts,tsx}"],
|
|
236
|
+
rules: {
|
|
237
|
+
"import/no-default-export": "off",
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "fenge/typescript/declaration",
|
|
242
|
+
files: ["**/*.d.{ts,cts,mts,tsx}"],
|
|
243
|
+
rules: {
|
|
244
|
+
"import/no-default-export": "off",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
// https://github.com/motemen/minimatch-cheat-sheet
|
|
249
|
+
name: "fenge/typescript/test",
|
|
250
|
+
files: [
|
|
251
|
+
"**/__tests__/**/*.{ts,cts,mts,tsx}",
|
|
252
|
+
"**/*.{test,spec}.{ts,cts,mts,tsx}",
|
|
253
|
+
],
|
|
254
|
+
rules: {
|
|
255
|
+
"@typescript-eslint/no-floating-promises": "off",
|
|
256
|
+
"@typescript-eslint/unbound-method": "off",
|
|
257
|
+
"esm/no-phantom-dep-imports": ["error", { allowDevDependencies: true }],
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
] as const;
|
|
261
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import config from "./eslint.config.js";
|
|
4
|
+
|
|
5
|
+
await describe("eslint.config", async () => {
|
|
6
|
+
await it("length of default export should be 9", () => {
|
|
7
|
+
assert.strictEqual(config.length, 9);
|
|
8
|
+
});
|
|
9
|
+
await it("no warns", () => {
|
|
10
|
+
config.forEach((configItem) => {
|
|
11
|
+
if (
|
|
12
|
+
"rules" in configItem &&
|
|
13
|
+
typeof configItem.rules === "object" &&
|
|
14
|
+
configItem.rules
|
|
15
|
+
) {
|
|
16
|
+
Object.values(configItem.rules).forEach((value) => {
|
|
17
|
+
assert.notStrictEqual(getValueString(value), "warn");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function getValueString(value: unknown): string {
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
return value;
|
|
27
|
+
} else if (Array.isArray(value) && typeof value[0] === "string") {
|
|
28
|
+
return value[0];
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error("unknown value");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { gitignore } from "./config/gitignore.js";
|
|
2
|
+
import { ignore } from "./config/ignore.js";
|
|
3
|
+
import { javascript } from "./config/javascript.js";
|
|
4
|
+
import { packagejson } from "./config/packagejson.js";
|
|
5
|
+
import { typescript } from "./config/typescript.js";
|
|
6
|
+
|
|
7
|
+
type JsRuleKey = keyof ReturnType<typeof javascript>[0]["rules"];
|
|
8
|
+
type TsRuleKey = keyof ReturnType<typeof typescript>[0]["rules"];
|
|
9
|
+
type PkgRuleKey = keyof ReturnType<typeof packagejson>[0]["rules"];
|
|
10
|
+
|
|
11
|
+
interface Options<T extends string> {
|
|
12
|
+
pick?: T[];
|
|
13
|
+
omit?: T[];
|
|
14
|
+
extend?: Record<
|
|
15
|
+
string,
|
|
16
|
+
"error" | "warn" | "off" | ["error" | "warn", ...unknown[]]
|
|
17
|
+
>;
|
|
18
|
+
override?: Partial<
|
|
19
|
+
Record<T, "error" | "warn" | "off" | ["error" | "warn", ...unknown[]]>
|
|
20
|
+
>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class Builder {
|
|
24
|
+
private readonly configs: object[] = [...gitignore(), ...ignore()];
|
|
25
|
+
|
|
26
|
+
toConfig() {
|
|
27
|
+
return this.configs;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private setup(
|
|
31
|
+
[mainConfig, ...otherConfigs]: readonly [
|
|
32
|
+
{ plugins: object; rules: object },
|
|
33
|
+
...object[],
|
|
34
|
+
],
|
|
35
|
+
{ pick, omit, extend = {}, override = {} }: Options<string>,
|
|
36
|
+
) {
|
|
37
|
+
const select = (ruleKey: string) => {
|
|
38
|
+
if (!pick && !omit) {
|
|
39
|
+
return true;
|
|
40
|
+
} else if (pick && !omit) {
|
|
41
|
+
return pick.includes(ruleKey);
|
|
42
|
+
} else if (!pick && omit) {
|
|
43
|
+
return !omit.includes(ruleKey);
|
|
44
|
+
} else {
|
|
45
|
+
throw new Error("You cannot specify both pick and omit");
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const rules = Object.fromEntries(
|
|
49
|
+
Object.entries(mainConfig.rules).filter(([ruleKey]) => select(ruleKey)),
|
|
50
|
+
);
|
|
51
|
+
// check `override` field
|
|
52
|
+
Object.keys(override).forEach((key) => {
|
|
53
|
+
if (!(key in rules)) {
|
|
54
|
+
throw new Error(`The overriding rule key ${key} is not existing.`);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// check `extend` field
|
|
58
|
+
Object.keys(extend).forEach((key) => {
|
|
59
|
+
if (key in rules) {
|
|
60
|
+
throw new Error(`The extending rule key ${key} is already existing.`);
|
|
61
|
+
}
|
|
62
|
+
if (key.includes("/")) {
|
|
63
|
+
const pluginName = key.split("/")[0];
|
|
64
|
+
if (!pluginName)
|
|
65
|
+
throw new Error(`The extending rule key '${key}' is invalid`);
|
|
66
|
+
if (!(pluginName in mainConfig.plugins)) {
|
|
67
|
+
const supportedPlugins = Object.keys(mainConfig.plugins)
|
|
68
|
+
.map((k) => `'${k}'`)
|
|
69
|
+
.join(",");
|
|
70
|
+
throw new Error(
|
|
71
|
+
`The plugin name '${pluginName}' of extending rule key '${key}' is not supported. Only ${supportedPlugins} plugins are supported.`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
this.configs.push(
|
|
77
|
+
{ ...mainConfig, rules: { ...rules, ...override, ...extend } },
|
|
78
|
+
...otherConfigs,
|
|
79
|
+
);
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
enableTypescript(options: Options<TsRuleKey> & { project?: string } = {}) {
|
|
84
|
+
return this.setup(typescript(options.project), options);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
enableJavascript(options: Options<JsRuleKey> = {}) {
|
|
88
|
+
return this.setup(javascript(), options);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
enablePackagejson(options: Options<PkgRuleKey> = {}) {
|
|
92
|
+
return this.setup(packagejson(), options);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default new Builder()
|
|
97
|
+
.enablePackagejson()
|
|
98
|
+
.enableJavascript()
|
|
99
|
+
.enableTypescript()
|
|
100
|
+
.toConfig();
|
package/src/typing.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { describe, it } from "node:test";
|
|
4
|
+
import prettier from "prettier";
|
|
5
|
+
import { javascript } from "../src/config/javascript.js";
|
|
6
|
+
import { typescript } from "../src/config/typescript.js";
|
|
7
|
+
|
|
8
|
+
function count(content: string, substring: string) {
|
|
9
|
+
return (content.match(new RegExp(`"${substring}"`, "g")) ?? []).length;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
await describe("no duplicated", async () => {
|
|
13
|
+
await it("no duplicated js rules is defined", async () => {
|
|
14
|
+
const configContent = await prettier.format(
|
|
15
|
+
(await fs.readFile("./src/config/javascript.ts", "utf-8")).replace(
|
|
16
|
+
"// prettier-ignore",
|
|
17
|
+
"",
|
|
18
|
+
),
|
|
19
|
+
{ parser: "typescript", quoteProps: "consistent" },
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
Object.keys(javascript()[0].rules)
|
|
23
|
+
.filter(
|
|
24
|
+
(rule) =>
|
|
25
|
+
!["import/no-default-export", "esm/no-phantom-dep-imports"].includes(
|
|
26
|
+
rule,
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
.forEach((rule) => {
|
|
30
|
+
assert.strictEqual(count(configContent, rule), 1);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await it("no duplicated ts rules is defined", async () => {
|
|
35
|
+
const configContent = await prettier.format(
|
|
36
|
+
(await fs.readFile("./src/config/typescript.ts", "utf-8")).replace(
|
|
37
|
+
"// prettier-ignore",
|
|
38
|
+
"",
|
|
39
|
+
),
|
|
40
|
+
{ parser: "typescript", quoteProps: "consistent" },
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
typescript()
|
|
44
|
+
.flatMap((c) => Object.keys(c.rules))
|
|
45
|
+
.forEach((rule) => {
|
|
46
|
+
if (
|
|
47
|
+
[
|
|
48
|
+
// "@typescript-eslint/consistent-type-assertions",
|
|
49
|
+
"@typescript-eslint/no-floating-promises",
|
|
50
|
+
// "@typescript-eslint/no-non-null-assertion",
|
|
51
|
+
"@typescript-eslint/unbound-method",
|
|
52
|
+
"import/no-default-export",
|
|
53
|
+
].includes(rule)
|
|
54
|
+
) {
|
|
55
|
+
assert.strictEqual(count(configContent, rule), 2);
|
|
56
|
+
} else {
|
|
57
|
+
assert.strictEqual(count(configContent, rule) <= 1, true);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import prettierConfig from "eslint-config-prettier";
|
|
4
|
+
import { javascript } from "../src/config/javascript.js";
|
|
5
|
+
import { packagejson } from "../src/config/packagejson.js";
|
|
6
|
+
import { typescript } from "../src/config/typescript.js";
|
|
7
|
+
|
|
8
|
+
await describe("prettier", async () => {
|
|
9
|
+
await it("prettier config should be standard", () => {
|
|
10
|
+
const properties = Object.keys(prettierConfig);
|
|
11
|
+
assert.deepStrictEqual(properties, ["rules"]);
|
|
12
|
+
|
|
13
|
+
const ruleValues = [...new Set(Object.values(prettierConfig.rules))];
|
|
14
|
+
assert.strictEqual(ruleValues.length, 2);
|
|
15
|
+
assert.strictEqual(ruleValues.includes(0), true);
|
|
16
|
+
assert.strictEqual(ruleValues.includes("off"), true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
await it("should not have prettier-conflicted rules", () => {
|
|
20
|
+
const included = (rule: string) => rule in prettierConfig.rules;
|
|
21
|
+
|
|
22
|
+
// 1
|
|
23
|
+
const jsForbidRule = Object.keys(javascript()[0].rules).find((rule) =>
|
|
24
|
+
included(rule),
|
|
25
|
+
);
|
|
26
|
+
assert.strictEqual(jsForbidRule, undefined);
|
|
27
|
+
|
|
28
|
+
// 2
|
|
29
|
+
assert.strictEqual(typeof typescript()[0], "object");
|
|
30
|
+
assert.strictEqual(typescript().length, 4);
|
|
31
|
+
const tsForbidRule = typescript()
|
|
32
|
+
.flatMap((config) => Object.keys(config.rules))
|
|
33
|
+
.find((rule) => included(rule));
|
|
34
|
+
assert.strictEqual(tsForbidRule, undefined);
|
|
35
|
+
|
|
36
|
+
// 3
|
|
37
|
+
const packagejsonRule = Object.keys(packagejson()[0].rules).find((rule) =>
|
|
38
|
+
included(rule),
|
|
39
|
+
);
|
|
40
|
+
assert.strictEqual(packagejsonRule, undefined);
|
|
41
|
+
});
|
|
42
|
+
});
|
package/tsconfig.json
ADDED