feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
32
frontend/infra/idl/idl2ts-helper/src/constant.ts
Normal file
32
frontend/infra/idl/idl2ts-helper/src/constant.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export const ReservedKeyWord = [
|
||||
'class',
|
||||
'const',
|
||||
'var',
|
||||
'arguments',
|
||||
'import',
|
||||
'export',
|
||||
'from',
|
||||
'extends',
|
||||
'interface',
|
||||
'enum',
|
||||
'package',
|
||||
'do',
|
||||
'eval',
|
||||
'object',
|
||||
];
|
||||
97
frontend/infra/idl/idl2ts-helper/src/ctx.ts
Normal file
97
frontend/infra/idl/idl2ts-helper/src/ctx.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type t from '@babel/types';
|
||||
|
||||
import {
|
||||
type IParseResultItem,
|
||||
type ServiceDefinition,
|
||||
type FunctionDefinition,
|
||||
type UnifyStatement,
|
||||
} from './types';
|
||||
interface BaseCtx {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface IMeta {
|
||||
reqType: string;
|
||||
resType: string;
|
||||
url: string;
|
||||
method: string;
|
||||
reqMapping: IHttpRpcMapping;
|
||||
resMapping?: IHttpRpcMapping; // res mapping
|
||||
name: string;
|
||||
service: string;
|
||||
schemaRoot: string;
|
||||
serializer?: string;
|
||||
}
|
||||
|
||||
type Fields = string[];
|
||||
|
||||
export interface IHttpRpcMapping {
|
||||
path?: Fields; // path参数
|
||||
query?: Fields; // query参数
|
||||
body?: Fields; // body 参数
|
||||
header?: Fields; // header 参数
|
||||
status_code?: Fields; // http状态码
|
||||
cookie?: Fields; // cookie
|
||||
entire_body?: Fields;
|
||||
raw_body?: Fields;
|
||||
}
|
||||
export interface BaseContent {
|
||||
ast: IParseResultItem[];
|
||||
}
|
||||
|
||||
interface BabelDist {
|
||||
type: 'babel';
|
||||
content: t.File;
|
||||
}
|
||||
|
||||
interface TextDist {
|
||||
type: 'text';
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface JsonDist {
|
||||
type: 'json';
|
||||
content: { [key: string]: any };
|
||||
}
|
||||
type Dist = JsonDist | BabelDist | TextDist;
|
||||
|
||||
export type IGentsRes = Map<string, Dist>;
|
||||
export interface IParseEntryCtx<T = any> extends BaseCtx {
|
||||
ast: IParseResultItem[];
|
||||
files: IGentsRes;
|
||||
instance: T;
|
||||
entries: string[];
|
||||
}
|
||||
export interface IGenTemplateCtx extends BaseCtx {
|
||||
ast: IParseResultItem;
|
||||
service: ServiceDefinition;
|
||||
method: FunctionDefinition;
|
||||
meta: IMeta;
|
||||
template: string;
|
||||
}
|
||||
|
||||
export interface ProcessIdlCtx extends BaseCtx {
|
||||
ast: IParseResultItem;
|
||||
output: IGentsRes;
|
||||
dts: t.File;
|
||||
mock: t.File;
|
||||
node?: UnifyStatement;
|
||||
mockStatements: t.Statement[];
|
||||
meta: IMeta[];
|
||||
}
|
||||
407
frontend/infra/idl/idl2ts-helper/src/helper.ts
Normal file
407
frontend/infra/idl/idl2ts-helper/src/helper.ts
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
|
||||
import prettier, { type Options } from 'prettier';
|
||||
import fs from 'fs-extra';
|
||||
import { SyntaxType } from '@coze-arch/idl-parser';
|
||||
import { type Program, type File, type Node } from '@babel/types';
|
||||
import * as t from '@babel/types';
|
||||
import template from '@babel/template';
|
||||
import { type ParserPlugin, parse } from '@babel/parser';
|
||||
|
||||
import * as h from './types';
|
||||
import { ReservedKeyWord } from './constant';
|
||||
export const plugins: ParserPlugin[] = [
|
||||
'typescript',
|
||||
'decorators-legacy',
|
||||
'classProperties',
|
||||
'doExpressions',
|
||||
];
|
||||
export const createFile = (source: string) => {
|
||||
const program: Program = template.program(source, {
|
||||
plugins,
|
||||
})();
|
||||
const file: File = {
|
||||
type: 'File',
|
||||
loc: program.loc,
|
||||
start: program.start,
|
||||
end: program.end,
|
||||
program,
|
||||
comments: [],
|
||||
tokens: null,
|
||||
leadingComments: [],
|
||||
trailingComments: [],
|
||||
innerComments: [],
|
||||
};
|
||||
return file;
|
||||
};
|
||||
|
||||
export function createIdWithTypeAnnotation(exp: string) {
|
||||
const dec = template.ast(`let ${exp}`, { plugins }) as t.VariableDeclaration;
|
||||
return dec.declarations[0].id as t.Identifier;
|
||||
}
|
||||
|
||||
export const parseFile = (fileName: string) =>
|
||||
parse(fs.readFileSync(fileName, 'utf8'), {
|
||||
sourceType: 'module',
|
||||
plugins,
|
||||
});
|
||||
|
||||
export function formatCode(code: string, root = '.') {
|
||||
const defaultConfig: Options = {
|
||||
tabWidth: 2,
|
||||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
};
|
||||
const file = path.resolve(process.cwd(), root, './for-prettier-bug'); // 这里一定要加多一级目录
|
||||
const config = prettier.resolveConfig(file, { editorconfig: true });
|
||||
return prettier.format(code, {
|
||||
...(config || defaultConfig),
|
||||
parser: 'typescript',
|
||||
});
|
||||
}
|
||||
|
||||
export function disableLint<T extends Node>(node: T, isTs = true) {
|
||||
return t.addComment<T>(
|
||||
node,
|
||||
'leading',
|
||||
isTs ? ' tslint:disable ' : ' eslint-disable ',
|
||||
);
|
||||
}
|
||||
|
||||
export async function safeWriteFile(fileName: string, content: string) {
|
||||
await fs.ensureDirSync(path.dirname(fileName));
|
||||
await fs.writeFile(fileName, content, 'utf8');
|
||||
}
|
||||
|
||||
export function addComment<T extends t.Node = t.Node>(
|
||||
node: T,
|
||||
comments: h.Comment[],
|
||||
position?: t.CommentTypeShorthand,
|
||||
): T {
|
||||
const [content, multi] = convertVComments(comments);
|
||||
if (content) {
|
||||
return t.addComment(
|
||||
node,
|
||||
position || multi ? 'leading' : 'trailing',
|
||||
content,
|
||||
!multi,
|
||||
);
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
export function convertVComments(comments: h.Comment[]): [string, boolean] {
|
||||
if (!comments) {
|
||||
return ['', false];
|
||||
}
|
||||
let res = [] as string[];
|
||||
for (const comment of comments) {
|
||||
const { value } = comment;
|
||||
if (Array.isArray(value)) {
|
||||
res = [...res, ...value];
|
||||
} else {
|
||||
res = [...res, value];
|
||||
}
|
||||
}
|
||||
if (res.length > 1) {
|
||||
return [
|
||||
`*\n * ${res.map(i => i.replace(/\*\//g, '/')).join('\n * ')}\n`,
|
||||
true,
|
||||
];
|
||||
}
|
||||
if (res.length > 0) {
|
||||
return [`* ${res[0]?.replace(/\*\//g, '/')} `, true];
|
||||
}
|
||||
|
||||
return ['', false];
|
||||
}
|
||||
|
||||
export function getRelativePath(from: string, to: string) {
|
||||
let relative = path.relative(path.parse(from).dir, to);
|
||||
relative = !relative.startsWith('.') ? `./${relative}` : relative;
|
||||
return removeFileExt(relative);
|
||||
}
|
||||
|
||||
export function removeFileExt(fileName: string) {
|
||||
const [_, ...target] = fileName.split('.').reverse();
|
||||
const res = target.reverse().join('.');
|
||||
return res.startsWith('./') || res.startsWith('/') ? res : `./${res}`;
|
||||
}
|
||||
|
||||
export function parseIdFiledType(fieldType: h.Identifier) {
|
||||
const { value } = fieldType;
|
||||
const namespaceArr = value.split('.');
|
||||
const [refName, ...namespace] = namespaceArr.reverse();
|
||||
const namespaceName = namespace.reverse().join('.');
|
||||
return {
|
||||
refName,
|
||||
namespace: namespaceName,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseId(id: string) {
|
||||
const res = id.split('.');
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const name = res.pop()!;
|
||||
const namespace = uniformNs(res.join('_'));
|
||||
return namespace ? `${namespace}.${name}` : name;
|
||||
}
|
||||
|
||||
export function uniformNs(ns: string) {
|
||||
if (ReservedKeyWord.includes(ns)) {
|
||||
// 命中保留字,处理为下划线开头
|
||||
return `_${ns}`;
|
||||
}
|
||||
return ns.replace(/\./g, '_');
|
||||
}
|
||||
|
||||
export function getValuesFromEnum(params: h.EnumDefinition) {
|
||||
const { members } = params;
|
||||
let currentVal = 0;
|
||||
const enumArr = [] as number[];
|
||||
for (const member of members) {
|
||||
const { initializer } = member;
|
||||
if (initializer) {
|
||||
if (h.isIntegerLiteral(initializer.value)) {
|
||||
currentVal = Number(initializer.value.value);
|
||||
} else if (h.isHexLiteral(initializer.value)) {
|
||||
// 16进制
|
||||
currentVal = Number(initializer.value.value);
|
||||
}
|
||||
enumArr.push(currentVal);
|
||||
} else {
|
||||
enumArr.push(currentVal);
|
||||
}
|
||||
currentVal = currentVal + 1;
|
||||
}
|
||||
return enumArr;
|
||||
}
|
||||
|
||||
export function parseFiledName(filed: h.FieldDefinition) {
|
||||
const { name, extensionConfig } = filed;
|
||||
if (extensionConfig?.key === '.') {
|
||||
return name.value;
|
||||
}
|
||||
return extensionConfig?.key || name.value;
|
||||
}
|
||||
|
||||
export function getAnnotation(
|
||||
annotations: h.Annotations | undefined,
|
||||
name: string,
|
||||
) {
|
||||
if (!annotations) {
|
||||
return undefined;
|
||||
}
|
||||
for (const ele of annotations.annotations) {
|
||||
if (ele.name.value === name) {
|
||||
return ele.value && ele.value.value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// export function parseAnnotations(anno: h.Annotations) {
|
||||
// const result = {} as { [key: string]: string };
|
||||
// anno.annotations.forEach((i) => {
|
||||
// const { name, value } = i;
|
||||
// result[name.value] = value ? value.value : "";
|
||||
// });
|
||||
// return result;
|
||||
// }
|
||||
|
||||
export function getNamespaceByPath(idlPath: string) {
|
||||
return (idlPath.split('/').pop() as string).replace(/\.(thrift|proto)$/, '');
|
||||
}
|
||||
|
||||
export function genAst<T = unknown>(code: string): T {
|
||||
return template.ast(code, {
|
||||
plugins,
|
||||
preserveComments: true,
|
||||
startLine: 2,
|
||||
}) as any;
|
||||
}
|
||||
|
||||
export function getStatementById(
|
||||
id: h.Identifier,
|
||||
current: h.IParseResultItem,
|
||||
) {
|
||||
const { namespace, refName } = parseIdFiledType(id);
|
||||
let statement: h.UnifyStatement | undefined;
|
||||
if (namespace) {
|
||||
const ast = getAstFromNamespace(namespace, current);
|
||||
statement = h.findDefinition(ast, refName);
|
||||
} else {
|
||||
statement = h.findDefinition(current.statements, id.value);
|
||||
}
|
||||
|
||||
if (!statement) {
|
||||
throw new Error(`can not find Struct: ${id.value} `);
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
export function getAstFromNamespace(
|
||||
namespace: string,
|
||||
current: h.IParseResultItem,
|
||||
) {
|
||||
const item = getParseResultFromNamespace(namespace, current);
|
||||
|
||||
return item.statements;
|
||||
}
|
||||
|
||||
export function getParseResultFromNamespace(
|
||||
namespace: string,
|
||||
current: h.IParseResultItem,
|
||||
) {
|
||||
let item = null as h.IParseResultItem | null;
|
||||
|
||||
for (const file in current.deps) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (current.deps.hasOwnProperty(file)) {
|
||||
const element = current.deps[file];
|
||||
const ns = getNamespaceByPath(file);
|
||||
if (ns === namespace) {
|
||||
item = element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!item) {
|
||||
throw new Error(`can not find ast by namespace : ${namespace}`);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
export function ignoreField(f: h.FieldDefinition) {
|
||||
if (['KContext', 'Base', 'BaseResp'].includes(f.name.value)) {
|
||||
return false;
|
||||
}
|
||||
if (h.isIdentifier(f.fieldType)) {
|
||||
return !['base.Base', 'base.BaseResp'].includes(f.fieldType.value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function isFullBody(f: h.FieldDefinition) {
|
||||
return (
|
||||
(f.extensionConfig?.position === 'body' && f.extensionConfig.key === '.') ||
|
||||
getAnnotation(f.annotations, 'api.full_body') !== undefined
|
||||
);
|
||||
}
|
||||
|
||||
export function hasDynamicJsonAnnotation(annotations?: h.Annotations) {
|
||||
if (!annotations) {
|
||||
return false;
|
||||
}
|
||||
return annotations.annotations.find(i =>
|
||||
[
|
||||
'kgw.json',
|
||||
'kgw.json.req',
|
||||
'kgw.json.resp',
|
||||
'api.request.converter',
|
||||
'api.response.converter',
|
||||
].some(k => k === i.name.value),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 api.(request|response).converter 中解析出前端与网关之间的真实类型,
|
||||
* 能搞出这两个注解来,这个协议着实恶心😭
|
||||
* @param annotations
|
||||
* @returns
|
||||
*/
|
||||
export function getTypeFromDynamicJsonAnnotation(
|
||||
annotations?: h.Annotations,
|
||||
): undefined | 'string' | 'Object' | 'unknown' {
|
||||
if (!annotations) {
|
||||
return undefined;
|
||||
}
|
||||
const requestVal = annotations.annotations.find(
|
||||
i => i.name.value === 'api.request.converter',
|
||||
)?.value?.value;
|
||||
const responseVal = annotations.annotations.find(
|
||||
i => i.name.value === 'api.response.converter',
|
||||
)?.value?.value;
|
||||
const typeValue = [
|
||||
[undefined, 'string', 'Object'],
|
||||
['Object', 'unknown', 'string'],
|
||||
['Object', 'Object', 'unknown'],
|
||||
] as const;
|
||||
const index = (value: undefined | 'encode' | 'decode' | string) =>
|
||||
value === 'encode' ? 2 : value === 'decode' ? 1 : 0;
|
||||
return typeValue[index(responseVal)][index(requestVal)];
|
||||
}
|
||||
|
||||
export function getFieldsAlias(i: h.FieldDefinition) {
|
||||
return parseFiledName(i);
|
||||
}
|
||||
|
||||
export function withExportDeclaration(
|
||||
node: t.Declaration,
|
||||
comments?: h.Comment[],
|
||||
) {
|
||||
const declaration = t.exportNamedDeclaration(node);
|
||||
if (!comments) {
|
||||
return declaration;
|
||||
}
|
||||
return addComment(declaration, comments, 'leading');
|
||||
}
|
||||
|
||||
export function getSchemaRootByPath(absFile: string, idlRoot: string) {
|
||||
const pathName = path
|
||||
.relative(idlRoot, removeFileExt(absFile))
|
||||
.replace(/\//g, '_');
|
||||
|
||||
return `api://schemas/${pathName}`;
|
||||
}
|
||||
|
||||
export function getOutputName(params: {
|
||||
source: string;
|
||||
idlRoot: string;
|
||||
outputDir: string;
|
||||
}) {
|
||||
const relativeName = path.relative(params.idlRoot, params.source);
|
||||
return path.resolve(params.outputDir, relativeName);
|
||||
}
|
||||
|
||||
export function transformFieldId(fieldName: string) {
|
||||
return fieldName.includes('-')
|
||||
? t.stringLiteral(fieldName)
|
||||
: t.identifier(fieldName);
|
||||
}
|
||||
|
||||
export function getBaseTypeConverts(i64Type: string) {
|
||||
let newType = 'number';
|
||||
if (i64Type === 'string') {
|
||||
newType = 'string';
|
||||
}
|
||||
|
||||
return {
|
||||
[SyntaxType.ByteKeyword]: 'number',
|
||||
[SyntaxType.I8Keyword]: 'number',
|
||||
[SyntaxType.I16Keyword]: 'number',
|
||||
[SyntaxType.I32Keyword]: 'number',
|
||||
[SyntaxType.I64Keyword]: newType,
|
||||
[SyntaxType.DoubleKeyword]: 'number',
|
||||
[SyntaxType.BinaryKeyword]: 'object',
|
||||
[SyntaxType.StringKeyword]: 'string',
|
||||
[SyntaxType.BoolKeyword]: 'boolean',
|
||||
};
|
||||
}
|
||||
21
frontend/infra/idl/idl2ts-helper/src/index.ts
Normal file
21
frontend/infra/idl/idl2ts-helper/src/index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './parser';
|
||||
export * from './types';
|
||||
export * from './ctx';
|
||||
export * from './utils';
|
||||
export * from './helper';
|
||||
92
frontend/infra/idl/idl2ts-helper/src/parser.ts
Normal file
92
frontend/infra/idl/idl2ts-helper/src/parser.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as path from 'path';
|
||||
|
||||
import { parse, type UnifyDocument } from '@coze-arch/idl-parser';
|
||||
|
||||
import { isPbFile, lookupFile } from './utils';
|
||||
import type * as t from './types';
|
||||
import { getNamespaceByPath, uniformNs } from './helper';
|
||||
|
||||
export function parseDSL(
|
||||
idlFullPaths: string[],
|
||||
parsedRes: t.IParseResultItem[] = [],
|
||||
idlRoot: string = process.cwd(),
|
||||
): t.IParseResultItem[] {
|
||||
const results = parsedRes;
|
||||
const entries =
|
||||
typeof idlFullPaths === 'string' ? [idlFullPaths] : idlFullPaths;
|
||||
const isPb = isPbFile(idlFullPaths[0]);
|
||||
function addResult(res: t.IParseResultItem) {
|
||||
if (!results.find(i => i.idlPath === res.idlPath)) {
|
||||
results.push(res);
|
||||
}
|
||||
}
|
||||
|
||||
function _parse(idlFullPath: string, isEntry = false) {
|
||||
const target = results.find(i => i.idlPath === idlFullPath);
|
||||
if (target) {
|
||||
if (isEntry) {
|
||||
target.isEntry = true;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
const ast: UnifyDocument = parse(idlFullPath, {
|
||||
cache: false,
|
||||
ignoreGoTagDash: false,
|
||||
root: idlRoot,
|
||||
namespaceRefer: true,
|
||||
searchPaths: [path.dirname(idlFullPath)],
|
||||
});
|
||||
const res = {
|
||||
...ast,
|
||||
deps: {},
|
||||
includeMap: {},
|
||||
idlPath: idlFullPath,
|
||||
isEntry,
|
||||
} as t.IParseResultItem;
|
||||
addResult(res);
|
||||
if (ast.includes && ast.includes.length > 0) {
|
||||
ast.includes.forEach(i => {
|
||||
if (/google\/(protobuf|api)/.test(i)) {
|
||||
return;
|
||||
}
|
||||
const filePath = isPb
|
||||
? lookupFile(i, [path.dirname(idlFullPath), idlRoot])
|
||||
: path.resolve(path.dirname(idlFullPath), i);
|
||||
const subResults = _parse(filePath);
|
||||
if (subResults) {
|
||||
res.deps[filePath] = subResults;
|
||||
res.includeMap[i] = filePath;
|
||||
if (!isPb) {
|
||||
res.includeRefer[i] = getNamespaceByPath(i);
|
||||
}
|
||||
res.includeRefer[i] = uniformNs(res.includeRefer[i]);
|
||||
addResult(subResults);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
entries.forEach(i => {
|
||||
_parse(i, true);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
232
frontend/infra/idl/idl2ts-helper/src/types.ts
Normal file
232
frontend/infra/idl/idl2ts-helper/src/types.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type UnifyStatement,
|
||||
SyntaxType,
|
||||
type StructDefinition,
|
||||
type FieldType,
|
||||
type Identifier,
|
||||
type BaseType,
|
||||
type MapType,
|
||||
type TypedefDefinition,
|
||||
type EnumDefinition,
|
||||
type ServiceDefinition,
|
||||
type FunctionType,
|
||||
type ConstDefinition,
|
||||
type SyntaxNode,
|
||||
type SetType,
|
||||
type ListType,
|
||||
type IntegerLiteral,
|
||||
type HexLiteral,
|
||||
type IntConstant,
|
||||
type StringLiteral,
|
||||
type DoubleConstant,
|
||||
type BooleanLiteral,
|
||||
type ConstMap,
|
||||
type ConstList,
|
||||
type ConstValue,
|
||||
type Annotations,
|
||||
type UnifyDocument,
|
||||
} from '@coze-arch/idl-parser';
|
||||
|
||||
export * from '@coze-arch/idl-parser';
|
||||
|
||||
export interface Deps {
|
||||
[path: string]: IParseResultItem;
|
||||
}
|
||||
|
||||
export type IParseResultItem = UnifyDocument & {
|
||||
idlPath: string;
|
||||
includeMap: Record<string, string>;
|
||||
deps: Deps;
|
||||
isEntry: boolean;
|
||||
};
|
||||
|
||||
export interface I64Type extends BaseType {
|
||||
type: SyntaxType.I64Keyword;
|
||||
annotations?: Annotations;
|
||||
}
|
||||
|
||||
export interface I32Type extends BaseType {
|
||||
type: SyntaxType.I32Keyword;
|
||||
annotations?: Annotations;
|
||||
}
|
||||
|
||||
export interface I16Type extends BaseType {
|
||||
type: SyntaxType.I16Keyword;
|
||||
annotations?: Annotations;
|
||||
}
|
||||
export interface I8Type extends BaseType {
|
||||
type: SyntaxType.I8Keyword;
|
||||
annotations?: Annotations;
|
||||
}
|
||||
|
||||
export interface StringType extends BaseType {
|
||||
type: SyntaxType.StringKeyword;
|
||||
annotations?: Annotations;
|
||||
}
|
||||
|
||||
export type RefType =
|
||||
| ConstDefinition
|
||||
| StructDefinition
|
||||
| EnumDefinition
|
||||
| TypedefDefinition
|
||||
| ServiceDefinition;
|
||||
|
||||
export function isServiceDefinition(
|
||||
statement: UnifyStatement,
|
||||
): statement is ServiceDefinition {
|
||||
return statement.type === SyntaxType.ServiceDefinition;
|
||||
}
|
||||
export function isStructDefinition(
|
||||
statement: UnifyStatement,
|
||||
): statement is StructDefinition {
|
||||
return statement.type === SyntaxType.StructDefinition;
|
||||
}
|
||||
|
||||
export function isTypedefDefinition(
|
||||
statement: UnifyStatement,
|
||||
): statement is TypedefDefinition {
|
||||
return statement.type === SyntaxType.TypedefDefinition;
|
||||
}
|
||||
export function isEnumDefinition(
|
||||
statement: UnifyStatement,
|
||||
): statement is EnumDefinition {
|
||||
return statement.type === SyntaxType.EnumDefinition;
|
||||
}
|
||||
export function isConstDefinition(
|
||||
statement: UnifyStatement,
|
||||
): statement is ConstDefinition {
|
||||
return statement.type === SyntaxType.ConstDefinition;
|
||||
}
|
||||
export function isIdentifier(
|
||||
statement: FieldType | FunctionType | ConstValue,
|
||||
): statement is Identifier {
|
||||
return statement.type === SyntaxType.Identifier;
|
||||
}
|
||||
|
||||
export function findDefinition(
|
||||
statements: UnifyStatement[],
|
||||
structName: string,
|
||||
): UnifyStatement | undefined {
|
||||
for (const statement in statements) {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (statements.hasOwnProperty(statement)) {
|
||||
const element = statements[statement];
|
||||
if (element.name.value === structName) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* isBasetype
|
||||
*/
|
||||
export function isBaseType(
|
||||
fieldType: FieldType | FunctionType,
|
||||
): fieldType is BaseType {
|
||||
const BaseType = [
|
||||
SyntaxType.StringKeyword,
|
||||
SyntaxType.DoubleKeyword,
|
||||
SyntaxType.BoolKeyword,
|
||||
SyntaxType.I8Keyword,
|
||||
SyntaxType.I16Keyword,
|
||||
SyntaxType.I32Keyword,
|
||||
SyntaxType.I64Keyword,
|
||||
SyntaxType.BinaryKeyword,
|
||||
SyntaxType.ByteKeyword,
|
||||
];
|
||||
return BaseType.indexOf(fieldType.type) > -1;
|
||||
}
|
||||
|
||||
export function isI64Type(
|
||||
fieldType: FieldType | FunctionType,
|
||||
): fieldType is I64Type {
|
||||
return fieldType.type === SyntaxType.I64Keyword;
|
||||
}
|
||||
|
||||
// export function isI64Type(fieldType: FieldType | FunctionType): fieldType is BaseType {
|
||||
|
||||
// }
|
||||
|
||||
/**
|
||||
* isReftype
|
||||
*/
|
||||
export function isReftype(statement: UnifyStatement): statement is RefType {
|
||||
const BaseType = [
|
||||
SyntaxType.ConstDefinition,
|
||||
SyntaxType.StructDefinition,
|
||||
SyntaxType.EnumDefinition,
|
||||
// SyntaxType.UnionDefinition,
|
||||
SyntaxType.TypedefDefinition,
|
||||
SyntaxType.ServiceDefinition,
|
||||
];
|
||||
return BaseType.indexOf(statement.type) > -1;
|
||||
}
|
||||
export function isMapType(
|
||||
fieldType: FieldType | FunctionType,
|
||||
): fieldType is MapType {
|
||||
return fieldType.type === SyntaxType.MapType;
|
||||
}
|
||||
export function isSetType(
|
||||
fieldType: FieldType | FunctionType,
|
||||
): fieldType is SetType {
|
||||
return fieldType.type === SyntaxType.SetType;
|
||||
}
|
||||
export function isListType(
|
||||
fieldType: FieldType | FunctionType,
|
||||
): fieldType is ListType {
|
||||
return fieldType.type === SyntaxType.ListType;
|
||||
}
|
||||
export function isIntegerLiteral(
|
||||
fieldType: SyntaxNode,
|
||||
): fieldType is IntegerLiteral {
|
||||
return fieldType.type === SyntaxType.IntegerLiteral;
|
||||
}
|
||||
|
||||
export function isHexLiteral(fieldType: SyntaxNode): fieldType is HexLiteral {
|
||||
return fieldType.type === SyntaxType.HexLiteral;
|
||||
}
|
||||
|
||||
export function isStringLiteral(
|
||||
fieldType: SyntaxNode,
|
||||
): fieldType is StringLiteral {
|
||||
return fieldType.type === SyntaxType.StringLiteral;
|
||||
}
|
||||
export function isAnnotations(fieldType: any): fieldType is Annotations {
|
||||
return fieldType.type === SyntaxType.Annotations;
|
||||
}
|
||||
export function isIntConstant(fieldType: SyntaxNode): fieldType is IntConstant {
|
||||
return fieldType.type === SyntaxType.IntConstant;
|
||||
}
|
||||
export function isDoubleConstant(
|
||||
fieldType: SyntaxNode,
|
||||
): fieldType is DoubleConstant {
|
||||
return fieldType.type === SyntaxType.DoubleConstant;
|
||||
}
|
||||
export function isBooleanLiteral(
|
||||
fieldType: SyntaxNode,
|
||||
): fieldType is BooleanLiteral {
|
||||
return fieldType.type === SyntaxType.BooleanLiteral;
|
||||
}
|
||||
export function isConstMap(fieldType: SyntaxNode): fieldType is ConstMap {
|
||||
return fieldType.type === SyntaxType.ConstMap;
|
||||
}
|
||||
export function isConstList(fieldType: SyntaxNode): fieldType is ConstList {
|
||||
return fieldType.type === SyntaxType.ConstList;
|
||||
}
|
||||
33
frontend/infra/idl/idl2ts-helper/src/utils.ts
Normal file
33
frontend/infra/idl/idl2ts-helper/src/utils.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
export function isPbFile(p: string) {
|
||||
return p.endsWith('.proto');
|
||||
}
|
||||
|
||||
export function lookupFile(include: string, search: string[]) {
|
||||
let results = include;
|
||||
search.forEach(s => {
|
||||
const target = path.resolve(s, include);
|
||||
if (fs.existsSync(target)) {
|
||||
results = target;
|
||||
}
|
||||
});
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user