Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e5d2f33
feat(reactive-rpc): 🎸 add util.schema route
streamich Nov 16, 2023
dc8110c
feat(json-type): 🎸 emit function TypeScript ASTs
streamich Nov 16, 2023
d9234d0
feat(json-type): 🎸 export router to TypeScript type annotations text
streamich Nov 16, 2023
ddab5b2
feat(json-type): 🎸 export router as a TypeScript modeul
streamich Nov 16, 2023
7d8a45a
test(json-type): 💍 check that type aliases are exported
streamich Nov 16, 2023
a40d36f
feat(reactive-rpc): 🎸 return TS types from util.schema
streamich Nov 16, 2023
9bdd15c
style: 💄 run Prettier
streamich Nov 16, 2023
4f9f895
chore(reactive-rpc): 🤖 replicate .ping error responseee
streamich Nov 17, 2023
a11c5c2
refactor(reactive-rpc): 💡 improve error method name
streamich Nov 17, 2023
eb1a5f9
feat(reactive-rpc): 🎸 improve decoding error handling
streamich Nov 17, 2023
294d3b9
feat(reactive-rpc): 🎸 improve error reporting
streamich Nov 17, 2023
409c7be
chore: 🤖 run Prettier and remove old tests
streamich Nov 17, 2023
83166bb
feat(reactive-rpc): 🎸 improve how WebSocket context is constructed
streamich Nov 17, 2023
e018a72
test(reactive-rpc): 💍 make E2E Websocket tests run
streamich Nov 17, 2023
10ef9eb
fix(reactive-rpc): 🐛 always use binary encoding for Websocket messages
streamich Nov 17, 2023
3f43171
style(reactive-rpc): 💄 run Prettier
streamich Nov 17, 2023
fe690d8
feat(reactive-rpc): 🎸 add ability to store response codec in RpcCodec
streamich Nov 17, 2023
803401b
feat(reactive-rpc): 🎸 support different request/response codecs in We…
streamich Nov 17, 2023
acd6379
test(reactive-rpc): 💍 move folders of E2E tests
streamich Nov 17, 2023
2fcdf69
test(reactive-rpc): 💍 move Reactive RPC E2E tests under the /src/reac…
streamich Nov 17, 2023
4ee7d5c
style(reactive-rpc): 💄 run Prettier
streamich Nov 17, 2023
a16547e
test(reactive-rpc): 💍 exit testing process after E2E tests are done
streamich Nov 17, 2023
50d3b0a
test: 💍 add .stop() methods for RPC clients
streamich Nov 17, 2023
32f1791
feat(reactive-rpc): 🎸 add convenience methods for RPC client instanti…
streamich Nov 17, 2023
c9e186c
refactor(reactive-rpc): 💡 remove server part from RpcPersistentClient
streamich Nov 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
- run: yarn test:cli:pack
- run: yarn demo:json-patch
- run: yarn demo:json-pointer
rx-rpc:
e2e-rx-rpc:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -59,5 +59,4 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: yarn
- run: yarn install --frozen-lockfile
- run: yarn build:all
- run: PORT=9999 yarn test:reactive-rpc
- run: yarn test:reactive-rpc
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@
"build": "yarn build:es2020",
"jest": "node -r ts-node/register ./node_modules/.bin/jest",
"test": "jest --maxWorkers 7",
"test:all": "yarn lint && yarn test && yarn test:cli:pointer && yarn test:cli:patch && yarn test:cli:pack && yarn test:reactive-rpc && yarn demo:json-patch && yarn demo:json-pointer",
"test:all": "yarn lint && yarn test && yarn build:all && yarn test:cli:pointer && yarn test:cli:patch && yarn test:cli:pack && yarn test:reactive-rpc && yarn demo:json-patch && yarn demo:json-pointer",
"test:ci": "yarn jest --maxWorkers 3 --no-cache",
"test:cli": "yarn test:cli:pointer && yarn test:cli:patch && yarn test:cli:pack",
"test:cli:pointer": "./bin/json-pointer-test.js ./bin/json-pointer.js",
"test:cli:patch": "./bin/json-patch-test.js ./bin/json-patch.js",
"test:cli:pack": "./bin/json-pack-test.js ./bin/json-pack.js",
"test:reactive-rpc": "node -r ts-node/register/transpile-only src/__tests__/reactive-rpc/run.ts",
"test:reactive-rpc:jest": "TEST_E2E=1 jest --maxWorkers 1 --no-cache src/__tests__/reactive-rpc/",
"test:reactive-rpc": "node -r ts-node/register/transpile-only src/reactive-rpc/__tests__/e2e/run.ts",
"test:reactive-rpc:jest": "TEST_E2E=1 jest --maxWorkers 1 --no-cache src/reactive-rpc/__tests__/e2e/",
"demo:json-patch": "ts-node src/json-patch/__demos__/json-patch.ts",
"demo:json-pointer": "ts-node src/json-pointer/__demos__/json-pointer.ts",
"demo:reactive-rpc:server": "ts-node src/reactive-rpc/__demos__/server.ts",
Expand Down Expand Up @@ -158,7 +158,7 @@
"webpack": "^5.84.1",
"webpack-cli": "^5.1.1",
"webpack-dev-server": "^4.15.0",
"ws": "^8.6.0",
"ws": "^8.14.2",
"yjs": "13.6.8",
"ywasm": "0.16.10"
},
Expand Down
45 changes: 44 additions & 1 deletion src/json-type/system/TypeRouter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as classes from '../type/classes';
import {TypeSystem} from './TypeSystem';
import {toText} from '../typescript/toText';
import type * as ts from '../typescript/types';
import type {TypeBuilder} from '../type/TypeBuilder';

