merge master -> init-contenteditable

pull/2996/head
Richard Harris 6 years ago
commit 9d94321333

@ -1,9 +0,0 @@
[ignore]
<PROJECT_ROOT>/types/.*
[include]
[libs]
[options]
strip_root=true

1
.gitattributes vendored

@ -1 +0,0 @@
*.svelte linguist-language=HTML

1
.gitignore vendored

@ -4,6 +4,7 @@
node_modules
*.map
/src/compiler/compile/internal-exports.ts
/compiler.d.ts
/compiler.*js
/index.*js
/internal

@ -9,12 +9,13 @@ init:
environment:
matrix:
# node.js
- nodejs_version: 8
- nodejs_version: 10
- nodejs_version: 12
install:
- ps: Install-Product node $env:nodejs_version
- npm install
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)
- npm ci || npm install
build: off

1
compiler.d.ts vendored

@ -1 +0,0 @@
export * from './types/compiler';

30
package-lock.json generated

@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "3.4.4",
"version": "3.5.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -30,16 +30,6 @@
"integrity": "sha512-UdVB1rSL7H8TS8674fH02p5lRbhfIqQ18YKLxLKEnHFztHUH6bhMqjebMxgSTmWVrs5raS5JSLJIKKHFT4WfPg==",
"dev": true
},
"@sveltejs/svelte-repl": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.0.5.tgz",
"integrity": "sha512-SKSX4xkqwH0XcUHQozwTNm3OCqatk66CXYZnqOW9Jf4E1B6opyQUb9f96KwAxh7ghZMbeePRv51oOWsw6n0Yww==",
"dev": true,
"requires": {
"codemirror": "^5.45.0",
"yootils": "0.0.15"
}
},
"@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@ -59,9 +49,9 @@
"dev": true
},
"@types/node": {
"version": "10.12.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==",
"version": "8.10.49",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.49.tgz",
"integrity": "sha512-YX30JVx0PvSmJ3Eqr74fYLGeBxD+C7vIL20ek+GGGLJeUbVYRUW3EzyAXpIRA0K8c8o0UWqR/GwEFYiFoz1T8w==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
@ -650,12 +640,6 @@
"urlgrey": "^0.4.4"
}
},
"codemirror": {
"version": "5.45.0",
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.45.0.tgz",
"integrity": "sha512-c19j644usCE8gQaXa0jqn2B/HN9MnB2u6qPIrrhrMkB+QAP42y8G4QnTwuwbVSoUS1jEl7JU9HZMGhCDL0nsAw==",
"dev": true
},
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@ -4750,12 +4734,6 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz",
"integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==",
"dev": true
},
"yootils": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/yootils/-/yootils-0.0.15.tgz",
"integrity": "sha512-GvGLuJ7XHJPGEUQ52vh8fh+vPjfikuGcu7yBswfrsNsHqnAoytOVuSb69eM0j8wQIjMz0U3kY3YsfwMhJgfG9w==",
"dev": true
}
}
}

