license import * as Lint from "tslint" ; import { isJsxElement } from "tsutils/typeguard/3.0" ; import * as ts from "typescript" ; export class Rule extends Lint . Rules . AbstractRule { public static metadata : Lint . IRuleMetadata = { ruleName : "jsx-self-close" , description : "Checks that JSX elements with no children are self-closing" , options : null , optionsDescription : "" , optionExamples : [ "true" ] , type : "style" , typescriptOnly : false , } ; public static FAILURE_STRING = "JSX elements with no children must be self-closing" ; public apply ( sourceFile ) { return this . applyWithFunction ( sourceFile , walk ) ; } } function walk ( ctx ) { return ts . forEachChild ( ctx . sourceFile , function cb ( node ) : void { if ( isJsxElement ( node ) ) { const missingOpeningOrClosingTag = node . openingElement == null || node . closingElement == null ; const textIsEmpty = node . children . length === 1 && node . children [ 0 ] . kind === ts . SyntaxKind . JsxText && node . children [ 0 ] . getText ( ) === "" ; const noChildren = node . children . length === 0 || textIsEmpty ; if ( ! missingOpeningOrClosingTag && noChildren ) { const openingElementText = node . openingElement . getFullText ( ) ; const selfClosingNode = openingElementText . slice ( 0 , openingElementText . lastIndexOf ( ">" ) ) + "/>" ; const fix = new Lint . Replacement ( node . getStart ( ) , node . getWidth ( ) , selfClosingNode ) ; ctx . addFailureAtNode ( node , Rule . FAILURE_STRING , fix ) ; } else if ( noChildren ) { ctx . addFailureAtNode ( node , Rule . FAILURE_STRING ) ; } } return ts . forEachChild ( node , cb ) ; } ) ; }