@imranbarbhuiya/oxc-config 0.1.9 → 0.1.11
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/cli/index.d.ts +1 -1
- package/dist/cli/index.js +78 -66
- package/dist/cli/index.js.map +1 -1
- package/dist/common.js +4 -25
- package/dist/common.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/nest.js +2 -2
- package/dist/nest.js.map +1 -1
- package/dist/node.js +0 -7
- package/dist/node.js.map +1 -1
- package/dist/plugins/api-error.d.ts +2 -3
- package/dist/plugins/api-error.js +144 -135
- package/dist/plugins/api-error.js.map +1 -1
- package/dist/plugins/central-icons.d.ts +2 -3
- package/dist/plugins/central-icons.js +45 -47
- package/dist/plugins/central-icons.js.map +1 -1
- package/dist/plugins/i18n.d.ts +2 -3
- package/dist/plugins/i18n.js +46 -49
- package/dist/plugins/i18n.js.map +1 -1
- package/dist/plugins/native-tailwind.d.ts +2 -3
- package/dist/plugins/native-tailwind.js +93 -95
- package/dist/plugins/native-tailwind.js.map +1 -1
- package/dist/plugins/nest.d.ts +2 -3
- package/dist/plugins/nest.js +32 -27
- package/dist/plugins/nest.js.map +1 -1
- package/dist/plugins/restricted-syntax.d.ts +5 -0
- package/dist/plugins/restricted-syntax.js +115 -0
- package/dist/plugins/restricted-syntax.js.map +1 -0
- package/dist/typescript.js +9 -14
- package/dist/typescript.js.map +1 -1
- package/package.json +62 -64
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { definePlugin, defineRule } from "@oxlint/plugins";
|
|
2
|
+
|
|
1
3
|
//#region src/plugins/api-error.ts
|
|
2
4
|
const DEFAULT_ALLOWED_ERRORS = ["ApiError", "FormValidationError"];
|
|
3
5
|
function getStaticFactoryCallee(arg) {
|
|
@@ -14,156 +16,163 @@ function getStaticFactoryCallee(arg) {
|
|
|
14
16
|
function isAstNode(value) {
|
|
15
17
|
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
16
18
|
}
|
|
17
|
-
const
|
|
19
|
+
const requireApiError = defineRule({
|
|
18
20
|
meta: {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}],
|
|
39
|
-
messages: {
|
|
40
|
-
useApiError: "Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `new {{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.",
|
|
41
|
-
useApiErrorCall: "Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `{{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.",
|
|
42
|
-
useApiErrorMember: "Throw `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of re-throwing `{{thrown}}` directly inside {{fnType}}. The client error object may lose its HTTP status code in QueryCache/retry/error reporting."
|
|
43
|
-
}
|
|
21
|
+
type: "problem",
|
|
22
|
+
docs: { description: "Require an allowed API error instead of Error inside queryFn/mutationFn so status codes propagate to QueryCache error handling" },
|
|
23
|
+
schema: [{
|
|
24
|
+
type: "object",
|
|
25
|
+
additionalProperties: false,
|
|
26
|
+
properties: { allowedErrors: {
|
|
27
|
+
type: "array",
|
|
28
|
+
items: {
|
|
29
|
+
type: "string",
|
|
30
|
+
minLength: 1
|
|
31
|
+
},
|
|
32
|
+
minItems: 1,
|
|
33
|
+
uniqueItems: true
|
|
34
|
+
} }
|
|
35
|
+
}],
|
|
36
|
+
messages: {
|
|
37
|
+
useApiError: "Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `new {{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.",
|
|
38
|
+
useApiErrorCall: "Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `{{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.",
|
|
39
|
+
useApiErrorMember: "Throw `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of re-throwing `{{thrown}}` directly inside {{fnType}}. The client error object may lose its HTTP status code in QueryCache/retry/error reporting."
|
|
44
40
|
},
|
|
45
|
-
defaultOptions: [{ allowedErrors: [...DEFAULT_ALLOWED_ERRORS] }]
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
defaultOptions: [{ allowedErrors: [...DEFAULT_ALLOWED_ERRORS] }]
|
|
42
|
+
},
|
|
43
|
+
createOnce(context) {
|
|
44
|
+
let allowedErrors = new Set(DEFAULT_ALLOWED_ERRORS);
|
|
45
|
+
let allowedExample = DEFAULT_ALLOWED_ERRORS[0];
|
|
46
|
+
const fnStack = [];
|
|
47
|
+
const extractedRefs = [];
|
|
48
|
+
const moduleFns = /* @__PURE__ */ new Map();
|
|
49
|
+
function recordModuleFn(name, body) {
|
|
50
|
+
if (!name || !body) return;
|
|
51
|
+
if (!moduleFns.has(name)) moduleFns.set(name, body);
|
|
52
|
+
}
|
|
53
|
+
function isAllowedThrow(arg) {
|
|
54
|
+
if (arg.type === "NewExpression" && arg.callee.type === "Identifier") return allowedErrors.has(arg.callee.name);
|
|
55
|
+
const factory = getStaticFactoryCallee(arg);
|
|
56
|
+
return factory !== void 0 && allowedErrors.has(factory.name);
|
|
57
|
+
}
|
|
58
|
+
function checkThrowNode(node, fnType) {
|
|
59
|
+
const arg = node.argument;
|
|
60
|
+
if (isAllowedThrow(arg)) return;
|
|
61
|
+
if (arg.type === "NewExpression" && arg.callee.type === "Identifier") {
|
|
62
|
+
context.report({
|
|
63
|
+
node: arg,
|
|
64
|
+
messageId: "useApiError",
|
|
65
|
+
data: {
|
|
66
|
+
thrown: arg.callee.name,
|
|
67
|
+
fnType,
|
|
68
|
+
allowed: allowedExample
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
62
72
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (arg.type === "NewExpression" && arg.callee.type === "Identifier") {
|
|
67
|
-
context.report({
|
|
68
|
-
node: arg,
|
|
69
|
-
messageId: "useApiError",
|
|
70
|
-
data: {
|
|
71
|
-
thrown: arg.callee.name,
|
|
72
|
-
fnType,
|
|
73
|
-
allowed: allowedExample
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const factory = getStaticFactoryCallee(arg);
|
|
79
|
-
if (factory) {
|
|
80
|
-
context.report({
|
|
81
|
-
node: arg,
|
|
82
|
-
messageId: "useApiErrorCall",
|
|
83
|
-
data: {
|
|
84
|
-
thrown: sourceCode.getText(factory.callee),
|
|
85
|
-
fnType,
|
|
86
|
-
allowed: allowedExample
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (arg.type === "MemberExpression") context.report({
|
|
73
|
+
const factory = getStaticFactoryCallee(arg);
|
|
74
|
+
if (factory) {
|
|
75
|
+
context.report({
|
|
92
76
|
node: arg,
|
|
93
|
-
messageId: "
|
|
77
|
+
messageId: "useApiErrorCall",
|
|
94
78
|
data: {
|
|
95
|
-
thrown: sourceCode.getText(
|
|
79
|
+
thrown: context.sourceCode.getText(factory.callee),
|
|
96
80
|
fnType,
|
|
97
81
|
allowed: allowedExample
|
|
98
82
|
}
|
|
99
83
|
});
|
|
84
|
+
return;
|
|
100
85
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
86
|
+
if (arg.type === "MemberExpression") context.report({
|
|
87
|
+
node: arg,
|
|
88
|
+
messageId: "useApiErrorMember",
|
|
89
|
+
data: {
|
|
90
|
+
thrown: context.sourceCode.getText(arg),
|
|
91
|
+
fnType,
|
|
92
|
+
allowed: allowedExample
|
|
107
93
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
for (const c of child) if (isAstNode(c)) walkThrows(c, fnType, visited);
|
|
117
|
-
} else if (isAstNode(child)) walkThrows(child, fnType, visited);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
function enterQueryOrMutationFn(node) {
|
|
121
|
-
const parent = node.parent;
|
|
122
|
-
if (parent.type !== "Property" || parent.key.type !== "Identifier") return;
|
|
123
|
-
const name = parent.key.name;
|
|
124
|
-
if (name === "queryFn" || name === "mutationFn") fnStack.push(name);
|
|
125
|
-
}
|
|
126
|
-
function exitQueryOrMutationFn(node) {
|
|
127
|
-
const parent = node.parent;
|
|
128
|
-
if (parent.type !== "Property" || parent.key.type !== "Identifier") return;
|
|
129
|
-
const name = parent.key.name;
|
|
130
|
-
if (name === "queryFn" || name === "mutationFn") fnStack.pop();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function walkThrows(node, fnType, visited = /* @__PURE__ */ new Set()) {
|
|
97
|
+
if (!node || visited.has(node)) return;
|
|
98
|
+
visited.add(node);
|
|
99
|
+
if (node.type === "ThrowStatement") {
|
|
100
|
+
checkThrowNode(node, fnType);
|
|
101
|
+
return;
|
|
131
102
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
103
|
+
if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
|
|
104
|
+
walkThrows(node.body, fnType, visited);
|
|
105
|
+
return;
|
|
135
106
|
}
|
|
136
|
-
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
fnType
|
|
141
|
-
});
|
|
107
|
+
for (const key of Object.keys(node)) {
|
|
108
|
+
if (key === "parent" || key === "loc" || key === "range") continue;
|
|
109
|
+
const child = node[key];
|
|
110
|
+
if (Array.isArray(child)) {
|
|
111
|
+
for (const item of child) if (isAstNode(item)) walkThrows(item, fnType, visited);
|
|
112
|
+
} else if (isAstNode(child)) walkThrows(child, fnType, visited);
|
|
142
113
|
}
|
|
143
|
-
return {
|
|
144
|
-
"Program > FunctionDeclaration"(node) {
|
|
145
|
-
recordModuleFn(node.id?.name, node.body);
|
|
146
|
-
},
|
|
147
|
-
"Program > VariableDeclaration > VariableDeclarator"(node) {
|
|
148
|
-
if (node.id.type === "Identifier" && (node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression")) recordModuleFn(node.id.name, node.init.body);
|
|
149
|
-
},
|
|
150
|
-
ArrowFunctionExpression: enterQueryOrMutationFn,
|
|
151
|
-
"ArrowFunctionExpression:exit": exitQueryOrMutationFn,
|
|
152
|
-
FunctionExpression: enterQueryOrMutationFn,
|
|
153
|
-
"FunctionExpression:exit": exitQueryOrMutationFn,
|
|
154
|
-
Property: recordExtractedRef,
|
|
155
|
-
ThrowStatement: checkThrowStatement,
|
|
156
|
-
"Program:exit"() {
|
|
157
|
-
for (const { name, fnType } of extractedRefs) {
|
|
158
|
-
const body = moduleFns.get(name);
|
|
159
|
-
if (body) walkThrows(body, fnType);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
114
|
}
|
|
164
|
-
|
|
165
|
-
|
|
115
|
+
function enterQueryOrMutationFn(node) {
|
|
116
|
+
const parent = node.parent;
|
|
117
|
+
if (parent.type !== "Property" || parent.key.type !== "Identifier") return;
|
|
118
|
+
const name = parent.key.name;
|
|
119
|
+
if (name === "queryFn" || name === "mutationFn") fnStack.push(name);
|
|
120
|
+
}
|
|
121
|
+
function exitQueryOrMutationFn(node) {
|
|
122
|
+
const parent = node.parent;
|
|
123
|
+
if (parent.type !== "Property" || parent.key.type !== "Identifier") return;
|
|
124
|
+
const name = parent.key.name;
|
|
125
|
+
if (name === "queryFn" || name === "mutationFn") fnStack.pop();
|
|
126
|
+
}
|
|
127
|
+
function checkThrowStatement(node) {
|
|
128
|
+
if (fnStack.length === 0) return;
|
|
129
|
+
checkThrowNode(node, fnStack.at(-1) ?? "");
|
|
130
|
+
}
|
|
131
|
+
function recordExtractedRef(prop) {
|
|
132
|
+
if (prop.type !== "Property") return;
|
|
133
|
+
if (prop.key.type !== "Identifier" || prop.key.name !== "queryFn" && prop.key.name !== "mutationFn" || prop.value.type !== "Identifier") return;
|
|
134
|
+
extractedRefs.push({
|
|
135
|
+
name: prop.value.name,
|
|
136
|
+
fnType: prop.key.name
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
before() {
|
|
141
|
+
const allowedList = context.options[0]?.allowedErrors ?? DEFAULT_ALLOWED_ERRORS;
|
|
142
|
+
allowedErrors = new Set(allowedList);
|
|
143
|
+
allowedExample = allowedList[0] ?? DEFAULT_ALLOWED_ERRORS[0];
|
|
144
|
+
fnStack.length = 0;
|
|
145
|
+
extractedRefs.length = 0;
|
|
146
|
+
moduleFns.clear();
|
|
147
|
+
},
|
|
148
|
+
"Program > FunctionDeclaration"(node) {
|
|
149
|
+
if (node.type !== "FunctionDeclaration") return;
|
|
150
|
+
recordModuleFn(node.id?.name, node.body);
|
|
151
|
+
},
|
|
152
|
+
"Program > VariableDeclaration > VariableDeclarator"(node) {
|
|
153
|
+
if (node.type !== "VariableDeclarator") return;
|
|
154
|
+
if (node.id.type === "Identifier" && (node.init?.type === "ArrowFunctionExpression" || node.init?.type === "FunctionExpression")) recordModuleFn(node.id.name, node.init.body);
|
|
155
|
+
},
|
|
156
|
+
ArrowFunctionExpression: enterQueryOrMutationFn,
|
|
157
|
+
"ArrowFunctionExpression:exit": exitQueryOrMutationFn,
|
|
158
|
+
FunctionExpression: enterQueryOrMutationFn,
|
|
159
|
+
"FunctionExpression:exit": exitQueryOrMutationFn,
|
|
160
|
+
Property: recordExtractedRef,
|
|
161
|
+
ThrowStatement: checkThrowStatement,
|
|
162
|
+
"Program:exit"() {
|
|
163
|
+
for (const { name, fnType } of extractedRefs) {
|
|
164
|
+
const body = moduleFns.get(name);
|
|
165
|
+
if (body) walkThrows(body, fnType);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
var api_error_default = definePlugin({
|
|
172
|
+
meta: { name: "eslint-plugin-mahir-api-error" },
|
|
173
|
+
rules: { "require-api-error": requireApiError }
|
|
174
|
+
});
|
|
166
175
|
|
|
167
176
|
//#endregion
|
|
168
|
-
export {
|
|
177
|
+
export { api_error_default as default };
|
|
169
178
|
//# sourceMappingURL=api-error.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-error.js","names":[],"sources":["../../src/plugins/api-error.ts"],"sourcesContent":["import type { TSESLint, TSESTree } from '@typescript-eslint/utils';\n\nconst DEFAULT_ALLOWED_ERRORS = ['ApiError', 'FormValidationError'];\n\nfunction getStaticFactoryCallee(arg: TSESTree.ThrowStatement['argument']) {\n\tif (arg.type !== 'CallExpression') return undefined;\n\tconst { callee } = arg;\n\tif (callee.type !== 'MemberExpression' || callee.computed) return undefined;\n\tconst { object, property } = callee;\n\tif (object.type !== 'Identifier' || property.type !== 'Identifier') return undefined;\n\treturn { callee, name: object.name };\n}\n\nfunction isAstNode(value: unknown): value is TSESTree.Node {\n\treturn typeof value === 'object' && value !== null && 'type' in value && typeof value.type === 'string';\n}\n\ntype Options = [\n\t{\n\t\tallowedErrors?: string[];\n\t},\n];\n\nconst requireApiError: TSESLint.RuleModule<'useApiError' | 'useApiErrorCall' | 'useApiErrorMember', Options> = {\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription:\n\t\t\t\t'Require an allowed API error instead of Error inside queryFn/mutationFn so status codes propagate to QueryCache error handling',\n\t\t},\n\t\tschema: [\n\t\t\t{\n\t\t\t\ttype: 'object',\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: {\n\t\t\t\t\tallowedErrors: {\n\t\t\t\t\t\ttype: 'array',\n\t\t\t\t\t\titems: { type: 'string', minLength: 1 },\n\t\t\t\t\t\tminItems: 1,\n\t\t\t\t\t\tuniqueItems: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tmessages: {\n\t\t\tuseApiError:\n\t\t\t\t'Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `new {{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.',\n\t\t\tuseApiErrorCall:\n\t\t\t\t'Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `{{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.',\n\t\t\tuseApiErrorMember:\n\t\t\t\t'Throw `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of re-throwing `{{thrown}}` directly inside {{fnType}}. The client error object may lose its HTTP status code in QueryCache/retry/error reporting.',\n\t\t},\n\t},\n\tdefaultOptions: [{ allowedErrors: [...DEFAULT_ALLOWED_ERRORS] }],\n\tcreate(context) {\n\t\tconst sourceCode = context.sourceCode;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n\t\tconst allowedList = context.options[0]?.allowedErrors ?? DEFAULT_ALLOWED_ERRORS;\n\t\tconst allowedErrors = new Set(allowedList);\n\t\tconst allowedExample = allowedList[0] ?? DEFAULT_ALLOWED_ERRORS[0];\n\t\tconst fnStack: string[] = [];\n\t\tconst extractedRefs: { name: string; fnType: string }[] = [];\n\t\tconst moduleFns = new Map<string, TSESTree.Node>();\n\n\t\tfunction recordModuleFn(name: string | undefined, body: TSESTree.Node | null | undefined) {\n\t\t\tif (!name || !body) return;\n\t\t\tif (!moduleFns.has(name)) moduleFns.set(name, body);\n\t\t}\n\n\t\tfunction isAllowedThrow(arg: TSESTree.ThrowStatement['argument']) {\n\t\t\tif (arg.type === 'NewExpression' && arg.callee.type === 'Identifier') return allowedErrors.has(arg.callee.name);\n\n\t\t\tconst factory = getStaticFactoryCallee(arg);\n\t\t\treturn factory !== undefined && allowedErrors.has(factory.name);\n\t\t}\n\n\t\tfunction checkThrowNode(node: TSESTree.ThrowStatement, fnType: string) {\n\t\t\tconst arg = node.argument;\n\t\t\tif (isAllowedThrow(arg)) return;\n\n\t\t\tif (arg.type === 'NewExpression' && arg.callee.type === 'Identifier') {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiError',\n\t\t\t\t\tdata: { thrown: arg.callee.name, fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst factory = getStaticFactoryCallee(arg);\n\t\t\tif (factory) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiErrorCall',\n\t\t\t\t\tdata: { thrown: sourceCode.getText(factory.callee), fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (arg.type === 'MemberExpression') {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiErrorMember',\n\t\t\t\t\tdata: { thrown: sourceCode.getText(arg), fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfunction walkThrows(node: TSESTree.Node | null | undefined, fnType: string, visited = new Set<TSESTree.Node>()) {\n\t\t\tif (!node || visited.has(node)) return;\n\t\t\tvisited.add(node);\n\n\t\t\tif (node.type === 'ThrowStatement') {\n\t\t\t\tcheckThrowNode(node, fnType);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tnode.type === 'FunctionDeclaration' ||\n\t\t\t\tnode.type === 'FunctionExpression' ||\n\t\t\t\tnode.type === 'ArrowFunctionExpression'\n\t\t\t) {\n\t\t\t\twalkThrows(node.body, fnType, visited);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const key of Object.keys(node)) {\n\t\t\t\tif (key === 'parent' || key === 'loc' || key === 'range') continue;\n\t\t\t\tconst child = (node as unknown as Record<string, unknown>)[key];\n\t\t\t\tif (Array.isArray(child)) {\n\t\t\t\t\tfor (const c of child) if (isAstNode(c)) walkThrows(c, fnType, visited);\n\t\t\t\t} else if (isAstNode(child)) walkThrows(child, fnType, visited);\n\t\t\t}\n\t\t}\n\n\t\tfunction enterQueryOrMutationFn(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression) {\n\t\t\tconst parent = node.parent;\n\t\t\tif (parent.type !== 'Property' || parent.key.type !== 'Identifier') return;\n\t\t\tconst name = parent.key.name;\n\t\t\tif (name === 'queryFn' || name === 'mutationFn') fnStack.push(name);\n\t\t}\n\n\t\tfunction exitQueryOrMutationFn(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression) {\n\t\t\tconst parent = node.parent;\n\t\t\tif (parent.type !== 'Property' || parent.key.type !== 'Identifier') return;\n\t\t\tconst name = parent.key.name;\n\t\t\tif (name === 'queryFn' || name === 'mutationFn') fnStack.pop();\n\t\t}\n\n\t\tfunction checkThrowStatement(node: TSESTree.ThrowStatement) {\n\t\t\tif (fnStack.length === 0) return;\n\t\t\tcheckThrowNode(node, fnStack[fnStack.length - 1]);\n\t\t}\n\n\t\tfunction recordExtractedRef(prop: TSESTree.Property) {\n\t\t\tif (\n\t\t\t\tprop.key.type !== 'Identifier' ||\n\t\t\t\t(prop.key.name !== 'queryFn' && prop.key.name !== 'mutationFn') ||\n\t\t\t\tprop.value.type !== 'Identifier'\n\t\t\t)\n\t\t\t\treturn;\n\t\t\textractedRefs.push({ name: prop.value.name, fnType: prop.key.name });\n\t\t}\n\n\t\treturn {\n\t\t\t'Program > FunctionDeclaration'(node: TSESTree.FunctionDeclaration) {\n\t\t\t\trecordModuleFn(node.id?.name, node.body);\n\t\t\t},\n\t\t\t'Program > VariableDeclaration > VariableDeclarator'(node: TSESTree.VariableDeclarator) {\n\t\t\t\tif (\n\t\t\t\t\tnode.id.type === 'Identifier' &&\n\t\t\t\t\t(node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression')\n\t\t\t\t)\n\t\t\t\t\trecordModuleFn(node.id.name, node.init.body);\n\t\t\t},\n\t\t\tArrowFunctionExpression: enterQueryOrMutationFn,\n\t\t\t'ArrowFunctionExpression:exit': exitQueryOrMutationFn,\n\t\t\tFunctionExpression: enterQueryOrMutationFn,\n\t\t\t'FunctionExpression:exit': exitQueryOrMutationFn,\n\t\t\tProperty: recordExtractedRef,\n\t\t\tThrowStatement: checkThrowStatement,\n\t\t\t'Program:exit'() {\n\t\t\t\tfor (const { name, fnType } of extractedRefs) {\n\t\t\t\t\tconst body = moduleFns.get(name);\n\t\t\t\t\tif (body) walkThrows(body, fnType);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n};\n\nconst plugin: TSESLint.FlatConfig.Plugin = {\n\tmeta: {\n\t\tname: 'eslint-plugin-mahir-api-error',\n\t\tversion: '1.0.0',\n\t},\n\trules: {\n\t\t'require-api-error': requireApiError,\n\t},\n};\n\nexport default plugin;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-error.js","names":[],"sources":["../../src/plugins/api-error.ts"],"sourcesContent":["import { definePlugin, defineRule } from '@oxlint/plugins';\n\nimport type { ESTree } from '@oxlint/plugins';\n\nconst DEFAULT_ALLOWED_ERRORS = ['ApiError', 'FormValidationError'];\n\nfunction getStaticFactoryCallee(arg: ESTree.Node) {\n\tif (arg.type !== 'CallExpression') return undefined;\n\tconst { callee } = arg;\n\tif (callee.type !== 'MemberExpression' || callee.computed) return undefined;\n\tconst { object, property } = callee;\n\tif (object.type !== 'Identifier' || property.type !== 'Identifier') return undefined;\n\treturn { callee, name: object.name };\n}\n\nfunction isAstNode(value: unknown): value is ESTree.Node {\n\treturn typeof value === 'object' && value !== null && 'type' in value && typeof (value as { type: unknown }).type === 'string';\n}\n\nconst requireApiError = defineRule({\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription:\n\t\t\t\t'Require an allowed API error instead of Error inside queryFn/mutationFn so status codes propagate to QueryCache error handling',\n\t\t},\n\t\tschema: [\n\t\t\t{\n\t\t\t\ttype: 'object',\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: {\n\t\t\t\t\tallowedErrors: {\n\t\t\t\t\t\ttype: 'array',\n\t\t\t\t\t\titems: { type: 'string', minLength: 1 },\n\t\t\t\t\t\tminItems: 1,\n\t\t\t\t\t\tuniqueItems: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tmessages: {\n\t\t\tuseApiError:\n\t\t\t\t'Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `new {{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.',\n\t\t\tuseApiErrorCall:\n\t\t\t\t'Use `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of `{{thrown}}(...)` inside {{fnType}}. This ensures the HTTP status code is available in QueryCache/retry/error reporting.',\n\t\t\tuseApiErrorMember:\n\t\t\t\t'Throw `new {{allowed}}(...)` or `{{allowed}}.from(...)` instead of re-throwing `{{thrown}}` directly inside {{fnType}}. The client error object may lose its HTTP status code in QueryCache/retry/error reporting.',\n\t\t},\n\t\tdefaultOptions: [{ allowedErrors: [...DEFAULT_ALLOWED_ERRORS] }],\n\t},\n\tcreateOnce(context) {\n\t\tlet allowedErrors = new Set(DEFAULT_ALLOWED_ERRORS);\n\t\tlet allowedExample = DEFAULT_ALLOWED_ERRORS[0];\n\t\tconst fnStack: string[] = [];\n\t\tconst extractedRefs: { name: string; fnType: string }[] = [];\n\t\tconst moduleFns = new Map<string, ESTree.Node>();\n\n\t\tfunction recordModuleFn(name: string | undefined, body: ESTree.Node | null | undefined) {\n\t\t\tif (!name || !body) return;\n\t\t\tif (!moduleFns.has(name)) moduleFns.set(name, body);\n\t\t}\n\n\t\tfunction isAllowedThrow(arg: ESTree.Node) {\n\t\t\tif (arg.type === 'NewExpression' && arg.callee.type === 'Identifier') return allowedErrors.has(arg.callee.name);\n\t\t\tconst factory = getStaticFactoryCallee(arg);\n\t\t\treturn factory !== undefined && allowedErrors.has(factory.name);\n\t\t}\n\n\t\tfunction checkThrowNode(node: ESTree.ThrowStatement, fnType: string) {\n\t\t\tconst arg = node.argument;\n\t\t\tif (isAllowedThrow(arg)) return;\n\n\t\t\tif (arg.type === 'NewExpression' && arg.callee.type === 'Identifier') {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiError',\n\t\t\t\t\tdata: { thrown: arg.callee.name, fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst factory = getStaticFactoryCallee(arg);\n\t\t\tif (factory) {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiErrorCall',\n\t\t\t\t\tdata: { thrown: context.sourceCode.getText(factory.callee), fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (arg.type === 'MemberExpression') {\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: arg,\n\t\t\t\t\tmessageId: 'useApiErrorMember',\n\t\t\t\t\tdata: { thrown: context.sourceCode.getText(arg), fnType, allowed: allowedExample },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfunction walkThrows(node: ESTree.Node | null | undefined, fnType: string, visited = new Set<ESTree.Node>()) {\n\t\t\tif (!node || visited.has(node)) return;\n\t\t\tvisited.add(node);\n\n\t\t\tif (node.type === 'ThrowStatement') {\n\t\t\t\tcheckThrowNode(node, fnType);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tnode.type === 'FunctionDeclaration' ||\n\t\t\t\tnode.type === 'FunctionExpression' ||\n\t\t\t\tnode.type === 'ArrowFunctionExpression'\n\t\t\t) {\n\t\t\t\twalkThrows(node.body, fnType, visited);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (const key of Object.keys(node)) {\n\t\t\t\tif (key === 'parent' || key === 'loc' || key === 'range') continue;\n\t\t\t\tconst child = (node as unknown as Record<string, unknown>)[key];\n\t\t\t\tif (Array.isArray(child)) {\n\t\t\t\t\tfor (const item of child) if (isAstNode(item)) walkThrows(item, fnType, visited);\n\t\t\t\t} else if (isAstNode(child)) walkThrows(child, fnType, visited);\n\t\t\t}\n\t\t}\n\n\t\tfunction enterQueryOrMutationFn(node: ESTree.ArrowFunctionExpression | ESTree.Function) {\n\t\t\tconst parent = node.parent;\n\t\t\tif (parent.type !== 'Property' || parent.key.type !== 'Identifier') return;\n\t\t\tconst name = parent.key.name;\n\t\t\tif (name === 'queryFn' || name === 'mutationFn') fnStack.push(name);\n\t\t}\n\n\t\tfunction exitQueryOrMutationFn(node: ESTree.ArrowFunctionExpression | ESTree.Function) {\n\t\t\tconst parent = node.parent;\n\t\t\tif (parent.type !== 'Property' || parent.key.type !== 'Identifier') return;\n\t\t\tconst name = parent.key.name;\n\t\t\tif (name === 'queryFn' || name === 'mutationFn') fnStack.pop();\n\t\t}\n\n\t\tfunction checkThrowStatement(node: ESTree.ThrowStatement) {\n\t\t\tif (fnStack.length === 0) return;\n\t\t\tcheckThrowNode(node, fnStack.at(-1) ?? '');\n\t\t}\n\n\t\tfunction recordExtractedRef(prop: ESTree.Node) {\n\t\t\tif (prop.type !== 'Property') return;\n\t\t\tif (\n\t\t\t\tprop.key.type !== 'Identifier' ||\n\t\t\t\t(prop.key.name !== 'queryFn' && prop.key.name !== 'mutationFn') ||\n\t\t\t\tprop.value.type !== 'Identifier'\n\t\t\t)\n\t\t\t\treturn;\n\t\t\textractedRefs.push({ name: prop.value.name, fnType: prop.key.name });\n\t\t}\n\n\t\treturn {\n\t\t\tbefore() {\n\t\t\t\tconst options = context.options[0] as { allowedErrors?: string[] } | undefined;\n\t\t\t\tconst allowedList = options?.allowedErrors ?? DEFAULT_ALLOWED_ERRORS;\n\t\t\t\tallowedErrors = new Set(allowedList);\n\t\t\t\tallowedExample = allowedList[0] ?? DEFAULT_ALLOWED_ERRORS[0];\n\t\t\t\tfnStack.length = 0;\n\t\t\t\textractedRefs.length = 0;\n\t\t\t\tmoduleFns.clear();\n\t\t\t},\n\t\t\t'Program > FunctionDeclaration'(node) {\n\t\t\t\tif (node.type !== 'FunctionDeclaration') return;\n\t\t\t\trecordModuleFn(node.id?.name, node.body);\n\t\t\t},\n\t\t\t'Program > VariableDeclaration > VariableDeclarator'(node) {\n\t\t\t\tif (node.type !== 'VariableDeclarator') return;\n\t\t\t\tif (\n\t\t\t\t\tnode.id.type === 'Identifier' &&\n\t\t\t\t\t(node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression')\n\t\t\t\t)\n\t\t\t\t\trecordModuleFn(node.id.name, node.init.body);\n\t\t\t},\n\t\t\tArrowFunctionExpression: enterQueryOrMutationFn,\n\t\t\t'ArrowFunctionExpression:exit': exitQueryOrMutationFn,\n\t\t\tFunctionExpression: enterQueryOrMutationFn,\n\t\t\t'FunctionExpression:exit': exitQueryOrMutationFn,\n\t\t\tProperty: recordExtractedRef,\n\t\t\tThrowStatement: checkThrowStatement,\n\t\t\t'Program:exit'() {\n\t\t\t\tfor (const { name, fnType } of extractedRefs) {\n\t\t\t\t\tconst body = moduleFns.get(name);\n\t\t\t\t\tif (body) walkThrows(body, fnType);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport default definePlugin({\n\tmeta: {\n\t\tname: 'eslint-plugin-mahir-api-error',\n\t},\n\trules: {\n\t\t'require-api-error': requireApiError,\n\t},\n});\n"],"mappings":"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"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { TSESLint } from "@typescript-eslint/utils";
|
|
2
1
|
//#region src/plugins/central-icons.d.ts
|
|
3
|
-
declare const
|
|
2
|
+
declare const _default: import("@oxlint/plugins").Plugin;
|
|
4
3
|
//#endregion
|
|
5
|
-
export {
|
|
4
|
+
export { _default as default };
|
|
6
5
|
//# sourceMappingURL=central-icons.d.ts.map
|
|
@@ -1,61 +1,59 @@
|
|
|
1
|
+
import { definePlugin, defineRule } from "@oxlint/plugins";
|
|
2
|
+
|
|
1
3
|
//#region src/plugins/central-icons.ts
|
|
2
4
|
const CENTRAL_ICONS_PACKAGE_RE = /^@central-icons-react(?:-native)?\/[^/]+$/;
|
|
3
5
|
function centralIconSubpath(iconName) {
|
|
4
6
|
if (iconName.endsWith("Default")) return iconName.slice(0, -7);
|
|
5
7
|
return iconName;
|
|
6
8
|
}
|
|
7
|
-
const
|
|
9
|
+
const noCentralIconsBarrelImport = defineRule({
|
|
8
10
|
meta: {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
type: "problem",
|
|
12
|
+
docs: { description: "Disallow barrel imports from @central-icons-react and @central-icons-react-native packages; use direct subpath imports instead" },
|
|
13
|
+
fixable: "code",
|
|
14
|
+
messages: {
|
|
15
|
+
barrelImport: "Avoid barrel imports from `{{source}}`. Import icons directly from `{{source}}/<IconName>` to keep the bundler from opening thousands of icon files.",
|
|
16
|
+
unsupportedImport: "Only named icon imports can be autofixed. Use direct subpath default imports from `{{source}}/<IconName>`."
|
|
17
|
+
}
|
|
11
18
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
messages: {
|
|
19
|
-
barrelImport: "Avoid barrel imports from `{{source}}`. Import icons directly from `{{source}}/<IconName>` to keep the bundler from opening thousands of icon files.",
|
|
20
|
-
unsupportedImport: "Only named icon imports can be autofixed. Use direct subpath default imports from `{{source}}/<IconName>`."
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
defaultOptions: [],
|
|
24
|
-
create(context) {
|
|
25
|
-
return { ImportDeclaration(node) {
|
|
26
|
-
const source = node.source.value;
|
|
27
|
-
if (typeof source !== "string" || !CENTRAL_ICONS_PACKAGE_RE.test(source)) return;
|
|
28
|
-
const namedSpecifiers = node.specifiers.filter((specifier) => specifier.type === "ImportSpecifier");
|
|
29
|
-
if (namedSpecifiers.length === 0 || namedSpecifiers.length !== node.specifiers.length) {
|
|
30
|
-
context.report({
|
|
31
|
-
node,
|
|
32
|
-
messageId: "unsupportedImport",
|
|
33
|
-
data: { source }
|
|
34
|
-
});
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
19
|
+
createOnce(context) {
|
|
20
|
+
return { ImportDeclaration(node) {
|
|
21
|
+
const source = node.source.value;
|
|
22
|
+
if (typeof source !== "string" || !CENTRAL_ICONS_PACKAGE_RE.test(source)) return;
|
|
23
|
+
const namedSpecifiers = node.specifiers.filter((specifier) => specifier.type === "ImportSpecifier");
|
|
24
|
+
if (namedSpecifiers.length === 0 || namedSpecifiers.length !== node.specifiers.length) {
|
|
37
25
|
context.report({
|
|
38
26
|
node,
|
|
39
|
-
messageId: "
|
|
40
|
-
data: { source }
|
|
41
|
-
fix(fixer) {
|
|
42
|
-
const quote = node.source.raw.startsWith("'") ? "'" : "\"";
|
|
43
|
-
const fixedImports = namedSpecifiers.map((specifier) => {
|
|
44
|
-
const imported = specifier.imported;
|
|
45
|
-
const importedName = imported.type === "Identifier" ? imported.name : imported.value;
|
|
46
|
-
const localName = specifier.local.name;
|
|
47
|
-
const typePrefix = node.importKind === "type" || specifier.importKind === "type" ? "type " : "";
|
|
48
|
-
const subpath = centralIconSubpath(importedName);
|
|
49
|
-
return `import ${typePrefix}${localName} from ${quote}${source}/${subpath}${quote};`;
|
|
50
|
-
});
|
|
51
|
-
return fixer.replaceText(node, fixedImports.join("\n"));
|
|
52
|
-
}
|
|
27
|
+
messageId: "unsupportedImport",
|
|
28
|
+
data: { source }
|
|
53
29
|
});
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
context.report({
|
|
33
|
+
node,
|
|
34
|
+
messageId: "barrelImport",
|
|
35
|
+
data: { source },
|
|
36
|
+
fix(fixer) {
|
|
37
|
+
const quote = (node.source.raw ?? "\"").startsWith("'") ? "'" : "\"";
|
|
38
|
+
const fixedImports = namedSpecifiers.map((specifier) => {
|
|
39
|
+
const imported = specifier.imported;
|
|
40
|
+
const importedName = imported.type === "Identifier" ? imported.name : imported.value;
|
|
41
|
+
const localName = specifier.local.name;
|
|
42
|
+
const typePrefix = node.importKind === "type" || specifier.importKind === "type" ? "type " : "";
|
|
43
|
+
const subpath = centralIconSubpath(importedName);
|
|
44
|
+
return `import ${typePrefix}${localName} from ${quote}${source}/${subpath}${quote};`;
|
|
45
|
+
});
|
|
46
|
+
return fixer.replaceText(node, fixedImports.join("\n"));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
} };
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
var central_icons_default = definePlugin({
|
|
53
|
+
meta: { name: "eslint-plugin-mahir-central-icons" },
|
|
54
|
+
rules: { "no-central-icons-barrel-import": noCentralIconsBarrelImport }
|
|
55
|
+
});
|
|
58
56
|
|
|
59
57
|
//#endregion
|
|
60
|
-
export {
|
|
58
|
+
export { central_icons_default as default };
|
|
61
59
|
//# sourceMappingURL=central-icons.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"central-icons.js","names":[],"sources":["../../src/plugins/central-icons.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"central-icons.js","names":[],"sources":["../../src/plugins/central-icons.ts"],"sourcesContent":["import { definePlugin, defineRule } from '@oxlint/plugins';\n\nconst CENTRAL_ICONS_PACKAGE_RE = /^@central-icons-react(?:-native)?\\/[^/]+$/;\n\nfunction centralIconSubpath(iconName: string) {\n\tif (iconName.endsWith('Default')) return iconName.slice(0, -'Default'.length);\n\treturn iconName;\n}\n\nconst noCentralIconsBarrelImport = defineRule({\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription:\n\t\t\t\t'Disallow barrel imports from @central-icons-react and @central-icons-react-native packages; use direct subpath imports instead',\n\t\t},\n\t\tfixable: 'code',\n\t\tmessages: {\n\t\t\tbarrelImport:\n\t\t\t\t'Avoid barrel imports from `{{source}}`. Import icons directly from `{{source}}/<IconName>` to keep the bundler from opening thousands of icon files.',\n\t\t\tunsupportedImport:\n\t\t\t\t'Only named icon imports can be autofixed. Use direct subpath default imports from `{{source}}/<IconName>`.',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\treturn {\n\t\t\tImportDeclaration(node) {\n\t\t\t\tconst source = node.source.value;\n\t\t\t\tif (typeof source !== 'string' || !CENTRAL_ICONS_PACKAGE_RE.test(source)) return;\n\n\t\t\t\tconst namedSpecifiers = node.specifiers.filter((specifier) => specifier.type === 'ImportSpecifier');\n\t\t\t\tif (namedSpecifiers.length === 0 || namedSpecifiers.length !== node.specifiers.length) {\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode,\n\t\t\t\t\t\tmessageId: 'unsupportedImport',\n\t\t\t\t\t\tdata: { source },\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode,\n\t\t\t\t\tmessageId: 'barrelImport',\n\t\t\t\t\tdata: { source },\n\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\tconst quote = (node.source.raw ?? '\"').startsWith(\"'\") ? \"'\" : '\"';\n\t\t\t\t\t\tconst fixedImports = namedSpecifiers.map((specifier) => {\n\t\t\t\t\t\t\tconst imported = specifier.imported;\n\t\t\t\t\t\t\tconst importedName = imported.type === 'Identifier' ? imported.name : imported.value;\n\t\t\t\t\t\t\tconst localName = specifier.local.name;\n\t\t\t\t\t\t\tconst typePrefix = node.importKind === 'type' || specifier.importKind === 'type' ? 'type ' : '';\n\t\t\t\t\t\t\tconst subpath = centralIconSubpath(importedName);\n\t\t\t\t\t\t\treturn `import ${typePrefix}${localName} from ${quote}${source}/${subpath}${quote};`;\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn fixer.replaceText(node, fixedImports.join('\\n'));\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport default definePlugin({\n\tmeta: {\n\t\tname: 'eslint-plugin-mahir-central-icons',\n\t},\n\trules: {\n\t\t'no-central-icons-barrel-import': noCentralIconsBarrelImport,\n\t},\n});\n"],"mappings":";;;AAEA,MAAM,2BAA2B;AAEjC,SAAS,mBAAmB,UAAkB;CAC7C,IAAI,SAAS,SAAS,SAAS,GAAG,OAAO,SAAS,MAAM,GAAG,EAAiB;CAC5E,OAAO;AACR;AAEA,MAAM,6BAA6B,WAAW;CAC7C,MAAM;EACL,MAAM;EACN,MAAM,EACL,aACC,iIACF;EACA,SAAS;EACT,UAAU;GACT,cACC;GACD,mBACC;EACF;CACD;CACA,WAAW,SAAS;EACnB,OAAO,EACN,kBAAkB,MAAM;GACvB,MAAM,SAAS,KAAK,OAAO;GAC3B,IAAI,OAAO,WAAW,YAAY,CAAC,yBAAyB,KAAK,MAAM,GAAG;GAE1E,MAAM,kBAAkB,KAAK,WAAW,QAAQ,cAAc,UAAU,SAAS,iBAAiB;GAClG,IAAI,gBAAgB,WAAW,KAAK,gBAAgB,WAAW,KAAK,WAAW,QAAQ;IACtF,QAAQ,OAAO;KACd;KACA,WAAW;KACX,MAAM,EAAE,OAAO;IAChB,CAAC;IACD;GACD;GAEA,QAAQ,OAAO;IACd;IACA,WAAW;IACX,MAAM,EAAE,OAAO;IACf,IAAI,OAAO;KACV,MAAM,SAAS,KAAK,OAAO,OAAO,KAAG,CAAE,WAAW,GAAG,IAAI,MAAM;KAC/D,MAAM,eAAe,gBAAgB,KAAK,cAAc;MACvD,MAAM,WAAW,UAAU;MAC3B,MAAM,eAAe,SAAS,SAAS,eAAe,SAAS,OAAO,SAAS;MAC/E,MAAM,YAAY,UAAU,MAAM;MAClC,MAAM,aAAa,KAAK,eAAe,UAAU,UAAU,eAAe,SAAS,UAAU;MAC7F,MAAM,UAAU,mBAAmB,YAAY;MAC/C,OAAO,UAAU,aAAa,UAAU,QAAQ,QAAQ,OAAO,GAAG,UAAU,MAAM;KACnF,CAAC;KACD,OAAO,MAAM,YAAY,MAAM,aAAa,KAAK,IAAI,CAAC;IACvD;GACD,CAAC;EACF,EACD;CACD;AACD,CAAC;AAED,4BAAe,aAAa;CAC3B,MAAM,EACL,MAAM,oCACP;CACA,OAAO,EACN,kCAAkC,2BACnC;AACD,CAAC"}
|
package/dist/plugins/i18n.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { TSESLint } from "@typescript-eslint/utils";
|
|
2
1
|
//#region src/plugins/i18n.d.ts
|
|
3
|
-
declare const
|
|
2
|
+
declare const _default: import("@oxlint/plugins").Plugin;
|
|
4
3
|
//#endregion
|
|
5
|
-
export {
|
|
4
|
+
export { _default as default };
|
|
6
5
|
//# sourceMappingURL=i18n.d.ts.map
|
package/dist/plugins/i18n.js
CHANGED
|
@@ -1,58 +1,55 @@
|
|
|
1
|
+
import { definePlugin, defineRule } from "@oxlint/plugins";
|
|
2
|
+
|
|
1
3
|
//#region src/plugins/i18n.ts
|
|
2
|
-
const
|
|
4
|
+
const staticTArguments = defineRule({
|
|
3
5
|
meta: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
type: "problem",
|
|
7
|
+
docs: { description: "Require t() calls to use static string literals so next-intl can extract messages at build time" },
|
|
8
|
+
messages: { staticArgument: "`t()` must receive a static string literal. Dynamic expressions cannot be extracted by next-intl. Use separate `t(\"Key\")` calls instead." }
|
|
6
9
|
},
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
schema: [],
|
|
33
|
-
messages: { noTParam: "Do not pass `t` as an argument. Call `useExtracted()` or `getExtracted()` directly in the consuming component/function instead." }
|
|
10
|
+
createOnce(context) {
|
|
11
|
+
return { CallExpression(node) {
|
|
12
|
+
if (node.callee.type !== "Identifier" || node.callee.name !== "t") return;
|
|
13
|
+
if (node.arguments.length === 0) return;
|
|
14
|
+
const firstArg = node.arguments[0];
|
|
15
|
+
if (firstArg.type !== "Literal" || typeof firstArg.value !== "string") context.report({
|
|
16
|
+
node: firstArg,
|
|
17
|
+
messageId: "staticArgument"
|
|
18
|
+
});
|
|
19
|
+
} };
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const noTAsParameter = defineRule({
|
|
23
|
+
meta: {
|
|
24
|
+
type: "problem",
|
|
25
|
+
docs: { description: "Disallow passing the `t` translation function as an argument to other functions or components" },
|
|
26
|
+
messages: { noTParam: "Do not pass `t` as an argument. Call `useExtracted()` or `getExtracted()` directly in the consuming component/function instead." }
|
|
27
|
+
},
|
|
28
|
+
createOnce(context) {
|
|
29
|
+
return {
|
|
30
|
+
CallExpression(node) {
|
|
31
|
+
for (const arg of node.arguments) if (arg.type === "Identifier" && arg.name === "t") context.report({
|
|
32
|
+
node: arg,
|
|
33
|
+
messageId: "noTParam"
|
|
34
|
+
});
|
|
34
35
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
node: arg,
|
|
41
|
-
messageId: "noTParam"
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
JSXAttribute(node) {
|
|
45
|
-
if (node.value?.type === "JSXExpressionContainer" && node.value.expression.type === "Identifier" && node.value.expression.name === "t") context.report({
|
|
46
|
-
node: node.value.expression,
|
|
47
|
-
messageId: "noTParam"
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
};
|
|
36
|
+
JSXAttribute(node) {
|
|
37
|
+
if (node.value?.type === "JSXExpressionContainer" && node.value.expression.type === "Identifier" && node.value.expression.name === "t") context.report({
|
|
38
|
+
node: node.value.expression,
|
|
39
|
+
messageId: "noTParam"
|
|
40
|
+
});
|
|
51
41
|
}
|
|
52
|
-
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
var i18n_default = definePlugin({
|
|
46
|
+
meta: { name: "eslint-plugin-mahir-i18n" },
|
|
47
|
+
rules: {
|
|
48
|
+
"static-t-arguments": staticTArguments,
|
|
49
|
+
"no-t-as-parameter": noTAsParameter
|
|
53
50
|
}
|
|
54
|
-
};
|
|
51
|
+
});
|
|
55
52
|
|
|
56
53
|
//#endregion
|
|
57
|
-
export {
|
|
54
|
+
export { i18n_default as default };
|
|
58
55
|
//# sourceMappingURL=i18n.js.map
|
package/dist/plugins/i18n.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n.js","names":[],"sources":["../../src/plugins/i18n.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"i18n.js","names":[],"sources":["../../src/plugins/i18n.ts"],"sourcesContent":["import { definePlugin, defineRule } from '@oxlint/plugins';\n\nconst staticTArguments = defineRule({\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Require t() calls to use static string literals so next-intl can extract messages at build time',\n\t\t},\n\t\tmessages: {\n\t\t\tstaticArgument:\n\t\t\t\t'`t()` must receive a static string literal. Dynamic expressions cannot be extracted by next-intl. Use separate `t(\"Key\")` calls instead.',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\treturn {\n\t\t\tCallExpression(node) {\n\t\t\t\tif (node.callee.type !== 'Identifier' || node.callee.name !== 't') return;\n\t\t\t\tif (node.arguments.length === 0) return;\n\t\t\t\tconst firstArg = node.arguments[0];\n\t\t\t\tif (firstArg.type !== 'Literal' || typeof firstArg.value !== 'string')\n\t\t\t\t\tcontext.report({ node: firstArg, messageId: 'staticArgument' });\n\t\t\t},\n\t\t};\n\t},\n});\n\nconst noTAsParameter = defineRule({\n\tmeta: {\n\t\ttype: 'problem',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow passing the `t` translation function as an argument to other functions or components',\n\t\t},\n\t\tmessages: {\n\t\t\tnoTParam:\n\t\t\t\t'Do not pass `t` as an argument. Call `useExtracted()` or `getExtracted()` directly in the consuming component/function instead.',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\treturn {\n\t\t\tCallExpression(node) {\n\t\t\t\tfor (const arg of node.arguments)\n\t\t\t\t\tif (arg.type === 'Identifier' && arg.name === 't') context.report({ node: arg, messageId: 'noTParam' });\n\t\t\t},\n\t\t\tJSXAttribute(node) {\n\t\t\t\tif (\n\t\t\t\t\tnode.value?.type === 'JSXExpressionContainer' &&\n\t\t\t\t\tnode.value.expression.type === 'Identifier' &&\n\t\t\t\t\tnode.value.expression.name === 't'\n\t\t\t\t)\n\t\t\t\t\tcontext.report({ node: node.value.expression, messageId: 'noTParam' });\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport default definePlugin({\n\tmeta: {\n\t\tname: 'eslint-plugin-mahir-i18n',\n\t},\n\trules: {\n\t\t'static-t-arguments': staticTArguments,\n\t\t'no-t-as-parameter': noTAsParameter,\n\t},\n});\n"],"mappings":";;;AAEA,MAAM,mBAAmB,WAAW;CACnC,MAAM;EACL,MAAM;EACN,MAAM,EACL,aAAa,kGACd;EACA,UAAU,EACT,gBACC,6IACF;CACD;CACA,WAAW,SAAS;EACnB,OAAO,EACN,eAAe,MAAM;GACpB,IAAI,KAAK,OAAO,SAAS,gBAAgB,KAAK,OAAO,SAAS,KAAK;GACnE,IAAI,KAAK,UAAU,WAAW,GAAG;GACjC,MAAM,WAAW,KAAK,UAAU;GAChC,IAAI,SAAS,SAAS,aAAa,OAAO,SAAS,UAAU,UAC5D,QAAQ,OAAO;IAAE,MAAM;IAAU,WAAW;GAAiB,CAAC;EAChE,EACD;CACD;AACD,CAAC;AAED,MAAM,iBAAiB,WAAW;CACjC,MAAM;EACL,MAAM;EACN,MAAM,EACL,aAAa,gGACd;EACA,UAAU,EACT,UACC,kIACF;CACD;CACA,WAAW,SAAS;EACnB,OAAO;GACN,eAAe,MAAM;IACpB,KAAK,MAAM,OAAO,KAAK,WACtB,IAAI,IAAI,SAAS,gBAAgB,IAAI,SAAS,KAAK,QAAQ,OAAO;KAAE,MAAM;KAAK,WAAW;IAAW,CAAC;GACxG;GACA,aAAa,MAAM;IAClB,IACC,KAAK,OAAO,SAAS,4BACrB,KAAK,MAAM,WAAW,SAAS,gBAC/B,KAAK,MAAM,WAAW,SAAS,KAE/B,QAAQ,OAAO;KAAE,MAAM,KAAK,MAAM;KAAY,WAAW;IAAW,CAAC;GACvE;EACD;CACD;AACD,CAAC;AAED,mBAAe,aAAa;CAC3B,MAAM,EACL,MAAM,2BACP;CACA,OAAO;EACN,sBAAsB;EACtB,qBAAqB;CACtB;AACD,CAAC"}
|