@@ -88,6 +88,10 @@ function runScanner() {
8888 results . push ( { name, status : "fail" , detail, points } ) ;
8989 }
9090
91+ function esc ( str ) {
92+ return String ( str ) . replace ( / & / g, "&" ) . replace ( / < / g, "<" ) . replace ( / > / g, ">" ) . replace ( / " / g, """ ) ;
93+ }
94+
9195 try {
9296 const title = doc . querySelector ( "title" ) ;
9397 const titleText = title ?. textContent ?. trim ( ) || "" ;
@@ -98,17 +102,17 @@ function runScanner() {
98102 } else if ( titleLen < 30 ) {
99103 warn (
100104 "Title tag" ,
101- `Too short (${ titleLen } chars). Aim for 50–60. Current: "${ titleText } "` ,
105+ `Too short (${ titleLen } chars). Aim for 50–60. Current: "${ esc ( titleText ) } "` ,
102106 5
103107 ) ;
104108 } else if ( titleLen > 70 ) {
105109 warn (
106110 "Title tag" ,
107- `Too long (${ titleLen } chars). Aim for 50–60. Current: "${ titleText . substring ( 0 , 60 ) } … "` ,
111+ `Too long (${ titleLen } chars). Aim for 50–60. Current: "${ esc ( titleText . substring ( 0 , 60 ) ) } \u2026 "` ,
108112 5
109113 ) ;
110114 } else {
111- pass ( "Title tag" , `${ titleLen } chars — good length. "${ titleText } "` , 10 ) ;
115+ pass ( "Title tag" , `${ titleLen } chars — good length. "${ esc ( titleText ) } "` , 10 ) ;
112116 }
113117
114118 const metaDesc = doc . querySelector ( 'meta[name="description"]' ) ;
@@ -141,7 +145,7 @@ function runScanner() {
141145 } else {
142146 pass (
143147 "H1 heading" ,
144- `One H1 found: "${ h1s [ 0 ] . textContent . trim ( ) . substring ( 0 , 60 ) } "` ,
148+ `One H1 found: "${ esc ( h1s [ 0 ] . textContent . trim ( ) . substring ( 0 , 60 ) ) } "` ,
145149 10
146150 ) ;
147151 }
@@ -250,7 +254,7 @@ function runScanner() {
250254 } else {
251255 pass (
252256 "Canonical URL" ,
253- `Present: <code>${ canonicalHref . substring ( 0 , 50 ) } </code>` ,
257+ `Present: <code>${ esc ( canonicalHref . substring ( 0 , 50 ) ) } </code>` ,
254258 10
255259 ) ;
256260 }
@@ -266,7 +270,7 @@ function runScanner() {
266270 5
267271 ) ;
268272 } else {
269- pass ( "Robots meta" , `Set to: <code>${ robotsContent } </code>` , 10 ) ;
273+ pass ( "Robots meta" , `Set to: <code>${ esc ( robotsContent ) } </code>` , 10 ) ;
270274 }
271275
272276 const jsonLd = doc . querySelectorAll ( 'script[type="application/ld+json"]' ) ;
@@ -282,11 +286,11 @@ function runScanner() {
282286 types = Array . from ( jsonLd )
283287 . map ( ( el ) => JSON . parse ( el . textContent ) )
284288 . filter ( Boolean )
285- . map ( ( d ) => d [ "@type" ] || d [ "@graph" ] ? "Graph" : "Unknown" ) ;
289+ . map ( ( d ) => d [ "@type" ] || ( d [ "@graph" ] ? "Graph" : "Unknown" ) ) ;
286290 } catch ( _ ) { }
287291 pass (
288292 "Structured data" ,
289- `${ jsonLd . length } JSON-LD block(s) found${ types . length ? ": " + types . slice ( 0 , 3 ) . join ( ", " ) : "" } .` ,
293+ `${ jsonLd . length } JSON-LD block(s) found${ types . length ? ": " + types . slice ( 0 , 3 ) . map ( esc ) . join ( ", " ) : "" } .` ,
290294 10
291295 ) ;
292296 }
@@ -303,7 +307,7 @@ function runScanner() {
303307 if ( vpContent . includes ( "width=device-width" ) ) {
304308 pass ( "Mobile viewport" , "Present with width=device-width — mobile-friendly." , 10 ) ;
305309 } else {
306- warn ( "Mobile viewport" , " Found but missing width=device-width." , 5 ) ;
310+ warn ( "Mobile viewport" , ` Found but missing width=device-width. Content: <code> ${ esc ( vpContent ) } </code>` , 5 ) ;
307311 }
308312 }
309313
@@ -315,7 +319,7 @@ function runScanner() {
315319 5
316320 ) ;
317321 } else {
318- pass ( "Language" , `Set to <code>${ htmlLang } </code>.` , 10 ) ;
322+ pass ( "Language" , `Set to <code>${ esc ( htmlLang ) } </code>.` , 10 ) ;
319323 }
320324
321325 const totalPoints = results . reduce ( ( sum , r ) => sum + r . points , 0 ) ;
@@ -331,7 +335,7 @@ function runScanner() {
331335 {
332336 name : "Scanner error" ,
333337 status : "fail" ,
334- detail : `Could not complete scan: ${ e . message } . The page may have restricted access to its DOM.` ,
338+ detail : `Could not complete scan: ${ esc ( e . message ) } . The page may have restricted access to its DOM.` ,
335339 points : 0 ,
336340 } ,
337341 ] ,
@@ -358,7 +362,7 @@ function renderResults(data) {
358362 <div class="check-item">
359363 <div class="check-header">
360364 <span class="check-name">${ r . name } </span>
361- <span class="check-status ${ r . status } ">${ r . status === "pass" ? "✓ Pass" : r . status === "warn" ? "⚠ Warn" : "✗ Fail" } </span>
365+ <span class="check-status ${ r . status } ">${ r . status === "pass" ? "\u2713 Pass" : r . status === "warn" ? "\u26a0 Warn" : "\u2717 Fail" } </span>
362366 </div>
363367 <div class="check-detail">${ r . detail } </div>
364368 </div>`
0 commit comments