@backtickjs/core 0.1.9 → 0.1.11

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/README.md CHANGED
@@ -36,7 +36,7 @@ export async function Home() {
36
36
  }
37
37
  ```
38
38
 
39
- `$node` and `$Counter` are splices: `node` is a server variable, written into the bundle as data; `Counter` is a script. `$useState` is a splice too, of an export the client provides. What can be spliced is `Spliceable`: data, and scripts. [Thinking in Backtick](https://backtickjs.com/docs/thinking-in-backtick) has what can cross, what can't, and how server and client components compose.
39
+ `$node` and `$Counter` are splices: `node` is a server variable, written into the bundle as data; `Counter` is a script. `$useState` is a splice too, of an export the client provides. What can be spliced is `Spliceable`: data, and scripts. [Thinking in Backtick](https://backtickjs.com/docs/thinking-in-backtick/) has what can cross, what can't, and how server and client components compose.
40
40
 
41
41
  A script every component shares, like a context or a store, is made once with `once`: one value for the bundle, where an expression script would run again at each read.
42
42
 
@@ -73,6 +73,11 @@ The client must provide that package, and the server must list it in the bundler
73
73
  - `Spliced<T>`: what a spliceable value becomes on the client (`Client<U>` becomes `U`; arrays and objects map member by member).
74
74
  - `createImport<T>({ name, from, version })`: an export of a module the client provides, as a value a script can splice.
75
75
  - `isClientImport`, `ClientImport`: its check and type.
76
+ - `Bundle<T>`: a bundle's code, branded with what it runs to. `bundler.build(…).generate(…)` writes one.
77
+ - `execRoot(bundle, moduleMap)`, from `@backtickjs/core/cjs`: in a React Native app, runs the CommonJS bundle it starts from to its value, as a promise, with `require` answered from `moduleMap`, a `ModuleMap`: the modules the app provides, by specifier.
78
+ - `execRoot(bundle)`, from `@backtickjs/core/es`: in a web page, imports the ES bundle it starts from and resolves to its value, the page's import map answering its imports. Each format has its own entry, so a React Native app's bundler never reads the ES one's `import()`.
79
+ - `exec`: in a script, `$exec(bundle)` runs another bundle as the script's own was run, with the same modules, to a promise of its value.
80
+ - `isClientExec`, `ClientExec`: its check and type.
76
81
  - `SplicesAs<T>`: `T` as a splice checks it, member by member. Used by the bundler to check its input.
77
82
  - `createJsxElement`, `isJsxElement`, `JsxElement`, `JsxElementOf`, `JsxElementTypeOf`: what a server-side JSX tag evaluates to before bundling. Used by adapters' JSX runtimes.
78
83
  - `create`, `isClientScript`, `ClientScript`, `ClientModule`, `Param`: the compiled form of a script, written by the compiler and read by the bundler. Not for application code.
@@ -83,7 +88,7 @@ The client must provide that package, and the server must list it in the bundler
83
88
  - [`@backtickjs/react`](https://github.com/backtickjs/backtick/tree/main/adapters/react), [`@backtickjs/react-native`](https://github.com/backtickjs/backtick/tree/main/adapters/react-native), [`@backtickjs/solid-js`](https://github.com/backtickjs/backtick/tree/main/adapters/solid-js): framework adapters
84
89
  - [`@backtickjs/node-plugin`](https://github.com/backtickjs/backtick/tree/main/packages/node-plugin), [`@backtickjs/bun-plugin`](https://github.com/backtickjs/backtick/tree/main/packages/bun-plugin): compile scripts as your server loads them
85
90
  - [`@backtickjs/tsc`](https://github.com/backtickjs/backtick/tree/main/packages/tsc): type-checks scripts and their splices
86
- - [Thinking in Backtick](https://backtickjs.com/docs/thinking-in-backtick), [Scripts in depth](https://backtickjs.com/docs/scripts-in-depth)
91
+ - [Thinking in Backtick](https://backtickjs.com/docs/thinking-in-backtick/), [Scripts in depth](https://backtickjs.com/docs/scripts-in-depth/)
87
92
 
88
93
  ## License
89
94
 
@@ -0,0 +1,9 @@
1
+ declare const value: unique symbol;
2
+ /**
3
+ * A bundle's code, which runs to a `T`: what the bundler writes for a
4
+ * `Client<T>`, as it reaches the client, from the server.
5
+ */
6
+ export type Bundle<T> = string & {
7
+ readonly [value]: T;
8
+ };
9
+ export {};
package/dist/Bundle.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=Bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Bundle.js","sourceRoot":"","sources":["../src/Bundle.ts"],"names":[],"mappings":""}
@@ -12,7 +12,7 @@ export interface ClientModule {
12
12
  readonly map: string;
13
13
  readonly dependencies: readonly string[];
14
14
  readonly params: readonly Param[];
15
- readonly kind: "function" | "expression" | "block";
15
+ readonly kind: "function" | "class" | "expression" | "block";
16
16
  }
17
17
  export interface ClientScript {
18
18
  readonly "@backtickjs": "ClientScript";
@@ -1 +1 @@
1
- {"version":3,"file":"ClientScript.js","sourceRoot":"","sources":["../src/ClientScript.ts"],"names":[],"mappings":"AA4CA,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,aAAa,IAAI,KAAK;QACtB,KAAK,CAAC,aAAa,CAAC,KAAK,cAAc,CACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,MAAoB,EACpB,IAA2B;IAE3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACzD,CAAC"}
1
+ {"version":3,"file":"ClientScript.js","sourceRoot":"","sources":["../src/ClientScript.ts"],"names":[],"mappings":"AA6CA,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,aAAa,IAAI,KAAK;QACtB,KAAK,CAAC,aAAa,CAAC,KAAK,cAAc,CACxC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,MAAoB,EACpB,IAA2B;IAE3B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACzD,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What a bundle may import, by specifier: each the module the app imported
3
+ * for it. What a web page's import map does, for an app, with modules for
4
+ * values instead of URLs:
5
+ *
6
+ * import * as React from "react";
7
+ * import * as JSXRuntime from "react/jsx-runtime";
8
+ * import * as ReactNative from "react-native";
9
+ *
10
+ * export const moduleMap = {
11
+ * react: React,
12
+ * "react/jsx-runtime": JSXRuntime,
13
+ * "react-native": ReactNative,
14
+ * };
15
+ */
16
+ export type ModuleMap = Readonly<Record<string, unknown>>;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ModuleMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ModuleMap.js","sourceRoot":"","sources":["../src/ModuleMap.ts"],"names":[],"mappings":""}
@@ -20,6 +20,6 @@ export type SplicesAs<T> = [T] extends [Spliceable] ? T : T extends (...args: ne
20
20
  };
21
21
  export type Spliced<T> = T extends Client<infer U> ? U : T extends readonly (infer Item extends Spliceable)[] ? number extends T["length"] ? Spliced<Item>[] : {
22
22
  -readonly [K in keyof T]: Spliced<T[K]>;
23
- } : T extends object ? {
23
+ } : T extends string | number | bigint | boolean ? T : T extends object ? {
24
24
  -readonly [K in keyof T]: Spliced<T[K]>;
25
25
  } : T;
package/dist/cjs.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+ import type { ModuleMap } from "./ModuleMap.js";
3
+ export type { ModuleMap };
4
+ /**
5
+ * Executes a CommonJS bundle an app starts from, the one nothing else runs,
6
+ * to its value, with `require` answered from `moduleMap`: how a React Native
7
+ * app runs what its server answers. The bundles it runs in turn, with `exec`,
8
+ * get the same modules. Fetching the bundle, and when, is the app's. The
9
+ * entry an app imports is its format: a web page imports
10
+ * `@backtickjs/core/es`.
11
+ *
12
+ * const screen = await execRoot(bundle, moduleMap);
13
+ */
14
+ export declare function execRoot<T>(bundle: Bundle<T>, moduleMap: ModuleMap): Promise<Awaited<T>>;
package/dist/cjs.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Executes a CommonJS bundle an app starts from, the one nothing else runs,
3
+ * to its value, with `require` answered from `moduleMap`: how a React Native
4
+ * app runs what its server answers. The bundles it runs in turn, with `exec`,
5
+ * get the same modules. Fetching the bundle, and when, is the app's. The
6
+ * entry an app imports is its format: a web page imports
7
+ * `@backtickjs/core/es`.
8
+ *
9
+ * const screen = await execRoot(bundle, moduleMap);
10
+ */
11
+ export async function execRoot(bundle, moduleMap) {
12
+ const require = (specifier) => {
13
+ if (!Object.hasOwn(moduleMap, specifier)) {
14
+ throw new Error(`The bundle requires "${specifier}", which this app doesn't provide.`);
15
+ }
16
+ return moduleMap[specifier];
17
+ };
18
+ const module = { exports: {} };
19
+ new Function("module", "exports", "require", bundle)(module, module.exports, require);
20
+ return module.exports;
21
+ }
22
+ //# sourceMappingURL=cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cjs.js","sourceRoot":"","sources":["../src/cjs.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAiB,EACjB,SAAoB;IAEpB,MAAM,OAAO,GAAG,CAAC,SAAiB,EAAW,EAAE;QAC7C,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CACb,wBAAwB,SAAS,oCAAoC,CACtE,CAAC;QACJ,CAAC;QACD,OAAO,SAAS,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,EAAa,EAAE,CAAC;IAC1C,IAAI,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAClD,MAAM,EACN,MAAM,CAAC,OAAO,EACd,OAAO,CACR,CAAC;IACF,OAAO,MAAM,CAAC,OAAqB,CAAC;AACtC,CAAC"}
package/dist/cs.d.ts CHANGED
@@ -4,15 +4,6 @@ import type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
4
4
  declare function lift<T>(_: T): Client<T>;
