@@ -10,8 +10,17 @@ const { HtmlValidate } = require('html-validate')
1010const validatorErrorPage = fs . readFileSync ( path . join ( __dirname , 'templates/errorPage.html' ) )
1111
1212module . exports = ( app , params ) => {
13- params = params || { }
14- const render = app . response . render
13+ if ( Object . prototype . hasOwnProperty . call ( app , 'listen' ) || typeof app . listen === 'function' ) {
14+ params = params || { } // two arguments
15+ } else {
16+ params = app // one argument
17+ app = null
18+ }
19+
20+ let render
21+ if ( app ) {
22+ render = app . response . render
23+ }
1524 let resModel
1625
1726 // sanitize config
@@ -71,91 +80,100 @@ module.exports = (app, params) => {
7180 // instantiate the validator module
7281 const htmlValidate = new HtmlValidate ( rules )
7382
74- // use some method overload trickery to store a usable model reference
75- app . response . render = function ( view , model , callback ) {
76- // store a reference to the model if exceptions are being used and a model was set
77- if ( model && typeof model === 'object' ) {
78- resModel = model
79- }
83+ function validate ( body , res ) {
84+ // run the validator against the response body
85+ const report = htmlValidate . validateString ( body )
8086
81- render . apply ( this , arguments )
82- }
87+ if ( ! report . valid ) {
88+ const errorMap = new Map ( )
89+ let parsedErrors = ''
90+
91+ for ( const error of report . results [ 0 ] . messages ) {
92+ const message = escapeHtmlEntities ( error . message )
93+
94+ // first line is error message
95+ parsedErrors += `${ message } \n`
8396
84- // validate responses under the right conditions
85- app . use ( tamper ( ( req , res ) => {
86- /**
87- * Skip validation when:
88- * - HTTP status is not 200 (don't validate error pages)
89- * - content-type is not text/html (don't validate non-HTML responses)
90- * - No exception applies
91- */
92- if ( res . statusCode === 200 && res . getHeader ( 'Content-Type' ) && res . getHeader ( 'Content-Type' ) . includes ( 'text/html' ) && ! validatorExceptions ( req , res ) ) {
93- // start validating the response body
94- return body => {
95- // run the validator against the response body
96- const report = htmlValidate . validateString ( body )
97-
98- if ( ! report . valid ) {
99- const errorMap = new Map ( )
100- let parsedErrors = ''
101-
102- for ( const error of report . results [ 0 ] . messages ) {
103- const message = escapeHtmlEntities ( error . message )
104-
105- // first line is error message
106- parsedErrors += `${ message } \n`
107-
108- // next line is line and column numbers
109- parsedErrors += `At line ${ error . line } , column ${ error . column } \n\n`
110-
111- // add error message and line number to map
112- errorMap . set ( error . line , error . message )
113- }
114-
115- const errorList = `<h2>Errors:</h2>\n<code class="validatorErrors">${ parsedErrors } </code>`
116-
117- // start building out stylized markup block
118- let formattedHTML = '<pre class=\'markup\'>\n<code class="language-html">\n'
119- const markupArray = body . split ( '\n' )
120-
121- // add line number highlighting for detected errors
122- for ( let i = 0 ; i < markupArray . length ; i ++ ) {
123- const markupLine = markupArray [ i ]
124- if ( errorMap . has ( i + 1 ) ) {
125- formattedHTML += `<span title='${ errorMap . get ( i + 1 ) } ' class='line-numbers error'>`
126- formattedHTML += Prism . highlight ( `${ markupLine } ` , Prism . languages . markup )
127- formattedHTML += '</span>'
128- } else {
129- formattedHTML += '<span class=\'line-numbers\'>'
130- formattedHTML += Prism . highlight ( `${ markupLine } ` , Prism . languages . markup )
131- formattedHTML += '</span>'
132- }
133- }
134-
135- // cap off the stylized markup blocks
136- formattedHTML += '</code>\n</pre>'
137- formattedHTML = `<h2>Markup used:</h2>\n${ formattedHTML } `
138-
139- // use 500 status for the validation error
140- res . status ( 500 )
141-
142- // build a model that includes error data, markup, and styling
143- const model = {
144- prismStyle : prismStyleSheet . toString ( ) ,
145- preWidth : markupArray . length . toString ( ) . length * 8 ,
146- errors : errorList ,
147- markup : formattedHTML ,
148- rawMarkup : body
149- }
150-
151- // parse error page template and replace response body with it
152- body = template ( validatorErrorPage , model )
97+ // next line is line and column numbers
98+ parsedErrors += `At line ${ error . line } , column ${ error . column } \n\n`
99+
100+ // add error message and line number to map
101+ errorMap . set ( error . line , error . message )
102+ }
103+
104+ const errorList = `<h2>Errors:</h2>\n<code class="validatorErrors">${ parsedErrors } </code>`
105+
106+ // start building out stylized markup block
107+ let formattedHTML = '<pre class=\'markup\'>\n<code class="language-html">\n'
108+ const markupArray = body . split ( '\n' )
109+
110+ // add line number highlighting for detected errors
111+ for ( let i = 0 ; i < markupArray . length ; i ++ ) {
112+ const markupLine = markupArray [ i ]
113+ if ( errorMap . has ( i + 1 ) ) {
114+ formattedHTML += `<span title='${ errorMap . get ( i + 1 ) } ' class='line-numbers error'>`
115+ formattedHTML += Prism . highlight ( `${ markupLine } ` , Prism . languages . markup )
116+ formattedHTML += '</span>'
117+ } else {
118+ formattedHTML += '<span class=\'line-numbers\'>'
119+ formattedHTML += Prism . highlight ( `${ markupLine } ` , Prism . languages . markup )
120+ formattedHTML += '</span>'
153121 }
122+ }
123+
124+ // cap off the stylized markup blocks
125+ formattedHTML += '</code>\n</pre>'
126+ formattedHTML = `<h2>Markup used:</h2>\n${ formattedHTML } `
127+
128+ // use 500 status for the validation error
129+ if ( res ) {
130+ res . status ( 500 )
131+ }
154132
155- return body
133+ // build a model that includes error data, markup, and styling
134+ const model = {
135+ prismStyle : prismStyleSheet . toString ( ) ,
136+ preWidth : markupArray . length . toString ( ) . length * 8 ,
137+ errors : errorList ,
138+ markup : formattedHTML ,
139+ rawMarkup : body
156140 }
141+
142+ // parse error page template and replace response body with it
143+ body = template ( validatorErrorPage , model )
157144 }
158- } ) )
145+
146+ return body
147+ }
148+
149+ if ( app ) {
150+ // use some method overload trickery to store a usable model reference
151+ app . response . render = function ( view , model , callback ) {
152+ // store a reference to the model if exceptions are being used and a model was set
153+ if ( model && typeof model === 'object' ) {
154+ resModel = model
155+ }
156+
157+ render . apply ( this , arguments )
158+ }
159+
160+ // validate responses under the right conditions
161+ app . use ( tamper ( ( req , res ) => {
162+ /**
163+ * Skip validation when:
164+ * - HTTP status is not 200 (don't validate error pages)
165+ * - content-type is not text/html (don't validate non-HTML responses)
166+ * - No exception applies
167+ */
168+ if ( res . statusCode === 200 && res . getHeader ( 'Content-Type' ) && res . getHeader ( 'Content-Type' ) . includes ( 'text/html' ) && ! validatorExceptions ( req , res ) ) {
169+ return ( body ) => {
170+ return validate ( body , res )
171+ }
172+ }
173+ } ) )
174+ }
175+
176+ return validate // export validate function for general use
159177}
160178
161179/*
0 commit comments