You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte/src/index.ts

165 lines
4.2 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import parse from './parse/index';
import validate from './validate/index';
import generate from './compile/dom/index';
import generateSSR from './compile/ssr/index';
import Stats from './Stats';
import { assign } from './shared/index.js';
import Stylesheet from './css/Stylesheet';
import { Ast, CompileOptions, Warning, PreprocessOptions, Preprocessor } from './interfaces';
import { SourceMap } from 'magic-string';
const version = '__VERSION__';
function normalizeOptions(options: CompileOptions): CompileOptions {
let normalizedOptions = assign({ generate: 'dom' }, options);
const { onwarn, onerror } = normalizedOptions;
normalizedOptions.onwarn = onwarn
? (warning: Warning) => onwarn(warning, defaultOnwarn)
: defaultOnwarn;
normalizedOptions.onerror = onerror
? (error: Error) => onerror(error, defaultOnerror)
: defaultOnerror;
return normalizedOptions;
}
function defaultOnwarn(warning: Warning) {
if (warning.start) {
console.warn(
`(${warning.start.line}:${warning.start.column}) ${warning.message}`
); // eslint-disable-line no-console
} else {
console.warn(warning.message); // eslint-disable-line no-console
}
}
function defaultOnerror(error: Error) {
throw error;
}
function parseAttributeValue(value: string) {
return /^['"]/.test(value) ?
value.slice(1, -1) :
value;
}
function parseAttributes(str: string) {
const attrs = {};
str.split(/\s+/).filter(Boolean).forEach(attr => {
const [name, value] = attr.split('=');
attrs[name] = value ? parseAttributeValue(value) : true;
});
return attrs;
}
async function replaceTagContents(source, type: 'script' | 'style', preprocessor: Preprocessor, options: PreprocessOptions) {
const exp = new RegExp(`<${type}([\\S\\s]*?)>([\\S\\s]*?)<\\/${type}>`, 'ig');
const match = exp.exec(source);
if (match) {
const attributes: Record<string, string | boolean> = parseAttributes(match[1]);
const content: string = match[2];
const processed: { code: string, map?: SourceMap | string } = await preprocessor({
content,
attributes,
filename : options.filename
});
if (processed && processed.code) {
return (
source.slice(0, match.index) +
`<${type}>${processed.code}</${type}>` +
source.slice(match.index + match[0].length)
);
}
}
return source;
}
export async function preprocess(source: string, options: PreprocessOptions) {
const { markup, style, script } = options;
if (!!markup) {
const processed: { code: string, map?: SourceMap | string } = await markup({
content: source,
filename: options.filename
});
source = processed.code;
}
if (!!style) {
source = await replaceTagContents(source, 'style', style, options);
}
if (!!script) {
source = await replaceTagContents(source, 'script', script, options);
}
return {
// TODO return separated output, in future version where svelte.compile supports it:
// style: { code: styleCode, map: styleMap },
// script { code: scriptCode, map: scriptMap },
// markup { code: markupCode, map: markupMap },
toString() {
return source;
}
};
}
function compile(source: string, _options: CompileOptions) {
const options = normalizeOptions(_options);
let ast: Ast;
const stats = new Stats({
onwarn: options.onwarn
});
try {
stats.start('parse');
ast = parse(source, options);
stats.stop('parse');
} catch (err) {
options.onerror(err);
return;
}
stats.start('stylesheet');
const stylesheet = new Stylesheet(source, ast, options.filename, options.dev);
stats.stop('stylesheet');
stats.start('validate');
validate(ast, source, stylesheet, stats, options);
stats.stop('validate');
if (options.generate === false) {
return { ast, stats: stats.render(null), js: null, css: null };
}
const compiler = options.generate === 'ssr' ? generateSSR : generate;
return compiler(ast, source, stylesheet, options, stats);
};
function create(source: string, _options: CompileOptions = {}) {
_options.format = 'eval';
const compiled = compile(source, _options);
if (!compiled || !compiled.js.code) {
return;
}
try {
return (new Function(`return ${compiled.js.code}`))();
} catch (err) {
if (_options.onerror) {
_options.onerror(err);
return;
} else {
throw err;
}
}
}
export { parse, create, compile, version as VERSION };