@ -21,10 +21,10 @@
"engines": {
"node": ">= 8"
},
"types": "types/runtime",
"types": "types/runtime/index.d.ts",
"scripts": {
"test": "mocha --opts mocha.opts",
"test:unit": "mocha --require sucrase/register --recursive ./**/__test__.ts",
"test:unit": "mocha --require sucrase/register --recursive src/**/__test__.ts",
"quicktest": "mocha --opts mocha.opts",
"precoverage": "c8 mocha --opts mocha.coverage.opts",
"coverage": "c8 report --reporter=text-lcov > coverage.lcov && c8 report --reporter=html",
@ -35,10 +35,8 @@
"dev": "rollup -cw",
"pretest": "npm run build",
"posttest": "agadoo internal/index.mjs",
"prepublishOnly": "export PUBLISH=true && npm test && npm run create-stubs",
"create-stubs": "node scripts/create-stubs.js",
"tsd": "tsc -p . --emitDeclarationOnly",
"typecheck": "tsc -p . --noEmit",
"prepublishOnly": "PUBLISH=true npm test",
"tsd": "tsc -p src/compiler --emitDeclarationOnly && tsc -p src/runtime --emitDeclarationOnly",
"lint": "eslint \"{src,test}/**/*.{ts,js}\""
},
"repository": {
@ -58,9 +56,8 @@
},
"homepage": "https://github.com/sveltejs/svelte#README",
"devDependencies": {
"@sveltejs/svelte-repl": "0.0.5",
"@types/mocha": "^5.2.0",
"@types/node": "^10.5.5",
"@types/node": "=8",
"@typescript-eslint/eslint-plugin": "^1.9.0",
"@typescript-eslint/parser": "^1.9.0",
"acorn": "^6.1.1",

@ -20,6 +20,8 @@ const ts_plugin = is_publish
const external = id => id.startsWith('svelte/');
fs.writeFileSync(`./compiler.d.ts`, `export * from './types/compiler/index';`);
export default [
/* runtime */
{
@ -59,12 +61,22 @@ export default [
external,
plugins: [
ts_plugin,
dir === 'internal' && {
generateBundle(options, bundle) {
const mod = bundle['index.mjs'];
if (mod) {
fs.writeFileSync('src/compiler/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
{
writeBundle(bundle) {
if (dir === 'internal') {
const mod = bundle['index.mjs'];
if (mod) {
fs.writeFileSync('src/compiler/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
}
}
fs.writeFileSync(`${dir}/package.json`, JSON.stringify({
main: './index',
module: './index.mjs',
types: './index.d.ts'
}, null, ' '));
fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index';`);
}
}
]

@ -1,12 +0,0 @@
const fs = require('fs');
fs.readdirSync('src/runtime')
.filter(dir => fs.statSync(`src/runtime/${dir}`).isDirectory())
.forEach(dir => {
fs.writeFileSync(`${dir}/package.json`, JSON.stringify({
main: './index',
module: './index.mjs'
}, null, ' '));
fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index.d.ts';`);
});

@ -101,27 +101,7 @@ Text can also contain JavaScript expressions:
```
### HTML expressions
```sv
{@html expression}
```
---
In a text expression, characters like `<` and `>` are escaped. With HTML expressions, they're not.
> Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability.
```html
<div class="blog-post">
<h1>{post.title}</h1>
{@html post.content}
</div>
```
### If blocks
### {#if ...}
```sv
{#if expression}...{/if}
@ -158,7 +138,7 @@ Additional conditions can be added with `{:else if expression}`, optionally endi
```
### Each blocks
### {#each ...}
```sv
{#each expression as name}...{/each}
@ -229,7 +209,7 @@ An each block can also have an `{:else}` clause, which is rendered if the list i
```
### Await blocks
### {#await ...}
```sv
{#await expression}...{:then name}...{:catch name}...{/await}
@ -283,7 +263,80 @@ If you don't care about the pending state, you can also omit the initial block.
```
### DOM events
### {@html ...}
```sv
{@html expression}
```
---
In a text expression, characters like `<` and `>` are escaped. With HTML expressions, they're not.
> Svelte does not sanitize expressions before injecting HTML. If the data comes from an untrusted source, you must sanitize it, or you are exposing your users to an XSS vulnerability.
```html
<div class="blog-post">
<h1>{post.title}</h1>
{@html post.content}
</div>
```
### {@debug ...}
```sv
{@debug}
```
```sv
{@debug var1, var2, ..., varN}
```
---
The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open.
It accepts a comma-separated list of variable names (not arbitrary expressions).
```html
<script>
let user = {
firstname: 'Ada',
lastname: 'Lovelace'
};
</script>
{@debug user}
<h1>Hello {user.firstname}!</h1>
```
---
`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions).
```html
<!-- Compiles -->
{@debug user}
{@debug user1, user2, user3}
<!-- WON'T compile -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}
```
The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when *any* state changes, as opposed to the specified variables.
### Element directives
As well as attributes, elements can have *directives*, which control the element's behaviour in some way.
#### [on:*eventname*](on_component_event)
```sv
on:eventname={handler}
@ -324,6 +377,13 @@ Handlers can be declared inline with no performance penalty. As with attributes,
Add *modifiers* to DOM events with the `|` character.
```html
<form on:submit|preventDefault={handleSubmit}>
<!-- the `submit` event's default is prevented,
so the page won't reload -->
</form>
```
The following modifiers are available:
* `preventDefault` — calls `event.preventDefault()` before running the handler
@ -334,13 +394,6 @@ The following modifiers are available:
Modifiers can be chained together, e.g. `on:click|once|capture={...}`.
```html
<form on:submit|preventDefault={handleSubmit}>
<!-- the `submit` event's default is prevented,
so the page won't reload -->
</form>
```
---
If the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
@ -370,39 +423,11 @@ It's possible to have multiple event listeners for the same event:
<button on:click={increment} on:click={track}>Click me!</button>
```
### Component events
```sv
on:eventname={handler}
```
---
Components can emit events using [createEventDispatcher](docs#createEventDispatcher), or by forwarding DOM events. Listening for component events looks the same as listening for DOM events:
```html
<SomeComponent on:whatever={handler}/>
```
---
As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
```html
<SomeComponent on:whatever/>
```
### Element bindings
#### [bind:*property*](bind_element_property)
```sv
bind:property={variable}
```
```sv
bind:group={variable}
```
```sv
bind:this={dom_node}
```
---
@ -436,31 +461,8 @@ Numeric input values are coerced; even though `input.value` is a string as far a
<input type="range" bind:value={num}>
```
#### Binding related elements
---
Inputs that work together can use `bind:group`.
```html
<script>
let tortilla = 'Plain';
let fillings = [];
</script>
<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain">
<input type="radio" bind:group={tortilla} value="Whole wheat">
<input type="radio" bind:group={tortilla} value="Spinach">
<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice">
<input type="checkbox" bind:group={fillings} value="Beans">
<input type="checkbox" bind:group={fillings} value="Cheese">
<input type="checkbox" bind:group={fillings} value="Guac (extra)">
```
#### Binding `<select>` value
##### Binding `<select>` value
---
@ -500,7 +502,7 @@ When the value of an `<option>` matches its text content, the attribute can be o
</select>
```
#### Media element bindings
##### Media element bindings
---
@ -530,7 +532,7 @@ Media elements (`<audio>` and `<video>`) have their own set of bindings — four
></video>
```
#### Block-level element bindings
##### Block-level element bindings
---
@ -550,61 +552,61 @@ Block-level elements have 4 readonly bindings, measured using a technique simila
</div>
```
#### Binding a DOM node
#### bind:group
```sv
bind:group={variable}
```
---
To get a reference to a DOM node, use `bind:this`.
Inputs that work together can use `bind:group`.
```html
<script>
import { onMount } from 'svelte';
let canvasElement;
onMount(() => {
const ctx = canvasElement.getContext('2d');
drawStuff(ctx);
});
let tortilla = 'Plain';
let fillings = [];
</script>
<canvas bind:this={canvasElement}></canvas>
```
<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain">
<input type="radio" bind:group={tortilla} value="Whole wheat">
<input type="radio" bind:group={tortilla} value="Spinach">
<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice">
<input type="checkbox" bind:group={fillings} value="Beans">
<input type="checkbox" bind:group={fillings} value="Cheese">
<input type="checkbox" bind:group={fillings} value="Guac (extra)">
```
### Component bindings
#### [bind:this](bind_element)
```sv
bind:property={variable}
```
```sv
bind:this={component_instance}
bind:this={dom_node}
```
---
You can bind to component props using the same mechanism.
To get a reference to a DOM node, use `bind:this`.
```html
<Keypad bind:value={pin}/>
```
---
Components also support `bind:this`, allowing you to interact with component instances programmatically.
<script>
import { onMount } from 'svelte';
> Note that we can't do `{cart.empty}` since `cart` is `undefined` when the button is first rendered and throws an error.
let canvasElement;
```html
<ShoppingCart bind:this={cart}/>
onMount(() => {
const ctx = canvasElement.getContext('2d');
drawStuff(ctx);
});
</script>
<button on:click={() => cart.empty()}>
Empty shopping cart
</button>
<canvas bind:this={canvasElement}></canvas>
```
### Classes
#### class:*name*
```sv
class:name={value}
@ -630,7 +632,7 @@ A `class:` directive provides a shorter way of toggling a class on an element.
```
### Actions
#### use:*action*
```sv
use:action
@ -695,43 +697,19 @@ An action can have parameters. If the returned value has an `update` method, it
```
### Transitions
#### transition:*fn*
```sv
transition:name
transition:fn
```
```sv
transition:name={params}
transition:fn={params}
```
```sv
transition:name|local
transition:fn|local
```
```sv
transition:name|local={params}
```
```sv
in:name
```
```sv
in:name={params}
```
```sv
in:name|local
```
```sv
in:name|local={params}
```
```sv
out:name
```
```sv
out:name={params}
```
```sv
out:name|local
```
```sv
out:name|local={params}
transition:fn|local={params}
```
@ -747,7 +725,7 @@ transition = (node: HTMLElement, params: any) => {
---
A transition is triggered by an element entering or leaving the DOM as a result of a state change. Transitions do not run when a component is first mounted, but only on subsequent updates.
A transition is triggered by an element entering or leaving the DOM as a result of a state change.
Elements inside an *outroing* block are kept in the DOM until all current transitions have completed.
@ -761,21 +739,9 @@ The `transition:` directive indicates a *bidirectional* transition, which means
{/if}
```
---
The `in:` and `out:` directives are not bidirectional. An in transition will continue to 'play' alongside the out transition, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.
```html
{#if visible}
<div in:fly out:fade>
flies in, fades out
</div>
{/if}
```
> By default intro transitions will not play on first render. You can modify this behaviour by setting `intro: true` when you [create a component](docs#Client-side_component_API).
#### Transition parameters
##### Transition parameters
---
@ -791,7 +757,7 @@ Like actions, transitions can have parameters.
{/if}
```
#### Custom transition functions
##### Custom transition functions
---
@ -867,7 +833,7 @@ A custom transition function can also return a `tick` function, which is called
If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making [crossfade effects](tutorial/deferred-transitions) possible.
#### Transition events
##### Transition events
---
@ -911,7 +877,51 @@ Local transitions only play when the block they belong to is created or destroye
```
### Animations
#### in:*fn*/out:*fn*
```sv
in:fn
```
```sv
in:fn={params}
```
```sv
in:fn|local
```
```sv
in:fn|local={params}
```
```sv
out:fn
```
```sv
out:fn={params}
```
```sv
out:fn|local
```
```sv
out:fn|local={params}
```
---
Similar to `transition:`, but only applies to elements entering (`in:`) or leaving (`out:`) the DOM.
Unlike with `transition:`, transitions applied with `in:` and `out:` are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.
```html
{#if visible}
<div in:fly out:fade>
flies in, fades out
</div>
{/if}
```
#### animate:
```sv
animate:name
@ -957,7 +967,7 @@ Animations can be used with Svelte's [built-in animation functions](docs#svelte_
{/each}
```
#### Animation Parameters
##### Animation Parameters
---
@ -971,7 +981,7 @@ As with actions and transitions, animations can have parameters.
{/each}
```
#### Custom animation functions
##### Custom animation functions
---
@ -1045,9 +1055,68 @@ A custom animation function can also return a `tick` function, which is called *
{/each}
```
### Component directives
#### [on:*eventname*](on_component_event)
### Slots
```sv
on:eventname={handler}
```
---
Components can emit events using [createEventDispatcher](docs#createEventDispatcher), or by forwarding DOM events. Listening for component events looks the same as listening for DOM events:
```html
<SomeComponent on:whatever={handler}/>
```
---
As with DOM events, if the `on:` directive is used without a value, the component will *forward* the event, meaning that a consumer of the component can listen for it.
```html
<SomeComponent on:whatever/>
```
#### [bind:*property*](bind_component_property)
```sv
bind:property={variable}
```
---
You can bind to component props using the same mechanism.
```html
<Keypad bind:value={pin}/>
```
#### [bind:this](bind_component)
```sv
bind:this={component_instance}
```
---
Components also support `bind:this`, allowing you to interact with component instances programmatically.
> Note that we can't do `{cart.empty}` since `cart` is `undefined` when the button is first rendered and throws an error.
```html
<ShoppingCart bind:this={cart}/>
<button on:click={() => cart.empty()}>
Empty shopping cart
</button>
```
### `<slot>`
```sv
<slot><!-- optional fallback --></slot>
@ -1079,6 +1148,8 @@ The content is exposed in the child component using the `<slot>` element, which
</div>
```
#### [`<slot name="`*name*`">`](slot_name)
---
Named slots allow consumers to target specific areas. They can also have fallback content.
@ -1098,6 +1169,8 @@ Named slots allow consumers to target specific areas. They can also have fallbac
</div>
```
#### [`<slot let:`*name*`={`*value*`}>`](slot_let)
---
Slots can be rendered zero or more times, and can pass values *back* to the parent using props. The parent exposes the values to the slot template using the `let:` directive.
@ -1144,7 +1217,7 @@ Named slots can also expose values. The `let:` directive goes on the element wit
```
### &lt;svelte:self&gt;
### `<svelte:self>`
---
@ -1165,7 +1238,7 @@ It cannot appear at the top level of your markup; it must be inside an if or eac
{/if}
```
### &lt;svelte:component&gt;
### `<svelte:component>`
```sv
<svelte:component this={expression}>
@ -1182,7 +1255,7 @@ If `this` is falsy, no component is rendered.
```
### &lt;svelte:window&gt;
### `<svelte:window>`
```sv
<svelte:window on:event={handler}/>
@ -1224,7 +1297,7 @@ All except `scrollX` and `scrollY` are readonly.
```
### &lt;svelte:body&gt;
### `<svelte:body>`
```sv
<svelte:body on:event={handler}/>
@ -1242,7 +1315,7 @@ As with `<svelte:window>`, this element allows you to add listeners to events on
```
### &lt;svelte:head&gt;
### `<svelte:head>`
```sv
<svelte:head>
@ -1259,7 +1332,7 @@ This element makes it possible to insert elements into `document.head`. During s
```
### &lt;svelte:options&gt;
### `<svelte:options>`
```sv
<svelte:options option={value}>
@ -1278,51 +1351,4 @@ The `<svelte:options>` element provides a place to specify per-component compile
```html
<svelte:options tag="my-custom-element"/>
```
### @debug
```sv
{@debug}
```
```sv
{@debug var1, var2, ..., varN}
```
---
The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open.
It accepts a comma-separated list of variable names (not arbitrary expressions).
```html
<script>
let user = {
firstname: 'Ada',
lastname: 'Lovelace'
};
</script>
{@debug user}
<h1>Hello {user.firstname}!</h1>
```
---
`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions).
```html
<!-- Compiles -->
{@debug user}
{@debug user1, user2, user3}
<!-- WON'T compile -->
{@debug user.firstname}
{@debug myArray[0]}
{@debug !isReady}
{@debug typeof user === 'object'}
```
The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when *any* state changes, as opposed to the specified variables.
```

@ -43,10 +43,12 @@
}
function remove() {
people = [...people.slice(0, i), ...people.slice(i + 1)];
// Remove selected person from the source array (people), not the filtered array
const index = people.indexOf(selected);
people = [...people.slice(0, index), ...people.slice(index + 1)];
first = last = '';
i = Math.min(i, people.length - 1);
i = Math.min(i, filteredPeople.length - 2);
}
function reset_inputs(person) {

@ -1,6 +1,6 @@
<script>
import { comicSans, link } from './styles.js';
import Hero from './Hero.html';
import Hero from './Hero.svelte';
</script>
<Hero/>

@ -1,4 +1,6 @@
import { css } from 'emotion/dist/emotion.umd.min.js';
import emotion from 'emotion/dist/emotion.umd.min.js';
const { css } = emotion;
const brand = '#74D900';
@ -30,4 +32,4 @@ export const link = css`
text-decoration: none;
background: ${brand};
}
`;
`;

@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

@ -1,19 +0,0 @@
describe('Sapper template app', () => {
beforeEach(() => {
cy.visit('/')
});
it('has the correct <h1>', () => {
cy.contains('h1', 'Great success!')
});
it('navigates to /about', () => {
cy.get('nav a').contains('about').click();
cy.url().should('include', '/about');
});
it('navigates to /blog', () => {
cy.get('nav a').contains('blog').click();
cy.url().should('include', '/blog');
});
});

@ -1,17 +0,0 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

@ -1,25 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

@ -1,20 +0,0 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')

@ -1352,9 +1352,9 @@
}
},
"@sveltejs/site-kit": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.0.4.tgz",
"integrity": "sha512-BaQhIL1iPhCF+iDXfy9psDvRdFzfyMPkWnoZHfVz+INpHsU2aJmRZOPl9rykXmPyiPo+AwTTNK5vjIvmtwHLPQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/site-kit/-/site-kit-1.1.0.tgz",
"integrity": "sha512-Pe0vsIW5c3LDAY4K7mPa+S1gNAVkpVRfvfylHOPOufhdXOwU3E+YhobrF2MMLcM6FEonJv1Au/RHHSBZu8+aKg==",
"dev": true,
"requires": {
"@sindresorhus/slugify": "^0.9.1",
@ -1362,9 +1362,9 @@
}
},
"@sveltejs/svelte-repl": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.6.tgz",
"integrity": "sha512-3BH30SlzdSQzs1qiLr+kNXw1u81e31RiBtYXJ5YMq0d64VBXKNbP6TYOLQuCN5Ibe86wnPhJUHyIesMWIjyS6w==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@sveltejs/svelte-repl/-/svelte-repl-0.1.8.tgz",
"integrity": "sha512-RSKsuiQE3DrdT7B7DNhd5DK+DkYGLT5m6Ugchxc8iN+5v/hfVTbeNb+KJtItXLpDxiYdbb0HIiQPEdy0M+HThw==",
"dev": true,
"requires": {
"codemirror": "^5.45.0",
@ -4204,9 +4204,9 @@
}
},
"sapper": {
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/sapper/-/sapper-0.27.1.tgz",
"integrity": "sha512-RH0K1uQ3zJ1IXvowxr2SuboGXV69q22KaPMhhoM5VNDv9fsUlVHtluZE8WTcGxckiO2L1xFfgM7v/aINkSZpcw==",
"version": "0.27.3",
"resolved": "https://registry.npmjs.org/sapper/-/sapper-0.27.3.tgz",
"integrity": "sha512-JOSrQEw5bD3770edZ+gwdZxS/69sySl+0KuJyMiBQKRnb85cb55w/fBYg2SMhKDa/BlaXg14aL19OiBRpXGZLQ==",
"dev": true,
"requires": {
"html-minifier": "^4.0.0",
@ -4671,9 +4671,9 @@
}
},
"svelte": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.3.0.tgz",
"integrity": "sha512-iJYkIJDvAak1kizEYnE4b4eJ17D25fU0adW7GjDgO0klbjcAFlqtWEGFJa9kpJOlUtNLilcF09k4Y9TDmK/vjg==",
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.5.1.tgz",
"integrity": "sha512-iMnuyteFGQ8Yl68G/DHTHY1sLwoAMya1eS0ZOHIm/dqn2etR8WEe8hUAoluLryde4Cft4gvMhtHV3NhE60nBmQ==",
"dev": true
},
"tar": {
@ -4802,9 +4802,9 @@
}
},
"uglify-js": {
"version": "3.5.14",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz",
"integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==",
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
"integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
"dev": true,
"requires": {
"commander": "~2.20.0",

@ -7,13 +7,9 @@
"copy-workers": "rm -rf static/workers && cp -r node_modules/@sveltejs/svelte-repl/workers static",
"migrate": "node-pg-migrate -r dotenv/config",
"sapper": "npm run copy-workers && sapper build --legacy",
"update_shimport": "cp node_modules/shimport/index.js __sapper__/build/client/shimport@0.0.14.js",
"update": "node scripts/update_template.js && node scripts/get-contributors.js",
"start": "node __sapper__/build",
"cy:run": "cypress run",
"cy:open": "cypress open",
"test": "run-p --race dev cy:run",
"testsrc": "mocha -r esm test/**",
"test": "mocha -r esm test/**",
"deploy": "make deploy"
},
"dependencies": {
@ -38,8 +34,8 @@
"@babel/preset-env": "^7.4.4",
"@babel/runtime": "^7.4.4",
"@sindresorhus/slugify": "^0.9.1",
"@sveltejs/site-kit": "^1.0.4",
"@sveltejs/svelte-repl": "^0.1.6",
"@sveltejs/site-kit": "^1.1.0",
"@sveltejs/svelte-repl": "^0.1.8",
"degit": "^2.1.3",
"dotenv": "^8.0.0",
"eslint-plugin-svelte3": "^1.0.0",
@ -57,9 +53,9 @@
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^4.0.4",
"sapper": "^0.27.1",
"sapper": "^0.27.3",
"shelljs": "^0.8.3",
"svelte": "^3.0.0"
"svelte": "^3.5.1"
},
"engines": {
"node": ">=10.0.0"

@ -21,6 +21,7 @@
<NavItem segment="examples">Examples</NavItem>
<NavItem segment="repl">REPL</NavItem>
<NavItem segment="blog">Blog</NavItem>
<NavItem segment="faq">FAQ</NavItem>
<NavItem external="https://sapper.svelte.dev">Sapper</NavItem>
@ -46,4 +47,4 @@
padding: var(--nav-h) 0 0 0;
overflow-x: hidden;
}
</style>
</style>

@ -38,7 +38,7 @@ const blockTypes = [
];
export default function() {
const makeSlug = make_session_slug_processor({
const make_slug = make_session_slug_processor({
preserve_unicode: SLUG_PRESERVE_UNICODE,
separator: SLUG_SEPARATOR
});
@ -51,7 +51,7 @@ export default function() {
const { content, metadata } = extract_frontmatter(markdown);
const sectionSlug = makeSlug(metadata.title);
const section_slug = make_slug(metadata.title);
const subsections = [];
@ -108,18 +108,24 @@ export default function() {
};
renderer.heading = (text, level, rawtext) => {
const slug = makeSlug(rawtext);
let slug;
const match = /<a href="([^"]+)">(.+)<\/a>/.exec(text);
if (match) {
slug = match[1];
text = match[2];
} else {
slug = make_slug(rawtext);
}
if (level === 3 || level === 4) {
const title = unescape(
text
.replace(/<\/?code>/g, '')
.replace(/\.(\w+)(\((.+)?\))?/, (m, $1, $2, $3) => {
if ($3) return `.${$1}(...)`;
if ($2) return `.${$1}()`;
return `.${$1}`;
})
);
const title = text
.replace(/<\/?code>/g, '')
.replace(/\.(\w+)(\((.+)?\))?/, (m, $1, $2, $3) => {
if ($3) return `.${$1}(...)`;
if ($2) return `.${$1}()`;
return `.${$1}`;
});
subsections.push({ slug, title, level });
}
@ -147,7 +153,7 @@ export default function() {
html: html.replace(/@@(\d+)/g, (m, id) => hashes[id] || m),
metadata,
subsections,
slug: sectionSlug,
slug: section_slug,
file,
};
});

@ -1,4 +1,4 @@
import { assign } from '../../runtime/internal/index';
import { assign } from '../../runtime/internal/utils';
import Stats from '../Stats';
import parse from '../parse/index';
import render_dom from './render-dom/index';
@ -6,6 +6,7 @@ import render_ssr from './render-ssr/index';
import { CompileOptions, Warning } from '../interfaces';
import Component from './Component';
import fuzzymatch from '../utils/fuzzymatch';
import get_name_from_filename from './utils/get_name_from_filename';
const valid_options = [
'format',
@ -55,25 +56,6 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
}
}
function get_name(filename: string) {
if (!filename) return null;
// eslint-disable-next-line no-useless-escape
const parts = filename.split(/[\/\\]/);
if (parts.length > 1 && /^index\.\w+/.test(parts[parts.length - 1])) {
parts.pop();
}
const base = parts.pop()
.replace(/\..+/, "")
.replace(/[^a-zA-Z_$0-9]+/g, '_')
.replace(/^_/, '')
.replace(/_$/, '')
.replace(/^(\d)/, '_$1');
return base[0].toUpperCase() + base.slice(1);
}
export default function compile(source: string, options: CompileOptions = {}) {
options = assign({ generate: 'dom', dev: false }, options);
@ -90,7 +72,7 @@ export default function compile(source: string, options: CompileOptions = {}) {
const component = new Component(
ast,
source,
options.name || get_name(options.filename) || 'Component',
options.name || get_name_from_filename(options.filename) || 'Component',
options,
stats,
warnings

@ -12,7 +12,7 @@ export default class Text extends Node {
super(component, parent, scope, info);
this.data = info.data;
if (!component.component_options.preserveWhitespace && !/\S/.test(info.data)) {
if (!component.component_options.preserveWhitespace && !/[\S\u00A0]/.test(info.data)) {
let node = parent;
while (node) {
if (node.type === 'Element' && node.name === 'pre') {

@ -224,79 +224,20 @@ export default class AttributeWrapper {
}
}
// source: https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
// source: https://html.spec.whatwg.org/multipage/indices.html
const attribute_lookup = {
accept: { applies_to: ['form', 'input'] },
'accept-charset': { property_name: 'acceptCharset', applies_to: ['form'] },
accesskey: { property_name: 'accessKey' },
action: { applies_to: ['form'] },
align: {
applies_to: [
'applet',
'caption',
'col',
'colgroup',
'hr',
'iframe',
'img',
'table',
'tbody',
'td',
'tfoot',
'th',
'thead',
'tr',
],
},
allowfullscreen: { property_name: 'allowFullscreen', applies_to: ['iframe'] },
alt: { applies_to: ['applet', 'area', 'img', 'input'] },
allowpaymentrequest: { property_name: 'allowPaymentRequest', applies_to: ['iframe'] },
async: { applies_to: ['script'] },
autocomplete: { applies_to: ['form', 'input'] },
autofocus: { applies_to: ['button', 'input', 'keygen', 'select', 'textarea'] },
autoplay: { applies_to: ['audio', 'video'] },
autosave: { applies_to: ['input'] },
bgcolor: {
property_name: 'bgColor',
applies_to: [
'body',
'col',
'colgroup',
'marquee',
'table',
'tbody',
'tfoot',
'td',
'th',
'tr',
],
},
border: { applies_to: ['img', 'object', 'table'] },
buffered: { applies_to: ['audio', 'video'] },
challenge: { applies_to: ['keygen'] },
charset: { applies_to: ['meta', 'script'] },
checked: { applies_to: ['command', 'input'] },
cite: { applies_to: ['blockquote', 'del', 'ins', 'q'] },
class: { property_name: 'className' },
code: { applies_to: ['applet'] },
codebase: { property_name: 'codeBase', applies_to: ['applet'] },
color: { applies_to: ['basefont', 'font', 'hr'] },
cols: { applies_to: ['textarea'] },
colspan: { property_name: 'colSpan', applies_to: ['td', 'th'] },
content: { applies_to: ['meta'] },
contenteditable: { property_name: 'contentEditable' },
contextmenu: {},
checked: { applies_to: ['input'] },
controls: { applies_to: ['audio', 'video'] },
coords: { applies_to: ['area'] },
data: { applies_to: ['object'] },
datetime: { property_name: 'dateTime', applies_to: ['del', 'ins', 'time'] },
default: { applies_to: ['track'] },
defer: { applies_to: ['script'] },
dir: {},
dirname: { property_name: 'dirName', applies_to: ['input', 'textarea'] },
disabled: {
applies_to: [
'button',
'command',
'fieldset',
'input',
'keygen',
@ -306,119 +247,21 @@ const attribute_lookup = {
'textarea',
],
},
download: { applies_to: ['a', 'area'] },
draggable: {},
dropzone: {},
enctype: { applies_to: ['form'] },
for: { property_name: 'htmlFor', applies_to: ['label', 'output'] },
formaction: { applies_to: ['input', 'button'] },
headers: { applies_to: ['td', 'th'] },
height: {
applies_to: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
},
formnovalidate: { property_name: 'formNoValidate', applies_to: ['button', 'input'] },
hidden: {},
high: { applies_to: ['meter'] },
href: { applies_to: ['a', 'area', 'base', 'link'] },
hreflang: { applies_to: ['a', 'area', 'link'] },
'http-equiv': { property_name: 'httpEquiv', applies_to: ['meta'] },
icon: { applies_to: ['command'] },
id: {},
indeterminate: { applies_to: ['input'] },
ismap: { property_name: 'isMap', applies_to: ['img'] },
itemprop: {},
keytype: { applies_to: ['keygen'] },
kind: { applies_to: ['track'] },
label: { applies_to: ['track'] },
lang: {},
language: { applies_to: ['script'] },
loop: { applies_to: ['audio', 'bgsound', 'marquee', 'video'] },
low: { applies_to: ['meter'] },
manifest: { applies_to: ['html'] },
max: { applies_to: ['input', 'meter', 'progress'] },
maxlength: { property_name: 'maxLength', applies_to: ['input', 'textarea'] },
media: { applies_to: ['a', 'area', 'link', 'source', 'style'] },
method: { applies_to: ['form'] },
min: { applies_to: ['input', 'meter'] },
loop: { applies_to: ['audio', 'bgsound', 'video'] },
multiple: { applies_to: ['input', 'select'] },
muted: { applies_to: ['audio', 'video'] },
name: {
applies_to: [
'button',
'form',
'fieldset',
'iframe',
'input',
'keygen',
'object',
'output',
'select',
'textarea',
'map',
'meta',
'param',
],
},
nomodule: { property_name: 'noModule', applies_to: ['script'] },
novalidate: { property_name: 'noValidate', applies_to: ['form'] },
open: { applies_to: ['details'] },
optimum: { applies_to: ['meter'] },
pattern: { applies_to: ['input'] },
ping: { applies_to: ['a', 'area'] },
placeholder: { applies_to: ['input', 'textarea'] },
poster: { applies_to: ['video'] },
preload: { applies_to: ['audio', 'video'] },
radiogroup: { applies_to: ['command'] },
open: { applies_to: ['details', 'dialog'] },
playsinline: { property_name: 'playsInline', applies_to: ['video'] },
readonly: { property_name: 'readOnly', applies_to: ['input', 'textarea'] },
rel: { applies_to: ['a', 'area', 'link'] },
required: { applies_to: ['input', 'select', 'textarea'] },
reversed: { applies_to: ['ol'] },
rows: { applies_to: ['textarea'] },
rowspan: { property_name: 'rowSpan', applies_to: ['td', 'th'] },
sandbox: { applies_to: ['iframe'] },
scope: { applies_to: ['th'] },
scoped: { applies_to: ['style'] },
seamless: { applies_to: ['iframe'] },
selected: { applies_to: ['option'] },
shape: { applies_to: ['a', 'area'] },
size: { applies_to: ['input', 'select'] },
sizes: { applies_to: ['link', 'img', 'source'] },
span: { applies_to: ['col', 'colgroup'] },
spellcheck: {},
src: {
applies_to: [
'audio',
'embed',
'iframe',
'img',
'input',
'script',
'source',
'track',
'video',
],
},
srcdoc: { applies_to: ['iframe'] },
srclang: { applies_to: ['track'] },
srcset: { applies_to: ['img'] },
start: { applies_to: ['ol'] },
step: { applies_to: ['input'] },
style: { property_name: 'style.cssText' },
summary: { applies_to: ['table'] },
tabindex: { property_name: 'tabIndex' },
target: { applies_to: ['a', 'area', 'base', 'form'] },
title: {},
type: {
applies_to: [
'button',
'command',
'embed',
'object',
'script',
'source',
'style',
'menu',
],
},
usemap: { property_name: 'useMap', applies_to: ['img', 'input', 'object'] },
value: {
applies_to: [
'button',
@ -432,12 +275,6 @@ const attribute_lookup = {
'textarea',
],
},
volume: { applies_to: ['audio', 'video'] },
playbackRate: { applies_to: ['audio', 'video'] },
width: {
applies_to: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
},
wrap: { applies_to: ['textarea'] },
};
Object.keys(attribute_lookup).forEach(name => {

@ -1,6 +1,7 @@
import * as assert from 'assert';
import deindent from './deindent';
import CodeBuilder from './CodeBuilder';
import get_name_from_filename from './get_name_from_filename';
describe('deindent', () => {
it('deindents a simple string', () => {
@ -164,3 +165,17 @@ describe('CodeBuilder', () => {
);
});
});
describe('get_name_from_filename', () => {
it('uses the basename', () => {
assert.equal(get_name_from_filename('path/to/Widget.svelte'), 'Widget');
});
it('uses the directory name, if basename is index', () => {
assert.equal(get_name_from_filename('path/to/Widget/index.svelte'), 'Widget');
});
it('handles unusual filenames', () => {
assert.equal(get_name_from_filename('path/to/[...parts].svelte'), 'Parts');
});
});

@ -0,0 +1,26 @@
export default function get_name_from_filename(filename: string) {
if (!filename) return null;
// eslint-disable-next-line no-useless-escape
const parts = filename.split(/[\/\\]/);
if (parts.length > 1) {
const index_match = parts[parts.length - 1].match(/^index(\.\w+)/);
if (index_match) {
parts.pop();
parts[parts.length - 1] += index_match[1];
}
}
const base = parts.pop()
.replace(/\.[^.]+$/, "")
.replace(/[^a-zA-Z_$0-9]+/g, '_')
.replace(/^_/, '')
.replace(/_$/, '')
.replace(/^(\d)/, '_$1');
if (!base) {
throw new Error(`Could not derive component name from file ${filename}`);
}
return base[0].toUpperCase() + base.slice(1);
}

@ -385,6 +385,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
let value: any[] | true = true;
if (parser.eat('=')) {
parser.allow_whitespace();
value = read_attribute_value(parser);
end = parser.index;
} else if (parser.match_regex(/["']/)) {

@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"include": ["."],
"compilerOptions": {
"lib": ["es2017", "webworker"]
// TODO: remove mocha types from the whole project
// "types": ["node", "estree"]
}
}

@ -0,0 +1,19 @@
declare module '*.svelte' {
type Props = Record<string, any>;
export default class {
constructor(options: {
target: Element;
anchor?: Element;
props?: Props;
hydrate?: boolean;
intro?: boolean;
});
$set(props: Props): void;
$on<T = any>(event: string, callback: (event: CustomEvent<T>) => void): () => void;
$destroy(): void;
[accessor: string]: any;
}
}

@ -1,3 +1,5 @@
import './ambient';
export {
onMount,
onDestroy,

@ -1,4 +1,5 @@
import { identity as linear, noop, now } from './utils';
import { identity as linear, noop } from './utils';
import { now } from './environment';
import { loop } from './loop';
import { create_rule, delete_rule } from './style_manager';
import { AnimationConfig } from '../animate';

@ -0,0 +1,16 @@
export const is_client = typeof window !== 'undefined';
export let now: () => number = is_client
? () => window.performance.now()
: () => Date.now();
export let raf = cb => requestAnimationFrame(cb);
// used internally for testing
export function set_now(fn) {
now = fn;
}
export function set_raf(fn) {
raf = fn;
}

@ -1,6 +1,7 @@
export * from './animations';
export * from './await-block';
export * from './dom';
export * from './environment';
export * from './keyed-each';
export * from './lifecycle';
export * from './loop';

@ -1,4 +1,4 @@
import { now, raf } from './utils';
import { now, raf } from './environment';
export interface Task { abort(): void; promise: Promise<void> }

@ -1,5 +1,5 @@
import { element } from './dom';
import { raf } from './utils';
import { raf } from './environment';
let stylesheet;
let active = 0;

@ -1,4 +1,5 @@
import { identity as linear, is_function, noop, now, run_all } from './utils';
import { identity as linear, is_function, noop, run_all } from './utils';
import { now } from "./environment";
import { loop } from './loop';
import { create_rule, delete_rule } from './style_manager';
import { custom_event } from './dom';

@ -87,22 +87,5 @@ export function once(fn) {
if (ran) return;
ran = true;
fn.call(this, ...args);
}
}
const is_client = typeof window !== 'undefined';
export let now: () => number = is_client
? () => window.performance.now()
: () => Date.now();
export let raf = is_client ? requestAnimationFrame : noop;
// used internally for testing
export function set_now(fn) {
now = fn;
}
export function set_raf(fn) {
raf = fn;
};
}

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.json",
"include": ["."],
"compilerOptions": {
"lib": ["es2015", "dom", "dom.iterable"],
"target": "es2015",
"types": [],
"baseUrl": ".",
"paths": {
"svelte/*": ["*"]
}
}
}

@ -1,6 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
attr,
detach,
element,
init,
@ -16,7 +17,7 @@ function create_fragment(ctx) {
c() {
a = element("a");
a.textContent = "Test";
a.href = "#";
attr(a, "href", "#");
},
m(target, anchor) {

@ -2,6 +2,7 @@
import {
SvelteComponent,
append,
attr,
detach,
element,
init,
@ -26,7 +27,7 @@ function create_fragment(ctx) {
c() {
p = element("p");
t = text(ctx.foo);
p.className = "svelte-1a7i8ec";
attr(p, "class", "svelte-1a7i8ec");
},
m(target, anchor) {

@ -2,6 +2,7 @@
import {
SvelteComponent,
append,
attr,
detach,
element,
init,
@ -23,7 +24,7 @@ function create_fragment(ctx) {
return {
c() {
div = element("div");
div.className = "svelte-1slhpfn";
attr(div, "class", "svelte-1slhpfn");
},
m(target, anchor) {

@ -2,6 +2,7 @@
import {
SvelteComponent,
append,
attr,
destroy_each,
detach,
detach_after,
@ -39,8 +40,8 @@ function create_each_block(ctx) {
t5 = text(" ago:");
t6 = space();
raw_before = element('noscript');
span.className = "meta";
div.className = "comment";
attr(span, "class", "meta");
attr(div, "class", "comment");
},
m(target, anchor) {

@ -1,6 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
attr,
detach,
element,
init,
@ -17,7 +18,7 @@ function create_fragment(ctx) {
c() {
a = element("a");
a.textContent = "this should not navigate to example.com";
a.href = "https://example.com";
attr(a, "href", "https://example.com");
dispose = listen(a, "touchstart", touchstart_handler);
},

@ -2,6 +2,7 @@
import {
SvelteComponent,
append,
attr,
detach,
element,
init,
@ -16,10 +17,10 @@ function create_fragment(ctx) {
c() {
meta0 = element("meta");
meta1 = element("meta");
meta0.name = "twitter:creator";
meta0.content = "@sveltejs";
meta1.name = "twitter:title";
meta1.content = "Svelte";
attr(meta0, "name", "twitter:creator");
attr(meta0, "content", "@sveltejs");
attr(meta1, "name", "twitter:title");
attr(meta1, "content", "Svelte");
},
m(target, anchor) {

@ -1,6 +1,7 @@
/* generated by Svelte vX.Y.Z */
import {
SvelteComponent,
attr,
detach,
element,
init,
@ -18,8 +19,8 @@ function create_fragment(ctx) {
div0 = element("div");
t = space();
div1 = element("div");
div0.style.cssText = ctx.style;
div1.style.cssText = div1_style_value = "" + ctx.key + ": " + ctx.value;
attr(div0, "style", ctx.style);
attr(div1, "style", div1_style_value = "" + ctx.key + ": " + ctx.value);
},
m(target, anchor) {
@ -30,11 +31,11 @@ function create_fragment(ctx) {
p(changed, ctx) {
if (changed.style) {
div0.style.cssText = ctx.style;
attr(div0, "style", ctx.style);
}
if ((changed.key || changed.value) && div1_style_value !== (div1_style_value = "" + ctx.key + ": " + ctx.value)) {
div1.style.cssText = div1_style_value;
attr(div1, "style", div1_style_value);
}
},

@ -0,0 +1 @@
<button on:click= {foo}>Click</button>

@ -0,0 +1,39 @@
{
"html": {
"start": 0,
"end": 38,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 38,
"type": "Element",
"name": "button",
"attributes": [
{
"start": 8,
"end": 23,
"type": "EventHandler",
"name": "click",
"modifiers": [],
"expression": {
"type": "Identifier",
"start": 19,
"end": 22,
"name": "foo"
}
}
],
"children": [
{
"start": 24,
"end": 29,
"type": "Text",
"raw": "Click",
"data": "Click"
}
]
}
]
}
}

@ -4,7 +4,7 @@ export default {
},
html: `
<editor><b>world</b></editor>
<editor contenteditable="true"><b>world</b></editor>
<p>hello <b>world</b></p>
`,
@ -21,7 +21,7 @@ export default {
// No updates to data yet
assert.htmlEqual(target.innerHTML, `
<editor>every<span>body</span></editor>
<editor contenteditable="true">every<span>body</span></editor>
<p>hello <b>world</b></p>
`);
@ -29,14 +29,14 @@ export default {
const event = new window.Event('input');
await el.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<editor>every<span>body</span></editor>
<editor contenteditable="true">every<span>body</span></editor>
<p>hello every<span>body</span></p>
`);
component.name = 'good<span>bye</span>';
assert.equal(el.innerHTML, 'good<span>bye</span>');
assert.htmlEqual(target.innerHTML, `
<editor>good<span>bye</span></editor>
<editor contenteditable="true">good<span>bye</span></editor>
<p>hello good<span>bye</span></p>
`);
},

@ -4,7 +4,7 @@ export default {
},
html: `
<editor>world</editor>
<editor contenteditable="true">world</editor>
<p>hello world</p>
`,
@ -23,14 +23,14 @@ export default {
await el.dispatchEvent(event);
assert.htmlEqual(target.innerHTML, `
<editor>everybody</editor>
<editor contenteditable="true">everybody</editor>
<p>hello everybody</p>
`);
component.name = 'goodbye';
assert.equal(el.textContent, 'goodbye');
assert.htmlEqual(target.innerHTML, `
<editor>goodbye</editor>
<editor contenteditable="true">goodbye</editor>
<p>hello goodbye</p>
`);
},

@ -0,0 +1,19 @@
export default {
html: `<div>&nbsp;hello</div>
<div>&nbsp;hello&nbsp;&nbsp;</div>
<div>&nbsp;hello&nbsp; &nbsp;hello</div>`,
test({ assert, component, target }) {
var divList = target.querySelectorAll('div')
assert.equal( divList[0].textContent.charCodeAt( 0 ), 160 );
assert.equal( divList[1].textContent.charCodeAt( 0 ), 160 );
assert.equal( divList[1].textContent.charCodeAt( 6 ), 160 );
assert.equal( divList[1].textContent.charCodeAt( 7 ), 160 );
assert.equal( divList[2].textContent.charCodeAt( 0 ), 160 );
assert.equal( divList[2].textContent.charCodeAt( 6 ), 160 );
assert.equal( divList[2].textContent.charCodeAt( 7 ), 32 );//normal space
assert.equal( divList[2].textContent.charCodeAt( 8 ), 160 );
}
};

@ -0,0 +1,7 @@
<script>
let name = 'hello';
</script>
<div>&nbsp;{name}</div>
<div>&nbsp;{name}&nbsp;&nbsp;</div>
<div>&nbsp;{name}&nbsp; &nbsp;{name}</div>

@ -1,5 +1,5 @@
export default {
html: '<div></div>',
html: `<div draggable='false'></div>`,
ssrHtml: '<div foo=1></div>'
ssrHtml: `<div foo='1' draggable='false'></div>`,
};

@ -3,10 +3,11 @@
export let foo = 1;
export let bar;
export let _class;
onMount(() => {
foo = undefined;
});
</script>
<div {foo} {bar}></div>
<div {foo} {bar} class={_class} draggable='false'></div>

@ -1,2 +0,0 @@
div.svelte-bzh57p{color:red}
div.svelte-4yw8vx{color:green}

@ -0,0 +1,10 @@
{
"extends": "../tsconfig.json",
"include": ["."],
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"noEmit": true
}
}

@ -1,33 +1,30 @@
{
"include": [],
"compilerOptions": {
"target": "es2015",
"module": "es6",
"rootDir": "src",
// target node v8+ (https://node.green/)
// the only missing feature is Array.prototype.values
"lib": ["es2017"],
"target": "es2017",
"declaration": true,
"declarationDir": "types",
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noEmitOnError": true,
"lib": [
"es5",
"es6",
"dom",
"es2015"
],
"importHelpers": true,
"noErrorTruncation": true,
// rollup takes care of these
"module": "esnext",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"svelte/internal": ["./src/runtime/internal/index"],
"svelte/easing": ["./src/runtime/easing/index"],
"svelte/motion": ["./src/runtime/motion/index"],
"svelte/store": ["./src/runtime/store/index"]
},
"typeRoots": [
"node_modules/@types"
]
},
"include": [
"src/**/*"
]
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
// TODO: error all the things
//"strict": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}

Loading…
Cancel
Save