Merge branch 'sveltejs:master' into master

pull/6928/head
andirady 5 years ago committed by GitHub
commit 74c5e60802
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,14 @@
# Svelte changelog # Svelte changelog
## 3.46.4
* Avoid `maximum call stack size exceeded` errors on large components ([#4694](https://github.com/sveltejs/svelte/issues/4694))
* Preserve leading space with `preserveWhitespace: true` ([#4731](https://github.com/sveltejs/svelte/issues/4731))
* Preserve leading space in `<pre>` tags ([#6437](https://github.com/sveltejs/svelte/issues/6437))
* Improve error message when trying to use `style:` directives on inline components ([#7177](https://github.com/sveltejs/svelte/issues/7177))
* Add `FormData` as a known global ([#7199](https://github.com/sveltejs/svelte/pull/7199))
* Mark `css`/`instance`/`module` AST properties as optional in types ([#7204](https://github.com/sveltejs/svelte/pull/7204))
## 3.46.3 ## 3.46.3
* Ignore whitespace in `{#each}` blocks when containing elements with `animate:` ([#5477](https://github.com/sveltejs/svelte/pull/5477)) * Ignore whitespace in `{#each}` blocks when containing elements with `animate:` ([#5477](https://github.com/sveltejs/svelte/pull/5477))

19
package-lock.json generated

@ -1,12 +1,11 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.46.3", "version": "3.46.4",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "svelte", "version": "3.46.4",
"version": "3.46.3",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@ampproject/remapping": "^0.3.0", "@ampproject/remapping": "^0.3.0",
@ -24,7 +23,7 @@
"@typescript-eslint/parser": "^4.31.2", "@typescript-eslint/parser": "^4.31.2",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"agadoo": "^1.1.0", "agadoo": "^1.1.0",
"code-red": "^0.2.4", "code-red": "^0.2.5",
"css-tree": "^1.1.2", "css-tree": "^1.1.2",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-import": "^2.24.2", "eslint-plugin-import": "^2.24.2",
@ -1018,9 +1017,9 @@
} }
}, },
"node_modules/code-red": { "node_modules/code-red": {
"version": "0.2.4", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.4.tgz", "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.5.tgz",
"integrity": "sha512-tAJQiZviSyB2KUhz+rocKFzCHPkVooX2aFrdpfWDRvxWJaBQTYFJ/Z2TcWqbjXj5oJJBlqd2GxBXdtAhOXySVQ==", "integrity": "sha512-x+uQyJLNS1v0+74eXqM7FMPoM1fU/fN3tdexGWtCuVjCfxADt1TuuEGIGlFyCC2vhgINDctDb/rgSn8/ZDfJsQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/estree": "^0.0.50", "@types/estree": "^0.0.50",
@ -5954,9 +5953,9 @@
} }
}, },
"code-red": { "code-red": {
"version": "0.2.4", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.4.tgz", "resolved": "https://registry.npmjs.org/code-red/-/code-red-0.2.5.tgz",
"integrity": "sha512-tAJQiZviSyB2KUhz+rocKFzCHPkVooX2aFrdpfWDRvxWJaBQTYFJ/Z2TcWqbjXj5oJJBlqd2GxBXdtAhOXySVQ==", "integrity": "sha512-x+uQyJLNS1v0+74eXqM7FMPoM1fU/fN3tdexGWtCuVjCfxADt1TuuEGIGlFyCC2vhgINDctDb/rgSn8/ZDfJsQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/estree": "^0.0.50", "@types/estree": "^0.0.50",

@ -1,6 +1,6 @@
{ {
"name": "svelte", "name": "svelte",
"version": "3.46.3", "version": "3.46.4",
"description": "Cybernetically enhanced web apps", "description": "Cybernetically enhanced web apps",
"module": "index.mjs", "module": "index.mjs",
"main": "index", "main": "index",
@ -127,7 +127,7 @@
"@typescript-eslint/parser": "^4.31.2", "@typescript-eslint/parser": "^4.31.2",
"acorn": "^8.4.1", "acorn": "^8.4.1",
"agadoo": "^1.1.0", "agadoo": "^1.1.0",
"code-red": "^0.2.4", "code-red": "^0.2.5",
"css-tree": "^1.1.2", "css-tree": "^1.1.2",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-import": "^2.24.2", "eslint-plugin-import": "^2.24.2",

@ -0,0 +1,106 @@
---
title: "What's new in Svelte: February 2022"
description: "Rapid-fire releases across Svelte, SvelteKit and the community"
author: Daniel Sandoval
authorURL: https://desandoval.net
---
Happy February, everyone! Over the last month or so, we've seen Svelte and SvelteKit [develop at rapid speed](accelerating-sveltes-development), new community rules across the [Reddit](https://www.reddit.com/r/sveltejs/comments/s9n8ou/new_rules/), [GitHub](https://github.com/sveltejs/community/blob/main/CODE_OF_CONDUCT.md) and [Discord](https://discord.com/channels/457912077277855764/831611707667382303/935264550436102315), and quite a few amazing apps, tutorials and libraries.
Let's take a look...
## Highlights from the Svelte changelog
- **3.45.0** brought a [new a11y warning `a11y-no-redundant-roles`](https://svelte.dev/docs#accessibility-warnings-a11y-no-redundant-roles), destructuring and caching fixes
- **3.46.0** added the much requested [`{@const}` tag](https://svelte.dev/docs#template-syntax-const) and [`style:` directive](https://svelte.dev/docs#template-syntax-element-directives-style-property)
- Check out **3.46.1 - 3.46.3** for fixes to the `{@const}` tag and `style:` directive, along with a number of fixes to animations
- [AST output is now available in the Svelte REPL](https://svelte.dev/repl/hello-world)
## What's new in SvelteKit
- `inlineStyleThreshold` allows you to specify where inline stylesheets are inserted into the page ([Docs](https://kit.svelte.dev/docs#configuration-inlinestylethreshold), [#2620](https://github.com/sveltejs/kit/pull/2620))
- `beforeNavigate`/`afterNavigate` lifecycle functions lets you add functionality before or after a page navigation ([Docs](https://kit.svelte.dev/docs#modules-$app-navigation), [#3293](https://github.com/sveltejs/kit/pull/3293))
- Platform context can now be passed from adapters ([Docs](https://kit.svelte.dev/docs#adapters-supported-environments-platform-specific-context), [#3429](https://github.com/sveltejs/kit/pull/3429))
- Hooks now have an `ssr` parameter in `resolve` to make it easier to skip SSR, when needed ([Docs](https://kit.svelte.dev/docs#hooks-handle), [#2804](https://github.com/sveltejs/kit/pull/2804))
- `$page.stuff` provides a mechanism for pages to pass data 'upward' to layouts ([Docs](https://kit.svelte.dev/docs#loading-input-stuff), [#3252](https://github.com/sveltejs/kit/pull/3252))
- Fallthrough routes let you specify where to route when an route can't be loaded ([Docs](https://kit.svelte.dev/docs#routing-advanced-fallthrough-routes), [#3217](https://github.com/sveltejs/kit/pull/3217))
**New configs**
- Content Security Policy (CSP) is now supported for increased security when using inline javascript or stylesheets ([Docs](https://kit.svelte.dev/docs#configuration-csp), [#3499](https://github.com/sveltejs/kit/pull/3499))
- `kit.routes` config allows you to customise public/private modules during build ([Docs](https://kit.svelte.dev/docs#configuration-routes), [#3576](https://github.com/sveltejs/kit/pull/3576))
- `prerender.createIndexFiles` config lets you prerender index.html files as their subfolder's name ([Docs](https://kit.svelte.dev/docs#configuration-prerender), [#2632](https://github.com/sveltejs/kit/pull/2632))
- HTTP methods can now be overridden using `kit.methodOverride` ([Docs](https://kit.svelte.dev/docs#routing-endpoints-http-method-overrides), [#2989](https://github.com/sveltejs/kit/pull/2989))
**Config changes**
- `config.kit.hydrate` and `config.kit.router` are now nested under `config.kit.browser` ([Docs](https://kit.svelte.dev/docs#configuration-browser), [3578](https://github.com/sveltejs/kit/pull/3578))
**Breaking change**
- use `Request` and `Response` objects in endpoints and hooks ([#3384](https://github.com/sveltejs/kit/pull/3384))
---
## Community Showcase
**Apps & Sites**
- [timb(re)](https://paullj.github.io/timb) is a live music programming environment
- [Music for Programming](https://musicforprogramming.net/latest/) is a series of mixes intended for listening while `${task}` to focus the brain and inspire the mind
- [Team Tale](https://teamtale.app/) allows two authors to write the same story in a tag-team sort of fashion
- [Puzzlez](https://www.puzzlez.io/) is an online place to play Sudoku and Wordle
- [Closed Caption Creator](https://www.closedcaptioncreator.com/) makes it easy to add subtitles to your video on Windows, Mac and Google Chrome
- [SC3Lab](https://sc3-lab.netlify.app/) is a code generator for experimenting with svelte-cubed and three.js
- [Donkeytype](https://github.com/0ql/Donkeytype) is a minimalistic and lightweight typingtest inspired by Monkeytype.
- [Above](https://above.silas.pro/) is a visual routine timer built for the ADHD/autistic mind
- [base.report](https://base.report/) is a modern research platform for serious investors
- [String](https://string.kampsy.xyz/) turns your Phone into a secure portable audio recorder, making it easy to capture and share personal notes, family moments, classroom lectures, and more
- [The Raytracer Challenge REPL](https://github.com/jakobwesthoff/the_raytracer_challenge_repl) provides a live editor interface to configure a raytraced scene and render it live in any modern browser
- [awesome-svelte-kit](https://github.com/janosh/awesome-svelte-kit) is a list of awesome examples of SvelteKit in the wild
- [Map Projection Explorer](https://www.geo-projections.com/) lets you explore different map projections and explains their differences
- [Rubiks](https://github.com/MeharGaur/rubiks) is a Rubik's Cube simulator
- [Pianisto](https://pianisto.net/) is a working piano made with SVG, ToneJS and a lot of patience
Want to work on a SvelteKit site with others, [try contributing to the Svelte Society site](https://github.com/svelte-society/sveltesociety-2021/issues)!
**Learning and Listening**
_To Read_
- [Accelerating Svelte's Development](https://svelte.dev/blog/accelerating-sveltes-development) by Ben McCann
- [Storybook for Vite](https://storybook.js.org/blog/storybook-for-vite/)
- [Let's learn SvelteKit by building a static Markdown blog from scratch](https://joshcollinsworth.com/blog/build-static-sveltekit-markdown-blog) by Josh Collinsworth
- [Building an iOS app with Svelte, Capacitor and Firebase](https://harryherskowitz.com/2022/01/05/tapedrop-app.html) by Harry Herskowitz
- [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) and [Workaround for Bubbling Custom Events in Svelte](https://dev.to/mohamadharith/workaround-for-bubbling-custom-events-in-svelte-3khk) by Mohamad Harith
- [How to build a full stack serverless application with Svelte and GraphQL](https://dev.to/shadid12/how-to-build-a-full-stack-serverless-application-with-svelte-graphql-and-fauna-5427) by Shadid Haque
- [How to Deploy SvelteKit Apps to Github Pages](https://sveltesaas.com/articles/sveltekit-github-pages-guide/)
- [Creating a dApp with SvelteKit](https://anthonyriley.org/2021/12/31/creating-a-dapp-with-sveltekit/) by Anthony Riley
- [Comparing Svelte Reactivity Options](https://opendirective.net/2022/01/06/comparing-svelte-reactivity-options/) by Steve Lee
_To Watch_
- [Integrating Storybook with SvelteKit](https://www.youtube.com/watch?v=Kc1ULlfyUcw) and [Integrating FaunaDB with Svelte](https://www.youtube.com/watch?v=zaoLZc76uZM) by the Svelte Sirens
- [SvelteKit Crash Course Tutorial](https://www.youtube.com/watch?v=9OlLxkaeVvw&list=PL4cUxeGkcC9hpM9ARM59Ve3jqcb54dqiP) by The Net Ninja
- [Svelte for Beginners](https://www.youtube.com/watch?v=BrkrOjknC_E&list=PLA9WiRZ-IS_ylnMYxIFCsZN6xVVSvLuHk) by Joy of Code
- [SvelteKit For Beginners | Movie App Tutorial](https://www.youtube.com/watch?v=ydR_M0fw9Xc) by Dev Ed
- [SvelteKit $app/stores](https://www.youtube.com/watch?v=gBPhr1xbgaQ) by lihautan
- [Sveltekit - Get All Routes/Pages](https://www.youtube.com/watch?v=Y_NE2R3HuOU) by WebJeda
_To Listen To_
- [New Year, New Svelte!?](https://share.transistor.fm/s/36212cdc) from Svelte Radio
- [So much Sveltey goodness (featuring Rich Harris)](https://changelog.com/jsparty/205) from JS Party
- [The Other Side of Tech: A Documentarian Perspective (with Stefan Kingham)](https://codingcat.dev/podcast/2-4-the-other-side-of-tech-a-documentarian-perspective) from Purrfect.dev
**Libraries, Tools & Components**
- [threlte](https://github.com/grischaerbe/threlte) is a three.js component library for Svelte
- [svelte-formify](https://github.com/nodify-at/svelte-formify) is a library to manage and validate forms that uses decorators to define validations
- [gQuery](https://github.com/leveluptuts/gQuery) is a GraphQL Fetcher & Cache for Svelte Kit
- [Unlock-protocol](https://github.com/novum-insights/sveltekit-unlock-firebase) is an integration to help login with MetaMask, Firebase, and paywall customers
- [AgnosticUI](https://github.com/AgnosticUI/agnosticui) is a set of UI primitives that start their lives in clean HTML and CSS
- [Vitebook](https://github.com/vitebook/vitebook) is a fast and lightweight alternative to Storybook that's powered by Vite
- [SwyxKit](https://swyxkit.netlify.app/) is an opinionated blog starter for SvelteKit + Tailwind + Netlify. Refreshed for 2022!
- [svelte-themes](https://github.com/beynar/svelte-themes) is an abstraction for themes in your SvelteKit app
- [svelte-transition](https://www.npmjs.com/package/svelte-transition) is a Svelte component to make using CSS class based transitions easier - ideally suited for use with TailwindCSS
- [Svelte Inview](https://www.npmjs.com/package/svelte-inview) is a Svelte action that monitors an element enters or leaves the viewport/parent element
- [svelte-inline-compile](https://github.com/DockYard/svelte-inline-compile) is a babel transform that allows for a much more pleasant experience when testing svelte components using Jest and `@testing-library/svelte`
- [@feltcoop/svelte-mutable-store](https://github.com/feltcoop/svelte-mutable-store) is a Svelte store for mutable values with an `immutable` compiler option
- [headless-svelte-ui](https://www.npmjs.com/package/@bojalelabs/headless-svelte-ui) is a group of headless components that can be used in building Svelte Apps.
Did we miss something? 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!

@ -57,7 +57,7 @@ In development mode (see the [compiler options](/docs#compile-time-svelte-compil
If you export a `const`, `class` or `function`, it is readonly from outside the component. Function *expressions* are valid props, however. If you export a `const`, `class` or `function`, it is readonly from outside the component. Function *expressions* are valid props, however.
Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-element-directives-bind-element). Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](/docs#template-syntax-component-directives-bind-this).
```sv ```sv
<script> <script>

@ -1736,7 +1736,7 @@ The `<svelte:options>` element provides a place to specify per-component compile
### `<svelte:fragment>` ### `<svelte:fragment>`
The `<svelte:fragment>` element allows you to place content in a [named slot](/docs#template-syntax-slot-slot-name) without wrapping it in a container DOM element. This keeps the flow layout of your document intact. The `<svelte:fragment>` element allows you to place content in a [named slot](/docs#template-syntax-slot-slot-name-name) without wrapping it in a container DOM element. This keeps the flow layout of your document intact.
```sv ```sv
<!-- Widget.svelte --> <!-- Widget.svelte -->

@ -226,7 +226,7 @@ dispatch: ((name: string, detail?: any) => void) = createEventDispatcher();
--- ---
Creates an event dispatcher that can be used to dispatch [component events](/docs#template-syntax-component-directives-on-component-event). Event dispatchers are functions that can take two arguments: `name` and `detail`. Creates an event dispatcher that can be used to dispatch [component events](/docs#template-syntax-component-directives-on-eventname). Event dispatchers are functions that can take two arguments: `name` and `detail`.
Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data. Component events created with `createEventDispatcher` create a [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture) and are not cancellable with `event.preventDefault()`. The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail) property and can contain any type of data.

@ -4,7 +4,7 @@ question: How do I document my components?
In editors which use the Svelte Language Server you can document Components, functions and exports using specially formatted comments. In editors which use the Svelte Language Server you can document Components, functions and exports using specially formatted comments.
````svelte ````sv
<script> <script>
/** What should we call the user? */ /** What should we call the user? */
export let name = 'world'; export let name = 'world';

@ -6,14 +6,14 @@ You need to install a preprocessor such as [svelte-preprocess](https://github.co
To declare the type of a reactive variable in a Svelte template, you should use the following syntax: To declare the type of a reactive variable in a Svelte template, you should use the following syntax:
``` ```ts
let x: number; let x: number;
$: x = count + 1; $: x = count + 1;
``` ```
To import a type or interface make sure to use [TypeScript's `type` modifier](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export): To import a type or interface make sure to use [TypeScript's `type` modifier](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export):
``` ```ts
import type { SomeInterface } from './SomeFile'; import type { SomeInterface } from './SomeFile';
``` ```

@ -265,5 +265,9 @@ export default {
cyclical_const_tags: (cycle: string[]) => ({ cyclical_const_tags: (cycle: string[]) => ({
code: 'cyclical-const-tags', code: 'cyclical-const-tags',
message: `Cyclical dependency detected: ${cycle.join(' → ')}` message: `Cyclical dependency detected: ${cycle.join(' → ')}`
}) }),
invalid_component_style_directive: {
code: 'invalid-component-style-directive',
message: 'Style directives cannot be used on components'
}
}; };

@ -8,6 +8,7 @@ import { CssNode } from './interfaces';
import hash from '../utils/hash'; import hash from '../utils/hash';
import compiler_warnings from '../compiler_warnings'; import compiler_warnings from '../compiler_warnings';
import { extract_ignores_above_position } from '../../utils/extract_svelte_ignore'; import { extract_ignores_above_position } from '../../utils/extract_svelte_ignore';
import { push_array } from '../../utils/push_array';
function remove_css_prefix(name: string): string { function remove_css_prefix(name: string): string {
return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, ''); return name.replace(/^-((webkit)|(moz)|(o)|(ms))-/, '');
@ -351,7 +352,7 @@ export default class Stylesheet {
const at_rule_declarations = node.block.children const at_rule_declarations = node.block.children
.filter(node => node.type === 'Declaration') .filter(node => node.type === 'Declaration')
.map(node => new Declaration(node)); .map(node => new Declaration(node));
atrule.declarations.push(...at_rule_declarations); push_array(atrule.declarations, at_rule_declarations);
} }
current_atrule = atrule; current_atrule = atrule;

@ -71,7 +71,10 @@ export default class InlineComponent extends Node {
case 'Transition': case 'Transition':
return component.error(node, compiler_errors.invalid_transition); return component.error(node, compiler_errors.invalid_transition);
case 'StyleDirective':
return component.error(node, compiler_errors.invalid_component_style_directive);
default: default:
throw new Error(`Not implemented: ${node.type}`); throw new Error(`Not implemented: ${node.type}`);
} }

@ -43,4 +43,21 @@ export default class Text extends Node {
return parent_element.namespace || elements_without_text.has(parent_element.name); return parent_element.namespace || elements_without_text.has(parent_element.name);
} }
keep_space(): boolean {
if (this.component.component_options.preserveWhitespace) return true;
return this.within_pre();
}
within_pre(): boolean {
let node = this.parent;
while (node) {
if (node.type === 'Element' && node.name === 'pre') {
return true;
}
node = node.parent;
}
return false;
}
} }

@ -18,6 +18,7 @@ import Text from '../Text';
import Title from '../Title'; import Title from '../Title';
import Window from '../Window'; import Window from '../Window';
import { TemplateNode } from '../../../interfaces'; import { TemplateNode } from '../../../interfaces';
import { push_array } from '../../../utils/push_array';
export type Children = ReturnType<typeof map_children>; export type Children = ReturnType<typeof map_children>;
@ -60,7 +61,7 @@ export default function map_children(component, parent, scope, children: Templat
if (use_ignores) component.pop_ignores(), ignores = []; if (use_ignores) component.pop_ignores(), ignores = [];
if (node.type === 'Comment' && node.ignores.length) { if (node.type === 'Comment' && node.ignores.length) {
ignores.push(...node.ignores); push_array(ignores, node.ignores);
} }
if (last) last.next = node; if (last) last.next = node;

@ -11,6 +11,7 @@ import { apply_preprocessor_sourcemap } from '../../utils/mapped_code';
import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types';
import { flatten } from '../../utils/flatten'; import { flatten } from '../../utils/flatten';
import check_enable_sourcemap from '../utils/check_enable_sourcemap'; import check_enable_sourcemap from '../utils/check_enable_sourcemap';
import { push_array } from '../../utils/push_array';
export default function dom( export default function dom(
component: Component, component: Component,
@ -67,7 +68,7 @@ export default function dom(
// TODO the deconflicted names of blocks are reversed... should set them here // TODO the deconflicted names of blocks are reversed... should set them here
const blocks = renderer.blocks.slice().reverse(); const blocks = renderer.blocks.slice().reverse();
body.push(...blocks.map(block => { push_array(body, blocks.map(block => {
// TODO this is a horrible mess — renderer.blocks // TODO this is a horrible mess — renderer.blocks
// contains a mixture of Blocks and Nodes // contains a mixture of Blocks and Nodes
if ((block as Block).render) return (block as Block).render(); if ((block as Block).render) return (block as Block).render();
@ -562,7 +563,7 @@ export default function dom(
}); });
} }
declaration.body.body.push(...accessors); push_array(declaration.body.body, accessors);
body.push(declaration); body.push(declaration);
@ -599,7 +600,7 @@ export default function dom(
} }
`[0] as ClassDeclaration; `[0] as ClassDeclaration;
declaration.body.body.push(...accessors); push_array(declaration.body.body, accessors);
body.push(declaration); body.push(declaration);
} }

@ -26,6 +26,7 @@ import Action from '../../../nodes/Action';
import MustacheTagWrapper from '../MustacheTag'; import MustacheTagWrapper from '../MustacheTag';
import RawMustacheTagWrapper from '../RawMustacheTag'; import RawMustacheTagWrapper from '../RawMustacheTag';
import is_dynamic from '../shared/is_dynamic'; import is_dynamic from '../shared/is_dynamic';
import { push_array } from '../../../../utils/push_array';
interface BindingGroup { interface BindingGroup {
events: string[]; events: string[];
@ -597,7 +598,7 @@ export default class ElementWrapper extends Wrapper {
this.attributes.forEach((attribute) => { this.attributes.forEach((attribute) => {
if (attribute.node.name === 'class') { if (attribute.node.name === 'class') {
const dependencies = attribute.node.get_dependencies(); const dependencies = attribute.node.get_dependencies();
this.class_dependencies.push(...dependencies); push_array(this.class_dependencies, dependencies);
} }
}); });

@ -95,7 +95,7 @@ export default class FragmentWrapper {
next_sibling ? (next_sibling.node.type === 'Text' && /^\s/.test(next_sibling.node.data) && trimmable_at(child, next_sibling)) : !child.has_ancestor('EachBlock') next_sibling ? (next_sibling.node.type === 'Text' && /^\s/.test(next_sibling.node.data) && trimmable_at(child, next_sibling)) : !child.has_ancestor('EachBlock')
); );
if (should_trim) { if (should_trim && !child.keep_space()) {
data = trim_end(data); data = trim_end(data);
if (!data) continue; if (!data) continue;
} }
@ -127,7 +127,7 @@ export default class FragmentWrapper {
if (strip_whitespace) { if (strip_whitespace) {
const first = this.nodes[0] as Text; const first = this.nodes[0] as Text;
if (first && first.node.type === 'Text') { if (first && first.node.type === 'Text' && !first.node.keep_space()) {
first.data = trim_start(first.data); first.data = trim_start(first.data);
if (!first.data) { if (!first.data) {
first.var = null; first.var = null;

@ -10,6 +10,7 @@ import { b, x } from 'code-red';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import { is_head } from './shared/is_head'; import { is_head } from './shared/is_head';
import { Identifier, Node } from 'estree'; import { Identifier, Node } from 'estree';
import { push_array } from '../../../utils/push_array';
function is_else_if(node: ElseBlock) { function is_else_if(node: ElseBlock) {
return ( return (
@ -166,7 +167,7 @@ export default class IfBlockWrapper extends Wrapper {
block.has_outro_method = has_outros; block.has_outro_method = has_outros;
}); });
renderer.blocks.push(...blocks); push_array(renderer.blocks, blocks);
} }
render( render(

@ -29,15 +29,7 @@ export default class TextWrapper extends Wrapper {
if (this.renderer.component.component_options.preserveWhitespace) return false; if (this.renderer.component.component_options.preserveWhitespace) return false;
if (/[\S\u00A0]/.test(this.data)) return false; if (/[\S\u00A0]/.test(this.data)) return false;
let node = this.parent && this.parent.node; return !this.node.within_pre();
while (node) {
if (node.type === 'Element' && node.name === 'pre') {
return false;
}
node = node.parent;
}
return true;
} }
render(block: Block, parent_node: Identifier, parent_nodes: Identifier) { render(block: Block, parent_node: Identifier, parent_nodes: Identifier) {

@ -26,7 +26,7 @@ export default function remove_whitespace_children(children: INode[], next?: INo
trimmable_at(child, next) trimmable_at(child, next)
: !child.has_ancestor('EachBlock'); : !child.has_ancestor('EachBlock');
if (should_trim) { if (should_trim && !child.keep_space()) {
data = trim_end(data); data = trim_end(data);
if (!data) continue; if (!data) continue;
} }
@ -47,7 +47,7 @@ export default function remove_whitespace_children(children: INode[], next?: INo
} }
const first = nodes[0]; const first = nodes[0];
if (first && first.type === 'Text') { if (first && first.type === 'Text' && !first.keep_space()) {
first.data = trim_start(first.data); first.data = trim_start(first.data);
if (!first.data) { if (!first.data) {
first.var = null; first.var = null;

@ -131,9 +131,9 @@ export interface Style extends BaseNode {
export interface Ast { export interface Ast {
html: TemplateNode; html: TemplateNode;
css: Style; css?: Style;
instance: Script; instance?: Script;
module: Script; module?: Script;
} }
export interface Warning { export interface Warning {

@ -2,6 +2,7 @@ import { DecodedSourceMap, RawSourceMap, SourceMapLoader } from '@ampproject/rem
import remapping from '@ampproject/remapping'; import remapping from '@ampproject/remapping';
import { SourceMap } from 'magic-string'; import { SourceMap } from 'magic-string';
import { Source, Processed } from '../preprocess/types'; import { Source, Processed } from '../preprocess/types';
import { push_array } from './push_array';
export type SourceLocation = { export type SourceLocation = {
line: number; line: number;
@ -60,14 +61,6 @@ function merge_tables<T>(this_table: T[], other_table: T[]): [T[], number[], boo
return [new_table, idx_map, val_changed, idx_changed]; return [new_table, idx_map, val_changed, idx_changed];
} }
function pushArray<T>(_this: T[], other: T[]) {
// We use push to mutate in place for memory and perf reasons
// We use the for loop instead of _this.push(...other) to avoid the JS engine's function argument limit (65,535 in JavascriptCore)
for (let i = 0; i < other.length; i++) {
_this.push(other[i]);
}
}
export class MappedCode { export class MappedCode {
string: string; string: string;
map: DecodedSourceMap; map: DecodedSourceMap;
@ -159,10 +152,10 @@ export class MappedCode {
} }
// combine last line + first line // combine last line + first line
pushArray(m1.mappings[m1.mappings.length - 1], m2.mappings.shift()); push_array(m1.mappings[m1.mappings.length - 1], m2.mappings.shift());
// append other lines // append other lines
pushArray(m1.mappings, m2.mappings); push_array(m1.mappings, m2.mappings);
return this; return this;
} }

@ -22,6 +22,7 @@ export const globals = new Set([
'Event', 'Event',
'EventSource', 'EventSource',
'fetch', 'fetch',
'FormData',
'global', 'global',
'globalThis', 'globalThis',
'history', 'history',

@ -0,0 +1,12 @@
/**
* Pushes all `items` into `array` using `push`, therefore mutating the array.
* We do this for memory and perf reasons, and because `array.push(...items)` would
* run into a "max call stack size exceeded" error with too many items (~65k).
* @param array
* @param items
*/
export function push_array<T>(array: T[], items: T[]): void {
for (let i = 0; i < items.length; i++) {
array.push(items[i]);
}
}

@ -0,0 +1,57 @@
export default {
test({ assert, target }) {
// Test for <pre> tag
const elementPre = target.querySelector('#pre');
// Test for non <pre> tag
const elementDiv = target.querySelector('#div');
// Test for <pre> tag in non <pre> tag
const elementDivWithPre = target.querySelector('#div-with-pre');
// There is a slight difference in innerHTML because there is a difference in HTML optimization (in jsdom)
// depending on how the innerHTML is set.
// (There is no difference in the display.)
// Reassign innerHTML to add the same optimizations to innerHTML.
// eslint-disable-next-line no-self-assign
elementPre.innerHTML = elementPre.innerHTML;
// eslint-disable-next-line no-self-assign
elementDiv.innerHTML = elementDiv.innerHTML;
// eslint-disable-next-line no-self-assign
elementDivWithPre.innerHTML = elementDivWithPre.innerHTML;
assert.equal(
elementPre.innerHTML,
`
A
B
<span>
C
D
</span>
E
F
`
);
assert.equal(
elementDiv.innerHTML,
`A
B
<span>C
D</span>
E
F`
);
assert.equal(
elementDivWithPre.innerHTML,
`<pre> A
B
<span>
C
D
</span>
E
F
</pre>`
);
}
};

@ -0,0 +1,34 @@
<pre id="pre">
A
B
<span>
C
D
</span>
E
F
</pre>
<div id="div">
A
B
<span>
C
D
</span>
E
F
</div>
<div id="div-with-pre">
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
</div>

@ -0,0 +1,66 @@
export default {
compileOptions: {
preserveWhitespace: true
},
test({ assert, target }) {
// Test for <pre> tag
const elementPre = target.querySelector('#pre');
// Test for non <pre> tag
const elementDiv = target.querySelector('#div');
// Test for <pre> tag in non <pre> tag
const elementDivWithPre = target.querySelector('#div-with-pre');
// There is a slight difference in innerHTML because there is a difference in HTML optimization (in jsdom)
// depending on how the innerHTML is set.
// (There is no difference in the display.)
// Reassign innerHTML to add the same optimizations to innerHTML.
// eslint-disable-next-line no-self-assign
elementPre.innerHTML = elementPre.innerHTML;
// eslint-disable-next-line no-self-assign
elementDiv.innerHTML = elementDiv.innerHTML;
// eslint-disable-next-line no-self-assign
elementDivWithPre.innerHTML = elementDivWithPre.innerHTML;
assert.equal(
elementPre.innerHTML,
`
A
B
<span>
C
D
</span>
E
F
`
);
assert.equal(
elementDiv.innerHTML,
`
A
B
<span>
C
D
</span>
E
F
`
);
assert.equal(
elementDivWithPre.innerHTML,
`
<pre> A
B
<span>
C
D
</span>
E
F
</pre>
`
);
}
};

@ -0,0 +1,34 @@
<pre id="pre">
A
B
<span>
C
D
</span>
E
F
</pre>
<div id="div">
A
B
<span>
C
D
</span>
E
F
</div>
<div id="div-with-pre">
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
</div>

@ -83,9 +83,13 @@ describe('ssr', () => {
if (css.code) fs.writeFileSync(`${dir}/_actual.css`, css.code); if (css.code) fs.writeFileSync(`${dir}/_actual.css`, css.code);
try { try {
(compileOptions.preserveComments if (config.withoutNormalizeHtml) {
? assert.htmlEqualWithComments assert.strictEqual(html.trim(), expectedHtml.trim().replace(/\r\n/g, '\n'));
: assert.htmlEqual)(html, expectedHtml); } else {
(compileOptions.preserveComments
? assert.htmlEqualWithComments
: assert.htmlEqual)(html, expectedHtml);
}
} catch (error) { } catch (error) {
if (shouldUpdateExpected()) { if (shouldUpdateExpected()) {
fs.writeFileSync(`${dir}/_expected.html`, html); fs.writeFileSync(`${dir}/_expected.html`, html);

@ -0,0 +1,3 @@
export default {
withoutNormalizeHtml: true
};

@ -0,0 +1,30 @@
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
<div>A
B
<span>C
D
</span>
E
F
</div>
<div><pre>
A
B
<span>
C
D
</span>
E
F
</pre></div>

@ -0,0 +1,34 @@
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
<div>
A
B
<span>
C
D
</span>
E
F
</div>
<div>
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
</div>

@ -0,0 +1,6 @@
export default {
withoutNormalizeHtml: true,
compileOptions: {
preserveWhitespace: true
}
};

@ -0,0 +1,34 @@
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
<div>
A
B
<span>
C
D
</span>
E
F
</div>
<div>
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
</div>

@ -0,0 +1,34 @@
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
<div>
A
B
<span>
C
D
</span>
E
F
</div>
<div>
<pre>
A
B
<span>
C
D
</span>
E
F
</pre>
</div>

@ -0,0 +1,9 @@
[
{
"code": "invalid-component-style-directive",
"message": "Style directives cannot be used on components",
"start": { "line": 7, "column": 19, "character": 97 },
"end": { "line": 7, "column": 36, "character": 114 },
"pos": 97
}
]

@ -0,0 +1,7 @@
<script>
let name = 'world';
import Child from 'Child.svelte';
</script>
<Child name={name} style:color="red" />
Loading…
Cancel
Save