remove some unused stuff (#10299)

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/10348/head
Rich Harris 2 years ago committed by GitHub
parent 23b38a3471
commit dc8ca4661f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -96,7 +96,8 @@
"check:watch": "tsc --watch",
"generate:version": "node ./scripts/generate-version.js",
"generate:types": "node ./scripts/generate-types.js",
"prepublishOnly": "pnpm build"
"prepublishOnly": "pnpm build",
"knip": "knip"
},
"devDependencies": {
"@jridgewell/trace-mapping": "^0.3.22",
@ -108,6 +109,7 @@
"@types/aria-query": "^5.0.4",
"dts-buddy": "^0.4.4",
"esbuild": "^0.19.11",
"knip": "^4.2.1",
"rollup": "^4.9.5",
"source-map": "^0.7.4",
"tiny-glob": "^0.2.9"
@ -126,5 +128,14 @@
"locate-character": "^3.0.0",
"magic-string": "^0.30.5",
"zimmerframe": "^1.1.0"
},
"knip": {
"entry": [
"src/*/index.js",
"src/*/public.d.ts"
],
"project": [
"src/**"
]
}
}

@ -1,841 +0,0 @@
import { parse } from 'acorn';
import type { OptimizeOptions } from '#compiler';
import { type NodePath, traverse, is, type Scope } from 'estree-toolkit';
import type {
CallExpression,
FunctionDeclaration,
ImportDeclaration,
VariableDeclaration,
Node,
Identifier,
Function,
BlockStatement,
Expression
} from 'estree';
import { print } from 'esrap';
import { error } from '../errors.js';
type Props =
| Map<string, { path: null | NodePath<VariableDeclaration>; type: 'static' | 'dynamic' }>
| 'unknown';
interface IfBlock {
condition: Node;
is_static: boolean;
type: 'if';
}
interface AwaitBlock {
is_static: boolean;
type: 'await';
}
interface EachBlock {
collection: Node;
is_static: boolean;
type: 'each';
}
interface ComponentState {
props: Props;
needs_template: boolean;
is_static: boolean;
template: {
open: null | NodePath<VariableDeclaration>;
traverse: Array<NodePath<VariableDeclaration>>;
close: null | NodePath<CallExpression>;
components: {
path: NodePath<CallExpression>;
state: ComponentState;
}[];
blocks: Map<NodePath<CallExpression>, IfBlock | AwaitBlock | EachBlock>;
render_effects: Map<
NodePath<CallExpression>,
{
is_static: boolean;
anchors: Set<NodePath<VariableDeclaration>>;
expressions: Set<NodePath<VariableDeclaration>>;
}
>;
};
references: ComponentState[];
}
interface ModuleContext {
parent: null;
needs_template: boolean;
type: 'module';
}
interface FunctionContext {
parent: ModuleContext | ComponentContext | FunctionContext;
needs_template: boolean;
type: 'function';
}
interface ComponentContext {
parent: ModuleContext | ComponentContext;
needs_template: boolean;
type: 'component';
}
interface OptimizeState {
components: Map<NodePath<FunctionDeclaration>, ComponentState>;
context: ModuleContext | FunctionContext | ComponentContext;
}
function visit_component(
component: NodePath<FunctionDeclaration>,
parent_component: null | ComponentState,
props: Props,
state: OptimizeState
): ComponentState {
let component_state = state.components.get(component);
let initial_visit = true;
if (component_state === undefined) {
component_state = {
props,
references: [],
is_static: true,
needs_template: state.context.needs_template,
template: {
open: null,
traverse: [],
close: null,
components: [],
blocks: new Map(),
render_effects: new Map()
}
};
if (parent_component !== null) {
component_state.references.push(parent_component);
}
state.components.set(component, component_state);
} else {
initial_visit = false;
if (state.context.needs_template && !component_state.needs_template) {
component_state.needs_template = true;
component_state.is_static = false;
}
}
const template = component_state.template;
const visitor = {
CallExpression(path: NodePath<CallExpression>) {
const callee = path.node!.callee;
const callee_path = path.get('callee');
if (!is.identifier(callee)) {
return;
}
const callee_name = callee.name;
const args = path.node!.arguments;
const grand_path = path.parentPath?.parentPath;
const blocks = component_state!.template.blocks;
if (initial_visit) {
// $.open
if (
is.variableDeclaration(grand_path) &&
is_svelte_import(callee_path) &&
(callee_name === 'open' || callee_name === 'open_frag') &&
// TODO: this won't optimize slots, needs some thought
state.context.type === 'component'
) {
template.open = grand_path;
}
// $.close
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
(callee_name === 'close' || callee_name === 'close_frag') &&
// TODO: this won't optimize slots, needs some thought
state.context.type === 'component'
) {
template.close = path;
}
// $.child / $.child_frag / $.sibling
if (
is.variableDeclaration(grand_path) &&
is_svelte_import(callee_path) &&
(callee_name === 'child' || callee_name === 'child_frag' || callee_name === 'sibling') &&
state.context.type === 'component'
) {
template.traverse.push(grand_path);
}
// $.delegated_event / $.transition / $.in / $.out / $.action / $.event / $.slot / $.auto_focus / $.component / $.element
if (
is_svelte_import(callee_path) &&
(callee_name === 'delegated_event' ||
callee_name === 'transition' ||
callee_name === 'in_fn' ||
callee_name === 'out' ||
callee_name === 'event' ||
callee_name === 'action' ||
callee_name === 'slot' ||
callee_name === 'auto_focus' ||
callee_name === 'component' ||
callee_name === 'element') &&
state.context.type === 'component'
) {
component_state!.is_static = false;
}
// $.bind_value / $.bind_content_editable / $.bind_group / $.bind_property / $.bind_scroll / $.bind_checked / $.bind_online / $.bind_this
// TODO: these should go likey be optimized out, but bail-out for now until we have that working
if (
is_svelte_import(callee_path) &&
(callee_name === 'bind_value' ||
callee_name === 'bind_content_editable' ||
callee_name === 'bind_group' ||
callee_name === 'bind_property' ||
callee_name === 'bind_scroll' ||
callee_name === 'bind_checked' ||
callee_name === 'bind_this' ||
callee_name === 'bind_online') &&
state.context.type === 'component'
) {
component_state!.is_static = false;
}
// $.source / $.derived / $.prop_source
if (
is.variableDeclaration(grand_path) &&
is_svelte_import(callee_path) &&
(callee_name === 'source' ||
callee_name === 'prop_source' ||
callee_name === 'derived') &&
state.context.type === 'component'
) {
component_state!.is_static = false;
}
// $.effect / $.pre_effect
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
(callee_name === 'effect' || callee_name === 'pre_effect') &&
state.context.type === 'component'
) {
component_state!.is_static = false;
}
// $.render_effect
// TODO: what about detection of DOM properties that need to be client-side?
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
callee_name === 'render_effect' &&
state.context.type === 'component'
) {
const closure = path.get('arguments')[0];
let render_effect = template.render_effects.get(path);
if (render_effect === undefined) {
render_effect = {
is_static: true,
anchors: new Set(),
expressions: new Set()
};
template.render_effects.set(path, render_effect);
}
let is_render_effect_static = true;
closure.traverse({
Identifier(path: NodePath<Identifier>) {
if (is_reactive(path, props, false)) {
is_render_effect_static = false;
} else if (path.node!.name.includes('_anchor')) {
const binding = path.scope!.getBinding(path.node!.name);
if (
binding != null &&
is.variableDeclarator(binding.path) &&
is.variableDeclaration(binding.path.parentPath)
) {
render_effect!.anchors.add(binding.path.parentPath);
}
} else if (path.node!.name.includes('_expression')) {
const binding = path.scope!.getBinding(path.node!.name);
if (
binding != null &&
is.variableDeclarator(binding.path) &&
is.variableDeclaration(binding.path.parentPath)
) {
render_effect!.expressions.add(binding.path.parentPath);
}
}
}
});
if (!is_render_effect_static) {
render_effect.is_static = false;
component_state!.is_static = false;
}
path.skipChildren();
}
// $.prop
if (
is.variableDeclaration(grand_path) &&
is_svelte_import(callee_path) &&
callee_name === 'prop' &&
state.context.type === 'component'
) {
const prop_key = args[1];
if (is.literal(prop_key) && props !== 'unknown') {
const prop = props.get(prop_key.value as string);
if (prop !== undefined) {
prop.path = grand_path;
if (prop.type === 'dynamic') {
component_state!.is_static = false;
}
}
} else {
component_state!.is_static = false;
}
}
}
// $.if
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
callee_name.startsWith('if_block')
) {
let condition = path.get('arguments')[1] as NodePath<Expression>;
if (is.arrowFunctionExpression(condition)) {
condition = condition.get('body') as NodePath<Expression>;
}
const is_static = !state.context.needs_template && !is_reactive(condition, props, false);
let if_block = blocks.get(path) as undefined | IfBlock;
if (if_block === undefined) {
if_block = {
condition: condition.node!,
is_static,
type: 'if'
};
blocks.set(path, if_block);
} else if (!is_static) {
if_block.is_static = false;
}
path.skipChildren();
if (!if_block.is_static) {
component_state!.is_static = false;
const consequent_fn = path.get('arguments')[0];
const alternate_fn = path.get('arguments')[1];
const prev_needs_template = state.context.needs_template;
state.context.needs_template = true;
if (is.function(consequent_fn)) {
consequent_fn.traverse(visitor);
}
if (is.function(alternate_fn)) {
alternate_fn.traverse(visitor);
}
state.context.needs_template = prev_needs_template;
}
}
// $.await
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
callee_name === 'await_block'
) {
component_state!.is_static = false;
}
// $.key
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
callee_name === 'key'
) {
component_state!.is_static = false;
}
// $.each
if (
is.expressionStatement(path.parentPath) &&
is_svelte_import(callee_path) &&
callee_name === 'each'
) {
let collection = path.get('arguments')[1] as NodePath<Expression>;
if (is.arrowFunctionExpression(collection)) {
collection = collection.get('body') as NodePath<Expression>;
}
const is_static = !state.context.needs_template && !is_reactive(collection, props, false);
let each_block = blocks.get(path) as undefined | EachBlock;
if (each_block === undefined) {
each_block = {
collection: collection.node!,
is_static,
type: 'each'
};
blocks.set(path, each_block);
} else {
error(null, 'TODO', '');
}
path.skipChildren();
if (!each_block.is_static) {
component_state!.is_static = false;
const each_fn = path.get('arguments')[4];
const else_fn = path.get('arguments')[5];
const prev_needs_template = state.context.needs_template;
state.context.needs_template = true;
if (is.function(each_fn)) {
each_fn.traverse(visitor);
}
if (is.function(else_fn)) {
else_fn.traverse(visitor);
}
state.context.needs_template = prev_needs_template;
}
}
// <Component />
if (
callee_name[0] === callee_name[0].toUpperCase() &&
is.expressionStatement(path.parentPath)
) {
const binding = path.scope!.getBinding(callee_name);
if (
binding != null &&
is.functionDeclaration(binding.path) &&
binding.path.node!.params.length === 3 &&
is.identifier(binding.path.node!.params[1]) &&
binding.path.node!.params[1].name === '$$props'
) {
const context: ComponentContext = {
parent: state.context as ComponentContext,
needs_template: state.context.needs_template,
type: 'component'
};
state.context = context;
const child_props = get_props(path.get('arguments')[1], props);
const child_component_state = visit_component(
binding.path,
component_state!,
child_props,
state
);
if (!child_component_state.is_static) {
component_state!.is_static = false;
}
template.components.push({
path,
state: child_component_state
});
state.context = state.context.parent;
}
}
},
Function: {
enter(path: NodePath<Function>) {
if (path !== component) {
const context: FunctionContext = {
needs_template: state.context.needs_template,
parent: state.context as ComponentContext | FunctionContext | ModuleContext,
type: 'function'
};
state.context = context;
}
},
leave(path: NodePath<Function>) {
if (path !== component) {
state.context = state.context.parent as
| ComponentContext
| FunctionContext
| ModuleContext;
}
}
}
};
component.traverse(visitor);
return component_state;
}
function get_props(props_arg: NodePath<Node>, parent_props: Props | null): Props {
const props: Props = new Map();
if (is.objectExpression(props_arg)) {
for (const property of props_arg.get('properties')) {
if (
is.property(property) &&
(is.identifier(property.node!.key) || is.literal(property.node!.key))
) {
const value = property.get('value');
const kind = property.node!.kind;
if (kind === 'init') {
const dynamic = is_reactive(value, parent_props, true);
props.set(
is.literal(property.node!.key)
? (property.node!.key.value as string)
: property.node!.key.name,
{
type: dynamic ? 'dynamic' : 'static',
path: null
}
);
} else if (
kind === 'get' &&
is.functionExpression(value) &&
value.node!.body.body.length === 1 &&
is.returnStatement(value.node!.body.body[0])
) {
const expression = (value.get('body') as NodePath<BlockStatement>)
.get('body')[0]
.get('argument') as NodePath<Expression>;
const dynamic = is_reactive(expression, parent_props, true);
props.set(
is.literal(property.node!.key)
? (property.node!.key.value as string)
: property.node!.key.name,
{
type: dynamic ? 'dynamic' : 'static',
path: null
}
);
} else {
return 'unknown';
}
} else {
// TODO
error(null, 'TODO', '');
return 'unknown';
}
}
} else {
// TODO
error(null, 'TODO', '');
return 'unknown';
}
return props;
}
function is_reactive(
path: NodePath<Node>,
props: Props | null,
functions_are_reactive: boolean
): boolean {
if (is.identifier(path)) {
const binding = path.scope!.getBinding(path.node!.name);
if (binding != null && is.variableDeclarator(binding.path)) {
const init = binding.path.get('init');
if (init.node! !== null && is_reactive(init, props, functions_are_reactive)) {
return true;
}
}
} else if (is.literal(path)) {
return false;
} else if (is.unaryExpression(path)) {
if (is_reactive(path.get('argument'), props, functions_are_reactive)) {
return true;
}
} else if (is.updateExpression(path)) {
if (is_reactive(path.get('argument'), props, functions_are_reactive)) {
return true;
}
} else if (is.assignmentExpression(path)) {
if (is_reactive(path.get('left'), props, functions_are_reactive)) {
return true;
}
if (is_reactive(path.get('right'), props, functions_are_reactive)) {
return true;
}
} else if (is.sequenceExpression(path)) {
for (const expression of path.get('expressions')) {
if (is_reactive(expression, props, functions_are_reactive)) {
return true;
}
}
} else if (is.conditionalExpression(path)) {
if (is_reactive(path.get('test'), props, functions_are_reactive)) {
return true;
}
if (is_reactive(path.get('consequent'), props, functions_are_reactive)) {
return true;
}
if (is_reactive(path.get('alternate'), props, functions_are_reactive)) {
return true;
}
} else if (is.binaryExpression(path)) {
if (is_reactive(path.get('left'), props, functions_are_reactive)) {
return true;
}
if (is_reactive(path.get('right'), props, functions_are_reactive)) {
return true;
}
} else if (is.logicalExpression(path)) {
if (is_reactive(path.get('left'), props, functions_are_reactive)) {
return true;
}
if (is_reactive(path.get('right'), props, functions_are_reactive)) {
return true;
}
} else if (is.arrayExpression(path)) {
for (const element of path.get('elements')) {
if (element !== null && is_reactive(element, props, functions_are_reactive)) {
return true;
}
}
} else if (is.objectExpression(path)) {
for (const property of path.get('properties')) {
if (is_reactive(property, props, functions_are_reactive)) {
return true;
}
}
} else if (is.function(path)) {
return functions_are_reactive;
} else if (is.callExpression(path)) {
if (is.identifier(path.node!.callee)) {
const prop_key = path.node!.arguments[1];
const callee_name = path.node!.callee.name;
// Check if prop
if (
is.variableDeclaration(path.parentPath?.parentPath) &&
is_svelte_import(path.get('callee')) &&
callee_name === 'prop' &&
is.literal(prop_key) &&
props !== 'unknown' &&
props !== null
) {
const prop = props.get(prop_key.value as string);
if (prop !== undefined && prop.type === 'static') {
return false;
}
}
// Check if referencing prop
const binding = path.scope!.getBinding(callee_name);
if (binding != null) {
if (
is.variableDeclarator(binding.path) &&
is.variableDeclaration(binding.path.parentPath) &&
is.callExpression(binding.path.node!.init) &&
is.identifier(binding.path.node!.init.callee) &&
binding.path.node!.init.callee.name === 'prop' &&
is_svelte_import((binding.path.get('init') as NodePath<CallExpression>).get('callee')) &&
is.literal(binding.path.node!.init.arguments[1]) &&
props !== 'unknown' &&
props !== null
) {
const prop = props.get(binding.path.node!.init.arguments[1].value as string);
if (prop !== undefined && prop.type === 'static') {
return false;
}
}
}
// Check if template
if (
is.variableDeclaration(path.parentPath?.parentPath) &&
is_svelte_import(path.get('callee')) &&
(callee_name === 'child' || callee_name === 'child_frag' || callee_name === 'sibling')
) {
return false;
}
}
return true;
} else if (is.memberExpression(path)) {
return true;
} else {
error(null, 'TODO', '');
}
return false;
}
function is_svelte_import(path: NodePath<Node>): boolean {
if (is.identifier(path)) {
const binding = path.scope!.getBinding(path.node!.name);
if (binding != null && is.importSpecifier(binding.path)) {
const import_declaration = binding.path.parentPath as NodePath<ImportDeclaration>;
if ((import_declaration.node!.source.value as string).includes('vendor')) {
return true;
}
}
}
return false;
}
function is_removed(path: NodePath<Node>): boolean {
let current_path: null | NodePath<Node> = path;
while (current_path !== null) {
if (current_path.removed) {
return true;
}
current_path = current_path.parentPath as null | NodePath<Node>;
}
return false;
}
function has_references(name: string, scope: Scope): boolean {
const binding = scope.getBinding(name)!;
let has_references = false;
for (const reference of binding.references) {
if (!is_removed(reference)) {
has_references = true;
break;
}
}
return has_references;
}
function optimize_component(component_state: ComponentState): void {
const template = component_state.template;
const is_static = component_state.is_static;
if (template.open !== null) {
const arg_to_remove = template.open
.get('declarations')[0]
.get('init')
.get('arguments')[1] as NodePath<Identifier>;
const template_path = arg_to_remove.scope!.getBinding(arg_to_remove.node!.name)!.path
.parentPath!;
template_path.remove();
if (is_static) {
template.open.remove();
} else {
arg_to_remove.remove();
}
}
if (is_static && template.close !== null) {
template.close.remove();
}
for (const [path, render_effect] of template.render_effects) {
if (render_effect.is_static) {
path.remove();
for (const anchor of render_effect.anchors) {
anchor.remove();
}
for (const expression of render_effect.expressions) {
expression.remove();
}
}
}
for (const [block_path, block] of template.blocks) {
if (is_static || block.is_static) {
if (block.type === 'each') {
const collection = block.collection;
if (is.identifier(collection)) {
const binding = block_path.scope!.getBinding(collection.name);
if (binding != null && binding.references.length === 1) {
binding.path.remove();
}
}
}
// remove the block
block_path.remove();
}
}
const reverse_template = template.traverse.slice().reverse();
for (const path of reverse_template) {
const id = path.node!.declarations[0].id! as Identifier;
if (is_static || !has_references(id.name, path.scope!)) {
if (!path.removed) {
path.remove();
}
}
}
for (const { path, state } of template.components) {
if (state.is_static) {
path.parentPath?.getPrevSibling()?.remove();
}
}
if (component_state.props !== 'unknown') {
for (const [prop, { path, type }] of component_state.props) {
if (type === 'static' && path !== null && !has_references(prop, path.scope!)) {
path.remove();
}
}
}
}
function is_optimizable(component_state: ComponentState): boolean {
if (component_state.needs_template || component_state.props === 'unknown') {
return false;
}
for (const [, { type }] of component_state.props) {
if (type === 'dynamic') {
return false;
}
}
return true;
}
export function optimize_chunk(source: string, options: OptimizeOptions): string | null {
const ast = parse(source, {
sourceType: 'module',
ecmaVersion: 13,
locations: true
});
const context: ModuleContext = {
parent: null,
needs_template: !options.hydrate,
type: 'module'
};
const state: OptimizeState = {
components: new Map(),
context
};
traverse(ast, {
$: { scope: true },
CallExpression(path: NodePath<CallExpression>) {
// TODO: mount signature changed, this needs updating
// Find the root component from a `mount(() => component(...), container)` call
const node = path.node!;
const callee = node.callee;
const args = node.arguments;
const first_arg = path.get('arguments')[0];
if (
is.identifier(callee) &&
callee.name === 'mount' &&
args.length === 2 &&
is.arrowFunctionExpression(first_arg) &&
is.callExpression(first_arg.node!.body)
) {
if (!is_svelte_import(path.get('callee'))) {
return;
}
const body = first_arg.get('body') as NodePath<CallExpression>;
const component_callee = body.node!.callee;
const component_args = body.node!.arguments[1];
if (!is.identifier(component_callee) || component_args == null) {
return;
}
const component_binding = path.scope!.getBinding(component_callee.name);
if (
component_binding == null ||
!is.functionDeclaration(component_binding.path) ||
component_binding.references.length !== 1
) {
return;
}
const component = component_binding.path;
const component_node = component.node!;
if (
component_node.params.length !== 3 ||
!is.identifier(component_node.params[1]) ||
component_node.params[1].name !== '$$props'
) {
return;
}
// We have the root render node
const context: ComponentContext = {
parent: state.context as ModuleContext,
needs_template: state.context.needs_template,
type: 'component'
};
state.context = context;
const props = get_props(body.get('arguments')[1], null);
visit_component(component, null, props, state);
state.context = state.context.parent;
}
}
});
for (const [, component_state] of state.components) {
if (is_optimizable(component_state)) {
optimize_component(component_state);
}
}
return print(ast as Node).code;
}

