collapse consecutive whitespace characters in the absense of options.preserveWhitespace or a <pre>

pull/2258/head
Richard Harris 5 years ago
parent 21d56c9ee3
commit 2b1aa77f29

@ -25,6 +25,7 @@ type ComponentOptions = {
tag?: string;
immutable?: boolean;
accessors?: boolean;
preserveWhitespace?: boolean;
};
// We need to tell estree-walker that it should always
@ -1195,7 +1196,8 @@ function process_component_options(component: Component, nodes) {
immutable: component.compile_options.immutable || false,
accessors: 'accessors' in component.compile_options
? component.compile_options.accessors
: !!component.compile_options.customElement
: !!component.compile_options.customElement,
preserveWhitespace: !!component.compile_options.preserveWhitespace
};
const node = nodes.find(node => node.name === 'svelte:options');
@ -1271,6 +1273,7 @@ function process_component_options(component: Component, nodes) {
case 'accessors':
case 'immutable':
case 'preserveWhitespace':
const code = `invalid-${name}-value`;
const message = `${name} attribute must be true or false`
const value = get_value(attribute, code, message);
@ -1291,7 +1294,7 @@ function process_component_options(component: Component, nodes) {
else {
component.error(attribute, {
code: `invalid-options-attribute`,
message: `<svelte:options> can only have static 'tag', 'namespace', 'accessors' and 'immutable' attributes`
message: `<svelte:options> can only have static 'tag', 'namespace', 'accessors', 'immutable' and 'preserveWhitespace' attributes`
});
}
});

