add lint/voidDomElementNoChildren for React
MODIFY
packages/@romejs/diagnostics/categories.ts
packages/@romejs/diagnostics/categories.ts
@@ -141,4 +141,5 @@ type LintDiagnosticCategory =
| 'lint/stylePropObject'
| 'lint/undeclaredVariables'
| 'lint/unsafeNegation'
- | 'lint/unusedVariables';
+ | 'lint/unusedVariables'
+ | 'lint/voidDomElementsNoChildren';

MODIFY
packages/@romejs/diagnostics/descriptions.ts
packages/@romejs/diagnostics/descriptions.ts
@@ -358,6 +358,10 @@ export const descriptions = createMessages({
category: 'lint/preferWhile',
message: 'A while loop should be used over a for loop',
},
+ REACT_JSX_VOID_DOM_ELEMENTS_NO_CHILDREN: (element, properties) => ({
+ category: 'lint/voidDomElementsNoChildren',
+ message: markup`<emphasis>${element}</emphasis> is a void element tag and must not have <emphasis>${properties}</emphasis>.`,
+ }),
REACT_JSX_NO_COMMENT_TEXT: {
category: 'lint/jsxNoCommentText',
message: 'Comments inside children should be placed in braces',

MODIFY
packages/@romejs/js-compiler/lint/rules/index.ts
packages/@romejs/js-compiler/lint/rules/index.ts
@@ -57,6 +57,7 @@ import stylePropObject from './react/stylePropObject';
import undeclaredVariables from './regular/undeclaredVariables';
import unsafeNegation from './regular/unsafeNegation';
import unusedVariables from './regular/unusedVariables';
+import voidDomElementsNoChildren from './react/voidDomElementsNoChildren';
export const lintTransforms = [
camelCase,
@@ -110,4 +111,5 @@ export const lintTransforms = [
undeclaredVariables,
unsafeNegation,
unusedVariables,
+ voidDomElementsNoChildren
];

ADD
packages/@romejs/js-compiler/lint/rules/react/voidDomElementsNoChildren.ts
+/**
+* Copyright (c) Facebook, Inc. and its affiliates.
+*
+* This source code is licensed under the MIT license found in the
+* LICENSE file in the root directory of this source tree.
+*/
+
+import {Path} from '@romejs/js-compiler';
+
+import {AnyNode, jsxElement} from '@romejs/js-ast';
+import {descriptions} from '@romejs/diagnostics';
+import { TransformExitResult } from '@romejs/js-compiler/types';
+
+const VOID_DOM_ELEMENTS = new Set([
+ 'area',
+ 'base',
+ 'br',
+ 'col',
+ 'embed',
+ 'hr',
+ 'img',
+ 'input',
+ 'keygen',
+ 'link',
+ 'menuitem',
+ 'meta',
+ 'param',
+ 'source',
+ 'track',
+ 'wbr',
+]);
+
+export default {
+ name: 'voidDomElementsNoChildren',
+ enter(path: Path): TransformExitResult {
+ const {node, context} = path;
+
+ if (
+ node.type === 'JSXElement' &&
+ node.name.type === 'JSXIdentifier' &&
+ VOID_DOM_ELEMENTS.has(node.name.name)
+ ) {
+ const element = node.name.name;
+
+ let properties = new Set();
+
+ if (node.children.length !== 0) {
+ properties.add('children');
+ }
+
+ const newAttributes = [];
+ for (const attribute of node.attributes) {
+ if (attribute.type === 'JSXAttribute') {
+ const property = attribute.name.name;
+ if (property === 'children') {
+ properties.add('children');
+ } else if (property === 'dangerouslySetInnerHTML') {
+ properties.add('dangerouslySetInnerHTML');
+ } else {
+ newAttributes.push(attribute);
+ }
+ }
+ }
+
+ if (properties.size > 0) {
+ return context.addFixableDiagnostic(
+ {
+ old: node,
+ fixed: {
+ ...node,
+ attributes: newAttributes,
+ children: [],
+ selfClosing: true
+ }
+ },
+ descriptions.LINT.REACT_JSX_VOID_DOM_ELEMENTS_NO_CHILDREN(element, Array.from(properties).join(" or ")),
+ );
+ }
+ }
+
+
+ return node;
+ },
+};

add lint/voidDomElementNoChildren for React