merge master -> composition

pull/1998/head
Richard Harris 7 years ago
commit ac4e1235b1

@ -33,7 +33,6 @@
"plugin:import/errors",
"plugin:import/warnings"
],
"plugins": ["svelte3"],
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"

1
.gitignore vendored

@ -2,6 +2,7 @@
.nyc_output
node_modules
*.map
/src/compile/internal-exports.ts
/cli/
/compiler.js
/index.js

3381
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -23,18 +23,17 @@
"scripts": {
"test": "mocha --opts mocha.opts",
"quicktest": "mocha --opts mocha.opts",
"precoverage": "export COVERAGE=true && nyc mocha --opts mocha.coverage.opts",
"coverage": "nyc report --reporter=text-lcov > coverage.lcov",
"precoverage": "c8 mocha --opts mocha.coverage.opts",
"coverage": "c8 report --reporter=text-lcov > coverage.lcov && c8 report --reporter=html",
"codecov": "codecov",
"precodecov": "npm run coverage",
"lint": "eslint src test/*.js",
"build": "rollup -c",
"prepare": "npm run build",
"dev": "rollup -c -w",
"dev": "rollup -cw",
"pretest": "npm run build",
"posttest": "agadoo src/internal/index.js",
"prepublishOnly": "npm run lint && npm test",
"prettier": "prettier --write \"src/**/*.ts\""
"prepublishOnly": "export PUBLISH=true && npm run lint && npm test"
},
"repository": {
"type": "git",
@ -58,28 +57,28 @@
"acorn": "^6.0.5",
"acorn-dynamic-import": "^4.0.0",
"agadoo": "^1.0.1",
"c8": "^3.4.0",
"codecov": "^3.0.0",
"css-tree": "1.0.0-alpha22",
"eslint": "^5.3.0",
"eslint-plugin-html": "^4.0.3",
"eslint-plugin-html": "^5.0.0",
"eslint-plugin-import": "^2.11.0",
"estree-walker": "^0.6.0",
"is-reference": "^1.1.1",
"jsdom": "^11.8.0",
"jsdom": "^12.2.0",
"kleur": "^3.0.0",
"locate-character": "^2.0.5",
"magic-string": "^0.25.0",
"mocha": "^5.2.0",
"nightmare": "^3.0.1",
"node-resolve": "^1.3.3",
"nyc": "^12.0.2",
"prettier": "^1.12.1",
"rollup": "^0.63.5",
"rollup": "^1.1.2",
"rollup-plugin-commonjs": "^9.1.0",
"rollup-plugin-json": "^3.0.0",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-replace": "^2.0.0",
"rollup-plugin-typescript": "^0.8.1",
"rollup-plugin-sucrase": "^2.0.0",
"rollup-plugin-typescript": "^1.0.0",
"rollup-plugin-virtual": "^1.0.1",
"rollup-watch": "^4.3.1",
"sade": "^1.4.0",
@ -88,7 +87,7 @@
"source-map": "0.6",
"source-map-support": "^0.5.4",
"tiny-glob": "^0.2.1",
"ts-node": "^7.0.0",
"ts-node": "^8.0.2",
"tslib": "^1.8.0",
"typescript": "^3.0.1"
},

