8000 feat: add `print(...)` function by Rich-Harris · Pull Request #16188 · sveltejs/svelte · GitHub
[go: up one dir, main page]

Skip to content

feat: add print(...) function #16188

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 41 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a0f86c5
use local version of esrap, for now
Rich-Harris Jun 15, 2025
486d10c
WIP
Rich-Harris Jun 16, 2025
97c5d98
WIP
Rich-Harris Jun 16, 2025
74ec766
fixes
Rich-Harris Jun 16, 2025
3026a37
more
Rich-Harris Jun 17, 2025
683ac71
add `Declaration` visitor
Ocean-OS Jun 17, 2025
45755ea
add `TransitionDirective`
Ocean-OS Jun 17, 2025
222dd41
`UseDirective`, `OnDirective`
Ocean-OS Jun 17, 2025
1e7b439
more directives
Ocean-OS Jun 17, 2025
afd3cb4
`SpreadAttribute`, directive shorthands
Ocean-OS Jun 17, 2025
4c404ac
`{#if ...} {:else ...}`
Ocean-OS Jun 17, 2025
c646f97
fix
Ocean-OS Jun 17, 2025
d96412b
more
Ocean-OS Jun 17, 2025
566da5b
add tags, `AnimateDirective`
Ocean-OS Jun 17, 2025
0b9f560
`KeyBlock`
Ocean-OS Jun 17, 2025
0de2182
`SelectorList`, `<svelte:whatever />`
Ocean-OS Jun 17, 2025
bfcec71
Merge branch 'main' into print
Ocean-OS Jun 17, 2025
e41bbe7
quote text in `Attribute` visitor
Ocean-OS Jun 21, 2025
0a61c80
tweak test logic to reduce false negatives
Rich-Harris Jun 23, 2025
5db4ea8
fix
Rich-Harris Jun 23, 2025
b80eb3e
fix
Rich-Harris Jun 23, 2025
4018b50
add separate test suite
Rich-Harris Jun 23, 2025
1ca1be5
fix
Rich-Harris Jun 23, 2025
80370e3
more
Rich-Harris Jun 23, 2025
4538f80
slightly nicer printing
Rich-Harris Jun 23, 2025
e47f579
install from pkg.pr.new
Rich-Harris Jun 23, 2025
203c321
Merge branch 'main' into print
Rich-Harris Jun 23, 2025
df3be44
merge main
Rich-Harris Jun 23, 2025
c474d67
bump
Rich-Harris Jun 23, 2025
e904753
fix
Rich-Harris Jun 23, 2025
7bf7f56
remove any
Rich-Harris Jun 23, 2025
700260b
fix indentation
Rich-Harris Jun 23, 2025
b4dde24
replace TODO with a type error
Rich-Harris Jun 23, 2025
e4c6d4e
bump
Rich-Harris Jun 23, 2025
132d84d
fix
Rich-Harris Jun 24, 2025
226b4ca
esrap@2
Rich-Harris Jun 25, 2025
9f42c0b
merge main
Rich-Harris Jun 25, 2025
85ee437
lockfile
Rich-Harris Jun 25, 2025
64bfedb
try this
Rich-Harris Jun 25, 2025
a39ab49
regenerate
Rich-Harris Jun 25, 2025
1377c40
Merge branch 'main' into print
Rich-Harris Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
WIP
  • Loading branch information
Rich-Harris committed Jun 16, 2025
commit 486d10c8806482940d15435a3c87d66a37a89525
133 changes: 50 additions & 83 deletions packages/svelte/scripts/process-messages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import fs from 'node:fs';
import * as acorn from 'acorn';
import { walk } from 'zimmerframe';
import * as esrap from 'esrap';
import ts from 'esrap/languages/ts';

const DIR = '../../documentation/docs/98-reference/.generated';

Expand Down Expand Up @@ -98,55 +99,18 @@ function run() {
.replace(/\r\n/g, '\n');

/**
* @type {Array<{
* type: string;
* value: string;
* start: number;
* end: number
* }>}
* @type {any[]}
*/
const comments = [];

let ast = acorn.parse(source, {
ecmaVersion: 'latest',
sourceType: 'module',
onComment: (block, value, start, end) => {
if (block && /\n/.test(value)) {
let a = start;
while (a > 0 && source[a - 1] !== '\n') a -= 1;

let b = a;
while (/[ \t]/.test(source[b])) b += 1;

const indentation = source.slice(a, b);
value = value.replace(new RegExp(`^${indentation}`, 'gm'), '');
}

comments.push({ type: block ? 'Block' : 'Line', value, start, end });
}
locations: true,
onComment: comments
});

ast = walk(ast, null, {
_(node, { next }) {
let comment;

while (comments[0] && comments[0].start < node.start) {
comment = comments.shift();
// @ts-expect-error
(node.leadingComments ||= []).push(comment);
}

next();

if (comments[0]) {
const slice = source.slice(node.end, comments[0].start);

if (/^[,) \t]*$/.test(slice)) {
// @ts-expect-error
node.trailingComments = [comments.shift()];
}
}
},
// @ts-expect-error
Identifier(node, context) {
if (node.name === 'CODES') {
Expand All @@ -161,11 +125,6 @@ function run() {
}
});

if (comments.length > 0) {
// @ts-expect-error
(ast.trailingComments ||= []).push(...comments);
}

const category = messages[name];

// find the `export function CODE` node
Expand All @@ -184,6 +143,16 @@ function run() {
const template_node = ast.body[index];
ast.body.splice(index, 1);

const jsdoc = comments.findLast((comment) => comment.start < template_node.start);

const printed = esrap.print(
ast,
// @ts-expect-error
ts({
comments: comments.filter((comment) => comment !== jsdoc)
})
);

for (const code in category) {
const { messages } = category[code];
/** @type {string[]} */
Expand Down Expand Up @@ -273,41 +242,6 @@ function run() {
}

const clone = walk(/** @type {import('estree').Node} */ (template_node), null, {
// @ts-expect-error Block is a block comment, which is not recognised
Block(node, context) {
if (!node.value.includes('PARAMETER')) return;

const value = /** @type {string} */ (node.value)
.split('\n')
.map((line) => {
if (line === ' * MESSAGE') {
return messages[messages.length - 1]
.split('\n')
.map((line) => ` * ${line}`)
.join('\n');
}

if (line.includes('PARAMETER')) {
return vars
.map((name, i) => {
const optional = i >= group[0].vars.length;

return optional
? ` * @param {string | undefined | null} [${name}]`
: ` * @param {string} ${name}`;
})
.join('\n');
}

return line;
})
.filter((x) => x !== '')
.join('\n');

if (value !== node.value) {
return { ...node, value };
}
},
FunctionDeclaration(node, context) {
if (node.id.name !== 'CODE') return;

Expand Down Expand Up @@ -394,16 +328,49 @@ function run() {
}
});

const jsdoc_clone = {
...jsdoc,
value: /** @type {string} */ (jsdoc.value)
.split('\n')
.map((line) => {
if (line === ' * MESSAGE') {
return messages[messages.length - 1]
.split('\n')
.map((line) => ` * ${line}`)
.join('\n');
}

if (line.includes('PARAMETER')) {
return vars
.map((name, i) => {
const optional = i >= group[0].vars.length;

return optional
? ` * @param {string | undefined | null} [${name}]`
: ` * @param {string} ${name}`;
})
.join('\n');
}

return line;
})
.filter((x) => x !== '')
.join('\n')
};

// @ts-expect-error
const block = esrap.print({ ...ast, body: [clone] }, ts({ comments: [jsdoc_clone] })).code;

printed.code += `\n\n${block}`;

// @ts-expect-error
ast.body.push(clone);
}

const module = esrap.print(ast);

fs.writeFileSync(
dest,
`/* This file is generated by scripts/process-messages/index.js. Do not edit! */\n\n` +
module.code,
printed.code,
'utf-8'
);
}
Expand Down
18 changes: 12 additions & 6 deletions packages/svelte/src/compiler/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@ import { CompileDiagnostic } from './utils/compile_diagnostic.js';

/** @typedef {{ start?: number, end?: number }} NodeLike */
class InternalCompileError extends Error {
message = ''; // ensure this property is enumerable
message = '';

// ensure this property is enumerable
#diagnostic;

/**
* @param {string} code
* @param {string} message
* @param {[number, number] | undefined} position
*/
* @param {string} code
* @param {string} message
* @param {[number, number] | undefined} position
*/
constructor(code, message, position) {
super(message);
this.stack = ''; // avoid unnecessary noise; don't set it as a class property or it becomes enumerable

// We want to extend from Error so that various bundler plugins properly handle it.
// But we also want to share the same object shape with that of warnings, therefore
// we create an instance of the shared class an copy over its properties.
this.#diagnostic = new CompileDiagnostic(code, message, position);

Object.assign(this, this.#diagnostic);
this.name = 'CompileError';
}
Expand Down Expand Up @@ -816,7 +820,9 @@ export function bind_invalid_expression(node) {
* @returns {never}
*/
export function bind_invalid_name(node, name, explanation) {
e(node, 'bind_invalid_name', `${explanation ? `\`bind:${name}\` is not a valid binding. ${explanation}` : `\`bind:${name}\` is not a valid binding`}\nhttps://svelte.dev/e/bind_invalid_name`);
e(node, 'bind_invalid_name', `${explanation
? `\`bind:${name}\` is not a valid binding. ${explanation}`
: `\`bind:${name}\` is not a valid binding`}\nhttps://svelte.dev/e/bind_invalid_name`);
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/svelte/src/compiler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { transform_component, transform_module } from './phases/3-transform/inde
import { validate_component_options, validate_module_options } from './validate-options.js';
import * as state from './state.js';
export { default as preprocess } from './preprocess/index.js';
export { print } from './print/index.js';

/**
* `compile` converts your `.svelte` source code into a JavaScript module that exports a component
Expand Down
1 change: 1 addition & 0 deletions packages/svelte/src/compiler/legacy.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ export function convert(source, ast) {
SpreadAttribute(node) {
return { ...node, type: 'Spread' };
},
// @ts-ignore
StyleSheet(node, context) {
return {
...node,
Expand Down
7 changes: 5 additions & 2 deletions packages/svelte/src/compiler/phases/3-transform/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @import { ValidatedCompileOptions, CompileResult, ValidatedModuleCompileOptions } from '#compiler' */
/** @import { ComponentAnalysis, Analysis } from '../types' */
import { print } from 'esrap';
import ts from 'esrap/languages/ts';
import { VERSION } from '../../../version.js';
import { server_component, server_module } from './server/transform-server.js';
import { client_component, client_module } from './client/transform-client.js';
Expand Down Expand Up @@ -34,7 +35,8 @@ export function transform_component(analysis, source, options) {

const js_source_name = get_source_name(options.filename, options.outputFilename, 'input.svelte');

const js = print(program, {
// @ts-ignore TODO
const js = print(program, ts(), {
// include source content; makes it easier/more robust looking up the source map code
// (else esrap does return null for source and sourceMapContent which may trip up tooling)
sourceMapContent: source,
Expand Down Expand Up @@ -94,7 +96,8 @@ export function transform_module(analysis, source, options) {
}

return {
js: print(program, {
// @ts-expect-error
js: print(program, ts(), {
// include source content; makes it easier/more robust looking up the source map code
// (else esrap does return null for source and sourceMapContent which may trip up tooling)
sourceMapContent: source,
Expand Down
Loading
0