mirror of https://github.com/sveltejs/svelte
commit
f4edb381bf
@ -0,0 +1,41 @@
|
||||
import Renderer from '../Renderer';
|
||||
import Block from '../Block';
|
||||
import Comment from '../../nodes/Comment';
|
||||
import Wrapper from './shared/Wrapper';
|
||||
import { x } from 'code-red';
|
||||
import { Identifier } from 'estree';
|
||||
|
||||
export default class CommentWrapper extends Wrapper {
|
||||
node: Comment;
|
||||
var: Identifier;
|
||||
|
||||
constructor(
|
||||
renderer: Renderer,
|
||||
block: Block,
|
||||
parent: Wrapper,
|
||||
node: Comment
|
||||
) {
|
||||
super(renderer, block, parent, node);
|
||||
this.var = x`c` as Identifier;
|
||||
}
|
||||
|
||||
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {
|
||||
if (!this.renderer.options.preserveComments) return;
|
||||
|
||||
const string_literal = {
|
||||
type: 'Literal',
|
||||
value: this.node.data,
|
||||
loc: {
|
||||
start: this.renderer.locate(this.node.start),
|
||||
end: this.renderer.locate(this.node.end)
|
||||
}
|
||||
};
|
||||
|
||||
block.add_element(
|
||||
this.var,
|
||||
x`@comment(${string_literal})`,
|
||||
parent_nodes && x`@claim_comment(${parent_nodes}, ${string_literal})`,
|
||||
parent_node
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// @ts-nocheck
|
||||
// Note: Must import from the `css-tree` browser bundled distribution due to `createRequire` usage if importing from
|
||||
// `css-tree` Node module directly. This allows the production build of Svelte to work correctly.
|
||||
import { fork } from '../../../../../node_modules/css-tree/dist/csstree.esm.js';
|
||||
|
||||
import * as node from './node';
|
||||
|
||||
/**
|
||||
* Extends `css-tree` for container query support by forking and adding new nodes and at-rule support for `@container`.
|
||||
*
|
||||
* The new nodes are located in `./node`.
|
||||
*/
|
||||
const cqSyntax = fork({
|
||||
atrule: { // extend or override at-rule dictionary
|
||||
container: {
|
||||
parse: {
|
||||
prelude() {
|
||||
return this.createSingleNodeList(
|
||||
this.ContainerQuery()
|
||||
);
|
||||
},
|
||||
block(isStyleBlock = false) {
|
||||
return this.Block(isStyleBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
node
|
||||
});
|
||||
|
||||
export const parse = cqSyntax.parse;
|
@ -0,0 +1,48 @@
|
||||
// @ts-nocheck
|
||||
import { Delim } from 'css-tree/tokenizer';
|
||||
|
||||
export const name = 'Comparison';
|
||||
export const structure = {
|
||||
value: String
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
|
||||
const char1 = this.consume(Delim);
|
||||
|
||||
// The first character in the comparison operator must match '<', '=', or '>'.
|
||||
if (char1 !== '<' && char1 !== '>' && char1 !== '=') {
|
||||
this.error('Malformed comparison operator');
|
||||
}
|
||||
|
||||
let char2;
|
||||
|
||||
if (this.tokenType === Delim) {
|
||||
char2 = this.consume(Delim);
|
||||
|
||||
// The second character in the comparison operator must match '='.
|
||||
if (char2 !== '=') {
|
||||
this.error('Malformed comparison operator');
|
||||
}
|
||||
}
|
||||
|
||||
// If the next token is also 'Delim' then it is malformed.
|
||||
if (this.tokenType === Delim) {
|
||||
this.error('Malformed comparison operator');
|
||||
}
|
||||
|
||||
const value = char2 ? `${char1}${char2}` : char1;
|
||||
|
||||
return {
|
||||
type: 'Comparison',
|
||||
loc: this.getLocation(start, this.tokenStart),
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
for (let index = 0; index < node.value.length; index++) {
|
||||
this.token(Delim, node.value.charAt(index));
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
Function,
|
||||
Ident,
|
||||
Number,
|
||||
Dimension,
|
||||
RightParenthesis,
|
||||
Colon,
|
||||
Delim
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
export const name = 'ContainerFeatureStyle';
|
||||
export const structure = {
|
||||
name: String,
|
||||
value: ['Function', 'Identifier', 'Number', 'Dimension', 'QueryCSSFunction', 'Ratio', null]
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
let value = null;
|
||||
|
||||
const function_name = this.consumeFunctionName();
|
||||
if (function_name !== 'style') {
|
||||
this.error('Unknown container style query identifier; "style" is expected');
|
||||
}
|
||||
|
||||
this.skipSC();
|
||||
|
||||
const name = this.consume(Ident);
|
||||
this.skipSC();
|
||||
|
||||
if (this.tokenType !== RightParenthesis) {
|
||||
this.eat(Colon);
|
||||
this.skipSC();
|
||||
|
||||
switch (this.tokenType) {
|
||||
case Number:
|
||||
if (this.lookupNonWSType(1) === Delim) {
|
||||
value = this.Ratio();
|
||||
} else {
|
||||
value = this.Number();
|
||||
}
|
||||
break;
|
||||
|
||||
case Dimension:
|
||||
value = this.Dimension();
|
||||
break;
|
||||
|
||||
case Function:
|
||||
value = this.QueryCSSFunction();
|
||||
break;
|
||||
|
||||
case Ident:
|
||||
value = this.Identifier();
|
||||
break;
|
||||
|
||||
default:
|
||||
this.error('Number, dimension, ratio, function or identifier is expected');
|
||||
break;
|
||||
}
|
||||
|
||||
this.skipSC();
|
||||
}
|
||||
|
||||
this.eat(RightParenthesis);
|
||||
|
||||
return {
|
||||
type: 'ContainerFeatureStyle',
|
||||
loc: this.getLocation(start, this.tokenStart),
|
||||
name,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
this.token(Function, 'style(');
|
||||
this.token(Ident, node.name);
|
||||
|
||||
if (node.value !== null) {
|
||||
this.token(Colon, ':');
|
||||
this.node(node.value);
|
||||
}
|
||||
|
||||
this.token(RightParenthesis, ')');
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
WhiteSpace,
|
||||
Comment,
|
||||
Function,
|
||||
Ident,
|
||||
LeftParenthesis
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
import { lookahead_is_range } from './lookahead_is_range';
|
||||
|
||||
const CONTAINER_QUERY_KEYWORDS = new Set(['none', 'and', 'not', 'or']);
|
||||
|
||||
export const name = 'ContainerQuery';
|
||||
export const structure = {
|
||||
name: 'Identifier',
|
||||
children: [[
|
||||
'Identifier',
|
||||
'QueryFeature',
|
||||
'QueryFeatureRange',
|
||||
'ContainerFeatureStyle',
|
||||
'WhiteSpace'
|
||||
]]
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
const children = this.createList();
|
||||
let child = null;
|
||||
let name = null;
|
||||
|
||||
// Parse potential container name.
|
||||
if (this.tokenType === Ident) {
|
||||
const container_name = this.substring(this.tokenStart, this.tokenEnd);
|
||||
|
||||
// Container name doesn't match a query keyword, so assign it as container name.
|
||||
if (!CONTAINER_QUERY_KEYWORDS.has(container_name.toLowerCase())) {
|
||||
name = container_name;
|
||||
this.eatIdent(container_name);
|
||||
}
|
||||
}
|
||||
|
||||
this.skipSC();
|
||||
|
||||
scan:
|
||||
while (!this.eof) {
|
||||
switch (this.tokenType) {
|
||||
case Comment:
|
||||
case WhiteSpace:
|
||||
this.next();
|
||||
continue;
|
||||
|
||||
case Ident:
|
||||
child = this.Identifier();
|
||||
break;
|
||||
|
||||
case Function:
|
||||
child = this.ContainerFeatureStyle();
|
||||
break;
|
||||
|
||||
case LeftParenthesis:
|
||||
// Lookahead to determine if range feature.
|
||||
child = lookahead_is_range.call(this) ? this.QueryFeatureRange() : this.QueryFeature();
|
||||
break;
|
||||
|
||||
default:
|
||||
break scan;
|
||||
}
|
||||
|
||||
children.push(child);
|
||||
}
|
||||
|
||||
if (child === null) {
|
||||
this.error('Identifier or parenthesis is expected');
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'ContainerQuery',
|
||||
loc: this.getLocation(start, this.tokenStart - 1),
|
||||
name,
|
||||
children
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
if (typeof node.name === 'string') {
|
||||
this.token(Ident, node.name);
|
||||
}
|
||||
|
||||
this.children(node);
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
export * as Comparison from './comparison';
|
||||
export * as ContainerFeatureStyle from './container_feature_style';
|
||||
export * as ContainerQuery from './container_query';
|
||||
export * as MediaQuery from './media_query';
|
||||
export * as QueryFeature from './query_feature';
|
||||
export * as QueryFeatureRange from './query_feature_range';
|
||||
export * as QueryCSSFunction from './query_css_function';
|
@ -0,0 +1,44 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
EOF,
|
||||
WhiteSpace,
|
||||
Delim,
|
||||
RightParenthesis,
|
||||
LeftCurlyBracket,
|
||||
Colon
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
/**
|
||||
* Looks ahead to determine if query feature is a range query. This involves locating at least one delimiter and no
|
||||
* colon tokens.
|
||||
*
|
||||
* @returns {boolean} Is potential range query.
|
||||
*/
|
||||
export function lookahead_is_range() {
|
||||
let type;
|
||||
let offset = 0;
|
||||
|
||||
let count = 0;
|
||||
let delim_found = false;
|
||||
let no_colon = true;
|
||||
|
||||
// A range query has maximum 5 tokens when formatted as 'mf-range' /
|
||||
// '<mf-value> <mf-lt> <mf-name> <mf-lt> <mf-value>'. So only look ahead maximum of 6 non-whitespace tokens.
|
||||
do {
|
||||
type = this.lookupNonWSType(offset++);
|
||||
if (type !== WhiteSpace) {
|
||||
count++;
|
||||
}
|
||||
if (type === Delim) {
|
||||
delim_found = true;
|
||||
}
|
||||
if (type === Colon) {
|
||||
no_colon = false;
|
||||
}
|
||||
if (type === LeftCurlyBracket || type === RightParenthesis) {
|
||||
break;
|
||||
}
|
||||
} while (type !== EOF && count <= 6);
|
||||
|
||||
return delim_found && no_colon;
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
WhiteSpace,
|
||||
Comment,
|
||||
Ident,
|
||||
LeftParenthesis
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
import { lookahead_is_range } from './lookahead_is_range';
|
||||
|
||||
export const name = 'MediaQuery';
|
||||
export const structure = {
|
||||
children: [[
|
||||
'Identifier',
|
||||
'QueryFeature',
|
||||
'QueryFeatureRange',
|
||||
'WhiteSpace'
|
||||
]]
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const children = this.createList();
|
||||
let child = null;
|
||||
|
||||
this.skipSC();
|
||||
|
||||
scan:
|
||||
while (!this.eof) {
|
||||
switch (this.tokenType) {
|
||||
case Comment:
|
||||
case WhiteSpace:
|
||||
this.next();
|
||||
continue;
|
||||
|
||||
case Ident:
|
||||
child = this.Identifier();
|
||||
break;
|
||||
|
||||
case LeftParenthesis:
|
||||
// Lookahead to determine if range feature.
|
||||
child = lookahead_is_range.call(this) ? this.QueryFeatureRange() : this.QueryFeature();
|
||||
break;
|
||||
|
||||
default:
|
||||
break scan;
|
||||
}
|
||||
|
||||
children.push(child);
|
||||
}
|
||||
|
||||
if (child === null) {
|
||||
this.error('Identifier or parenthesis is expected');
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'MediaQuery',
|
||||
loc: this.getLocationFromList(children),
|
||||
children
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
this.children(node);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
RightParenthesis
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
const QUERY_CSS_FUNCTIONS = new Set(['calc', 'clamp', 'min', 'max']);
|
||||
|
||||
export const name = 'QueryCSSFunction';
|
||||
export const structure = {
|
||||
name: String,
|
||||
expression: String
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
|
||||
const name = this.consumeFunctionName();
|
||||
|
||||
if (!QUERY_CSS_FUNCTIONS.has(name)) {
|
||||
this.error('Unknown query single value function; expected: "calc", "clamp", "max", min"');
|
||||
}
|
||||
|
||||
const body = this.Raw(this.tokenIndex, null, false);
|
||||
|
||||
this.eat(RightParenthesis);
|
||||
|
||||
return {
|
||||
type: 'QueryCSSFunction',
|
||||
loc: this.getLocation(start, this.tokenStart),
|
||||
name,
|
||||
expression: body.value
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
this.token(Function, `${node.name}(`);
|
||||
|
||||
this.node(node.expression);
|
||||
|
||||
this.token(RightParenthesis, ')');
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
Ident,
|
||||
Number,
|
||||
Dimension,
|
||||
Function,
|
||||
LeftParenthesis,
|
||||
RightParenthesis,
|
||||
Colon,
|
||||
Delim
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
export const name = 'QueryFeature';
|
||||
export const structure = {
|
||||
name: String,
|
||||
value: ['Identifier', 'Number', 'Dimension', 'QueryCSSFunction', 'Ratio', null]
|
||||
};
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
let value = null;
|
||||
|
||||
this.eat(LeftParenthesis);
|
||||
this.skipSC();
|
||||
|
||||
const name = this.consume(Ident);
|
||||
this.skipSC();
|
||||
|
||||
if (this.tokenType !== RightParenthesis) {
|
||||
this.eat(Colon);
|
||||
this.skipSC();
|
||||
|
||||
switch (this.tokenType) {
|
||||
case Number:
|
||||
if (this.lookupNonWSType(1) === Delim) {
|
||||
value = this.Ratio();
|
||||
} else {
|
||||
value = this.Number();
|
||||
}
|
||||
break;
|
||||
|
||||
case Dimension:
|
||||
value = this.Dimension();
|
||||
break;
|
||||
|
||||
case Function:
|
||||
value = this.QueryCSSFunction();
|
||||
break;
|
||||
|
||||
case Ident:
|
||||
value = this.Identifier();
|
||||
break;
|
||||
|
||||
default:
|
||||
this.error('Number, dimension, ratio, function, or identifier is expected');
|
||||
break;
|
||||
}
|
||||
|
||||
this.skipSC();
|
||||
}
|
||||
|
||||
this.eat(RightParenthesis);
|
||||
|
||||
return {
|
||||
type: 'QueryFeature',
|
||||
loc: this.getLocation(start, this.tokenStart),
|
||||
name,
|
||||
value
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
this.token(LeftParenthesis, '(');
|
||||
this.token(Ident, node.name);
|
||||
|
||||
if (node.value !== null) {
|
||||
this.token(Colon, ':');
|
||||
this.node(node.value);
|
||||
}
|
||||
|
||||
this.token(RightParenthesis, ')');
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
// @ts-nocheck
|
||||
import {
|
||||
Ident,
|
||||
Number,
|
||||
Delim,
|
||||
Dimension,
|
||||
Function,
|
||||
LeftParenthesis,
|
||||
RightParenthesis,
|
||||
WhiteSpace
|
||||
} from 'css-tree/tokenizer';
|
||||
|
||||
export const name = 'QueryFeatureRange';
|
||||
export const structure = {
|
||||
name: String,
|
||||
value: ['Identifier', 'Number', 'Comparison', 'Dimension', 'QueryCSSFunction', 'Ratio', null]
|
||||
};
|
||||
|
||||
function lookup_non_WS_type_and_value(offset, type, referenceStr) {
|
||||
let current_type;
|
||||
|
||||
do {
|
||||
current_type = this.lookupType(offset++);
|
||||
if (current_type !== WhiteSpace) {
|
||||
break;
|
||||
}
|
||||
} while (current_type !== 0); // NULL -> 0
|
||||
|
||||
return current_type === type ? this.lookupValue(offset - 1, referenceStr) : false;
|
||||
}
|
||||
|
||||
export function parse() {
|
||||
const start = this.tokenStart;
|
||||
const children = this.createList();
|
||||
let child = null;
|
||||
|
||||
this.eat(LeftParenthesis);
|
||||
this.skipSC();
|
||||
|
||||
while (!this.eof && this.tokenType !== RightParenthesis) {
|
||||
switch (this.tokenType) {
|
||||
case Number:
|
||||
if (lookup_non_WS_type_and_value.call(this, 1, Delim, '/')) {
|
||||
child = this.Ratio();
|
||||
} else {
|
||||
child = this.Number();
|
||||
}
|
||||
break;
|
||||
|
||||
case Delim:
|
||||
child = this.Comparison();
|
||||
break;
|
||||
|
||||
case Dimension:
|
||||
child = this.Dimension();
|
||||
break;
|
||||
|
||||
case Function:
|
||||
child = this.QueryCSSFunction();
|
||||
break;
|
||||
|
||||
case Ident:
|
||||
child = this.Identifier();
|
||||
break;
|
||||
|
||||
default:
|
||||
this.error('Number, dimension, comparison, ratio, function, or identifier is expected');
|
||||
break;
|
||||
}
|
||||
|
||||
children.push(child);
|
||||
|
||||
this.skipSC();
|
||||
}
|
||||
|
||||
this.eat(RightParenthesis);
|
||||
|
||||
return {
|
||||
type: 'QueryFeatureRange',
|
||||
loc: this.getLocation(start, this.tokenStart),
|
||||
children
|
||||
};
|
||||
}
|
||||
|
||||
export function generate(node) {
|
||||
this.children(node);
|
||||
}
|
@ -0,0 +1 @@
|
||||
div.svelte-xyz{container:test-container / inline-size}@container (min-width: 400px){div.svelte-xyz{color:red}}@container test-container (min-width: 410px){div.svelte-xyz{color:green}}@container test-container (width < 400px){div.svelte-xyz{color:blue}}@container test-container (0 <= width < 300px){div.svelte-xyz{color:purple}}@container not (width < 400px){div.svelte-xyz{color:pink}}@container (width > 400px) and (height > 400px){div.svelte-xyz{color:lightgreen}}@container (width > 400px) or (height > 400px){div.svelte-xyz{color:lightblue}}@container (width > 400px) and (width > 800px) or (orientation: portrait){div.svelte-xyz{color:salmon}}@container style(color: blue){div.svelte-xyz{color:tan}}@container test-container (min-width: calc(400px + 1px)){div.svelte-xyz{color:green}}@container test-container (width < clamp(200px, 40%, 400px)){div.svelte-xyz{color:blue}}@container test-container (calc(400px + 1px) <= width < calc(500px + 1px)){div.svelte-xyz{color:purple}}@container style(--var: calc(400px + 1px)){div.svelte-xyz{color:sandybrown}}
|
@ -0,0 +1,87 @@
|
||||
<div>container query</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
container: test-container / inline-size;
|
||||
}
|
||||
|
||||
/* Most common container query statements. */
|
||||
|
||||
@container (min-width: 400px) {
|
||||
div {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (min-width: 410px) {
|
||||
div {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (width < 400px) {
|
||||
div {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (0 <= width < 300px) {
|
||||
div {
|
||||
color: purple;
|
||||
}
|
||||
}
|
||||
|
||||
@container not (width < 400px) {
|
||||
div {
|
||||
color: pink;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width > 400px) and (height > 400px) {
|
||||
div {
|
||||
color: lightgreen;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width > 400px) or (height > 400px) {
|
||||
div {
|
||||
color: lightblue;
|
||||
}
|
||||
}
|
||||
|
||||
@container (width > 400px) and (width > 800px) or (orientation: portrait) {
|
||||
div {
|
||||
color: salmon;
|
||||
}
|
||||
}
|
||||
|
||||
@container style(color: blue) {
|
||||
div {
|
||||
color: tan;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (min-width: calc(400px + 1px)) {
|
||||
div {
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (width < clamp(200px, 40%, 400px)) {
|
||||
div {
|
||||
color: blue;
|
||||
}
|
||||
}
|
||||
|
||||
@container test-container (calc(400px + 1px) <= width < calc(500px + 1px)) {
|
||||
div {
|
||||
color: purple;
|
||||
}
|
||||
}
|
||||
|
||||
@container style(--var: calc(400px + 1px)) {
|
||||
div {
|
||||
color: sandybrown;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1 +1 @@
|
||||
@media(min-width: 400px){.large-screen.svelte-xyz{display:block}}
|
||||
@media(min-width: 400px){.large-screen.svelte-xyz{display:block}}@media(min-width: calc(400px + 1px)){.large-screen.svelte-xyz{display:block}}@media(width >= 600px){.large-screen.svelte-xyz{display:block}}@media(400px <= width <= 1000px){.large-screen.svelte-xyz{display:block}}@media(width < clamp(200px, 40%, 400px)){.large-screen.svelte-xyz{display:block}}@media(calc(400px + 1px) <= width <= calc(1000px + 1px)){.large-screen.svelte-xyz{display:block}}
|
@ -0,0 +1 @@
|
||||
<div><!-- test1 --><!-- test2 --></div>
|
@ -0,0 +1 @@
|
||||
<div><!-- test1 --></div>
|
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
compileOptions: {
|
||||
preserveComments:true
|
||||
},
|
||||
snapshot(target) {
|
||||
const div = target.querySelector('div');
|
||||
|
||||
return {
|
||||
div,
|
||||
comment: div.childNodes[0]
|
||||
};
|
||||
},
|
||||
|
||||
test(assert, target, snapshot) {
|
||||
const div = target.querySelector('div');
|
||||
assert.equal(div, snapshot.div);
|
||||
assert.equal(div.childNodes[0], snapshot.comment);
|
||||
assert.equal(div.childNodes[1].nodeType, 8);
|
||||
}
|
||||
};
|
@ -0,0 +1 @@
|
||||
<div><!-- test1 --><!-- test2 --></div>
|
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
options: {
|
||||
preserveComments: true
|
||||
}
|
||||
};
|
@ -0,0 +1,58 @@
|
||||
/* generated by Svelte vX.Y.Z */
|
||||
import {
|
||||
SvelteComponent,
|
||||
comment,
|
||||
detach,
|
||||
element,
|
||||
init,
|
||||
insert,
|
||||
noop,
|
||||
safe_not_equal,
|
||||
space
|
||||
} from "svelte/internal";
|
||||
|
||||
function create_fragment(ctx) {
|
||||
let div0;
|
||||
let t1;
|
||||
let c;
|
||||
let t2;
|
||||
let div1;
|
||||
|
||||
return {
|
||||
c() {
|
||||
div0 = element("div");
|
||||
div0.textContent = "content";
|
||||
t1 = space();
|
||||
c = comment(" comment ");
|
||||
t2 = space();
|
||||
div1 = element("div");
|
||||
div1.textContent = "more content";
|
||||
},
|
||||
m(target, anchor) {
|
||||
insert(target, div0, anchor);
|
||||
insert(target, t1, anchor);
|
||||
insert(target, c, anchor);
|
||||
insert(target, t2, anchor);
|
||||
insert(target, div1, anchor);
|
||||
},
|
||||
p: noop,
|
||||
i: noop,
|
||||
o: noop,
|
||||
d(detaching) {
|
||||
if (detaching) detach(div0);
|
||||
if (detaching) detach(t1);
|
||||
if (detaching) detach(c);
|
||||
if (detaching) detach(t2);
|
||||
if (detaching) detach(div1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class Component extends SvelteComponent {
|
||||
constructor(options) {
|
||||
super();
|
||||
init(this, options, null, create_fragment, safe_not_equal, {});
|
||||
}
|
||||
}
|
||||
|
||||
export default Component;
|
@ -0,0 +1,3 @@
|
||||
<div>content</div>
|
||||
<!-- comment -->
|
||||
<div>more content</div>
|
@ -0,0 +1,10 @@
|
||||
export default {
|
||||
props: {
|
||||
hidden: true
|
||||
},
|
||||
html: '<div hidden />',
|
||||
test({ assert, component, target }) {
|
||||
component.hidden = false;
|
||||
assert.htmlEqual(target.innerHTML, '<div />');
|
||||
}
|
||||
};
|
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
export let hidden = false;
|
||||
</script>
|
||||
|
||||
<div {hidden} />
|
@ -1,11 +0,0 @@
|
||||
export default {
|
||||
props: {
|
||||
itemscope: true
|
||||
},
|
||||
test({ assert, target, component }) {
|
||||
const div = target.querySelector('div');
|
||||
assert.ok(div.itemscope);
|
||||
component.itemscope = false;
|
||||
assert.ok(!div.itemscope);
|
||||
}
|
||||
};
|
@ -1,5 +0,0 @@
|
||||
<script>
|
||||
export let itemscope;
|
||||
</script>
|
||||
|
||||
<div {itemscope} />
|
@ -0,0 +1,4 @@
|
||||
export default {
|
||||
html: '<textarea></textarea>',
|
||||
ssrHtml: '<textarea>test\'"></textarea><script>alert(\'BIM\');</script></textarea>'
|
||||
};
|
@ -0,0 +1 @@
|
||||
<textarea value={`test'"></textarea><script>alert('BIM');</script>`} />
|
@ -0,0 +1,25 @@
|
||||
// There is no relationship between the attribute and the dom node with regards to microdata attributes https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata
|
||||
export default {
|
||||
html: `<div itemscope itemtype="https://schema.org/SoftwareApplication">
|
||||
<span itemprop="name">Game</span> - REQUIRES
|
||||
<span itemprop="operatingSystem">OS</span><br/>
|
||||
<link itemprop="applicationCategory" href="https://schema.org/GameApplication"/>
|
||||
|
||||
<div itemprop="aggregateRating" itemscope="" itemtype="https://schema.org/AggregateRating">RATING:
|
||||
<span itemprop="ratingValue">4.6</span> (
|
||||
<span itemprop="ratingCount">8864</span> ratings )</div>
|
||||
<div itemref="offers"></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
itemprop="offers"
|
||||
itemid="offers"
|
||||
id="offers"
|
||||
itemscope
|
||||
itemtype="https://schema.org/Offer"
|
||||
>
|
||||
Price: $<span itemprop="price">1.00</span>
|
||||
<meta itemprop="priceCurrency" content="USD"/>
|
||||
</div>
|
||||
`
|
||||
};
|
@ -0,0 +1,31 @@
|
||||
<!-- Example from https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata -->
|
||||
<div itemscope itemtype="https://schema.org/SoftwareApplication">
|
||||
<span itemprop="name">Game</span> - REQUIRES
|
||||
<span itemprop="operatingSystem">OS</span><br />
|
||||
<link
|
||||
itemprop="applicationCategory"
|
||||
href="https://schema.org/GameApplication"
|
||||
/>
|
||||
|
||||
<div
|
||||
itemprop="aggregateRating"
|
||||
itemscope
|
||||
itemtype="https://schema.org/AggregateRating"
|
||||
>
|
||||
RATING:
|
||||
<span itemprop="ratingValue">4.6</span> (
|
||||
<span itemprop="ratingCount">8864</span> ratings )
|
||||
</div>
|
||||
<div itemref="offers" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
itemprop="offers"
|
||||
itemid="offers"
|
||||
id="offers"
|
||||
itemscope
|
||||
itemtype="https://schema.org/Offer"
|
||||
>
|
||||
Price: $<span itemprop="price">1.00</span>
|
||||
<meta itemprop="priceCurrency" content="USD" />
|
||||
</div>
|
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
html: `
|
||||
<p>4, 12, 60</p>
|
||||
`,
|
||||
|
||||
async test({ component, target, assert }) {
|
||||
component.permutation = [2, 3, 1];
|
||||
await (component.promise1 = Promise.resolve({length: 1, width: 2, height: 3}));
|
||||
try {
|
||||
await (component.promise2 = Promise.reject({length: 97, width: 98, height: 99}));
|
||||
} catch (e) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
assert.htmlEqual(target.innerHTML, `
|
||||
<p>2, 11, 2</p>
|
||||
<p>9506, 28811, 98</p>
|
||||
`);
|
||||
}
|
||||
};
|
@ -0,0 +1,27 @@
|
||||
<script>
|
||||
export let promise1 = {length: 5, width: 3, height: 4};
|
||||
export let promise2 = {length: 12, width: 5, height: 13};
|
||||
export let permutation = [1, 2, 3];
|
||||
|
||||
function calculate(length, width, height) {
|
||||
return {
|
||||
'1-Dimensions': [length, width, height],
|
||||
'2-Dimensions': [length * width, width * height, length * height],
|
||||
'3-Dimensions': [length * width * height, length + width + height, length * width + width * height + length * height]
|
||||
};
|
||||
}
|
||||
|
||||
const th = 'th';
|
||||
</script>
|
||||
|
||||
{#await promise1 then { length, width, height }}
|
||||
{@const { [0]: a, [1]: b, [2]: c } = permutation}
|
||||
{@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) }
|
||||
<p>{first}, {second}, {third}</p>
|
||||
{/await}
|
||||
|
||||
{#await promise2 catch { [`leng${th}`]: l, [`wid${th}`]: w, height: h }}
|
||||
{@const [a, b, c] = permutation}
|
||||
{@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(l, w, h) }
|
||||
<p>{first}, {second}, {third}</p>
|
||||
{/await}
|
@ -0,0 +1,15 @@
|
||||
export default {
|
||||
html: `
|
||||
<button>6, 12, 8, 24</button>
|
||||
<button>45, 35, 63, 315</button>
|
||||
<button>60, 48, 80, 480</button>
|
||||
`,
|
||||
|
||||
async test({ component, target, assert }) {
|
||||
component.boxes = [{ length: 10, width: 20, height: 30 }];
|
||||
|
||||
assert.htmlEqual(target.innerHTML,
|
||||
'<button>200, 600, 300, 6000</button>'
|
||||
);
|
||||
}
|
||||
};
|
@ -0,0 +1,44 @@
|
||||
<script>
|
||||
export let boxes = [
|
||||
{length: 2, width: 3, height: 4},
|
||||
{length: 9, width: 5, height: 7},
|
||||
{length: 10, width: 6, height: 8}
|
||||
];
|
||||
|
||||
function calculate(length, width, height) {
|
||||
return {
|
||||
twoDimensions: {
|
||||
bottomArea: length * width,
|
||||
sideArea1: width * height,
|
||||
sideArea2: length * height
|
||||
},
|
||||
threeDimensions: {
|
||||
volume: length * width * height
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export let dimension = 'Dimensions';
|
||||
function changeDimension() {
|
||||
dimension = 'DIMENSIONS';
|
||||
}
|
||||
|
||||
let area = 'Area';
|
||||
let th = 'th';
|
||||
</script>
|
||||
|
||||
{#each boxes as { [`leng${th}`]: length, [`wid${th}`]: width, height }}
|
||||
{@const {
|
||||
[`two${dimension}`]: areas,
|
||||
[`three${dimension}`]: {
|
||||
volume
|
||||
}
|
||||
} = calculate(length, width, height)}
|
||||
{@const {
|
||||
i = 1,
|
||||
[`bottom${area}`]: bottom,
|
||||
[`side${area}${i++}`]: sideone,
|
||||
[`side${area}${i++}`]: sidetwo
|
||||
} = areas}
|
||||
<button on:click={changeDimension}>{bottom}, {sideone}, {sidetwo}, {volume}</button>
|
||||
{/each}
|
Loading…
Reference in new issue