a few more tests

pull/1864/head
Rich Harris 7 years ago
parent e272736d06
commit 80ea0572e2

@ -10,7 +10,7 @@ import namespaces from '../utils/namespaces';
import { removeNode } from '../utils/removeNode';
import nodeToString from '../utils/nodeToString';
import wrapModule from './wrapModule';
import { createScopes } from '../utils/annotateWithScopes';
import { createScopes, extractNames } from '../utils/annotateWithScopes';
import getName from '../utils/getName';
import Stylesheet from './css/Stylesheet';
import { test } from '../config';
@ -92,6 +92,7 @@ function increaseIndentation(
// the wrong idea about the shape of each/if blocks
childKeys.EachBlock = childKeys.IfBlock = ['children', 'else'];
childKeys.Attribute = ['value'];
childKeys.ExportNamedDeclaration = ['declaration', 'specifiers'];
export default class Component {
stats: Stats;
@ -104,7 +105,6 @@ export default class Component {
customElement: CustomElementOptions;
tag: string;
props: string[];
properties: Map<string, Node>;
@ -123,7 +123,7 @@ export default class Component {
hasComponents: boolean;
computations: Computation[];
templateProperties: Record<string, Node>;
javascript: [string, string];
javascript: string;
used: {
components: Set<string>;
@ -135,6 +135,8 @@ export default class Component {
};
declarations: string[];
exports: Array<{ name: string, as: string }>;
props: string[];
refCallees: Node[];
@ -193,6 +195,7 @@ export default class Component {
};
this.declarations = [];
this.exports = [];
this.refs = new Set();
this.refCallees = [];
@ -509,10 +512,15 @@ export default class Component {
const { code, source, imports } = this;
const indentationLevel = getIndentationLevel(source, js.content.body[0].start);
const indentExclusionRanges = getIndentExclusionRanges(js.content);
const indent = code.getIndentString();
code.indent(indent, {
exclude: [
[0, js.content.start],
[js.content.end, source.length]
]
});
const { scope, globals } = createScopes(js.content);
let { scope, map, globals } = createScopes(js.content);
scope.declarations.forEach(name => {
this.userVars.add(name);
@ -533,6 +541,30 @@ export default class Component {
})
}
if (node.type === 'ExportNamedDeclaration') {
if (node.declaration) {
if (node.declaration.type === 'VariableDeclaration') {
node.declaration.declarations.forEach(declarator => {
extractNames(declarator.id).forEach(name => {
this.exports.push({ name, as: name });
});
});
} else {
const { name } = node.declaration.id;
this.exports.push({ name, as: name });
}
code.remove(node.start, node.declaration.start);
} else {
node.specifiers.forEach(specifier => {
this.exports.push({
name: specifier.local.name,
as: specifier.exported.name
});
});
}
}
// imports need to be hoisted out of the IIFE
// TODO hoist other stuff where possible
else if (node.type === 'ImportDeclaration') {
@ -545,20 +577,32 @@ export default class Component {
}
});
walk(js.content, {
enter(node) {
if (map.has(node)) {
scope = map.get(node);
}
if (node.type === 'AssignmentExpression') {
const { name } = flattenReference(node.left);
code.appendLeft(node.end, `; __make_dirty('${name}')`);
}
},
leave(node) {
if (map.has(node)) {
scope = scope.parent;
}
}
});
let a = js.content.start;
while (/\s/.test(source[a])) a += 1;
let b = js.content.end;
while (/\s/.test(source[b - 1])) b -= 1;
this.javascript = this.defaultExport
? [
a !== this.defaultExport.start ? `[✂${a}-${this.defaultExport.start}✂]` : '',
b !== this.defaultExport.end ?`[✂${this.defaultExport.end}-${b}✂]` : ''
]
: [
a !== b ? `[✂${a}-${b}✂]` : '',
''
];
this.javascript = a !== b ? `[✂${a}-${b}✂]` : '';
}
}

@ -13,7 +13,6 @@ export default function dom(
const format = options.format || 'es';
const {
computations,
name,
templateProperties
} = component;
@ -110,9 +109,16 @@ export default function dom(
} else {
builder.addBlock(deindent`
class ${name} extends @SvelteComponent {
__init() {
__init(__set_inject_props, __set_inject_refs, __make_dirty) {
${component.javascript}
__set_inject_props(props => {
// TODO only do this for export let|var
${(component.exports.map(name =>
`if ('${name.as}' in props) ${name.as} = props.${name.as};`
))}
});
return () => ({ ${(component.declarations).join(', ')} });
}

@ -1,9 +1,11 @@
import { schedule_update } from './scheduler';
import { schedule_update, flush } from './scheduler';
export class SvelteComponent {
constructor(options) {
this.__get_state = this.__init(
fn => this.__inject_props = fn
fn => this.__inject_props = fn,
fn => this.__inject_refs = fn,
key => this.__make_dirty(key)
);
this.__dirty = null;
@ -14,6 +16,7 @@ export class SvelteComponent {
if (options.target) {
this.__mount(options.target);
flush();
}
}
@ -25,10 +28,12 @@ export class SvelteComponent {
this.__destroy(true);
}
__make_dirty() {
if (this.__dirty) return;
this.__dirty = {};
__make_dirty(key) {
if (!this.__dirty) {
schedule_update(this);
this.__dirty = {};
}
this.__dirty[key] = true;
}
__mount(target, anchor) {
@ -39,8 +44,7 @@ export class SvelteComponent {
__set(key, value) {
this.__inject_props({ [key]: value });
this.__make_dirty();
this.__dirty[key] = true;
this.__make_dirty(key);
}
__update() {

@ -398,7 +398,7 @@ function readAttribute(parser: Parser, uniqueNames: Set<string>) {
end,
type,
name,
expression: value[0].expression
expression: value[0] && value[0].expression
};
}

@ -83,7 +83,7 @@ export class Scope {
}
}
function extractNames(param: Node) {
export function extractNames(param: Node) {
const names: string[] = [];
extractors[param.type](names, param);
return names;

@ -46,16 +46,18 @@ describe.only("runtime", () => {
const failed = new Set();
function runTest(dir, shared, hydrate) {
function runTest(dir, internal, hydrate) {
if (dir[0] === ".") return;
const { flush } = require(internal);
const config = loadConfig(`./runtime/samples/${dir}/_config.js`);
if (config.solo && process.env.CI) {
throw new Error("Forgot to remove `solo: true` from test");
}
(config.skip ? it.skip : config.solo ? it.only : it)(`${dir} (${shared ? 'shared' : 'inline'} helpers${hydrate ? ', hydration' : ''})`, () => {
(config.skip ? it.skip : config.solo ? it.only : it)(`${dir} ${hydrate ? '(with hydration)' : ''}`, () => {
if (failed.has(dir)) {
// this makes debugging easier, by only printing compiled output once
throw new Error('skipping test, already failed');
@ -67,7 +69,7 @@ describe.only("runtime", () => {
global.document.title = '';
compileOptions = config.compileOptions || {};
compileOptions.shared = shared;
compileOptions.shared = internal;
compileOptions.hydratable = hydrate;
compileOptions.store = !!config.store;
compileOptions.immutable = config.immutable;
@ -114,7 +116,7 @@ describe.only("runtime", () => {
try {
SvelteComponent = require(`./samples/${dir}/main.html`);
} catch (err) {
showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile); // eslint-disable-line no-console
showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile); // eslint-disable-line no-console
throw err;
}
@ -134,8 +136,7 @@ describe.only("runtime", () => {
const options = Object.assign({}, {
target,
hydrate,
data: config.data,
store: (config.store !== true && config.store),
props: config.props,
intro: config.intro
}, config.options || {});
@ -178,7 +179,7 @@ describe.only("runtime", () => {
} else {
failed.add(dir);
showOutput(cwd, {
shared,
internal,
format: 'cjs',
hydratable: hydrate,
store: !!compileOptions.store,
@ -190,7 +191,9 @@ describe.only("runtime", () => {
}
})
.then(() => {
if (config.show) showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile);
if (config.show) showOutput(cwd, { internal, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store, skipIntroByDefault: compileOptions.skipIntroByDefault, nestedTransitions: compileOptions.nestedTransitions }, compile);
flush();
});
});
}

@ -1,5 +1,5 @@
export default {
data: {
props: {
target: 'World!',
display: true,
},
@ -8,13 +8,13 @@ export default {
<h1></h1>
`,
test ( assert, component, target, window ) {
const header = target.querySelector( 'h1' );
const eventClick = new window.MouseEvent( 'click' );
test(assert, component, target, window) {
const header = target.querySelector('h1');
const click = new window.MouseEvent('click');
header.dispatchEvent( eventClick );
assert.htmlEqual( target.innerHTML, `
header.dispatchEvent(click);
assert.htmlEqual(target.innerHTML, `
<h1>Hello World!</h1>
` );
}
`);
},
};

@ -3,7 +3,6 @@
export let target;
function insert(node, text) {
function onClick() {
node.textContent = text;
}

@ -1,10 +1,11 @@
export default {
test ( assert, component, target, window ) {
const button = target.querySelector( 'button' );
const click = new window.MouseEvent( 'click' );
async test(assert, component, target, window) {
const button = target.querySelector('button');
const click = new window.MouseEvent('click');
assert.htmlEqual( target.innerHTML, `<button>0</button>` );
button.dispatchEvent( click );
assert.htmlEqual( target.innerHTML, `<button>1</button>` );
}
assert.htmlEqual(target.innerHTML, `<button>1</button>`);
await button.dispatchEvent(click);
await Promise.resolve();
assert.htmlEqual(target.innerHTML, `<button>2</button>`);
},
};

@ -1,10 +1,10 @@
<script>
export let x;
export let x = 0;
function foo(node) {
let x = 0;
const handler = () => x = x++;
const handler = () => {
x += 1;
}
node.addEventListener('click', handler);
handler();

@ -3,27 +3,27 @@ export default {
<button>action</button>
`,
test ( assert, component, target, window ) {
const button = target.querySelector( 'button' );
const eventEnter = new window.MouseEvent( 'mouseenter' );
const eventLeave = new window.MouseEvent( 'mouseleave' );
const ctrlPress = new window.KeyboardEvent( 'keydown', { ctrlKey: true } );
test (assert, component, target, window) {
const button = target.querySelector('button');
const eventEnter = new window.MouseEvent('mouseenter');
const eventLeave = new window.MouseEvent('mouseleave');
const ctrlPress = new window.KeyboardEvent('keydown', { ctrlKey: true });
button.dispatchEvent( eventEnter );
assert.htmlEqual( target.innerHTML, `
button.dispatchEvent(eventEnter);
assert.htmlEqual(target.innerHTML, `
<button>action</button>
<div class="tooltip">Perform an Action</div>
` );
`);
window.dispatchEvent( ctrlPress );
assert.htmlEqual( target.innerHTML, `
window.dispatchEvent(ctrlPress);
assert.htmlEqual(target.innerHTML, `
<button>action</button>
<div class="tooltip">Perform an augmented Action</div>
` );
`);
button.dispatchEvent( eventLeave );
assert.htmlEqual( target.innerHTML, `
button.dispatchEvent(eventLeave);
assert.htmlEqual(target.innerHTML, `
<button>action</button>
` );
`);
}
};

@ -1,5 +1,5 @@
<script>
export let tooltip = 'Perform an Action';
export let text = 'Perform an Action';
function checkForCtrl(event) {
if (event.ctrlKey) {
@ -40,5 +40,5 @@
}
</script>
<button use:tooltip="{tooltip}">action</button>
<button use:tooltip="{text}">action</button>
<svelte:window on:keydown="{checkForCtrl}" on:keyup="{checkForCtrl}"/>
Loading…
Cancel
Save