Skip to content

Commit f99e543

Browse files
committed
remove bom once at start, add test
1 parent 693009d commit f99e543

File tree

3 files changed

+39
-6
lines changed

3 files changed

+39
-6
lines changed

packages/svelte/src/compiler/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export { default as preprocess } from './preprocess/index.js';
2020
* @returns {CompileResult}
2121
*/
2222
export function compile(source, options) {
23+
source = remove_bom(source);
2324
state.reset_warning_filter(options.warningFilter);
2425
const validated = validate_component_options(options, '');
2526
state.reset(source, validated);
@@ -58,6 +59,7 @@ export function compile(source, options) {
5859
* @returns {CompileResult}
5960
*/
6061
export function compileModule(source, options) {
62+
source = remove_bom(source);
6163
state.reset_warning_filter(options.warningFilter);
6264
const validated = validate_module_options(options, '');
6365
state.reset(source, validated);
@@ -101,6 +103,7 @@ export function compileModule(source, options) {
101103
* @returns {AST.Root | LegacyRoot}
102104
*/
103105
export function parse(source, { filename, rootDir, modern } = {}) {
106+
source = remove_bom(source);
104107
state.reset_warning_filter(() => false);
105108
state.reset(source, { filename: filename ?? '(unknown)', rootDir });
106109

@@ -140,6 +143,17 @@ function to_public_ast(source, ast, modern) {
140143
return convert(source, ast);
141144
}
142145

146+
/**
147+
* Remove the byte order mark from a string if it's present since it would mess with our template generation logic
148+
* @param {string} source
149+
*/
150+
function remove_bom(source) {
151+
if (source.charCodeAt(0) === 0xfeff) {
152+
return source.slice(1);
153+
}
154+
return source;
155+
}
156+
143157
/**
144158
* @deprecated Replace this with `import { walk } from 'estree-walker'`
145159
* @returns {never}

packages/svelte/src/compiler/phases/1-parse/utils/html.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ const entity_pattern_attr_value = get_entity_pattern(true);
3838
* @param {boolean} is_attribute_value
3939
*/
4040
export function decode_character_references(html, is_attribute_value) {
41-
// Replace all BOM characters from the HTML with a standard space
42-
const sanitised_html = html.replaceAll(String.fromCharCode(65279), ' ');
4341
const entity_pattern = is_attribute_value ? entity_pattern_attr_value : entity_pattern_content;
44-
return sanitised_html.replace(
42+
return html.replace(
4543
entity_pattern,
4644
/**
4745
* @param {any} match
@@ -77,8 +75,8 @@ const NUL = 0;
7775

7876
/** @param {number} code */
7977
function validate_code(code) {
80-
// line feed becomes generic whitespace, as does a BOM character
81-
if (code === 10 || code === 65279) {
78+
// line feed becomes generic whitespace
79+
if (code === 10) {
8280
return 32;
8381
}
8482

packages/svelte/tests/parser-modern/test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as fs from 'node:fs';
2-
import { assert } from 'vitest';
2+
import { assert, it } from 'vitest';
33
import { parse } from 'svelte/compiler';
44
import { try_load_json } from '../helpers.js';
55
import { suite, type BaseTest } from '../suite.js';
@@ -34,3 +34,24 @@ const { test, run } = suite<ParserTest>(async (config, cwd) => {
3434
export { test };
3535

3636
await run(__dirname);
37+
38+
it('Strips BOM from the input', () => {
39+
const input = '\uFEFF<div></div>';
40+
const actual = parse(input, { modern: true });
41+
assert.deepEqual(JSON.parse(JSON.stringify(actual.fragment)), {
42+
type: 'Fragment',
43+
nodes: [
44+
{
45+
attributes: [],
46+
end: 11,
47+
fragment: {
48+
nodes: [],
49+
type: 'Fragment'
50+
},
51+
name: 'div',
52+
start: 0,
53+
type: 'RegularElement'
54+
}
55+
]
56+
});
57+
});

0 commit comments

Comments
 (0)