feat(rpc): convert protocol to yaml (#3102)
This commit is contained in:
parent
b1a5a02154
commit
68c4f79b02
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -11413,6 +11413,12 @@
|
||||||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"yaml": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "13.2.4",
|
"version": "13.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz",
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@
|
||||||
"ts-loader": "^6.1.2",
|
"ts-loader": "^6.1.2",
|
||||||
"typescript": "^3.8.3",
|
"typescript": "^3.8.3",
|
||||||
"webpack": "^4.41.0",
|
"webpack": "^4.41.0",
|
||||||
"webpack-cli": "^3.3.9"
|
"webpack-cli": "^3.3.9",
|
||||||
|
"yaml": "^1.10.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,8 @@ export interface BrowserContextChannel extends Channel {
|
||||||
on(event: 'close', callback: (params: BrowserContextCloseEvent) => void): this;
|
on(event: 'close', callback: (params: BrowserContextCloseEvent) => void): this;
|
||||||
on(event: 'page', callback: (params: BrowserContextPageEvent) => void): this;
|
on(event: 'page', callback: (params: BrowserContextPageEvent) => void): this;
|
||||||
on(event: 'route', callback: (params: BrowserContextRouteEvent) => void): this;
|
on(event: 'route', callback: (params: BrowserContextRouteEvent) => void): this;
|
||||||
|
on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this;
|
||||||
|
on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this;
|
||||||
addCookies(params: BrowserContextAddCookiesParams): Promise<BrowserContextAddCookiesResult>;
|
addCookies(params: BrowserContextAddCookiesParams): Promise<BrowserContextAddCookiesResult>;
|
||||||
addInitScript(params: BrowserContextAddInitScriptParams): Promise<BrowserContextAddInitScriptResult>;
|
addInitScript(params: BrowserContextAddInitScriptParams): Promise<BrowserContextAddInitScriptResult>;
|
||||||
clearCookies(params?: BrowserContextClearCookiesParams): Promise<BrowserContextClearCookiesResult>;
|
clearCookies(params?: BrowserContextClearCookiesParams): Promise<BrowserContextClearCookiesResult>;
|
||||||
|
|
@ -368,8 +370,6 @@ export interface BrowserContextChannel extends Channel {
|
||||||
setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams): Promise<BrowserContextSetHTTPCredentialsResult>;
|
setHTTPCredentials(params: BrowserContextSetHTTPCredentialsParams): Promise<BrowserContextSetHTTPCredentialsResult>;
|
||||||
setNetworkInterceptionEnabled(params: BrowserContextSetNetworkInterceptionEnabledParams): Promise<BrowserContextSetNetworkInterceptionEnabledResult>;
|
setNetworkInterceptionEnabled(params: BrowserContextSetNetworkInterceptionEnabledParams): Promise<BrowserContextSetNetworkInterceptionEnabledResult>;
|
||||||
setOffline(params: BrowserContextSetOfflineParams): Promise<BrowserContextSetOfflineResult>;
|
setOffline(params: BrowserContextSetOfflineParams): Promise<BrowserContextSetOfflineResult>;
|
||||||
on(event: 'crBackgroundPage', callback: (params: BrowserContextCrBackgroundPageEvent) => void): this;
|
|
||||||
on(event: 'crServiceWorker', callback: (params: BrowserContextCrServiceWorkerEvent) => void): this;
|
|
||||||
crNewCDPSession(params: BrowserContextCrNewCDPSessionParams): Promise<BrowserContextCrNewCDPSessionResult>;
|
crNewCDPSession(params: BrowserContextCrNewCDPSessionParams): Promise<BrowserContextCrNewCDPSessionResult>;
|
||||||
}
|
}
|
||||||
export type BrowserContextBindingCallEvent = {
|
export type BrowserContextBindingCallEvent = {
|
||||||
|
|
@ -383,6 +383,12 @@ export type BrowserContextRouteEvent = {
|
||||||
route: RouteChannel,
|
route: RouteChannel,
|
||||||
request: RequestChannel,
|
request: RequestChannel,
|
||||||
};
|
};
|
||||||
|
export type BrowserContextCrBackgroundPageEvent = {
|
||||||
|
page: PageChannel,
|
||||||
|
};
|
||||||
|
export type BrowserContextCrServiceWorkerEvent = {
|
||||||
|
worker: WorkerChannel,
|
||||||
|
};
|
||||||
export type BrowserContextAddCookiesParams = {
|
export type BrowserContextAddCookiesParams = {
|
||||||
cookies: {
|
cookies: {
|
||||||
name: string,
|
name: string,
|
||||||
|
|
@ -473,12 +479,6 @@ export type BrowserContextSetOfflineParams = {
|
||||||
offline: boolean,
|
offline: boolean,
|
||||||
};
|
};
|
||||||
export type BrowserContextSetOfflineResult = void;
|
export type BrowserContextSetOfflineResult = void;
|
||||||
export type BrowserContextCrBackgroundPageEvent = {
|
|
||||||
page: PageChannel,
|
|
||||||
};
|
|
||||||
export type BrowserContextCrServiceWorkerEvent = {
|
|
||||||
worker: WorkerChannel,
|
|
||||||
};
|
|
||||||
export type BrowserContextCrNewCDPSessionParams = {
|
export type BrowserContextCrNewCDPSessionParams = {
|
||||||
page: PageChannel,
|
page: PageChannel,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,12 @@ scheme.BrowserContextRouteEvent = tObject({
|
||||||
route: tChannel('Route'),
|
route: tChannel('Route'),
|
||||||
request: tChannel('Request'),
|
request: tChannel('Request'),
|
||||||
});
|
});
|
||||||
|
scheme.BrowserContextCrBackgroundPageEvent = tObject({
|
||||||
|
page: tChannel('Page'),
|
||||||
|
});
|
||||||
|
scheme.BrowserContextCrServiceWorkerEvent = tObject({
|
||||||
|
worker: tChannel('Worker'),
|
||||||
|
});
|
||||||
scheme.BrowserContextAddCookiesParams = tObject({
|
scheme.BrowserContextAddCookiesParams = tObject({
|
||||||
cookies: tArray(tObject({
|
cookies: tArray(tObject({
|
||||||
name: tString,
|
name: tString,
|
||||||
|
|
@ -404,12 +410,6 @@ scheme.BrowserContextSetOfflineParams = tObject({
|
||||||
offline: tBoolean,
|
offline: tBoolean,
|
||||||
});
|
});
|
||||||
scheme.BrowserContextSetOfflineResult = tUndefined;
|
scheme.BrowserContextSetOfflineResult = tUndefined;
|
||||||
scheme.BrowserContextCrBackgroundPageEvent = tObject({
|
|
||||||
page: tChannel('Page'),
|
|
||||||
});
|
|
||||||
scheme.BrowserContextCrServiceWorkerEvent = tObject({
|
|
||||||
worker: tChannel('Worker'),
|
|
||||||
});
|
|
||||||
scheme.BrowserContextCrNewCDPSessionParams = tObject({
|
scheme.BrowserContextCrNewCDPSessionParams = tObject({
|
||||||
page: tChannel('Page'),
|
page: tChannel('Page'),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
1482
src/rpc/protocol.pdl
1482
src/rpc/protocol.pdl
File diff suppressed because it is too large
Load diff
1926
src/rpc/protocol.yml
Normal file
1926
src/rpc/protocol.yml
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,145 +17,76 @@
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const yaml = require('yaml');
|
||||||
|
|
||||||
const channels = new Set();
|
const channels = new Set();
|
||||||
|
|
||||||
function tokenize(source) {
|
|
||||||
const lines = source.split('\n').filter(line => {
|
|
||||||
const trimmed = line.trim();
|
|
||||||
return !!trimmed && trimmed[0] != '#';
|
|
||||||
});
|
|
||||||
|
|
||||||
const stack = [{ indent: -1, list: [], words: '' }];
|
|
||||||
for (const line of lines) {
|
|
||||||
const indent = line.length - line.trimLeft().length;
|
|
||||||
const o = { indent, list: [], words: line.split(' ').filter(word => !!word) };
|
|
||||||
|
|
||||||
let current = stack[stack.length - 1];
|
|
||||||
while (indent <= current.indent) {
|
|
||||||
stack.pop();
|
|
||||||
current = stack[stack.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
current.list.push(o);
|
|
||||||
stack.push(o);
|
|
||||||
}
|
|
||||||
return stack[0].list;
|
|
||||||
}
|
|
||||||
|
|
||||||
function raise(item) {
|
function raise(item) {
|
||||||
throw new Error(item.words.join(' '));
|
throw new Error('Invalid item: ' + JSON.stringify(item, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
function titleCase(name) {
|
function titleCase(name) {
|
||||||
return name[0].toUpperCase() + name.substring(1);
|
return name[0].toUpperCase() + name.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inlineType(item, indent) {
|
function inlineType(type, indent, wrapEnums = false) {
|
||||||
let type = item.words[1];
|
if (typeof type === 'string') {
|
||||||
const array = type.endsWith('[]');
|
const optional = type.endsWith('?');
|
||||||
if (array)
|
|
||||||
type = type.substring(0, type.length - 2);
|
|
||||||
let inner = '';
|
|
||||||
if (type === 'enum') {
|
|
||||||
const literals = item.list.map(literal => {
|
|
||||||
if (literal.words.length > 1 || literal.list.length)
|
|
||||||
raise(literal);
|
|
||||||
return literal.words[0];
|
|
||||||
});
|
|
||||||
inner = literals.map(literal => `'${literal}'`).join(' | ');
|
|
||||||
if (array)
|
|
||||||
inner = `(${inner})`;
|
|
||||||
} else if (['string', 'boolean', 'number', 'undefined'].includes(type)) {
|
|
||||||
inner = type;
|
|
||||||
} else if (type === 'object') {
|
|
||||||
inner = `{\n${properties(item, indent + ' ')}\n${indent}}`;
|
|
||||||
} else if (type === 'binary') {
|
|
||||||
inner = 'Binary';
|
|
||||||
} else if (channels.has(type)) {
|
|
||||||
inner = type + 'Channel';
|
|
||||||
} else {
|
|
||||||
inner = type;
|
|
||||||
}
|
|
||||||
return inner + (array ? '[]' : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function inlineTypeScheme(item, indent) {
|
|
||||||
let type = item.words[1];
|
|
||||||
const array = type.endsWith('[]');
|
|
||||||
if (array)
|
|
||||||
type = type.substring(0, type.length - 2);
|
|
||||||
let inner = '';
|
|
||||||
if (type === 'enum') {
|
|
||||||
const literals = item.list.map(literal => {
|
|
||||||
if (literal.words.length > 1 || literal.list.length)
|
|
||||||
raise(literal);
|
|
||||||
return literal.words[0];
|
|
||||||
});
|
|
||||||
inner = `tEnum([${literals.map(literal => `'${literal}'`).join(', ')}])`;
|
|
||||||
} else if (['string', 'boolean', 'number', 'undefined'].includes(type)) {
|
|
||||||
inner = `t${titleCase(type)}`;
|
|
||||||
} else if (type === 'object') {
|
|
||||||
inner = `tObject({\n${propertiesScheme(item, indent + ' ')}\n${indent}})`;
|
|
||||||
} else if (type === 'binary') {
|
|
||||||
inner = 'tBinary';
|
|
||||||
} else if (channels.has(type)) {
|
|
||||||
inner = `tChannel('${type}')`;
|
|
||||||
} else if (type === 'Channel') {
|
|
||||||
inner = `tChannel('*')`;
|
|
||||||
} else {
|
|
||||||
inner = `tType('${type}')`;
|
|
||||||
}
|
|
||||||
return array ? `tArray(${inner})` : inner;
|
|
||||||
}
|
|
||||||
|
|
||||||
function properties(item, indent) {
|
|
||||||
const result = [];
|
|
||||||
for (const prop of item.list) {
|
|
||||||
if (prop.words.length !== 2)
|
|
||||||
raise(prop);
|
|
||||||
let name = prop.words[0];
|
|
||||||
if (!name.endsWith(':'))
|
|
||||||
raise(item);
|
|
||||||
name = name.substring(0, name.length - 1);
|
|
||||||
const optional = name.endsWith('?');
|
|
||||||
if (optional)
|
if (optional)
|
||||||
name = name.substring(0, name.length - 1);
|
type = type.substring(0, type.length - 1);
|
||||||
result.push(`${indent}${name}${optional ? '?' : ''}: ${inlineType(prop, indent)},`);
|
if (type === 'binary')
|
||||||
|
return { ts: 'Binary', scheme: 'tBinary', optional };
|
||||||
|
if (['string', 'boolean', 'number', 'undefined'].includes(type))
|
||||||
|
return { ts: type, scheme: `t${titleCase(type)}`, optional };
|
||||||
|
if (channels.has(type))
|
||||||
|
return { ts: `${type}Channel`, scheme: `tChannel('${type}')` , optional };
|
||||||
|
if (type === 'Channel')
|
||||||
|
return { ts: `Channel`, scheme: `tChannel('*')`, optional };
|
||||||
|
return { ts: type, scheme: `tType('${type}')`, optional };
|
||||||
}
|
}
|
||||||
return result.join('\n');
|
if (type.type.startsWith('array')) {
|
||||||
|
const optional = type.type.endsWith('?');
|
||||||
|
const inner = inlineType(type.items, indent, true);
|
||||||
|
return { ts: `${inner.ts}[]`, scheme: `tArray(${inner.scheme})`, optional };
|
||||||
|
}
|
||||||
|
if (type.type.startsWith('enum')) {
|
||||||
|
const optional = type.type.endsWith('?');
|
||||||
|
const ts = type.literals.map(literal => `'${literal}'`).join(' | ');
|
||||||
|
return {
|
||||||
|
ts: wrapEnums ? `(${ts})` : ts,
|
||||||
|
scheme: `tEnum([${type.literals.map(literal => `'${literal}'`).join(', ')}])`,
|
||||||
|
optional
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (type.type.startsWith('object')) {
|
||||||
|
const optional = type.type.endsWith('?');
|
||||||
|
const inner = properties(type.properties, indent + ' ');
|
||||||
|
return {
|
||||||
|
ts: `{\n${inner.ts}\n${indent}}`,
|
||||||
|
scheme: `tObject({\n${inner.scheme}\n${indent}})`,
|
||||||
|
optional
|
||||||
|
};
|
||||||
|
}
|
||||||
|
raise(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
function propertiesScheme(item, indent) {
|
function properties(props, indent) {
|
||||||
const result = [];
|
const ts = [];
|
||||||
for (const prop of item.list) {
|
const scheme = [];
|
||||||
if (prop.words.length !== 2)
|
for (const [name, value] of Object.entries(props)) {
|
||||||
raise(prop);
|
const inner = inlineType(value, indent);
|
||||||
let name = prop.words[0];
|
ts.push(`${indent}${name}${inner.optional ? '?' : ''}: ${inner.ts},`);
|
||||||
if (!name.endsWith(':'))
|
const wrapped = inner.optional ? `tOptional(${inner.scheme})` : inner.scheme;
|
||||||
raise(item);
|
scheme.push(`${indent}${name}: ${wrapped},`);
|
||||||
name = name.substring(0, name.length - 1);
|
|
||||||
const optional = name.endsWith('?');
|
|
||||||
if (optional)
|
|
||||||
name = name.substring(0, name.length - 1);
|
|
||||||
let type = inlineTypeScheme(prop, indent);
|
|
||||||
if (optional)
|
|
||||||
type = `tOptional(${type})`;
|
|
||||||
result.push(`${indent}${name}: ${type},`);
|
|
||||||
}
|
}
|
||||||
return result.join('\n');
|
return { ts: ts.join('\n'), scheme: scheme.join('\n') };
|
||||||
}
|
}
|
||||||
|
|
||||||
function objectType(name, item, indent) {
|
function objectType(props, indent) {
|
||||||
if (!item.list.length)
|
if (!Object.entries(props).length)
|
||||||
return `export type ${name} = {};`;
|
return { ts: `{}`, scheme: `tObject({})` };
|
||||||
return `export type ${name} = {\n${properties(item, indent)}\n};`
|
const inner = properties(props, indent + ' ');
|
||||||
}
|
return { ts: `{\n${inner.ts}\n${indent}}`, scheme: `tObject({\n${inner.scheme}\n${indent}})` };
|
||||||
|
|
||||||
function objectTypeScheme(item, indent) {
|
|
||||||
if (!item.list.length)
|
|
||||||
return `tObject({})`;
|
|
||||||
return `tObject({\n${propertiesScheme(item, indent)}\n})`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const channels_ts = [
|
const channels_ts = [
|
||||||
|
|
@ -185,108 +116,6 @@ export interface Channel extends EventEmitter {
|
||||||
}
|
}
|
||||||
`];
|
`];
|
||||||
|
|
||||||
const pdl = fs.readFileSync(path.join(__dirname, '..', 'src', 'rpc', 'protocol.pdl'), 'utf-8');
|
|
||||||
const list = tokenize(pdl);
|
|
||||||
const scheme = new Map();
|
|
||||||
const inherits = new Map();
|
|
||||||
|
|
||||||
function addScheme(name, s) {
|
|
||||||
if (scheme.has(name))
|
|
||||||
throw new Error('Duplicate scheme name ' + name);
|
|
||||||
scheme.set(name, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const item of list) {
|
|
||||||
if (item.words[0] === 'interface') {
|
|
||||||
channels.add(item.words[1]);
|
|
||||||
if (item.words[2] === 'extends')
|
|
||||||
inherits.set(item.words[1], item.words[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const item of list) {
|
|
||||||
if (item.words[0] === 'type') {
|
|
||||||
if (item.words.length !== 2)
|
|
||||||
raise(item);
|
|
||||||
channels_ts.push(`export type ${item.words[1]} = {`);
|
|
||||||
channels_ts.push(properties(item, ' '));
|
|
||||||
channels_ts.push(`};`);
|
|
||||||
addScheme(item.words[1], objectTypeScheme(item, ' '));
|
|
||||||
} else if (item.words[0] === 'interface') {
|
|
||||||
const channelName = item.words[1];
|
|
||||||
channels_ts.push(`// ----------- ${channelName} -----------`);
|
|
||||||
const init = item.list.find(i => i.words[0] === 'initializer');
|
|
||||||
if (init && init.words.length > 1)
|
|
||||||
raise(init);
|
|
||||||
channels_ts.push(objectType(channelName + 'Initializer', init || { list: [] }, ' '));
|
|
||||||
addScheme(channelName + 'Initializer', objectTypeScheme(init || { list: [] }, ' '));
|
|
||||||
|
|
||||||
let extendsName = 'Channel';
|
|
||||||
if (item.words.length === 4 && item.words[2] === 'extends')
|
|
||||||
extendsName = item.words[3] + 'Channel';
|
|
||||||
else if (item.words.length !== 2)
|
|
||||||
raise(item);
|
|
||||||
channels_ts.push(`export interface ${channelName}Channel extends ${extendsName} {`);
|
|
||||||
|
|
||||||
const types = new Map();
|
|
||||||
for (const method of item.list) {
|
|
||||||
if (method === init)
|
|
||||||
continue;
|
|
||||||
if (method.words[0] === 'command') {
|
|
||||||
if (method.words.length !== 2)
|
|
||||||
raise(method);
|
|
||||||
const methodName = method.words[1];
|
|
||||||
|
|
||||||
const parameters = method.list.find(i => i.words[0] === 'parameters');
|
|
||||||
const paramsName = `${channelName}${titleCase(methodName)}Params`;
|
|
||||||
types.set(paramsName, parameters || { list: [] });
|
|
||||||
addScheme(paramsName, parameters ? objectTypeScheme(parameters, ' ') : `tOptional(tObject({}))`);
|
|
||||||
|
|
||||||
const returns = method.list.find(i => i.words[0] === 'returns');
|
|
||||||
const resultName = `${channelName}${titleCase(methodName)}Result`;
|
|
||||||
types.set(resultName, returns);
|
|
||||||
addScheme(resultName, returns ? objectTypeScheme(returns, ' ') : `tUndefined`);
|
|
||||||
|
|
||||||
channels_ts.push(` ${methodName}(params${parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`);
|
|
||||||
for (const key of inherits.keys()) {
|
|
||||||
if (inherits.get(key) === channelName) {
|
|
||||||
addScheme(`${key}${titleCase(methodName)}Params`, `tType('${paramsName}')`);
|
|
||||||
addScheme(`${key}${titleCase(methodName)}Result`, `tType('${resultName}')`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (method.words[0] === 'event') {
|
|
||||||
if (method.words.length !== 2)
|
|
||||||
raise(method);
|
|
||||||
const eventName = method.words[1];
|
|
||||||
|
|
||||||
const parameters = method.list.find(i => i.words[0] === 'parameters');
|
|
||||||
const paramsName = `${channelName}${titleCase(eventName)}Event`;
|
|
||||||
types.set(paramsName, parameters || { list: [] });
|
|
||||||
addScheme(paramsName, objectTypeScheme(parameters || { list: [] }, ' '));
|
|
||||||
|
|
||||||
channels_ts.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`);
|
|
||||||
for (const key of inherits.keys()) {
|
|
||||||
if (inherits.get(key) === channelName)
|
|
||||||
addScheme(`${key}${titleCase(eventName)}Event`, `tType('${paramsName}')`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
raise(method);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
channels_ts.push(`}`);
|
|
||||||
for (const [name, item] of types) {
|
|
||||||
if (!item)
|
|
||||||
channels_ts.push(`export type ${name} = void;`);
|
|
||||||
else
|
|
||||||
channels_ts.push(objectType(name, item, ' '));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
raise(item);
|
|
||||||
}
|
|
||||||
channels_ts.push(``);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const client_validator_ts = [
|
const client_validator_ts = [
|
||||||
`/**
|
`/**
|
||||||
* Copyright (c) Microsoft Corporation.
|
* Copyright (c) Microsoft Corporation.
|
||||||
|
|
@ -309,9 +138,83 @@ const client_validator_ts = [
|
||||||
import { scheme, tOptional, tObject, tBoolean, tNumber, tString, tType, tEnum, tArray, tChannel, tUndefined, tBinary } from './validatorPrimitives';
|
import { scheme, tOptional, tObject, tBoolean, tNumber, tString, tType, tEnum, tArray, tChannel, tUndefined, tBinary } from './validatorPrimitives';
|
||||||
export { validateParams } from './validatorPrimitives';
|
export { validateParams } from './validatorPrimitives';
|
||||||
`];
|
`];
|
||||||
for (const [name, value] of scheme)
|
|
||||||
client_validator_ts.push(`scheme.${name} = ${value};`);
|
|
||||||
client_validator_ts.push(``);
|
|
||||||
|
|
||||||
|
const yml = fs.readFileSync(path.join(__dirname, '..', 'src', 'rpc', 'protocol.yml'), 'utf-8');
|
||||||
|
const protocol = yaml.parse(yml);
|
||||||
|
|
||||||
|
function addScheme(name, s) {
|
||||||
|
client_validator_ts.push(`scheme.${name} = ${s};`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inherits = new Map();
|
||||||
|
for (const [name, value] of Object.entries(protocol)) {
|
||||||
|
if (value.type === 'interface') {
|
||||||
|
channels.add(name);
|
||||||
|
if (value.extends)
|
||||||
|
inherits.set(name, value.extends);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [name, item] of Object.entries(protocol)) {
|
||||||
|
if (item.type === 'interface') {
|
||||||
|
const channelName = name;
|
||||||
|
channels_ts.push(`// ----------- ${channelName} -----------`);
|
||||||
|
const init = objectType(item.initializer || {}, '');
|
||||||
|
const initializerName = channelName + 'Initializer';
|
||||||
|
channels_ts.push(`export type ${initializerName} = ${init.ts};`);
|
||||||
|
addScheme(initializerName, init.scheme);
|
||||||
|
|
||||||
|
channels_ts.push(`export interface ${channelName}Channel extends ${(item.extends || '') + 'Channel'} {`);
|
||||||
|
const ts_types = new Map();
|
||||||
|
|
||||||
|
for (let [eventName, event] of Object.entries(item.events || {})) {
|
||||||
|
if (event === null)
|
||||||
|
event = {};
|
||||||
|
const parameters = objectType(event.parameters || {}, '');
|
||||||
|
const paramsName = `${channelName}${titleCase(eventName)}Event`;
|
||||||
|
ts_types.set(paramsName, parameters.ts);
|
||||||
|
addScheme(paramsName, parameters.scheme);
|
||||||
|
|
||||||
|
channels_ts.push(` on(event: '${eventName}', callback: (params: ${paramsName}) => void): this;`);
|
||||||
|
for (const key of inherits.keys()) {
|
||||||
|
if (inherits.get(key) === channelName)
|
||||||
|
addScheme(`${key}${titleCase(eventName)}Event`, `tType('${paramsName}')`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let [methodName, method] of Object.entries(item.commands || {})) {
|
||||||
|
if (method === null)
|
||||||
|
method = {};
|
||||||
|
const parameters = objectType(method.parameters || {}, '');
|
||||||
|
const paramsName = `${channelName}${titleCase(methodName)}Params`;
|
||||||
|
ts_types.set(paramsName, parameters.ts);
|
||||||
|
addScheme(paramsName, method.parameters ? parameters.scheme : `tOptional(tObject({}))`);
|
||||||
|
|
||||||
|
const resultName = `${channelName}${titleCase(methodName)}Result`;
|
||||||
|
const returns = objectType(method.returns || {}, '');
|
||||||
|
ts_types.set(resultName, method.returns ? returns.ts : 'void');
|
||||||
|
addScheme(resultName, method.returns ? returns.scheme : `tUndefined`);
|
||||||
|
|
||||||
|
channels_ts.push(` ${methodName}(params${method.parameters ? '' : '?'}: ${paramsName}): Promise<${resultName}>;`);
|
||||||
|
for (const key of inherits.keys()) {
|
||||||
|
if (inherits.get(key) === channelName) {
|
||||||
|
addScheme(`${key}${titleCase(methodName)}Params`, `tType('${paramsName}')`);
|
||||||
|
addScheme(`${key}${titleCase(methodName)}Result`, `tType('${resultName}')`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channels_ts.push(`}`);
|
||||||
|
for (const [typeName, typeValue] of ts_types)
|
||||||
|
channels_ts.push(`export type ${typeName} = ${typeValue};`);
|
||||||
|
} else if (item.type === 'object') {
|
||||||
|
const inner = objectType(item.properties, '');
|
||||||
|
channels_ts.push(`export type ${name} = ${inner.ts};`);
|
||||||
|
addScheme(name, inner.scheme);
|
||||||
|
}
|
||||||
|
channels_ts.push(``);
|
||||||
|
}
|
||||||
|
|
||||||
|
client_validator_ts.push(``);
|
||||||
fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), channels_ts.join('\n'), 'utf-8');
|
fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'channels.ts'), channels_ts.join('\n'), 'utf-8');
|
||||||
fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'client', 'validator.ts'), client_validator_ts.join('\n'), 'utf-8');
|
fs.writeFileSync(path.join(__dirname, '..', 'src', 'rpc', 'client', 'validator.ts'), client_validator_ts.join('\n'), 'utf-8');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue