= block.else ? loop_child(block.else.children, adjacent_only) : new Map();
-
+
const not_exhaustive = !has_definite_elements(else_result);
if (not_exhaustive) {
diff --git a/src/compiler/compile/nodes/Binding.ts b/src/compiler/compile/nodes/Binding.ts
index 3a9aa943e9..8fcc70ded9 100644
--- a/src/compiler/compile/nodes/Binding.ts
+++ b/src/compiler/compile/nodes/Binding.ts
@@ -9,6 +9,7 @@ import { TemplateNode } from '../../interfaces';
import Element from './Element';
import InlineComponent from './InlineComponent';
import Window from './Window';
+import { clone } from '../../utils/clone';
// TODO this should live in a specific binding
const read_only_media_attributes = new Set([
@@ -42,7 +43,7 @@ export default class Binding extends Node {
this.name = info.name;
this.expression = new Expression(component, this, scope, info.expression);
- this.raw_expression = JSON.parse(JSON.stringify(info.expression));
+ this.raw_expression = clone(info.expression);
const { name } = get_object(this.expression.node);
diff --git a/src/compiler/compile/nodes/shared/Context.ts b/src/compiler/compile/nodes/shared/Context.ts
index c6ad2c2893..dbcdada587 100644
--- a/src/compiler/compile/nodes/shared/Context.ts
+++ b/src/compiler/compile/nodes/shared/Context.ts
@@ -2,6 +2,7 @@ import { x } from 'code-red';
import { Node, Identifier, Expression } from 'estree';
import { walk } from 'estree-walker';
import is_reference from 'is-reference';
+import { clone } from '../../../utils/clone';
export interface Context {
key: Identifier;
@@ -81,7 +82,7 @@ function update_reference(contexts: Context[], n: number, expression: Expression
}
// NOTE: avoid unnecessary deep clone?
- expression = JSON.parse(JSON.stringify(expression)) as Expression;
+ expression = clone(expression) as Expression;
walk(expression, {
enter(node, parent: Node) {
if (is_reference(node, parent)) {
diff --git a/src/compiler/compile/nodes/shared/Expression.ts b/src/compiler/compile/nodes/shared/Expression.ts
index caece14f00..cca81b6372 100644
--- a/src/compiler/compile/nodes/shared/Expression.ts
+++ b/src/compiler/compile/nodes/shared/Expression.ts
@@ -16,6 +16,7 @@ import { is_reserved_keyword } from '../../utils/reserved_keywords';
import replace_object from '../../utils/replace_object';
import is_contextual from './is_contextual';
import EachBlock from '../EachBlock';
+import { clone } from '../../../utils/clone';
type Owner = INode;
@@ -195,7 +196,7 @@ export default class Expression {
const node = walk(this.node, {
enter(node: any, parent: any) {
if (node.type === 'Property' && node.shorthand) {
- node.value = JSON.parse(JSON.stringify(node.value));
+ node.value = clone(node.value);
node.shorthand = false;
}
diff --git a/src/compiler/preprocess/index.ts b/src/compiler/preprocess/index.ts
index 93b48996c1..16bcdf1687 100644
--- a/src/compiler/preprocess/index.ts
+++ b/src/compiler/preprocess/index.ts
@@ -5,6 +5,8 @@ import { decode_map } from './decode_sourcemap';
import { replace_in_code, slice_source } from './replace_in_code';
import { MarkupPreprocessor, Source, Preprocessor, PreprocessorGroup, Processed } from './types';
+export * from './types';
+
interface SourceUpdate {
string?: string;
map?: DecodedSourceMap;
diff --git a/src/compiler/utils/clone.ts b/src/compiler/utils/clone.ts
new file mode 100644
index 0000000000..74b6cfa0a1
--- /dev/null
+++ b/src/compiler/utils/clone.ts
@@ -0,0 +1,33 @@
+// adapted from klona v2.0.4 - https://github.com/lukeed/klona
+// (c) Luke Edwards, under MIT License
+
+// The sole modification is to skip function values in objects when cloning, so we don't break tests.
+
+export function clone(val) {
+ let k, out, tmp;
+
+ if (Array.isArray(val)) {
+ out = Array(k=val.length);
+ while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
+ return out;
+ }
+
+ if (Object.prototype.toString.call(val) === '[object Object]') {
+ out = {}; // null
+ for (k in val) {
+ if (k === '__proto__') {
+ Object.defineProperty(out, k, {
+ value: clone(val[k]),
+ configurable: true,
+ enumerable: true,
+ writable: true
+ });
+ } else if (typeof val[k] !== 'function') { // MODIFICATION: skip functions
+ out[k] = (tmp=val[k]) && typeof tmp === 'object' ? clone(tmp) : tmp;
+ }
+ }
+ return out;
+ }
+
+ return val;
+}
diff --git a/test/parser/samples/slotted-element/input.svelte b/test/parser/samples/slotted-element/input.svelte
new file mode 100644
index 0000000000..709dede9a5
--- /dev/null
+++ b/test/parser/samples/slotted-element/input.svelte
@@ -0,0 +1 @@
+
diff --git a/test/parser/samples/slotted-element/output.json b/test/parser/samples/slotted-element/output.json
new file mode 100644
index 0000000000..7028a367ff
--- /dev/null
+++ b/test/parser/samples/slotted-element/output.json
@@ -0,0 +1,42 @@
+{
+ "html": {
+ "start": 0,
+ "end": 45,
+ "type": "Fragment",
+ "children": [
+ {
+ "start": 0,
+ "end": 45,
+ "type": "InlineComponent",
+ "name": "Component",
+ "attributes": [],
+ "children": [
+ {
+ "start": 11,
+ "end": 33,
+ "type": "Element",
+ "name": "div",
+ "attributes": [
+ {
+ "start": 16,
+ "end": 26,
+ "type": "Attribute",
+ "name": "slot",
+ "value": [
+ {
+ "start": 22,
+ "end": 25,
+ "type": "Text",
+ "raw": "foo",
+ "data": "foo"
+ }
+ ]
+ }
+ ],
+ "children": []
+ }
+ ]
+ }
+ ]
+ }
+}
diff --git a/test/parser/samples/textarea-children/output.json b/test/parser/samples/textarea-children/output.json
index 919fa33fde..0ebbfd38fc 100644
--- a/test/parser/samples/textarea-children/output.json
+++ b/test/parser/samples/textarea-children/output.json
@@ -9,51 +9,45 @@
"end": 61,
"type": "Element",
"name": "textarea",
- "attributes": [
+ "attributes": [],
+ "children": [
{
- "type": "Attribute",
- "name": "value",
- "value": [
- {
- "start": 10,
- "end": 41,
- "type": "Text",
- "raw": "\n\tnot actually an element. ",
- "data": "\n\t
not actually an element. "
- },
- {
- "start": 40,
- "end": 45,
- "type": "MustacheTag",
- "expression": {
- "type": "Identifier",
- "start": 41,
- "end": 44,
- "loc": {
- "start": {
- "line": 2,
- "column": 30
- },
- "end": {
- "line": 2,
- "column": 33
- }
- },
- "name": "foo"
+ "start": 10,
+ "end": 41,
+ "type": "Text",
+ "raw": "\n\t
not actually an element. ",
+ "data": "\n\t
not actually an element. "
+ },
+ {
+ "start": 40,
+ "end": 45,
+ "type": "MustacheTag",
+ "expression": {
+ "type": "Identifier",
+ "start": 41,
+ "end": 44,
+ "loc": {
+ "start": {
+ "line": 2,
+ "column": 30
+ },
+ "end": {
+ "line": 2,
+ "column": 33
}
},
- {
- "start": 45,
- "end": 50,
- "type": "Text",
- "raw": "
\n",
- "data": "\n"
- }
- ]
+ "name": "foo"
+ }
+ },
+ {
+ "start": 45,
+ "end": 50,
+ "type": "Text",
+ "raw": "\n",
+ "data": "\n"
}
- ],
- "children": []
+ ]
}
]
}
-}
\ No newline at end of file
+}