runtime-compiler 3.2.0 → 4.0.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 +125 -11
- package/build/index.d.ts +6 -0
- package/build/index.js +1 -0
- package/build/rolldown.d.ts +16 -0
- package/build/rolldown.js +1 -0
- package/env/aot.js +1 -0
- package/env/build.js +1 -0
- package/env/index.d.ts +3 -0
- package/env/index.js +1 -0
- package/globals.d.ts +10 -0
- package/globals.js +1 -0
- package/package.json +1 -1
- package/scope.d.ts +13 -0
- package/scope.js +1 -0
- package/utils.d.ts +1 -43
- package/utils.js +1 -1
- package/config/index.d.ts +0 -8
- package/config/index.js +0 -1
- package/config/loader/build.d.ts +0 -1
- package/config/loader/build.js +0 -1
- package/config/loader/hydrate.d.ts +0 -1
- package/config/loader/hydrate.js +0 -1
- package/config/mode/build.d.ts +0 -2
- package/config/mode/build.js +0 -1
- package/config/mode/hydrate.d.ts +0 -2
- package/config/mode/hydrate.js +0 -1
- package/index.d.ts +0 -119
- package/index.js +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 aquapi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,17 +1,131 @@
|
|
|
1
|
-
|
|
2
|
-
A code generation system for JS.
|
|
1
|
+
A code generation system.
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
- `build`: Build only.
|
|
7
|
-
- `hydrate`: Run only.
|
|
3
|
+
# Usage
|
|
4
|
+
See [examples](https://github.com/re-utils/runtime-compiler/tree/main/examples).
|
|
8
5
|
|
|
6
|
+
# Code generation
|
|
7
|
+
Code generation is a trick used in a lot of high performance libraries, especially schema validators (TypeBox, Ajv, Sury, ...).
|
|
9
8
|
```ts
|
|
10
|
-
|
|
9
|
+
const schema = {
|
|
10
|
+
id: t.string,
|
|
11
|
+
pwd: t.string
|
|
12
|
+
};
|
|
11
13
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
+
// Can be compiled to a fast check function
|
|
15
|
+
const check = (0, eval)(`
|
|
16
|
+
(d) => typeof d === 'object'
|
|
17
|
+
&& d !== null
|
|
18
|
+
&& typeof d.id === 'string'
|
|
19
|
+
&& typeof d.pwd === 'string'
|
|
20
|
+
`);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Backend frameworks like Elysia also use it to optimize their request handling:
|
|
24
|
+
```ts
|
|
25
|
+
// Not exactly what Elysia generates but u get the idea
|
|
26
|
+
switch (path) {
|
|
27
|
+
case '/': return handleHome();
|
|
28
|
+
case '/user': {
|
|
29
|
+
// Calls can be analyzed to remove
|
|
30
|
+
// unused fields in the context object
|
|
31
|
+
const c = { ... };
|
|
14
32
|
|
|
15
|
-
//
|
|
16
|
-
|
|
33
|
+
// Inline hook calls
|
|
34
|
+
onRequestHook(c);
|
|
35
|
+
handleRequest(c);
|
|
36
|
+
afterRequestHook(c);
|
|
37
|
+
|
|
38
|
+
return sendResponse(c);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For cases that code generation works, it is usually much easier to write and setup than AST transformations, compiles faster, and also has more flexibility.
|
|
44
|
+
|
|
45
|
+
The output startup cost is higher than AST transformations though, but this library has primitives to minimize that additional cost.
|
|
46
|
+
|
|
47
|
+
## Writing codegen
|
|
48
|
+
The first example was pretty simple, but what if we want to use an user-defined value?
|
|
49
|
+
```ts
|
|
50
|
+
const check = (0, eval)(`
|
|
51
|
+
(d) => typeof d === 'string' && checkEmail(d)
|
|
52
|
+
`);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This works but it breaks with closures (similarly for other types of unserializable data):
|
|
56
|
+
```ts
|
|
57
|
+
import { checkEmail } from './utils.ts';
|
|
58
|
+
|
|
59
|
+
// eval returns the value of the last statement
|
|
60
|
+
const check = (0, eval)(`
|
|
61
|
+
const checkEmail = ${checkEmail.toString()};
|
|
62
|
+
(d) => typeof d === 'string' && checkEmail(d)
|
|
63
|
+
`);
|
|
64
|
+
|
|
65
|
+
// For a checkEmail function like this it would
|
|
66
|
+
// break as emailRegex is not available in eval scope
|
|
67
|
+
const emailRegex = /.../;
|
|
68
|
+
const checkEmail = (str: string) => emailRegex.test(str);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
We gonna need a dependency array to inject user-defined values into the eval scope:
|
|
72
|
+
```ts
|
|
73
|
+
import { checkEmail } from './utils.ts';
|
|
74
|
+
|
|
75
|
+
const buildCheck = (0, eval)(`(deps) => {
|
|
76
|
+
const checkEmail = deps[0];
|
|
77
|
+
return (d) => typeof d === 'string' && checkEmail(d)
|
|
78
|
+
}`);
|
|
79
|
+
|
|
80
|
+
const check = buildCheck([checkEmail]);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Problems
|
|
84
|
+
Code generation has 2 main problems:
|
|
85
|
+
- It has a startup time, memory usage and bundle size cost.
|
|
86
|
+
- It does not work on certain runtimes.
|
|
87
|
+
|
|
88
|
+
This library merges all `eval()` calls into 1 (which makes it able to do ahead of time compilation) and make compiled values easier to work with.
|
|
89
|
+
```ts
|
|
90
|
+
const check1 = compile(schema1);
|
|
91
|
+
const check2 = compile(schema2);
|
|
92
|
+
|
|
93
|
+
// Can be rewritten as
|
|
94
|
+
const check1Id = compile(schema1);
|
|
95
|
+
const check2Id = compile(schema2);
|
|
96
|
+
|
|
97
|
+
// For ahead-of-time compilation to work
|
|
98
|
+
// this evaluate() call can just be replaced with
|
|
99
|
+
// whatever code is generated at the moment
|
|
100
|
+
evaluate();
|
|
101
|
+
|
|
102
|
+
const check1 = artifact(check1Id);
|
|
103
|
+
const check2 = artifact(check2Id);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The ahead of time output can be:
|
|
107
|
+
```js
|
|
108
|
+
// Store dependencies and build outputs
|
|
109
|
+
const check1Id = compile(schema1);
|
|
110
|
+
const check2Id = compile(schema2);
|
|
111
|
+
|
|
112
|
+
$[0] = (d) => typeof d === 'string';
|
|
113
|
+
$[1] = (d) => Number.isInteger(d) && d > -1 && d < 256;
|
|
114
|
+
|
|
115
|
+
const check1 = artifact(check1Id);
|
|
116
|
+
const check2 = artifact(check2Id);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
We can remove the codegen cost with flags:
|
|
120
|
+
```ts
|
|
121
|
+
const compile = IS_AOT
|
|
122
|
+
// This is the compile() function after build, since
|
|
123
|
+
// we don't need to codegen anymore
|
|
124
|
+
? () => reserveArtifact()
|
|
125
|
+
: (schema1) => {
|
|
126
|
+
...;
|
|
127
|
+
const schemaId = reserveArtifact();
|
|
128
|
+
emit(`$[${schemaId}]=${builtFnCode}`);
|
|
129
|
+
return schemaId;
|
|
130
|
+
}
|
|
17
131
|
```
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const getPromiseResolvers: (res: any, rej: any) => void;
|
|
2
|
+
export declare const runInWorker: (code: string) => Promise<string[]>;
|
|
3
|
+
/**
|
|
4
|
+
* Requires code to not bundle "runtime-compiler/env" and "runtime-compiler/globals"
|
|
5
|
+
*/
|
|
6
|
+
export declare const compile: (code: string) => Promise<string>;
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Worker}from"node:worker_threads";let curRes,curRej;export const getPromiseResolvers=(res,rej)=>{curRes=res;curRej=rej};let workerOptions={eval:!0};export const runInWorker=code=>{let p=new Promise(getPromiseResolvers),worker=new Worker(`import"runtime-compiler/env/build";import{__rtcpl_ct__}from"runtime-compiler/globals";import{parentPort as __rtcpl_pp__}from"node:worker_threads";${code};\n__rtcpl_pp__.postMessage(__rtcpl_ct__)`,workerOptions);worker.once("message",curRes);worker.once("error",curRej);return p};export const compile=async code=>{let str='import"runtime-compiler/env/aot";import{__rtcpl_setup_aot__}from"runtime-compiler/globals";';for(let i=0,codes=await runInWorker(code);i<codes.length;i++)str+=`__rtcpl_setup_aot__($=>{${codes[i]}});`;return str+code};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Plugin } from "rolldown";
|
|
2
|
+
interface ImportBinding {
|
|
3
|
+
name: string;
|
|
4
|
+
alias: string;
|
|
5
|
+
}
|
|
6
|
+
interface ImportStatement {
|
|
7
|
+
start: number;
|
|
8
|
+
end: number;
|
|
9
|
+
bindings: ImportBinding[];
|
|
10
|
+
}
|
|
11
|
+
export declare const parseImports: (code: string) => {
|
|
12
|
+
envImports: ImportStatement;
|
|
13
|
+
globalsImports: ImportStatement;
|
|
14
|
+
};
|
|
15
|
+
declare const _default: () => Plugin;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{runInWorker}from"./index.js";let parseImportBindings=(code,start,end)=>{let startSpecs=code.indexOf("{",start),endSpecs=code.lastIndexOf("}",end);if(-1===start&&-1===end)throw new Error("Only named imports replacement is supported!");let bindings=[];for(let i=0,specifiers=code.slice(startSpecs+1,endSpecs-1).split(",");i<specifiers.length;i++){let specifier=specifiers[i].trim();if(""===specifier)continue;let parts=specifier.split(" as ",2);if(1===parts.length){let name=parts[0].trim();bindings.push({name,alias:name})}else bindings.push({name:parts[0].trim(),alias:parts[1].trim()})}return{bindings,start,end}};export const parseImports=code=>{let envImports,globalsImports;for(let start=0,eol=code.indexOf("\n");eol>-1&&(null==envImports||null==globalsImports);eol=code.indexOf("\n",start=eol+1))code.startsWith("import",start)&&(code.endsWith('"runtime-compiler/env";',eol)?envImports=parseImportBindings(code,start,eol):code.endsWith('"runtime-compiler/globals";',eol)&&(globalsImports=parseImportBindings(code,start,eol)));return{envImports,globalsImports}};export default(()=>({name:"rolldown-plugin-runtime-compiler",resolveId:{filter:{id:/^runtime-compiler\/(?:env|globals)$/},handler:()=>!1},renderChunk:async(code,chunk)=>{if(!chunk.imports.includes("runtime-compiler/globals")||!chunk.imports.includes("runtime-compiler/env"))return null;let{envImports,globalsImports}=parseImports(code),aotCode="const __rtcpl_atf__=[],__rtcpl_aot_fns__=[],__rtcpl_setup_aot__=f=>{__rtcpl_aot_fns__.push(f)};let __rtcpl_aot_fn_idx__=0;";for(let i=0,{bindings}=envImports;i<bindings.length;i++){let{name,alias}=bindings[i];aotCode+="IS_AOT"===name?`const ${alias}=true;`:"IS_BUILD"===name||"IS_JIT"===name?`const ${alias}=false;`:""}for(let i=0,{bindings}=globalsImports;i<bindings.length;i++){let{name,alias}=bindings[i];aotCode+="artifact"===name?`const ${alias}=i=>__rtcpl_atf__[i];`:"emit"===name?`const ${alias}=()=>{};`:"evaluate"===name?`const ${alias}=()=>__rtcpl_aot_fns__[__rtcpl_aot_fn_idx__++](__rtcpl_atf__);`:"reserveArtifact"===name?`const ${alias}=()=>__rtcpl_atf__.push(undefined)-1;`:"importArtifact"===name?`const ${alias}=v=>__rtcpl_atf__.push(v)-1;`:""}for(let i=0,codes=await runInWorker(code);i<codes.length;i++)aotCode+=`__rtcpl_setup_aot__($=>{${codes[i]}});`;aotCode+=envImports.start<globalsImports.start?code.slice(0,envImports.start)+code.slice(envImports.end,globalsImports.start)+code.slice(globalsImports.end):code.slice(0,globalsImports.start)+code.slice(globalsImports.end,envImports.start)+code.slice(envImports.end);return{code:aotCode}}}));
|
package/env/aot.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setAOT}from"./index.js";setAOT();
|
package/env/build.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{setBuild}from"./index.js";setBuild();
|
package/env/index.d.ts
ADDED
package/env/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export let IS_JIT=!0;export let IS_BUILD=!1;export let IS_AOT=!1;export const setBuild=()=>{IS_JIT=!1;IS_BUILD=!0;IS_AOT=!1};export const setAOT=()=>{IS_JIT=!1;IS_BUILD=!1;IS_AOT=!0};
|
package/globals.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Artifact<T> = number & {
|
|
2
|
+
"~": T;
|
|
3
|
+
};
|
|
4
|
+
export declare const importArtifact: <T>(value: T) => Artifact<T>;
|
|
5
|
+
export declare const reserveArtifact: <T>() => Artifact<T>;
|
|
6
|
+
export declare let evaluate: <T>() => T;
|
|
7
|
+
export declare const emit: (code: string) => void;
|
|
8
|
+
export type ArtifactsRecord = Record<any, Artifact<any>>;
|
|
9
|
+
export type ArtifactGroup<T extends ArtifactsRecord> = <K extends keyof T>(k: K) => T[K]["~"];
|
|
10
|
+
export declare const artifact: <T>(id: Artifact<T>) => T;
|
package/globals.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{IS_AOT,IS_BUILD}from"./env/index.js";import{emptyFn}from"./utils.js";let __rtcpl_atf__=[];export const importArtifact=value=>__rtcpl_atf__.push(value)-1;export const reserveArtifact=()=>__rtcpl_atf__.push(void 0)-1;let content="";export let __rtcpl_ct__=[];export let evaluate=IS_AOT?()=>__rtcpl_aot_fns__[__rtcpl_aot_fn_idx__++](__rtcpl_atf__):IS_BUILD?()=>{__rtcpl_ct__.push(content);let currentContent=content;content="";if(currentContent.length>0)return(0,eval)(`$=>{${currentContent}}`)(__rtcpl_atf__)}:()=>{let currentContent=content;content="";if(currentContent.length>0)return(0,eval)(`$=>{${currentContent}}`)(__rtcpl_atf__)};export const emit=IS_AOT?emptyFn:code=>{content+=code};let __rtcpl_aot_fns__=[],__rtcpl_aot_fn_idx__=0;export const __rtcpl_setup_aot__=fn=>{__rtcpl_aot_fns__.push(fn)};export const artifact=id=>__rtcpl_atf__[id];
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"runtime-compiler","version":"
|
|
1
|
+
{"name":"runtime-compiler","version":"4.0.0","description":"A compiler system.","keywords":[],"homepage":"","license":"MIT","repository":"","type":"module","exports":{"./*":"./*.js","./build":"./build/index.js","./env":"./env/index.js"}}
|
package/scope.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type Scope = [start: string, end: string, nextId: number];
|
|
2
|
+
/**
|
|
3
|
+
* Get next available id in a scope.
|
|
4
|
+
*/
|
|
5
|
+
export declare const scopeNextId: (scope: Scope) => number;
|
|
6
|
+
/**
|
|
7
|
+
* Get scope content.
|
|
8
|
+
*/
|
|
9
|
+
export declare const scopeContent: (scope: Scope) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Fork a new scope.
|
|
12
|
+
*/
|
|
13
|
+
export declare const scopeFork: <T extends Scope>(scope: T) => T;
|
package/scope.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const scopeNextId=scope=>scope[2]++;export const scopeContent=scope=>`{${scope[0]+scope[1]}}`;export const scopeFork=scope=>scope.slice();
|
package/utils.d.ts
CHANGED
|
@@ -1,43 +1 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* Placeholder for `hydrate` mode.
|
|
4
|
-
*/
|
|
5
|
-
export declare const noOp: () => string;
|
|
6
|
-
/**
|
|
7
|
-
* Async function constructor
|
|
8
|
-
*/
|
|
9
|
-
export declare const AsyncFunction: typeof Function;
|
|
10
|
-
/**
|
|
11
|
-
* Derive a value from other expressions.
|
|
12
|
-
* Use in `default` and `build` mode.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* const newValue = derive(
|
|
16
|
-
* ['Math.random()' as Expression<number>],
|
|
17
|
-
* (rand) => rand * 10
|
|
18
|
-
* ); // '$[0](Math.random())'
|
|
19
|
-
*
|
|
20
|
-
* // In hydrate mode
|
|
21
|
-
* injectExternal((rand) => rand * 10);
|
|
22
|
-
*/
|
|
23
|
-
export declare const derive: <
|
|
24
|
-
const Expressions extends Expression<any>[],
|
|
25
|
-
R
|
|
26
|
-
>(values: Expressions, fn: (...args: { [K in keyof Expressions] : Expressions[K]["~type"] }) => R) => Value<R>;
|
|
27
|
-
/**
|
|
28
|
-
* Derive a value from other expressions.
|
|
29
|
-
* Use in `default` and `build` mode.
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* const newValue = deriveAsync(
|
|
33
|
-
* ['await fetch("http://example.com")' as Expression<Response>],
|
|
34
|
-
* async (res) => await res.text()
|
|
35
|
-
* ); // 'await $[0](await fetch("http://example.com"))'
|
|
36
|
-
*
|
|
37
|
-
* // In hydrate mode
|
|
38
|
-
* injectExternal((rand) => rand * 10);
|
|
39
|
-
*/
|
|
40
|
-
export declare const deriveAsync: <
|
|
41
|
-
const Expressions extends Expression<any>[],
|
|
42
|
-
R
|
|
43
|
-
>(values: Expressions, fn: (...args: { [K in keyof Expressions] : Expressions[K]["~type"] }) => Promise<R>) => Expression<R>;
|
|
1
|
+
export declare const emptyFn: () => void;
|
package/utils.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export const emptyFn=()=>{};
|
package/config/index.d.ts
DELETED
package/config/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=false;export let onlyBuild=false;export let hydrating=()=>{isHydrating=true};export let building=()=>{onlyBuild=true};
|
package/config/loader/build.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/config/loader/build.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{building}from"../index.js";building();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/config/loader/hydrate.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{hydrating}from"../index.js";hydrating();
|
package/config/mode/build.d.ts
DELETED
package/config/mode/build.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=false;export let onlyBuild=true;
|
package/config/mode/hydrate.d.ts
DELETED
package/config/mode/hydrate.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export let isHydrating=true;export let onlyBuild=false;
|
package/index.d.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
export type Expression<T> = string & {
|
|
2
|
-
"~type": T
|
|
3
|
-
};
|
|
4
|
-
export type Value<T> = Expression<T> & {
|
|
5
|
-
"~value": 0
|
|
6
|
-
};
|
|
7
|
-
export type Identifier<T> = Value<T> & {
|
|
8
|
-
"~id": 0
|
|
9
|
-
};
|
|
10
|
-
export type ExportedDependency<T> = number & {
|
|
11
|
-
"~type": T
|
|
12
|
-
};
|
|
13
|
-
export interface Scope {
|
|
14
|
-
/**
|
|
15
|
-
* Current scope content.
|
|
16
|
-
*/
|
|
17
|
-
0: string;
|
|
18
|
-
/**
|
|
19
|
-
* Next available id.
|
|
20
|
-
*/
|
|
21
|
-
1: number;
|
|
22
|
-
/**
|
|
23
|
-
* End scope content.
|
|
24
|
-
*/
|
|
25
|
-
2: string;
|
|
26
|
-
slice: () => this;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* External dependencies
|
|
30
|
-
*/
|
|
31
|
-
export declare const $: any[];
|
|
32
|
-
/**
|
|
33
|
-
* Inject an external dependency.
|
|
34
|
-
*/
|
|
35
|
-
export declare const injectExternal: <T>(val: T) => Value<T>;
|
|
36
|
-
/**
|
|
37
|
-
* Get next available identifier name in a scope
|
|
38
|
-
*/
|
|
39
|
-
export declare const nextId: <T>(scope: Scope) => Identifier<T>;
|
|
40
|
-
export declare const content: <T>(scope: Scope) => string;
|
|
41
|
-
/**
|
|
42
|
-
* Declare a new variable in a scope
|
|
43
|
-
*
|
|
44
|
-
* @example
|
|
45
|
-
* declareLocal(scope, '1;');
|
|
46
|
-
*/
|
|
47
|
-
export declare const declareLocal: <T>(scope: Scope, str: string) => Identifier<T>;
|
|
48
|
-
/**
|
|
49
|
-
* Declare a new variable in a scope
|
|
50
|
-
*/
|
|
51
|
-
export declare const declareExternal: <T>(scope: Scope, val: T) => Identifier<T>;
|
|
52
|
-
interface ExportToParent {
|
|
53
|
-
<T>(scope: Scope, expr: Expression<T>, parentScope: Scope): Identifier<T>;
|
|
54
|
-
(scope: Scope, expr: string, parentScope: Scope): string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Export a local expression to a parent local variable.
|
|
58
|
-
* Use in `default` and `build` mode.
|
|
59
|
-
*
|
|
60
|
-
* @example
|
|
61
|
-
* // Fork scope
|
|
62
|
-
* const childScope = ['', parentScope.id];
|
|
63
|
-
* // let d0;{let d1=1;d0=d1}
|
|
64
|
-
* const id = exportTo(childScope, declareLocal(childScope, '1'), parentScope); // d0
|
|
65
|
-
*/
|
|
66
|
-
export declare const exportToParent: ExportToParent;
|
|
67
|
-
/**
|
|
68
|
-
* Mark current available variable id to be already in use.
|
|
69
|
-
* Use in `hydrate` mode.
|
|
70
|
-
* @param scope
|
|
71
|
-
*/
|
|
72
|
-
export declare const markDeclared: (scope: Scope) => void;
|
|
73
|
-
export declare let statements: string;
|
|
74
|
-
interface ExportScope {
|
|
75
|
-
<T>(scope: Scope, value: Expression<T>): ExportedDependency<T>;
|
|
76
|
-
<T>(scope: Scope, value: string): ExportedDependency<T>;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Export a local dependency of a scope.
|
|
80
|
-
* Use in `default` and `build` mode.
|
|
81
|
-
*/
|
|
82
|
-
export declare const exportScope: ExportScope;
|
|
83
|
-
/**
|
|
84
|
-
* Export a value.
|
|
85
|
-
* Use in `default` and `build` mode.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* exportLocal('1;');
|
|
89
|
-
*/
|
|
90
|
-
export declare const exportLocal: <T>(value: string) => ExportedDependency<T>;
|
|
91
|
-
/**
|
|
92
|
-
* Mark a slot to export a dependency.
|
|
93
|
-
* Use in `hydrate` mode.
|
|
94
|
-
*/
|
|
95
|
-
export declare const markExported: <T>() => ExportedDependency<T>;
|
|
96
|
-
/**
|
|
97
|
-
* Get the value of an exported dependency.
|
|
98
|
-
* Use in `default` mode.
|
|
99
|
-
* @param idx
|
|
100
|
-
*/
|
|
101
|
-
export declare const getDependency: <T>(idx: ExportedDependency<T>) => T;
|
|
102
|
-
/**
|
|
103
|
-
* Get built statements and reset for next build.
|
|
104
|
-
* Use in `build` mode.
|
|
105
|
-
*/
|
|
106
|
-
export declare const getStatements: () => string;
|
|
107
|
-
/**
|
|
108
|
-
* Store temporary build data.
|
|
109
|
-
*/
|
|
110
|
-
export declare let buildData: any[];
|
|
111
|
-
/**
|
|
112
|
-
* @example
|
|
113
|
-
* const slot = createBuildSlot();
|
|
114
|
-
*
|
|
115
|
-
* // Reset after every build
|
|
116
|
-
* buildData[slot] ??= data;
|
|
117
|
-
*/
|
|
118
|
-
export declare const createBuildSlot: () => number;
|
|
119
|
-
export {};
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
;export let $=[];export let injectExternal=f=>`$[${$.push(f)-1}]`;export let nextId=e=>`d`+ e[1]++;export let content=e=>e[0]+e[2];export let declareLocal=(e,f)=>{let m=nextId(e);e[0]+=`let ${m}=`+f;return m};export let declareExternal=(f,m)=>{let h=nextId(f);f[0]+=`let ${h}=$[${$.push(m)-1}];`;return h};export let exportToParent=(e,f,h)=>{let g=nextId(h);h[0]+=`let ${g};{${content(e)+g}=${f}}`;return g};export let markDeclared=e=>{e[1]++};export let statements=``;export let exportScope=(f,p)=>(statements+=`{${content(f)}$[${$.length}]=${p}}`,$.length++);export let exportLocal=f=>(statements+=`$[${$.length}]=${f}`,$.length++);export let markExported=()=>$.length++;export let getDependency=f=>{if(statements.length>0){globalThis.__rt_externals__=$;(0,eval)(`{let $=__rt_externals__;`+statements+`}`);globalThis.__rt_externals__=null;statements=``;buildData=[]}return $[f]};export let getStatements=()=>{let e=statements;statements=``;buildData=[];return e};export let buildData=[];let nextSlot=0;export let createBuildSlot=()=>nextSlot++;
|