move files around a bit

pull/1721/head
Rich Harris 7 years ago
parent a4d412fb53
commit 27f7df4db8

@ -2,7 +2,6 @@ import CodeBuilder from '../../utils/CodeBuilder';
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import { escape } from '../../utils/stringify'; import { escape } from '../../utils/stringify';
import Compiler from '../Compiler'; import Compiler from '../Compiler';
import { Node } from '../../interfaces';
export interface BlockOptions { export interface BlockOptions {
parent?: Block; parent?: Block;

@ -1,19 +1,12 @@
import MagicString from 'magic-string';
import isReference from 'is-reference';
import { parseExpressionAt } from 'acorn';
import annotateWithScopes from '../../utils/annotateWithScopes';
import { walk } from 'estree-walker';
import deindent from '../../utils/deindent'; import deindent from '../../utils/deindent';
import { stringify, escape } from '../../utils/stringify'; import { stringify, escape } from '../../utils/stringify';
import CodeBuilder from '../../utils/CodeBuilder'; import CodeBuilder from '../../utils/CodeBuilder';
import globalWhitelist from '../../utils/globalWhitelist'; import globalWhitelist from '../../utils/globalWhitelist';
import reservedNames from '../../utils/reservedNames';
import Compiler from '../Compiler'; import Compiler from '../Compiler';
import Stylesheet from '../../css/Stylesheet'; import Stylesheet from '../../css/Stylesheet';
import Stats from '../../Stats'; import Stats from '../../Stats';
import Block from './Block'; import Block from './Block';
import { test } from '../../config'; import { Ast, CompileOptions } from '../../interfaces';
import { Ast, CompileOptions, Node } from '../../interfaces';
export class DomTarget { export class DomTarget {
blocks: (Block|string)[]; blocks: (Block|string)[];

@ -0,0 +1,69 @@
import { assign } from '../shared';
import Stats from '../Stats';
import parse from '../parse/index';
import Stylesheet from '../css/Stylesheet';
import validate from '../validate';
import generate from './dom/index';
import generateSSR from './ssr/index';
import { CompileOptions, Warning, Ast } from '../interfaces';
function normalize_options(options: CompileOptions): CompileOptions {
let normalized = assign({ generate: 'dom' }, options);
const { onwarn, onerror } = normalized;
normalized.onwarn = onwarn
? (warning: Warning) => onwarn(warning, default_onwarn)
: default_onwarn;
normalized.onerror = onerror
? (error: Error) => onerror(error, default_onerror)
: default_onerror;
return normalized;
}
function default_onwarn({ start, message }: Warning) {
if (start) {
console.warn(`(${start.line}:${start.column}) ${message}`);
} else {
console.warn(message);
}
}
function default_onerror(error: Error) {
throw error;
}
export default function compile(source: string, _options: CompileOptions) {
const options = normalize_options(_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);
}

@ -1,149 +1,10 @@
import parse from './parse/index'; import compile from './compile/index';
import validate from './validate/index'; import { CompileOptions } from './interfaces';
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__'; export function create(source: string, options: CompileOptions = {}) {
options.format = 'eval';
function normalizeOptions(options: CompileOptions): CompileOptions { const compiled = compile(source, options);
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) { if (!compiled || !compiled.js.code) {
return; return;
@ -152,8 +13,8 @@ function create(source: string, _options: CompileOptions = {}) {
try { try {
return (new Function(`return ${compiled.js.code}`))(); return (new Function(`return ${compiled.js.code}`))();
} catch (err) { } catch (err) {
if (_options.onerror) { if (options.onerror) {
_options.onerror(err); options.onerror(err);
return; return;
} else { } else {
throw err; throw err;
@ -161,4 +22,7 @@ function create(source: string, _options: CompileOptions = {}) {
} }
} }
export { parse, create, compile, version as VERSION }; export { default as compile } from './compile/index';
export { default as parse } from './parse/index';
export { default as preprocess } from './preprocess/index';
export const VERSION = '__VERSION__';

@ -1,5 +1,3 @@
import {SourceMap} from 'magic-string';
export interface Node { export interface Node {
start: number; start: number;
end: number; end: number;
@ -67,7 +65,7 @@ export interface CompileOptions {
// to remove in v3 // to remove in v3
skipIntroByDefault?: boolean; skipIntroByDefault?: boolean;
nestedTransitions: boolean; nestedTransitions?: boolean;
} }
export interface GenerateOptions { export interface GenerateOptions {
@ -92,15 +90,6 @@ export interface CustomElementOptions {
props?: string[]; props?: string[];
} }
export interface PreprocessOptions {
markup?: (options: {content: string, filename: string}) => { code: string, map?: SourceMap | string };
style?: Preprocessor;
script?: Preprocessor;
filename?: string
}
export type Preprocessor = (options: {content: string, attributes: Record<string, string | boolean>, filename?: string}) => { code: string, map?: SourceMap | string };
export interface AppendTarget { export interface AppendTarget {
slots: Record<string, string>; slots: Record<string, string>;
slotStack: string[] slotStack: string[]

@ -1,17 +1,15 @@
import { isIdentifierStart, isIdentifierChar } from 'acorn'; import { isIdentifierStart, isIdentifierChar } from 'acorn';
import { locate, Location } from 'locate-character';
import fragment from './state/fragment'; import fragment from './state/fragment';
import { whitespace } from '../utils/patterns'; import { whitespace } from '../utils/patterns';
import { trimStart, trimEnd } from '../utils/trim';
import reservedNames from '../utils/reservedNames'; import reservedNames from '../utils/reservedNames';
import fullCharCodeAt from '../utils/fullCharCodeAt'; import fullCharCodeAt from '../utils/fullCharCodeAt';
import { Node, Ast } from '../interfaces'; import { Node, Ast, CustomElementOptions } from '../interfaces';
import error from '../utils/error'; import error from '../utils/error';
interface ParserOptions { interface ParserOptions {
filename?: string; filename?: string;
bind?: boolean; bind?: boolean;
customElement?: boolean; customElement?: CustomElementOptions | true;
} }
type ParserState = (parser: Parser) => (ParserState | void); type ParserState = (parser: Parser) => (ParserState | void);
@ -19,7 +17,7 @@ type ParserState = (parser: Parser) => (ParserState | void);
export class Parser { export class Parser {
readonly template: string; readonly template: string;
readonly filename?: string; readonly filename?: string;
readonly customElement: boolean; readonly customElement: CustomElementOptions | true;
index: number; index: number;
stack: Array<Node>; stack: Array<Node>;

@ -0,0 +1,100 @@
import { SourceMap } from 'magic-string';
export interface PreprocessOptions {
markup?: (options: {
content: string,
filename: string
}) => { code: string, map?: SourceMap | string };
style?: Preprocessor;
script?: Preprocessor;
filename?: string
}
export type Preprocessor = (options: {
content: string,
attributes: Record<string, string | boolean>,
filename?: string
}) => { code: string, map?: SourceMap | string };
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 default 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;
}
};
}

@ -1,5 +1,5 @@
import assert from 'assert'; import assert from 'assert';
import {svelte} from '../helpers.js'; import { svelte } from '../helpers.js';
describe('preprocess', () => { describe('preprocess', () => {
it('preprocesses entire component', () => { it('preprocesses entire component', () => {

Loading…
Cancel
Save