-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement normalization using base class (#2276)
- add onyx-component as base-class to every component - put normalize.apply in onyx-componet class - add linting rool
- Loading branch information
1 parent
5c1c4f1
commit 41c2adf
Showing
74 changed files
with
313 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
packages/eslint-plugin/src/rules/require-root-class.cjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
"use strict"; | ||
|
||
/** | ||
* @typedef {import('vue-eslint-parser').AST.VDirective} VDirective | ||
* @typedef {import('vue-eslint-parser').AST.VElement} VElement | ||
* @typedef {import('vue-eslint-parser').AST.VAttribute} VAttribute | ||
* @typedef {import('vue-eslint-parser').AST.VIdentifier} VIdentifier | ||
* @typedef {import('eslint').Rule.RuleContext} RuleContext | ||
* @typedef {import('eslint').Rule.RuleListener} RuleListener | ||
*/ | ||
|
||
/** | ||
* Check whether the given start tag has specific directive. | ||
* @param {VElement} node The start tag node to check. | ||
* @param {string} name The directive name to check. | ||
* @param {string} [argument] The directive argument to check. | ||
* @returns {boolean} `true` if the start tag has the directive. | ||
*/ | ||
function hasDirective(node, name, argument) { | ||
return Boolean(getDirective(node, name, argument)); | ||
} | ||
|
||
/** | ||
* Get the directive which has the given name. | ||
* @param {VElement} node The start tag node to check. | ||
* @param {string} name The directive name to check. | ||
* @param {string} [argument] The directive argument to check. | ||
* @returns {VDirective | null} The found directive. | ||
*/ | ||
function getDirective(node, name, argument) { | ||
return ( | ||
node.startTag.attributes.find( | ||
/** | ||
* @param {VAttribute | VDirective} node | ||
* @returns {node is VDirective} | ||
*/ | ||
(node) => | ||
node.directive && | ||
node.key.name.name === name && | ||
(argument === undefined || | ||
(node.key.argument && | ||
node.key.argument.type === "VIdentifier" && | ||
node.key.argument.name) === argument), | ||
) || null | ||
); | ||
} | ||
|
||
module.exports = { | ||
meta: { | ||
type: "problem", | ||
docs: { | ||
description: "disallow adding root nodes to the template", | ||
}, | ||
fixable: null, | ||
schema: [], | ||
messages: { | ||
multipleRoot: "The template root requires exactly one element.", | ||
textRoot: "The template root requires an element rather than texts.", | ||
disallowedDirective: "The template root disallows 'v-for' directives.", | ||
missingClass: "The root element is missing the 'onyx-component' class.", | ||
}, | ||
}, | ||
/** | ||
* @param {RuleContext} context - The rule context. | ||
* @returns {RuleListener} AST event handlers. | ||
*/ | ||
create(context) { | ||
const sourceCode = context.getSourceCode(); | ||
|
||
return { | ||
Program(program) { | ||
const element = program.templateBody; | ||
if (element == null) { | ||
return; | ||
} | ||
|
||
const rootElements = []; | ||
let extraElement = null; | ||
let vIf = false; | ||
for (const child of element.children) { | ||
if (child.type === "VElement") { | ||
if (rootElements.length === 0) { | ||
rootElements.push(child); | ||
vIf = hasDirective(child, "if"); | ||
} else if (vIf && hasDirective(child, "else-if")) { | ||
rootElements.push(child); | ||
} else if (vIf && hasDirective(child, "else")) { | ||
rootElements.push(child); | ||
vIf = false; | ||
} else { | ||
extraElement = child; | ||
} | ||
} else if (sourceCode.getText(child).trim() !== "") { | ||
context.report({ | ||
node: child, | ||
messageId: "textRoot", | ||
}); | ||
return; | ||
} | ||
} | ||
|
||
if (extraElement == null) { | ||
for (const element of rootElements) { | ||
const tag = element.startTag; | ||
const name = element.name; | ||
|
||
if (name === "template" || name === "slot") { | ||
return; | ||
} | ||
if (element.name.startsWith("onyx")) { | ||
return true; | ||
} | ||
// Check for existence of base class | ||
/** | ||
* @type {VIdentifier, VDirectiveKey} | ||
*/ | ||
const has = element.startTag.attributes.some(({ key, value }) => { | ||
const isClassAttribute = | ||
(key.type === "VIdentifier" && key.name === "class") || | ||
(key.type === "VDirectiveKey" && | ||
key.argument?.type === "VIdentifier" && | ||
key.argument.name === "class"); | ||
if (!isClassAttribute) return false; | ||
|
||
// static class: class="..." | ||
if (value?.value) { | ||
return value.value.includes("onyx-component"); | ||
} | ||
|
||
// dynamic class: :class="..." | ||
if (value?.expression) { | ||
const expression = value.expression; | ||
|
||
if (expression.type === "ArrayExpression") { | ||
// :class="['class1', 'onyx-component']" | ||
return expression.elements.some( | ||
(element) => element.type === "Literal" && element.value === "onyx-component", | ||
); | ||
} else if (expression.type === "ObjectExpression") { | ||
// :class="{ 'onyx-component': true, 'class2': false }" | ||
return expression.properties.some((property) => { | ||
if (property.type === "SpreadElement") { | ||
return false; | ||
} | ||
return ( | ||
property.key.type === "Literal" && | ||
property.key.value === "onyx-component" && | ||
property.value.type === "Literal" && | ||
Boolean(property.value.value) === true | ||
); | ||
}); | ||
} else if (expression.type === "Literal") { | ||
// :class="'onyx-component'" | ||
return expression.value === "onyx-component"; | ||
} | ||
} | ||
|
||
return false; | ||
}); | ||
|
||
if (!has) { | ||
context.report({ | ||
node: tag, | ||
loc: tag.loc, | ||
messageId: "missingClass", | ||
}); | ||
} | ||
|
||
if (hasDirective(element, "for")) { | ||
context.report({ | ||
node: tag, | ||
loc: tag.loc, | ||
messageId: "disallowedDirective", | ||
}); | ||
} | ||
} | ||
} else if (extraElement?.name === "teleport") { | ||
// Exclude teleport from this rule | ||
return true; | ||
} else { | ||
context.report({ | ||
node: extraElement, | ||
loc: extraElement.loc, | ||
messageId: "multipleRoot", | ||
}); | ||
} | ||
}, | ||
}; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.