5
5
  declare function splice<T extends [T] extends [SplicesAs<T>] ? unknown : Spliceable>(_: T): unknown extends Spliced<T> ? any : Spliced<T>;
6
6
  declare function awaited<T>(_: T): Awaited<T>;
7
- /**
8
- * The globals a project declares — its libs, `@types`, a `declare global` —
9
- * as an ordinary object type: reading one it doesn't declare is an error
10
- * however strict the project is, where `typeof globalThis` itself lets it
11
- * through as `any` without `noImplicitAny`.
12
- */
13
- export type GlobalThis = {
14
- [Key in keyof typeof globalThis]: (typeof globalThis)[Key];
15
- };
16
7
  /**
17
8
  * Writes a client script: code in the host's files that runs on the client.
18
9
  * The template is one expression, one block in braces, or one function; a
@@ -20,16 +11,11 @@ export type GlobalThis = {
20
11
  * `${expression}` splice host values into it. Returns a `Client<T>`, `T`
21
12
  * being what the script computes. Compiled when the host loads the file, by
22
13
  * a Backtick plugin; called uncompiled, it throws.
23
- *
24
- * `cs.globalThis` is what a name the script didn't bind is read off. In the
25
- * type and not in the object: nothing runs the virtual code it is written in.
26
14
  */
