mirror of https://github.com/sveltejs/svelte
commit
037693c296
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
|||||||
|
---
|
||||||
|
title: What's new in Svelte: December 2020
|
||||||
|
description: Better tooling, export maps and improvements to slots and context
|
||||||
|
author: Daniel Sandoval
|
||||||
|
authorURL: https://desandoval.net
|
||||||
|
---
|
||||||
|
|
||||||
|
It's the last "What's new in Svelte" of the year and there's lots to celebrate! This month's coverage includes updates from `rollup-plugin-svelte`, `Sapper` and `SvelteKit` and a bunch of showcases from the Svelte community!
|
||||||
|
|
||||||
|
## New features & impactful bug fixes
|
||||||
|
|
||||||
|
1. `$$props`, `$$restProps`, and `$$slots` are all now supported in custom web components (**3.29.5**, [Example](https://svelte.dev/repl/ad8e6f39cd20403dacd1be84d71e498d?version=3.29.5)) and `slot` components now support spread props: `<slot {...foo} />` (**3.30.0**)
|
||||||
|
2. A new `hasContext` lifecycle function makes it easy to check whether a `key` has been set in the context of a parent component (**3.30.0** & **3.30.1**, [Docs](https://svelte.dev/docs#hasContext))
|
||||||
|
3. There is now a new `SvelteComponentTyped` class which makes it easier to add strongly typed components that extend base Svelte components. Component library and framework authors rejoice! An example: `export class YourComponent extends SvelteComponentTyped<{aProp: boolean}, {click: MouseEvent}, {default: {aSlot: string}}> {}` (**3.31.0**, [RFC](https://github.com/sveltejs/rfcs/pull/37))
|
||||||
|
4. Transitions within `{:else}` blocks should now complete successfully (**3.29.5**, [Example](https://svelte.dev/repl/49cef205e5da459594ef2eafcbd41593?version=3.29.5))
|
||||||
|
5. Svelte now includes an export map, which explicitly states which files can be imported from its npm package (**3.29.5** with some fixes in **3.29.6**, **3.29.7** and **3.30.0**)
|
||||||
|
6. `rollup-plugin-svelte` had a new [7.0.0 release](https://github.com/sveltejs/rollup-plugin-svelte/blob/master/CHANGELOG.md). The biggest change is that the `css` option was removed. Users who were using that option should add another plugin like `rollup-plugin-css-only` as demonstrated [in the template](https://github.com/sveltejs/template/blob/5b1135c286f7a649daa99825a077586655051649/rollup.config.js#L48)
|
||||||
|
|
||||||
|
|
||||||
|
## What's going on in Sapper?
|
||||||
|
Lots of new TypeScript definition improvements to make editing Sapper apps even easier! CSS for dynamic imports also should now work in `client.js` files. (Unreleased)
|
||||||
|
|
||||||
|
## What's the deal with SvelteKit?
|
||||||
|
We're glad you asked! If you didn't catch Rich's blog post from early last month, [you can find it here](https://svelte.dev/blog/whats-the-deal-with-sveltekit)!
|
||||||
|
|
||||||
|
For all the features and bugfixes see the CHANGELOGs for [Svelte](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md) and [Sapper](https://github.com/sveltejs/sapper/blob/master/CHANGELOG.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Community Showcase
|
||||||
|
|
||||||
|
**Apps & Sites**
|
||||||
|
- [narration.studio](https://narration.studio/) (Chrome Only) is an automatic in-browser audio recording & editing platform for voice over narration.
|
||||||
|
- [Vippet](https://vippet.netlify.app/) is a video recording and editing tool for the browser.
|
||||||
|
- [Pattern Monster](https://pattern.monster/) is a simple online pattern generator to create repeatable SVG patterns.
|
||||||
|
- [Plant-based diets](https://planetbaseddiets.panda.org/) is a website from the World Wildlife Foundation (WWF) built with Svelte.
|
||||||
|
- [johnells.se](https://www.johnells.se/) is a Swedish fashion e-commerce site, built with [Crown](https://crownframework.com/) - a Svelte-powered framework.
|
||||||
|
- [sentence-length](https://sentence-length.netlify.app/) is a learning and analysis tool to show how some authors play with different lengths, while others stick with one.
|
||||||
|
- [svelte-presenter](https://github.com/stephane-vanraes/svelte-presenter) lets you quickly make good looking presentations using Svelte and mdsvex.
|
||||||
|
|
||||||
|
**Demos**
|
||||||
|
- [u/loopcake got SSR working in Java Spring Boot](https://www.reddit.com/r/sveltejs/comments/jkh5up/svelte_ssr_but_its_java_spring_boot_and_its_native/) for all the Java shops out there looking to render Svelte server-side.
|
||||||
|
- [svelte-liquid-swipe](https://github.com/tncrazvan/svelte-liquid-swipe) shows off a fancy interaction pattern using svg paths.
|
||||||
|
- [Crossfade Link Animation](https://svelte.dev/repl/7f68e148caf04b2787bb6f296208f870?version=3.29.7) demonstrates how to animate between navigation links using a crossfade (made by Blu, from the Discord community)
|
||||||
|
- [Clip-Path Transitions](https://svelte.dev/repl/b5ad281ae8024b629b545c70c9e8764d?version=3.29.7) showcases how to use clip paths and custom transitions to create magical in-and-out transitions (made by Faber, from the Discord community)
|
||||||
|
|
||||||
|
**Learning Resources**
|
||||||
|
- [lihautan](https://www.youtube.com/channel/UCbmC3HP3FaAFdcZkui8YoMQ/featured) has been making easy-to-follow videos to share his in-depth knowledge of Svelte.
|
||||||
|
- [Lessons From Building a Static Site Generator](https://nicholasreese.com/lessons-from-building-a-static-site-generator/) shares the backstory and thinking behind Elder.js - and the design decision made along the way.
|
||||||
|
- [Svelte Tutorial and Projects Course ](https://www.udemy.com/course/svelte-tutorial-and-projects-course/) is a udemy course by John Smilga where students learn Svelte.js by building interesting projects.
|
||||||
|
- [Building Pastebin on IPFS - with FastAPI, Svelte, and IPFS](https://amalshaji.wtf/building-pastebin-on-ipfs-with-fastapi-svelte-and-ipfs) explains how to make a distributed pastebin-like application.
|
||||||
|
|
||||||
|
|
||||||
|
**Components, Libraries & Tools**
|
||||||
|
- [svelte-crossword](https://russellgoldenberg.github.io/svelte-crossword/) is a customizable crossword puzzle component for Svelte.
|
||||||
|
- [svelte-cloudinary](https://github.com/cupcakearmy/svelte-cloudinary) makes it easy to integrate Cloudinary with Svelte (including Typescript and SSR support)
|
||||||
|
- [Svelte Nova](https://extensions.panic.com/extensions/sb.lao/sb.lao.svelte-nova/) extends the new Nova editor to support Svelte
|
||||||
|
- [saos](https://github.com/shiryel/saos) is a small svelte component to animate your elements on scroll.
|
||||||
|
- [Svelte-nStore](https://github.com/lacikawiz/svelte-nStore) is a general purpose store replacement that fulfills the Svelte store contract and adds getter and calculation features.
|
||||||
|
- [svelte-slimscroll](https://github.com/MelihAltintas/svelte-slimscroll) is a Svelte Action that transforms any div into a scrollable area with a nice scrollbar.
|
||||||
|
- [svelte-typewriter](https://github.com/henriquehbr/svelte-typewriter) is a simple and reusable typewriter effect for your Svelte applications
|
||||||
|
- [svelte-store-router](https://github.com/zyxd/svelte-store-router) is a store-based router for Svelte that suggests that routing is just another global state and History API changes are just an optional side-effects of this state.
|
||||||
|
- [Routify](https://routify.dev/blog/routify-2-released) just released version 2 of its Svelte router.
|
||||||
|
- [svelte-error-boundary](https://www.npmjs.com/package/@crownframework/svelte-error-boundary) provides a simple error boundary component for Svelte that can be can be used with both DOM and SSR targets.
|
||||||
|
- [svelte2dts](https://www.npmjs.com/package/svelte2dts) generates d.ts files from svelte files, creating truly sharable and well typed components.
|
||||||
|
|
||||||
|
## See you next month!
|
||||||
|
|
||||||
|
Got an idea for something to add to the Showcase? Want to get involved more with Svelte? We're always looking for maintainers, contributors and fanatics... Check out the [Svelte Society](https://sveltesociety.dev/), [Reddit](https://www.reddit.com/r/sveltejs/) and [Discord](https://discord.com/invite/yy75DKs) to get involved!
|
||||||
|
|
||||||
|
That's all for the year, folks! See you in January 😎
|
After Width: | Height: | Size: 8.9 KiB |
@ -0,0 +1,276 @@
|
|||||||
|
import { DecodedSourceMap, RawSourceMap, SourceMapLoader } from '@ampproject/remapping/dist/types/types';
|
||||||
|
import remapping from '@ampproject/remapping';
|
||||||
|
import { SourceMap } from 'magic-string';
|
||||||
|
|
||||||
|
type SourceLocation = {
|
||||||
|
line: number;
|
||||||
|
column: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function last_line_length(s: string) {
|
||||||
|
return s.length - s.lastIndexOf('\n') - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mutate map in-place
|
||||||
|
export function sourcemap_add_offset(
|
||||||
|
map: DecodedSourceMap, offset: SourceLocation
|
||||||
|
) {
|
||||||
|
if (map.mappings.length == 0) return map;
|
||||||
|
// shift columns in first line
|
||||||
|
const segment_list = map.mappings[0];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
const seg = segment_list[segment];
|
||||||
|
if (seg[3]) seg[3] += offset.column;
|
||||||
|
}
|
||||||
|
// shift lines
|
||||||
|
for (let line = 0; line < map.mappings.length; line++) {
|
||||||
|
const segment_list = map.mappings[line];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
const seg = segment_list[segment];
|
||||||
|
if (seg[2]) seg[2] += offset.line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge_tables<T>(this_table: T[], other_table: T[]): [T[], number[], boolean, boolean] {
|
||||||
|
const new_table = this_table.slice();
|
||||||
|
const idx_map = [];
|
||||||
|
other_table = other_table || [];
|
||||||
|
let val_changed = false;
|
||||||
|
for (const [other_idx, other_val] of other_table.entries()) {
|
||||||
|
const this_idx = this_table.indexOf(other_val);
|
||||||
|
if (this_idx >= 0) {
|
||||||
|
idx_map[other_idx] = this_idx;
|
||||||
|
} else {
|
||||||
|
const new_idx = new_table.length;
|
||||||
|
new_table[new_idx] = other_val;
|
||||||
|
idx_map[other_idx] = new_idx;
|
||||||
|
val_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let idx_changed = val_changed;
|
||||||
|
if (val_changed) {
|
||||||
|
if (idx_map.find((val, idx) => val != idx) === undefined) {
|
||||||
|
// idx_map is identity map [0, 1, 2, 3, 4, ....]
|
||||||
|
idx_changed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 StringWithSourcemap {
|
||||||
|
string: string;
|
||||||
|
map: DecodedSourceMap;
|
||||||
|
|
||||||
|
constructor(string = '', map: DecodedSourceMap = null) {
|
||||||
|
this.string = string;
|
||||||
|
if (map) {
|
||||||
|
this.map = map as DecodedSourceMap;
|
||||||
|
} else {
|
||||||
|
this.map = {
|
||||||
|
version: 3,
|
||||||
|
mappings: [],
|
||||||
|
sources: [],
|
||||||
|
names: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* concat in-place (mutable), return this (chainable)
|
||||||
|
* will also mutate the `other` object
|
||||||
|
*/
|
||||||
|
concat(other: StringWithSourcemap): StringWithSourcemap {
|
||||||
|
// noop: if one is empty, return the other
|
||||||
|
if (other.string == '') return this;
|
||||||
|
if (this.string == '') {
|
||||||
|
this.string = other.string;
|
||||||
|
this.map = other.map;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.string += other.string;
|
||||||
|
|
||||||
|
const m1 = this.map;
|
||||||
|
const m2 = other.map;
|
||||||
|
|
||||||
|
if (m2.mappings.length == 0) return this;
|
||||||
|
|
||||||
|
// combine sources and names
|
||||||
|
const [sources, new_source_idx, sources_changed, sources_idx_changed] = merge_tables(m1.sources, m2.sources);
|
||||||
|
const [names, new_name_idx, names_changed, names_idx_changed] = merge_tables(m1.names, m2.names);
|
||||||
|
|
||||||
|
if (sources_changed) m1.sources = sources;
|
||||||
|
if (names_changed) m1.names = names;
|
||||||
|
|
||||||
|
// unswitched loops are faster
|
||||||
|
if (sources_idx_changed && names_idx_changed) {
|
||||||
|
for (let line = 0; line < m2.mappings.length; line++) {
|
||||||
|
const segment_list = m2.mappings[line];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
const seg = segment_list[segment];
|
||||||
|
if (seg[1]) seg[1] = new_source_idx[seg[1]];
|
||||||
|
if (seg[4]) seg[4] = new_name_idx[seg[4]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (sources_idx_changed) {
|
||||||
|
for (let line = 0; line < m2.mappings.length; line++) {
|
||||||
|
const segment_list = m2.mappings[line];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
const seg = segment_list[segment];
|
||||||
|
if (seg[1]) seg[1] = new_source_idx[seg[1]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (names_idx_changed) {
|
||||||
|
for (let line = 0; line < m2.mappings.length; line++) {
|
||||||
|
const segment_list = m2.mappings[line];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
const seg = segment_list[segment];
|
||||||
|
if (seg[4]) seg[4] = new_name_idx[seg[4]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// combine the mappings
|
||||||
|
|
||||||
|
// combine
|
||||||
|
// 1. last line of first map
|
||||||
|
// 2. first line of second map
|
||||||
|
// columns of 2 must be shifted
|
||||||
|
|
||||||
|
const column_offset = last_line_length(this.string);
|
||||||
|
if (m2.mappings.length > 0 && column_offset > 0) {
|
||||||
|
const first_line = m2.mappings[0];
|
||||||
|
for (let i = 0; i < first_line.length; i++) {
|
||||||
|
first_line[i][0] += column_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// combine last line + first line
|
||||||
|
pushArray(m1.mappings[m1.mappings.length - 1], m2.mappings.shift());
|
||||||
|
|
||||||
|
// append other lines
|
||||||
|
pushArray(m1.mappings, m2.mappings);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static from_processed(string: string, map?: DecodedSourceMap): StringWithSourcemap {
|
||||||
|
if (map) return new StringWithSourcemap(string, map);
|
||||||
|
if (string == '') return new StringWithSourcemap();
|
||||||
|
map = { version: 3, names: [], sources: [], mappings: [] };
|
||||||
|
|
||||||
|
// add empty SourceMapSegment[] for every line
|
||||||
|
const line_count = (string.match(/\n/g) || '').length;
|
||||||
|
for (let i = 0; i < line_count; i++) map.mappings.push([]);
|
||||||
|
return new StringWithSourcemap(string, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static from_source(
|
||||||
|
source_file: string, source: string, offset?: SourceLocation
|
||||||
|
): StringWithSourcemap {
|
||||||
|
if (!offset) offset = { line: 0, column: 0 };
|
||||||
|
const map: DecodedSourceMap = { version: 3, names: [], sources: [source_file], mappings: [] };
|
||||||
|
if (source == '') return new StringWithSourcemap(source, map);
|
||||||
|
|
||||||
|
// we create a high resolution identity map here,
|
||||||
|
// we know that it will eventually be merged with svelte's map,
|
||||||
|
// at which stage the resolution will decrease.
|
||||||
|
const line_list = source.split('\n');
|
||||||
|
for (let line = 0; line < line_list.length; line++) {
|
||||||
|
map.mappings.push([]);
|
||||||
|
const token_list = line_list[line].split(/([^\d\w\s]|\s+)/g);
|
||||||
|
for (let token = 0, column = 0; token < token_list.length; token++) {
|
||||||
|
if (token_list[token] == '') continue;
|
||||||
|
map.mappings[line].push([column, 0, offset.line + line, column]);
|
||||||
|
column += token_list[token].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// shift columns in first line
|
||||||
|
const segment_list = map.mappings[0];
|
||||||
|
for (let segment = 0; segment < segment_list.length; segment++) {
|
||||||
|
segment_list[segment][3] += offset.column;
|
||||||
|
}
|
||||||
|
return new StringWithSourcemap(source, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function combine_sourcemaps(
|
||||||
|
filename: string,
|
||||||
|
sourcemap_list: Array<DecodedSourceMap | RawSourceMap>
|
||||||
|
): RawSourceMap {
|
||||||
|
if (sourcemap_list.length == 0) return null;
|
||||||
|
|
||||||
|
let map_idx = 1;
|
||||||
|
const map: RawSourceMap =
|
||||||
|
sourcemap_list.slice(0, -1)
|
||||||
|
.find(m => m.sources.length !== 1) === undefined
|
||||||
|
|
||||||
|
? remapping( // use array interface
|
||||||
|
// only the oldest sourcemap can have multiple sources
|
||||||
|
sourcemap_list,
|
||||||
|
() => null,
|
||||||
|
true // skip optional field `sourcesContent`
|
||||||
|
)
|
||||||
|
|
||||||
|
: remapping( // use loader interface
|
||||||
|
sourcemap_list[0], // last map
|
||||||
|
function loader(sourcefile) {
|
||||||
|
if (sourcefile === filename && sourcemap_list[map_idx]) {
|
||||||
|
return sourcemap_list[map_idx++]; // idx 1, 2, ...
|
||||||
|
// bundle file = branch node
|
||||||
|
} else {
|
||||||
|
return null; // source file = leaf node
|
||||||
|
}
|
||||||
|
} as SourceMapLoader,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!map.file) delete map.file; // skip optional field `file`
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser vs node.js
|
||||||
|
const b64enc = typeof btoa == 'function' ? btoa : b => Buffer.from(b).toString('base64');
|
||||||
|
|
||||||
|
export function apply_preprocessor_sourcemap(filename: string, svelte_map: SourceMap, preprocessor_map_input: string | DecodedSourceMap | RawSourceMap): SourceMap {
|
||||||
|
if (!svelte_map || !preprocessor_map_input) return svelte_map;
|
||||||
|
|
||||||
|
const preprocessor_map = typeof preprocessor_map_input === 'string' ? JSON.parse(preprocessor_map_input) : preprocessor_map_input;
|
||||||
|
|
||||||
|
const result_map = combine_sourcemaps(
|
||||||
|
filename,
|
||||||
|
[
|
||||||
|
svelte_map as RawSourceMap,
|
||||||
|
preprocessor_map
|
||||||
|
]
|
||||||
|
) as RawSourceMap;
|
||||||
|
|
||||||
|
// Svelte expects a SourceMap which includes toUrl and toString. Instead of wrapping our output in a class,
|
||||||
|
// we just tack on the extra properties.
|
||||||
|
Object.defineProperties(result_map, {
|
||||||
|
toString: {
|
||||||
|
enumerable: false,
|
||||||
|
value: function toString() {
|
||||||
|
return JSON.stringify(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toUrl: {
|
||||||
|
enumerable: false,
|
||||||
|
value: function toUrl() {
|
||||||
|
return 'data:application/json;charset=utf-8;base64,' + b64enc(this.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result_map as SourceMap;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
export let obj;
|
||||||
|
export let c;
|
||||||
|
export let d;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot {c} {...obj} {d} />
|
@ -0,0 +1,55 @@
|
|||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
obj: { a: 1, b: 42 },
|
||||||
|
c: 5,
|
||||||
|
d: 10
|
||||||
|
},
|
||||||
|
html: `
|
||||||
|
<p>1</p>
|
||||||
|
<p>42</p>
|
||||||
|
<p>5</p>
|
||||||
|
<p>10</p>
|
||||||
|
`,
|
||||||
|
|
||||||
|
test({ assert, target, component }) {
|
||||||
|
component.obj = { a: 2, b: 50, c: 30 };
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>2</p>
|
||||||
|
<p>50</p>
|
||||||
|
<p>30</p>
|
||||||
|
<p>10</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.c = 22;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>2</p>
|
||||||
|
<p>50</p>
|
||||||
|
<p>30</p>
|
||||||
|
<p>10</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.d = 44;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>2</p>
|
||||||
|
<p>50</p>
|
||||||
|
<p>30</p>
|
||||||
|
<p>44</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.obj = { a: 9, b: 12 };
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>9</p>
|
||||||
|
<p>12</p>
|
||||||
|
<p>22</p>
|
||||||
|
<p>44</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
component.c = 88;
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<p>9</p>
|
||||||
|
<p>12</p>
|
||||||
|
<p>88</p>
|
||||||
|
<p>44</p>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from './Nested.svelte';
|
||||||
|
|
||||||
|
export let obj;
|
||||||
|
export let c;
|
||||||
|
export let d;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested {obj} {c} {d} let:a let:b let:c let:d>
|
||||||
|
<p>{a}</p>
|
||||||
|
<p>{b}</p>
|
||||||
|
<p>{c}</p>
|
||||||
|
<p>{d}</p>
|
||||||
|
</Nested>
|
@ -0,0 +1,7 @@
|
|||||||
|
<script>
|
||||||
|
import { hasContext } from 'svelte';
|
||||||
|
|
||||||
|
const has = hasContext('test');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>{has}</div>
|
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { setContext } from 'svelte';
|
||||||
|
|
||||||
|
export let value = '';
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
setContext('test', value);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot></slot>
|
@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<div>true</div>
|
||||||
|
<div>false</div>
|
||||||
|
`
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
import Nested from "./Nested.svelte";
|
||||||
|
import Leaf from "./Leaf.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Nested value="bar">
|
||||||
|
<Leaf />
|
||||||
|
</Nested>
|
||||||
|
|
||||||
|
<Nested>
|
||||||
|
<Leaf />
|
||||||
|
</Nested>
|
@ -0,0 +1,21 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<section>
|
||||||
|
<div>Second</div>
|
||||||
|
</section>
|
||||||
|
<button>Click</button>
|
||||||
|
`,
|
||||||
|
async test({ assert, component, target, window }) {
|
||||||
|
const button = target.querySelector('button');
|
||||||
|
|
||||||
|
await button.dispatchEvent(new window.Event('click'));
|
||||||
|
|
||||||
|
assert.htmlEqual(target.innerHTML, `
|
||||||
|
<section>
|
||||||
|
<div>First</div>
|
||||||
|
<div>Second</div>
|
||||||
|
</section>
|
||||||
|
<button>Click</button>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,17 @@
|
|||||||
|
<script>
|
||||||
|
let slide = 0;
|
||||||
|
let num = false;
|
||||||
|
|
||||||
|
const changeNum = () => num = !num;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
{#key slide}
|
||||||
|
{#if num}
|
||||||
|
<div>First</div>
|
||||||
|
{/if}
|
||||||
|
{/key}
|
||||||
|
<div>Second</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<button on:click={changeNum}>Click</button>
|
@ -0,0 +1,26 @@
|
|||||||
|
export default {
|
||||||
|
html: `
|
||||||
|
<p>42</p>
|
||||||
|
<p>42</p>
|
||||||
|
`,
|
||||||
|
|
||||||
|
async test({ assert, component, target }) {
|
||||||
|
await component.updateStore(undefined);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>undefined</p><p>42</p>');
|
||||||
|
|
||||||
|
await component.updateStore(33);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>33</p><p>42</p>');
|
||||||
|
|
||||||
|
await component.updateStore(undefined);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>undefined</p><p>42</p>');
|
||||||
|
|
||||||
|
await component.updateVar(undefined);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>undefined</p><p>undefined</p>');
|
||||||
|
|
||||||
|
await component.updateVar(33);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>undefined</p><p>33</p>');
|
||||||
|
|
||||||
|
await component.updateVar(undefined);
|
||||||
|
assert.htmlEqual(target.innerHTML, '<p>undefined</p><p>undefined</p>');
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
<script>
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
let store = writable(42);
|
||||||
|
let variable = 42;
|
||||||
|
let value;
|
||||||
|
let value2;
|
||||||
|
$: value = $store;
|
||||||
|
$: value2 = variable;
|
||||||
|
|
||||||
|
export function updateStore(value) {
|
||||||
|
store.set(value);
|
||||||
|
}
|
||||||
|
export function updateVar(value) {
|
||||||
|
variable = value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{ value }</p>
|
||||||
|
<p>{ value2 }</p>
|
@ -0,0 +1,20 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
|
||||||
|
export function magic_string_preprocessor_result(filename: string, src: MagicString) {
|
||||||
|
return {
|
||||||
|
code: src.toString(),
|
||||||
|
map: src.generateMap({
|
||||||
|
source: filename,
|
||||||
|
hires: true,
|
||||||
|
includeContent: false
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function magic_string_replace_all(src: MagicString, search: string, replace: string) {
|
||||||
|
let idx = src.original.indexOf(search);
|
||||||
|
if (idx == -1) throw new Error('search not found in src');
|
||||||
|
do {
|
||||||
|
src.overwrite(idx, idx + search.length, replace, { storeName: true });
|
||||||
|
} while ((idx = src.original.indexOf(search, idx + 1)) != -1);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
compile_options: {
|
||||||
|
dev: true
|
||||||
|
},
|
||||||
|
preprocess: [
|
||||||
|
{ style: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, '--replace-me-once', '\n --done-replace-once');
|
||||||
|
magic_string_replace_all(src, '--replace-me-twice', '\n--almost-done-replace-twice');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
} },
|
||||||
|
{ style: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, '--almost-done-replace-twice', '\n --done-replace-twice');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
} }
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
<h1>Testing Styles</h1>
|
||||||
|
<h2>Testing Styles 2</h2>
|
||||||
|
<div>Testing Styles 3</div>
|
||||||
|
<script>export const b = 2;</script>
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
--replace-me-once: red;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
--replace-me-twice: green;
|
||||||
|
}
|
||||||
|
div {
|
||||||
|
--keep-me: blue;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,40 @@
|
|||||||
|
import { SourceMapConsumer } from 'source-map';
|
||||||
|
|
||||||
|
const b64dec = s => Buffer.from(s, 'base64').toString();
|
||||||
|
|
||||||
|
export async function test({ assert, css, js }) {
|
||||||
|
|
||||||
|
// We check that the css source map embedded in the js is accurate
|
||||||
|
const match = js.code.match(/\tstyle\.textContent = "(.*?)(?:\\n\/\*# sourceMappingURL=data:(.*?);charset=(.*?);base64,(.*?) \*\/)?";\n/);
|
||||||
|
assert.notEqual(match, null);
|
||||||
|
|
||||||
|
const [mimeType, encoding, cssMapBase64] = match.slice(2);
|
||||||
|
assert.equal(mimeType, 'application/json');
|
||||||
|
assert.equal(encoding, 'utf-8');
|
||||||
|
|
||||||
|
const cssMapJson = b64dec(cssMapBase64);
|
||||||
|
css.mapConsumer = await new SourceMapConsumer(cssMapJson);
|
||||||
|
|
||||||
|
// TODO make util fn + move to test index.js
|
||||||
|
const sourcefile = 'input.svelte';
|
||||||
|
[
|
||||||
|
// TODO how to get line + column numbers?
|
||||||
|
[css, '--keep-me', 13, 2],
|
||||||
|
[css, '--done-replace-once', 6, 5],
|
||||||
|
[css, '--done-replace-twice', 9, 5]
|
||||||
|
]
|
||||||
|
.forEach(([where, content, line, column]) => {
|
||||||
|
assert.deepEqual(
|
||||||
|
where.mapConsumer.originalPositionFor(
|
||||||
|
where.locate_1(content)
|
||||||
|
),
|
||||||
|
{
|
||||||
|
source: sourcefile,
|
||||||
|
name: null,
|
||||||
|
line,
|
||||||
|
column
|
||||||
|
},
|
||||||
|
`failed to locate "${content}" from "${sourcefile}"`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
|
||||||
|
js_map_sources: [], // test component has no scripts
|
||||||
|
|
||||||
|
preprocess: {
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'replace me', 'success');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,2 @@
|
|||||||
|
<h1>decoded-sourcemap</h1>
|
||||||
|
<div>replace me</div>
|
@ -0,0 +1,19 @@
|
|||||||
|
export function test({ assert, input, preprocessed }) {
|
||||||
|
|
||||||
|
const expected = input.locate('replace me');
|
||||||
|
|
||||||
|
const start = preprocessed.locate('success');
|
||||||
|
|
||||||
|
const actualbar = preprocessed.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbar, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: 'replace me',
|
||||||
|
line: expected.line + 1,
|
||||||
|
column: expected.column
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: {
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'baritone', 'bar');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,5 @@
|
|||||||
|
<script>
|
||||||
|
export let foo;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{foo.baritone.baz}
|
@ -0,0 +1,32 @@
|
|||||||
|
export function test({ assert, input, js }) {
|
||||||
|
const expectedBar = input.locate('baritone.baz');
|
||||||
|
const expectedBaz = input.locate('.baz');
|
||||||
|
|
||||||
|
let start = js.locate('bar.baz');
|
||||||
|
|
||||||
|
const actualbar = js.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbar, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: 'baritone',
|
||||||
|
line: expectedBar.line + 1,
|
||||||
|
column: expectedBar.column
|
||||||
|
});
|
||||||
|
|
||||||
|
start = js.locate('.baz');
|
||||||
|
|
||||||
|
const actualbaz = js.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbaz, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: null,
|
||||||
|
line: expectedBaz.line + 1,
|
||||||
|
column: expectedBaz.column
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: {
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'baritone', 'bar');
|
||||||
|
magic_string_replace_all(src, '--bazitone', '--baz');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
},
|
||||||
|
script: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
const idx = content.indexOf('bar');
|
||||||
|
src.prependLeft(idx, ' ');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
},
|
||||||
|
style: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
const idx = content.indexOf('--baz');
|
||||||
|
src.prependLeft(idx, ' ');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
<script>
|
||||||
|
export let foo = { baritone: 5 }
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
background-color: var(--bazitone);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1>multiple {foo}</h1>
|
@ -0,0 +1,32 @@
|
|||||||
|
export function test({ assert, input, js, css }) {
|
||||||
|
const expectedBar = input.locate('baritone');
|
||||||
|
const expectedBaz = input.locate('--bazitone');
|
||||||
|
|
||||||
|
let start = js.locate('bar');
|
||||||
|
|
||||||
|
const actualbar = js.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbar, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: 'baritone',
|
||||||
|
line: expectedBar.line + 1,
|
||||||
|
column: expectedBar.column
|
||||||
|
});
|
||||||
|
|
||||||
|
start = css.locate('--baz');
|
||||||
|
|
||||||
|
const actualbaz = css.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbaz, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: '--bazitone',
|
||||||
|
line: expectedBaz.line + 1,
|
||||||
|
column: expectedBaz.column
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: {
|
||||||
|
script: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'baritone', 'bar');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,9 @@
|
|||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export let foo = { baritone: { baz: 5 } }
|
||||||
|
</script>
|
||||||
|
<h1>{foo.bar.baz}</h1>
|
@ -0,0 +1,32 @@
|
|||||||
|
export function test({ assert, input, js }) {
|
||||||
|
const expectedBar = input.locate('baritone:');
|
||||||
|
const expectedBaz = input.locate('baz:');
|
||||||
|
|
||||||
|
let start = js.locate('bar:');
|
||||||
|
|
||||||
|
const actualbar = js.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbar, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: 'baritone',
|
||||||
|
line: expectedBar.line + 1,
|
||||||
|
column: expectedBar.column
|
||||||
|
}, "couldn't find bar: in source");
|
||||||
|
|
||||||
|
start = js.locate('baz:');
|
||||||
|
|
||||||
|
const actualbaz = js.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbaz, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: null,
|
||||||
|
line: expectedBaz.line + 1,
|
||||||
|
column: expectedBaz.column
|
||||||
|
}, "couldn't find baz: in source");
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: {
|
||||||
|
style: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'baritone', 'bar');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
<h1>Testing Styles</h1>
|
||||||
|
<h2>Testing Styles 2</h2>
|
||||||
|
<script>export const b = 2;</script>
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
--baritone: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
--baz: blue;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,32 @@
|
|||||||
|
export function test({ assert, input, css }) {
|
||||||
|
const expectedBar = input.locate('--baritone');
|
||||||
|
const expectedBaz = input.locate('--baz');
|
||||||
|
|
||||||
|
let start = css.locate('--bar');
|
||||||
|
|
||||||
|
const actualbar = css.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbar, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: null,
|
||||||
|
line: expectedBar.line + 1,
|
||||||
|
column: expectedBar.column
|
||||||
|
}, "couldn't find bar in source");
|
||||||
|
|
||||||
|
start = css.locate('--baz');
|
||||||
|
|
||||||
|
const actualbaz = css.mapConsumer.originalPositionFor({
|
||||||
|
line: start.line + 1,
|
||||||
|
column: start.column
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(actualbaz, {
|
||||||
|
source: 'input.svelte',
|
||||||
|
name: null,
|
||||||
|
line: expectedBaz.line + 1,
|
||||||
|
column: expectedBaz.column
|
||||||
|
}, "couldn't find baz in source");
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { SourceMapConsumer, SourceMapGenerator } from 'source-map';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: {
|
||||||
|
style: async ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
const idx = content.indexOf('baritone');
|
||||||
|
src.overwrite(idx, idx+'baritone'.length, 'bar');
|
||||||
|
|
||||||
|
const map = SourceMapGenerator.fromSourceMap(
|
||||||
|
await new SourceMapConsumer(
|
||||||
|
// sourcemap must be encoded for SourceMapConsumer
|
||||||
|
src.generateMap({
|
||||||
|
source: filename,
|
||||||
|
hires: true,
|
||||||
|
includeContent: false
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return { code: src.toString(), map };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
<h1>Testing Styles</h1>
|
||||||
|
<h2>Testing Styles 2</h2>
|
||||||
|
<script>export const b = 2;</script>
|
||||||
|
<style>
|
||||||
|
h1 {
|
||||||
|
--baritone: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
--baz: blue;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1 @@
|
|||||||
|
export { test } from '../preprocessed-styles/test';
|
@ -0,0 +1,33 @@
|
|||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { magic_string_preprocessor_result, magic_string_replace_all } from '../../helpers';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
preprocess: [
|
||||||
|
{
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'baritone', 'bar');
|
||||||
|
magic_string_replace_all(src,'--bazitone', '--baz');
|
||||||
|
magic_string_replace_all(src,'old_name_1', 'temp_new_name_1');
|
||||||
|
magic_string_replace_all(src,'old_name_2', 'temp_new_name_2');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'temp_new_name_1', 'temp_temp_new_name_1');
|
||||||
|
magic_string_replace_all(src, 'temp_new_name_2', 'temp_temp_new_name_2');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
markup: ({ content, filename }) => {
|
||||||
|
const src = new MagicString(content);
|
||||||
|
magic_string_replace_all(src, 'temp_temp_new_name_1', 'new_name_1');
|
||||||
|
magic_string_replace_all(src, 'temp_temp_new_name_2', 'new_name_2');
|
||||||
|
return magic_string_preprocessor_result(filename, src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
<script>
|
||||||
|
export let old_name_1 = { baritone: 5 };
|
||||||
|
let old_name_2 = 'value_2';
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
background-color: var(--bazitone);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<h1>use-names</h1>
|
||||||
|
<div>{old_name_1.baritone}</div>
|
||||||
|
<pre style="color: var(--bazitone)">{old_name_2}</pre>
|
@ -0,0 +1,42 @@
|
|||||||
|
// needed for workaround, TODO remove
|
||||||
|
import { getLocator } from 'locate-character';
|
||||||
|
|
||||||
|
export function test({ assert, preprocessed, js, css }) {
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
preprocessed.map.names.sort(),
|
||||||
|
['baritone', '--bazitone', 'old_name_1', 'old_name_2'].sort()
|
||||||
|
);
|
||||||
|
|
||||||
|
function test_name(old_name, new_name, where) {
|
||||||
|
|
||||||
|
let loc = { character: -1 };
|
||||||
|
while (loc = where.locate(new_name, loc.character + 1)) {
|
||||||
|
const actualMapping = where.mapConsumer.originalPositionFor({
|
||||||
|
line: loc.line + 1, column: loc.column
|
||||||
|
});
|
||||||
|
if (actualMapping.line === null) {
|
||||||
|
// location is not mapped - ignore
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert.equal(actualMapping.name, old_name);
|
||||||
|
}
|
||||||
|
if (loc === undefined) {
|
||||||
|
// workaround for bug in locate-character, TODO remove
|
||||||
|
// https://github.com/Rich-Harris/locate-character/pull/5
|
||||||
|
where.locate = getLocator(where.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_name('baritone', 'bar', js);
|
||||||
|
test_name('baritone', 'bar', preprocessed);
|
||||||
|
|
||||||
|
test_name('--bazitone', '--baz', css);
|
||||||
|
test_name('--bazitone', '--baz', preprocessed);
|
||||||
|
|
||||||
|
test_name('old_name_1', 'new_name_1', js);
|
||||||
|
test_name('old_name_1', 'new_name_1', preprocessed);
|
||||||
|
|
||||||
|
test_name('old_name_2', 'new_name_2', js);
|
||||||
|
test_name('old_name_2', 'new_name_2', preprocessed);
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/* eslint-disable import/no-duplicates */
|
||||||
|
/* the code that transforms these to commonjs, can't handle "MagicString, { Bundle } from.." */
|
||||||
|
|
||||||
|
import MagicString from 'magic-string';
|
||||||
|
import { Bundle } from 'magic-string';
|
||||||
|
|
||||||
|
|
||||||
|
function add(bundle, filename, source) {
|
||||||
|
bundle.addSource({
|
||||||
|
filename,
|
||||||
|
content: new MagicString(source),
|
||||||
|
separator: '\n'
|
||||||
|
//separator: '' // ERROR. probably a bug in magic-string
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function result(bundle, filename) {
|
||||||
|
return {
|
||||||
|
code: bundle.toString(),
|
||||||
|
map: bundle.generateMap({
|
||||||
|
file: filename,
|
||||||
|
includeContent: false,
|
||||||
|
hires: true // required for remapping
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
js_map_sources: [
|
||||||
|
'input.svelte',
|
||||||
|
'foo.js',
|
||||||
|
'bar.js',
|
||||||
|
'foo2.js',
|
||||||
|
'bar2.js'
|
||||||
|
],
|
||||||
|
preprocess: [
|
||||||
|
{
|
||||||
|
script: ({ content, filename }) => {
|
||||||
|
const bundle = new Bundle();
|
||||||
|
|
||||||
|
add(bundle, filename, content);
|
||||||
|
add(bundle, 'foo.js', 'var answer = 42; // foo.js\n');
|
||||||
|
add(bundle, 'bar.js', 'console.log(answer); // bar.js\n');
|
||||||
|
|
||||||
|
return result(bundle, filename);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
script: ({ content, filename }) => {
|
||||||
|
const bundle = new Bundle();
|
||||||
|
|
||||||
|
add(bundle, filename, content);
|
||||||
|
add(bundle, 'foo2.js', 'var answer2 = 84; // foo2.js\n');
|
||||||
|
add(bundle, 'bar2.js', 'console.log(answer2); // bar2.js\n');
|
||||||
|
|
||||||
|
return result(bundle, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
@ -0,0 +1,4 @@
|
|||||||
|
<script>
|
||||||
|
export let name;
|
||||||
|
</script>
|
||||||
|
<h1>sourcemap-sources</h1>
|
@ -0,0 +1,29 @@
|
|||||||
|
export function test({ assert, preprocessed, js }) {
|
||||||
|
|
||||||
|
assert.equal(preprocessed.error, undefined);
|
||||||
|
|
||||||
|
// sourcemap stores location only for 'answer = 42;'
|
||||||
|
// not for 'var answer = 42;'
|
||||||
|
[
|
||||||
|
[js, 'foo.js', 'answer = 42;', 4],
|
||||||
|
[js, 'bar.js', 'console.log(answer);', 0],
|
||||||
|
[js, 'foo2.js', 'answer2 = 84;', 4],
|
||||||
|
[js, 'bar2.js', 'console.log(answer2);', 0]
|
||||||
|
]
|
||||||
|
.forEach(([where, sourcefile, content, column]) => {
|
||||||
|
|
||||||
|
assert.deepEqual(
|
||||||
|
where.mapConsumer.originalPositionFor(
|
||||||
|
where.locate_1(content)
|
||||||
|
),
|
||||||
|
{
|
||||||
|
source: sourcefile,
|
||||||
|
name: null,
|
||||||
|
line: 1,
|
||||||
|
column
|
||||||
|
},
|
||||||
|
`failed to locate "${content}" from "${sourcefile}"`
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in new issue