@backtickjs/core 0.1.4 → 0.1.5
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 +3 -4
- package/dist/Client.d.ts +6 -0
- package/dist/Spliceable.d.ts +14 -6
- package/dist/cs.d.ts +13 -3
- package/dist/cs.js +15 -5
- package/dist/cs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/Client.ts +7 -0
- package/src/Spliceable.ts +17 -3
- package/src/cs.ts +17 -8
- package/src/index.ts +1 -1
package/README.md
CHANGED
|
@@ -36,9 +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.
|
|
40
|
-
|
|
41
|
-
What can be spliced is `Spliceable`: strings, numbers, booleans, `null`, `undefined`, plain arrays and objects of those, and scripts. Host functions and class instances can't be spliced; a function the client calls is written as a script, `` cs`(n: number) => …` ``.
|
|
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.
|
|
42
40
|
|
|
43
41
|
To use a package the client provides beyond what an adapter covers, describe its export with `createImport`. `from` is the specifier the bundle imports, and `version` the semver range of its package that the export works with:
|
|
44
42
|
|
|
@@ -63,6 +61,7 @@ The client must provide that package, and the server must list it in the bundler
|
|
|
63
61
|
- `Spliced<T>`: what a spliceable value becomes on the client (`Client<U>` becomes `U`; arrays and objects map member by member).
|
|
64
62
|
- `createImport<T>({ name, from, version })`: an export of a module the client provides, as a value a script can splice.
|
|
65
63
|
- `isClientImport`, `ClientImport`: its check and type.
|
|
64
|
+
- `SplicesAs<T>`: `T` as a splice checks it, member by member. Used by the bundler to check its input.
|
|
66
65
|
- `createJsxElement`, `isJsxElement`, `JsxElement`, `JsxElementOf`, `JsxElementTypeOf`: what a server-side JSX tag evaluates to before bundling. Used by adapters' JSX runtimes.
|
|
67
66
|
- `create`, `isClientScript`, `ClientScript`, `ClientModule`, `Param`: the compiled form of a script, written by the compiler and read by the bundler. Not for application code.
|
|
68
67
|
|
|
@@ -72,7 +71,7 @@ The client must provide that package, and the server must list it in the bundler
|
|
|
72
71
|
- [`@backtickjs/react`](https://github.com/backtickjs/backtick/tree/main/packages/react), [`@backtickjs/react-native`](https://github.com/backtickjs/backtick/tree/main/packages/react-native), [`@backtickjs/solid-js`](https://github.com/backtickjs/backtick/tree/main/packages/solid-js): framework adapters
|
|
73
72
|
- [`@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
|
|
74
73
|
- [`@backtickjs/tsc`](https://github.com/backtickjs/backtick/tree/main/packages/tsc): type-checks scripts and their splices
|
|
75
|
-
- [
|
|
74
|
+
- [Thinking in Backtick](https://backtickjs.com/docs/thinking-in-backtick), [Scripts in depth](https://backtickjs.com/docs/scripts-in-depth)
|
|
76
75
|
|
|
77
76
|
## License
|
|
78
77
|
|
package/dist/Client.d.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
declare const ClientBrand: unique symbol;
|
|
2
|
+
/**
|
|
3
|
+
* A client script, as the host holds it: a value the client computes as a
|
|
4
|
+
* `T`. The host can't read the `T`, which doesn't exist until the client runs
|
|
5
|
+
* the script; it can splice the script into another, pass it around, and
|
|
6
|
+
* return it from a server component.
|
|
7
|
+
*/
|
|
2
8
|
export interface Client<T> {
|
|
3
9
|
readonly [ClientBrand]: T;
|
|
4
10
|
}
|
package/dist/Spliceable.d.ts
CHANGED
|
@@ -2,14 +2,22 @@ import type { Client } from "./Client.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* What the host may splice: the value written out, a script standing in for
|
|
4
4
|
* it, or a container mixing the two. Not a host function, which is host code:
|
|
5
|
-
* a client function is a script, cs`(n: number) => …`.
|
|
6
|
-
*
|
|
5
|
+
* a client function is a script, cs`(n: number) => …`. Matches an object
|
|
6
|
+
* through an index signature, which TypeScript gives a type alias but never an
|
|
7
|
+
* interface: a splice checks with `SplicesAs`, which takes either.
|
|
7
8
|
*/
|
|
8
|
-
export type Spliceable = Client<unknown> | null | undefined | number | boolean | string | readonly Spliceable[] | {
|
|
9
|
+
export type Spliceable = Client<unknown> | null | undefined | number | bigint | boolean | string | readonly Spliceable[] | {
|
|
9
10
|
readonly [key: string]: Spliceable;
|
|
10
11
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
/**
|
|
13
|
+
* `T` as a splice checks it, member by member, so it takes an interface as a
|
|
14
|
+
* type alias. What already is
|
|
15
|
+
* `Spliceable` is as it is; a function, which can't cross, is checked against
|
|
16
|
+
* `Spliceable`, and fails.
|
|
17
|
+
*/
|
|
18
|
+
export type SplicesAs<T> = [T] extends [Spliceable] ? T : T extends (...args: never) => unknown ? Spliceable : {
|
|
19
|
+
readonly [K in keyof T]: SplicesAs<T[K]>;
|
|
20
|
+
};
|
|
21
|
+
export type Spliced<T> = T extends Client<infer U> ? U : T extends readonly (infer Item extends Spliceable)[] ? Spliced<Item>[] : T extends object ? {
|
|
14
22
|
-readonly [K in keyof T]: Spliced<T[K]>;
|
|
15
23
|
} : T;
|
package/dist/cs.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Client } from "./Client.js";
|
|
2
2
|
import { create } from "./ClientScript.js";
|
|
3
|
-
import type { Spliceable } from "./Spliceable.js";
|
|
4
|
-
import type { Spliced } from "./Spliceable.js";
|
|
3
|
+
import type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
|
|
5
4
|
declare function lift<T>(_: T): Client<T>;
|
|
6
|
-
declare function splice<T extends [T] extends [
|
|
5
|
+
declare function splice<T extends [T] extends [SplicesAs<T>] ? unknown : Spliceable>(_: T): unknown extends Spliced<T> ? any : Spliced<T>;
|
|
7
6
|
declare function awaited<T>(_: T): Awaited<T>;
|
|
8
7
|
/**
|
|
9
8
|
* The globals a project declares — its libs, `@types`, a `declare global` —
|
|
@@ -14,6 +13,17 @@ declare function awaited<T>(_: T): Awaited<T>;
|
|
|
14
13
|
export type GlobalThis = {
|
|
15
14
|
[Key in keyof typeof globalThis]: (typeof globalThis)[Key];
|
|
16
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Writes a client script: code in the host's files that runs on the client.
|
|
18
|
+
* The template is one expression, one block in braces, or one function; a
|
|
19
|
+
* function that returns JSX is a client component. `$name` and
|
|
20
|
+
* `${expression}` splice host values into it. Returns a `Client<T>`, `T`
|
|
21
|
+
* being what the script computes. Compiled when the host loads the file, by
|
|
22
|
+
* 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
|
+
*/
|
|
17
27
|
export declare const cs: ((_strings: TemplateStringsArray, ..._values: unknown[]) => Client<unknown>) & {
|
|
18
28
|
awaited: typeof awaited;
|
|
19
29
|
create: typeof create;
|
package/dist/cs.js
CHANGED
|
@@ -6,9 +6,10 @@ function lift(_) {
|
|
|
6
6
|
}
|
|
7
7
|
// A constraint that is `unknown` for a value that splices, rather than
|
|
8
8
|
// `Spliceable` itself or an intersection with it: either of those keeps a
|
|
9
|
-
// literal a literal instead of widening it.
|
|
10
|
-
//
|
|
11
|
-
// `Spliceable`,
|
|
9
|
+
// literal a literal instead of widening it. Checked member by member, as
|
|
10
|
+
// `SplicesAs<T>`, so an interface splices too. What can't be spliced is refused
|
|
11
|
+
// once, where it is written, as not `Spliceable`, and is `any` after:
|
|
12
|
+
// refused, `T` falls back to `Spliceable`, which splices to `unknown`.
|
|
12
13
|
function splice(_) {
|
|
13
14
|
throw new Error("Don't call `cs.splice` directly; it's used to generate virtual " +
|
|
14
15
|
"code for the typechecker. Write code using cs`...` instead.");
|
|
@@ -26,8 +27,17 @@ const members = {
|
|
|
26
27
|
lift,
|
|
27
28
|
splice,
|
|
28
29
|
};
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Writes a client script: code in the host's files that runs on the client.
|
|
32
|
+
* The template is one expression, one block in braces, or one function; a
|
|
33
|
+
* function that returns JSX is a client component. `$name` and
|
|
34
|
+
* `${expression}` splice host values into it. Returns a `Client<T>`, `T`
|
|
35
|
+
* being what the script computes. Compiled when the host loads the file, by
|
|
36
|
+
* 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
|
+
*/
|
|
31
41
|
export const cs = Object.assign((_strings, ..._values) => {
|
|
32
42
|
throw new Error("`cs` was not compiled. Is @backtickjs set up for this project?");
|
|
33
43
|
}, members);
|
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;
|
|
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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export { cs } from "./cs.js";
|
|
6
6
|
export type { Client } from "./Client.js";
|
|
7
|
-
export type { Spliceable, Spliced } from "./Spliceable.js";
|
|
7
|
+
export type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
|
|
8
8
|
export { createImport, isClientImport, type ClientImport, } from "./ClientImport.js";
|
|
9
9
|
export { createJsxElement, isJsxElement, type JsxElement, type JsxElementOf, type JsxElementTypeOf, } from "./JsxElement.js";
|
|
10
10
|
export { create, type ClientModule, type ClientScript, isClientScript, type Param, } from "./ClientScript.js";
|
package/package.json
CHANGED
package/src/Client.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
declare const ClientBrand: unique symbol;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A client script, as the host holds it: a value the client computes as a
|
|
5
|
+
* `T`. The host can't read the `T`, which doesn't exist until the client runs
|
|
6
|
+
* the script; it can splice the script into another, pass it around, and
|
|
7
|
+
* return it from a server component.
|
|
8
|
+
*/
|
|
2
9
|
export interface Client<T> {
|
|
3
10
|
readonly [ClientBrand]: T;
|
|
4
11
|
}
|
package/src/Spliceable.ts
CHANGED
|
@@ -3,19 +3,33 @@ import type { Client } from "./Client.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* What the host may splice: the value written out, a script standing in for
|
|
5
5
|
* it, or a container mixing the two. Not a host function, which is host code:
|
|
6
|
-
* a client function is a script, cs`(n: number) => …`.
|
|
7
|
-
*
|
|
6
|
+
* a client function is a script, cs`(n: number) => …`. Matches an object
|
|
7
|
+
* through an index signature, which TypeScript gives a type alias but never an
|
|
8
|
+
* interface: a splice checks with `SplicesAs`, which takes either.
|
|
8
9
|
*/
|
|
9
10
|
export type Spliceable =
|
|
10
11
|
| Client<unknown>
|
|
11
12
|
| null
|
|
12
13
|
| undefined
|
|
13
14
|
| number
|
|
15
|
+
| bigint
|
|
14
16
|
| boolean
|
|
15
17
|
| string
|
|
16
18
|
| readonly Spliceable[]
|
|
17
19
|
| { readonly [key: string]: Spliceable };
|
|
18
20
|
|
|
21
|
+
/**
|
|
22
|
+
* `T` as a splice checks it, member by member, so it takes an interface as a
|
|
23
|
+
* type alias. What already is
|
|
24
|
+
* `Spliceable` is as it is; a function, which can't cross, is checked against
|
|
25
|
+
* `Spliceable`, and fails.
|
|
26
|
+
*/
|
|
27
|
+
export type SplicesAs<T> = [T] extends [Spliceable]
|
|
28
|
+
? T
|
|
29
|
+
: T extends (...args: never) => unknown
|
|
30
|
+
? Spliceable
|
|
31
|
+
: { readonly [K in keyof T]: SplicesAs<T[K]> };
|
|
32
|
+
|
|
19
33
|
// What a spliceable becomes on the client:
|
|
20
34
|
// Client<U> -> U
|
|
21
35
|
// T[] -> Spliced<T>[]
|
|
@@ -26,6 +40,6 @@ export type Spliced<T> =
|
|
|
26
40
|
? U
|
|
27
41
|
: T extends readonly (infer Item extends Spliceable)[]
|
|
28
42
|
? Spliced<Item>[]
|
|
29
|
-
: T extends
|
|
43
|
+
: T extends object
|
|
30
44
|
? { -readonly [K in keyof T]: Spliced<T[K]> }
|
|
31
45
|
: T;
|
package/src/cs.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { Client } from "./Client.js";
|
|
2
2
|
import { create } from "./ClientScript.js";
|
|
3
|
-
import type { Spliceable } from "./Spliceable.js";
|
|
4
|
-
import type { Spliced } from "./Spliceable.js";
|
|
3
|
+
import type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
|
|
5
4
|
|
|
6
5
|
// The root of a script
|
|
7
6
|
function lift<T>(_: T): Client<T> {
|
|
@@ -13,10 +12,11 @@ function lift<T>(_: T): Client<T> {
|
|
|
13
12
|
|
|
14
13
|
// A constraint that is `unknown` for a value that splices, rather than
|
|
15
14
|
// `Spliceable` itself or an intersection with it: either of those keeps a
|
|
16
|
-
// literal a literal instead of widening it.
|
|
17
|
-
//
|
|
18
|
-
// `Spliceable`,
|
|
19
|
-
|
|
15
|
+
// literal a literal instead of widening it. Checked member by member, as
|
|
16
|
+
// `SplicesAs<T>`, so an interface splices too. What can't be spliced is refused
|
|
17
|
+
// once, where it is written, as not `Spliceable`, and is `any` after:
|
|
18
|
+
// refused, `T` falls back to `Spliceable`, which splices to `unknown`.
|
|
19
|
+
function splice<T extends [T] extends [SplicesAs<T>] ? unknown : Spliceable>(
|
|
20
20
|
_: T,
|
|
21
21
|
): unknown extends Spliced<T> ? any : Spliced<T> {
|
|
22
22
|
throw new Error(
|
|
@@ -52,8 +52,17 @@ export type GlobalThis = {
|
|
|
52
52
|
[Key in keyof typeof globalThis]: (typeof globalThis)[Key];
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Writes a client script: code in the host's files that runs on the client.
|
|
57
|
+
* The template is one expression, one block in braces, or one function; a
|
|
58
|
+
* function that returns JSX is a client component. `$name` and
|
|
59
|
+
* `${expression}` splice host values into it. Returns a `Client<T>`, `T`
|
|
60
|
+
* being what the script computes. Compiled when the host loads the file, by
|
|
61
|
+
* 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
|
+
*/
|
|
57
66
|
export const cs = Object.assign(
|
|
58
67
|
(_strings: TemplateStringsArray, ..._values: unknown[]): Client<unknown> => {
|
|
59
68
|
throw new Error(
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ export type { Client } from "./Client.js";
|
|
|
9
9
|
|
|
10
10
|
// What a host may hand a client: data, a script, or an export of a module the
|
|
11
11
|
// client provides.
|
|
12
|
-
export type { Spliceable, Spliced } from "./Spliceable.js";
|
|
12
|
+
export type { Spliceable, SplicesAs, Spliced } from "./Spliceable.js";
|
|
13
13
|
export {
|
|
14
14
|
createImport,
|
|
15
15
|
isClientImport,
|