@@ -1898,6 +1898,86 @@ describe("what the preview loaded", () => {
18981898 expect ( affectsPreview ( projectDir , "im" ) ) . toBe ( false ) ;
18991899 } ) ;
19001900
1901+ it ( "does not walk entity-quoted inline image data as a filesystem path" , ( ) => {
1902+ const projectDir = createProjectDir ( ) ;
1903+ const data = `data:image/png;base64,${ "A/" . repeat ( 128 ) } ` ;
1904+ for ( const quote of [ """ , "'" , """ , """ , "'" , "'" ] ) {
1905+ recordPreviewReferences (
1906+ projectDir ,
1907+ `<i style="background-image:url(${ quote } ${ data } ${ quote } )"></i>` ,
1908+ ) ;
1909+ recordPreviewBuilt ( projectDir ) ;
1910+ expect ( affectsPreview ( projectDir , `${ quote } ${ data } ${ quote } ` ) ) . toBe ( false ) ;
1911+ }
1912+ recordPreviewBuilt ( projectDir ) ;
1913+ expect ( affectsPreview ( projectDir , `"${ data } "` ) ) . toBe ( false ) ;
1914+ } ) ;
1915+
1916+ it ( "tracks entity-quoted local image paths after decoding their HTML entities" , ( ) => {
1917+ const projectDir = createProjectDir ( ) ;
1918+ recordPreviewReferences (
1919+ projectDir ,
1920+ '<i style="background-image:url("assets/a&b.png")"></i>' ,
1921+ ) ;
1922+ recordPreviewBuilt ( projectDir ) ;
1923+ expect ( affectsPreview ( projectDir , "assets/a&b.png" ) ) . toBe ( true ) ;
1924+ } ) ;
1925+
1926+ it ( "keeps entities literal in stylesheet URLs, as CSS raw text does" , ( ) => {
1927+ const projectDir = createProjectDir ( ) ;
1928+ recordPreviewReferences (
1929+ projectDir ,
1930+ "<style>i { background:url('assets/a&b.png') }</style>" ,
1931+ ) ;
1932+ recordPreviewBuilt ( projectDir ) ;
1933+ expect ( affectsPreview ( projectDir , "assets/a&b.png" ) ) . toBe ( true ) ;
1934+ expect ( affectsPreview ( projectDir , "assets/a&b.png" ) ) . toBe ( false ) ;
1935+ } ) ;
1936+
1937+ it ( "does not mistake style-looking text for an HTML style attribute" , ( ) => {
1938+ const projectDir = createProjectDir ( ) ;
1939+ recordPreviewReferences (
1940+ projectDir ,
1941+ `<i title='style="'></i><style>/* style=" */ i { background:url('assets/a&b.png') } /* " */</style><i title='"'></i>` ,
1942+ ) ;
1943+ recordPreviewBuilt ( projectDir ) ;
1944+ expect ( affectsPreview ( projectDir , "assets/a&b.png" ) ) . toBe ( true ) ;
1945+ expect ( affectsPreview ( projectDir , "assets/a&b.png" ) ) . toBe ( false ) ;
1946+ } ) ;
1947+
1948+ it ( "tracks references in nested templates and script-created CSS" , ( ) => {
1949+ const projectDir = createProjectDir ( ) ;
1950+ recordPreviewReferences (
1951+ projectDir ,
1952+ '<template><template><img src="assets/nested.png"></template></template><script>el.style.background="url(assets/script.png)"</script>' ,
1953+ ) ;
1954+ recordPreviewBuilt ( projectDir ) ;
1955+ expect ( affectsPreview ( projectDir , "assets/nested.png" ) ) . toBe ( true ) ;
1956+ expect ( affectsPreview ( projectDir , "assets/script.png" ) ) . toBe ( true ) ;
1957+ } ) ;
1958+
1959+ it ( "bounds filesystem paths after stripping long queries and decoding escapes" , ( ) => {
1960+ const projectDir = createProjectDir ( ) ;
1961+ const path = `assets/${ "x/" . repeat ( 1200 ) } image.png` ;
1962+ const encoded = path . replace ( / x / g, "%78" ) ;
1963+ recordPreviewReferences (
1964+ projectDir ,
1965+ `<img src="assets/image.png?${ "x" . repeat ( 5000 ) } "><img src="${ encoded } ">` ,
1966+ ) ;
1967+ recordPreviewBuilt ( projectDir ) ;
1968+ expect ( affectsPreview ( projectDir , "assets/image.png" ) ) . toBe ( true ) ;
1969+ expect ( affectsPreview ( projectDir , path ) ) . toBe ( true ) ;
1970+ } ) ;
1971+
1972+ it ( "does not walk oversized preview references or direct read paths" , ( ) => {
1973+ const projectDir = createProjectDir ( ) ;
1974+ const path = `assets/${ "long/" . repeat ( 850 ) } image.png` ;
1975+ recordPreviewReferences ( projectDir , `<img src="${ path } ">` ) ;
1976+ recordPreviewRead ( projectDir , path ) ;
1977+ recordPreviewBuilt ( projectDir ) ;
1978+ expect ( affectsPreview ( projectDir , path ) ) . toBe ( false ) ;
1979+ } ) ;
1980+
19011981 it . skipIf ( process . platform === "win32" ) (
19021982 "counts an edit to the file a symlinked asset points at" ,
19031983 async ( ) => {
0 commit comments