pasika 0.10.21 → 0.10.23
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/eslint/pasika/index.js +77 -19
- package/package.json +1 -1
|
@@ -59,10 +59,22 @@ import path from "path";
|
|
|
59
59
|
import ts from "typescript";
|
|
60
60
|
var isPascalCase = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
61
61
|
var isHookCallName = (name) => /^use[A-Z]/.test(name);
|
|
62
|
+
var isHandlerName = (name) => /^handle[A-Z]/.test(name);
|
|
62
63
|
function isExported(node) {
|
|
63
64
|
if (!ts.canHaveModifiers(node)) return false;
|
|
64
65
|
return (ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword);
|
|
65
66
|
}
|
|
67
|
+
function namedExportedLocalNames(sourceFile) {
|
|
68
|
+
const names = /* @__PURE__ */ new Set();
|
|
69
|
+
for (const statement of sourceFile.statements) {
|
|
70
|
+
if (!ts.isExportDeclaration(statement) || statement.moduleSpecifier || !statement.exportClause) continue;
|
|
71
|
+
if (!ts.isNamedExports(statement.exportClause)) continue;
|
|
72
|
+
for (const element of statement.exportClause.elements) {
|
|
73
|
+
names.add((element.propertyName ?? element.name).text);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return names;
|
|
77
|
+
}
|
|
66
78
|
function containsJsx(node) {
|
|
67
79
|
let found = false;
|
|
68
80
|
const visit = (child) => {
|
|
@@ -76,35 +88,77 @@ function containsJsx(node) {
|
|
|
76
88
|
ts.forEachChild(node, visit);
|
|
77
89
|
return found;
|
|
78
90
|
}
|
|
79
|
-
function
|
|
91
|
+
function containsDataFetch(node) {
|
|
80
92
|
let found = false;
|
|
81
93
|
const visit = (child) => {
|
|
82
94
|
if (found) return;
|
|
83
|
-
if (ts.isCallExpression(child)) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (ts.isIdentifier(expression)) {
|
|
87
|
-
name = expression.text;
|
|
88
|
-
} else if (ts.isPropertyAccessExpression(expression)) {
|
|
89
|
-
name = expression.name.text;
|
|
90
|
-
}
|
|
91
|
-
if (isHookCallName(name)) {
|
|
92
|
-
found = true;
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
+
if (ts.isCallExpression(child) && ts.isIdentifier(child.expression) && child.expression.text === "zodFetch") {
|
|
96
|
+
found = true;
|
|
97
|
+
return;
|
|
95
98
|
}
|
|
96
99
|
ts.forEachChild(child, visit);
|
|
97
100
|
};
|
|
98
101
|
ts.forEachChild(node, visit);
|
|
99
102
|
return found;
|
|
100
103
|
}
|
|
101
|
-
function
|
|
102
|
-
|
|
104
|
+
function isComponentTagName(tagName2) {
|
|
105
|
+
if (ts.isIdentifier(tagName2)) return isPascalCase(tagName2.text);
|
|
106
|
+
if (ts.isPropertyAccessExpression(tagName2)) {
|
|
107
|
+
let root = tagName2.expression;
|
|
108
|
+
while (ts.isPropertyAccessExpression(root)) root = root.expression;
|
|
109
|
+
return ts.isIdentifier(root) && isPascalCase(root.text);
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
function containsOwnedHandlerProp(node) {
|
|
114
|
+
const handlerNames = /* @__PURE__ */ new Set();
|
|
115
|
+
const collectHandlers = (child) => {
|
|
116
|
+
if (ts.isVariableDeclaration(child) && ts.isIdentifier(child.name) && isHandlerName(child.name.text) && child.initializer && (ts.isArrowFunction(child.initializer) || ts.isFunctionExpression(child.initializer) || ts.isCallExpression(child.initializer) && ts.isPropertyAccessExpression(child.initializer.expression) && child.initializer.expression.name.text === "useCallback" || ts.isCallExpression(child.initializer) && ts.isIdentifier(child.initializer.expression) && child.initializer.expression.text === "useCallback")) {
|
|
117
|
+
handlerNames.add(child.name.text);
|
|
118
|
+
} else if (ts.isFunctionDeclaration(child) && child.name && isHandlerName(child.name.text)) {
|
|
119
|
+
handlerNames.add(child.name.text);
|
|
120
|
+
}
|
|
121
|
+
ts.forEachChild(child, collectHandlers);
|
|
122
|
+
};
|
|
123
|
+
ts.forEachChild(node, collectHandlers);
|
|
124
|
+
if (handlerNames.size === 0) return false;
|
|
125
|
+
let found = false;
|
|
126
|
+
const findPassedHandler = (child) => {
|
|
127
|
+
if (found) return;
|
|
128
|
+
let attributes;
|
|
129
|
+
let tagName2;
|
|
130
|
+
if (ts.isJsxElement(child)) {
|
|
131
|
+
attributes = child.openingElement.attributes;
|
|
132
|
+
tagName2 = child.openingElement.tagName;
|
|
133
|
+
} else if (ts.isJsxSelfClosingElement(child)) {
|
|
134
|
+
attributes = child.attributes;
|
|
135
|
+
tagName2 = child.tagName;
|
|
136
|
+
}
|
|
137
|
+
if (attributes && tagName2 && isComponentTagName(tagName2)) {
|
|
138
|
+
for (const property of attributes.properties) {
|
|
139
|
+
if (!ts.isJsxAttribute(property) || !ts.isIdentifier(property.name) || !/^on[A-Z]/.test(property.name.text)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const initializer = property.initializer;
|
|
143
|
+
if (!initializer || !ts.isJsxExpression(initializer) || !initializer.expression) continue;
|
|
144
|
+
if (ts.isIdentifier(initializer.expression) && handlerNames.has(initializer.expression.text)) {
|
|
145
|
+
found = true;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
ts.forEachChild(child, findPassedHandler);
|
|
151
|
+
};
|
|
152
|
+
ts.forEachChild(node, findPassedHandler);
|
|
153
|
+
return found;
|
|
154
|
+
}
|
|
155
|
+
function isSmartComponent(node) {
|
|
156
|
+
return containsDataFetch(node) || containsOwnedHandlerProp(node);
|
|
103
157
|
}
|
|
104
158
|
function componentFromFunction(node) {
|
|
105
159
|
const name = node.name?.text;
|
|
106
160
|
if (!name || !isPascalCase(name) || !containsJsx(node)) return void 0;
|
|
107
|
-
return { name, declaration: node, smart:
|
|
161
|
+
return { name, declaration: node, smart: isSmartComponent(node) };
|
|
108
162
|
}
|
|
109
163
|
function componentFromVariable(node) {
|
|
110
164
|
if (!ts.isIdentifier(node.name) || !isPascalCase(node.name.text)) return void 0;
|
|
@@ -114,22 +168,26 @@ function componentFromVariable(node) {
|
|
|
114
168
|
return {
|
|
115
169
|
name: node.name.text,
|
|
116
170
|
declaration: node,
|
|
117
|
-
smart:
|
|
171
|
+
smart: isSmartComponent(initializer)
|
|
118
172
|
};
|
|
119
173
|
}
|
|
120
174
|
function parseComponentInfo(text, filename, options) {
|
|
121
175
|
const sourceFile = ts.createSourceFile(path.resolve(filename), text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
122
176
|
const components = [];
|
|
177
|
+
const namedExports = namedExportedLocalNames(sourceFile);
|
|
123
178
|
for (const statement of sourceFile.statements) {
|
|
124
|
-
const
|
|
125
|
-
if (!exported && !options?.includeNonExported) continue;
|
|
179
|
+
const statementExported = isExported(statement);
|
|
126
180
|
if (ts.isFunctionDeclaration(statement)) {
|
|
181
|
+
const name = statement.name?.text;
|
|
182
|
+
if (!options?.includeNonExported && !statementExported && (!name || !namedExports.has(name))) continue;
|
|
127
183
|
const component = componentFromFunction(statement);
|
|
128
184
|
if (component) components.push(component);
|
|
129
185
|
continue;
|
|
130
186
|
}
|
|
131
187
|
if (ts.isVariableStatement(statement)) {
|
|
132
188
|
for (const declaration of statement.declarationList.declarations) {
|
|
189
|
+
const name = ts.isIdentifier(declaration.name) ? declaration.name.text : void 0;
|
|
190
|
+
if (!options?.includeNonExported && !statementExported && (!name || !namedExports.has(name))) continue;
|
|
133
191
|
const component = componentFromVariable(declaration);
|
|
134
192
|
if (component) components.push(component);
|
|
135
193
|
}
|