export interface TypeRouterOptions<R extends RoutesBase> {
Expand Down Expand Up @@ -27,7 +29,7 @@ export class TypeRouter<Routes extends RoutesBase> {
this.system = options.system;
this.t = this.system.t;
this.routes = options.routes;
this.system.importTypes(this.routes);
// this.system.importTypes(this.routes);
}

protected merge<Router extends TypeRouter<any>>(router: Router): TypeRouter<Routes & TypeRouterRoutes<Router>> {
Expand Down Expand Up @@ -60,6 +62,47 @@ export class TypeRouter<Routes extends RoutesBase> {
this.routes[name] = <any>type;
return <any>this;
}

public toTypeScriptAst(): ts.TsTypeLiteral {
const node: ts.TsTypeLiteral = {
node: 'TypeLiteral',
members: [],
};
for (const [name, type] of Object.entries(this.routes)) {
const schema = type.getSchema();
const property: ts.TsPropertySignature = {
node: 'PropertySignature',
name,
type: type.toTypeScriptAst(),
};
if (schema.title) property.comment = schema.title;
node.members.push(property);
}
return node;
}

public toTypeScriptModuleAst(): ts.TsModuleDeclaration {
const node: ts.TsModuleDeclaration = {
node: 'ModuleDeclaration',
name: 'Router',
export: true,
statements: [
{
node: 'TypeAliasDeclaration',
name: 'Routes',
type: this.toTypeScriptAst(),
export: true,
},
],
};
for (const alias of this.system.aliases.values()) node.statements.push({...alias.toTypeScriptAst(), export: true});
return node;
}

public toTypeScript(): string {
this.system.exportTypes;
return toText(this.toTypeScriptModuleAst());
}
}

export type RoutesBase = Record<string, classes.FunctionType<any, any> | classes.FunctionStreamingType<any, any>>;
Expand Down
2 changes: 1 addition & 1 deletion src/json-type/system/TypeSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type {Printable} from '../../util/print/types';
export class TypeSystem implements Printable {
public readonly t = new TypeBuilder(this);

protected readonly aliases: Map<string, TypeAlias<string, any>> = new Map();
public readonly aliases: Map<string, TypeAlias<string, any>> = new Map();

/**
* @todo Add ability fetch object of given type by its ID, analogous to
Expand Down
47 changes: 47 additions & 0 deletions src/json-type/system/__tests__/toTypeScript.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {TypeSystem} from '..';
import {TypeRouter} from '../TypeRouter';

test('generates TypeScript source for simple string type', () => {
const system = new TypeSystem();
Expand Down Expand Up @@ -91,3 +92,49 @@ test('type interface inside a tuple', () => {
"
`);
});

test('can export whole router', () => {
const system = new TypeSystem();
const {t} = system;
const router = new TypeRouter({system, routes: {}}).extend(() => ({
callMe: t.Function(t.str, t.num),
'block.subscribe': t.Function$(t.Object(t.prop('id', t.str)), t.obj),
}));
expect(router.toTypeScript()).toMatchInlineSnapshot(`
"export namespace Router {
export type Routes = {
callMe: (request: string) => Promise<number>;
"block.subscribe": (request$: Observable<{
id: string;
}>) => Observable<{}>;
};
}
"
`);
});

test('can export whole router and aliases', () => {
const system = new TypeSystem();
const {t} = system;
system.alias('Document', t.Object(t.prop('id', t.str), t.prop('title', t.str)).options({title: 'The document'}));
const router = new TypeRouter({system, routes: {}}).extend(() => ({
callMe: t.Function(t.str, t.num),
'block.subscribe': t.Function$(t.Object(t.prop('id', t.str)), t.Ref('Document')),
}));
expect(router.toTypeScript()).toMatchInlineSnapshot(`
"export namespace Router {
export type Routes = {
callMe: (request: string) => Promise<number>;
"block.subscribe": (request$: Observable<{
id: string;
}>) => Observable<Document>;
};

export interface Document {
id: string;
title: string;
}
}
"
`);
});
83 changes: 83 additions & 0 deletions src/json-type/type/__tests__/toTypeScriptAst.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,86 @@ describe('or', () => {
`);
});
});

describe('fn', () => {
test('can emit reference AST', () => {
const system = new TypeSystem();
const {t} = system;
const type = system.t.Function(t.str, t.num);
expect(type.toTypeScriptAst()).toMatchInlineSnapshot(`
{
"node": "FunctionType",
"parameters": [
{
"name": {
"name": "request",
"node": "Identifier",
},
"node": "Parameter",
"type": {
"node": "StringKeyword",
},
},
],
"type": {
"node": "TypeReference",
"typeArguments": [
{
"node": "NumberKeyword",
},
],
"typeName": {
"name": "Promise",
"node": "Identifier",
},
},
}
`);
});
});

describe('fn$', () => {
test('can emit reference AST', () => {
const system = new TypeSystem();
const {t} = system;
const type = system.t.Function$(t.str, t.num);
expect(type.toTypeScriptAst()).toMatchInlineSnapshot(`
{
"node": "FunctionType",
"parameters": [
{
"name": {
"name": "request$",
"node": "Identifier",
},
"node": "Parameter",
"type": {
"node": "TypeReference",
"typeArguments": [
{
"node": "StringKeyword",
},
],
"typeName": {
"name": "Observable",
"node": "Identifier",
},
},
},
],
"type": {
"node": "TypeReference",
"typeArguments": [
{
"node": "NumberKeyword",
},
],
"typeName": {
"name": "Observable",
"node": "Identifier",
},
},
}
`);
});
});
57 changes: 53 additions & 4 deletions src/json-type/type/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2228,8 +2228,29 @@ export class FunctionType<Req extends Type, Res extends Type> extends AbstractTy
return this;
}

public toTypeScriptAst(): ts.TsUnionType {
throw new Error('Method not implemented.');
public toTypeScriptAst(): ts.TsFunctionType {
const node: ts.TsFunctionType = {
node: 'FunctionType',
parameters: [
{
node: 'Parameter',
name: {
node: 'Identifier',
name: 'request',
},
type: this.req.toTypeScriptAst(),
},
],
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Promise',
},
typeArguments: [this.res.toTypeScriptAst()],
},
};
return node;
}

public toString(tab: string = ''): string {
Expand Down Expand Up @@ -2289,8 +2310,36 @@ export class FunctionStreamingType<Req extends Type, Res extends Type> extends A
return this;
}

public toTypeScriptAst(): ts.TsUnionType {
throw new Error('Method not implemented.');
public toTypeScriptAst(): ts.TsFunctionType {
const node: ts.TsFunctionType = {
node: 'FunctionType',
parameters: [
{
node: 'Parameter',
name: {
node: 'Identifier',
name: 'request$',
},
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Observable',
},
typeArguments: [this.req.toTypeScriptAst()],
},
},
],
type: {
node: 'TypeReference',
typeName: {
node: 'Identifier',
name: 'Observable',
},
typeArguments: [this.res.toTypeScriptAst()],
},
};
return node;
}

public toString(tab: string = ''): string {
Expand Down
Loading