27
15
  export declare const cs: ((_strings: TemplateStringsArray, ..._values: unknown[]) => Client<unknown>) & {
28
16
  awaited: typeof awaited;
29
17
  create: typeof create;
30
18
  lift: typeof lift;
31
19
  splice: typeof splice;
32
- } & {
33
- readonly globalThis: GlobalThis;
34
20
  };
35
21
  export {};
package/dist/cs.js CHANGED
@@ -20,13 +20,6 @@ function awaited(_) {
20
20
  throw new Error("Don't call `cs.awaited` directly; it's used to generate virtual " +
21
21
  "code for the typechecker. Write code using cs`...` instead.");
22
22
  }
23
- // What hangs off the tag.
24
- const members = {
25
- awaited,
26
- create,
27
- lift,
28
- splice,
29
- };
30
23
  /**
31
24
  * Writes a client script: code in the host's files that runs on the client.
32
25
  * The template is one expression, one block in braces, or one function; a
@@ -34,11 +27,8 @@ const members = {
34
27
  * `${expression}` splice host values into it. Returns a `Client<T>`, `T`
35
28
  * being what the script computes. Compiled when the host loads the file, by
36
29
  * a Backtick plugin; called uncompiled, it throws.
37
- *
38
- * `cs.globalThis` is what a name the script didn't bind is read off. In the
39
- * type and not in the object: nothing runs the virtual code it is written in.
40
30
  */
41
31
  export const cs = Object.assign((_strings, ..._values) => {
42
32
  throw new Error("`cs` was not compiled. Is @backtickjs set up for this project?");
43
- }, members);
33
+ }, { awaited, create, lift, splice });
44
34
  //# sourceMappingURL=cs.js.map
