use `@_` sigil for globals

pull/2963/head
Conduitry 6 years ago
parent 788cf97a93
commit cd4c2f2075

@ -102,6 +102,7 @@ export default class Component {
has_reactive_assignments = false;
injected_reactive_declaration_vars: Set<string> = new Set();
helpers: Map<string, string> = new Map();
globals: Map<string, string> = new Map();
indirect_dependencies: Map<string, Set<string>> = new Map();
@ -238,6 +239,12 @@ export default class Component {
return alias;
}
global(name: string) {
const alias = this.alias(name);
this.globals.set(name, alias);
return alias;
}
generate(result: string) {
let js = null;
let css = null;
@ -252,6 +259,10 @@ export default class Component {
.replace(/__svelte:self__/g, this.name)
.replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => {
if (sigil === '@') {
if (name[0] === '_') {
return this.global(name.slice(1));
}
if (!internal_exports.has(name)) {
throw new Error(`compiler error: this shouldn't happen! generated code is trying to use inexistent internal '${name}'`);
}
@ -266,6 +277,10 @@ export default class Component {
return sigil.slice(1) + name;
});
const referenced_globals = Array.from(this.globals, ([name, alias]) => name !== alias && ({ name, alias })).filter(Boolean);
if (referenced_globals.length) {
this.helper('globals');
}
const imported_helpers = Array.from(this.helpers, ([name, alias]) => ({ name, alias }));
const module = create_module(
@ -275,6 +290,7 @@ export default class Component {
banner,
compile_options.sveltePath,
imported_helpers,
referenced_globals,
this.imports,
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
name: variable.name,

@ -17,6 +17,7 @@ export default function create_module(
banner: string,
sveltePath = 'svelte',
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -24,10 +25,10 @@ export default function create_module(
const internal_path = `${sveltePath}/internal`;
if (format === 'esm') {
return esm(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports, source);
return esm(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports, source);
}
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, imports, module_exports);
if (format === 'cjs') return cjs(code, name, banner, sveltePath, internal_path, helpers, globals, imports, module_exports);
throw new Error(`options.format is invalid (must be ${list(Object.keys(wrappers))})`);
}
@ -45,6 +46,7 @@ function esm(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -52,6 +54,9 @@ function esm(
const internal_imports = helpers.length > 0 && (
`import ${stringify_props(helpers.map(h => h.name === h.alias ? 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
@ -70,6 +75,7 @@ function esm(
return deindent`
${banner}
${internal_imports}
${internal_globals}
${user_imports}
${code}
@ -85,6 +91,7 @@ function cjs(
sveltePath: string,
internal_path: string,
helpers: Array<{ name: string; alias: string }>,
globals: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[]
) {
@ -93,6 +100,9 @@ function cjs(
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;
@ -127,6 +137,7 @@ function cjs(
"use strict";
${internal_imports}
${internal_globals}
${requires}
${code}

@ -164,7 +164,7 @@ export default class Block {
if (parent_node) {
this.builders.mount.add_line(`@append(${parent_node}, ${name});`);
if (parent_node === '@document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
if (parent_node === '@_document.head' && !no_detach) this.builders.destroy.add_line(`@detach(${name});`);
} else {
this.builders.mount.add_line(`@insert(#target, ${name}, anchor);`);
if (!no_detach) this.builders.destroy.add_conditional('detaching', `@detach(${name});`);

@ -44,7 +44,7 @@ export default function dom(
var style = @element("style");
style.id = '${component.stylesheet.id}-style';
style.textContent = ${styles};
@append(@document.head, style);
@append(@_document.head, style);
}
`);
}
@ -59,7 +59,7 @@ export default function dom(
if (options.dev && !options.hydratable) {
block.builders.claim.add_line(
'throw new @Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
'throw new @_Error("options.hydrate only works if the component was compiled with the `hydratable: true` option");'
);
}
@ -108,7 +108,7 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
get ${x.export_name}() {
throw new @Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
@ -124,14 +124,14 @@ export default function dom(
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new @Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
}
`);
}
} else if (component.compile_options.dev) {
body.push(deindent`
set ${x.export_name}(value) {
throw new @Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}
@ -147,7 +147,7 @@ export default function dom(
const props = ${options.customElement ? `this.attributes` : `options.props || {}`};
${expected.map(prop => deindent`
if (ctx.${prop.name} === undefined && !('${prop.export_name}' in props)) {
@console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
@_console.warn("<${component.tag}> was created without expected prop '${prop.export_name}'");
}`)}
`;
}
@ -404,7 +404,7 @@ export default function dom(
if (component.compile_options.dev && !component.var_lookup.has('$$props') && writable_props.length) {
unknown_props_check = deindent`
const writable_props = [${writable_props.map(prop => `'${prop.export_name}'`).join(', ')}];
@Object.keys($$props).forEach(key => {
@_Object.keys($$props).forEach(key => {
if (!writable_props.includes(key) && !key.startsWith('$$')) console.warn(\`<${component.tag}> was created with unknown prop '\${key}'\`);
});
`;
@ -483,7 +483,7 @@ export default function dom(
if (component.tag != null) {
builder.add_block(deindent`
@customElements.define("${component.tag}", ${name});
@_customElements.define("${component.tag}", ${name});
`);
}
} else {
@ -493,7 +493,7 @@ export default function dom(
class ${name} extends @${superclass} {
constructor(options) {
super(${options.dev && `options`});
${should_add_css && `if (!@document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
${should_add_css && `if (!@_document.getElementById("${component.stylesheet.id}-style")) ${add_css}();`}
@init(this, options, ${definition}, create_fragment, ${not_equal}, ${prop_names});
${dev_props_check}

@ -11,11 +11,11 @@ export default class BodyWrapper extends Wrapper {
const snippet = handler.render(block);
block.builders.init.add_block(deindent`
@document.body.addEventListener("${handler.name}", ${snippet});
@_document.body.addEventListener("${handler.name}", ${snippet});
`);
block.builders.destroy.add_block(deindent`
@document.body.removeEventListener("${handler.name}", ${snippet});
@_document.body.removeEventListener("${handler.name}", ${snippet});
`);
});
}

@ -62,7 +62,7 @@ export default class DebugTagWrapper extends Wrapper {
block.builders.update.add_block(deindent`
if (${condition}) {
const { ${ctx_identifiers} } = ctx;
@console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);
@ -70,7 +70,7 @@ export default class DebugTagWrapper extends Wrapper {
block.builders.create.add_block(deindent`
{
const { ${ctx_identifiers} } = ctx;
@console.${log}({ ${logged_identifiers} });
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);

@ -190,7 +190,7 @@ export default class EachBlockWrapper extends Wrapper {
renderer.blocks.push(deindent`
function ${this.vars.get_each_context}(ctx, list, i) {
const child_ctx = @Object.create(ctx);
const child_ctx = @_Object.create(ctx);
${this.context_props}
return child_ctx;
}
@ -296,7 +296,7 @@ export default class EachBlockWrapper extends Wrapper {
const lookup = block.get_unique_name(`${this.var}_lookup`);
block.add_variable(iterations, '[]');
block.add_variable(lookup, `new @Map()`);
block.add_variable(lookup, `new @_Map()`);
if (this.fragment.nodes[0].is_dom_node()) {
this.block.first = this.fragment.nodes[0].var;

@ -136,7 +136,7 @@ export default class BindingWrapper {
case 'currentTime':
case 'playbackRate':
case 'volume':
update_conditions.push(`!@isNaN(${this.snippet})`);
update_conditions.push(`!@_isNaN(${this.snippet})`);
break;
case 'paused':

@ -270,7 +270,7 @@ export default class ElementWrapper extends Wrapper {
`@append(${parent_node}, ${node});`
);
if (parent_node === '@document.head') {
if (parent_node === '@_document.head') {
block.builders.destroy.add_line(`@detach(${node});`);
}
} else {
@ -379,7 +379,7 @@ export default class ElementWrapper extends Wrapper {
}
if (namespace) {
return `@document.createElementNS("${namespace}", "${name}")`;
return `@_document.createElementNS("${namespace}", "${name}")`;
}
return `@element("${name}")`;
@ -465,7 +465,7 @@ export default class ElementWrapper extends Wrapper {
block.builders.init.add_block(deindent`
function ${handler}() {
${animation_frame && deindent`
@cancelAnimationFrame(${animation_frame});
@_cancelAnimationFrame(${animation_frame});
if (!${this.var}.paused) ${animation_frame} = @raf(${handler});`}
${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});

@ -30,6 +30,6 @@ export default class HeadWrapper extends Wrapper {
}
render(block: Block, _parent_node: string, _parent_nodes: string) {
this.fragment.render(block, '@document.head', 'nodes');
this.fragment.render(block, '@_document.head', 'nodes');
}
}

@ -154,7 +154,7 @@ export default class IfBlockWrapper extends Wrapper {
const vars = { name, anchor, if_name, has_else, has_transitions };
const detaching = (parent_node && parent_node !== '@document.head') ? '' : 'detaching';
const detaching = (parent_node && parent_node !== '@_document.head') ? '' : 'detaching';
if (this.node.else) {
if (has_outros) {

@ -22,7 +22,7 @@ export default class RawMustacheTagWrapper extends Tag {
render(block: Block, parent_node: string, parent_nodes: string) {
const name = this.var;
const in_head = parent_node === '@document.head';
const in_head = parent_node === '@_document.head';
const needs_anchors = !parent_node || in_head;
// if in head always needs anchors

@ -68,9 +68,9 @@ export default class TitleWrapper extends Wrapper {
const init = this.node.should_cache ? `${last} = ${value}` : value;
block.builders.init.add_line(
`@document.title = ${init};`
`@_document.title = ${init};`
);
const updater = `@document.title = ${this.node.should_cache ? last : value};`;
const updater = `@_document.title = ${this.node.should_cache ? last : value};`;
if (all_dependencies.size) {
const dependencies = Array.from(all_dependencies);
@ -95,7 +95,7 @@ export default class TitleWrapper extends Wrapper {
? stringify((this.node.children[0] as Text).data)
: '""';
block.builders.hydrate.add_line(`@document.title = ${value};`);
block.builders.hydrate.add_line(`@_document.title = ${value};`);
}
}
}

@ -44,8 +44,8 @@ export default class WindowWrapper extends Wrapper {
const events = {};
const bindings: Record<string, string> = {};
add_actions(component, block, '@window', this.node.actions);
add_event_handlers(block, '@window', this.node.handlers);
add_actions(component, block, '@_window', this.node.actions);
add_event_handlers(block, '@_window', this.node.handlers);
this.node.bindings.forEach(binding => {
// in dev mode, throw if read-only values are written to
@ -92,29 +92,29 @@ export default class WindowWrapper extends Wrapper {
renderer.meta_bindings.add_block(deindent`
if (${condition}) {
@window.scrollTo(${x || 'window.pageXOffset'}, ${y || 'window.pageYOffset'});
@_scrollTo(${x || '@_pageXOffset'}, ${y || '@pageYOffset'});
}
${x && `${x} = @window.pageXOffset;`}
${y && `${y} = @window.pageYOffset;`}
${x && `${x} = @_pageXOffset;`}
${y && `${y} = @_pageYOffset;`}
`);
block.event_listeners.push(deindent`
@listen(@window, "${event}", () => {
@listen(@_window, "${event}", () => {
${scrolling} = true;
@clearTimeout(${scrolling_timeout});
${scrolling_timeout} = @setTimeout(${clear_scrolling}, 100);
@_clearTimeout(${scrolling_timeout});
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
ctx.${handler_name}();
})
`);
} else {
props.forEach(prop => {
renderer.meta_bindings.add_line(
`this._state.${prop.name} = @window.${prop.value};`
`this._state.${prop.name} = @_window.${prop.value};`
);
});
block.event_listeners.push(deindent`
@listen(@window, "${event}", ctx.${handler_name})
@listen(@_window, "${event}", ctx.${handler_name})
`);
}
@ -126,7 +126,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(deindent`
function ${handler_name}() {
${props.map(prop => `${prop.name} = @window.${prop.value}; $$invalidate('${prop.name}', ${prop.name});`)}
${props.map(prop => `${prop.name} = @_window.${prop.value}; $$invalidate('${prop.name}', ${prop.name});`)}
}
`);
@ -146,13 +146,13 @@ export default class WindowWrapper extends Wrapper {
).join(' || ')
} && !${scrolling}) {
${scrolling} = true;
@clearTimeout(${scrolling_timeout});
@window.scrollTo(${
bindings.scrollX ? `ctx.${bindings.scrollX}` : `@window.pageXOffset`
@_clearTimeout(${scrolling_timeout});
@_scrollTo(${
bindings.scrollX ? `ctx.${bindings.scrollX}` : `@_pageXOffset`
}, ${
bindings.scrollY ? `ctx.${bindings.scrollY}` : `@window.pageYOffset`
bindings.scrollY ? `ctx.${bindings.scrollY}` : `@_pageYOffset`
});
${scrolling_timeout} = @setTimeout(${clear_scrolling}, 100);
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
}
`);
}
@ -170,7 +170,7 @@ export default class WindowWrapper extends Wrapper {
component.partly_hoisted.push(deindent`
function ${handler_name}() {
${name} = @navigator.onLine; $$invalidate('${name}', ${name});
${name} = @_navigator.onLine; $$invalidate('${name}', ${name});
}
`);
@ -179,8 +179,8 @@ export default class WindowWrapper extends Wrapper {
`);
block.event_listeners.push(
`@listen(@window, "online", ctx.${handler_name})`,
`@listen(@window, "offline", ctx.${handler_name})`
`@listen(@_window, "online", ctx.${handler_name})`,
`@listen(@_window, "offline", ctx.${handler_name})`
);
component.has_reactive_assignments = true;

@ -163,7 +163,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
node_contents='${(' + snippet + ') || ""}';
} else {
const snippet = snip(expression);
opening_tag += ' ${(v => v ? ("' + name + '" + (v === true ? "" : "=" + @JSON.stringify(v))) : "")(' + snippet + ')}';
opening_tag += ' ${(v => v ? ("' + name + '" + (v === true ? "" : "=" + @_JSON.stringify(v))) : "")(' + snippet + ')}';
}
});

@ -52,7 +52,7 @@ export default function(node: InlineComponent, renderer: Renderer, options: Rend
let props;
if (uses_spread) {
props = `@Object.assign(${
props = `@_Object.assign(${
node.attributes
.map(attribute => {
if (attribute.is_spread) {

@ -2,7 +2,7 @@ import { identity as linear, noop, now } from './utils';
import { loop } from './loop';
import { create_rule, delete_rule } from './style_manager';
import { AnimationConfig } from '../animate';
import { getComputedStyle } from './globals';
//todo: documentation says it is DOMRect, but in IE it would be ClientRect
type PositionRect = DOMRect|ClientRect;

@ -1,5 +1,3 @@
import { document, getComputedStyle, navigator } from './globals';
export function append(target: Node, node: Node) {
target.appendChild(node);
}

@ -1,42 +1 @@
const win = typeof window !== 'undefined' ? window : global;
const {
// ecmascript
Error,
JSON,
Map,
Object,
console,
isNaN,
// dom
cancelAnimationFrame,
clearTimeout,
customElements,
document,
getComputedStyle,
navigator,
requestAnimationFrame,
setTimeout: export_setTimeout // TODO: remove when upgrading typescript, bug
} = win as unknown as typeof globalThis;
export {
// ecmascript
Error,
JSON,
Map,
Object,
console,
isNaN,
// dom
cancelAnimationFrame,
clearTimeout,
customElements,
document,
getComputedStyle,
navigator,
requestAnimationFrame,
export_setTimeout as setTimeout,
win as window,
};
export const globals = (typeof window !== 'undefined' ? window : global) as unknown as typeof globalThis;

@ -1,6 +1,5 @@
import { element } from './dom';
import { raf } from './utils';
import { document } from './globals';
let stylesheet;
let active = 0;

@ -1,5 +1,3 @@
import { requestAnimationFrame } from './globals';
export function noop() {}
export const identity = x => x;

Loading…
Cancel
Save