feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,288 @@
/*
* 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.
*/
/* eslint no-param-reassign: ["error", { "props": false }] */
import * as path from 'path';
import * as fs from 'fs';
import { parse as thriftParse } from '@lancewuz/thrift-parser';
import { logAndThrowError } from '../utils';
import {
type ThriftDocument,
type ThriftErrors,
SyntaxType,
type InterfaceWithFields,
type Annotation,
type ServiceDefinition,
type FunctionDefinition,
type EnumDefinition,
type FieldExtensionConfig,
type ServiceExtensionConfig,
type FunctionExtensionConfig,
type Comment,
} from './type';
import * as extensionUtil from '../common/extension_util';
// export statements
export * from './type';
// global variables
let reviseTailComment = true;
function extractExtensionConfigFromAnnotation(annotation: Annotation) {
let key = annotation.name.value;
const value = (annotation.value && annotation.value.value) || '';
if (/^((agw\.)|(api\.)|(go\.tag))/.test(key) === false) {
return false;
}
if (/^((agw\.)|(api\.))/.test(key)) {
key = key.slice(4);
}
const config = extensionUtil.extractExtensionConfig(key, value);
return config;
}
function convertFieldAnnotations(struct: InterfaceWithFields) {
const name = struct.name.value;
const { fields } = struct;
for (const field of fields) {
if (field.annotations && field.annotations.annotations.length > 0) {
const extensionConfig: FieldExtensionConfig = {};
const fieldName = field.name.value;
const fieldSyntaxType = field.fieldType.type;
for (const annotation of field.annotations.annotations) {
const config = extractExtensionConfigFromAnnotation(annotation);
if (config) {
if ('key' in config) {
// a key which is the same with the field name will make no sense
if (config.key === fieldName) {
delete config.key;
}
} else if (config.position === 'path') {
if (
[
SyntaxType.DoubleKeyword,
SyntaxType.BoolKeyword,
SyntaxType.ByteKeyword,
SyntaxType.ListKeyword,
SyntaxType.SetKeyword,
SyntaxType.MapKeyword,
SyntaxType.VoidKeyword,
].includes(fieldSyntaxType)
) {
const message = `the type of path parameter '${fieldName}' in '${name}' should be string or integer`;
logAndThrowError(message);
}
}
Object.assign(extensionConfig, config);
}
}
field.extensionConfig =
extensionUtil.filterFieldExtensionConfig(extensionConfig);
}
}
}
function convertFunctionAnnotations(func: FunctionDefinition) {
const { annotations } = func;
if (!(annotations && annotations.annotations.length > 0)) {
return;
}
const extensionConfig: FunctionExtensionConfig = {};
for (const annotation of annotations.annotations) {
const config = extractExtensionConfigFromAnnotation(annotation);
/* istanbul ignore next */
if (config) {
Object.assign(extensionConfig, config);
}
}
func.extensionConfig =
extensionUtil.filterFunctionExtensionConfig(extensionConfig);
}
function convertServiceAnnotations(service: ServiceDefinition) {
const { annotations } = service;
if (annotations && annotations.annotations.length > 0) {
const extensionConfig: ServiceExtensionConfig = {};
for (const annotation of annotations.annotations) {
const config = extractExtensionConfigFromAnnotation(annotation);
/* istanbul ignore else */
if (config) {
Object.assign(extensionConfig, config);
}
}
service.extensionConfig =
extensionUtil.filterServiceExtensionConfig(extensionConfig);
}
if (service.functions.length > 0) {
service.functions.forEach(func => {
convertFunctionAnnotations(func);
});
}
}
function reviseFieldComments(struct: InterfaceWithFields) {
const { fields } = struct;
/* istanbul ignore next */
if (fields.length < 2) {return;}
for (let i = fields.length - 1; i > 0; i--) {
const currentField = fields[i];
const prevField = fields[i - 1];
const prevFieldEndLine = prevField.loc.end.line;
const prevFieldComments = prevField.comments;
for (let j = 0; j < prevFieldComments.length; j++) {
if (prevFieldComments[j].loc.end.line > prevFieldEndLine) {
const dislocatedComments = prevFieldComments.splice(
j,
prevFieldComments.length - j,
);
currentField.comments = [
...dislocatedComments,
...currentField.comments,
];
break;
}
}
}
}
function reviseEnumMemberComments(enm: EnumDefinition) {
const { members } = enm;
/* istanbul ignore next */
if (members.length < 2) {return;}
for (let i = 0; i < members.length - 1; i++) {
const currentMember = members[i];
const nextMember = members[i + 1];
const currentMemberEndLine = currentMember.loc.end.line;
const nextMemberFirstComment = nextMember.comments[0];
if (
nextMemberFirstComment &&
nextMemberFirstComment.loc.end.line === currentMemberEndLine
) {
const dislocatedComment = nextMember.comments.shift() as Comment;
currentMember.comments.push(dislocatedComment);
}
}
}
function reviseFunctionComments(service: ServiceDefinition) {
const { functions } = service;
if (functions.length < 2) {return;}
for (let i = 0; i < functions.length - 1; i++) {
const currentFunction = functions[i];
const nextFunction = functions[i + 1];
const currentFunctionEndLine = currentFunction.loc.end.line;
const nextFunctionFirstComment = nextFunction.comments[0];
if (
nextFunctionFirstComment &&
nextFunctionFirstComment.loc.end.line === currentFunctionEndLine
) {
const dislocatedComment = nextFunction.comments.shift() as Comment;
currentFunction.comments.push(dislocatedComment);
}
}
}
export interface ParseOption {
reviseTailComment?: boolean;
}
const defualtParseOption = {
reviseTailComment: true,
};
export function parse(source: string, option?: ParseOption): ThriftDocument {
let content: string;
let filePath = 'source';
if (/\.thrift$/.test(source)) {
filePath = path.resolve(process.cwd(), source);
if (!fs.existsSync(filePath)) {
const message = `no such file: ${filePath}`;
logAndThrowError(message);
}
content = fs.readFileSync(filePath, 'utf8');
} else {
content = source;
}
const document: ThriftDocument | ThriftErrors = thriftParse(content);
if ((document as ThriftErrors).type === SyntaxType.ThriftErrors) {
const error = (document as ThriftErrors).errors[0];
const { start } = error.loc;
const message = `${error.message}(${filePath}:${start.line}:${start.column})`;
logAndThrowError(message);
}
const parseOption = { ...defualtParseOption, ...option };
reviseTailComment = parseOption.reviseTailComment;
for (const statement of (document as ThriftDocument).body) {
/* istanbul ignore else */
if (
[SyntaxType.StructDefinition, SyntaxType.UnionDefinition].includes(
statement.type,
)
) {
convertFieldAnnotations(statement as InterfaceWithFields);
if (reviseTailComment) {
reviseFieldComments(statement as InterfaceWithFields);
}
} else if (statement.type === SyntaxType.ServiceDefinition) {
convertServiceAnnotations(statement);
if (reviseTailComment) {
reviseFunctionComments(statement);
}
} else if (statement.type === SyntaxType.EnumDefinition) {
/* istanbul ignore else */
if (reviseTailComment) {
reviseEnumMemberComments(statement);
}
}
}
return document as ThriftDocument;
}

