📄 no-dynamic-tests¶
📊 Analysis Summary¶
| Metric | Count |
|---|---|
| 🔧 Functions | 2 |
| 📦 Imports | 4 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/eslint-plugin-internal/src/rules/no-dynamic-tests.ts
📤 Default Export¶
| Property | Value |
|---|---|
name |
'no-dynamic-tests' |
meta.type |
'problem' |
meta.docs.description |
'Disallow dynamic syntax in RuleTester test arrays' |
meta.fixable |
'code' |
meta.messages.noDynamicTests |
'Dynamic syntax is not allowed in RuleTester test arrays. Use static values only.' |
meta.messages.noFormatNotAllowedHere |
'Dynamic syntax is not allowed in RuleTester test arrays. noFormat is only for the input code, not for other properti... |
meta.schema |
[] |
defaultOptions |
[] |
Entry point: create — documented under Functions.
📦 Imports¶
| Name | Source |
|---|---|
TSESTree |
@typescript-eslint/utils |
AST_NODE_TYPES |
@typescript-eslint/utils |
getRuleTesterCallObject |
../util/getRuleTesterCallObject.js |
createRule |
../util/index.js |
Functions¶
create(context: any): { CallExpression(node: any): void; }¶
Parameters:
contextany
Returns: { CallExpression(node: any): void; }
Calls:
context.reportnode.expressions.forEachreportDynamicElementsnode.elements.forEachnode.properties.forEachkeyToValidate.includesfieldStack.atfixer.removegetRuleTesterCallObject (from ../util/getRuleTesterCallObject.js)prop.value.elements.forEach
Internal Comments:
// InvalidTestCase extends ValidTestCase (x2)
// allow noFormat for the 'code' field only (or if a valid test case is using the string shorthand)
Code
create(context) {
function reportDynamicElements(
node: TSESTree.Node,
fieldStack: string[],
): void {
switch (node.type) {
case AST_NODE_TYPES.Identifier:
if (node.name === 'undefined') {
break;
}
context.report({
node,
messageId: 'noDynamicTests',
});
break;
case AST_NODE_TYPES.CallExpression:
case AST_NODE_TYPES.SpreadElement:
case AST_NODE_TYPES.BinaryExpression:
case AST_NODE_TYPES.ConditionalExpression:
case AST_NODE_TYPES.MemberExpression:
context.report({
node,
messageId: 'noDynamicTests',
});
break;
case AST_NODE_TYPES.TemplateLiteral:
node.expressions.forEach(expr => {
reportDynamicElements(expr, fieldStack);
});
break;
case AST_NODE_TYPES.ArrayExpression:
node.elements.forEach(element => {
if (element) {
reportDynamicElements(element, fieldStack);
}
});
break;
case AST_NODE_TYPES.ObjectExpression:
node.properties.forEach(prop => {
if (prop.type === AST_NODE_TYPES.SpreadElement) {
context.report({
node: prop,
messageId: 'noDynamicTests',
});
} else {
// InvalidTestCase extends ValidTestCase
const keyToValidate = [
'code',
'errors',
'output',
'suggestions',
'messageId',
];
if (
prop.key.type === AST_NODE_TYPES.Identifier &&
keyToValidate.includes(prop.key.name)
) {
reportDynamicElements(prop.value, [
...fieldStack,
prop.key.name,
]);
} else if (
prop.key.type === AST_NODE_TYPES.Literal &&
keyToValidate.includes(prop.key.value as string)
) {
reportDynamicElements(prop.value, [
...fieldStack,
prop.key.value as string,
]);
}
}
});
break;
case AST_NODE_TYPES.TaggedTemplateExpression: {
if (
node.tag.type === AST_NODE_TYPES.Identifier &&
node.tag.name === 'noFormat'
) {
// allow noFormat for the 'code' field only (or if a valid test case is using the string shorthand)
if (
fieldStack.length === 1 ||
(fieldStack.length === 2 && fieldStack.at(-1) === 'code')
) {
break;
}
context.report({
node: node.tag,
messageId: 'noFormatNotAllowedHere',
fix: fixer => fixer.remove(node.tag),
});
break;
}
context.report({
node: node.tag,
messageId: 'noDynamicTests',
});
break;
}
case AST_NODE_TYPES.Literal:
default:
break;
}
}
return {
CallExpression(node) {
const testObject = getRuleTesterCallObject(node);
if (!testObject) {
return;
}
for (const prop of testObject.properties) {
const isTestCases =
prop.type === AST_NODE_TYPES.Property &&
prop.key.type === AST_NODE_TYPES.Identifier &&
(prop.key.name === 'valid' || prop.key.name === 'invalid');
if (isTestCases) {
const propName = (prop.key as TSESTree.Identifier).name;
if (prop.value.type === AST_NODE_TYPES.ArrayExpression) {
prop.value.elements.forEach(element => {
if (element) {
reportDynamicElements(element, [propName]);
}
});
} else {
context.report({
node: prop.value,
messageId: 'noDynamicTests',
});
}
}
}
},
};
}
Internal helpers¶
Declared inside another function in this file.
reportDynamicElements(node: TSESTree.Node, fieldStack: string[]): void¶
Parameters:
nodeTSESTree.NodefieldStackstring[]
Returns: void
Calls:
context.reportnode.expressions.forEachreportDynamicElementsnode.elements.forEachnode.properties.forEachkeyToValidate.includesfieldStack.atfixer.remove
Internal Comments:
// InvalidTestCase extends ValidTestCase (x2)
// allow noFormat for the 'code' field only (or if a valid test case is using the string shorthand)
Code
function reportDynamicElements(
node: TSESTree.Node,
fieldStack: string[],
): void {
switch (node.type) {
case AST_NODE_TYPES.Identifier:
if (node.name === 'undefined') {
break;
}
context.report({
node,
messageId: 'noDynamicTests',
});
break;
case AST_NODE_TYPES.CallExpression:
case AST_NODE_TYPES.SpreadElement:
case AST_NODE_TYPES.BinaryExpression:
case AST_NODE_TYPES.ConditionalExpression:
case AST_NODE_TYPES.MemberExpression:
context.report({
node,
messageId: 'noDynamicTests',
});
break;
case AST_NODE_TYPES.TemplateLiteral:
node.expressions.forEach(expr => {
reportDynamicElements(expr, fieldStack);
});
break;
case AST_NODE_TYPES.ArrayExpression:
node.elements.forEach(element => {
if (element) {
reportDynamicElements(element, fieldStack);
}
});
break;
case AST_NODE_TYPES.ObjectExpression:
node.properties.forEach(prop => {
if (prop.type === AST_NODE_TYPES.SpreadElement) {
context.report({
node: prop,
messageId: 'noDynamicTests',
});
} else {
// InvalidTestCase extends ValidTestCase
const keyToValidate = [
'code',
'errors',
'output',
'suggestions',
'messageId',
];
if (
prop.key.type === AST_NODE_TYPES.Identifier &&
keyToValidate.includes(prop.key.name)
) {
reportDynamicElements(prop.value, [
...fieldStack,
prop.key.name,
]);
} else if (
prop.key.type === AST_NODE_TYPES.Literal &&
keyToValidate.includes(prop.key.value as string)
) {
reportDynamicElements(prop.value, [
...fieldStack,
prop.key.value as string,
]);
}
}
});
break;
case AST_NODE_TYPES.TaggedTemplateExpression: {
if (
node.tag.type === AST_NODE_TYPES.Identifier &&
node.tag.name === 'noFormat'
) {
// allow noFormat for the 'code' field only (or if a valid test case is using the string shorthand)
if (
fieldStack.length === 1 ||
(fieldStack.length === 2 && fieldStack.at(-1) === 'code')
) {
break;
}
context.report({
node: node.tag,
messageId: 'noFormatNotAllowedHere',
fix: fixer => fixer.remove(node.tag),
});
break;
}
context.report({
node: node.tag,
messageId: 'noDynamicTests',
});
break;
}
case AST_NODE_TYPES.Literal:
default:
break;
}
}
Generated by Syntax Scribe