@blogic-cz/oxc-config 1.1.0 → 1.3.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/.oxlintrc.ts.json +13 -1
- package/package.json +2 -2
- package/plugins/effect-ts.js +70 -0
- package/plugins/effect-ts.ts +107 -0
package/.oxlintrc.ts.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/niconiconainu/oxc/HEAD/npm/oxc-types/src/generated/schema/oxlintrc.json",
|
|
3
3
|
"jsPlugins": [
|
|
4
|
+
"./plugins/effect-ts.js",
|
|
4
5
|
"./plugins/enforce-props-type-name.js",
|
|
5
6
|
"./plugins/max-file-lines.js"
|
|
6
7
|
],
|
|
@@ -30,6 +31,16 @@
|
|
|
30
31
|
"eslint/no-self-compare": "error",
|
|
31
32
|
"eslint/no-template-curly-in-string": "error",
|
|
32
33
|
"eslint/no-var": "error",
|
|
34
|
+
"import/extensions": [
|
|
35
|
+
"error",
|
|
36
|
+
"ignorePackages",
|
|
37
|
+
{
|
|
38
|
+
"js": "never",
|
|
39
|
+
"jsx": "never",
|
|
40
|
+
"ts": "never",
|
|
41
|
+
"tsx": "never"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
33
44
|
"import/no-cycle": "error",
|
|
34
45
|
"import/no-duplicates": "error",
|
|
35
46
|
"import/no-relative-parent-imports": "error",
|
|
@@ -74,7 +85,8 @@
|
|
|
74
85
|
"naming/no-console-in-server": "error",
|
|
75
86
|
"naming/no-dynamic-type-import": "error",
|
|
76
87
|
"naming/no-server-logger-in-client": "error",
|
|
77
|
-
"naming/no-undefined-parameter-union": "error"
|
|
88
|
+
"naming/no-undefined-parameter-union": "error",
|
|
89
|
+
"effect-ts/no-direct-tag-check": "error"
|
|
78
90
|
},
|
|
79
91
|
"overrides": [
|
|
80
92
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blogic-cz/oxc-config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Shared oxlint and oxfmt configs for blogic projects — layered TypeScript, React, and formatter presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oxlint",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"LICENSE"
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
|
-
"build": "bun build plugins/enforce-props-type-name.ts --outdir plugins --outfile enforce-props-type-name.js && bun build plugins/max-file-lines.ts --outdir plugins --outfile max-file-lines.js",
|
|
33
|
+
"build": "bun build plugins/effect-ts.ts --outdir plugins --outfile effect-ts.js && bun build plugins/enforce-props-type-name.ts --outdir plugins --outfile enforce-props-type-name.js && bun build plugins/max-file-lines.ts --outdir plugins --outfile max-file-lines.js",
|
|
34
34
|
"prepublishOnly": "bun run build"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// plugins/effect-ts.ts
|
|
2
|
+
var EFFECT_TAGS = {
|
|
3
|
+
Some: "Use `Option.isSome(value)` or `Option.match(value, { onSome, onNone })`.",
|
|
4
|
+
None: "Use `Option.isNone(value)` or `Option.match(value, { onSome, onNone })`.",
|
|
5
|
+
Left: "Use `Either.isLeft(value)` or `Either.match(value, { onLeft, onRight })`.",
|
|
6
|
+
Right: "Use `Either.isRight(value)` or `Either.match(value, { onLeft, onRight })`.",
|
|
7
|
+
Success: "Use `Exit.isSuccess(value)` or `Exit.match(value, { onSuccess, onFailure })`.",
|
|
8
|
+
Failure: "Use `Exit.isFailure(value)` or `Exit.match(value, { onSuccess, onFailure })`."
|
|
9
|
+
};
|
|
10
|
+
var TAG_PROPERTY = "_tag";
|
|
11
|
+
var isMemberAccessOnTag = (node) => node.type === "MemberExpression" && !node.computed && node.property?.type === "Identifier" && node.property.name === TAG_PROPERTY;
|
|
12
|
+
var isEffectTagLiteral = (node) => {
|
|
13
|
+
if (node.type === "StringLiteral" && typeof node.value === "string") {
|
|
14
|
+
return node.value in EFFECT_TAGS ? node.value : undefined;
|
|
15
|
+
}
|
|
16
|
+
return;
|
|
17
|
+
};
|
|
18
|
+
var plugin = {
|
|
19
|
+
meta: {
|
|
20
|
+
name: "effect-ts"
|
|
21
|
+
},
|
|
22
|
+
rules: {
|
|
23
|
+
"no-direct-tag-check": {
|
|
24
|
+
meta: {
|
|
25
|
+
schema: []
|
|
26
|
+
},
|
|
27
|
+
create(context) {
|
|
28
|
+
return {
|
|
29
|
+
BinaryExpression(node) {
|
|
30
|
+
if (node.operator !== "===" && node.operator !== "!==" && node.operator !== "==" && node.operator !== "!=") {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let tag;
|
|
34
|
+
if (isMemberAccessOnTag(node.left)) {
|
|
35
|
+
tag = isEffectTagLiteral(node.right);
|
|
36
|
+
} else if (isMemberAccessOnTag(node.right)) {
|
|
37
|
+
tag = isEffectTagLiteral(node.left);
|
|
38
|
+
}
|
|
39
|
+
if (tag === undefined) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const hint = EFFECT_TAGS[tag];
|
|
43
|
+
context.report({
|
|
44
|
+
message: `Do not check \`._tag\` directly for "${tag}". ${hint}`,
|
|
45
|
+
node
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
SwitchStatement(node) {
|
|
49
|
+
if (!isMemberAccessOnTag(node.discriminant)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const effectCases = node.cases.filter((c) => c.test && c.test.type === "StringLiteral" && typeof c.test.value === "string" && (c.test.value in EFFECT_TAGS));
|
|
53
|
+
if (effectCases.length === 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const tags = effectCases.map((c) => `"${c.test.value}"`).join(", ");
|
|
57
|
+
context.report({
|
|
58
|
+
message: `Do not switch on \`._tag\` with Effect tags (${tags}). Use the \`.pipe(T.match(...))\` API instead.`,
|
|
59
|
+
node: node.discriminant
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var effect_ts_default = plugin;
|
|
68
|
+
export {
|
|
69
|
+
effect_ts_default as default
|
|
70
|
+
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Plugin } from "#oxlint/plugins";
|
|
2
|
+
|
|
3
|
+
const EFFECT_TAGS: Record<string, string> = {
|
|
4
|
+
Some: 'Use `Option.isSome(value)` or `Option.match(value, { onSome, onNone })`.',
|
|
5
|
+
None: 'Use `Option.isNone(value)` or `Option.match(value, { onSome, onNone })`.',
|
|
6
|
+
Left: 'Use `Either.isLeft(value)` or `Either.match(value, { onLeft, onRight })`.',
|
|
7
|
+
Right: 'Use `Either.isRight(value)` or `Either.match(value, { onLeft, onRight })`.',
|
|
8
|
+
Success: 'Use `Exit.isSuccess(value)` or `Exit.match(value, { onSuccess, onFailure })`.',
|
|
9
|
+
Failure: 'Use `Exit.isFailure(value)` or `Exit.match(value, { onSuccess, onFailure })`.',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const TAG_PROPERTY = "_tag";
|
|
13
|
+
|
|
14
|
+
const isMemberAccessOnTag = (node: {
|
|
15
|
+
type: string;
|
|
16
|
+
property?: { type: string; name?: string };
|
|
17
|
+
computed?: boolean;
|
|
18
|
+
}): boolean =>
|
|
19
|
+
node.type === "MemberExpression" &&
|
|
20
|
+
!node.computed &&
|
|
21
|
+
node.property?.type === "Identifier" &&
|
|
22
|
+
node.property.name === TAG_PROPERTY;
|
|
23
|
+
|
|
24
|
+
const isEffectTagLiteral = (node: {
|
|
25
|
+
type: string;
|
|
26
|
+
value?: unknown;
|
|
27
|
+
}): string | undefined => {
|
|
28
|
+
if (node.type === "StringLiteral" && typeof node.value === "string") {
|
|
29
|
+
return node.value in EFFECT_TAGS ? node.value : undefined;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const plugin: Plugin = {
|
|
35
|
+
meta: {
|
|
36
|
+
name: "effect-ts",
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
"no-direct-tag-check": {
|
|
40
|
+
meta: {
|
|
41
|
+
schema: [],
|
|
42
|
+
},
|
|
43
|
+
create(context) {
|
|
44
|
+
return {
|
|
45
|
+
BinaryExpression(node) {
|
|
46
|
+
if (
|
|
47
|
+
node.operator !== "===" &&
|
|
48
|
+
node.operator !== "!==" &&
|
|
49
|
+
node.operator !== "==" &&
|
|
50
|
+
node.operator !== "!="
|
|
51
|
+
) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let tag: string | undefined;
|
|
56
|
+
|
|
57
|
+
if (isMemberAccessOnTag(node.left)) {
|
|
58
|
+
tag = isEffectTagLiteral(node.right);
|
|
59
|
+
} else if (isMemberAccessOnTag(node.right)) {
|
|
60
|
+
tag = isEffectTagLiteral(node.left);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (tag === undefined) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const hint = EFFECT_TAGS[tag];
|
|
68
|
+
|
|
69
|
+
context.report({
|
|
70
|
+
message: `Do not check \`._tag\` directly for "${tag}". ${hint}`,
|
|
71
|
+
node,
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
SwitchStatement(node) {
|
|
76
|
+
if (!isMemberAccessOnTag(node.discriminant)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const effectCases = node.cases.filter(
|
|
81
|
+
(c) =>
|
|
82
|
+
c.test &&
|
|
83
|
+
c.test.type === "StringLiteral" &&
|
|
84
|
+
typeof c.test.value === "string" &&
|
|
85
|
+
c.test.value in EFFECT_TAGS
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (effectCases.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const tags = effectCases
|
|
93
|
+
.map((c) => `"${c.test!.value}"`)
|
|
94
|
+
.join(", ");
|
|
95
|
+
|
|
96
|
+
context.report({
|
|
97
|
+
message: `Do not switch on \`._tag\` with Effect tags (${tags}). Use the \`.pipe(T.match(...))\` API instead.`,
|
|
98
|
+
node: node.discriminant,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default plugin;
|