Home / File/ transform-async.js — svelte Source File

transform-async.js — svelte Source File

Architecture documentation for transform-async.js, a javascript file in the svelte codebase. 1 imports, 2 dependents.

File javascript Compiler Transformer 1 imports 2 dependents 1 functions

Entity Profile

Dependency Diagram

graph LR
  4a72fe76_77b1_749a_ab61_f53e30c4916a["transform-async.js"]
  95c28355_f14c_c3cd_5a03_d5a53ca255bc["builders"]
  4a72fe76_77b1_749a_ab61_f53e30c4916a --> 95c28355_f14c_c3cd_5a03_d5a53ca255bc
  446a5632_54bb_cf7e_dbdc_33bec913df9e["Program.js"]
  446a5632_54bb_cf7e_dbdc_33bec913df9e --> 4a72fe76_77b1_749a_ab61_f53e30c4916a
  a458b454_095e_18fe_3040_d9dd3fae8000["Program.js"]
  a458b454_095e_18fe_3040_d9dd3fae8000 --> 4a72fe76_77b1_749a_ab61_f53e30c4916a
  style 4a72fe76_77b1_749a_ab61_f53e30c4916a fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

/** @import * as ESTree from 'estree' */
/** @import { ComponentAnalysis } from '../../types' */
import * as b from '#compiler/builders';

/**
 * Transforms the body of the instance script in such a way that await expressions are made non-blocking as much as possible.
 *
 * Example Transformation:
 * ```js
 * let x = 1;
 * let data = await fetch('/api');
 * let y = data.value;
 * ```
 * becomes:
 * ```js
 * let x = 1;
 * var data, y;
 * var $$promises = $.run([
 *   () => data = await fetch('/api'),
 *   () => y = data.value
 * ]);
 * ```
 * where `$$promises` is an array of promises that are resolved in the order they are declared,
 * and which expressions in the template can await on like `await $$promises[0]` which means they
 * wouldn't have to wait for e.g. `$$promises[1]` to resolve.
 *
 * @param {ComponentAnalysis['instance_body']} instance_body
 * @param {ESTree.Expression} runner
 * @param {(node: ESTree.Node) => ESTree.Node} transform
 * @returns {Array<ESTree.Statement | ESTree.VariableDeclaration>}
 */
export function transform_body(instance_body, runner, transform) {
	// Any sync statements before the first await expression
	const statements = instance_body.sync.map(
		(node) => /** @type {ESTree.Statement | ESTree.VariableDeclaration} */ (transform(node))
	);

	// Declarations for the await expressions (they will assign to them; need to be hoisted to be available in whole instance scope)
	if (instance_body.declarations.length > 0) {
		statements.push(
			b.declaration(
				'var',
				instance_body.declarations.map((id) => b.declarator(id))
			)
		);
	}

	// Thunks for the await expressions
	if (instance_body.async.length > 0) {
		const thunks = instance_body.async.map((s) => {
			if (s.node.type === 'VariableDeclarator') {
				const visited = /** @type {ESTree.VariableDeclaration | ESTree.EmptyStatement} */ (
					transform(b.var(s.node.id, s.node.init))
				);

				const statements =
					visited.type === 'VariableDeclaration'
						? visited.declarations.map((node) => {
								if (
									node.id.type === 'Identifier' &&
									(node.id.name.startsWith('$$d') || node.id.name.startsWith('$$array'))
								) {
									// this is an intermediate declaration created in VariableDeclaration.js;
									// subsequent statements depend on it
									return b.var(node.id, node.init);
								}

								return b.stmt(b.assignment('=', node.id, node.init ?? b.void0));
							})
						: [];

				if (statements.length === 1) {
					const statement = /** @type {ESTree.ExpressionStatement} */ (statements[0]);
					return b.thunk(statement.expression, s.has_await);
				}

				return b.thunk(b.block(statements), s.has_await);
			}

			if (s.node.type === 'ClassDeclaration') {
				return b.thunk(
					b.assignment(
						'=',
						s.node.id,
						/** @type {ESTree.ClassExpression} */ ({ ...s.node, type: 'ClassExpression' })
					),
					s.has_await
				);
			}

			if (s.node.type === 'ExpressionStatement') {
				// the expression may be a $inspect call, which will be transformed into an empty statement
				const expression = /** @type {ESTree.Expression | ESTree.EmptyStatement} */ (
					transform(s.node.expression)
				);

				if (expression.type === 'EmptyStatement') {
					return null;
				}

				return expression.type === 'AwaitExpression'
					? b.thunk(expression, true)
					: b.thunk(b.unary('void', expression), s.has_await);
			}

			return b.thunk(b.block([/** @type {ESTree.Statement} */ (transform(s.node))]), s.has_await);
		});

		// TODO get the `$$promises` ID from scope
		statements.push(b.var('$$promises', b.call(runner, b.array(thunks))));
	}

	return statements;
}

Domain

Subdomains

Functions

Dependencies

  • builders

Frequently Asked Questions

What does transform-async.js do?
transform-async.js is a source file in the svelte codebase, written in javascript. It belongs to the Compiler domain, Transformer subdomain.
What functions are defined in transform-async.js?
transform-async.js defines 1 function(s): transform_body.
What does transform-async.js depend on?
transform-async.js imports 1 module(s): builders.
What files import transform-async.js?
transform-async.js is imported by 2 file(s): Program.js, Program.js.
Where is transform-async.js in the architecture?
transform-async.js is located at packages/svelte/src/compiler/phases/3-transform/shared/transform-async.js (domain: Compiler, subdomain: Transformer, directory: packages/svelte/src/compiler/phases/3-transform/shared).

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free