@ -1,11 +1,41 @@
import fs from 'fs';
import replace from 'rollup-plugin-replace';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import sucrase from 'rollup-plugin-sucrase';
import typescript from 'rollup-plugin-typescript';
import pkg from './package.json';
const is_publish = !!process.env.PUBLISH;
export default [
/* internal.[m]js */
{
input: `src/internal/index.js`,
output: [
{
file: `internal.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
},
{
file: `internal.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
}
],
external: id => id.startsWith('svelte/'),
plugins: [{
generateBundle(options, bundle) {
const mod = bundle['internal.mjs'];
if (mod) {
fs.writeFileSync('src/compile/internal-exports.ts', `// This file is automatically generated\nexport default new Set(${JSON.stringify(mod.exports)});`);
}
}
}]
},
/* compiler.js */
{
input: 'src/index.ts',
@ -13,21 +43,32 @@ export default [
replace({
__VERSION__: pkg.version
}),
resolve(),
commonjs(),
resolve({
extensions: ['.js', '.ts']
}),
commonjs({
include: ['node_modules/**']
}),
json(),
typescript({
include: 'src/**',
exclude: 'src/internal/**',
typescript: require('typescript')
})
is_publish
? typescript({
include: 'src/**',
exclude: 'src/internal/**',
typescript: require('typescript')
})
: sucrase({
transforms: ['typescript']
})
],
output: {
file: 'compiler.js',
format: 'umd',
format: is_publish ? 'umd' : 'cjs',
name: 'svelte',
sourcemap: true
}
sourcemap: true,
},
external: is_publish
? []
: id => id === 'acorn' || id === 'magic-string' || id.startsWith('css-tree')
},
/* cli/*.js */
@ -48,27 +89,26 @@ export default [
typescript({
typescript: require('typescript')
})
],
experimentalCodeSplitting: true
]
},
/* internal.[m]js, motion.mjs */
...['internal', 'motion'].map(name => ({
input: `src/${name}/index.js`,
/* motion.mjs */
{
input: `src/motion/index.js`,
output: [
{
file: `${name}.mjs`,
file: `motion.mjs`,
format: 'esm',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
},
{
file: `${name}.js`,
file: `motion.js`,
format: 'cjs',
paths: id => id.startsWith('svelte/') && id.replace('svelte', '.')
}
],
external: id => id.startsWith('svelte/')
})),
},
// everything else
...['index', 'store', 'easing', 'transition'].map(name => ({

@ -10,7 +10,7 @@ import { createScopes, extractNames, Scope } from '../utils/annotateWithScopes';
import Stylesheet from './css/Stylesheet';
import { test } from '../config';
import Fragment from './nodes/Fragment';
import * as internal from '../internal/index';
import internal_exports from './internal-exports';
import { Node, Ast, CompileOptions } from '../interfaces';
import error from '../utils/error';
import getCodeFrame from '../utils/getCodeFrame';
@ -160,9 +160,12 @@ export default class Component {
: this.name;
this.walk_module_js();
this.walk_instance_js();
this.walk_instance_js_pre_template();
this.fragment = new Fragment(this, ast.html);
this.walk_instance_js_post_template();
if (!options.customElement) this.stylesheet.reify();
this.stylesheet.warnOnUnusedSelectors(stats);
@ -212,8 +215,8 @@ export default class Component {
// TODO use same regex for both
result = result.replace(options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
if (sigil === '@') {
if (name in internal) {
if (options.dev && `${name}Dev` in internal) name = `${name}Dev`;
if (internal_exports.has(name)) {
if (options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
helpers.add(name);
}
@ -510,7 +513,7 @@ export default class Component {
this.module_javascript = this.extract_javascript(script);
}
walk_instance_js() {
walk_instance_js_pre_template() {
const script = this.instance_script;
if (!script) return;
@ -545,6 +548,12 @@ export default class Component {
this.track_mutations();
this.extract_imports_and_exports(script.content, this.imports, this.props);
}
walk_instance_js_post_template() {
const script = this.instance_script;
if (!script) return;
this.hoist_instance_declarations();
this.extract_reactive_declarations();
this.extract_reactive_store_references();
@ -756,12 +765,13 @@ export default class Component {
// hoistable functions. TODO others?
const { hoistable_names, hoistable_nodes, imported_declarations, instance_scope: scope } = this;
const template_scope = this.fragment.scope;
const top_level_function_declarations = new Map();
this.instance_script.content.body.forEach(node => {
if (node.type === 'VariableDeclaration') {
if (node.declarations.every(d => d.init && d.init.type === 'Literal' && !this.mutable_props.has(d.id.name))) {
if (node.declarations.every(d => d.init && d.init.type === 'Literal' && !this.mutable_props.has(d.id.name) && !template_scope.containsMutable([d.id.name]))) {
node.declarations.forEach(d => {
hoistable_names.add(d.id.name);
});

@ -42,12 +42,6 @@ export default class Wrapper {
if (this.parent) this.parent.cannotUseInnerHTML();
}
// TODO do we still need equivalent method on Node?
findNearest(pattern) {
if (pattern.test(this.node.type)) return this;
return this.parent && this.parent.findNearest(pattern);
}
getOrCreateAnchor(block: Block, parentNode: string, parentNodes: string) {
// TODO use this in EachBlock and IfBlock — tricky because
// children need to be created first
@ -81,8 +75,4 @@ export default class Wrapper {
this.node.type === 'MustacheTag'
);
}
render(block: Block, parentNode: string, parentNodes: string) {
throw new Error(`render method not implemented by subclass ${this.node.type}`);
}
}

@ -7,11 +7,6 @@ export function assign(tar, src) {
return tar;
}
export function assignTrue(tar, src) {
for (var k in src) tar[k] = 1;
return tar;
}
export function isPromise(value) {
return value && typeof value.then === 'function';
}
@ -22,12 +17,6 @@ export function addLoc(element, file, line, column, char) {
};
}
export function exclude(src, prop) {
const tar = {};
for (const k in src) k === prop || (tar[k] = src[k]);
return tar;
}
export function run(fn) {
return fn();
}

@ -199,10 +199,6 @@ export class Parser {
return this.template.slice(start);
}
remaining() {
return this.template.slice(this.index);
}
requireWhitespace() {
if (!whitespace.test(this.template[this.index])) {
this.error({

@ -41,18 +41,10 @@ export default class CodeBuilder {
if (line && !whitespace.test(line)) this.current.children.push(this.last = { type: 'line', line });
}
addLineAtStart(line: string) {
if (line && !whitespace.test(line)) this.root.children.unshift({ type: 'line', line });
}
addBlock(block: string) {
if (block && !whitespace.test(block)) this.current.children.push(this.last = { type: 'line', line: block, block: true });
}
addBlockAtStart(block: string) {
if (block && !whitespace.test(block)) this.root.children.unshift({ type: 'line', line: block, block: true });
}
isEmpty() { return !findLine(this.root); }
pushCondition(condition: string) {

@ -124,67 +124,4 @@ describe('CodeBuilder', () => {
`
);
});
it('adds a line at start', () => {
const builder = new CodeBuilder();
builder.addLine('// second');
builder.addLineAtStart('// first');
assert.equal(
builder.toString(),
deindent`
// first
// second
`
);
});
it('adds a line at start before a block', () => {
const builder = new CodeBuilder();
builder.addBlock('// second');
builder.addLineAtStart('// first');
assert.equal(
builder.toString(),
deindent`
// first
// second
`
);
});
it('adds a block at start', () => {
const builder = new CodeBuilder();
builder.addLine('// second');
builder.addBlockAtStart('// first');
assert.equal(
builder.toString(),
deindent`
// first
// second
`
);
});
it('adds a block at start before a block', () => {
const builder = new CodeBuilder();
builder.addBlock('// second');
builder.addBlockAtStart('// first');
assert.equal(
builder.toString(),
deindent`
// first
// second
`
);
});
});

@ -10,11 +10,11 @@ export default async function replaceAsync(
replacements.push(
func(...args).then(
res =>
<Replacement>{
<Replacement>({
offset: args[args.length - 2],
length: args[0].length,
replacement: res,
}
})
)
);
return '';

@ -89,8 +89,8 @@ describe('custom-elements', function() {
]
})
.then(bundle => bundle.generate({ format: 'iife', name: 'test' }))
.then(generated => {
bundle = generated.code;
.then(result => {
bundle = result.output[0].code;
const nightmare = new Nightmare({ show: false });

@ -11,7 +11,7 @@ function create_fragment(ctx) {
text1 = createText("\n\n");
p = createElement("p");
text2 = createText("x: ");
text3 = createText(x);
text3 = createText(ctx.x);
dispose = addListener(button, "click", ctx.click_handler);
},
@ -25,7 +25,7 @@ function create_fragment(ctx) {
p(changed, ctx) {
if (changed.x) {
setData(text3, x);
setData(text3, ctx.x);
}
},
@ -44,15 +44,14 @@ function create_fragment(ctx) {
};
}
let x = 0;
function instance($$self, $$props, $$invalidate) {
let x = 0;
function click_handler() {
if (true) { x += 1; $$invalidate('x', x); }
}
return { click_handler };
return { x, click_handler };
}
class SvelteComponent extends SvelteComponent_1 {

@ -248,7 +248,7 @@ describe("runtime", () => {
});
return eval(
`(function () { ${result.code}; return App; }())`
`(function () { ${result.output[0].code}; return App; }())`
);
}

@ -0,0 +1,5 @@
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">{count}</button>

@ -0,0 +1,14 @@
export default {
async test({ assert, target }) {
const btns = target.querySelectorAll('button');
const event = new window.MouseEvent('click');
await btns[0].dispatchEvent(event);
await btns[0].dispatchEvent(event);
await btns[1].dispatchEvent(event);
await btns[1].dispatchEvent(event);
await btns[1].dispatchEvent(event);
assert.equal(btns[1].innerHTML, '3');
}
};

@ -0,0 +1,6 @@
<script>
import Widget from './Widget.html';
</script>
<Widget />
<Widget />
Loading…
Cancel
Save