@backtickjs/core 0.1.4 → 0.1.6

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,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. A server component is drawn inside a script through a splice: `{${<Footer />}}`.
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
- - [Documentation](https://backtickjs.com/docs)
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
  }
@@ -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) => …`. An index signature rather than a mapped
6
- * type, so it can be named in a `satisfies` without a type to walk.
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
- export type Spliced<T> = T extends Client<infer U> ? U : T extends readonly (infer Item extends Spliceable)[] ? Spliced<Item>[] : T extends {
12
- readonly [key: string]: Spliceable;
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 [Spliceable] ? unknown : Spliceable>(_: T): unknown extends Spliced<T> ? any : Spliced<T>;
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. What can't be spliced is refused
10
- // once, where it is written, and is `any` after: refused, `T` falls back to
11
- // `Spliceable`, which splices to `unknown`.
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
- // `globalThis`, which a name the script didn't bind is read off. In the type
30
- // and not in the object: nothing runs the virtual code it is written in.
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;AAI3C,uBAAuB;AACvB,SAAS,IAAI,CAAI,CAAI;IACnB,MAAM,IAAI,KAAK,CACb,+DAA+D;QAC7D,6DAA6D,CAChE,CAAC;AACJ,CAAC;AAED,uEAAuE;AACvE,0EAA0E;AAC1E,6EAA6E;AAC7E,4EAA4E;AAC5E,4CAA4C;AAC5C,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,6EAA6E;AAC7E,yEAAyE;AACzE,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,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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtickjs/core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
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",
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) => …`. An index signature rather than a mapped
7
- * type, so it can be named in a `satisfies` without a type to walk.
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 { readonly [key: string]: Spliceable }
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. What can't be spliced is refused
17
- // once, where it is written, and is `any` after: refused, `T` falls back to
18
- // `Spliceable`, which splices to `unknown`.
19
- function splice<T extends [T] extends [Spliceable] ? unknown : Spliceable>(
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
- // `globalThis`, which a name the script didn't bind is read off. In the type
56
- // and not in the object: nothing runs the virtual code it is written in.
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,