import * as Lint from "tslint" ; import * as ts from "typescript" ; import { addImportToFile } from "./utils/addImportToFile" ; import { replaceTagName } from "./utils/replaceTagName" ; const PATTERN = /^(h[1-6]|code|pre|blockquote|table)$/ ; export class Rule extends Lint . Rules . AbstractRule { public static metadata : Lint . IRuleMetadata = { ruleName : "blueprint-html-components" , description : "Enforce usage of Blueprint components over JSX intrinsic elements." , options : null , optionsDescription : "Not configurable" , optionExamples : [ "true" ] , type : "style" , typescriptOnly : false , } ; public static getFailure ( componentName ) { return `use Blueprint <${ componentName }> component instead of JSX intrinsic element.` ; } public apply ( sourceFile ) { return this . applyWithFunction ( sourceFile , walk ) ; } } function walk ( ctx ) { const tagFailures = [ ] ; ts . forEachChild ( ctx . sourceFile , function cb ( node ) : void { if ( ts . isJsxOpeningElement ( node ) || ts . isJsxSelfClosingElement ( node ) ) { const match = PATTERN . exec ( node . tagName . getFullText ( ) ) ; if ( match != null ) { const newTagName = getNewTagName ( match [ 1 ] ) ; const replacements = [ replaceTagName ( node . tagName , newTagName ) ] ; if ( ts . isJsxOpeningElement ( node ) ) { const [ closingNode ] = node . parent ! . getChildren ( ) . filter ( ts . isJsxClosingElement ) ; replacements . push ( replaceTagName ( closingNode . tagName , newTagName ) ) ; } tagFailures . push ( { jsxTag : node . tagName , newTagName , replacements } ) ; } } return ts . forEachChild ( node , cb ) ; } ) ; if ( tagFailures . length === 0 ) { return ; } const importsToAdd = addImportToFile ( ctx . sourceFile , tagFailures . map ( m => m . newTagName ) , "@blueprintjs/core" ) ; tagFailures [ 0 ] . replacements . push ( importsToAdd ) ; tagFailures . forEach ( ( { jsxTag , newTagName , replacements } ) => ctx . addFailureAt ( jsxTag . getFullStart ( ) , jsxTag . getFullWidth ( ) , Rule . getFailure ( newTagName ) , replacements ) ) ; } function getNewTagName ( tagName ) { switch ( tagName ) { case "table" : return "HTMLTable" ; default : return tagName . charAt ( 0 ) . toUpperCase ( ) + tagName . slice ( 1 ) ; } }