rooklang 0.0.0-stage → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +177 -2
- package/README.ru.md +178 -0
- package/dist/ast/declarations.d.ts +185 -0
- package/dist/ast/declarations.js +1 -0
- package/dist/ast/expressions.d.ts +201 -0
- package/dist/ast/expressions.js +1 -0
- package/dist/ast/markup.d.ts +141 -0
- package/dist/ast/markup.js +1 -0
- package/dist/ast/statements.d.ts +173 -0
- package/dist/ast/statements.js +1 -0
- package/dist/ast.d.ts +18 -0
- package/dist/ast.js +18 -0
- package/dist/attrs.d.ts +8 -0
- package/dist/attrs.js +23 -0
- package/dist/browser.d.ts +30 -0
- package/dist/browser.js +36 -0
- package/dist/build.d.ts +48 -0
- package/dist/build.js +112 -0
- package/dist/checker/assignments.d.ts +14 -0
- package/dist/checker/assignments.js +197 -0
- package/dist/checker/base.d.ts +124 -0
- package/dist/checker/base.js +180 -0
- package/dist/checker/bigint.d.ts +15 -0
- package/dist/checker/bigint.js +85 -0
- package/dist/checker/builtins.d.ts +9 -0
- package/dist/checker/builtins.js +307 -0
- package/dist/checker/bytes.d.ts +11 -0
- package/dist/checker/bytes.js +72 -0
- package/dist/checker/calls.d.ts +23 -0
- package/dist/checker/calls.js +210 -0
- package/dist/checker/channel.d.ts +14 -0
- package/dist/checker/channel.js +44 -0
- package/dist/checker/channels.d.ts +9 -0
- package/dist/checker/channels.js +95 -0
- package/dist/checker/checker.d.ts +4 -0
- package/dist/checker/checker.js +22 -0
- package/dist/checker/classes.d.ts +24 -0
- package/dist/checker/classes.js +223 -0
- package/dist/checker/completion-names.d.ts +11 -0
- package/dist/checker/completion-names.js +100 -0
- package/dist/checker/completion.d.ts +25 -0
- package/dist/checker/completion.js +222 -0
- package/dist/checker/component-values.d.ts +11 -0
- package/dist/checker/component-values.js +88 -0
- package/dist/checker/components.d.ts +37 -0
- package/dist/checker/components.js +287 -0
- package/dist/checker/context.d.ts +196 -0
- package/dist/checker/context.js +35 -0
- package/dist/checker/control-flow.d.ts +24 -0
- package/dist/checker/control-flow.js +237 -0
- package/dist/checker/declarations.d.ts +26 -0
- package/dist/checker/declarations.js +259 -0
- package/dist/checker/decorator-exports.d.ts +5 -0
- package/dist/checker/decorator-exports.js +40 -0
- package/dist/checker/decorator-members.d.ts +28 -0
- package/dist/checker/decorator-members.js +140 -0
- package/dist/checker/decorator-wrappers.d.ts +20 -0
- package/dist/checker/decorator-wrappers.js +132 -0
- package/dist/checker/decorators.d.ts +28 -0
- package/dist/checker/decorators.js +265 -0
- package/dist/checker/dom-svg.d.ts +7 -0
- package/dist/checker/dom-svg.js +19 -0
- package/dist/checker/dom.d.ts +22 -0
- package/dist/checker/dom.js +361 -0
- package/dist/checker/expressions.d.ts +32 -0
- package/dist/checker/expressions.js +244 -0
- package/dist/checker/flow.d.ts +18 -0
- package/dist/checker/flow.js +134 -0
- package/dist/checker/forwarding.d.ts +15 -0
- package/dist/checker/forwarding.js +78 -0
- package/dist/checker/functions.d.ts +24 -0
- package/dist/checker/functions.js +154 -0
- package/dist/checker/go-for.d.ts +12 -0
- package/dist/checker/go-for.js +93 -0
- package/dist/checker/goroutines.d.ts +19 -0
- package/dist/checker/goroutines.js +110 -0
- package/dist/checker/helpers.d.ts +35 -0
- package/dist/checker/helpers.js +162 -0
- package/dist/checker/imports.d.ts +7 -0
- package/dist/checker/imports.js +83 -0
- package/dist/checker/initializers.d.ts +22 -0
- package/dist/checker/initializers.js +104 -0
- package/dist/checker/iterables.d.ts +5 -0
- package/dist/checker/iterables.js +17 -0
- package/dist/checker/iterators.d.ts +13 -0
- package/dist/checker/iterators.js +95 -0
- package/dist/checker/loops.d.ts +10 -0
- package/dist/checker/loops.js +82 -0
- package/dist/checker/markup.d.ts +28 -0
- package/dist/checker/markup.js +220 -0
- package/dist/checker/members.d.ts +29 -0
- package/dist/checker/members.js +233 -0
- package/dist/checker/operators.d.ts +13 -0
- package/dist/checker/operators.js +177 -0
- package/dist/checker/promise.d.ts +17 -0
- package/dist/checker/promise.js +49 -0
- package/dist/checker/refs.d.ts +26 -0
- package/dist/checker/refs.js +136 -0
- package/dist/checker/resolution.d.ts +23 -0
- package/dist/checker/resolution.js +173 -0
- package/dist/checker/statements.d.ts +28 -0
- package/dist/checker/statements.js +212 -0
- package/dist/checker/styles.d.ts +14 -0
- package/dist/checker/styles.js +49 -0
- package/dist/checker/transfer.d.ts +5 -0
- package/dist/checker/transfer.js +83 -0
- package/dist/checker/types/bytes.d.ts +4 -0
- package/dist/checker/types/bytes.js +51 -0
- package/dist/checker/types/classes.d.ts +22 -0
- package/dist/checker/types/classes.js +93 -0
- package/dist/checker/types/constructors.d.ts +27 -0
- package/dist/checker/types/constructors.js +129 -0
- package/dist/checker/types/generics.d.ts +20 -0
- package/dist/checker/types/generics.js +75 -0
- package/dist/checker/types/lazy.d.ts +30 -0
- package/dist/checker/types/lazy.js +92 -0
- package/dist/checker/types/model.d.ts +149 -0
- package/dist/checker/types/model.js +15 -0
- package/dist/checker/types/params.d.ts +7 -0
- package/dist/checker/types/params.js +220 -0
- package/dist/checker/types/printing.d.ts +6 -0
- package/dist/checker/types/printing.js +109 -0
- package/dist/checker/types/relations.d.ts +16 -0
- package/dist/checker/types/relations.js +294 -0
- package/dist/checker/types.d.ts +9 -0
- package/dist/checker/types.js +10 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +193 -0
- package/dist/codegen/analysis.d.ts +18 -0
- package/dist/codegen/analysis.js +144 -0
- package/dist/codegen/attributes.d.ts +40 -0
- package/dist/codegen/attributes.js +227 -0
- package/dist/codegen/calls.d.ts +22 -0
- package/dist/codegen/calls.js +106 -0
- package/dist/codegen/chan-helpers.d.ts +2 -0
- package/dist/codegen/chan-helpers.js +253 -0
- package/dist/codegen/component-helpers.d.ts +33 -0
- package/dist/codegen/component-helpers.js +18 -0
- package/dist/codegen/component-props.d.ts +42 -0
- package/dist/codegen/component-props.js +173 -0
- package/dist/codegen/component-values.d.ts +27 -0
- package/dist/codegen/component-values.js +146 -0
- package/dist/codegen/components.d.ts +53 -0
- package/dist/codegen/components.js +268 -0
- package/dist/codegen/control-flow.d.ts +25 -0
- package/dist/codegen/control-flow.js +152 -0
- package/dist/codegen/control-statements.d.ts +28 -0
- package/dist/codegen/control-statements.js +226 -0
- package/dist/codegen/creation.d.ts +31 -0
- package/dist/codegen/creation.js +113 -0
- package/dist/codegen/early-returns.d.ts +59 -0
- package/dist/codegen/early-returns.js +244 -0
- package/dist/codegen/element-helpers.d.ts +12 -0
- package/dist/codegen/element-helpers.js +54 -0
- package/dist/codegen/elements.d.ts +71 -0
- package/dist/codegen/elements.js +293 -0
- package/dist/codegen/emitter.d.ts +135 -0
- package/dist/codegen/emitter.js +296 -0
- package/dist/codegen/expressions.d.ts +49 -0
- package/dist/codegen/expressions.js +262 -0
- package/dist/codegen/functions.d.ts +28 -0
- package/dist/codegen/functions.js +170 -0
- package/dist/codegen/go-helpers.d.ts +9 -0
- package/dist/codegen/go-helpers.js +307 -0
- package/dist/codegen/helpers.d.ts +10 -0
- package/dist/codegen/helpers.js +356 -0
- package/dist/codegen/imported.d.ts +38 -0
- package/dist/codegen/imported.js +71 -0
- package/dist/codegen/js.d.ts +20 -0
- package/dist/codegen/js.js +113 -0
- package/dist/codegen/mutations.d.ts +10 -0
- package/dist/codegen/mutations.js +102 -0
- package/dist/codegen/parallel.d.ts +7 -0
- package/dist/codegen/parallel.js +63 -0
- package/dist/codegen/reactive.d.ts +95 -0
- package/dist/codegen/reactive.js +280 -0
- package/dist/codegen/refs.d.ts +62 -0
- package/dist/codegen/refs.js +160 -0
- package/dist/codegen/select-helpers.d.ts +2 -0
- package/dist/codegen/select-helpers.js +135 -0
- package/dist/codegen/simple-statements.d.ts +42 -0
- package/dist/codegen/simple-statements.js +253 -0
- package/dist/codegen/statements.d.ts +22 -0
- package/dist/codegen/statements.js +142 -0
- package/dist/codegen/styles.d.ts +54 -0
- package/dist/codegen/styles.js +157 -0
- package/dist/codegen/syntax.d.ts +18 -0
- package/dist/codegen/syntax.js +70 -0
- package/dist/codegen/thread-helpers.d.ts +2 -0
- package/dist/codegen/thread-helpers.js +198 -0
- package/dist/codegen/updates.d.ts +51 -0
- package/dist/codegen/updates.js +201 -0
- package/dist/codegen/web-components.d.ts +20 -0
- package/dist/codegen/web-components.js +149 -0
- package/dist/compile-file.d.ts +11 -0
- package/dist/compile-file.js +24 -0
- package/dist/compile.d.ts +53 -0
- package/dist/compile.js +187 -0
- package/dist/completion.d.ts +10 -0
- package/dist/completion.js +134 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +44 -0
- package/dist/css/hash.d.ts +1 -0
- package/dist/css/hash.js +10 -0
- package/dist/css/parse.d.ts +42 -0
- package/dist/css/parse.js +138 -0
- package/dist/css/print.d.ts +9 -0
- package/dist/css/print.js +35 -0
- package/dist/css/selectors.d.ts +29 -0
- package/dist/css/selectors.js +168 -0
- package/dist/declarations.d.ts +3 -0
- package/dist/declarations.js +207 -0
- package/dist/decorator-copy.d.ts +18 -0
- package/dist/decorator-copy.js +158 -0
- package/dist/decorators.d.ts +61 -0
- package/dist/decorators.js +241 -0
- package/dist/diagnostics.d.ts +17 -0
- package/dist/diagnostics.js +22 -0
- package/dist/go-for.d.ts +26 -0
- package/dist/go-for.js +155 -0
- package/dist/goroutines.d.ts +37 -0
- package/dist/goroutines.js +253 -0
- package/dist/html-tag.d.ts +21 -0
- package/dist/html-tag.js +103 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +55 -0
- package/dist/inline-packages.d.ts +32 -0
- package/dist/inline-packages.js +129 -0
- package/dist/iterators.d.ts +10 -0
- package/dist/iterators.js +33 -0
- package/dist/lexer/base.d.ts +24 -0
- package/dist/lexer/base.js +87 -0
- package/dist/lexer/lexer.d.ts +8 -0
- package/dist/lexer/lexer.js +134 -0
- package/dist/lexer/literals.d.ts +18 -0
- package/dist/lexer/literals.js +203 -0
- package/dist/lexer/markup.d.ts +10 -0
- package/dist/lexer/markup.js +93 -0
- package/dist/lexer/style.d.ts +17 -0
- package/dist/lexer/style.js +97 -0
- package/dist/lexer/tables.d.ts +53 -0
- package/dist/lexer/tables.js +101 -0
- package/dist/lexer/token.d.ts +42 -0
- package/dist/lexer/token.js +108 -0
- package/dist/loader.d.ts +1 -0
- package/dist/loader.js +50 -0
- package/dist/methods.d.ts +5 -0
- package/dist/methods.js +81 -0
- package/dist/modules.d.ts +3 -0
- package/dist/modules.js +49 -0
- package/dist/names.d.ts +23 -0
- package/dist/names.js +267 -0
- package/dist/parser/base.d.ts +96 -0
- package/dist/parser/base.js +202 -0
- package/dist/parser/classes.d.ts +8 -0
- package/dist/parser/classes.js +164 -0
- package/dist/parser/control-flow.d.ts +29 -0
- package/dist/parser/control-flow.js +232 -0
- package/dist/parser/declarations.d.ts +27 -0
- package/dist/parser/declarations.js +238 -0
- package/dist/parser/decorators.d.ts +30 -0
- package/dist/parser/decorators.js +176 -0
- package/dist/parser/expressions.d.ts +15 -0
- package/dist/parser/expressions.js +255 -0
- package/dist/parser/literals.d.ts +27 -0
- package/dist/parser/literals.js +206 -0
- package/dist/parser/markup.d.ts +22 -0
- package/dist/parser/markup.js +193 -0
- package/dist/parser/parser.d.ts +14 -0
- package/dist/parser/parser.js +22 -0
- package/dist/parser/simple-statements.d.ts +22 -0
- package/dist/parser/simple-statements.js +156 -0
- package/dist/parser/statements.d.ts +37 -0
- package/dist/parser/statements.js +267 -0
- package/dist/parser/syntax.d.ts +51 -0
- package/dist/parser/syntax.js +173 -0
- package/dist/parser/types.d.ts +23 -0
- package/dist/parser/types.js +218 -0
- package/dist/recursion.d.ts +25 -0
- package/dist/recursion.js +170 -0
- package/dist/refs.d.ts +49 -0
- package/dist/refs.js +210 -0
- package/dist/run.d.ts +1 -0
- package/dist/run.js +21 -0
- package/dist/source.d.ts +15 -0
- package/dist/source.js +34 -0
- package/dist/style-modules.d.ts +17 -0
- package/dist/style-modules.js +49 -0
- package/dist/styles.d.ts +36 -0
- package/dist/styles.js +160 -0
- package/dist/svg.d.ts +8 -0
- package/dist/svg.js +77 -0
- package/dist/ts-types.d.ts +11 -0
- package/dist/ts-types.js +133 -0
- package/dist/typed-arrays.d.ts +8 -0
- package/dist/typed-arrays.js +43 -0
- package/dist/typescript/convert-base.d.ts +42 -0
- package/dist/typescript/convert-base.js +135 -0
- package/dist/typescript/convert-objects.d.ts +28 -0
- package/dist/typescript/convert-objects.js +245 -0
- package/dist/typescript/convert.d.ts +14 -0
- package/dist/typescript/convert.js +67 -0
- package/dist/typescript/importer.d.ts +37 -0
- package/dist/typescript/importer.js +152 -0
- package/dist/typescript/library.d.ts +23 -0
- package/dist/typescript/library.js +81 -0
- package/dist/vite.d.ts +11 -0
- package/dist/vite.js +86 -0
- package/dist/walk-types.d.ts +4 -0
- package/dist/walk-types.js +56 -0
- package/dist/walk.d.ts +5 -0
- package/dist/walk.js +315 -0
- package/package.json +104 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { type Type } from '../checker/types.ts';
|
|
3
|
+
/** What can be inside markup: children of an element, or statements of a markup block. */
|
|
4
|
+
export type Content = ast.JsxChild | ast.Statement;
|
|
5
|
+
export type ControlStatement = ast.JsxStatementContainer['statement'];
|
|
6
|
+
/** `onClick` → `click`, `onKeyDown` → `keydown`; JSX spells `dblclick` as `onDoubleClick`. */
|
|
7
|
+
export declare function eventName(attribute: string): string;
|
|
8
|
+
/** How a child expression is appended: as is, spread, after a null check, or by $$append. */
|
|
9
|
+
export declare function contentKind(node: ast.Expression, given: Type | undefined): 'value' | 'list' | 'nullable' | 'unknown';
|
|
10
|
+
export declare function isPlainContent(type: Type): boolean;
|
|
11
|
+
/** Whether a name is used inside a node, e.g. `event` in a handler. */
|
|
12
|
+
export declare function mentions(node: ast.Node, name: string): boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { widenLiterals } from "../checker/types.js";
|
|
2
|
+
import { forEachChild } from "../walk.js";
|
|
3
|
+
/** `onClick` → `click`, `onKeyDown` → `keydown`; JSX spells `dblclick` as `onDoubleClick`. */
|
|
4
|
+
export function eventName(attribute) {
|
|
5
|
+
return attribute === 'onDoubleClick' ? 'dblclick' : attribute.slice(2).toLowerCase();
|
|
6
|
+
}
|
|
7
|
+
/** How a child expression is appended: as is, spread, after a null check, or by $$append. */
|
|
8
|
+
export function contentKind(node, given) {
|
|
9
|
+
// `"primary" | "ghost"` is text like `string`.
|
|
10
|
+
const type = given && widenLiterals(given);
|
|
11
|
+
if (type === undefined) {
|
|
12
|
+
// Without types only literals are known for sure.
|
|
13
|
+
return node.kind === 'StringLiteral' ||
|
|
14
|
+
node.kind === 'NumberLiteral' ||
|
|
15
|
+
node.kind === 'TemplateLiteral'
|
|
16
|
+
? 'value'
|
|
17
|
+
: 'unknown';
|
|
18
|
+
}
|
|
19
|
+
switch (type.kind) {
|
|
20
|
+
case 'string':
|
|
21
|
+
case 'number':
|
|
22
|
+
case 'object':
|
|
23
|
+
case 'class':
|
|
24
|
+
return 'value';
|
|
25
|
+
case 'array':
|
|
26
|
+
return isPlainContent(type.element) ? 'list' : 'unknown';
|
|
27
|
+
case 'nullable':
|
|
28
|
+
return isPlainContent(type.type) ? 'nullable' : 'unknown';
|
|
29
|
+
default:
|
|
30
|
+
return 'unknown';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function isPlainContent(type) {
|
|
34
|
+
return (type.kind === 'string' ||
|
|
35
|
+
type.kind === 'number' ||
|
|
36
|
+
type.kind === 'object' ||
|
|
37
|
+
type.kind === 'class');
|
|
38
|
+
}
|
|
39
|
+
/** Whether a name is used inside a node, e.g. `event` in a handler. */
|
|
40
|
+
export function mentions(node, name) {
|
|
41
|
+
let found = false;
|
|
42
|
+
const visit = (child) => {
|
|
43
|
+
if (found)
|
|
44
|
+
return;
|
|
45
|
+
if (child.kind === 'Identifier' && child.name === name)
|
|
46
|
+
found = true;
|
|
47
|
+
else if (child.kind === 'MemberExpression')
|
|
48
|
+
visit(child.object);
|
|
49
|
+
else
|
|
50
|
+
forEachChild(child, visit);
|
|
51
|
+
};
|
|
52
|
+
visit(node);
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import { CreationEmitter } from './creation.ts';
|
|
3
|
+
import { type Content, type ControlStatement } from './element-helpers.ts';
|
|
4
|
+
import type { Live, Source } from './reactive.ts';
|
|
5
|
+
export type { ControlStatement } from './element-helpers.ts';
|
|
6
|
+
/**
|
|
7
|
+
* Markup: `<a href="/">Link {name}</a>` becomes statements that create the element. When the
|
|
8
|
+
* expression is evaluated exactly once they go before the statement that contains it; otherwise
|
|
9
|
+
* the element is created inside a function that is called right away.
|
|
10
|
+
*
|
|
11
|
+
* Markup that a component creates once (what it returns, and elements declared at the top level
|
|
12
|
+
* of its body) is live: parts that read state are updated when the state changes. `live` is where
|
|
13
|
+
* their updates go. `{if ...}`, `{switch ...}` and `{for ...}` become plain JS control flow that
|
|
14
|
+
* appends elements, unless they depend on state; see ControlFlowEmitter.
|
|
15
|
+
*/
|
|
16
|
+
export declare abstract class ElementEmitter extends CreationEmitter {
|
|
17
|
+
/** A tag that takes its component from a value; implemented by ComponentValueEmitter. */
|
|
18
|
+
protected abstract valueTag(node: ast.ElementExpression, value: ast.Expression, live: Live | null): string;
|
|
19
|
+
/** Inlines a component; implemented by ComponentEmitter. */
|
|
20
|
+
protected abstract expand(node: ast.ElementExpression, component: ast.ComponentDeclaration, live: Live | null): string;
|
|
21
|
+
/**
|
|
22
|
+
* The element a ref created for markup to fill in; not `created` when it may be missing, as
|
|
23
|
+
* `$$root` of a function. Implemented by RefEmitter.
|
|
24
|
+
*/
|
|
25
|
+
protected abstract presetElement(node: ast.ElementExpression): {
|
|
26
|
+
name: string;
|
|
27
|
+
created: boolean;
|
|
28
|
+
} | null;
|
|
29
|
+
/** The class of the style an element belongs to; implemented by StyleEmitter. */
|
|
30
|
+
protected abstract scopeOf(node: ast.ElementExpression): string | null;
|
|
31
|
+
/** Control flow in live markup that depends on state; implemented by ControlFlowEmitter. */
|
|
32
|
+
protected abstract liveControl(statement: ControlStatement, live: Live, sources: ReadonlySet<Source>): string;
|
|
33
|
+
protected element(node: ast.ElementExpression): string;
|
|
34
|
+
protected elementDeclaration(declaration: string, node: ast.ElementExpression): void;
|
|
35
|
+
/** Where the updates of `const x = <markup>` go: markup at the top level of a component is live. */
|
|
36
|
+
protected declaredLive(node: ast.ElementExpression): Live | null;
|
|
37
|
+
protected elementStatement(node: ast.JsxElementStatement): void;
|
|
38
|
+
/** A number for a generated name: `$$li1`, `$$updateCount2`, ... */
|
|
39
|
+
protected nextId(): number;
|
|
40
|
+
/** Writes the code for an element or a component and returns the variable with the result. */
|
|
41
|
+
protected create(node: ast.ElementExpression, live: Live | null): string;
|
|
42
|
+
protected componentOf(node: ast.ElementExpression): ast.ComponentDeclaration | undefined;
|
|
43
|
+
/** `section.content` of `<section.content />`, or `Page` of `<Page />` with a variable `Page`. */
|
|
44
|
+
protected tagValue(node: ast.ElementExpression): ast.Expression | null;
|
|
45
|
+
/** Markup that creates an element or a fragment, not a component. */
|
|
46
|
+
protected isElement(node: ast.ElementExpression): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Writes the statements that create the element and returns the name of its variable.
|
|
49
|
+
* `declaration` is `const link` for `const link = <a>`; otherwise a temporary name is used.
|
|
50
|
+
*/
|
|
51
|
+
protected build(node: ast.ElementExpression, declaration: string | null, live: Live | null): string;
|
|
52
|
+
/**
|
|
53
|
+
* Children are appended in order; consecutive ones that need no checks go into one `append`.
|
|
54
|
+
* Values whose type allows null, or is not known, are checked before they are appended. The
|
|
55
|
+
* statements of markup blocks are handled here too.
|
|
56
|
+
*/
|
|
57
|
+
protected children(element: string, children: readonly Content[], live: Live | null): void;
|
|
58
|
+
protected withContentTarget<T>(element: string, emit: () => T): T;
|
|
59
|
+
/**
|
|
60
|
+
* `{value}` that depends on state. Text becomes a text node whose data is replaced; other
|
|
61
|
+
* content is kept by the $$content helper, which replaces its nodes. Returns what to append.
|
|
62
|
+
*/
|
|
63
|
+
protected liveChild(expression: ast.Expression, live: Live, sources: ReadonlySet<Source>): string;
|
|
64
|
+
/**
|
|
65
|
+
* `const` in a markup block. When its value depends on state, it is computed again on updates,
|
|
66
|
+
* before the parts that read it.
|
|
67
|
+
*/
|
|
68
|
+
protected blockConst(node: ast.VariableDeclaration, live: Live | null): void;
|
|
69
|
+
/** The expression if it can be repeated, otherwise a temporary that holds its value. */
|
|
70
|
+
protected once(node: ast.Expression): string;
|
|
71
|
+
}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { widenLiterals } from "../checker/types.js";
|
|
2
|
+
import { constantAttributes } from "../refs.js";
|
|
3
|
+
import { hasClass } from "../styles.js";
|
|
4
|
+
import { childrenInSvg, isSvgElement } from "../svg.js";
|
|
5
|
+
import { isSimple } from "./analysis.js";
|
|
6
|
+
import { CreationEmitter } from "./creation.js";
|
|
7
|
+
import { contentKind } from "./element-helpers.js";
|
|
8
|
+
import { ARROW, arrayPattern } from "./syntax.js";
|
|
9
|
+
/**
|
|
10
|
+
* Markup: `<a href="/">Link {name}</a>` becomes statements that create the element. When the
|
|
11
|
+
* expression is evaluated exactly once they go before the statement that contains it; otherwise
|
|
12
|
+
* the element is created inside a function that is called right away.
|
|
13
|
+
*
|
|
14
|
+
* Markup that a component creates once (what it returns, and elements declared at the top level
|
|
15
|
+
* of its body) is live: parts that read state are updated when the state changes. `live` is where
|
|
16
|
+
* their updates go. `{if ...}`, `{switch ...}` and `{for ...}` become plain JS control flow that
|
|
17
|
+
* appends elements, unless they depend on state; see ControlFlowEmitter.
|
|
18
|
+
*/
|
|
19
|
+
export class ElementEmitter extends CreationEmitter {
|
|
20
|
+
element(node) {
|
|
21
|
+
if (this.hoist)
|
|
22
|
+
return this.create(node, null);
|
|
23
|
+
const body = this.withHoisting(true, () => this.block(() => this.line(`return ${this.create(node, null)};`)));
|
|
24
|
+
return `(() => ${body})()`;
|
|
25
|
+
}
|
|
26
|
+
elementDeclaration(declaration, node) {
|
|
27
|
+
const live = this.declaredLive(node);
|
|
28
|
+
const component = this.componentOf(node);
|
|
29
|
+
const value = this.tagValue(node);
|
|
30
|
+
if (component)
|
|
31
|
+
this.line(`${declaration} = ${this.expand(node, component, live)};`);
|
|
32
|
+
else if (value)
|
|
33
|
+
this.line(`${declaration} = ${this.valueTag(node, value, live)};`);
|
|
34
|
+
else
|
|
35
|
+
this.build(node, declaration, live);
|
|
36
|
+
}
|
|
37
|
+
/** Where the updates of `const x = <markup>` go: markup at the top level of a component is live. */
|
|
38
|
+
declaredLive(node) {
|
|
39
|
+
return this.reactive?.topLevel.has(node) ? this.reactive : null;
|
|
40
|
+
}
|
|
41
|
+
elementStatement(node) {
|
|
42
|
+
if (this.contentTarget === null)
|
|
43
|
+
throw new Error('an element statement outside of markup');
|
|
44
|
+
const element = this.create(node.element, null);
|
|
45
|
+
this.line(`${this.contentTarget}.append(${element});`);
|
|
46
|
+
}
|
|
47
|
+
/** A number for a generated name: `$$li1`, `$$updateCount2`, ... */
|
|
48
|
+
nextId() {
|
|
49
|
+
return ++this.elementCount;
|
|
50
|
+
}
|
|
51
|
+
/** Writes the code for an element or a component and returns the variable with the result. */
|
|
52
|
+
create(node, live) {
|
|
53
|
+
const component = this.componentOf(node);
|
|
54
|
+
const value = this.tagValue(node);
|
|
55
|
+
if (component)
|
|
56
|
+
return this.expand(node, component, live);
|
|
57
|
+
return value ? this.valueTag(node, value, live) : this.build(node, null, live);
|
|
58
|
+
}
|
|
59
|
+
componentOf(node) {
|
|
60
|
+
return node.tag && node.value === null ? this.componentNamed(node.tag.name) : undefined;
|
|
61
|
+
}
|
|
62
|
+
/** `section.content` of `<section.content />`, or `Page` of `<Page />` with a variable `Page`. */
|
|
63
|
+
tagValue(node) {
|
|
64
|
+
if (node.value || !node.tag || !/^[A-Z]/.test(node.tag.name))
|
|
65
|
+
return node.value;
|
|
66
|
+
return this.componentNamed(node.tag.name) ? null : node.tag;
|
|
67
|
+
}
|
|
68
|
+
/** Markup that creates an element or a fragment, not a component. */
|
|
69
|
+
isElement(node) {
|
|
70
|
+
return !this.componentOf(node) && !this.tagValue(node);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Writes the statements that create the element and returns the name of its variable.
|
|
74
|
+
* `declaration` is `const link` for `const link = <a>`; otherwise a temporary name is used.
|
|
75
|
+
*/
|
|
76
|
+
build(node, declaration, live) {
|
|
77
|
+
const tag = node.tag?.name ?? null;
|
|
78
|
+
const svg = tag !== null && isSvgElement(tag, this.inSvg);
|
|
79
|
+
const preset = this.presetElement(node);
|
|
80
|
+
// A ref created the element with its constant attributes, so the markup only fills it in.
|
|
81
|
+
const created = preset?.created ? preset.name : null;
|
|
82
|
+
const name = created ?? declaration?.split(' ').at(-1) ?? this.elementName(tag);
|
|
83
|
+
// Set by a ref, or by the helper that creates the element.
|
|
84
|
+
const covered = new Set(created ? constantAttributes(node) : []);
|
|
85
|
+
const scope = tag === null ? null : this.scopeOf(node);
|
|
86
|
+
// A spread may set the class: the class of the style is added after it, so that both stay.
|
|
87
|
+
const spread = node.attributes.some((attribute) => attribute.kind === 'JsxSpreadAttribute');
|
|
88
|
+
const scopeClass = scope && !created && !hasClass(node) ? scope : null;
|
|
89
|
+
let scoped = false;
|
|
90
|
+
if (created === null) {
|
|
91
|
+
const target = declaration ?? `const ${name}`;
|
|
92
|
+
if (tag === null) {
|
|
93
|
+
this.line(`${target} = document.createDocumentFragment();`);
|
|
94
|
+
}
|
|
95
|
+
else if (preset) {
|
|
96
|
+
this.createdElements++;
|
|
97
|
+
this.line(`${target} = ${preset.name} ?? ${this.createElement(tag, svg)};`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const creation = this.createWith(target, name, tag, svg, node.attributes, live, scope, spread ? null : scopeClass);
|
|
101
|
+
for (const attribute of creation.covered)
|
|
102
|
+
covered.add(attribute);
|
|
103
|
+
scoped = creation.scoped;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Bindings go last: `valueAsNumber` needs the `type` attribute to be set.
|
|
107
|
+
const bindings = [];
|
|
108
|
+
for (const attribute of node.attributes) {
|
|
109
|
+
if (covered.has(attribute))
|
|
110
|
+
continue;
|
|
111
|
+
if (attribute.kind === 'JsxAttribute' && attribute.name.name === 'ref')
|
|
112
|
+
continue;
|
|
113
|
+
if (attribute.kind === 'JsxAttribute' && attribute.name.name.startsWith('bind:')) {
|
|
114
|
+
bindings.push(attribute);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.attribute(name, tag, attribute, live, svg, scope);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Without a class attribute the element still gets the class of its style; a ref has set it.
|
|
121
|
+
if (scopeClass !== null && !scoped) {
|
|
122
|
+
if (spread)
|
|
123
|
+
this.line(`${name}.classList.add(${JSON.stringify(scopeClass)});`);
|
|
124
|
+
else
|
|
125
|
+
this.scopeClass(name, scopeClass, svg);
|
|
126
|
+
}
|
|
127
|
+
if (tag !== null) {
|
|
128
|
+
for (const attribute of bindings)
|
|
129
|
+
this.binding(name, tag, attribute, live);
|
|
130
|
+
}
|
|
131
|
+
const inSvg = this.inSvg;
|
|
132
|
+
this.inSvg = childrenInSvg(tag, svg, inSvg);
|
|
133
|
+
try {
|
|
134
|
+
this.children(name, node.children, live);
|
|
135
|
+
}
|
|
136
|
+
finally {
|
|
137
|
+
this.inSvg = inSvg;
|
|
138
|
+
}
|
|
139
|
+
if (created !== null && declaration)
|
|
140
|
+
this.line(`${declaration} = ${created};`);
|
|
141
|
+
return name;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Children are appended in order; consecutive ones that need no checks go into one `append`.
|
|
145
|
+
* Values whose type allows null, or is not known, are checked before they are appended. The
|
|
146
|
+
* statements of markup blocks are handled here too.
|
|
147
|
+
*/
|
|
148
|
+
children(element, children, live) {
|
|
149
|
+
let pending = [];
|
|
150
|
+
let pendingCalls = false;
|
|
151
|
+
const flush = () => {
|
|
152
|
+
if (pending.length > 0)
|
|
153
|
+
this.line(`${element}.append(${pending.join(', ')});`);
|
|
154
|
+
pending = [];
|
|
155
|
+
pendingCalls = false;
|
|
156
|
+
};
|
|
157
|
+
for (const child of children) {
|
|
158
|
+
switch (child.kind) {
|
|
159
|
+
case 'JsxText':
|
|
160
|
+
pending.push(JSON.stringify(child.value));
|
|
161
|
+
break;
|
|
162
|
+
case 'ElementExpression':
|
|
163
|
+
case 'JsxElementStatement': {
|
|
164
|
+
// A child element is created before the append; earlier calls must still run first.
|
|
165
|
+
if (pendingCalls)
|
|
166
|
+
flush();
|
|
167
|
+
const node = child.kind === 'ElementExpression' ? child : child.element;
|
|
168
|
+
pending.push(this.create(node, live));
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case 'JsxStatementContainer':
|
|
172
|
+
case 'IfStatement':
|
|
173
|
+
case 'ForStatement':
|
|
174
|
+
case 'ForInStatement':
|
|
175
|
+
case 'SwitchStatement': {
|
|
176
|
+
const statement = child.kind === 'JsxStatementContainer' ? child.statement : child;
|
|
177
|
+
const sources = live?.dependencies(statement);
|
|
178
|
+
if (live && sources && sources.size > 0) {
|
|
179
|
+
if (pendingCalls)
|
|
180
|
+
flush();
|
|
181
|
+
pending.push(this.liveControl(statement, live, sources));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Nothing in it changes: plain control flow that appends the elements.
|
|
185
|
+
flush();
|
|
186
|
+
this.withContentTarget(element, () => this.statement(statement));
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case 'VariableDeclaration':
|
|
191
|
+
flush();
|
|
192
|
+
this.blockConst(child, live);
|
|
193
|
+
break;
|
|
194
|
+
case 'JsxExpressionContainer': {
|
|
195
|
+
const { expression } = child;
|
|
196
|
+
const sources = live?.dependencies(expression);
|
|
197
|
+
if (live && sources && sources.size > 0) {
|
|
198
|
+
if (pendingCalls)
|
|
199
|
+
flush();
|
|
200
|
+
pending.push(this.liveChild(expression, live, sources));
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
switch (contentKind(expression, this.typeOf(expression))) {
|
|
204
|
+
case 'value':
|
|
205
|
+
pending.push(this.expression(expression, ARROW));
|
|
206
|
+
pendingCalls ||= !isSimple(expression);
|
|
207
|
+
break;
|
|
208
|
+
case 'list':
|
|
209
|
+
pending.push(`...${this.expression(expression, ARROW)}`);
|
|
210
|
+
pendingCalls ||= !isSimple(expression);
|
|
211
|
+
break;
|
|
212
|
+
case 'nullable': {
|
|
213
|
+
flush();
|
|
214
|
+
const text = this.once(expression);
|
|
215
|
+
this.line(`if (${text} != null) ${element}.append(${text});`);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
case 'unknown':
|
|
219
|
+
flush();
|
|
220
|
+
this.helpers.add('append');
|
|
221
|
+
this.line(`$$append(${element}, ${this.expression(expression, ARROW)});`);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
default:
|
|
227
|
+
// The parser allows no other statements in markup.
|
|
228
|
+
flush();
|
|
229
|
+
this.statement(child);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
flush();
|
|
233
|
+
}
|
|
234
|
+
withContentTarget(element, emit) {
|
|
235
|
+
const saved = this.contentTarget;
|
|
236
|
+
this.contentTarget = element;
|
|
237
|
+
try {
|
|
238
|
+
return emit();
|
|
239
|
+
}
|
|
240
|
+
finally {
|
|
241
|
+
this.contentTarget = saved;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* `{value}` that depends on state. Text becomes a text node whose data is replaced; other
|
|
246
|
+
* content is kept by the $$content helper, which replaces its nodes. Returns what to append.
|
|
247
|
+
*/
|
|
248
|
+
liveChild(expression, live, sources) {
|
|
249
|
+
const type = this.typeOf(expression);
|
|
250
|
+
const kind = type && widenLiterals(type).kind;
|
|
251
|
+
const id = this.nextId();
|
|
252
|
+
if (kind === 'string' || kind === 'number') {
|
|
253
|
+
const text = this.liveExpression(expression);
|
|
254
|
+
const node = `$$text${id}`;
|
|
255
|
+
this.line(`const ${node} = document.createTextNode(${text});`);
|
|
256
|
+
live.depend(sources, `${node}.data = ${text};`);
|
|
257
|
+
return node;
|
|
258
|
+
}
|
|
259
|
+
const name = `$$content${id}`;
|
|
260
|
+
const update = `$$updateContent${id}`;
|
|
261
|
+
this.helpers.add('content');
|
|
262
|
+
this.line(`const [${name}, ${update}] = $$content(${this.liveFunction(expression)});`);
|
|
263
|
+
live.depend(sources, `${update}();`);
|
|
264
|
+
return name;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* `const` in a markup block. When its value depends on state, it is computed again on updates,
|
|
268
|
+
* before the parts that read it.
|
|
269
|
+
*/
|
|
270
|
+
blockConst(node, live) {
|
|
271
|
+
const sources = live?.dependencies(node);
|
|
272
|
+
const names = node.names.map((name) => (name.name === '_' ? '' : this.name(name.name)));
|
|
273
|
+
if (!live || !sources || sources.size === 0 || names.every((name) => name === '')) {
|
|
274
|
+
this.statement(node);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const values = node.values.map((value) => this.liveExpression(value));
|
|
278
|
+
const assignments = values.length === names.length
|
|
279
|
+
? names.flatMap((name, i) => (name === '' ? [] : [`${name} = ${values[i]}`]))
|
|
280
|
+
: [`${arrayPattern(names)} = ${values[0]}`];
|
|
281
|
+
this.line(`let ${assignments.join(', ')};`);
|
|
282
|
+
for (const assignment of assignments)
|
|
283
|
+
live.depend(sources, `${assignment};`);
|
|
284
|
+
}
|
|
285
|
+
/** The expression if it can be repeated, otherwise a temporary that holds its value. */
|
|
286
|
+
once(node) {
|
|
287
|
+
if (isSimple(node))
|
|
288
|
+
return this.expression(node, ARROW);
|
|
289
|
+
const temp = this.temp();
|
|
290
|
+
this.line(`const ${temp} = ${this.expression(node, ARROW)};`);
|
|
291
|
+
return temp;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type * as ast from '../ast.ts';
|
|
2
|
+
import type { Type } from '../checker/types.ts';
|
|
3
|
+
import { type DecoratorSource } from '../decorators.ts';
|
|
4
|
+
import type { InlinePackage } from '../inline-packages.ts';
|
|
5
|
+
import { type ImportedComponent, type LocalizedPackage } from './imported.ts';
|
|
6
|
+
import type { Root } from '../refs.ts';
|
|
7
|
+
import type { StyleModule } from '../style-modules.ts';
|
|
8
|
+
import type { BindingKind } from './analysis.ts';
|
|
9
|
+
import type { Helper } from './helpers.ts';
|
|
10
|
+
export interface JsOptions {
|
|
11
|
+
/** The Rook source, used to keep the blank lines between statements. */
|
|
12
|
+
source: string;
|
|
13
|
+
/** Replace `.rk` with `.js` in relative import paths, for output written next to the sources. */
|
|
14
|
+
rewriteImports: boolean;
|
|
15
|
+
/** Types from the checker, when it ran; without them the generated code is more general. */
|
|
16
|
+
types?: WeakMap<ast.Expression, Type> | undefined;
|
|
17
|
+
/** Decorators imported from other modules, by name: their code is inlined here. */
|
|
18
|
+
decorators?: ReadonlyMap<string, ImportedDecorator> | undefined;
|
|
19
|
+
/** Components imported from other modules, by name: called, or inlined when they are small. */
|
|
20
|
+
components?: ReadonlyMap<string, ImportedComponent> | undefined;
|
|
21
|
+
/** Components of the module that become functions, since inlining them adds too many lines. */
|
|
22
|
+
functions?: ReadonlySet<string> | undefined;
|
|
23
|
+
/** The CSS modules the module imports, by their paths as written. */
|
|
24
|
+
styleModules?: ReadonlyMap<string, StyleModule> | undefined;
|
|
25
|
+
/** Create elements with their attributes by a helper, $$element; see creation.ts. */
|
|
26
|
+
elementHelper?: boolean | undefined;
|
|
27
|
+
/** For `go`: where the worker module is (`./app.worker.js`), or in it, the functions it runs. */
|
|
28
|
+
goroutines?: {
|
|
29
|
+
workerUrl: string;
|
|
30
|
+
} | {
|
|
31
|
+
targets: readonly string[];
|
|
32
|
+
} | undefined;
|
|
33
|
+
}
|
|
34
|
+
/** A decorator of another module, with the types of the expressions of that module. */
|
|
35
|
+
export interface ImportedDecorator extends DecoratorSource {
|
|
36
|
+
types: WeakMap<ast.Expression, Type> | null;
|
|
37
|
+
/** The components of that module its code uses, which go with it into the components here. */
|
|
38
|
+
inline: InlinePackage | null;
|
|
39
|
+
}
|
|
40
|
+
/** How a function implements its `defer` statements. */
|
|
41
|
+
export type DeferMode = 'none' | 'try' | 'stack' | 'effect';
|
|
42
|
+
interface FunctionContext {
|
|
43
|
+
deferMode: DeferMode;
|
|
44
|
+
/** Where `defer` puts its closures in 'stack' and 'effect' modes. */
|
|
45
|
+
deferList: string;
|
|
46
|
+
/** Counter for `$$0`, `$$1`, ... temporaries. */
|
|
47
|
+
temps: number;
|
|
48
|
+
/** Innermost last: `null` for loops and switches, a label for a switch compiled to if/else. */
|
|
49
|
+
breakTargets: (string | null)[];
|
|
50
|
+
/** An iterator, `func(yield func(T) bool)`: a generator, where `yield(v)` yields. */
|
|
51
|
+
iterator?: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The base of the JS generator: the output buffer, scopes of declared names and the state of the
|
|
55
|
+
* current function. The generator is split into layers, each adding to the previous one:
|
|
56
|
+
*
|
|
57
|
+
* Emitter → ExpressionEmitter → CallEmitter → SimpleStatementEmitter → ControlStatementEmitter
|
|
58
|
+
* → ParallelLoopEmitter → StatementEmitter → UpdateEmitter → AttributeEmitter
|
|
59
|
+
* → CreationEmitter → ElementEmitter → ControlFlowEmitter → ComponentPropsEmitter
|
|
60
|
+
* → ComponentValueEmitter → EarlyReturnEmitter → RefEmitter
|
|
61
|
+
* → StyleEmitter → ComponentEmitter → WebComponentEmitter → FunctionEmitter → JsGenerator
|
|
62
|
+
*/
|
|
63
|
+
export declare abstract class Emitter {
|
|
64
|
+
protected readonly program: ast.Program;
|
|
65
|
+
protected readonly options: JsOptions;
|
|
66
|
+
protected lines: string[];
|
|
67
|
+
private level;
|
|
68
|
+
private readonly scopes;
|
|
69
|
+
protected fn: FunctionContext;
|
|
70
|
+
/** Helpers that the module must define, such as $$runDeferred. */
|
|
71
|
+
protected readonly helpers: Set<Helper>;
|
|
72
|
+
/**
|
|
73
|
+
* Whether code for the current expression may be written before the statement that contains it.
|
|
74
|
+
* Elements use this to be created in statements of their own; it is off where an expression is
|
|
75
|
+
* not always evaluated exactly once (branches of `?:`, loop conditions and so on).
|
|
76
|
+
*/
|
|
77
|
+
protected hoist: boolean;
|
|
78
|
+
/** Top-level `type` aliases, to find the zero value of `let id ID`. */
|
|
79
|
+
protected readonly typeAliases: Map<string, ast.TypeNode>;
|
|
80
|
+
/** Names that are assigned somewhere in the module; others keep their value. */
|
|
81
|
+
protected readonly assigned: Set<string>;
|
|
82
|
+
/** Names used as values; imports used only as types are dropped. */
|
|
83
|
+
protected readonly valueNames: Set<string>;
|
|
84
|
+
/** Components of the module with their decorators applied, inlined where they are used. */
|
|
85
|
+
protected readonly components: Map<string, ast.ComponentDeclaration>;
|
|
86
|
+
/**
|
|
87
|
+
* Components that become functions: recursive ones cannot be inlined, and web components
|
|
88
|
+
* (`@html-tag`) create their markup in the element's class.
|
|
89
|
+
*/
|
|
90
|
+
protected readonly functionComponents: ReadonlySet<ast.ComponentDeclaration>;
|
|
91
|
+
/** Web components of the module by their tags: `<app-card count={3} />` sets their properties. */
|
|
92
|
+
protected readonly webComponents: Map<string, ast.ComponentDeclaration>;
|
|
93
|
+
/** The JS functions of components of other modules: `$$Card`, imported from their modules. */
|
|
94
|
+
protected readonly functionNames: Map<ast.ComponentDeclaration, string>;
|
|
95
|
+
/** For those, the element at the top of what they create, found in their modules. */
|
|
96
|
+
protected readonly importedRoots: Map<ast.ComponentDeclaration, Root>;
|
|
97
|
+
/** The inlined copies of each component and the lines they take, to choose functions (js.ts). */
|
|
98
|
+
readonly inlined: Map<string, {
|
|
99
|
+
copies: number;
|
|
100
|
+
lines: number;
|
|
101
|
+
}>;
|
|
102
|
+
/** The decorators that components of the module apply, by name. */
|
|
103
|
+
protected readonly appliedDecorators: Set<string>;
|
|
104
|
+
/** Copies of the code of other modules: their positions are in the sources of those. */
|
|
105
|
+
private readonly foreign;
|
|
106
|
+
/** Components of other modules inlined here, by name, with what their packages bring. */
|
|
107
|
+
protected readonly inlinedImports: Map<string, LocalizedPackage>;
|
|
108
|
+
/** The components that decorators of other modules bring, by the names of the decorators. */
|
|
109
|
+
protected readonly decoratorImports: Map<string, LocalizedPackage>;
|
|
110
|
+
/** Components a package brings: they have no function here, so they are always inlined. */
|
|
111
|
+
readonly alwaysInlined: Set<string>;
|
|
112
|
+
constructor(program: ast.Program, options: JsOptions);
|
|
113
|
+
protected indent(): string;
|
|
114
|
+
/** Writes a line at the current indentation. Later lines of `text` are already indented. */
|
|
115
|
+
protected line(text: string): void;
|
|
116
|
+
protected blankLine(): void;
|
|
117
|
+
/** Returns the lines written by `emit`, one level deeper than the current one. */
|
|
118
|
+
protected capture(emit: () => void): string[];
|
|
119
|
+
/** Renders the lines written by `emit` as a `{ ... }` block, for use inside a line. */
|
|
120
|
+
protected block(emit: () => void): string;
|
|
121
|
+
protected blankLineBetween(previous: ast.Node, next: ast.Node): boolean;
|
|
122
|
+
/** A component of the module as it is inlined: with its decorators applied. */
|
|
123
|
+
protected applied(component: ast.ComponentDeclaration): ast.ComponentDeclaration;
|
|
124
|
+
protected withScope<T>(bindings: Iterable<[string, BindingKind]>, emit: () => T): T;
|
|
125
|
+
protected lookup(name: string): BindingKind | undefined;
|
|
126
|
+
/** The JS name for a Rook name. */
|
|
127
|
+
protected name(name: string): string;
|
|
128
|
+
protected params(params: ast.Parameter[]): string;
|
|
129
|
+
protected withFunction<T>(mode: DeferMode, params: ast.Parameter[], emit: () => T): T;
|
|
130
|
+
protected withHoisting<T>(hoist: boolean, emit: () => T): T;
|
|
131
|
+
/** A fresh temporary name: `$$0`, `$$1`, ... */
|
|
132
|
+
protected temp(): string;
|
|
133
|
+
protected withBreakTarget<T>(label: string | null, emit: () => T): T;
|
|
134
|
+
}
|
|
135
|
+
export {};
|