pull/3539/head
Richard Harris 6 years ago
parent 8addd2313e
commit 0bcbe965dc

8
package-lock.json generated

@ -507,13 +507,13 @@
"dev": true
},
"code-red": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.6.tgz",
"integrity": "sha512-nsAPEQ+o1Z8UyIbOaOqfTxWHaA4JarPH7OBxDPmqAkkRvATvc2j7khlaAtsXnFreH2fTwekmZed4GlHvY3hQiw==",
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/code-red/-/code-red-0.0.7.tgz",
"integrity": "sha512-UgcXT2tiYOFe5MF6FYeP1s+XKvd5XFlm+p+By6/Q/0/NwgT2ZqkR32liLhosDivtO1vvtLTg51LN1LUW5AYSEw==",
"dev": true,
"requires": {
"acorn": "^7.0.0",
"astring": "github:Rich-Harris/astring#generic-handler",
"astring": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d",
"estree-walker": "^0.6.1",
"is-reference": "^1.1.3",
"periscopic": "^1.0.0",

@ -63,7 +63,7 @@
"acorn": "^7.0.0",
"agadoo": "^1.0.1",
"c8": "^5.0.1",
"code-red": "0.0.6",
"code-red": "0.0.7",
"codecov": "^3.5.0",
"css-tree": "1.0.0-alpha22",
"eslint": "^6.3.0",

@ -1,4 +1,4 @@
import MagicString, { Bundle } from 'magic-string';
import MagicString from 'magic-string';
// @ts-ignore
import { walk, childKeys } from 'estree-walker';
import { getLocator } from 'locate-character';
@ -333,8 +333,16 @@ export default class Component {
// }
// );
const printed = print({ type: 'Program', body: result } as any);
console.log(printed);
const program: any = { type: 'Program', body: result };
walk(program, {
enter: (node) => {
if (node.type === 'Identifier' && node.name[0] === '@') {
const alias = this.helper(node.name.slice(1));
node.name = alias.name;
}
}
});
const referenced_globals = Array.from(
this.globals,
@ -348,10 +356,10 @@ export default class Component {
alias,
}));
const module = create_module(
printed.code,
create_module(
program,
format,
name.name,
name,
banner,
compile_options.sveltePath,
imported_helpers,
@ -362,61 +370,14 @@ export default class Component {
.map(variable => ({
name: variable.name,
as: variable.export_name,
})),
this.source
}))
);
const parts = module.split('✂]');
const final_chunk = parts.pop();
const compiled = new Bundle({ separator: '' });
function add_string(str: string) {
compiled.addSource({
content: new MagicString(str),
});
}
const { filename } = compile_options;
// special case — the source file doesn't actually get used anywhere. we need
// to add an empty file to populate map.sources and map.sourcesContent
if (!parts.length) {
compiled.addSource({
filename,
content: new MagicString(this.source).remove(0, this.source.length),
});
}
const pattern = /\[✂(\d+)-(\d+)$/;
parts.forEach((str: string) => {
const chunk = str.replace(pattern, '');
if (chunk) add_string(chunk);
const match = pattern.exec(str);
const snippet = this.code.snip(+match[1], +match[2]);
compiled.addSource({
filename,
content: snippet,
});
});
add_string(final_chunk);
css = compile_options.customElement
? { code: null, map: null }
: this.stylesheet.render(compile_options.cssOutputFilename, true);
js = {
code: compiled.toString(),
map: compiled.generateMap({
includeContent: true,
file: compile_options.outputFilename,
}),
};
js = print(program);
}
return {

@ -1,7 +1,6 @@
import deindent from './utils/deindent';
import list from '../utils/list';
import { ModuleFormat, Node, Identifier } from '../interfaces';
import { stringify_props } from './utils/stringify_props';
import { b, x } from 'code-red';
const wrappers = { esm, cjs };
@ -11,24 +10,23 @@ interface Export {
}
export default function create_module(
code: string,
program: any,
format: ModuleFormat,
name: string,
name: Identifier,
banner: string,
sveltePath = 'svelte',
helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>,
imports: Node[],
module_exports: Export[],
source: string
): string {
module_exports: Export[]
) {
const internal_path = `${sveltePath}/internal`;
if (format === 'esm') {
return esm(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, source);
return esm(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
}
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
if (format === 'cjs') return cjs(program, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
@ -40,54 +38,75 @@ function edit_source(source, sveltePath) {
}
function esm(
code: string,
name: string,
banner: string,
program: any,
name: Identifier,
_banner: string,
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: Identifier }>,
globals: Array<{ name: string; alias: Identifier }>,
imports: Node[],
module_exports: Export[],
source: string
module_exports: Export[]
) {
const internal_imports = helpers.length > 0 && (
`import ${stringify_props(helpers.map(h => h.name === h.alias.name ? h.name : `${h.name} as ${h.alias}`).sort())} from ${JSON.stringify(internal_path)};`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);
const user_imports = imports.length > 0 && (
imports
.map((declaration: Node) => {
const import_source = edit_source(declaration.source.value, sveltePath);
return (
source.slice(declaration.start, declaration.source.start) +
JSON.stringify(import_source) +
source.slice(declaration.source.end, declaration.end)
);
})
.join('\n')
);
return deindent`
${banner}
${internal_imports}
const import_declaration = {
type: 'ImportDeclaration',
specifiers: helpers.map(h => ({
type: 'ImportSpecifier',
local: h.alias,
imported: { type: 'Identifier', name: h.name }
})),
source: { type: 'Literal', value: internal_path }
}
const internal_globals = globals.length > 0 &&{
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
id: {
type: 'ObjectPattern',
properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({
type: 'Property',
method: false,
shorthand: false,
computed: false,
key: { type: 'Identifier', name: g.name },
value: { type: 'Identifier', name: g.alias }
}))
},
init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias }
}]
};
// edit user imports
imports.forEach(node => {
node.source.value = edit_source(node.source.value, sveltePath);
});
const exports = module_exports.length > 0 && {
type: 'ExportNamedDeclaration',
specifiers: module_exports.map(x => ({
type: 'Specifier',
local: { type: 'Identifier', name: x.name },
exported: { type: 'Identifier', name: x.as }
}))
};
program.body = b`
${import_declaration}
${internal_globals}
${user_imports}
${imports}
${code}
${program.body}
export default ${name};
${module_exports.length > 0 && `export { ${module_exports.map(e => e.name === e.as ? e.name : `${e.name} as ${e.as}`).join(', ')} };`}`;
${exports}
`;
}
function cjs(
code: string,
name: string,
banner: string,
program: any,
name: Identifier,
_banner: string,
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: Identifier }>,
@ -95,52 +114,80 @@ function cjs(
imports: Node[],
module_exports: Export[]
) {
const declarations = helpers.map(h => `${h.alias.name === h.name ? h.name : `${h.name}: ${h.alias}`}`).sort();
const internal_imports = helpers.length > 0 && (
`const ${stringify_props(declarations)} = require(${JSON.stringify(internal_path)});\n`
);
const internal_globals = globals.length > 0 && (
`const ${stringify_props(globals.map(g => `${g.name}: ${g.alias}`).sort())} = ${helpers.find(({ name }) => name === 'globals').alias};`
);
const requires = imports.map(node => {
let lhs;
if (node.specifiers[0].type === 'ImportNamespaceSpecifier') {
lhs = node.specifiers[0].local.name;
} else {
const properties = node.specifiers.map(s => {
if (s.type === 'ImportDefaultSpecifier') {
return `default: ${s.local.name}`;
}
return s.local.name === s.imported.name
? s.local.name
: `${s.imported.name}: ${s.local.name}`;
});
lhs = `{ ${properties.join(', ')} }`;
}
const source = edit_source(node.source.value, sveltePath);
return `const ${lhs} = require("${source}");`;
});
const exports = [`exports.default = ${name};`].concat(
module_exports.map(x => `exports.${x.as} = ${x.name};`)
);
return deindent`
${banner}
const internal_requires = {
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: {
type: 'ObjectPattern',
properties: helpers.sort((a, b) => a.name < b.name ? -1 : 1).map(h => ({
type: 'Property',
method: false,
shorthand: false,
computed: false,
key: { type: 'Identifier', name: h.name },
value: h.alias,
kind: 'init'
}))
},
init: x`require("${internal_path}")`
}]
};
const internal_globals = globals.length > 0 &&{
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: {
type: 'ObjectPattern',
properties: globals.sort((a, b) => a.name < b.name ? -1 : 1).map(g => ({
type: 'Property',
method: false,
shorthand: false,
computed: false,
key: { type: 'Identifier', name: g.name },
value: { type: 'Identifier', name: g.alias }
}))
},
init: { type: 'Identifier', name: helpers.find(({ name }) => name === 'globals').alias }
}]
};
const user_requires = imports.map(node => ({
type: 'VariableDeclaration',
kind: 'const',
declarations: [{
type: 'VariableDeclarator',
id: node.specifiers[0].type === 'ImportNamespaceSpecifier'
? { type: 'Identifier', name: node.specifiers[0].local.name }
: {
type: 'ObjectPattern',
properties: node.specifiers.map(s => ({
type: 'Property',
method: false,
shorthand: false,
computed: false,
key: s.imported || { type: 'Identifier', name: 'default' },
value: s.local
}))
},
init: x`require("${edit_source(node.source.value, sveltePath)}")`
}]
}));
const exports = module_exports.map(x => b`exports.${{ type: 'Identifier', name: x.as }} = ${{ type: 'Identifier', name: x.name }};`);
program.body = b`
"use strict";
${internal_requires}
// ${internal_globals}
${user_requires}
${internal_imports}
${internal_globals}
${requires}
${code}
${program.body}
${exports}`;
exports.default = ${name};
${exports}
`;
}

@ -255,7 +255,7 @@ export default class Block {
const properties: Record<string, any> = {};
const noop = x`noop`;
const noop = x`@noop`;
properties.key = key
properties.first = this.first;
@ -296,7 +296,7 @@ export default class Block {
properties.mount = noop;
} else {
properties.mount = x`function mount(#target, anchor) {
//${this.chunks.mount}
${this.chunks.mount}
}`;
}
@ -354,21 +354,22 @@ export default class Block {
}
const return_value: any = x`{
// key: ${properties.key},
// first: ${properties.first},
// c: ${properties.create},
// l: ${properties.claim},
// h: ${properties.hydrate},
key: ${properties.key},
first: ${properties.first},
c: ${properties.create},
l: ${properties.claim},
h: ${properties.hydrate},
m: ${properties.mount},
// p: ${properties.update},
// r: ${properties.measure},
// f: ${properties.fix},
// a: ${properties.animate},
// i: ${properties.intro},
// o: ${properties.outro},
// d: ${properties.destroy}
p: ${properties.update},
r: ${properties.measure},
f: ${properties.fix},
a: ${properties.animate},
i: ${properties.intro},
o: ${properties.outro},
d: ${properties.destroy}
}`;
// TODO should code-red do this automatically? probably
return_value.properties = return_value.properties.filter(prop => prop.value);
/* eslint-disable @typescript-eslint/indent,indent */

@ -390,7 +390,12 @@ export default function dom(
`);
}
const prop_names = x`[${props.map(v => ({ type: 'Literal', value: v.export_name }))}]`;
const prop_names = x`[]`;
// TODO find a more idiomatic way of doing this
props.forEach(v => {
(prop_names as any).elements.push({ type: 'Literal', value: v.export_name });
});
if (options.customElement) {
body.push(b`
@ -453,5 +458,18 @@ export default function dom(
`);
}
return body;
return flatten(body, []);
}
function flatten(nodes: any[], target: any[]) {
for (let i = 0; i < nodes.length; i += 1) {
const node = nodes[i];
if (Array.isArray(node)) {
flatten(node, target);
} else {
target.push(node);
}
}
return target;
}

@ -3,7 +3,7 @@ import * as path from "path";
import * as fs from "fs";
import { rollup } from 'rollup';
import * as virtual from 'rollup-plugin-virtual';
import { clear_loops, flush, set_now, set_raf } from "../../internal";
import { clear_loops, flush, set_now, set_raf, component_subscribe } from "../../internal";
import {
showOutput,
@ -33,9 +33,7 @@ describe("runtime", () => {
require.extensions[".svelte"] = function(module, filename) {
const options = Object.assign({
filename,
format: 'cjs',
sveltePath
filename
}, compileOptions);
const { js: { code } } = compile(fs.readFileSync(filename, "utf-8"), options);
@ -72,6 +70,7 @@ describe("runtime", () => {
const cwd = path.resolve(`test/runtime/samples/${dir}`);
compileOptions = config.compileOptions || {};
compileOptions.format = 'cjs';
compileOptions.sveltePath = sveltePath;
compileOptions.hydratable = hydrate;
compileOptions.immutable = config.immutable;

@ -1,5 +1,6 @@
export default {
solo: 1,
show: 1,
html: '<h1>Hello world!</h1>'
};
Loading…
Cancel
Save