Merge branch 'master' into feat/export-store-types

pull/5887/head
hantatsang 6 years ago
commit e786ee1925

@ -1,5 +1,15 @@
# Svelte changelog
## 3.32.3
* Fix removal of lone `:host` selectors ([#5982](https://github.com/sveltejs/svelte/issues/5982))
## 3.32.2
* Fix unnecessary additional invalidation with `<Component bind:prop={obj.foo}/>` ([#3075](https://github.com/sveltejs/svelte/issues/3075), [#4447](https://github.com/sveltejs/svelte/issues/4447), [#5555](https://github.com/sveltejs/svelte/issues/5555))
* Fix scoping of selectors with `:global()` and `~` sibling combinators ([#5499](https://github.com/sveltejs/svelte/issues/5499))
* Fix removal of `:host` selectors as unused when compiling to a custom element ([#5946](https://github.com/sveltejs/svelte/issues/5946))
## 3.32.1
* Warn when using `module` variables reactively, and close weird reactivity loophole ([#5847](https://github.com/sveltejs/svelte/pull/5847))

24
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.32.1",
"version": "3.32.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1051,19 +1051,19 @@
}
},
"css-tree": {
"version": "1.0.0-alpha22",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha22.tgz",
"integrity": "sha1-M4oAbjMce0+dq3tq9Tns5W/3ivI=",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.2.tgz",
"integrity": "sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==",
"dev": true,
"requires": {
"mdn-data": "^1.0.0",
"source-map": "^0.5.3"
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
@ -2904,9 +2904,9 @@
}
},
"mdn-data": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.2.0.tgz",
"integrity": "sha512-esDqNvsJB2q5V28+u7NdtdMg6Rmg4khQmAVSjUiX7BY/7haIv0K2yWM43hYp0or+3nvG7+UaTF1JHz31hgU1TA==",
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"dev": true
},
"mem": {

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.32.1",
"version": "3.32.3",
"description": "Cybernetically enhanced web apps",
"module": "index.mjs",
"main": "index",
@ -112,7 +112,7 @@
"c8": "^5.0.1",
"code-red": "^0.1.4",
"codecov": "^3.5.0",
"css-tree": "1.0.0-alpha22",
"css-tree": "^1.1.2",
"eslint": "^7.15.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-svelte3": "^2.7.3",

@ -44,7 +44,10 @@ export default class Selector {
}
this.local_blocks = this.blocks.slice(0, i);
this.used = this.local_blocks.length === 0;
const host_only = this.blocks.length === 1 && this.blocks[0].host;
this.used = this.local_blocks.length === 0 || host_only;
}
apply(node: Element) {
@ -84,7 +87,7 @@ export default class Selector {
while (i--) {
const selector = block.selectors[i];
if (selector.type === 'PseudoElementSelector' || selector.type === 'PseudoClassSelector') {
if (selector.name !== 'root') {
if (selector.name !== 'root' && selector.name !== 'host') {
if (i === 0) code.prependRight(selector.start, attr);
}
continue;
@ -162,7 +165,10 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: any[]):
if (!block) return false;
if (!node) {
return block.global && blocks.every(block => block.global);
return (
(block.global && blocks.every(block => block.global)) ||
(block.host && blocks.length === 0)
);
}
switch (block_might_apply_to_node(block, node)) {
@ -182,6 +188,11 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: any[]):
continue;
}
if (ancestor_block.host) {
to_encapsulate.push({ node, block });
return true;
}
let parent = node;
while (parent = get_element_parent(parent)) {
if (block_might_apply_to_node(ancestor_block, parent) !== BlockAppliesToNode.NotPossible) {
@ -211,6 +222,19 @@ function apply_selector(blocks: Block[], node: Element, to_encapsulate: any[]):
} else if (block.combinator.name === '+' || block.combinator.name === '~') {
const siblings = get_possible_element_siblings(node, block.combinator.name === '+');
let has_match = false;
// NOTE: if we have :global(), we couldn't figure out what is selected within `:global` due to the
// css-tree limitation that does not parse the inner selector of :global
// so unless we are sure there will be no sibling to match, we will consider it as matched
const has_global = blocks.some(block => block.global);
if (has_global) {
if (siblings.size === 0 && get_element_parent(node) !== null) {
return false;
}
to_encapsulate.push({ node, block });
return true;
}
for (const possible_sibling of siblings.keys()) {
if (apply_selector(blocks.slice(), possible_sibling, to_encapsulate)) {
to_encapsulate.push({ node, block });
@ -236,6 +260,10 @@ function block_might_apply_to_node(block: Block, node: Element): BlockAppliesToN
const selector = block.selectors[i];
const name = typeof selector.name === 'string' && selector.name.replace(/\\(.)/g, '$1');
if (selector.type === 'PseudoClassSelector' && name === 'host') {
return BlockAppliesToNode.NotPossible;
}
if (selector.type === 'PseudoClassSelector' || selector.type === 'PseudoElementSelector') {
continue;
}
@ -541,6 +569,7 @@ function loop_child(children: INode[], adjacent_only: boolean) {
class Block {
global: boolean;
host: boolean;
combinator: CssNode;
selectors: CssNode[]
start: number;
@ -550,6 +579,7 @@ class Block {
constructor(combinator: CssNode) {
this.combinator = combinator;
this.global = false;
this.host = false;
this.selectors = [];
this.start = null;
@ -562,6 +592,7 @@ class Block {
if (this.selectors.length === 0) {
this.start = selector.start;
this.global = selector.type === 'PseudoClassSelector' && selector.name === 'global';
this.host = selector.type === 'PseudoClassSelector' && selector.name === 'host';
}
this.selectors.push(selector);

@ -47,7 +47,7 @@ class Rule {
constructor(node: CssNode, stylesheet, parent?: Atrule) {
this.node = node;
this.parent = parent;
this.selectors = node.selector.children.map((node: CssNode) => new Selector(node, stylesheet));
this.selectors = node.prelude.children.map((node: CssNode) => new Selector(node, stylesheet));
this.declarations = node.block.children.map((node: CssNode) => new Declaration(node));
}
@ -182,11 +182,11 @@ class Atrule {
minify(code: MagicString, dev: boolean) {
if (this.node.name === 'media') {
const expression_char = code.original[this.node.expression.start];
const expression_char = code.original[this.node.prelude.start];
let c = this.node.start + (expression_char === '(' ? 6 : 7);
if (this.node.expression.start > c) code.remove(c, this.node.expression.start);
if (this.node.prelude.start > c) code.remove(c, this.node.prelude.start);
this.node.expression.children.forEach((query: CssNode) => {
this.node.prelude.children.forEach((query: CssNode) => {
// TODO minify queries
c = query.end;
});
@ -194,17 +194,17 @@ class Atrule {
code.remove(c, this.node.block.start);
} else if (this.node.name === 'supports') {
let c = this.node.start + 9;
if (this.node.expression.start - c > 1) code.overwrite(c, this.node.expression.start, ' ');
this.node.expression.children.forEach((query: CssNode) => {
if (this.node.prelude.start - c > 1) code.overwrite(c, this.node.prelude.start, ' ');
this.node.prelude.children.forEach((query: CssNode) => {
// TODO minify queries
c = query.end;
});
code.remove(c, this.node.block.start);
} else {
let c = this.node.start + this.node.name.length + 1;
if (this.node.expression) {
if (this.node.expression.start - c > 1) code.overwrite(c, this.node.expression.start, ' ');
c = this.node.expression.end;
if (this.node.prelude) {
if (this.node.prelude.start - c > 1) code.overwrite(c, this.node.prelude.start, ' ');
c = this.node.prelude.end;
}
if (this.node.block && this.node.block.start - c > 0) {
code.remove(c, this.node.block.start);
@ -235,7 +235,7 @@ class Atrule {
transform(code: MagicString, id: string, keyframes: Map<string, string>, max_amount_class_specificity_increased: number) {
if (is_keyframes_node(this.node)) {
this.node.expression.children.forEach(({ type, name, start, end }: CssNode) => {
this.node.prelude.children.forEach(({ type, name, start, end }: CssNode) => {
if (type === 'Identifier') {
if (name.startsWith('-global-')) {
code.remove(start, start + 8);
@ -317,7 +317,7 @@ export default class Stylesheet {
}
if (is_keyframes_node(node)) {
node.expression.children.forEach((expression: CssNode) => {
node.prelude.children.forEach((expression: CssNode) => {
if (expression.type === 'Identifier' && !expression.name.startsWith('-global-')) {
this.keyframes.set(expression.name, `${this.id}-${expression.name}`);
}

@ -347,8 +347,8 @@ export default class InlineComponentWrapper extends Wrapper {
}
const params = [x`#value`];
const args = [x`#value`];
if (contextual_dependencies.length > 0) {
const args = [];
contextual_dependencies.forEach(name => {
params.push({
@ -361,25 +361,30 @@ export default class InlineComponentWrapper extends Wrapper {
});
block.chunks.init.push(b`
function ${id}(#value) {
${callee}.call(null, #value, ${args});
}
`);
block.maintain_context = true; // TODO put this somewhere more logical
} else {
block.chunks.init.push(b`
function ${id}(#value) {
${callee}.call(null, #value);
}
block.chunks.init.push(b`
function ${id}(#value) {
${callee}(${args});
}
`);
let invalidate_binding = b`
${lhs} = #value;
${renderer.invalidate(dependencies[0])};
`;
if (binding.expression.node.type === 'MemberExpression') {
invalidate_binding = b`
if ($$self.$$.not_equal(${lhs}, #value)) {
${invalidate_binding}
}
`);
`;
}
const body = b`
function ${id}(${params}) {
${lhs} = #value;
${renderer.invalidate(dependencies[0])};
${invalidate_binding}
}
`;

@ -14,10 +14,13 @@ export default function read_style(parser: Parser, start: number, attributes: No
try {
ast = parse(styles, {
positions: true,
offset: content_start
offset: content_start,
onParseError(error) {
throw error;
}
});
} catch (err) {
if (err.name === 'CssSyntaxError') {
if (err.name === 'SyntaxError') {
parser.error({
code: 'css-syntax-error',
message: err.message

@ -0,0 +1,27 @@
export default {
warnings: [
{
code: 'css-unused-selector',
message: 'Unused CSS selector ":host > span"',
pos: 147,
start: {
character: 147,
column: 1,
line: 18
},
end: {
character: 159,
column: 13,
line: 18
},
frame: `
16: }
17:
18: :host > span {
^
19: color: red;
20: }
`
}
]
};

@ -0,0 +1 @@
:host h1.svelte-xyz{color:red}:host>h1.svelte-xyz{color:red}:host>.svelte-xyz{color:red}:host span.svelte-xyz{color:red}:host{color:red}

@ -0,0 +1,31 @@
<style>
:host h1 {
color: red;
}
:host > h1 {
color: red;
}
:host > * {
color: red;
}
:host span {
color: red;
}
:host > span {
color: red;
}
:host {
color: red;
}
</style>
<h1>Hello!</h1>
<div>
<span>World!</span>
</div>

@ -0,0 +1,50 @@
export default {
warnings: [
{
code: 'css-unused-selector',
message: 'Unused CSS selector ":global(input) + span"',
pos: 239,
start: {
character: 239,
column: 2,
line: 9
},
end: {
character: 260,
column: 23,
line: 9
},
frame: `
7: :global(input) ~ p { color: red; }
8:
9: :global(input) + span { color: red; }
^
10: :global(input) ~ span { color: red; }
11: </style>
`
},
{
code: 'css-unused-selector',
message: 'Unused CSS selector ":global(input) ~ span"',
pos: 279,
start: {
character: 279,
column: 2,
line: 10
},
end: {
character: 300,
column: 23,
line: 10
},
frame: `
8:
9: :global(input) + span { color: red; }
10: :global(input) ~ span { color: red; }
^
11: </style>
12:
`
}
]
};

@ -0,0 +1 @@
input+div.svelte-xyz{color:red}input~div.svelte-xyz{color:red}input+h1.svelte-xyz{color:red}input~h1.svelte-xyz{color:red}input+p.svelte-xyz{color:red}input~p.svelte-xyz{color:red}

@ -0,0 +1,21 @@
<style>
:global(input) + div { color: red; }
:global(input) ~ div { color: red; }
:global(input) + h1 { color: red; }
:global(input) ~ h1 { color: red; }
:global(input) + p { color: red; }
:global(input) ~ p { color: red; }
:global(input) + span { color: red; }
:global(input) ~ span { color: red; }
</style>
<h1>Hello!</h1>
<div>
<span>World!</span>
</div>
{#each [] as _}
<p />
{/each}

@ -37,7 +37,7 @@
"children": [
{
"type": "Rule",
"selector": {
"prelude": {
"type": "SelectorList",
"children": [
{
@ -74,7 +74,7 @@
"end": 43
}
],
"start": 39,
"start": 40,
"end": 43
},
"start": 33,

@ -0,0 +1,6 @@
<script>
export let value;
export let value2;
</script>
{value}{value2}

@ -0,0 +1,5 @@
export default {
async test({ assert, component }) {
assert.equal(component.object_updates, component.primitive_updates);
}
};

@ -0,0 +1,13 @@
<script>
import Component from './Component.svelte';
export let primitive_updates = 0;
export let object_updates = 0;
const obj = { foo: '' };
let foo = 'bar';
$: if (obj) object_updates++;
$: if (foo) primitive_updates++;
</script>
<Component bind:value={obj.foo} bind:value2={foo} />
Loading…
Cancel
Save