View File

@@ -0,0 +1,460 @@
/*
* 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 FieldExtensionConfig,
type ServiceExtensionConfig,
type FunctionExtensionConfig,
} from '../common/extension_type';
export * from '../common/extension_type';
export interface ThriftError {
type: ErrorType;
message: string;
loc: TextLocation;
}
export interface ParseError extends ThriftError {
type: ErrorType.ParseError;
}
export interface ScanError extends ThriftError {
type: ErrorType.ScanError;
}
export interface Node {
type: SyntaxType;
}
export interface SyntaxNode extends Node {
loc: TextLocation;
}
export interface StructLike {
name: Identifier;
fields: Array<FieldDefinition>;
annotations?: Annotations;
comments: Array<Comment>;
loc: TextLocation;
}
export interface TextLocation {
start: TextPosition;
end: TextPosition;
}
export interface TextPosition {
line: number;
column: number;
index: number;
}
export interface Token extends SyntaxNode {
text: string;
}
export interface ThriftDocument extends Node {
type: SyntaxType.ThriftDocument;
body: Array<ThriftStatement>;
tokens?: Array<Token>;
}
export interface ThriftErrors {
type: SyntaxType.ThriftErrors;
errors: Array<ThriftError>;
}
export type ThriftStatement =
| NamespaceDefinition
| IncludeDefinition
| CppIncludeDefinition
| ConstDefinition
| StructDefinition
| EnumDefinition
| ExceptionDefinition
| UnionDefinition
| TypedefDefinition
| ServiceDefinition;
export type CommentType = SyntaxType.CommentLine | SyntaxType.CommentBlock;
export type Comment = CommentLine | CommentBlock;
export interface CommentLine extends SyntaxNode {
type: SyntaxType.CommentLine;
value: string;
}
export interface CommentBlock extends SyntaxNode {
type: SyntaxType.CommentBlock;
value: Array<string>;
}
export interface Annotations extends SyntaxNode {
annotations: Array<Annotation>;
}
export interface Annotation extends SyntaxNode {
name: Identifier;
value?: StringLiteral;
}
export interface PrimarySyntax extends SyntaxNode {
comments: Array<Comment>;
}
export type FieldType = BaseType | ContainerType | Identifier;
export type FunctionType = FieldType | VoidType;
export type KeywordType =
| SyntaxType.StringKeyword
| SyntaxType.DoubleKeyword
| SyntaxType.BoolKeyword
| SyntaxType.I8Keyword
| SyntaxType.I16Keyword
| SyntaxType.I32Keyword
| SyntaxType.I64Keyword
| SyntaxType.BinaryKeyword
| SyntaxType.ByteKeyword;
export interface VoidType extends SyntaxNode {
type: SyntaxType.VoidKeyword;
}
export type ContainerType = SetType | MapType | ListType;
export interface BaseType extends SyntaxNode {
type: KeywordType;
annotations?: Annotations;
}
export interface SetType extends SyntaxNode {
type: SyntaxType.SetType;
valueType: FieldType;
annotations?: Annotations;
}
export interface ListType extends SyntaxNode {
type: SyntaxType.ListType;
valueType: FieldType;
annotations?: Annotations;
}
export interface MapType extends SyntaxNode {
type: SyntaxType.MapType;
keyType: FieldType;
valueType: FieldType;
annotations?: Annotations;
}
export type ConstValue =
| StringLiteral
| IntConstant
| DoubleConstant
| BooleanLiteral
| ConstMap
| ConstList
| Identifier;
export interface NamespaceDefinition extends PrimarySyntax {
type: SyntaxType.NamespaceDefinition;
scope: Identifier;
name: Identifier;
}
export interface ConstDefinition extends PrimarySyntax {
type: SyntaxType.ConstDefinition;
name: Identifier;
fieldType: FieldType;
initializer: ConstValue;
annotations?: Annotations;
}
export type FieldRequired = 'required' | 'optional';
export interface IncludeDefinition extends PrimarySyntax {
type: SyntaxType.IncludeDefinition;
path: StringLiteral;
}
export interface CppIncludeDefinition extends PrimarySyntax {
type: SyntaxType.CppIncludeDefinition;
path: StringLiteral;
}
export interface InterfaceWithFields extends PrimarySyntax {
name: Identifier;
fields: Array<FieldDefinition>;
annotations?: Annotations;
}
export interface StructDefinition extends InterfaceWithFields {
type: SyntaxType.StructDefinition;
}
export interface UnionDefinition extends InterfaceWithFields {
type: SyntaxType.UnionDefinition;
}
export interface ExceptionDefinition extends InterfaceWithFields {
type: SyntaxType.ExceptionDefinition;
}
export interface FieldDefinition extends PrimarySyntax {
type: SyntaxType.FieldDefinition;
name: Identifier;
fieldID: FieldID | null;
fieldType: FunctionType;
requiredness: FieldRequired | null;
defaultValue: ConstValue | null;
annotations?: Annotations;
extensionConfig?: FieldExtensionConfig;
}
export interface FieldID extends SyntaxNode {
type: SyntaxType.FieldID;
value: number;
}
export interface EnumDefinition extends PrimarySyntax {
type: SyntaxType.EnumDefinition;
name: Identifier;
members: Array<EnumMember>;
annotations?: Annotations;
}
export interface EnumMember extends PrimarySyntax {
type: SyntaxType.EnumMember;
name: Identifier;
initializer: IntConstant | null;
annotations?: Annotations;
}
export interface TypedefDefinition extends PrimarySyntax {
type: SyntaxType.TypedefDefinition;
name: Identifier;
definitionType: FieldType;
annotations?: Annotations;
}
export interface ServiceDefinition extends PrimarySyntax {
type: SyntaxType.ServiceDefinition;
name: Identifier;
extends: Identifier | null;
functions: Array<FunctionDefinition>;
annotations?: Annotations;
extensionConfig?: ServiceExtensionConfig;
}
export interface FunctionDefinition extends PrimarySyntax {
type: SyntaxType.FunctionDefinition;
name: Identifier;
oneway: boolean;
returnType: FunctionType;
fields: Array<FieldDefinition>;
throws: Array<FieldDefinition>;
modifiers: Array<Token>;
annotations?: Annotations;
extensionConfig?: FunctionExtensionConfig;
}
export interface ParametersDefinition extends SyntaxNode {
type: SyntaxType.ParametersDefinition;
fields: Array<FieldDefinition>;
}
export interface ThrowsDefinition extends SyntaxNode {
type: SyntaxType.ThrowsDefinition;
fields: Array<FieldDefinition>;
}
export interface StringLiteral extends SyntaxNode {
type: SyntaxType.StringLiteral;
value: string;
}
export interface BooleanLiteral extends SyntaxNode {
type: SyntaxType.BooleanLiteral;
value: boolean;
}
export interface IntegerLiteral extends SyntaxNode {
type: SyntaxType.IntegerLiteral;
value: string;
}
export interface HexLiteral extends SyntaxNode {
type: SyntaxType.HexLiteral;
value: string;
}
export interface FloatLiteral extends SyntaxNode {
type: SyntaxType.FloatLiteral;
value: string;
}
export interface ExponentialLiteral extends SyntaxNode {
type: SyntaxType.ExponentialLiteral;
value: string;
}
export interface IntConstant extends SyntaxNode {
type: SyntaxType.IntConstant;
value: IntegerLiteral | HexLiteral;
}
export interface DoubleConstant extends SyntaxNode {
type: SyntaxType.DoubleConstant;
value: FloatLiteral | ExponentialLiteral;
}
export interface ConstMap extends SyntaxNode {
type: SyntaxType.ConstMap;
properties: Array<PropertyAssignment>;
}
export interface ConstList extends SyntaxNode {
type: SyntaxType.ConstList;
elements: Array<ConstValue>;
}
export interface PropertyAssignment extends SyntaxNode {
type: SyntaxType.PropertyAssignment;
name: ConstValue;
initializer: ConstValue;
}
export interface Identifier extends SyntaxNode {
type: SyntaxType.Identifier;
value: string;
annotations?: Annotations;
}
export enum ErrorType {
ParseError = 'ParseError',
ScanError = 'ScanError',
}
export enum SyntaxType {
ThriftDocument = 'ThriftDocument',
ThriftErrors = 'ThriftErrors',
Identifier = 'Identifier',
FieldID = 'FieldID',
// Statements
NamespaceDefinition = 'NamespaceDefinition',
IncludeDefinition = 'IncludeDefinition',
CppIncludeDefinition = 'CppIncludeDefinition',
ConstDefinition = 'ConstDefinition',
StructDefinition = 'StructDefinition',
EnumDefinition = 'EnumDefinition',
ServiceDefinition = 'ServiceDefinition',
ExceptionDefinition = 'ExceptionDefinition',
TypedefDefinition = 'TypedefDefinition',
UnionDefinition = 'UnionDefinition',
// Fields
FieldDefinition = 'FieldDefinition',
FunctionDefinition = 'FunctionDefinition',
ParametersDefinition = 'ParametersDefinition',
ThrowsDefinition = 'ThrowsDefinition',
// Type Annotations
FieldType = 'FieldType',
BaseType = 'BaseType',
SetType = 'SetType',
MapType = 'MapType',
ListType = 'ListType',
// Values
ConstValue = 'ConstValue',
IntConstant = 'IntConstant',
DoubleConstant = 'DoubleConstant',
ConstList = 'ConstList',
ConstMap = 'ConstMap',
EnumMember = 'EnumMember',
// Literals
CommentLine = 'CommentLine',
CommentBlock = 'CommentBlock',
StringLiteral = 'StringLiteral',
IntegerLiteral = 'IntegerLiteral',
FloatLiteral = 'FloatLiteral',
HexLiteral = 'HexLiteral',
ExponentialLiteral = 'ExponentialLiteral',
BooleanLiteral = 'BooleanLiteral',
PropertyAssignment = 'PropertyAssignment',
// Tokens
LeftParenToken = 'LeftParenToken',
RightParenToken = 'RightParenToken',
LeftBraceToken = 'LeftBraceToken',
RightBraceToken = 'RightBraceToken',
LeftBracketToken = 'LeftBracketToken',
RightBracketToken = 'RightBracketToken',
CommaToken = 'CommaToken',
DotToken = 'DotToken',
MinusToken = 'MinusToken',
SemicolonToken = 'SemicolonToken',
ColonToken = 'ColonToken',
StarToken = 'StarToken',
EqualToken = 'EqualToken',
LessThanToken = 'LessThanToken',
GreaterThanToken = 'GreaterThanToken',
// Keywords
NamespaceKeyword = 'NamespaceKeyword',
IncludeKeyword = 'IncludeKeyword',
CppIncludeKeyword = 'CppIncludeKeyword',
ExceptionKeyword = 'ExceptionKeyword',
ServiceKeyword = 'ServiceKeyword',
ExtendsKeyword = 'ExtendsKeyword',
RequiredKeyword = 'RequiredKeyword',
OptionalKeyword = 'OptionalKeyword',
FalseKeyword = 'FalseKeyword',
TrueKeyword = 'TrueKeyword',
ConstKeyword = 'ConstKeyword',
DoubleKeyword = 'DoubleKeyword',
StructKeyword = 'StructKeyword',
TypedefKeyword = 'TypedefKeyword',
UnionKeyword = 'UnionKeyword',
StringKeyword = 'StringKeyword',
BinaryKeyword = 'BinaryKeyword',
BoolKeyword = 'BoolKeyword',
ByteKeyword = 'ByteKeyword',
EnumKeyword = 'EnumKeyword',
SenumKeyword = 'SenumKeyword',
ListKeyword = 'ListKeyword',
SetKeyword = 'SetKeyword',
MapKeyword = 'MapKeyword',
I8Keyword = 'I8Keyword',
I16Keyword = 'I16Keyword',
I32Keyword = 'I32Keyword',
I64Keyword = 'I64Keyword',
ThrowsKeyword = 'ThrowsKeyword',
VoidKeyword = 'VoidKeyword',
OnewayKeyword = 'OnewayKeyword',
// Other
Annotation = 'Annotation',
Annotations = 'Annotations',
EOF = 'EOF',
}