mirror of https://github.com/sveltejs/svelte
commit
58568930f9
@ -1,52 +0,0 @@
|
|||||||
# Configuration for probot-stale - https://github.com/probot/stale
|
|
||||||
|
|
||||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
|
||||||
onlyLabels: []
|
|
||||||
|
|
||||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
|
||||||
exemptLabels:
|
|
||||||
- popular
|
|
||||||
- pinned
|
|
||||||
- security
|
|
||||||
- bug
|
|
||||||
- "[Status] Maybe Later"
|
|
||||||
|
|
||||||
# Set to true to ignore issues in a project (defaults to false)
|
|
||||||
exemptProjects: false
|
|
||||||
|
|
||||||
# Set to true to ignore issues in a milestone (defaults to false)
|
|
||||||
exemptMilestones: false
|
|
||||||
|
|
||||||
# Set to true to ignore issues with an assignee (defaults to false)
|
|
||||||
exemptAssignees: false
|
|
||||||
|
|
||||||
# Label to use when marking as stale
|
|
||||||
staleLabel: stale-bot
|
|
||||||
|
|
||||||
# Comment to post when removing the stale label.
|
|
||||||
# unmarkComment: >
|
|
||||||
# Your comment here.
|
|
||||||
|
|
||||||
# Limit the number of actions per hour, from 1-30. Default is 30
|
|
||||||
limitPerRun: 1
|
|
||||||
|
|
||||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
|
||||||
pulls:
|
|
||||||
daysUntilStale: 210
|
|
||||||
daysUntilClose: 25
|
|
||||||
markComment: >
|
|
||||||
This pull request has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
|
||||||
for your contributions.
|
|
||||||
closeComment: >
|
|
||||||
This pull request has been closed as it was previously marked as stale and saw no subsequent activity.
|
|
||||||
|
|
||||||
issues:
|
|
||||||
daysUntilStale: 180
|
|
||||||
daysUntilClose: 14
|
|
||||||
markComment: >
|
|
||||||
This issue has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
|
||||||
for your contributions.
|
|
||||||
closeComment: >
|
|
||||||
This issue has been closed as it was previously marked as stale and saw no subsequent activity.
|
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
title: "What's new in Svelte: January 2022"
|
||||||
|
description: "Faster builds with SvelteKit and a much anticipated REPL feature"
|
||||||
|
author: Daniel Sandoval
|
||||||
|
authorURL: https://desandoval.net
|
||||||
|
---
|
||||||
|
|
||||||
|
Happy new year, Svelte Community! Lots to share this month across Svelte, SvelteKit, Language Tools and the Showcase. Thanks to everyone who made 2021 a great year to use Svelte. Looking forward to the next one 🚀
|
||||||
|
|
||||||
|
## What's new in SvelteKit
|
||||||
|
- `@sveltejs/adapter-static` for SvelteKit now has a `precompress` option to make brotli compression of assets and pages easier to do out of the box ([#3079](https://github.com/sveltejs/kit/pull/3079))
|
||||||
|
- Concurrency mode in SvelteKit will now prerender pages in parallel ([#3120](https://github.com/sveltejs/kit/pull/3120)). It is enabled by default in `1.0.0-next.205` and later
|
||||||
|
- CSS is now automatically included before JS for improved page performance ([d13efe](https://github.com/sveltejs/kit/commit/d138efe21692f5925f1e89afc0a33f42d6a1a711))
|
||||||
|
- A new config option adds the ability to disable service worker registration to do your own custom registration ([#2988](https://github.com/sveltejs/kit/pull/2988))
|
||||||
|
- SSR route-splitting is here - breaking monolithic builds into smaller pieces for improved startup and routing performance ([#2931](https://github.com/sveltejs/kit/pull/2931))
|
||||||
|
- `request.origin/path/query` is now `request.url` - simplifying the config and page `load` functions ([#3126](https://github.com/sveltejs/kit/pull/3126))
|
||||||
|
- After the [update to Vite 2.7](https://github.com/sveltejs/kit/pull/3018), SvelteKit users are [reporting significant performance improvements](https://www.reddit.com/r/sveltejs/comments/rljhfc/sveltekit_massive_compiler_improvement_by/) and loading third-parties libraries in SSR has also been greatly improved
|
||||||
|
- SvelteKit server will now automatically restart when the config files is changed ([vite-plugin-svelte#237](https://github.com/sveltejs/vite-plugin-svelte/pull/237))
|
||||||
|
|
||||||
|
|
||||||
|
## Other new bits from `svelte/*`
|
||||||
|
- [Svelte 3.44.3](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md#3443) is out with a few bug fixes in the binding and loop code
|
||||||
|
- Svelte Language Tools has introduced support for the then/catch shorthands from Svelte 3.41 and TypeScript's "go to" functionality ([105.8.0 and later](https://github.com/sveltejs/language-tools/releases/tag/extensions-105.8.0))
|
||||||
|
- The Svelte REPL got a nice upgrade as well - letting you delete saved REPLs. Try it out by logging in at [svelte.dev/apps](https://svelte.dev/apps)
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Community Showcase
|
||||||
|
|
||||||
|
**Apps & Sites**
|
||||||
|
- [Discover Twitter Spaces](https://github.com/navneetsharmaui/discover-twitter-spaces) is a tool that helps you find the Twitter Spaces
|
||||||
|
- [Modern Fluid Typography Editor](https://github.com/codeAdrian/modern-fluid-typography-editor) helps create beautiful fluid typography using CSS clamp
|
||||||
|
- [Unnwhiteboard](https://github.com/AviKKi/unnwhiteboard) is a job board for companies (or teams) that don't do "whiteboard" interviews
|
||||||
|
- [Secret Santa](https://gitlab.com/arturoguzman/secret-santa-sveltekit) is a gift giving coordination app developed with easiness in mind
|
||||||
|
- [LogSnag](https://logsnag.com/) notifies you of your projects' events and provides you with a timeline to keep track of anything important that happens
|
||||||
|
- [Version 0.2 of Tangent](http://tangentnotes.com/Download), a Svelte-based note writing app, is now in beta
|
||||||
|
- [Intl Explorer](https://github.com/jesperorb/intl-explorer) is a tool for viewing output for all possible formatters for Intl
|
||||||
|
|
||||||
|
A lot of work this month has gone into migrating the Svelte main website and Svelte REPL to live in the https://github.com/sveltejs/sites repository - including a brand new homepage for [svelte.dev](https://svelte.dev/). Thanks to all the contributors who made this possible!
|
||||||
|
|
||||||
|
If you're looking for a fun SvelteKit project to work on, [you can contribute to the Svelte Society site rewrite](https://github.com/svelte-society/sveltesociety-2021/issues) 💅
|
||||||
|
|
||||||
|
|
||||||
|
**Learning and Listening**
|
||||||
|
|
||||||
|
_To Read_
|
||||||
|
- [Mutating Query Params in SvelteKit Without Page Reloads or Navigations](https://dev.to/mohamadharith/mutating-query-params-in-sveltekit-without-page-reloads-or-navigations-2i2b) by Mohamad Harith
|
||||||
|
- [Svelte for Reactaholics : A guide for React developers](https://www.100ms.live/blog/svelte-guide-for-react-developers) by Puru Vijay
|
||||||
|
- [Svelte's lifecycle methods can be used anywhere](https://geoffrich.net/posts/svelte-lifecycle-examples/) and [The many meanings of $ in Svelte](https://geoffrich.net/posts/svelte-$-meanings/) by Geoff Rich
|
||||||
|
- [Vercel and Svelte: A Perfect Match for Web Developers](https://thenewstack.io/vercel-and-svelte-a-perfect-match-for-web-developers/) by Darryl K. Taft
|
||||||
|
- [User-defined TailwindCSS Color Scheme with Svelte Stores](https://blog.dayslice.io/user-defined-tailwindcss-color-scheme-with-svelte-stores-ad80ca2cf038) by jeremy zaborowski
|
||||||
|
- [Ionic 6 + Svelte 🚀](https://medium.com/@raymondboswel/ionic-6-svelte-ae904caa82df) by Raymond Boswel
|
||||||
|
- [What happened in #Svelte language tools this year](https://twitter.com/dummdidumm_/status/1474158105395179525?t=ytj2K2Q52iD5-lNyLnQaAQ&s=19) by Simon H
|
||||||
|
|
||||||
|
_To Watch_
|
||||||
|
- [The Future of Svelte (Interview with Rich Harris)](https://www.youtube.com/watch?v=uQntFkK8Z54) by Lee Robinson, Director of Developer Relations at Vercel
|
||||||
|
- [Svelte is becoming the go-to framework](https://www.youtube.com/watch?v=fo6BKY2xR2w&t=1834s) for Obsidian plugin developers
|
||||||
|
- [Sveltekit WordPress Headless Blog](https://www.youtube.com/watch?v=c0UDVgjPxFw) by WebJeda
|
||||||
|
- [Getting started with SvelteKit](https://www.youtube.com/watch?v=i2suPKMPUFA) by Lihau Tan
|
||||||
|
- [Deploy a full-stack SvelteKit app on Cloudflare Pages](https://www.youtube.com/watch?v=Wc1_U6Dy5Tw) by 1nf
|
||||||
|
|
||||||
|
_To Listen To_
|
||||||
|
- [Syntax podcast: How To Do Things In Svelte](https://podcasts.apple.com/ca/podcast/how-to-do-things-in-svelte/id1253186678?i=1000544796072)
|
||||||
|
- [JS Party #205: So much Sveltey goodness (w/ Rich Harris)](https://changelog.com/jsparty/205)
|
||||||
|
|
||||||
|
**Libraries, Tools & Components**
|
||||||
|
- [svelte-headlessui](https://github.com/rgossiaux/svelte-headlessui) is an unofficial, complete Svelte port of the Headless UI component library
|
||||||
|
- [svelte-forms v2](https://chainlist.github.io/svelte-forms/) has been released - the author is [looking for feedback](https://www.reddit.com/r/sveltejs/comments/r6354j/svelteforms_v2_has_been_released/)
|
||||||
|
- [Percival](https://github.com/ekzhang/percival) is a declarative data query and visualization language
|
||||||
|
- [Svelte FlatList](https://github.com/snuffyDev/svelte-flatlist) is a mobile-friendly, simple, and customizable draggable menu
|
||||||
|
- [svelte-keyed](https://github.com/bryanmylee/svelte-keyed) is a writable derived store for objects and arrays
|
||||||
|
- [Svemix](https://github.com/svemix/svemix) is Remix for Svelte - providing server scripts inside your Svelte components/routes, which will be transformed into endpoints
|
||||||
|
|
||||||
|
Want to add something to the showcase? Need help bringing your next idea to life in Svelte? Join us on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.com/invite/yy75DKs).
|
||||||
|
|
||||||
|
See ya next month!
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
import Node from './shared/Node';
|
||||||
|
import Expression from './shared/Expression';
|
||||||
|
import Component from '../Component';
|
||||||
|
import TemplateScope from './shared/TemplateScope';
|
||||||
|
import { Context, unpack_destructuring } from './shared/Context';
|
||||||
|
import { ConstTag as ConstTagType } from '../../interfaces';
|
||||||
|
import { INodeAllowConstTag } from './interfaces';
|
||||||
|
import { walk } from 'estree-walker';
|
||||||
|
import { extract_identifiers } from 'periscopic';
|
||||||
|
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
|
||||||
|
import get_object from '../utils/get_object';
|
||||||
|
import compiler_errors from '../compiler_errors';
|
||||||
|
|
||||||
|
const allowed_parents = new Set(['EachBlock', 'CatchBlock', 'ThenBlock', 'InlineComponent', 'SlotTemplate']);
|
||||||
|
|
||||||
|
export default class ConstTag extends Node {
|
||||||
|
type: 'ConstTag';
|
||||||
|
expression: Expression;
|
||||||
|
contexts: Context[] = [];
|
||||||
|
node: ConstTagType;
|
||||||
|
scope: TemplateScope;
|
||||||
|
|
||||||
|
assignees: Set<string> = new Set();
|
||||||
|
dependencies: Set<string> = new Set();
|
||||||
|
|
||||||
|
constructor(component: Component, parent: INodeAllowConstTag, scope: TemplateScope, info: ConstTagType) {
|
||||||
|
super(component, parent, scope, info);
|
||||||
|
|
||||||
|
if (!allowed_parents.has(parent.type)) {
|
||||||
|
component.error(info, compiler_errors.invalid_const_placement);
|
||||||
|
}
|
||||||
|
this.node = info;
|
||||||
|
this.scope = scope;
|
||||||
|
|
||||||
|
const { assignees, dependencies } = this;
|
||||||
|
|
||||||
|
extract_identifiers(info.expression.left).forEach(({ name }) => {
|
||||||
|
assignees.add(name);
|
||||||
|
const owner = this.scope.get_owner(name);
|
||||||
|
if (owner === parent) {
|
||||||
|
component.error(info, compiler_errors.invalid_const_declaration(name));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
walk(info.expression.right, {
|
||||||
|
enter(node, parent) {
|
||||||
|
if (is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
|
||||||
|
const identifier = get_object(node as any);
|
||||||
|
const { name } = identifier;
|
||||||
|
dependencies.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_expression() {
|
||||||
|
unpack_destructuring({
|
||||||
|
contexts: this.contexts,
|
||||||
|
node: this.node.expression.left,
|
||||||
|
scope: this.scope,
|
||||||
|
component: this.component
|
||||||
|
});
|
||||||
|
this.expression = new Expression(this.component, this, this.scope, this.node.expression.right);
|
||||||
|
this.contexts.forEach(context => {
|
||||||
|
const owner = this.scope.get_owner(context.key.name);
|
||||||
|
if (owner && owner.type === 'ConstTag' && owner.parent === this.parent) {
|
||||||
|
this.component.error(this.node, compiler_errors.invalid_const_declaration(context.key.name));
|
||||||
|
}
|
||||||
|
this.scope.add(context.key.name, this.expression.dependencies, this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +0,0 @@
|
|||||||
import Component from '../Component';
|
|
||||||
import TemplateScope from './shared/TemplateScope';
|
|
||||||
import Node from './shared/Node';
|
|
||||||
import Let from './Let';
|
|
||||||
import { INode } from './interfaces';
|
|
||||||
|
|
||||||
export default class DefaultSlotTemplate extends Node {
|
|
||||||
type: 'SlotTemplate';
|
|
||||||
scope: TemplateScope;
|
|
||||||
children: INode[];
|
|
||||||
lets: Let[] = [];
|
|
||||||
slot_template_name = 'default';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
component: Component,
|
|
||||||
parent: INode,
|
|
||||||
scope: TemplateScope,
|
|
||||||
info: any,
|
|
||||||
lets: Let[],
|
|
||||||
children: INode[]
|
|
||||||
) {
|
|
||||||
super(component, parent, scope, info);
|
|
||||||
this.type = 'SlotTemplate';
|
|
||||||
this.children = children;
|
|
||||||
this.scope = scope;
|
|
||||||
this.lets = lets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import { TemplateNode } from '../../interfaces';
|
||||||
|
import Component from '../Component';
|
||||||
|
import { nodes_to_template_literal } from '../utils/nodes_to_template_literal';
|
||||||
|
import Expression from './shared/Expression';
|
||||||
|
import Node from './shared/Node';
|
||||||
|
import TemplateScope from './shared/TemplateScope';
|
||||||
|
|
||||||
|
export default class StyleDirective extends Node {
|
||||||
|
type: 'StyleDirective';
|
||||||
|
name: string;
|
||||||
|
expression: Expression;
|
||||||
|
should_cache: boolean;
|
||||||
|
|
||||||
|
constructor(component: Component, parent: Node, scope: TemplateScope, info: TemplateNode) {
|
||||||
|
super(component, parent, scope, info);
|
||||||
|
|
||||||
|
this.name = info.name;
|
||||||
|
|
||||||
|
// Convert the value array to an expression so it's easier to handle
|
||||||
|
// the StyleDirective going forward.
|
||||||
|
if (info.value === true || (info.value.length === 1 && info.value[0].type === 'MustacheTag')) {
|
||||||
|
const identifier = info.value === true
|
||||||
|
? {
|
||||||
|
type: 'Identifier',
|
||||||
|
start: info.end - info.name.length,
|
||||||
|
end: info.end,
|
||||||
|
name: info.name
|
||||||
|
} as any
|
||||||
|
: info.value[0].expression;
|
||||||
|
this.expression = new Expression(component, this, scope, identifier);
|
||||||
|
this.should_cache = false;
|
||||||
|
} else {
|
||||||
|
const raw_expression = nodes_to_template_literal(info.value);
|
||||||
|
this.expression = new Expression(component, this, scope, raw_expression);
|
||||||
|
this.should_cache = raw_expression.expressions.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
import { TemplateNode, ConstTag as ConstTagType } from '../../../interfaces';
|
||||||
|
import Component from '../../Component';
|
||||||
|
import ConstTag from '../ConstTag';
|
||||||
|
import map_children from './map_children';
|
||||||
|
import { INodeAllowConstTag, INode } from '../interfaces';
|
||||||
|
import check_graph_for_cycles from '../../utils/check_graph_for_cycles';
|
||||||
|
import compiler_errors from '../../compiler_errors';
|
||||||
|
|
||||||
|
export default function get_const_tags(children: TemplateNode[], component: Component, node: INodeAllowConstTag, parent: INode): [ConstTag[], Array<Exclude<INode, ConstTag>>] {
|
||||||
|
const const_tags: ConstTagType[] = [];
|
||||||
|
const others: Array<Exclude<TemplateNode, ConstTagType>> = [];
|
||||||
|
|
||||||
|
for (const child of children) {
|
||||||
|
if (child.type === 'ConstTag') {
|
||||||
|
const_tags.push(child as ConstTagType);
|
||||||
|
} else {
|
||||||
|
others.push(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const consts_nodes = const_tags.map(tag => new ConstTag(component, node, node.scope, tag));
|
||||||
|
const sorted_consts_nodes = sort_consts_nodes(consts_nodes, component);
|
||||||
|
sorted_consts_nodes.forEach(node => node.parse_expression());
|
||||||
|
|
||||||
|
const children_nodes = map_children(component, parent, node.scope, others);
|
||||||
|
|
||||||
|
return [sorted_consts_nodes, children_nodes as Array<Exclude<INode, ConstTag>>];
|
||||||
|
}
|
||||||
|
|
||||||
|
function sort_consts_nodes(consts_nodes: ConstTag[], component: Component) {
|
||||||
|
type ConstNode = {
|
||||||
|
assignees: Set<string>;
|
||||||
|
dependencies: Set<string>;
|
||||||
|
node: ConstTag;
|
||||||
|
};
|
||||||
|
const sorted_consts_nodes: ConstNode[] = [];
|
||||||
|
|
||||||
|
const unsorted_consts_nodes: ConstNode[] = consts_nodes.map(node => {
|
||||||
|
return {
|
||||||
|
assignees: node.assignees,
|
||||||
|
dependencies: node.dependencies,
|
||||||
|
node
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const lookup = new Map();
|
||||||
|
|
||||||
|
unsorted_consts_nodes.forEach(node => {
|
||||||
|
node.assignees.forEach(name => {
|
||||||
|
if (!lookup.has(name)) {
|
||||||
|
lookup.set(name, []);
|
||||||
|
}
|
||||||
|
lookup.get(name).push(node);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const cycle = check_graph_for_cycles(unsorted_consts_nodes.reduce((acc, node) => {
|
||||||
|
node.assignees.forEach(v => {
|
||||||
|
node.dependencies.forEach(w => {
|
||||||
|
if (!node.assignees.has(w)) {
|
||||||
|
acc.push([v, w]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}, []));
|
||||||
|
|
||||||
|
if (cycle && cycle.length) {
|
||||||
|
const nodeList = lookup.get(cycle[0]);
|
||||||
|
const node = nodeList[0];
|
||||||
|
component.error(node.node, compiler_errors.cyclical_const_tags(cycle));
|
||||||
|
}
|
||||||
|
|
||||||
|
const add_node = (node: ConstNode) => {
|
||||||
|
if (sorted_consts_nodes.includes(node)) return;
|
||||||
|
|
||||||
|
node.dependencies.forEach(name => {
|
||||||
|
if (node.assignees.has(name)) return;
|
||||||
|
const earlier_nodes = lookup.get(name);
|
||||||
|
if (earlier_nodes) {
|
||||||
|
earlier_nodes.forEach(add_node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sorted_consts_nodes.push(node);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsorted_consts_nodes.forEach(add_node);
|
||||||
|
|
||||||
|
return sorted_consts_nodes.map(node => node.node);
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import ConstTag from '../../../nodes/ConstTag';
|
||||||
|
import Block from '../../Block';
|
||||||
|
import { b, x } from 'code-red';
|
||||||
|
import Renderer from '../../Renderer';
|
||||||
|
|
||||||
|
export function add_const_tags(block: Block, const_tags: ConstTag[], ctx: string) {
|
||||||
|
const const_tags_props = [];
|
||||||
|
const_tags.forEach((const_tag, i) => {
|
||||||
|
const name = `#constants_${i}`;
|
||||||
|
const_tags_props.push(b`const ${name} = ${const_tag.expression.manipulate(block, ctx)}`);
|
||||||
|
const_tag.contexts.forEach(context => {
|
||||||
|
const_tags_props.push(b`${ctx}[${block.renderer.context_lookup.get(context.key.name).index}] = ${context.default_modifier(context.modifier({ type: 'Identifier', name }), name => block.renderer.context_lookup.has(name) ? x`${ctx}[${block.renderer.context_lookup.get(name).index}]` : { type: 'Identifier', name })};`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return const_tags_props;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function add_const_tags_context(renderer: Renderer, const_tags: ConstTag[]) {
|
||||||
|
const_tags.forEach(const_tag => {
|
||||||
|
const_tag.contexts.forEach(context => {
|
||||||
|
renderer.add_to_context(context.key.name, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import ConstTag from '../../../nodes/ConstTag';
|
||||||
|
|
||||||
|
export function get_const_tags(const_tags: ConstTag[]) {
|
||||||
|
if (const_tags.length === 0) return null;
|
||||||
|
return {
|
||||||
|
type: 'VariableDeclaration',
|
||||||
|
kind: 'let',
|
||||||
|
declarations: const_tags.map(const_tag => {
|
||||||
|
const assignment = const_tag.node.expression;
|
||||||
|
return {
|
||||||
|
type: 'VariableDeclarator',
|
||||||
|
id: assignment.left,
|
||||||
|
init: assignment.right
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import { TemplateElement, TemplateLiteral } from 'estree';
|
||||||
|
import { MustacheTag, Text } from '../../interfaces';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a list of Text and MustacheTags into a TemplateLiteral expression.
|
||||||
|
* Start/End positions on the elements of the expression are not set.
|
||||||
|
*/
|
||||||
|
export function nodes_to_template_literal(value: Array<Text | MustacheTag>): TemplateLiteral {
|
||||||
|
const literal: TemplateLiteral = {
|
||||||
|
type: 'TemplateLiteral',
|
||||||
|
expressions: [],
|
||||||
|
quasis: []
|
||||||
|
};
|
||||||
|
|
||||||
|
let quasi: TemplateElement = {
|
||||||
|
type: 'TemplateElement',
|
||||||
|
value: { raw: '', cooked: null },
|
||||||
|
tail: false
|
||||||
|
};
|
||||||
|
|
||||||
|
value.forEach((node) => {
|
||||||
|
if (node.type === 'Text') {
|
||||||
|
quasi.value.raw += node.raw;
|
||||||
|
} else if (node.type === 'MustacheTag') {
|
||||||
|
literal.quasis.push(quasi);
|
||||||
|
literal.expressions.push(node.expression as any);
|
||||||
|
quasi = {
|
||||||
|
type: 'TemplateElement',
|
||||||
|
value: { raw: '', cooked: null },
|
||||||
|
tail: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quasi.tail = true;
|
||||||
|
literal.quasis.push(quasi);
|
||||||
|
return literal;
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
<div>before</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- HTML_TAG_START -->a <!-- HTML_TAG_END --><!-- HTML_TAG_START -->b <!-- HTML_TAG_END --><!-- HTML_TAG_START -->c <!-- HTML_TAG_END -->
|
||||||
|
<div>after</div>
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
<div>before</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<!-- HTML_TAG_START -->a <!-- HTML_TAG_END --><!-- HTML_TAG_START -->b <!-- HTML_TAG_END --><!-- HTML_TAG_START -->c <!-- HTML_TAG_END -->
|
||||||
|
<div>after</div>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
let content = ["a ", "b ", "c "];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>before</div>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
{#each content as c}
|
||||||
|
{@html c}
|
||||||
|
{/each}
|
||||||
|
<div>after</div>
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div class:foo={isFoo}></div>
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 29,
|
||||||
|
"type": "Fragment",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 29,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 5,
|
||||||
|
"end": 22,
|
||||||
|
"type": "Class",
|
||||||
|
"name": "foo",
|
||||||
|
"modifiers": [],
|
||||||
|
"expression": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 16,
|
||||||
|
"end": 21,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 16
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 21
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "isFoo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div style:color></div>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 23,
|
||||||
|
"type": "Fragment",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 23,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 5,
|
||||||
|
"end": 16,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<div style:color="red"></div>
|
||||||
|
<div style:color='red'></div>
|
||||||
|
<div style:color=red></div>
|
||||||
|
<div style:color="red{variable}"></div>
|
||||||
|
<div style:color='red{variable}'></div>
|
||||||
|
<div style:color=red{variable}></div>
|
||||||
|
<div style:color={`template${literal}`}></div>
|
||||||
@ -0,0 +1,355 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 252,
|
||||||
|
"type": "Fragment",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 29,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 5,
|
||||||
|
"end": 22,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 18,
|
||||||
|
"end": 21,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 29,
|
||||||
|
"end": 30,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 30,
|
||||||
|
"end": 59,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 35,
|
||||||
|
"end": 52,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 48,
|
||||||
|
"end": 51,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 59,
|
||||||
|
"end": 60,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 60,
|
||||||
|
"end": 87,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 65,
|
||||||
|
"end": 80,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 77,
|
||||||
|
"end": 80,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 87,
|
||||||
|
"end": 88,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 88,
|
||||||
|
"end": 127,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 93,
|
||||||
|
"end": 120,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 106,
|
||||||
|
"end": 109,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 109,
|
||||||
|
"end": 119,
|
||||||
|
"type": "MustacheTag",
|
||||||
|
"expression": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 110,
|
||||||
|
"end": 118,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 22
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "variable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 127,
|
||||||
|
"end": 128,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 128,
|
||||||
|
"end": 167,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 133,
|
||||||
|
"end": 160,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 146,
|
||||||
|
"end": 149,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 149,
|
||||||
|
"end": 159,
|
||||||
|
"type": "MustacheTag",
|
||||||
|
"expression": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 150,
|
||||||
|
"end": 158,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 22
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "variable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 167,
|
||||||
|
"end": 168,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 168,
|
||||||
|
"end": 205,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 173,
|
||||||
|
"end": 198,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 185,
|
||||||
|
"end": 188,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 188,
|
||||||
|
"end": 198,
|
||||||
|
"type": "MustacheTag",
|
||||||
|
"expression": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 189,
|
||||||
|
"end": 197,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 6,
|
||||||
|
"column": 21
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 6,
|
||||||
|
"column": 29
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "variable"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 205,
|
||||||
|
"end": 206,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "\n",
|
||||||
|
"data": "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"start": 206,
|
||||||
|
"end": 252,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 211,
|
||||||
|
"end": 245,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 223,
|
||||||
|
"end": 245,
|
||||||
|
"type": "MustacheTag",
|
||||||
|
"expression": {
|
||||||
|
"type": "TemplateLiteral",
|
||||||
|
"start": 224,
|
||||||
|
"end": 244,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 18
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 38
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expressions": [
|
||||||
|
{
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 235,
|
||||||
|
"end": 242,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 29
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 36
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "literal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"quasis": [
|
||||||
|
{
|
||||||
|
"type": "TemplateElement",
|
||||||
|
"start": 225,
|
||||||
|
"end": 233,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 19
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 27
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"raw": "template",
|
||||||
|
"cooked": "template"
|
||||||
|
},
|
||||||
|
"tail": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TemplateElement",
|
||||||
|
"start": 243,
|
||||||
|
"end": 243,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 37
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 7,
|
||||||
|
"column": 37
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"raw": "",
|
||||||
|
"cooked": ""
|
||||||
|
},
|
||||||
|
"tail": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div style:color={myColor}></div>
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 33,
|
||||||
|
"type": "Fragment",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 33,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 5,
|
||||||
|
"end": 26,
|
||||||
|
"type": "StyleDirective",
|
||||||
|
"name": "color",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 17,
|
||||||
|
"end": 26,
|
||||||
|
"type": "MustacheTag",
|
||||||
|
"expression": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 18,
|
||||||
|
"end": 25,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 18
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 25
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "myColor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div style="color: red;">red</div>
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 34,
|
||||||
|
"type": "Fragment",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 0,
|
||||||
|
"end": 34,
|
||||||
|
"type": "Element",
|
||||||
|
"name": "div",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"start": 5,
|
||||||
|
"end": 24,
|
||||||
|
"type": "Attribute",
|
||||||
|
"name": "style",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"start": 12,
|
||||||
|
"end": 23,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "color: red;",
|
||||||
|
"data": "color: red;"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"start": 25,
|
||||||
|
"end": 28,
|
||||||
|
"type": "Text",
|
||||||
|
"raw": "red",
|
||||||
|
"data": "red"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
export default {
|
export default {
|
||||||
html: '<textarea readonly></textarea>',
|
html: '<textarea readonly data-attr="true"></textarea>',
|
||||||
test({ assert, target }) {
|
test({ assert, target }) {
|
||||||
const textarea = target.querySelector('textarea');
|
const textarea = target.querySelector('textarea');
|
||||||
|
assert.equal(textarea.dataset.attr, 'true');
|
||||||
assert.ok(textarea.readOnly);
|
assert.ok(textarea.readOnly);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
<textarea readonly="{true}"></textarea>
|
<textarea readonly={true} data-attr={true} />
|
||||||
|
|||||||
@ -0,0 +1,18 @@
|
|||||||
|
// binding member expression shouldn't invalidate the property name
|
||||||
|
export default {
|
||||||
|
async test({ assert, component, target, window }) {
|
||||||
|
const input = target.querySelector('input');
|
||||||
|
assert.deepEqual(component.logs.length, 1);
|
||||||
|
assert.equal(input.value, 'abc');
|
||||||
|
|
||||||
|
input.value = 'hij';
|
||||||
|
await input.dispatchEvent(new window.Event('input'));
|
||||||
|
|
||||||
|
assert.deepEqual(component.values.a, 'hij');
|
||||||
|
assert.deepEqual(component.logs.length, 1);
|
||||||
|
|
||||||
|
component.paths = ['b'];
|
||||||
|
assert.deepEqual(component.logs.length, 2);
|
||||||
|
assert.equal(input.value, 'def');
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
export let values = { a: 'abc', b: 'def' };
|
||||||
|
export let paths = ['a'];
|
||||||
|
export let logs = [];
|
||||||
|
|
||||||
|
$: paths && logs.push('paths updated');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<input bind:value={values[paths[0]]} />
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
export default {
|
||||||
|
html: '<div>content</div><div>content</div><div>content</div>',
|
||||||
|
|
||||||
|
test({ assert, target, component }) {
|
||||||
|
const divs = target.querySelectorAll('div');
|
||||||
|
assert.equal(component.refs[0], divs[0]);
|
||||||
|
assert.equal(component.refs[1], divs[1]);
|
||||||
|
assert.equal(component.refs[2], divs[2]);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
export let data = [ { id: '1' }, { id: '2' }, { id: '3' } ];
|
||||||
|
|
||||||
|
export let refs = [];
|
||||||
|
|
||||||
|
// note that this is NOT data.slice().reverse()
|
||||||
|
// as that wouldn't have triggered an infinite loop
|
||||||
|
$: list = data.reverse();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each list as { id }, index (id)}
|
||||||
|
<div bind:this={refs[index]}>
|
||||||
|
content
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
// binding member expression shouldn't invalidate the property name
|
||||||
|
export default {
|
||||||
|
test({ assert, component, target }) {
|
||||||
|
const div = target.querySelector('div');
|
||||||
|
assert.equal(div, component.container.a);
|
||||||
|
assert.deepEqual(component.logs.length, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
export let container = {};
|
||||||
|
export let paths = ['a'];
|
||||||
|
export let logs = [];
|
||||||
|
|
||||||
|
$: paths && logs.push('paths updated');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div bind:this={container[paths[0]]} />
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
export default {
|
||||||
|
html: '<div>12 120 70, 30+4=34</div>',
|
||||||
|
async test({ component, target, assert }) {
|
||||||
|
component.promise1 = Promise.resolve({width: 5, height: 6});
|
||||||
|
component.promise2 = Promise.reject({width: 6, height: 7});
|
||||||
|
|
||||||
|
await Promise.resolve();
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>30 300 110, 50+6=56</div>
|
||||||
|
<div>42 420 130, 60+7=67</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.constant = 20;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>42 840 260, 120+7=127</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<script>
|
||||||
|
export let promise1 = {width: 3, height: 4};
|
||||||
|
export let promise2 = {width: 5, height: 7};
|
||||||
|
export let constant = 10;
|
||||||
|
|
||||||
|
function calculate(width, height, constant) {
|
||||||
|
return { area: width * height, volume: width * height * constant };
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await promise1 then { width, height }}
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
{#await promise2 catch { width, height }}
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
{/await}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
export default {
|
||||||
|
html: '<div>12 120 70, 30+4=34</div>',
|
||||||
|
async test({ component, target, assert }) {
|
||||||
|
component.promise1 = Promise.resolve({width: 5, height: 6});
|
||||||
|
component.promise2 = Promise.reject({width: 6, height: 7});
|
||||||
|
|
||||||
|
await Promise.resolve();
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>30 300 110, 50+6=56</div>
|
||||||
|
<div>42 420 130, 60+7=67</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.constant = 20;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>42 840 260, 120+7=127</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<script>
|
||||||
|
export let promise1 = {width: 3, height: 4};
|
||||||
|
export let promise2 = {width: 5, height: 7};
|
||||||
|
export let constant = 10;
|
||||||
|
|
||||||
|
function calculate(width, height, constant) {
|
||||||
|
return { area: width * height, volume: width * height * constant };
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#await promise1 then box}
|
||||||
|
{@const {area, volume} = calculate(box.width, box.height, constant)}
|
||||||
|
{@const perimeter = (box.width + box.height) * constant}
|
||||||
|
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
{#await promise2 catch box}
|
||||||
|
{@const {area, volume} = calculate(box.width, box.height, constant)}
|
||||||
|
{@const perimeter = (box.width + box.height) * constant}
|
||||||
|
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
|
||||||
|
{/await}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
export let box;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot name="box1" {box} />
|
||||||
|
<slot name="box2" width={box.width} height={box.height} />
|
||||||
|
<slot {box} />
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
<div slot="box1">
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
</div>
|
||||||
|
<div slot="box2">
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
</div>
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
`,
|
||||||
|
async test({ component, target, assert }) {
|
||||||
|
component.constant = 20;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div slot="box1">
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
</div>
|
||||||
|
<div slot="box2">
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
</div>
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.box = {width: 5, height: 6};
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div slot="box1">
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
</div>
|
||||||
|
<div slot="box2">
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
</div>
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
<script>
|
||||||
|
import Component from './Component.svelte';
|
||||||
|
export let box = {width: 3, height: 4};
|
||||||
|
export let constant = 10;
|
||||||
|
|
||||||
|
function calculate(width, height, constant) {
|
||||||
|
return { area: width * height, volume: width * height * constant };
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Component {box}>
|
||||||
|
<svelte:fragment slot="box1" let:box>
|
||||||
|
{@const {area, volume} = calculate(box.width, box.height, constant)}
|
||||||
|
{@const perimeter = (box.width + box.height) * constant}
|
||||||
|
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<svelte:fragment slot="box2" let:width let:height>
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<svelte:fragment let:box={{width, height}}>
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
</svelte:fragment>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component {box} let:box>
|
||||||
|
<div slot="box1" let:box>
|
||||||
|
{@const {area, volume} = calculate(box.width, box.height, constant)}
|
||||||
|
{@const perimeter = (box.width + box.height) * constant}
|
||||||
|
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div slot="box2" let:width let:height>
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{@const {area, volume} = calculate(box.width, box.height, constant)}
|
||||||
|
{@const perimeter = (box.width + box.height) * constant}
|
||||||
|
{@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {width}+{height}={sum}</div>
|
||||||
|
</Component>
|
||||||
|
|
||||||
|
<Component {box} let:box={{width, height}}>
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
</Component>
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<div>7</div>
|
||||||
|
`,
|
||||||
|
async test({ component, target, assert }) {
|
||||||
|
component.a = 5;
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>9</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<script>
|
||||||
|
export let value = 4;
|
||||||
|
export let a = 3;
|
||||||
|
export let b = 4;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each [value] as n}
|
||||||
|
{@const ab = a + b}
|
||||||
|
<div>{ab}</div>
|
||||||
|
{/each}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<div>12 120 70, 30+4=34</div>
|
||||||
|
<div>35 350 120, 50+7=57</div>
|
||||||
|
<div>48 480 140, 60+8=68</div>
|
||||||
|
`,
|
||||||
|
async test({ component, target, assert }) {
|
||||||
|
component.constant = 20;
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div>35 700 240, 100+7=107</div>
|
||||||
|
<div>48 960 280, 120+8=128</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.boxes = [
|
||||||
|
{width: 3, height: 4},
|
||||||
|
{width: 4, height: 5},
|
||||||
|
{width: 5, height: 6},
|
||||||
|
{width: 6, height: 7}
|
||||||
|
];
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<div>12 240 140, 60+4=64</div>
|
||||||
|
<div>20 400 180, 80+5=85</div>
|
||||||
|
<div>30 600 220, 100+6=106</div>
|
||||||
|
<div>42 840 260, 120+7=127</div>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<script>
|
||||||
|
export let boxes = [
|
||||||
|
{width: 3, height: 4},
|
||||||
|
{width: 5, height: 7},
|
||||||
|
{width: 6, height: 8},
|
||||||
|
];
|
||||||
|
export let constant = 10;
|
||||||
|
|
||||||
|
function calculate(width, height, constant) {
|
||||||
|
return { area: width * height, volume: width * height * constant };
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#each boxes as { width, height }}
|
||||||
|
{@const {area, volume} = calculate(width, height, constant)}
|
||||||
|
{@const perimeter = (width + height) * constant}
|
||||||
|
{@const [_width, _height, sum] = [width * constant, height, width * constant + height]}
|
||||||
|
<div>{area} {volume} {perimeter}, {_width}+{_height}={sum}</div>
|
||||||
|
{/each}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue