|
|
@ -6,8 +6,93 @@ import { getLocator } from 'locate-character';
|
|
|
|
import { walk } from 'zimmerframe';
|
|
|
|
import { walk } from 'zimmerframe';
|
|
|
|
import { validate_component_options, validate_module_options } from './validate-options.js';
|
|
|
|
import { validate_component_options, validate_module_options } from './validate-options.js';
|
|
|
|
import { convert } from './legacy.js';
|
|
|
|
import { convert } from './legacy.js';
|
|
|
|
|
|
|
|
import { transform_warnings } from './utils/warnings.js';
|
|
|
|
export { default as preprocess } from './preprocess/index.js';
|
|
|
|
export { default as preprocess } from './preprocess/index.js';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @param {string} source
|
|
|
|
|
|
|
|
* @param {string | undefined} filename
|
|
|
|
|
|
|
|
* @param {Function} fn
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
function handle_error(source, filename, fn) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
return fn();
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
if (/** @type {any} */ (e).name === 'CompileError') {
|
|
|
|
|
|
|
|
const error = /** @type {import('#compiler').CompileError} */ (e);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
error.filename = filename;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (error.position) {
|
|
|
|
|
|
|
|
// TODO this is reused with warnings — DRY out
|
|
|
|
|
|
|
|
const locator = getLocator(source, { offsetLine: 1 });
|
|
|
|
|
|
|
|
const start = locator(error.position[0]);
|
|
|
|
|
|
|
|
const end = locator(error.position[1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
error.start = start;
|
|
|
|
|
|
|
|
error.end = end;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* The parse function parses a component, returning only its abstract syntax tree.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* The `modern` option (`false` by default in Svelte 5) makes the parser return a modern AST instead of the legacy AST.
|
|
|
|
|
|
|
|
* `modern` will become `true` by default in Svelte 6, and the option will be removed in Svelte 7.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* https://svelte.dev/docs/svelte-compiler#svelte-parse
|
|
|
|
|
|
|
|
* @param {string} source
|
|
|
|
|
|
|
|
* @param {{ filename?: string; modern?: boolean }} [options]
|
|
|
|
|
|
|
|
* @returns {import('#compiler').SvelteNode | import('./types/legacy-nodes.js').LegacySvelteNode}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function parse(source, options = {}) {
|
|
|
|
|
|
|
|
return handle_error(source, undefined, () => {
|
|
|
|
|
|
|
|
/** @type {import('#compiler').Root} */
|
|
|
|
|
|
|
|
const ast = _parse(source);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (options.modern) {
|
|
|
|
|
|
|
|
// remove things that we don't want to treat as public API
|
|
|
|
|
|
|
|
return walk(/** @type {import('#compiler').SvelteNode} */ (ast), null, {
|
|
|
|
|
|
|
|
_(node, { next }) {
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
|
|
delete node.parent;
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
|
|
delete node.metadata;
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return convert(source, ast);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @param {string} source
|
|
|
|
|
|
|
|
* @param {TODO} options
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function analyze(source, options = {}) {
|
|
|
|
|
|
|
|
return handle_error(source, options.filename, () => {
|
|
|
|
|
|
|
|
const validated = validate_component_options(options, '');
|
|
|
|
|
|
|
|
const parsed = _parse(source);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const combined_options = /** @type {import('#compiler').ValidatedCompileOptions} */ ({
|
|
|
|
|
|
|
|
...validated,
|
|
|
|
|
|
|
|
...parsed.options
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const analysis = analyze_component(parsed, combined_options);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
warnings: transform_warnings(source, options.filename, analysis.warnings)
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* `compile` converts your `.svelte` source code into a JavaScript module that exports a component
|
|
|
|
* `compile` converts your `.svelte` source code into a JavaScript module that exports a component
|
|
|
|
*
|
|
|
|
*
|
|
|
@ -17,7 +102,7 @@ export { default as preprocess } from './preprocess/index.js';
|
|
|
|
* @returns {import('#compiler').CompileResult}
|
|
|
|
* @returns {import('#compiler').CompileResult}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function compile(source, options) {
|
|
|
|
export function compile(source, options) {
|
|
|
|
try {
|
|
|
|
return handle_error(source, options.filename, () => {
|
|
|
|
const validated = validate_component_options(options, '');
|
|
|
|
const validated = validate_component_options(options, '');
|
|
|
|
const parsed = _parse(source);
|
|
|
|
const parsed = _parse(source);
|
|
|
|
|
|
|
|
|
|
|
@ -29,17 +114,7 @@ export function compile(source, options) {
|
|
|
|
const analysis = analyze_component(parsed, combined_options);
|
|
|
|
const analysis = analyze_component(parsed, combined_options);
|
|
|
|
const result = transform_component(analysis, source, combined_options);
|
|
|
|
const result = transform_component(analysis, source, combined_options);
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
} catch (e) {
|
|
|
|
});
|
|
|
|
if (/** @type {any} */ (e).name === 'CompileError') {
|
|
|
|
|
|
|
|
handle_compile_error(
|
|
|
|
|
|
|
|
/** @type {import('#compiler').CompileError} */ (e),
|
|
|
|
|
|
|
|
options.filename,
|
|
|
|
|
|
|
|
source
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -51,86 +126,11 @@ export function compile(source, options) {
|
|
|
|
* @returns {import('#compiler').CompileResult}
|
|
|
|
* @returns {import('#compiler').CompileResult}
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
export function compileModule(source, options) {
|
|
|
|
export function compileModule(source, options) {
|
|
|
|
try {
|
|
|
|
return handle_error(source, options.filename, () => {
|
|
|
|
const validated = validate_module_options(options, '');
|
|
|
|
const validated = validate_module_options(options, '');
|
|
|
|
const analysis = analyze_module(parse_acorn(source), validated);
|
|
|
|
const analysis = analyze_module(parse_acorn(source), validated);
|
|
|
|
return transform_module(analysis, source, validated);
|
|
|
|
return transform_module(analysis, source, validated);
|
|
|
|
} catch (e) {
|
|
|
|
});
|
|
|
|
if (/** @type {any} */ (e).name === 'CompileError') {
|
|
|
|
|
|
|
|
handle_compile_error(
|
|
|
|
|
|
|
|
/** @type {import('#compiler').CompileError} */ (e),
|
|
|
|
|
|
|
|
options.filename,
|
|
|
|
|
|
|
|
source
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* @param {import('#compiler').CompileError} error
|
|
|
|
|
|
|
|
* @param {string | undefined} filename
|
|
|
|
|
|
|
|
* @param {string} source
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
function handle_compile_error(error, filename, source) {
|
|
|
|
|
|
|
|
error.filename = filename;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (error.position) {
|
|
|
|
|
|
|
|
// TODO this is reused with warnings — DRY out
|
|
|
|
|
|
|
|
const locator = getLocator(source, { offsetLine: 1 });
|
|
|
|
|
|
|
|
const start = locator(error.position[0]);
|
|
|
|
|
|
|
|
const end = locator(error.position[1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
error.start = start;
|
|
|
|
|
|
|
|
error.end = end;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* The parse function parses a component, returning only its abstract syntax tree.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* The `modern` option (`false` by default in Svelte 5) makes the parser return a modern AST instead of the legacy AST.
|
|
|
|
|
|
|
|
* `modern` will become `true` by default in Svelte 6, and the option will be removed in Svelte 7.
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* https://svelte.dev/docs/svelte-compiler#svelte-parse
|
|
|
|
|
|
|
|
* @param {string} source
|
|
|
|
|
|
|
|
* @param {{ filename?: string; modern?: boolean }} [options]
|
|
|
|
|
|
|
|
* @returns {import('#compiler').SvelteNode | import('./types/legacy-nodes.js').LegacySvelteNode}
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
export function parse(source, options = {}) {
|
|
|
|
|
|
|
|
/** @type {import('#compiler').Root} */
|
|
|
|
|
|
|
|
let ast;
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
ast = _parse(source);
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
if (/** @type {any} */ (e).name === 'CompileError') {
|
|
|
|
|
|
|
|
handle_compile_error(
|
|
|
|
|
|
|
|
/** @type {import('#compiler').CompileError} */ (e),
|
|
|
|
|
|
|
|
options.filename,
|
|
|
|
|
|
|
|
source
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (options.modern) {
|
|
|
|
|
|
|
|
// remove things that we don't want to treat as public API
|
|
|
|
|
|
|
|
return walk(/** @type {import('#compiler').SvelteNode} */ (ast), null, {
|
|
|
|
|
|
|
|
_(node, { next }) {
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
|
|
delete node.parent;
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
|
|
delete node.metadata;
|
|
|
|
|
|
|
|
next();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return convert(source, ast);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|