package/dist/cs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cs.js","sourceRoot":"","sources":["../src/cs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,uBAAuB;AACvB,SAAS,IAAI,CAAI,CAAI;IACnB,MAAM,IAAI,KAAK,CACb,+DAA+D;QAC7D,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,gFAAgF;AAChF,sEAAsE;AACtE,uEAAuE;AACvE,SAAS,MAAM,CACb,CAAI;IAEJ,MAAM,IAAI,KAAK,CACb,iEAAiE;QAC/D,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,gDAAgD;AAChD,SAAS,OAAO,CAAI,CAAI;IACtB,MAAM,IAAI,KAAK,CACb,kEAAkE;QAChE,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,0BAA0B;AAC1B,MAAM,OAAO,GAAG;IACd,OAAO;IACP,MAAM;IACN,IAAI;IACJ,MAAM;CACP,CAAC;AAYF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAC7B,CAAC,QAA8B,EAAE,GAAG,OAAkB,EAAmB,EAAE;IACzE,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;AACJ,CAAC,EACD,OAEC,CACF,CAAC"}
1
+ {"version":3,"file":"cs.js","sourceRoot":"","sources":["../src/cs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAG3C,uBAAuB;AACvB,SAAS,IAAI,CAAI,CAAI;IACnB,MAAM,IAAI,KAAK,CACb,+DAA+D;QAC7D,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,gFAAgF;AAChF,sEAAsE;AACtE,uEAAuE;AACvE,SAAS,MAAM,CACb,CAAI;IAEJ,MAAM,IAAI,KAAK,CACb,iEAAiE;QAC/D,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,gDAAgD;AAChD,SAAS,OAAO,CAAI,CAAI;IACtB,MAAM,IAAI,KAAK,CACb,kEAAkE;QAChE,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAC7B,CAAC,QAA8B,EAAE,GAAG,OAAkB,EAAmB,EAAE;IACzE,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;AACJ,CAAC,EACD,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAClC,CAAC"}
package/dist/es.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+ /**
3
+ * Executes an ES bundle a web page starts from, the one nothing else runs, to
4
+ * its value: imported from a `data:` URL, the page's import map answering its
5
+ * imports, and those of the bundles it runs in turn with `exec`. Apart from
6
+ * `@backtickjs/core/cjs`, so a React Native app never reads its `import()`:
7
+ * Metro rejects one of anything but a string literal, and Hermes has none.
8
+ *
9
+ * const screen = await execRoot(bundle);
10
+ */
11
+ export declare function execRoot<T>(bundle: Bundle<T>): Promise<Awaited<T>>;
package/dist/es.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Executes an ES bundle a web page starts from, the one nothing else runs, to
3
+ * its value: imported from a `data:` URL, the page's import map answering its
4
+ * imports, and those of the bundles it runs in turn with `exec`. Apart from
5
+ * `@backtickjs/core/cjs`, so a React Native app never reads its `import()`:
6
+ * Metro rejects one of anything but a string literal, and Hermes has none.
7
+ *
8
+ * const screen = await execRoot(bundle);
9
+ */
10
+ export async function execRoot(bundle) {
11
+ const module = (await import("data:text/javascript," + encodeURIComponent(bundle)));
12
+ return module.default;
13
+ }
14
+ //# sourceMappingURL=es.js.map
package/dist/es.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"es.js","sourceRoot":"","sources":["../src/es.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,MAAiB;IACjD,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAC1B,uBAAuB,GAAG,kBAAkB,CAAC,MAAM,CAAC,CACrD,CAA4B,CAAC;IAC9B,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC"}
package/dist/exec.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+ import type { Client } from "./Client.js";
3
+ /**
4
+ * Executes a bundle on the client, as the bundle reading it was run, with the
5
+ * same modules, and resolves to its value: what a script fetched at runtime
6
+ * from the server, which the bundler couldn't see. As CommonJS, a function of
7
+ * `require`, handed the bundle's own; as an ES module, imported from a `data:`
8
+ * URL, which the page's import map answers.
9
+ */
10
+ export interface ClientExec extends Client<(<T>(bundle: Bundle<T>) => Promise<Awaited<T>>)> {
11
+ readonly "@backtickjs": "ClientExec";
12
+ }
13
+ export declare const exec: Client<(<T>(bundle: Bundle<T>) => Promise<Awaited<T>>)>;
14
+ export declare function isClientExec(value: unknown): value is ClientExec;
package/dist/exec.js ADDED
@@ -0,0 +1,10 @@
1
+ export const exec = {
2
+ "@backtickjs": "ClientExec",
3
+ };
4
+ export function isClientExec(value) {
5
+ return (typeof value === "object" &&
6
+ value !== null &&
7
+ "@backtickjs" in value &&
8
+ value["@backtickjs"] === "ClientExec");
9
+ }
10
+ //# sourceMappingURL=exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exec.js","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAgBA,MAAM,CAAC,MAAM,IAAI,GAA0D;IACzE,aAAa,EAAE,YAAY;CACH,CAAC;AAE3B,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,aAAa,IAAI,KAAK;QACtB,KAAK,CAAC,aAAa,CAAC,KAAK,YAAY,CACtC,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -7,5 +7,7 @@ export type { Client } from "./Client.js";
7
7
  export { once } from "./once.js";
8
8
  export type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
9
9
  export { createImport, isClientImport, type ClientImport, } from "./ClientImport.js";
10
+ export type { Bundle } from "./Bundle.js";
11
+ export { exec, isClientExec, type ClientExec } from "./exec.js";
10
12
  export { createJsxElement, isJsxElement, type JsxElement, type JsxElementOf, type JsxElementTypeOf, } from "./JsxElement.js";
11
13
  export { create, type ClientModule, type ClientScript, isClientScript, type Param, } from "./ClientScript.js";
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@
7
7
  export { cs } from "./cs.js";
8
8
  export { once } from "./once.js";
9
9
  export { createImport, isClientImport, } from "./ClientImport.js";
10
+ export { exec, isClientExec } from "./exec.js";
10
11
  // A drawing as a host builds one: what an adapter's JSX runtime makes, and
11
12
  // what the bundler expands.
12
13
  export { createJsxElement, isJsxElement, } from "./JsxElement.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,4EAA4E;AAC5E,wCAAwC;AACxC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKjC,OAAO,EACL,YAAY,EACZ,cAAc,GAEf,MAAM,mBAAmB,CAAC;AAE3B,2EAA2E;AAC3E,4BAA4B;AAC5B,OAAO,EACL,gBAAgB,EAChB,YAAY,GAIb,MAAM,iBAAiB,CAAC;AAEzB,6EAA6E;AAC7E,qCAAqC;AACrC,OAAO,EACL,MAAM,EAGN,cAAc,GAEf,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,4EAA4E;AAC5E,wCAAwC;AACxC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKjC,OAAO,EACL,YAAY,EACZ,cAAc,GAEf,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAE,IAAI,EAAE,YAAY,EAAmB,MAAM,WAAW,CAAC;AAEhE,2EAA2E;AAC3E,4BAA4B;AAC5B,OAAO,EACL,gBAAgB,EAChB,YAAY,GAIb,MAAM,iBAAiB,CAAC;AAEzB,6EAA6E;AAC7E,qCAAqC;AACrC,OAAO,EACL,MAAM,EAGN,cAAc,GAEf,MAAM,mBAAmB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtickjs/core",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "The cs tag for Backtick client scripts, and the types for the values that cross from server to client",
5
5
  "keywords": [
6
6
  "backtick",
@@ -28,6 +28,14 @@
28
28
  ".": {
29
29
  "types": "./dist/index.d.ts",
30
30
  "default": "./dist/index.js"
31
+ },
32
+ "./cjs": {
33
+ "types": "./dist/cjs.d.ts",
34
+ "default": "./dist/cjs.js"
35
+ },
36
+ "./es": {
37
+ "types": "./dist/es.d.ts",
38
+ "default": "./dist/es.js"
31
39
  }
32
40
  },
33
41
  "files": [
package/src/Bundle.ts ADDED
@@ -0,0 +1,7 @@
1
+ declare const value: unique symbol;
2
+
3
+ /**
4
+ * A bundle's code, which runs to a `T`: what the bundler writes for a
5
+ * `Client<T>`, as it reaches the client, from the server.
6
+ */
7
+ export type Bundle<T> = string & { readonly [value]: T };
@@ -24,8 +24,9 @@ export interface ClientModule {
24
24
  // `params[i]` is the function's `$splice<i>` or `$capture<i>`
25
25
  readonly params: readonly Param[];
26
26
  // What the script is written as: a function, `(props) => …`, which a splice
27
- // reads as that function; or an expression or a block, which a splice runs.
28
- readonly kind: "function" | "expression" | "block";
27
+ // reads as that function; a class, `class … {}`, one class for the bundle;
28
+ // or an expression or a block, which a splice runs.
29
+ readonly kind: "function" | "class" | "expression" | "block";
29
30
  }
30
31
 
31
32
  // One run of a `cs`: its module, and the values that run passes it. The rest
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What a bundle may import, by specifier: each the module the app imported
3
+ * for it. What a web page's import map does, for an app, with modules for
4
+ * values instead of URLs:
5
+ *
6
+ * import * as React from "react";
7
+ * import * as JSXRuntime from "react/jsx-runtime";
8
+ * import * as ReactNative from "react-native";
9
+ *
10
+ * export const moduleMap = {
11
+ * react: React,
12
+ * "react/jsx-runtime": JSXRuntime,
13
+ * "react-native": ReactNative,
14
+ * };
15
+ */
16
+ export type ModuleMap = Readonly<Record<string, unknown>>;
package/src/Spliceable.ts CHANGED
@@ -34,7 +34,7 @@ export type SplicesAs<T> = [T] extends [Spliceable]
34
34
  // Client<U> -> U
35
35
  // T[], [A, B] -> Spliced<T>[], [Spliced<A>, Spliced<B>]
36
36
  // { k: T } -> { k: Spliced<T> }
37
- // primitives -> unchanged
37
+ // primitives -> unchanged, branded ones too e.g. `Bundle<T>`
38
38
  // A tuple maps homomorphically, which keeps it a tuple; any other array stays
39
39
  // `Spliced<Item>[]`, which TypeScript defers, so `Spliceable[]` doesn't recurse.
40
40
  export type Spliced<T> =
@@ -44,6 +44,8 @@ export type Spliced<T> =
44
44
  ? number extends T["length"]
45
45
  ? Spliced<Item>[]
46
46
  : { -readonly [K in keyof T]: Spliced<T[K]> }
47
- : T extends object
48
- ? { -readonly [K in keyof T]: Spliced<T[K]> }
49
- : T;
47
+ : T extends string | number | bigint | boolean
48
+ ? T
49
+ : T extends object
50
+ ? { -readonly [K in keyof T]: Spliced<T[K]> }
51
+ : T;
package/src/cjs.ts ADDED
@@ -0,0 +1,35 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+ import type { ModuleMap } from "./ModuleMap.js";
3
+
4
+ export type { ModuleMap };
5
+
6
+ /**
7
+ * Executes a CommonJS bundle an app starts from, the one nothing else runs,
8
+ * to its value, with `require` answered from `moduleMap`: how a React Native
9
+ * app runs what its server answers. The bundles it runs in turn, with `exec`,
10
+ * get the same modules. Fetching the bundle, and when, is the app's. The
11
+ * entry an app imports is its format: a web page imports
12
+ * `@backtickjs/core/es`.
13
+ *
14
+ * const screen = await execRoot(bundle, moduleMap);
15
+ */
16
+ export async function execRoot<T>(
17
+ bundle: Bundle<T>,
18
+ moduleMap: ModuleMap,
19
+ ): Promise<Awaited<T>> {
20
+ const require = (specifier: string): unknown => {
21
+ if (!Object.hasOwn(moduleMap, specifier)) {
22
+ throw new Error(
23
+ `The bundle requires "${specifier}", which this app doesn't provide.`,
24
+ );
25
+ }
26
+ return moduleMap[specifier];
27
+ };
28
+ const module = { exports: {} as unknown };
29
+ new Function("module", "exports", "require", bundle)(
30
+ module,
31
+ module.exports,
32
+ require,
33
+ );
34
+ return module.exports as Awaited<T>;
35
+ }
package/src/cs.ts CHANGED
@@ -34,24 +34,6 @@ function awaited<T>(_: T): Awaited<T> {
34
34
  );
35
35
  }
36
36
 
37
- // What hangs off the tag.
38
- const members = {
39
- awaited,
40
- create,
41
- lift,
42
- splice,
43
- };
44
-
45
- /**
46
- * The globals a project declares — its libs, `@types`, a `declare global` —
47
- * as an ordinary object type: reading one it doesn't declare is an error
48
- * however strict the project is, where `typeof globalThis` itself lets it
49
- * through as `any` without `noImplicitAny`.
50
- */
51
- export type GlobalThis = {
52
- [Key in keyof typeof globalThis]: (typeof globalThis)[Key];
53
- };
54
-
55
37
  /**
56
38
  * Writes a client script: code in the host's files that runs on the client.
57
39
  * The template is one expression, one block in braces, or one function; a
@@ -59,9 +41,6 @@ export type GlobalThis = {
59
41
  * `${expression}` splice host values into it. Returns a `Client<T>`, `T`
60
42
  * being what the script computes. Compiled when the host loads the file, by
61
43
  * a Backtick plugin; called uncompiled, it throws.
62
- *
63
- * `cs.globalThis` is what a name the script didn't bind is read off. In the
64
- * type and not in the object: nothing runs the virtual code it is written in.
65
44
  */
66
45
  export const cs = Object.assign(
67
46
  (_strings: TemplateStringsArray, ..._values: unknown[]): Client<unknown> => {
@@ -69,7 +48,5 @@ export const cs = Object.assign(
69
48
  "`cs` was not compiled. Is @backtickjs set up for this project?",
70
49
  );
71
50
  },
72
- members as typeof members & {
73
- readonly globalThis: GlobalThis;
74
- },
51
+ { awaited, create, lift, splice },
75
52
  );
package/src/es.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+
3
+ /**
4
+ * Executes an ES bundle a web page starts from, the one nothing else runs, to
5
+ * its value: imported from a `data:` URL, the page's import map answering its
6
+ * imports, and those of the bundles it runs in turn with `exec`. Apart from
7
+ * `@backtickjs/core/cjs`, so a React Native app never reads its `import()`:
8
+ * Metro rejects one of anything but a string literal, and Hermes has none.
9
+ *
10
+ * const screen = await execRoot(bundle);
11
+ */
12
+ export async function execRoot<T>(bundle: Bundle<T>): Promise<Awaited<T>> {
13
+ const module = (await import(
14
+ "data:text/javascript," + encodeURIComponent(bundle)
15
+ )) as { default: Awaited<T> };
16
+ return module.default;
17
+ }
package/src/exec.ts ADDED
@@ -0,0 +1,28 @@
1
+ import type { Bundle } from "./Bundle.js";
2
+ import type { Client } from "./Client.js";
3
+
4
+ /**
5
+ * Executes a bundle on the client, as the bundle reading it was run, with the
6
+ * same modules, and resolves to its value: what a script fetched at runtime
7
+ * from the server, which the bundler couldn't see. As CommonJS, a function of
8
+ * `require`, handed the bundle's own; as an ES module, imported from a `data:`
9
+ * URL, which the page's import map answers.
10
+ */
11
+ export interface ClientExec extends Client<
12
+ <T>(bundle: Bundle<T>) => Promise<Awaited<T>>
13
+ > {
14
+ readonly "@backtickjs": "ClientExec";
15
+ }
16
+
17
+ export const exec: Client<<T>(bundle: Bundle<T>) => Promise<Awaited<T>>> = {
18
+ "@backtickjs": "ClientExec",
19
+ } as unknown as ClientExec;
20
+
21
+ export function isClientExec(value: unknown): value is ClientExec {
22
+ return (
23
+ typeof value === "object" &&
24
+ value !== null &&
25
+ "@backtickjs" in value &&
26
+ value["@backtickjs"] === "ClientExec"
27
+ );
28
+ }
package/src/index.ts CHANGED
@@ -17,6 +17,11 @@ export {
17
17
  isClientImport,
18
18
  type ClientImport,
19
19
  } from "./ClientImport.js";
20
+ // A bundle's code, typed by what it runs to, and, in a script, executing
21
+ // another as this one was. The one an app starts from is executed by
22
+ // `@backtickjs/core/cjs` or `@backtickjs/core/es`.
23
+ export type { Bundle } from "./Bundle.js";
24
+ export { exec, isClientExec, type ClientExec } from "./exec.js";
20
25
 
21
26
  // A drawing as a host builds one: what an adapter's JSX runtime makes, and
22
27
  // what the bundler expands.