Add file: comment,

pull/8452/head
Puru Vijay 3 years ago
parent de803e1749
commit 9b439393e6

@ -50,10 +50,12 @@ In development mode (see the [compiler options](/docs/svelte-compiler#svelte-com
If you export a `const`, `class` or `function`, it is readonly from outside the component. Functions are valid prop values, however, as shown below. If you export a `const`, `class` or `function`, it is readonly from outside the component. Functions are valid prop values, however, as shown below.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
// these are readonly // these are readonly
export const thisIs = 'readonly'; export const thisIs = 'readonly';
/** @param {string} name */
export function greet(name) { export function greet(name) {
alert(`hello ${name}!`); alert(`hello ${name}!`);
} }
@ -68,6 +70,7 @@ Readonly props can be accessed as properties on the element, tied to the compone
You can use reserved words as prop names. You can use reserved words as prop names.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
/** @type {string} */ /** @type {string} */
let className; let className;
@ -154,10 +157,12 @@ Any top-level statement (i.e. not inside a block or a function) can be made reac
Only values which directly appear within the `$:` block will become dependencies of the reactive statement. For example, in the code below `total` will only update when `x` changes, but not `y`. Only values which directly appear within the `$:` block will become dependencies of the reactive statement. For example, in the code below `total` will only update when `x` changes, but not `y`.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
let x = 0; let x = 0;
let y = 0; let y = 0;
/** @param {number} value */
function yPlusAValue(value) { function yPlusAValue(value) {
return value + y; return value + y;
} }
@ -178,9 +183,10 @@ It is important to note that the reactive blocks are ordered via simple static a
let x = 0; let x = 0;
let y = 0; let y = 0;
const setY = (value) => { /** @param {number} value */
function setY(value) {
y = value; y = value;
}; }
$: yDependent = y; $: yDependent = y;
$: setY(x); $: setY(x);
@ -192,6 +198,7 @@ Moving the line `$: yDependent = y` below `$: setY(x)` will cause `yDependent` t
If a statement consists entirely of an assignment to an undeclared variable, Svelte will inject a `let` declaration on your behalf. If a statement consists entirely of an assignment to an undeclared variable, Svelte will inject a `let` declaration on your behalf.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
/** @type {number} */ /** @type {number} */
export let num; export let num;

@ -17,9 +17,11 @@ on:eventname|modifiers={handler}
Use the `on:` directive to listen to DOM events. Use the `on:` directive to listen to DOM events.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
let count = 0; let count = 0;
/** @param {MouseEvent} event */
function handleClick(event) { function handleClick(event) {
count += 1; count += 1;
} }
@ -70,12 +72,14 @@ If the `on:` directive is used without a value, the component will _forward_ the
It's possible to have multiple event listeners for the same event: It's possible to have multiple event listeners for the same event:
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
let counter = 0; let counter = 0;
function increment() { function increment() {
counter = counter + 1; counter = counter + 1;
} }
/** @param {MouseEvent} event */
function track(event) { function track(event) {
trackEvent(event); trackEvent(event);
} }
@ -274,8 +278,10 @@ bind:group={variable}
Inputs that work together can use `bind:group`. Inputs that work together can use `bind:group`.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
let tortilla = 'Plain'; let tortilla = 'Plain';
/** @type {Array<string>} */ /** @type {Array<string>} */
let fillings = []; let fillings = [];
</script> </script>
@ -301,6 +307,7 @@ bind:this={dom_node}
To get a reference to a DOM node, use `bind:this`. To get a reference to a DOM node, use `bind:this`.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
@ -400,8 +407,9 @@ action = (node: HTMLElement, parameters: any) => {
Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted: Actions are functions that are called when an element is created. They can return an object with a `destroy` method that is called after the element is unmounted:
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
/** @param {HTMLElement} node */ /** @type {import('svelte/action').Action} */
function foo(node) { function foo(node) {
// the node has been mounted in the DOM // the node has been mounted in the DOM
@ -421,9 +429,11 @@ An action can have a parameter. If the returned value has an `update` method, it
> Don't worry about the fact that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition. > Don't worry about the fact that we're redeclaring the `foo` function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
export let bar; export let bar;
/** @type {import('svelte/action').Action} */
function foo(node, bar) { function foo(node, bar) {
// the node has been mounted in the DOM // the node has been mounted in the DOM
@ -505,6 +515,7 @@ The `t` argument passed to `css` is a value between `0` and `1` after the `easin
The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments. The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments.
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
import { elasticOut } from 'svelte/easing'; import { elasticOut } from 'svelte/easing';
@ -717,12 +728,15 @@ The function is called repeatedly _before_ the animation begins, with different
<!-- TODO: Types --> <!-- TODO: Types -->
```svelte ```svelte
<!--- file: App.svelte --->
<script> <script>
import { cubicOut } from 'svelte/easing'; import { cubicOut } from 'svelte/easing';
/** /**
* @param {HTMLElement} node * @param {HTMLElement} node
* @param {{ from: DOMRect, to: DOMRect }} states * @param {Object} states
* @param {DOMRect} states.from
* @param {DOMRect} states.to
* @param {any} params * @param {any} params
*/ */
function whizz(node, { from, to }, params) { function whizz(node, { from, to }, params) {
@ -755,7 +769,9 @@ A custom animation function can also return a `tick` function, which is called _
/** /**
* @param {HTMLElement} node * @param {HTMLElement} node
* @param {{ from: DOMRect, to: DOMRect }} states * @param {Object} states
* @param {DOMRect} states.from
* @param {DOMRect} states.to
* @param {any} params * @param {any} params
*/ */
function whizz(node, { from, to }, params) { function whizz(node, { from, to }, params) {

@ -19,6 +19,7 @@ Function that creates a store which has values that can be set from 'outside' co
`update` is a method that takes one argument which is a callback. The callback takes the existing store value as its argument and returns the new value to be set to the store. `update` is a method that takes one argument which is a callback. The callback takes the existing store value as its argument and returns the new value to be set to the store.
```js ```js
/// file: store.js
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
const count = writable(0); const count = writable(0);
@ -60,6 +61,7 @@ Note that the value of a `writable` is lost when it is destroyed, for example wh
Creates a store whose value cannot be set from 'outside', the first argument is the store's initial value, and the second argument to `readable` is the same as the second argument to `writable`. Creates a store whose value cannot be set from 'outside', the first argument is the store's initial value, and the second argument to `readable` is the same as the second argument to `writable`.
```js ```js
/// file: store.js
import { readable } from 'svelte/store'; import { readable } from 'svelte/store';
/** @type {import('svelte/store').Readable<Date>} */ /** @type {import('svelte/store').Readable<Date>} */
@ -92,6 +94,8 @@ The callback can set a value asynchronously by accepting a second argument, `set
In this case, you can also pass a third argument to `derived` — the initial value of the derived store before `set` is first called. In this case, you can also pass a third argument to `derived` — the initial value of the derived store before `set` is first called.
<!-- TODO types -->
```js ```js
import { derived } from 'svelte/store'; import { derived } from 'svelte/store';
@ -106,6 +110,8 @@ const delayed = derived(
If you return a function from the callback, it will be called when a) the callback runs again, or b) the last subscriber unsubscribes. If you return a function from the callback, it will be called when a) the callback runs again, or b) the last subscriber unsubscribes.
<!-- TODO types -->
```js ```js
import { derived } from 'svelte/store'; import { derived } from 'svelte/store';
@ -126,6 +132,8 @@ const tick = derived(
In both cases, an array of arguments can be passed as the first argument instead of a single store. In both cases, an array of arguments can be passed as the first argument instead of a single store.
<!-- TODO type -->
```js ```js
import { derived } from 'svelte/store'; import { derived } from 'svelte/store';
@ -158,10 +166,6 @@ readableStore.set(2); // ERROR
> EXPORT_SNIPPET: svelte/store#get > EXPORT_SNIPPET: svelte/store#get
```js
declare function get<T>(store: Readable<T>): T;
```
Generally, you should read the value of a store by subscribing to it and using the value as it changes over time. Occasionally, you may need to retrieve the value of a store to which you're not subscribed. `get` allows you to do so. Generally, you should read the value of a store by subscribing to it and using the value as it changes over time. Occasionally, you may need to retrieve the value of a store to which you're not subscribed. `get` allows you to do so.
> This works by creating a subscription, reading the value, then unsubscribing. It's therefore not recommended in hot code paths. > This works by creating a subscription, reading the value, then unsubscribing. It's therefore not recommended in hot code paths.

@ -10,23 +10,12 @@ Nonetheless, it's useful to understand how to use the compiler, since bundler pl
> EXPORT_SNIPPET: svelte/compiler#compile > EXPORT_SNIPPET: svelte/compiler#compile
```js
result: {
js,
css,
ast,
warnings,
vars,
stats
} = svelte.compile(source: string, options?: {...})
```
This is where the magic happens. `svelte.compile` takes your component source code, and turns it into a JavaScript module that exports a class. This is where the magic happens. `svelte.compile` takes your component source code, and turns it into a JavaScript module that exports a class.
```js ```js
import svelte from 'svelte/compiler'; import { compile } from 'svelte/compiler';
const result = svelte.compile(source, { const result = compile(source, {
// options // options
}); });
``` ```
@ -86,7 +75,7 @@ The following options can be passed to the compiler. None are required:
The returned `result` object contains the code for your component, along with useful bits of metadata. The returned `result` object contains the code for your component, along with useful bits of metadata.
```js ```js
const { js, css, ast, warnings, vars, stats } = svelte.compile(source); const { js, css, ast, warnings, vars, stats } = compile(source);
``` ```
- `js` and `css` are objects with the following properties: - `js` and `css` are objects with the following properties:
@ -151,22 +140,12 @@ compiled: {
> EXPORT_SNIPPET: svelte/compiler#parse > EXPORT_SNIPPET: svelte/compiler#parse
```js
ast: object = svelte.parse(
source: string,
options?: {
filename?: string,
customElement?: boolean
}
)
```
The `parse` function parses a component, returning only its abstract syntax tree. Unlike compiling with the `generate: false` option, this will not perform any validation or other analysis of the component beyond parsing it. Note that the returned AST is not considered public API, so breaking changes could occur at any point in time. The `parse` function parses a component, returning only its abstract syntax tree. Unlike compiling with the `generate: false` option, this will not perform any validation or other analysis of the component beyond parsing it. Note that the returned AST is not considered public API, so breaking changes could occur at any point in time.
```js ```js
import svelte from 'svelte/compiler'; import { parse } from 'svelte/compiler';
const ast = svelte.parse(source, { filename: 'App.svelte' }); const ast = parse(source, { filename: 'App.svelte' });
``` ```
## `svelte.preprocess` ## `svelte.preprocess`
@ -177,33 +156,6 @@ A number of [community-maintained preprocessing plugins](https://sveltesociety.d
You can write your own preprocessor using the `svelte.preprocess` API. You can write your own preprocessor using the `svelte.preprocess` API.
```js
/** @type {{
code: string,
dependencies: Array<string>
}} */
result = await svelte.preprocess(
source: string,
preprocessors: Array<{
markup?: (input: { content: string, filename: string }) => Promise<{
code: string,
dependencies?: Array<string>
}>,
script?: (input: { content: string, markup: string, attributes: Record<string, string>, filename: string }) => Promise<{
code: string,
dependencies?: Array<string>
}>,
style?: (input: { content: string, markup: string, attributes: Record<string, string>, filename: string }) => Promise<{
code: string,
dependencies?: Array<string>
}>
}>,
options?: {
filename?: string
}
)
```
The `preprocess` function provides convenient hooks for arbitrarily transforming component source code. For example, it can be used to convert a `<style lang="sass">` block into vanilla CSS. The `preprocess` function provides convenient hooks for arbitrarily transforming component source code. For example, it can be used to convert a `<style lang="sass">` block into vanilla CSS.
The first argument is the component source code. The second is an array of _preprocessors_ (or a single preprocessor, if you only have one), where a preprocessor is an object with `markup`, `script` and `style` functions, each of which is optional. The first argument is the component source code. The second is an array of _preprocessors_ (or a single preprocessor, if you only have one), where a preprocessor is an object with `markup`, `script` and `style` functions, each of which is optional.
@ -215,10 +167,10 @@ The `markup` function receives the entire component source text, along with the
> Preprocessor functions should additionally return a `map` object alongside `code` and `dependencies`, where `map` is a sourcemap representing the transformation. > Preprocessor functions should additionally return a `map` object alongside `code` and `dependencies`, where `map` is a sourcemap representing the transformation.
```js ```js
import svelte from 'svelte/compiler'; import { preprocess } from 'svelte/compiler';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
const { code } = await svelte.preprocess( const { code } = await preprocess(
source, source,
{ {
markup: ({ content, filename }) => { markup: ({ content, filename }) => {
@ -275,9 +227,9 @@ const { code, dependencies } = await preprocess(
Multiple preprocessors can be used together. The output of the first becomes the input to the second. `markup` functions run first, then `script` and `style`. Multiple preprocessors can be used together. The output of the first becomes the input to the second. `markup` functions run first, then `script` and `style`.
```js ```js
import svelte from 'svelte/compiler'; import { preprocess } from 'svelte/compiler';
const { code } = await svelte.preprocess( const { code } = await preprocess(
source, source,
[ [
{ {
@ -313,21 +265,14 @@ const { code } = await svelte.preprocess(
> EXPORT_SNIPPET: svelte/compiler#walk > EXPORT_SNIPPET: svelte/compiler#walk
```js
walk(ast: Node, {
enter(node: Node, parent: Node, prop: string, index: number)?: void,
leave(node: Node, parent: Node, prop: string, index: number)?: void
})
```
The `walk` function provides a way to walk the abstract syntax trees generated by the parser, using the compiler's own built-in instance of [estree-walker](https://github.com/Rich-Harris/estree-walker). The `walk` function provides a way to walk the abstract syntax trees generated by the parser, using the compiler's own built-in instance of [estree-walker](https://github.com/Rich-Harris/estree-walker).
The walker takes an abstract syntax tree to walk and an object with two optional methods: `enter` and `leave`. For each node, `enter` is called (if present). Then, unless `this.skip()` is called during `enter`, each of the children are traversed, and then `leave` is called on the node. The walker takes an abstract syntax tree to walk and an object with two optional methods: `enter` and `leave`. For each node, `enter` is called (if present). Then, unless `this.skip()` is called during `enter`, each of the children are traversed, and then `leave` is called on the node.
```js ```js
import svelte from 'svelte/compiler'; import { walk } from 'svelte/compiler';
svelte.walk(ast, { walk(ast, {
enter(node, parent, prop, index) { enter(node, parent, prop, index) {
do_something(node); do_something(node);
if (should_skip_children(node)) { if (should_skip_children(node)) {
@ -347,6 +292,6 @@ svelte.walk(ast, {
The current version, as set in package.json. The current version, as set in package.json.
```js ```js
import svelte from 'svelte/compiler'; import { VERSION } from 'svelte/compiler';
console.log(`running svelte version ${svelte.VERSION}`); console.log(`running svelte version ${VERSION}`);
``` ```

@ -12,3 +12,4 @@
.vercel .vercel
examples-data.js examples-data.js
type-info.js type-info.js
.snippets

@ -7,9 +7,17 @@ import { SHIKI_LANGUAGE_MAP, normalizeSlugify, transform } from '../markdown';
import { replace_placeholders } from './render.js'; import { replace_placeholders } from './render.js';
// import { parse_route_id } from '../../../../../../packages/kit/src/utils/routing.js'; // import { parse_route_id } from '../../../../../../packages/kit/src/utils/routing.js';
import { createHash } from 'crypto'; import { createHash } from 'crypto';
import fs from 'fs';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import ts from 'typescript'; import ts from 'typescript';
const FILE_METADATA_REGEX = /(?:<!---\s*file:\s*(.*?)(?:\s*--->)|\/\/\/\s*file:\s*(.*?)(?:$))/i;
const snippet_cache = new URL('../../../../.snippets', import.meta.url).pathname;
if (!fs.existsSync(snippet_cache)) {
fs.mkdirSync(snippet_cache, { recursive: true });
}
/** /**
* @param {import('./types').DocsData} docs_data * @param {import('./types').DocsData} docs_data
* @param {string} slug * @param {string} slug
@ -35,10 +43,9 @@ export async function get_parsed_docs(docs_data, slug) {
hash.update(source + language + current); hash.update(source + language + current);
const digest = hash.digest().toString('base64').replace(/\//g, '-'); const digest = hash.digest().toString('base64').replace(/\//g, '-');
// TODO: cache if (fs.existsSync(`${snippet_cache}/${digest}.html`)) {
// if (fs.existsSync(`${snippet_cache}/${digest}.html`)) { return fs.readFileSync(`${snippet_cache}/${digest}.html`, 'utf-8');
// return fs.readFileSync(`${snippet_cache}/${digest}.html`, 'utf-8'); }
// }
/** @type {Record<string, string>} */ /** @type {Record<string, string>} */
const options = {}; const options = {};
@ -46,10 +53,14 @@ export async function get_parsed_docs(docs_data, slug) {
let html = ''; let html = '';
source = source source = source
.replace(/^\/\/\/ (.+?): (.+)\n/gm, (_, key, value) => { .replace(
/(?:<!---\s*([\w-]+):\s*(.*?)\s*--->|\/\/\/\s*([\w-]+):\s*(.*))\n/gm,
(_, key, value) => {
options[key] = value; options[key] = value;
console.log(options);
return ''; return '';
}) }
)
.replace(/^([\-\+])?((?: )+)/gm, (match, prefix = '', spaces) => { .replace(/^([\-\+])?((?: )+)/gm, (match, prefix = '', spaces) => {
if (prefix && language !== 'diff') return match; if (prefix && language !== 'diff') return match;
@ -228,7 +239,7 @@ export async function get_parsed_docs(docs_data, slug) {
) )
.replace(/\/\*…\*\//g, '…'); .replace(/\/\*…\*\//g, '…');
// fs.writeFileSync(`${snippet_cache}/${digest}.html`, html); fs.writeFileSync(`${snippet_cache}/${digest}.html`, html);
return html; return html;
}, },
codespan: (text) => { codespan: (text) => {
@ -315,7 +326,7 @@ export function generate_ts_from_js(markdown) {
return match.replace('js', 'original-js') + '\n```generated-ts\n' + ts + '\n```'; return match.replace('js', 'original-js') + '\n```generated-ts\n' + ts + '\n```';
}) })
.replaceAll(/```svelte\n([\s\S]+?)\n```/g, (match, code) => { .replaceAll(/```svelte\n([\s\S]+?)\n```/g, (match, code) => {
if (!code.includes('/// file:')) { if (!FILE_METADATA_REGEX.test(code)) {
// No named file -> assume that the code is not meant to be shown in two versions // No named file -> assume that the code is not meant to be shown in two versions
return match; return match;
} }
@ -335,7 +346,7 @@ export function generate_ts_from_js(markdown) {
return ( return (
match.replace('svelte', 'original-svelte') + match.replace('svelte', 'original-svelte') +
'\n```generated-svelte\n' + '\n```generated-svelte\n' +
code.replace(outer, `<script lang="ts">${ts}</script>`) + code.replace(outer, `<script lang="ts">\n\t${ts.trim()}\n</script>`) +
'\n```' '\n```'
); );
}); });
@ -414,11 +425,11 @@ function convert_to_ts(js_code, indent = '', offset = '') {
throw new Error('Unhandled @type JsDoc->TS conversion: ' + js_code); throw new Error('Unhandled @type JsDoc->TS conversion: ' + js_code);
} }
} else if (ts.isJSDocParameterTag(tag) && ts.isFunctionDeclaration(node)) { } else if (ts.isJSDocParameterTag(tag) && ts.isFunctionDeclaration(node)) {
if (node.parameters.length !== 1) { // if (node.parameters.length !== 1) {
throw new Error( // throw new Error(
'Unhandled @type JsDoc->TS conversion; needs more params logic: ' + node.getText() // 'Unhandled @type JsDoc->TS conversion; needs more params logic: ' + node.getText()
); // );
} // }
const [name] = get_type_info(tag); const [name] = get_type_info(tag);
code.appendLeft(node.parameters[0].getEnd(), `: ${name}`); code.appendLeft(node.parameters[0].getEnd(), `: ${name}`);

@ -7,8 +7,6 @@ export function replace_placeholders(content) {
const module = modules.find((module) => module.name === name); const module = modules.find((module) => module.name === name);
if (!module) throw new Error(`Could not find module ${name}`); if (!module) throw new Error(`Could not find module ${name}`);
console.log(module);
const type = module.types.find((t) => t.name === id); const type = module.types.find((t) => t.name === id);
return ( return (

@ -1,6 +1,7 @@
<script> <script>
import { page } from '$app/stores'; import { page } from '$app/stores';
import Contents from './Contents.svelte'; import Contents from './Contents.svelte';
import { TSToggle } from '@sveltejs/site-kit/components';
export let data; export let data;
@ -21,6 +22,10 @@
<div class="toc-container"> <div class="toc-container">
<Contents contents={data.sections} /> <Contents contents={data.sections} />
</div> </div>
<div class="ts-toggle">
<TSToggle />
</div>
</div> </div>
<style> <style>
@ -71,12 +76,12 @@
.toc-container { .toc-container {
background: var(--sk-back-3); background: var(--sk-back-3);
} }
/*
.ts-toggle { .ts-toggle {
width: 100%; width: 100%;
border-top: 1px solid var(--sk-back-4); border-top: 1px solid var(--sk-back-4);
background-color: var(--sk-back-3); background-color: var(--sk-back-3);
} */ }
@media (min-width: 832px) { @media (min-width: 832px) {
.toc-container { .toc-container {
@ -103,14 +108,14 @@
padding-left: calc(var(--sidebar-width) + var(--sk-page-padding-side)); padding-left: calc(var(--sidebar-width) + var(--sk-page-padding-side));
} }
/* .ts-toggle { .ts-toggle {
position: fixed; position: fixed;
width: var(--sidebar-width); width: var(--sidebar-width);
bottom: 0; bottom: 0;
z-index: 1; z-index: 1;
margin-right: 0; margin-right: 0;
border-right: 1px solid var(--sk-back-5); border-right: 1px solid var(--sk-back-5);
} */ }
} }
@media (min-width: 1200px) { @media (min-width: 1200px) {

Loading…
Cancel
Save