@ -23,7 +23,8 @@ const valid_options = [
'customElement',
'tag',
'css',
'preserveComments'
'preserveComments',
'preserveWhitespace'
];
function validate_options(options: CompileOptions, warnings: Warning[]) {

@ -1,11 +1,26 @@
import Node from './shared/Node';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
export default class Text extends Node {
type: 'Text';
data: string;
use_space = false;
constructor(component, parent, scope, info) {
constructor(component: Component, parent: Node, scope: TemplateScope, info: any) {
super(component, parent, scope, info);
this.data = info.data;
if (!component.component_options.preserveWhitespace && !/\S/.test(info.data)) {
let node = parent;
while (node) {
if (node.type === 'Element' && node.name === 'pre') {
return;
}
node = node.parent;
}
this.use_space = true;
}
}
}

@ -54,7 +54,7 @@ export default class TextWrapper extends Wrapper {
block.add_element(
this.var,
`@text(${stringify(this.data)})`,
this.node.use_space ? `@space()` : `@text(${stringify(this.data)})`,
parent_nodes && `@claim_text(${parent_nodes}, ${stringify(this.data)})`,
parent_node
);

@ -57,7 +57,8 @@ export interface CompileOptions {
tag?: string;
css?: boolean;
preserveComments?: boolean | false;
preserveComments?: boolean;
preserveWhitespace?: boolean;
}
export interface Visitor {

@ -46,6 +46,10 @@ export function text(data) {
return document.createTextNode(data);
}
export function space() {
return text(' ');
}
export function comment() {
return document.createComment('');
}

@ -85,11 +85,11 @@ function cleanChildren(node) {
node.removeChild(child);
}
child.data = child.data.replace(/\s{2,}/g, '\n');
child.data = child.data.replace(/\s+/g, '\n');
if (previous && previous.nodeType === 3) {
previous.data += child.data;
previous.data = previous.data.replace(/\s{2,}/g, '\n');
previous.data = previous.data.replace(/\s+/g, '\n');
node.removeChild(child);
child = previous;

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -24,7 +25,7 @@ function create_fragment(ctx) {
t0 = text("Hello ");
t1 = text(ctx.name);
t2 = text("!");
t3 = text("\n");
t3 = space();
debugger;
add_location(h1, file, 4, 0, 38);
},

@ -11,6 +11,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -30,7 +31,7 @@ function create_each_block(ctx) {
c: function create() {
span = element("span");
t0 = text(t0_value);
t1 = text("\n\t");
t1 = space();
{
const { foo, bar, baz, thing } = ctx;
@ -84,7 +85,7 @@ function create_fragment(ctx) {
each_blocks[i].c();
}
t0 = text("\n\n");
t0 = space();
p = element("p");
t1 = text("foo: ");
t2 = text(ctx.foo);

@ -11,6 +11,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -30,7 +31,7 @@ function create_each_block(ctx) {
c: function create() {
span = element("span");
t0 = text(t0_value);
t1 = text("\n\t");
t1 = space();
{
const { foo } = ctx;
@ -84,7 +85,7 @@ function create_fragment(ctx) {
each_blocks[i].c();
}
t0 = text("\n\n");
t0 = space();
p = element("p");
t1 = text("foo: ");
t2 = text(ctx.foo);

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -22,7 +23,7 @@ function create_fragment(ctx) {
c: function create() {
p = element("p");
t0 = text(t0_value);
t1 = text("\n\t");
t1 = space();
t2 = text(ctx.bar);
add_location(p, file, 7, 0, 67);
},

@ -7,7 +7,7 @@ import {
insert,
noop,
safe_not_equal,
text
space
} from "svelte/internal";
function create_fragment(ctx) {
@ -16,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
div0 = element("div");
t = text("\n");
t = space();
div1 = element("div");
div0.dataset.foo = "bar";
div1.dataset.foo = ctx.bar;

@ -8,7 +8,7 @@ import {
insert,
noop,
safe_not_equal,
text
space
} from "svelte/internal";
function create_fragment(ctx) {
@ -17,7 +17,7 @@ function create_fragment(ctx) {
return {
c() {
div0 = element("div");
t = text("\n");
t = space();
div1 = element("div");
attr(div0, "data-foo", "bar");
attr(div1, "data-foo", ctx.bar);

@ -11,6 +11,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -30,13 +31,13 @@ function create_each_block(ctx) {
div = element("div");
strong = element("strong");
t0 = text(ctx.i);
t1 = text("\n\n\t\t");
t1 = space();
span = element("span");
t2 = text(t2_value);
t3 = text(" wrote ");
t4 = text(t4_value);
t5 = text(" ago:");
t6 = text("\n\n\t\t");
t6 = space();
raw_before = element('noscript');
span.className = "meta";
div.className = "comment";
@ -97,7 +98,7 @@ function create_fragment(ctx) {
each_blocks[i].c();
}
t0 = text("\n\n");
t0 = space();
p = element("p");
t1 = text(ctx.foo);
},

@ -11,8 +11,8 @@ import {
prevent_default,
run_all,
safe_not_equal,
stop_propagation,
text
space,
stop_propagation
} from "svelte/internal";
function create_fragment(ctx) {
@ -23,10 +23,10 @@ function create_fragment(ctx) {
div = element("div");
button0 = element("button");
button0.textContent = "click me";
t1 = text("\n\t");
t1 = space();
button1 = element("button");
button1.textContent = "or me";
t3 = text("\n\t");
t3 = space();
button2 = element("button");
button2.textContent = "or me!";
dispose = [

@ -7,7 +7,7 @@ import {
insert,
noop,
safe_not_equal,
text
space
} from "svelte/internal";
function create_fragment(ctx) {
@ -16,7 +16,7 @@ function create_fragment(ctx) {
return {
c() {
div0 = element("div");
t = text("\n");
t = space();
div1 = element("div");
div0.style.cssText = ctx.style;
div1.style.cssText = div1_style_value = "" + ctx.key + ": " + ctx.value;

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -20,7 +21,7 @@ function create_fragment(ctx) {
c() {
button = element("button");
button.textContent = "foo";
t1 = text("\n\n");
t1 = space();
p = element("p");
t2 = text("x: ");
t3 = text(ctx.x);

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -20,7 +21,7 @@ function create_fragment(ctx) {
c() {
button = element("button");
button.textContent = "foo";
t1 = text("\n\n");
t1 = space();
p = element("p");
t2 = text("number of things: ");
t3 = text(t3_value);

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -20,7 +21,7 @@ function create_fragment(ctx) {
c() {
button = element("button");
button.textContent = "foo";
t1 = text("\n\n");
t1 = space();
p = element("p");
t2 = text("x: ");
t3 = text(ctx.x);

@ -10,6 +10,7 @@ import {
noop,
safe_not_equal,
set_data,
space,
text
} from "svelte/internal";
@ -20,7 +21,7 @@ function create_fragment(ctx) {
c() {
button = element("button");
button.textContent = "foo";
t1 = text("\n\n");
t1 = space();
p = element("p");
t2 = text("number of things: ");
t3 = text(t3_value);

@ -7,7 +7,7 @@ import {
mount_component,
noop,
safe_not_equal,
text
space
} from "svelte/internal";
import Imported from "Imported.svelte";
@ -21,7 +21,7 @@ function create_fragment(ctx) {
return {
c() {
imported.$$.fragment.c();
t = text("\n");
t = space();
nonimported.$$.fragment.c();
},

@ -9,7 +9,7 @@ import {
insert,
noop,
safe_not_equal,
text
space
} from "svelte/internal";
// (10:1) {#if a}
@ -139,19 +139,19 @@ function create_fragment(ctx) {
c() {
div = element("div");
if (if_block0) if_block0.c();
t0 = text("\n\n\t");
t0 = space();
p0 = element("p");
p0.textContent = "this can be used as an anchor";
t2 = text("\n\n\t");
t2 = space();
if (if_block1) if_block1.c();
t3 = text("\n\n\t");
t3 = space();
if (if_block2) if_block2.c();
t4 = text("\n\n\t");
t4 = space();
p1 = element("p");
p1.textContent = "so can this";
t6 = text("\n\n\t");
t6 = space();
if (if_block3) if_block3.c();
t7 = text("\n\n");
t7 = space();
if (if_block4) if_block4.c();
if_block4_anchor = comment();
},

@ -22,10 +22,16 @@ export default {
input.checked = false;
await input.dispatchEvent(event);
assert.equal(target.innerHTML, `<input type="checkbox">\n<p>false</p>`);
assert.htmlEqual(target.innerHTML, `
<input type="checkbox">
<p>false</p>
`);
component.foo = true;
assert.equal(input.checked, true);
assert.equal(target.innerHTML, `<input type="checkbox">\n<p>true</p>`);
assert.htmlEqual(target.innerHTML, `
<input type="checkbox">
<p>true</p>
`);
}
};

@ -5,13 +5,25 @@ export default {
compound: 'piece of',
go: { deeper: 'core' }
},
html: `<div><p>foo: lol</p>\n<p>baz: 42 (number)</p>\n<p>qux: this is a piece of string</p>\n<p>quux: core</p></div>`,
html: `
<div><p>foo: lol</p>
<p>baz: 42 (number)</p>
<p>qux: this is a piece of string</p>
<p>quux: core</p></div>
`,
test({ assert, component, target }) {
component.bar = 'wut';
component.x = 3;
component.compound = 'rather boring';
component.go = { deeper: 'heart' };
assert.equal( target.innerHTML, `<div><p>foo: wut</p>\n<p>baz: 43 (number)</p>\n<p>qux: this is a rather boring string</p>\n<p>quux: heart</p></div>` );
assert.htmlEqual(target.innerHTML, `
<div><p>foo: wut</p>
<p>baz: 43 (number)</p>
<p>qux: this is a rather boring string</p>
<p>quux: heart</p></div>
`);
}
};

@ -1,5 +1,8 @@
export default {
html: '<button>+1</button>\n\n<p>0</p>',
html: `
<button>+1</button>
<p>0</p>
`,
async test({ assert, component, target, window }) {
const button = target.querySelector('button');
@ -7,11 +10,17 @@ export default {
await button.dispatchEvent(event);
assert.equal(component.counter, 1);
assert.equal(target.innerHTML, '<button>+1</button>\n\n<p>1</p>');
assert.htmlEqual(target.innerHTML, `
<button>+1</button>
<p>1</p>
`);
await button.dispatchEvent(event);
assert.equal(component.counter, 2);
assert.equal(target.innerHTML, '<button>+1</button>\n\n<p>2</p>');
assert.htmlEqual(target.innerHTML, `
<button>+1</button>
<p>2</p>
`);
assert.equal(component.foo(), 42);
}

Loading…
Cancel
Save