@ -53,7 +53,7 @@ export function parse_expression_at(source, typescript, index) {
* in JS code and so that `prettier-plugin-svelte` doesn't remove all comments when formatting.
* @param {string} source
*/
export function get_comment_handlers(source) {
function get_comment_handlers(source) {
/**
* @typedef {import('estree').Comment & {
* start: number;
@ -119,7 +119,7 @@ export function get_comment_handlers(source) {
* @param {string} source
* @param {import('acorn').Node} node
*/
export function amend(source, node) {
function amend(source, node) {
return walk(node, null, {
_(node, context) {
// @ts-expect-error

@ -1,41 +0,0 @@
const regex_tabs = /^\t+/;
/** @param {string} str */
function tabs_to_spaces(str) {
return str.replace(regex_tabs, /** @param {any} match */ (match) => match.split('\t').join(' '));
}
/**
* @param {string} source
* @param {number} line
* @param {number} column
*/
export default function get_code_frame(source, line, column) {
const lines = source.split('\n');
const frame_start = Math.max(0, line - 2);
const frame_end = Math.min(line + 3, lines.length);
const digits = String(frame_end + 1).length;
return lines
.slice(frame_start, frame_end)
.map(
/**
* @param {any} str
* @param {any} i
*/ (str, i) => {
const is_error_line = frame_start + i === line;
const line_num = String(i + frame_start + 1).padStart(digits, ' ');
if (is_error_line) {
const indicator =
' '.repeat(digits + 2 + tabs_to_spaces(str.slice(0, column)).length) + '^';
return `${line_num}: ${tabs_to_spaces(str)}\n${indicator}`;
}
return `${line_num}: ${tabs_to_spaces(str)}`;
}
)
.join('\n');
}

@ -1,24 +0,0 @@
/** @param {import('#compiler').TemplateNode} node */
export function to_string(node) {
switch (node.type) {
case 'IfBlock':
return '{#if} block';
case 'AwaitBlock':
return '{#await} block';
case 'EachBlock':
return '{#each} block';
case 'HtmlTag':
return '{@html} block';
case 'DebugTag':
return '{@debug} block';
case 'ConstTag':
return '{@const} tag';
case 'RegularElement':
case 'Component':
case 'SlotElement':
case 'TitleElement':
return `<${node.name}> tag`;
default:
return node.type;
}
}

@ -1,14 +0,0 @@
/**
* Pushes all `items` into `array` using `push`, therefore mutating the array.
* We do this for memory and perf reasons, and because `array.push(...items)` would
* run into a "max call stack size exceeded" error with too many items (~65k).
* @param {T[]} array undefined
* @param {T[]} items undefined
* @template T
* @returns {void}
*/
export function push_array(array, items) {
for (let i = 0; i < items.length; i++) {
array.push(items[i]);
}
}

@ -1,11 +0,0 @@
import { regex_starts_with_whitespaces, regex_ends_with_whitespaces } from '../../patterns.js';
/** @param {string} str */
export function trim_start(str) {
return str.replace(regex_starts_with_whitespaces, '');
}
/** @param {string} str */
export function trim_end(str) {
return str.replace(regex_ends_with_whitespaces, '');
}

@ -837,7 +837,7 @@ function is_known_safe_call(node, context) {
* @param {import('estree').ArrowFunctionExpression | import('estree').FunctionExpression | import('estree').FunctionDeclaration} node
* @param {import('./types').Context} context
*/
export const function_visitor = (node, context) => {
const function_visitor = (node, context) => {
// TODO retire this in favour of a more general solution based on bindings
node.metadata = {
// module context -> already hoisted

@ -334,7 +334,7 @@ function is_tag_valid_with_parent(tag, parent_tag) {
/**
* @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, import('./types.js').AnalysisState>}
*/
export const validation = {
const validation = {
BindDirective(node, context) {
validate_no_const_assignment(node, node.expression, context.state.scope, true);

@ -28,48 +28,6 @@ export const VoidElements = [
export const PassiveEvents = ['wheel', 'touchstart', 'touchmove', 'touchend', 'touchcancel'];
// TODO this is currently unused
export const ElementBindings = [
'this',
'value',
'checked',
'files',
'group',
'visibilityState',
'fullscreenElement',
'innerWidth',
'innerHeight',
'outerWidth',
'outerHeight',
'scrollX',
'scrollY',
'online',
'devicePixelRatio',
'naturalWidth',
'naturalHeight',
'clientWidth',
'clientHeight',
'offsetWidth',
'offsetHeight',
'duration',
'buffered',
'played',
'seekable',
'seeking',
'ended',
'readyState',
'currentTime',
'playbackRate',
'paused',
'volume',
'muted',
'innerHTML',
'innerText',
'textContent',
'open',
'indeterminate'
];
export const Runes = /** @type {const} */ ([
'$state',
'$state.frozen',

@ -16,8 +16,6 @@ export const regex_not_newline_characters = /[^\n]/g;
export const regex_is_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/;
export const regex_special_chars = /[\d+`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/;
export const regex_starts_with_vowel = /^[aeiou]/;
export const regex_heading_tags = /^h[1-6]$/;
export const regex_illegal_attribute_character = /(^[0-9-.])|[\^$@%&#?!|()[\]{}^*+~;]/;

@ -38,7 +38,7 @@ export function is_text_attribute(attribute) {
* @param {import('#compiler').Attribute} attribute
* @returns {attribute is import('#compiler').Attribute & { value: [import('#compiler').ExpressionTag] }}
*/
export function is_expression_attribute(attribute) {
function is_expression_attribute(attribute) {
return (
attribute.value !== true &&
attribute.value.length === 1 &&

@ -57,7 +57,7 @@ export function async(func) {
* @param {import('estree').Expression} argument
* @returns {import('estree').AwaitExpression}
*/
export function await_builder(argument) {
function await_builder(argument) {
return { type: 'AwaitExpression', argument };
}
@ -236,7 +236,7 @@ export function private_id(name) {
* @param {string} local
* @returns {import('estree').ImportNamespaceSpecifier}
*/
export function import_namespace(local) {
function import_namespace(local) {
return {
type: 'ImportNamespaceSpecifier',
local: id(local)
@ -592,7 +592,6 @@ export function throw_error(str) {
export {
await_builder as await,
new_builder as new,
let_builder as let,
const_builder as const,
var_builder as var,

@ -1,7 +1,7 @@
export const EACH_ITEM_REACTIVE = 1;
export const EACH_INDEX_REACTIVE = 1 << 1;
export const EACH_KEYED = 1 << 2;
export const EACH_PROXIED = 1 << 3;
/** See EachBlock interface metadata.is_controlled for an explanation what this is */
export const EACH_IS_CONTROLLED = 1 << 3;
export const EACH_IS_ANIMATED = 1 << 4;

@ -16,14 +16,6 @@ function run_tasks(now) {
if (tasks.size !== 0) raf.tick(run_tasks);
}
/**
* For testing purposes only!
* @returns {void}
*/
export function clear_loops() {
tasks.clear();
}
/**
* Creates a new task that runs on each raf frame
* until it returns a falsy value or is aborted

@ -287,12 +287,6 @@ const state_proxy_handler = {
}
};
/** @param {any} object */
export function observe(object) {
const metadata = object[STATE_SYMBOL];
if (metadata) get(metadata.v);
}
if (DEV) {
state_proxy_handler.setPrototypeOf = () => {
throw new Error('Cannot set prototype of $state object');

@ -3,7 +3,6 @@
export var is_array = Array.isArray;
export var array_from = Array.from;
export var object_keys = Object.keys;
export var object_entries = Object.entries;
export var object_assign = Object.assign;
export var is_frozen = Object.isFrozen;
export var object_freeze = Object.freeze;

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save