Merge branch 'master' into dispatch-cancelable

pull/7064/head
Bjorn Lu 5 years ago committed by GitHub
commit fae2581431
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,7 +2,12 @@
## Unreleased ## Unreleased
* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function will also return a boolean depending on whether the event is cancelled. * Avoid `maximum call stack size exceeded` errors on large components ([#4694](https://github.com/sveltejs/svelte/issues/4694))
* Keep space in `<pre>` tags or when `preserveWhitespace` is `true`([#6437](https://github.com/sveltejs/svelte/issues/6437), [#4731](https://github.com/sveltejs/svelte/issues/4731))
* Better 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 ([#7204](https://github.com/sveltejs/svelte/pull/7204))
* Add a third parameter to the returned function of `createEventDispatcher` that allows passing an object of `{ cancelable: true }` to create a cancelable custom event. The returned function will also return a boolean depending on whether the event is cancelled. ([#7064](https://github.com/sveltejs/svelte/pull/7064))
## 3.46.3 ## 3.46.3

15
package-lock.json generated

@ -5,7 +5,6 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "svelte",
"version": "3.46.3", "version": "3.46.3",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
@ -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",

@ -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, options?: DispatchOptions) => boolean) =
--- ---
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). 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). 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.

@ -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;

@ -72,6 +72,9 @@ 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