Skip to content

Commit

Permalink
Merge branch 'master' of github.com:sveltejs/svelte
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Apr 19, 2018
2 parents bfd380b + bba0444 commit d215279
Show file tree
Hide file tree
Showing 1,245 changed files with 3,483 additions and 19,149 deletions.
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,11 @@ The Svelte compiler optionally takes a second argument, an object of configurati

| | **Values** | **Description** | **Default** |
|---|---|---|---|
| `generate` | `'dom'`, `'ssr'` | Whether to generate JavaScript code intended for use on the client (`'dom'`), or for use in server-side rendering (`'ssr'`). | `'dom'` |
| `generate` | `'dom'`, `'ssr'`, `false` | Whether to generate JavaScript code intended for use on the client (`'dom'`), or for use in server-side rendering (`'ssr'`). If `false`, component will be parsed and validated but no code will be emitted | `'dom'` |
| `dev` | `true`, `false` | Whether to enable run-time checks in the compiled component. These are helpful during development, but slow your component down. | `false` |
| `css` | `true`, `false` | Whether to include code to inject your component's styles into the DOM. | `true` |
| `store` | `true`, `false` | Whether to support store integration on the compiled component. | `false` |
| `hydratable` | `true`, `false` | Whether to support hydration on the compiled component. | `false` |
| `customElement` | `true`, `false`, `{ tag, props }` | Whether to compile this component to a custom element. If `tag`/`props` are passed, compiles to a custom element and overrides the values exported by the component. | `false` |
| `cascade` | `true`, `false` | Whether to cascade all of the component's styles to child components. If `false`, only selectors wrapped in `:global(...)` and keyframe IDs beginning with `-global-` are cascaded. | `true` |
| `parser` | `v2` | Opt in to [v2 syntax](https://github.com/sveltejs/svelte-upgrade#svelte-v2-syntax-changes). | `undefined` |
| `bind` | `boolean` | If `false`, disallows `bind:` directives | `true` |
| | | |
| `shared` | `true`, `false`, `string` | Whether to import various helpers from a shared external library. When you have a project with multiple components, this reduces the overall size of your JavaScript bundle, at the expense of having immediately-usable component. You can pass a string of the module path to use, or `true` will import from `'svelte/shared.js'`. | `false` |
Expand All @@ -94,7 +91,7 @@ The Svelte compiler optionally takes a second argument, an object of configurati
| `filename` | `string` | The filename to use in sourcemaps and compiler error and warning messages. | `'SvelteComponent.html'` |
| `amd`.`id` | `string` | The AMD module ID to use for the `'amd'` and `'umd'` output formats. | `undefined` |
| `globals` | `object`, `function` | When outputting to the `'umd'`, `'iife'` or `'eval'` formats, an object or function mapping the names of imported dependencies to the names of global variables. | `{}` |
| `preserveComments` | `boolean` | Include comments in rendering. Currently, only applies to SSR rendering | `false` |
| `preserveComments` | `boolean` | Include comments in rendering. Currently, only applies to SSR rendering | `false` |
| | | |
| `onerror` | `function` | Specify a callback for when Svelte encounters an error while compiling the component. Passed two arguments: the error object, and another function that is Svelte's default onerror handling. | (exception is thrown) |
| `onwarn` | `function` | Specify a callback for when Svelte encounters a non-fatal warning while compiling the component. Passed two arguments: the warning object, and another function that is Svelte's default onwarn handling. | (warning is logged to console) |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"glob": "^7.1.1",
"is-reference": "^1.1.0",
"jsdom": "^11.6.1",
"locate-character": "^2.0.0",
"locate-character": "^2.0.5",
"magic-string": "^0.22.3",
"mocha": "^3.2.0",
"nightmare": "^2.10.0",
Expand Down
13 changes: 12 additions & 1 deletion src/Stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,24 @@ function collapseTimings(timings) {
}

export default class Stats {
onwarn: (warning: Warning) => void;

startTime: number;
currentTiming: Timing;
currentChildren: Timing[];
timings: Timing[];
stack: Timing[];
warnings: Warning[];

constructor() {
constructor({ onwarn }: {
onwarn: (warning: Warning) => void
}) {
this.startTime = now();
this.stack = [];
this.currentChildren = this.timings = [];

this.onwarn = onwarn;

this.warnings = [];
}

Expand Down Expand Up @@ -99,4 +105,9 @@ export default class Stats {
hooks
};
}

warn(warning) {
this.warnings.push(warning);
this.onwarn(warning);
}
}
76 changes: 21 additions & 55 deletions src/css/Stylesheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ class Rule {
return this.selectors.some(s => s.used);
}

minify(code: MagicString, cascade: boolean, dev: boolean) {
minify(code: MagicString, dev: boolean) {
let c = this.node.start;
let started = false;

this.selectors.forEach((selector, i) => {
if (cascade || selector.used) {
if (selector.used) {
const separator = started ? ',' : '';
if ((selector.node.start - c) > separator.length) {
code.overwrite(c, selector.node.start, separator);
}

if (!cascade) selector.minify(code);
selector.minify(code);
c = selector.node.end;

started = true;
Expand All @@ -66,39 +66,12 @@ class Rule {
code.remove(c, this.node.block.end - 1);
}

transform(code: MagicString, id: string, keyframes: Map<string, string>, cascade: boolean) {
transform(code: MagicString, id: string, keyframes: Map<string, string>) {
if (this.parent && this.parent.node.type === 'Atrule' && this.parent.node.name === 'keyframes') return true;

const attr = `.${id}`;

if (cascade) {
this.selectors.forEach(selector => {
// TODO disable cascading (without :global(...)) in v2
const { start, end, children } = selector.node;

const css = code.original;
const selectorString = css.slice(start, end);

const firstToken = children[0];

let transformed;

if (firstToken.type === 'TypeSelector') {
const insert = firstToken.end;
const head = firstToken.name === '*' ? '' : css.slice(start, insert);
const tail = css.slice(insert, end);

transformed = `${head}${attr}${tail},${attr} ${selectorString}`;
} else {
transformed = `${attr}${selectorString},${attr} ${selectorString}`;
}

code.overwrite(start, end, transformed);
});
} else {
this.selectors.forEach(selector => selector.transform(code, attr));
}

this.selectors.forEach(selector => selector.transform(code, attr));
this.declarations.forEach(declaration => declaration.transform(code, keyframes));
}

Expand Down Expand Up @@ -182,7 +155,7 @@ class Atrule {
return true; // TODO
}

minify(code: MagicString, cascade: boolean, dev: boolean) {
minify(code: MagicString, dev: boolean) {
if (this.node.name === 'media') {
const expressionChar = code.original[this.node.expression.start];
let c = this.node.start + (expressionChar === '(' ? 6 : 7);
Expand Down Expand Up @@ -215,9 +188,9 @@ class Atrule {
let c = this.node.block.start + 1;

this.children.forEach(child => {
if (cascade || child.isUsed(dev)) {
if (child.isUsed(dev)) {
code.remove(c, child.node.start);
child.minify(code, cascade, dev);
child.minify(code, dev);
c = child.node.end;
}
});
Expand All @@ -226,7 +199,7 @@ class Atrule {
}
}

transform(code: MagicString, id: string, keyframes: Map<string, string>, cascade: boolean) {
transform(code: MagicString, id: string, keyframes: Map<string, string>) {
if (this.node.name === 'keyframes') {
this.node.expression.children.forEach(({ type, name, start, end }: Node) => {
if (type === 'Identifier') {
Expand All @@ -240,7 +213,7 @@ class Atrule {
}

this.children.forEach(child => {
child.transform(code, id, keyframes, cascade);
child.transform(code, id, keyframes);
})
}

Expand All @@ -264,7 +237,6 @@ const keys = {};
export default class Stylesheet {
source: string;
parsed: Parsed;
cascade: boolean;
filename: string;
dev: boolean;

Expand All @@ -276,10 +248,9 @@ export default class Stylesheet {

nodesWithCssClass: Set<Node>;

constructor(source: string, parsed: Parsed, filename: string, cascade: boolean, dev: boolean) {
constructor(source: string, parsed: Parsed, filename: string, dev: boolean) {
this.source = source;
this.parsed = parsed;
this.cascade = cascade;
this.filename = filename;
this.dev = dev;

Expand Down Expand Up @@ -356,11 +327,6 @@ export default class Stylesheet {
if (parent.type === 'Element') stack.unshift(<Element>parent);
}

if (this.cascade) {
if (stack.length === 0) this.nodesWithCssClass.add(node);
return;
}

for (let i = 0; i < this.children.length; i += 1) {
const child = this.children[i];
child.apply(node, stack);
Expand Down Expand Up @@ -389,15 +355,15 @@ export default class Stylesheet {

if (shouldTransformSelectors) {
this.children.forEach((child: (Atrule|Rule)) => {
child.transform(code, this.id, this.keyframes, this.cascade);
child.transform(code, this.id, this.keyframes);
});
}

let c = 0;
this.children.forEach(child => {
if (this.cascade || child.isUsed(this.dev)) {
if (child.isUsed(this.dev)) {
code.remove(c, child.node.start);
child.minify(code, this.cascade, this.dev);
child.minify(code, this.dev);
c = child.node.end;
}
});
Expand All @@ -421,27 +387,27 @@ export default class Stylesheet {
}

warnOnUnusedSelectors(onwarn: (warning: Warning) => void) {
if (this.cascade) return;

let locator;

const handler = (selector: Selector) => {
const pos = selector.node.start;

if (!locator) locator = getLocator(this.source);
const { line, column } = locator(pos);
if (!locator) locator = getLocator(this.source, { offsetLine: 1 });
const start = locator(pos);
const end = locator(selector.node.end);

const frame = getCodeFrame(this.source, line, column);
const frame = getCodeFrame(this.source, start.line - 1, start.column);
const message = `Unused CSS selector`;

onwarn({
code: `css-unused-selector`,
message,
frame,
loc: { line: line + 1, column },
start,
end,
pos,
filename: this.filename,
toString: () => `${message} (${line + 1}:${column})\n${frame}`,
toString: () => `${message} (${start.line}:${start.column})\n${frame}`,
});
};

Expand Down
41 changes: 11 additions & 30 deletions src/generators/Generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { getLocator } from 'locate-character';
import Stats from '../Stats';
import deindent from '../utils/deindent';
import CodeBuilder from '../utils/CodeBuilder';
import getCodeFrame from '../utils/getCodeFrame';
import flattenReference from '../utils/flattenReference';
import reservedNames from '../utils/reservedNames';
import namespaces from '../utils/namespaces';
Expand Down Expand Up @@ -84,7 +83,6 @@ export default class Generator {
source: string;
name: string;
options: CompileOptions;
v2: boolean;

customElement: CustomElementOptions;
tag: string;
Expand All @@ -95,6 +93,7 @@ export default class Generator {
helpers: Set<string>;
components: Set<string>;
events: Set<string>;
methods: Set<string>;
transitions: Set<string>;
actions: Set<string>;
importedComponents: Map<string, string>;
Expand Down Expand Up @@ -133,8 +132,6 @@ export default class Generator {
stats.start('compile');
this.stats = stats;

this.v2 = options.parser === 'v2';

this.ast = clone(parsed);

this.parsed = parsed;
Expand All @@ -145,6 +142,7 @@ export default class Generator {
this.helpers = new Set();
this.components = new Set();
this.events = new Set();
this.methods = new Set();
this.transitions = new Set();
this.actions = new Set();
this.importedComponents = new Map();
Expand Down Expand Up @@ -369,31 +367,13 @@ export default class Generator {
})
};

Object.getOwnPropertyNames(String.prototype).forEach(name => {
const descriptor = Object.getOwnPropertyDescriptor(String.prototype, name);
if (typeof descriptor.value === 'function') {
Object.defineProperty(css, name, {
value: (...args) => {
return css.code === null
? null
: css.code[name].call(css.code, ...args);
}
});
}
});

this.stats.stop('compile');

return {
ast: this.ast,
js,
css,
stats: this.stats.render(this),

// TODO deprecate
code: js.code,
map: js.map,
cssMap: css.map
stats: this.stats.render(this)
};
}

Expand Down Expand Up @@ -441,6 +421,7 @@ export default class Generator {
code,
source,
computations,
methods,
templateProperties,
imports
} = this;
Expand Down Expand Up @@ -578,9 +559,7 @@ export default class Generator {
const key = getName(prop.key);
const value = prop.value;

const deps = this.v2
? value.params[0].properties.map(prop => prop.key.name)
: value.params.map(param => param.type === 'AssignmentPattern' ? param.left.name : param.name);
const deps = value.params[0].properties.map(prop => prop.key.name);

deps.forEach(dep => {
this.expectedProperties.add(dep);
Expand Down Expand Up @@ -632,19 +611,21 @@ export default class Generator {

if (templateProperties.methods && dom) {
addDeclaration('methods', templateProperties.methods.value);

templateProperties.methods.value.properties.forEach(prop => {
this.methods.add(prop.key.name);
});
}

if (templateProperties.namespace) {
const ns = nodeToString(templateProperties.namespace.value);
this.namespace = namespaces[ns] || ns;
}

if (templateProperties.onrender) templateProperties.oncreate = templateProperties.onrender; // remove after v2
if (templateProperties.oncreate && dom) {
addDeclaration('oncreate', templateProperties.oncreate.value);
}

if (templateProperties.onteardown) templateProperties.ondestroy = templateProperties.onteardown; // remove after v2
if (templateProperties.ondestroy && dom) {
addDeclaration('ondestroy', templateProperties.ondestroy.value);
}
Expand Down Expand Up @@ -802,7 +783,7 @@ export default class Generator {

node.generator = generator;

if (node.type === 'Element' && (node.name === ':Component' || node.name === ':Self' || node.name === 'svelte:component' || node.name === 'svelte:self' || generator.components.has(node.name))) {
if (node.type === 'Element' && (node.name === 'svelte:component' || node.name === 'svelte:self' || generator.components.has(node.name))) {
node.type = 'Component';
Object.setPrototypeOf(node, nodes.Component.prototype);
} else if (node.type === 'Element' && node.name === 'title' && parentIsHead(parent)) { // TODO do this in parse?
Expand Down Expand Up @@ -886,7 +867,7 @@ export default class Generator {
this.skip();
}

if (node.type === 'Component' && (node.name === ':Component' || node.name === 'svelte:component')) {
if (node.type === 'Component' && node.name === 'svelte:component') {
node.metadata = contextualise(node.expression, contextDependencies, indexes, false);
}

Expand Down

0 comments on commit d215279

Please sign in to comment.