Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/compile/nodes/StrictMustacheTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Tag from './shared/Tag';

export default class StrictMustacheTag extends Tag {}
2 changes: 2 additions & 0 deletions src/compile/nodes/shared/map_children.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import InlineComponent from '../InlineComponent';
import MustacheTag from '../MustacheTag';
import Options from '../Options';
import RawMustacheTag from '../RawMustacheTag';
import StrictMustacheTag from '../StrictMustacheTag';
import DebugTag from '../DebugTag';
import Slot from '../Slot';
import Text from '../Text';
Expand All @@ -29,6 +30,7 @@ function get_constructor(type): typeof Node {
case 'MustacheTag': return MustacheTag;
case 'Options': return Options;
case 'RawMustacheTag': return RawMustacheTag;
case 'StrictMustacheTag': return StrictMustacheTag;
case 'DebugTag': return DebugTag;
case 'Slot': return Slot;
case 'Text': return Text;
Expand Down
2 changes: 2 additions & 0 deletions src/compile/render-dom/wrappers/Fragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import IfBlock from './IfBlock';
import InlineComponent from './InlineComponent/index';
import MustacheTag from './MustacheTag';
import RawMustacheTag from './RawMustacheTag';
import StrictMustacheTag from './StrictMustacheTag';
import Slot from './Slot';
import Text from './Text';
import Title from './Title';
Expand All @@ -32,6 +33,7 @@ const wrappers = {
MustacheTag,
Options: null,
RawMustacheTag,
StrictMustacheTag,
Slot,
Text,
Title,
Expand Down
28 changes: 28 additions & 0 deletions src/compile/render-dom/wrappers/StrictMustacheTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Renderer from '../Renderer';
import Block from '../Block';
import Node from '../../nodes/shared/Node';
import Tag from './shared/Tag';
import Wrapper from './shared/Wrapper';

export default class StrictMustacheTagWrapper extends Tag {
var = 't';

constructor(renderer: Renderer, block: Block, parent: Wrapper, node: Node) {
super(renderer, block, parent, node);
this.cannot_use_innerhtml();
}

render(block: Block, parent_node: string, parent_nodes: string) {
const { init } = this.rename_this_method(
block,
value => `@set_data_strict(${this.var}, ${value});`
);

block.add_element(
this.var,
`@text(${init})`,
parent_nodes && `@claim_text(${parent_nodes}, ${init})`,
parent_node
);
}
}
5 changes: 3 additions & 2 deletions src/compile/render-dom/wrappers/shared/Tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import Renderer from '../../Renderer';
import Block from '../../Block';
import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag';
import StrictMustacheTag from '../../../nodes/StrictMustacheTag';

export default class Tag extends Wrapper {
node: MustacheTag | RawMustacheTag;
node: MustacheTag | RawMustacheTag | StrictMustacheTag;

constructor(renderer: Renderer, block: Block, parent: Wrapper, node: MustacheTag | RawMustacheTag) {
constructor(renderer: Renderer, block: Block, parent: Wrapper, node: MustacheTag | RawMustacheTag | StrictMustacheTag) {
super(renderer, block, parent, node);
this.cannot_use_innerhtml();

Expand Down
3 changes: 2 additions & 1 deletion src/compile/render-dom/wrappers/shared/Wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ export default class Wrapper {
return (
this.node.type === 'Element' ||
this.node.type === 'Text' ||
this.node.type === 'MustacheTag'
this.node.type === 'MustacheTag' ||
this.node.type === 'StrictMustacheTag'
);
}
}
1 change: 1 addition & 0 deletions src/compile/render-ssr/Renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const handlers: Record<string, Handler> = {
MustacheTag: Tag, // TODO MustacheTag is an anachronism
Options: noop,
RawMustacheTag: HtmlTag,
StrictMustacheTag: Tag,
Slot,
Text,
Title,
Expand Down
4 changes: 4 additions & 0 deletions src/internal/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ export function set_data(text, data) {
text.data = '' + data;
}

export function set_data_strict(text, data) {
if (text.data !== '' + data) text.data = '' + data;
}

export function set_input_type(input, type) {
try {
input.type = type;
Expand Down
15 changes: 15 additions & 0 deletions src/parse/state/mustache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,21 @@ export default function mustache(parser: Parser) {
type: 'RawMustacheTag',
expression,
});
} else if (parser.eat('@strict')) {
// {@equal content} tag
parser.require_whitespace();

const expression = read_expression(parser);

parser.allow_whitespace();
parser.eat('}', true);

parser.current().children.push({
start,
end: parser.index,
type: 'StrictMustacheTag',
expression,
});
} else if (parser.eat('@debug')) {
let identifiers;

Expand Down
49 changes: 49 additions & 0 deletions test/runtime/samples/strict-mustaches/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
export default {
skip_if_ssr: true,

props: {
text: 'test'
},

html: '<div>beforetestafter</div>',

test({ assert, component, target }) {
const text = component.container.childNodes[1];
text.data += 'ing';

assert.equal(target.innerHTML, '<div>beforetestingafter</div>');

// Track when .data is set on text
let get, set, proto = text.__proto__;
while (proto) {
const descriptor = Object.getOwnPropertyDescriptor(proto, 'data');
if (descriptor) {
get = descriptor.get;
set = descriptor.set;
break;
} else {
proto = proto.__proto__;
}
}
if (!get || !set) throw new Error('Could not get the getter/setter for data');
let setValue;

Object.defineProperty(text, 'data', {
get,
set(value) {
console.log('SETTING VALUE:', value);
setValue = value;
set.call(this, value);
}
});

component.text += 'ing';
assert.equal(setValue, undefined);

component.text += '!';
assert.equal(setValue, 'testing!');

component.$destroy();
assert.equal(target.innerHTML, '');
}
};
8 changes: 8 additions & 0 deletions test/runtime/samples/strict-mustaches/main.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
export let text;
export let container = null;
</script>

<div bind:this={container}>
before{@strict text}after
</div>