@blogic-cz/oxc-config 1.3.0 → 1.4.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/.oxlintrc.ts.json +5 -3
- package/dist/index.d.ts +141 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +381 -0
- package/dist/plugins/effect-ts.d.ts +18 -0
- package/dist/plugins/effect-ts.d.ts.map +1 -0
- package/{plugins → dist/plugins}/effect-ts.js +1 -1
- package/dist/plugins/enforce-props-type-name.d.ts +65 -0
- package/dist/plugins/enforce-props-type-name.d.ts.map +1 -0
- package/{plugins → dist/plugins}/enforce-props-type-name.js +29 -1
- package/dist/plugins/max-file-lines.d.ts +54 -0
- package/dist/plugins/max-file-lines.d.ts.map +1 -0
- package/{plugins → dist/plugins}/max-file-lines.js +5 -3
- package/package.json +54 -4
- package/src/index.ts +22 -0
- package/{plugins → src/plugins}/effect-ts.ts +1 -3
- package/{plugins → src/plugins}/enforce-props-type-name.ts +49 -3
- package/{plugins → src/plugins}/max-file-lines.ts +9 -14
package/.oxlintrc.ts.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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",
|
|
5
|
-
"./plugins/enforce-props-type-name.js",
|
|
6
|
-
"./plugins/max-file-lines.js"
|
|
4
|
+
"./dist/plugins/effect-ts.js",
|
|
5
|
+
"./dist/plugins/enforce-props-type-name.js",
|
|
6
|
+
"./dist/plugins/max-file-lines.js"
|
|
7
7
|
],
|
|
8
8
|
"plugins": [
|
|
9
9
|
"import",
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"naming/no-console-in-server": "error",
|
|
86
86
|
"naming/no-dynamic-type-import": "error",
|
|
87
87
|
"naming/no-server-logger-in-client": "error",
|
|
88
|
+
"naming/no-process-env": "error",
|
|
88
89
|
"naming/no-undefined-parameter-union": "error",
|
|
89
90
|
"effect-ts/no-direct-tag-check": "error"
|
|
90
91
|
},
|
|
@@ -126,6 +127,7 @@
|
|
|
126
127
|
"import/no-relative-parent-imports": "off",
|
|
127
128
|
"naming/enforce-props-type-name": "off",
|
|
128
129
|
"naming/no-default-parameter-values": "off",
|
|
130
|
+
"naming/no-process-env": "off",
|
|
129
131
|
"naming/no-undefined-parameter-union": "off",
|
|
130
132
|
"typescript/no-unsafe-type-assertion": "off",
|
|
131
133
|
"unicorn/no-array-sort": "off"
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import effectTs from "./plugins/effect-ts";
|
|
2
|
+
import enforcePropsTypeName from "./plugins/enforce-props-type-name";
|
|
3
|
+
import maxFileLines from "./plugins/max-file-lines";
|
|
4
|
+
export { effectTs, enforcePropsTypeName, maxFileLines, };
|
|
5
|
+
export declare const oxlintTsConfigPath = "@blogic-cz/oxc-config/oxlint/ts";
|
|
6
|
+
export declare const oxlintTsReactConfigPath = "@blogic-cz/oxc-config/oxlint/ts-react";
|
|
7
|
+
export declare const oxfmtBaseConfigPath = "@blogic-cz/oxc-config/oxfmt/base";
|
|
8
|
+
export declare const oxlintPlugins: {
|
|
9
|
+
effectTs: {
|
|
10
|
+
meta: {
|
|
11
|
+
name: string;
|
|
12
|
+
};
|
|
13
|
+
rules: {
|
|
14
|
+
"no-direct-tag-check": {
|
|
15
|
+
meta: {
|
|
16
|
+
schema: any[];
|
|
17
|
+
};
|
|
18
|
+
create(context: any): {
|
|
19
|
+
BinaryExpression(node: any): void;
|
|
20
|
+
SwitchStatement(node: any): void;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
enforcePropsTypeName: {
|
|
26
|
+
meta: {
|
|
27
|
+
name: string;
|
|
28
|
+
};
|
|
29
|
+
rules: {
|
|
30
|
+
"enforce-props-type-name": {
|
|
31
|
+
meta: {
|
|
32
|
+
schema: any[];
|
|
33
|
+
};
|
|
34
|
+
create(context: any): {
|
|
35
|
+
TSTypeAliasDeclaration(node: any): void;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
"no-dynamic-type-import": {
|
|
39
|
+
meta: {
|
|
40
|
+
schema: any[];
|
|
41
|
+
};
|
|
42
|
+
create(context: any): {
|
|
43
|
+
TSImportType(node: any): void;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
"no-server-logger-in-client": {
|
|
47
|
+
meta: {
|
|
48
|
+
schema: any[];
|
|
49
|
+
};
|
|
50
|
+
create(context: any): {
|
|
51
|
+
ImportDeclaration(node: any): void;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
"no-console-in-server": {
|
|
55
|
+
meta: {
|
|
56
|
+
schema: any[];
|
|
57
|
+
};
|
|
58
|
+
create(context: any): {
|
|
59
|
+
MemberExpression(node: any): void;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
"no-default-parameter-values": {
|
|
63
|
+
meta: {
|
|
64
|
+
schema: any[];
|
|
65
|
+
};
|
|
66
|
+
create(context: any): {
|
|
67
|
+
AssignmentPattern(node: any): void;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
"no-process-env": {
|
|
71
|
+
meta: {
|
|
72
|
+
schema: any[];
|
|
73
|
+
};
|
|
74
|
+
create(context: any): {
|
|
75
|
+
MemberExpression(node: any): void;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
"no-undefined-parameter-union": {
|
|
79
|
+
meta: {
|
|
80
|
+
schema: any[];
|
|
81
|
+
};
|
|
82
|
+
create(context: any): {
|
|
83
|
+
TSUndefinedKeyword(node: any): void;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
maxFileLines: {
|
|
89
|
+
meta: {
|
|
90
|
+
name: string;
|
|
91
|
+
};
|
|
92
|
+
rules: {
|
|
93
|
+
"max-file-lines": {
|
|
94
|
+
meta: {
|
|
95
|
+
defaultOptions: {
|
|
96
|
+
maxLines: number;
|
|
97
|
+
extensions: string[];
|
|
98
|
+
}[];
|
|
99
|
+
schema: {
|
|
100
|
+
type: string;
|
|
101
|
+
default: {};
|
|
102
|
+
properties: {
|
|
103
|
+
maxLines: {
|
|
104
|
+
type: string;
|
|
105
|
+
default: number;
|
|
106
|
+
};
|
|
107
|
+
extensions: {
|
|
108
|
+
type: string;
|
|
109
|
+
items: {
|
|
110
|
+
type: string;
|
|
111
|
+
};
|
|
112
|
+
default: string[];
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
additionalProperties: boolean;
|
|
116
|
+
}[];
|
|
117
|
+
};
|
|
118
|
+
create(context: any): {
|
|
119
|
+
Program(): void;
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
"no-barrel-files": {
|
|
123
|
+
meta: {
|
|
124
|
+
schema: any[];
|
|
125
|
+
};
|
|
126
|
+
create(context: any): {
|
|
127
|
+
Program(node: any): void;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
"kebab-case-filename": {
|
|
131
|
+
meta: {
|
|
132
|
+
schema: any[];
|
|
133
|
+
};
|
|
134
|
+
create(context: any): {
|
|
135
|
+
Program(node: any): void;
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,oBAAoB,MAAM,mCAAmC,CAAC;AACrE,OAAO,YAAY,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EACL,QAAQ,EACR,oBAAoB,EACpB,YAAY,GACb,CAAC;AAEF,eAAO,MAAM,kBAAkB,oCACI,CAAC;AACpC,eAAO,MAAM,uBAAuB,0CACK,CAAC;AAC1C,eAAO,MAAM,mBAAmB,qCACI,CAAC;AAErC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAIzB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
// src/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
|
+
|
|
69
|
+
// src/plugins/enforce-props-type-name.ts
|
|
70
|
+
var isFunctionNode = (type) => type === "FunctionDeclaration" || type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "TSDeclareFunction";
|
|
71
|
+
var plugin2 = {
|
|
72
|
+
meta: {
|
|
73
|
+
name: "naming"
|
|
74
|
+
},
|
|
75
|
+
rules: {
|
|
76
|
+
"enforce-props-type-name": {
|
|
77
|
+
meta: {
|
|
78
|
+
schema: []
|
|
79
|
+
},
|
|
80
|
+
create(context) {
|
|
81
|
+
return {
|
|
82
|
+
TSTypeAliasDeclaration(node) {
|
|
83
|
+
if (!context.filename.endsWith(".tsx")) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const name = node.id.name;
|
|
87
|
+
if (name.endsWith("Props") && name !== "Props") {
|
|
88
|
+
context.report({
|
|
89
|
+
message: `Props type must be named "Props", not "${name}". Use \`type Props = { ... }\` instead.`,
|
|
90
|
+
node: node.id
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"no-dynamic-type-import": {
|
|
98
|
+
meta: {
|
|
99
|
+
schema: []
|
|
100
|
+
},
|
|
101
|
+
create(context) {
|
|
102
|
+
return {
|
|
103
|
+
TSImportType(node) {
|
|
104
|
+
context.report({
|
|
105
|
+
message: 'Use regular `import type` instead of dynamic `import("...")` type syntax.',
|
|
106
|
+
node
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"no-server-logger-in-client": {
|
|
113
|
+
meta: {
|
|
114
|
+
schema: []
|
|
115
|
+
},
|
|
116
|
+
create(context) {
|
|
117
|
+
return {
|
|
118
|
+
ImportDeclaration(node) {
|
|
119
|
+
const source = node.source.value;
|
|
120
|
+
if ((source.endsWith("/logger") || source === "pino") && context.filename.endsWith(".tsx")) {
|
|
121
|
+
context.report({
|
|
122
|
+
message: `Do not import "${source}" in client-side (.tsx) files. Use console.log/console.error instead.`,
|
|
123
|
+
node
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"no-console-in-server": {
|
|
131
|
+
meta: {
|
|
132
|
+
schema: []
|
|
133
|
+
},
|
|
134
|
+
create(context) {
|
|
135
|
+
return {
|
|
136
|
+
MemberExpression(node) {
|
|
137
|
+
const filename = context.filename;
|
|
138
|
+
const isServerFile = filename.endsWith(".ts") && !filename.endsWith(".tsx");
|
|
139
|
+
const isWebAppServer = filename.includes("apps/web-app/src/");
|
|
140
|
+
const isExcluded = filename.includes(".test.ts") || filename.includes("/jobs/") || filename.includes("/scripts/");
|
|
141
|
+
if (isServerFile && isWebAppServer && !isExcluded && node.object.type === "Identifier" && node.object.name === "console") {
|
|
142
|
+
context.report({
|
|
143
|
+
message: "Do not use console.* in server-side code. Use the project logger package instead.",
|
|
144
|
+
node
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
"no-default-parameter-values": {
|
|
152
|
+
meta: {
|
|
153
|
+
schema: []
|
|
154
|
+
},
|
|
155
|
+
create(context) {
|
|
156
|
+
return {
|
|
157
|
+
AssignmentPattern(node) {
|
|
158
|
+
const parentType = node.parent.type;
|
|
159
|
+
const isFunctionParamDefault = parentType === "FunctionDeclaration" || parentType === "FunctionExpression" || parentType === "ArrowFunctionExpression" || parentType === "TSParameterProperty";
|
|
160
|
+
if (!isFunctionParamDefault) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
context.report({
|
|
164
|
+
message: "Default parameter values are not allowed. Require the caller to pass the value explicitly.",
|
|
165
|
+
node
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"no-process-env": {
|
|
172
|
+
meta: {
|
|
173
|
+
schema: []
|
|
174
|
+
},
|
|
175
|
+
create(context) {
|
|
176
|
+
return {
|
|
177
|
+
MemberExpression(node) {
|
|
178
|
+
if (node.object.type !== "Identifier" || node.object.name !== "process") {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const isEnvAccess = !node.computed && node.property.type === "Identifier" && node.property.name === "env" || node.computed && node.property.type === "StringLiteral" && node.property.value === "env";
|
|
182
|
+
if (!isEnvAccess) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const filename = context.filename;
|
|
186
|
+
const parts = filename.split("/");
|
|
187
|
+
const basename = parts.at(-1) ?? "";
|
|
188
|
+
if (basename === "env.ts" || basename.startsWith("env.") || basename === "public-env.ts" || parts.includes("env")) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
context.report({
|
|
192
|
+
message: 'Do not access `process.env` directly. Import the typed `env` object from the env module instead (e.g., `import { env } from "@/env/env.server"`).',
|
|
193
|
+
node
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"no-undefined-parameter-union": {
|
|
200
|
+
meta: {
|
|
201
|
+
schema: []
|
|
202
|
+
},
|
|
203
|
+
create(context) {
|
|
204
|
+
return {
|
|
205
|
+
TSUndefinedKeyword(node) {
|
|
206
|
+
if (node.parent.type !== "TSUnionType") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (node.parent.parent.type !== "TSTypeAnnotation") {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const annotationTarget = node.parent.parent.parent;
|
|
213
|
+
const parentType = annotationTarget.parent.type;
|
|
214
|
+
const isDirectFunctionParam = parentType && isFunctionNode(parentType);
|
|
215
|
+
const isTsParameterProperty = annotationTarget.type === "Identifier" && parentType === "TSParameterProperty" && annotationTarget.parent.parent.type === "FunctionExpression" && annotationTarget.parent.parent.parent.type === "MethodDefinition";
|
|
216
|
+
if (!isDirectFunctionParam && !isTsParameterProperty) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
context.report({
|
|
220
|
+
message: "Avoid `| undefined` in parameter types. Use explicit `| null` (or an optional parameter when intended).",
|
|
221
|
+
node
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
var enforce_props_type_name_default = plugin2;
|
|
230
|
+
|
|
231
|
+
// src/plugins/max-file-lines.ts
|
|
232
|
+
function parseOptions(value) {
|
|
233
|
+
if (typeof value !== "object" || value === null) {
|
|
234
|
+
return { maxLines: 500, extensions: [".tsx"] };
|
|
235
|
+
}
|
|
236
|
+
const maxLinesValue = "maxLines" in value ? value.maxLines : undefined;
|
|
237
|
+
const maxLines = typeof maxLinesValue === "number" ? maxLinesValue : 500;
|
|
238
|
+
const extensionsValue = "extensions" in value ? value.extensions : undefined;
|
|
239
|
+
const extensions = Array.isArray(extensionsValue) ? extensionsValue.filter((extension) => typeof extension === "string") : [".tsx"];
|
|
240
|
+
return {
|
|
241
|
+
maxLines,
|
|
242
|
+
extensions: extensions.length > 0 ? extensions : [".tsx"]
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
var plugin3 = {
|
|
246
|
+
meta: {
|
|
247
|
+
name: "file-quality"
|
|
248
|
+
},
|
|
249
|
+
rules: {
|
|
250
|
+
"max-file-lines": {
|
|
251
|
+
meta: {
|
|
252
|
+
defaultOptions: [
|
|
253
|
+
{
|
|
254
|
+
maxLines: 500,
|
|
255
|
+
extensions: [".tsx"]
|
|
256
|
+
}
|
|
257
|
+
],
|
|
258
|
+
schema: [
|
|
259
|
+
{
|
|
260
|
+
type: "object",
|
|
261
|
+
default: {},
|
|
262
|
+
properties: {
|
|
263
|
+
maxLines: { type: "number", default: 500 },
|
|
264
|
+
extensions: {
|
|
265
|
+
type: "array",
|
|
266
|
+
items: { type: "string" },
|
|
267
|
+
default: [".tsx"]
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
additionalProperties: false
|
|
271
|
+
}
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
create(context) {
|
|
275
|
+
return {
|
|
276
|
+
Program() {
|
|
277
|
+
const options = parseOptions(context.options[0]);
|
|
278
|
+
const { maxLines, extensions } = options;
|
|
279
|
+
if (!extensions.some((ext) => context.filename.endsWith(ext))) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const lineCount = context.sourceCode.lines.length;
|
|
283
|
+
if (lineCount <= maxLines) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
context.report({
|
|
287
|
+
message: `File has ${lineCount} lines (max ${maxLines}). Consider splitting into smaller modules.`,
|
|
288
|
+
node: context.sourceCode.ast
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
"no-barrel-files": {
|
|
295
|
+
meta: {
|
|
296
|
+
schema: []
|
|
297
|
+
},
|
|
298
|
+
create(context) {
|
|
299
|
+
return {
|
|
300
|
+
Program(node) {
|
|
301
|
+
const filename = context.filename;
|
|
302
|
+
if (!filename.endsWith("/index.ts")) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (/packages\/[^/]+\/src\//.test(filename)) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const body = node.body;
|
|
309
|
+
if (body.length === 0) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const isBarrel = body.every((stmt) => stmt.type === "ExportNamedDeclaration" && stmt.source !== null || stmt.type === "ExportAllDeclaration" || stmt.type === "ImportDeclaration");
|
|
313
|
+
if (isBarrel) {
|
|
314
|
+
context.report({
|
|
315
|
+
message: "Barrel files (index.ts with only re-exports) are not allowed. Import directly from source files.",
|
|
316
|
+
node
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"kebab-case-filename": {
|
|
324
|
+
meta: {
|
|
325
|
+
schema: []
|
|
326
|
+
},
|
|
327
|
+
create(context) {
|
|
328
|
+
return {
|
|
329
|
+
Program(node) {
|
|
330
|
+
const filename = context.filename;
|
|
331
|
+
if (filename.includes("node_modules") || filename.endsWith(".d.ts")) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const parts = filename.split("/");
|
|
335
|
+
const basename = parts.at(-1);
|
|
336
|
+
if (!basename) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (basename.includes("$") || basename.includes("[") || basename.includes("]")) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const nameWithoutExt = basename.replace(/\.(test|e2e|server|client|config)\.(ts|tsx|js|jsx|mjs|cjs)$/, "").replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
343
|
+
if (nameWithoutExt === "") {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (nameWithoutExt === "routeTree.gen" || nameWithoutExt === "Dockerfile" || nameWithoutExt.startsWith("__") || nameWithoutExt.endsWith(".gen") || nameWithoutExt === "vite-env") {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const kebabRegex = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
350
|
+
if (!kebabRegex.test(nameWithoutExt)) {
|
|
351
|
+
context.report({
|
|
352
|
+
message: `Filename "${basename}" must use kebab-case (e.g., "my-component.tsx").`,
|
|
353
|
+
node
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
var max_file_lines_default = plugin3;
|
|
363
|
+
|
|
364
|
+
// src/index.ts
|
|
365
|
+
var oxlintTsConfigPath = "@blogic-cz/oxc-config/oxlint/ts";
|
|
366
|
+
var oxlintTsReactConfigPath = "@blogic-cz/oxc-config/oxlint/ts-react";
|
|
367
|
+
var oxfmtBaseConfigPath = "@blogic-cz/oxc-config/oxfmt/base";
|
|
368
|
+
var oxlintPlugins = {
|
|
369
|
+
effectTs: effect_ts_default,
|
|
370
|
+
enforcePropsTypeName: enforce_props_type_name_default,
|
|
371
|
+
maxFileLines: max_file_lines_default
|
|
372
|
+
};
|
|
373
|
+
export {
|
|
374
|
+
oxlintTsReactConfigPath,
|
|
375
|
+
oxlintTsConfigPath,
|
|
376
|
+
oxlintPlugins,
|
|
377
|
+
oxfmtBaseConfigPath,
|
|
378
|
+
max_file_lines_default as maxFileLines,
|
|
379
|
+
enforce_props_type_name_default as enforcePropsTypeName,
|
|
380
|
+
effect_ts_default as effectTs
|
|
381
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
declare const plugin: {
|
|
2
|
+
meta: {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
rules: {
|
|
6
|
+
"no-direct-tag-check": {
|
|
7
|
+
meta: {
|
|
8
|
+
schema: any[];
|
|
9
|
+
};
|
|
10
|
+
create(context: any): {
|
|
11
|
+
BinaryExpression(node: any): void;
|
|
12
|
+
SwitchStatement(node: any): void;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export default plugin;
|
|
18
|
+
//# sourceMappingURL=effect-ts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-ts.d.ts","sourceRoot":"","sources":["../../src/plugins/effect-ts.ts"],"names":[],"mappings":"AA+BA,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;CAuEX,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
declare const plugin: {
|
|
2
|
+
meta: {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
rules: {
|
|
6
|
+
"enforce-props-type-name": {
|
|
7
|
+
meta: {
|
|
8
|
+
schema: any[];
|
|
9
|
+
};
|
|
10
|
+
create(context: any): {
|
|
11
|
+
TSTypeAliasDeclaration(node: any): void;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
"no-dynamic-type-import": {
|
|
15
|
+
meta: {
|
|
16
|
+
schema: any[];
|
|
17
|
+
};
|
|
18
|
+
create(context: any): {
|
|
19
|
+
TSImportType(node: any): void;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
"no-server-logger-in-client": {
|
|
23
|
+
meta: {
|
|
24
|
+
schema: any[];
|
|
25
|
+
};
|
|
26
|
+
create(context: any): {
|
|
27
|
+
ImportDeclaration(node: any): void;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
"no-console-in-server": {
|
|
31
|
+
meta: {
|
|
32
|
+
schema: any[];
|
|
33
|
+
};
|
|
34
|
+
create(context: any): {
|
|
35
|
+
MemberExpression(node: any): void;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
"no-default-parameter-values": {
|
|
39
|
+
meta: {
|
|
40
|
+
schema: any[];
|
|
41
|
+
};
|
|
42
|
+
create(context: any): {
|
|
43
|
+
AssignmentPattern(node: any): void;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
"no-process-env": {
|
|
47
|
+
meta: {
|
|
48
|
+
schema: any[];
|
|
49
|
+
};
|
|
50
|
+
create(context: any): {
|
|
51
|
+
MemberExpression(node: any): void;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
"no-undefined-parameter-union": {
|
|
55
|
+
meta: {
|
|
56
|
+
schema: any[];
|
|
57
|
+
};
|
|
58
|
+
create(context: any): {
|
|
59
|
+
TSUndefinedKeyword(node: any): void;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export default plugin;
|
|
65
|
+
//# sourceMappingURL=enforce-props-type-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enforce-props-type-name.d.ts","sourceRoot":"","sources":["../../src/plugins/enforce-props-type-name.ts"],"names":[],"mappings":"AAMA,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqOX,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// plugins/enforce-props-type-name.ts
|
|
1
|
+
// src/plugins/enforce-props-type-name.ts
|
|
2
2
|
var isFunctionNode = (type) => type === "FunctionDeclaration" || type === "FunctionExpression" || type === "ArrowFunctionExpression" || type === "TSDeclareFunction";
|
|
3
3
|
var plugin = {
|
|
4
4
|
meta: {
|
|
@@ -100,6 +100,34 @@ var plugin = {
|
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
+
"no-process-env": {
|
|
104
|
+
meta: {
|
|
105
|
+
schema: []
|
|
106
|
+
},
|
|
107
|
+
create(context) {
|
|
108
|
+
return {
|
|
109
|
+
MemberExpression(node) {
|
|
110
|
+
if (node.object.type !== "Identifier" || node.object.name !== "process") {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const isEnvAccess = !node.computed && node.property.type === "Identifier" && node.property.name === "env" || node.computed && node.property.type === "StringLiteral" && node.property.value === "env";
|
|
114
|
+
if (!isEnvAccess) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const filename = context.filename;
|
|
118
|
+
const parts = filename.split("/");
|
|
119
|
+
const basename = parts.at(-1) ?? "";
|
|
120
|
+
if (basename === "env.ts" || basename.startsWith("env.") || basename === "public-env.ts" || parts.includes("env")) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
context.report({
|
|
124
|
+
message: 'Do not access `process.env` directly. Import the typed `env` object from the env module instead (e.g., `import { env } from "@/env/env.server"`).',
|
|
125
|
+
node
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
},
|
|
103
131
|
"no-undefined-parameter-union": {
|
|
104
132
|
meta: {
|
|
105
133
|
schema: []
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
declare const plugin: {
|
|
2
|
+
meta: {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
5
|
+
rules: {
|
|
6
|
+
"max-file-lines": {
|
|
7
|
+
meta: {
|
|
8
|
+
defaultOptions: {
|
|
9
|
+
maxLines: number;
|
|
10
|
+
extensions: string[];
|
|
11
|
+
}[];
|
|
12
|
+
schema: {
|
|
13
|
+
type: string;
|
|
14
|
+
default: {};
|
|
15
|
+
properties: {
|
|
16
|
+
maxLines: {
|
|
17
|
+
type: string;
|
|
18
|
+
default: number;
|
|
19
|
+
};
|
|
20
|
+
extensions: {
|
|
21
|
+
type: string;
|
|
22
|
+
items: {
|
|
23
|
+
type: string;
|
|
24
|
+
};
|
|
25
|
+
default: string[];
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
additionalProperties: boolean;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
|
31
|
+
create(context: any): {
|
|
32
|
+
Program(): void;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
"no-barrel-files": {
|
|
36
|
+
meta: {
|
|
37
|
+
schema: any[];
|
|
38
|
+
};
|
|
39
|
+
create(context: any): {
|
|
40
|
+
Program(node: any): void;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
"kebab-case-filename": {
|
|
44
|
+
meta: {
|
|
45
|
+
schema: any[];
|
|
46
|
+
};
|
|
47
|
+
create(context: any): {
|
|
48
|
+
Program(node: any): void;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export default plugin;
|
|
54
|
+
//# sourceMappingURL=max-file-lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-file-lines.d.ts","sourceRoot":"","sources":["../../src/plugins/max-file-lines.ts"],"names":[],"mappings":"AA6BA,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoKX,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
// plugins/max-file-lines.ts
|
|
1
|
+
// src/plugins/max-file-lines.ts
|
|
2
2
|
function parseOptions(value) {
|
|
3
3
|
if (typeof value !== "object" || value === null) {
|
|
4
4
|
return { maxLines: 500, extensions: [".tsx"] };
|
|
5
5
|
}
|
|
6
|
-
const
|
|
7
|
-
const
|
|
6
|
+
const maxLinesValue = "maxLines" in value ? value.maxLines : undefined;
|
|
7
|
+
const maxLines = typeof maxLinesValue === "number" ? maxLinesValue : 500;
|
|
8
|
+
const extensionsValue = "extensions" in value ? value.extensions : undefined;
|
|
9
|
+
const extensions = Array.isArray(extensionsValue) ? extensionsValue.filter((extension) => typeof extension === "string") : [".tsx"];
|
|
8
10
|
return {
|
|
9
11
|
maxLines,
|
|
10
12
|
extensions: extensions.length > 0 ? extensions : [".tsx"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blogic-cz/oxc-config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Shared oxlint and oxfmt configs for blogic projects — layered TypeScript, React, and formatter presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oxlint",
|
|
@@ -20,19 +20,69 @@
|
|
|
20
20
|
"type": "git",
|
|
21
21
|
"url": "https://github.com/blogic-cz/oxc-config.git"
|
|
22
22
|
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"import": "./dist/index.js",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./plugins/effect-ts": {
|
|
33
|
+
"types": "./dist/plugins/effect-ts.d.ts",
|
|
34
|
+
"import": "./dist/plugins/effect-ts.js",
|
|
35
|
+
"default": "./dist/plugins/effect-ts.js"
|
|
36
|
+
},
|
|
37
|
+
"./plugins/effect-ts.js": {
|
|
38
|
+
"types": "./dist/plugins/effect-ts.d.ts",
|
|
39
|
+
"import": "./dist/plugins/effect-ts.js",
|
|
40
|
+
"default": "./dist/plugins/effect-ts.js"
|
|
41
|
+
},
|
|
42
|
+
"./plugins/enforce-props-type-name": {
|
|
43
|
+
"types": "./dist/plugins/enforce-props-type-name.d.ts",
|
|
44
|
+
"import": "./dist/plugins/enforce-props-type-name.js",
|
|
45
|
+
"default": "./dist/plugins/enforce-props-type-name.js"
|
|
46
|
+
},
|
|
47
|
+
"./plugins/enforce-props-type-name.js": {
|
|
48
|
+
"types": "./dist/plugins/enforce-props-type-name.d.ts",
|
|
49
|
+
"import": "./dist/plugins/enforce-props-type-name.js",
|
|
50
|
+
"default": "./dist/plugins/enforce-props-type-name.js"
|
|
51
|
+
},
|
|
52
|
+
"./plugins/max-file-lines": {
|
|
53
|
+
"types": "./dist/plugins/max-file-lines.d.ts",
|
|
54
|
+
"import": "./dist/plugins/max-file-lines.js",
|
|
55
|
+
"default": "./dist/plugins/max-file-lines.js"
|
|
56
|
+
},
|
|
57
|
+
"./plugins/max-file-lines.js": {
|
|
58
|
+
"types": "./dist/plugins/max-file-lines.d.ts",
|
|
59
|
+
"import": "./dist/plugins/max-file-lines.js",
|
|
60
|
+
"default": "./dist/plugins/max-file-lines.js"
|
|
61
|
+
},
|
|
62
|
+
"./oxlint/ts": "./.oxlintrc.ts.json",
|
|
63
|
+
"./oxlint/ts-react": "./.oxlintrc.ts-react.json",
|
|
64
|
+
"./oxfmt/base": "./.oxfmtrc.base.jsonc",
|
|
65
|
+
"./package.json": "./package.json"
|
|
66
|
+
},
|
|
23
67
|
"files": [
|
|
68
|
+
"dist",
|
|
69
|
+
"src",
|
|
24
70
|
".oxlintrc.ts.json",
|
|
25
71
|
".oxlintrc.ts-react.json",
|
|
26
72
|
".oxfmtrc.base.jsonc",
|
|
27
|
-
"plugins/*.js",
|
|
28
|
-
"plugins/*.ts",
|
|
29
73
|
"README.md",
|
|
30
74
|
"LICENSE"
|
|
31
75
|
],
|
|
32
76
|
"scripts": {
|
|
33
|
-
"
|
|
77
|
+
"clean": "rm -rf dist",
|
|
78
|
+
"build:js": "bun run clean && bun build src/index.ts --outdir dist && bun build src/plugins/effect-ts.ts --outdir dist/plugins --outfile effect-ts.js && bun build src/plugins/enforce-props-type-name.ts --outdir dist/plugins --outfile enforce-props-type-name.js && bun build src/plugins/max-file-lines.ts --outdir dist/plugins --outfile max-file-lines.js",
|
|
79
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
80
|
+
"build": "bun run build:js && bun run build:types",
|
|
34
81
|
"prepublishOnly": "bun run build"
|
|
35
82
|
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"typescript": "5.9.3"
|
|
85
|
+
},
|
|
36
86
|
"publishConfig": {
|
|
37
87
|
"access": "public"
|
|
38
88
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import effectTs from "./plugins/effect-ts";
|
|
2
|
+
import enforcePropsTypeName from "./plugins/enforce-props-type-name";
|
|
3
|
+
import maxFileLines from "./plugins/max-file-lines";
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
effectTs,
|
|
7
|
+
enforcePropsTypeName,
|
|
8
|
+
maxFileLines,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const oxlintTsConfigPath =
|
|
12
|
+
"@blogic-cz/oxc-config/oxlint/ts";
|
|
13
|
+
export const oxlintTsReactConfigPath =
|
|
14
|
+
"@blogic-cz/oxc-config/oxlint/ts-react";
|
|
15
|
+
export const oxfmtBaseConfigPath =
|
|
16
|
+
"@blogic-cz/oxc-config/oxfmt/base";
|
|
17
|
+
|
|
18
|
+
export const oxlintPlugins = {
|
|
19
|
+
effectTs,
|
|
20
|
+
enforcePropsTypeName,
|
|
21
|
+
maxFileLines,
|
|
22
|
+
};
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Plugin } from "#oxlint/plugins";
|
|
2
|
-
|
|
3
1
|
const EFFECT_TAGS: Record<string, string> = {
|
|
4
2
|
Some: 'Use `Option.isSome(value)` or `Option.match(value, { onSome, onNone })`.',
|
|
5
3
|
None: 'Use `Option.isNone(value)` or `Option.match(value, { onSome, onNone })`.',
|
|
@@ -31,7 +29,7 @@ const isEffectTagLiteral = (node: {
|
|
|
31
29
|
return undefined;
|
|
32
30
|
};
|
|
33
31
|
|
|
34
|
-
const plugin
|
|
32
|
+
const plugin = {
|
|
35
33
|
meta: {
|
|
36
34
|
name: "effect-ts",
|
|
37
35
|
},
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import type { Plugin } from "#oxlint/plugins";
|
|
2
|
-
|
|
3
1
|
const isFunctionNode = (type: string): boolean =>
|
|
4
2
|
type === "FunctionDeclaration" ||
|
|
5
3
|
type === "FunctionExpression" ||
|
|
6
4
|
type === "ArrowFunctionExpression" ||
|
|
7
5
|
type === "TSDeclareFunction";
|
|
8
6
|
|
|
9
|
-
const plugin
|
|
7
|
+
const plugin = {
|
|
10
8
|
meta: {
|
|
11
9
|
name: "naming",
|
|
12
10
|
},
|
|
@@ -138,6 +136,54 @@ const plugin: Plugin = {
|
|
|
138
136
|
};
|
|
139
137
|
},
|
|
140
138
|
},
|
|
139
|
+
"no-process-env": {
|
|
140
|
+
meta: {
|
|
141
|
+
schema: [],
|
|
142
|
+
},
|
|
143
|
+
create(context) {
|
|
144
|
+
return {
|
|
145
|
+
MemberExpression(node) {
|
|
146
|
+
if (
|
|
147
|
+
node.object.type !== "Identifier" ||
|
|
148
|
+
node.object.name !== "process"
|
|
149
|
+
) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const isEnvAccess =
|
|
154
|
+
(!node.computed &&
|
|
155
|
+
node.property.type === "Identifier" &&
|
|
156
|
+
node.property.name === "env") ||
|
|
157
|
+
(node.computed &&
|
|
158
|
+
node.property.type === "StringLiteral" &&
|
|
159
|
+
node.property.value === "env");
|
|
160
|
+
|
|
161
|
+
if (!isEnvAccess) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const filename = context.filename;
|
|
166
|
+
const parts = filename.split("/");
|
|
167
|
+
const basename = parts.at(-1) ?? "";
|
|
168
|
+
|
|
169
|
+
if (
|
|
170
|
+
basename === "env.ts" ||
|
|
171
|
+
basename.startsWith("env.") ||
|
|
172
|
+
basename === "public-env.ts" ||
|
|
173
|
+
parts.includes("env")
|
|
174
|
+
) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
context.report({
|
|
179
|
+
message:
|
|
180
|
+
'Do not access `process.env` directly. Import the typed `env` object from the env module instead (e.g., `import { env } from "@/env/env.server"`).',
|
|
181
|
+
node,
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
},
|
|
141
187
|
"no-undefined-parameter-union": {
|
|
142
188
|
meta: {
|
|
143
189
|
schema: [],
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { Plugin } from "#oxlint/plugins";
|
|
2
|
-
|
|
3
1
|
function parseOptions(value: unknown): {
|
|
4
2
|
maxLines: number;
|
|
5
3
|
extensions: string[];
|
|
@@ -8,12 +6,16 @@ function parseOptions(value: unknown): {
|
|
|
8
6
|
return { maxLines: 500, extensions: [".tsx"] };
|
|
9
7
|
}
|
|
10
8
|
|
|
9
|
+
const maxLinesValue =
|
|
10
|
+
"maxLines" in value ? value.maxLines : undefined;
|
|
11
11
|
const maxLines =
|
|
12
|
-
typeof
|
|
13
|
-
?
|
|
12
|
+
typeof maxLinesValue === "number"
|
|
13
|
+
? maxLinesValue
|
|
14
14
|
: 500;
|
|
15
|
-
const
|
|
16
|
-
? value.extensions
|
|
15
|
+
const extensionsValue =
|
|
16
|
+
"extensions" in value ? value.extensions : undefined;
|
|
17
|
+
const extensions = Array.isArray(extensionsValue)
|
|
18
|
+
? extensionsValue.filter(
|
|
17
19
|
(extension) => typeof extension === "string"
|
|
18
20
|
)
|
|
19
21
|
: [".tsx"];
|
|
@@ -25,7 +27,7 @@ function parseOptions(value: unknown): {
|
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
const plugin
|
|
30
|
+
const plugin = {
|
|
29
31
|
meta: {
|
|
30
32
|
name: "file-quality",
|
|
31
33
|
},
|
|
@@ -93,12 +95,10 @@ const plugin: Plugin = {
|
|
|
93
95
|
Program(node) {
|
|
94
96
|
const filename = context.filename;
|
|
95
97
|
|
|
96
|
-
// Only check index.ts files (not .tsx — route files are OK)
|
|
97
98
|
if (!filename.endsWith("/index.ts")) {
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
// Exception: any index.ts inside packages/ (root and sub-path entry points)
|
|
102
102
|
if (/packages\/[^/]+\/src\//.test(filename)) {
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
@@ -136,7 +136,6 @@ const plugin: Plugin = {
|
|
|
136
136
|
Program(node) {
|
|
137
137
|
const filename = context.filename;
|
|
138
138
|
|
|
139
|
-
// Skip node_modules and .d.ts files
|
|
140
139
|
if (
|
|
141
140
|
filename.includes("node_modules") ||
|
|
142
141
|
filename.endsWith(".d.ts")
|
|
@@ -150,7 +149,6 @@ const plugin: Plugin = {
|
|
|
150
149
|
return;
|
|
151
150
|
}
|
|
152
151
|
|
|
153
|
-
// Skip TanStack Router dynamic segments ($param, $, [param])
|
|
154
152
|
if (
|
|
155
153
|
basename.includes("$") ||
|
|
156
154
|
basename.includes("[") ||
|
|
@@ -159,7 +157,6 @@ const plugin: Plugin = {
|
|
|
159
157
|
return;
|
|
160
158
|
}
|
|
161
159
|
|
|
162
|
-
// Strip compound extensions first, then simple
|
|
163
160
|
const nameWithoutExt = basename
|
|
164
161
|
.replace(
|
|
165
162
|
/\.(test|e2e|server|client|config)\.(ts|tsx|js|jsx|mjs|cjs)$/,
|
|
@@ -167,12 +164,10 @@ const plugin: Plugin = {
|
|
|
167
164
|
)
|
|
168
165
|
.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
169
166
|
|
|
170
|
-
// Skip empty names (e.g., just an extension)
|
|
171
167
|
if (nameWithoutExt === "") {
|
|
172
168
|
return;
|
|
173
169
|
}
|
|
174
170
|
|
|
175
|
-
// Skip known special files
|
|
176
171
|
if (
|
|
177
172
|
nameWithoutExt === "routeTree.gen" ||
|
|
178
173
|
nameWithoutExt === "Dockerfile" ||
|