chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -48,7 +48,7 @@ export const flowPreset = {
'@coze-arch/tsx-no-leaked-render': 'warn',
'@coze-arch/no-pkg-dir-import': 'error',
'@coze-arch/no-duplicated-deps': 'error',
// 不允许超过 4 层的相对应用
// Relative applications with more than 4 layers are not allowed
'@coze-arch/no-deep-relative-import': [
'error',
{
@@ -56,7 +56,7 @@ export const flowPreset = {
},
],
'@coze-arch/package-require-author': 'error',
// 函数代码行不要超过 150
// Function code lines should not exceed 150.
'@coze-arch/max-line-per-function': [
'error',
{
@@ -73,11 +73,11 @@ export const flowPreset = {
files: ['package.json'],
processor: '@coze-arch/json-processor',
rules: {
// TODO: 需要重构为直接解析json否则全局规则都会对processor处理后的文件`package.js`生效.
// TODO: It needs to be refactored to parse json directly, otherwise the global rules will take effect on the file'package.js' processed by the processor.
//https://github.com/eslint/json
'@coze-arch/package-require-author': 'error',
'@coze-arch/package-disallow-deps': 'error',
// 关闭prettier规则因为该规则lint package.js存在bug
// Close the prettier rule because there is a bug in the rule lint package.js
'prettier/prettier': 'off',
},
},

View File

@@ -36,7 +36,7 @@ const getStaticStringValue = node => {
*
* @param node
* @returns
* 为什么需要这个判断,对于下面这种函数
* Why is this judgment necessary for a function such as
* ```
* var obj1 = {
* set
@@ -46,9 +46,9 @@ const getStaticStringValue = node => {
* }
* }
*```
* 如果不采用下面这个判断函数判断将得到3实际应该为5. 类似的还有
* If you don't use the following judgment, the function judgment will get 3, which should actually be 5. Similarly, there are
* ```
* //如果不采用下面这个判断函数判断将得到3实际应该为8
* //If the following judgment is not used, the function judgment will get 3, which should actually be 8ing judgment, the function judgment will get 3, which should actually be 8.
* class A {
static
[
@@ -85,14 +85,14 @@ const isEmbedded = node => {
*
* @param node
* @returns function name
* Q:为什么不直接用 node.id.value获取函数名称 ?
* A:这种方式对于 传统的函数写法没问题,但是对于
* Q: Why not get the function name directly with node.id?
* A: This method is fine for traditional function writing, but for
* const tips = {
* fun: () => {}
* };
* 或者
* or
* const fun2 = () => {}
* 方式书写函数得到的名称为null所以采取下面这种方式获取
* The name of the function written in the following way is null, so it is obtained in the following way.
*
*/
@@ -192,7 +192,7 @@ const getStaticPropertyName = node => {
case 'VariableDeclarator':
prop = node.id;
break;
//TODO CallExpression 场景较为复杂,目前应该没有完全覆盖
//TODO: The CallExpression scenario is more complex and should not be fully covered at present
case 'CallExpression':
prop = node.callee;
break;
@@ -240,7 +240,7 @@ export const maxLinePerFunctionRule: Rule.RuleModule = {
function checkFunctionLength(funcNode) {
const node = isEmbedded(funcNode) ? funcNode.parent : funcNode;
// 针对函数声明,函数表达式,箭头函数,函数定义四种类型
// Four types of function declarations, function expressions, arrow functions, and function definitions
if (
node.type === 'FunctionDeclaration' ||
node.type === 'FunctionExpression' ||

View File

@@ -40,7 +40,7 @@ export const noDuplicatedDepsRule: Rule.RuleModule = {
if (!properties) {
return;
}
// 对比 dependencies devDependencies 之间是否存在重复依赖
// Compare dependencies with devDependencies for duplicate dependencies
const dependencies = properties.find(
p => p.key.value === 'dependencies',
);

View File

@@ -40,7 +40,7 @@ export const noPkgDirImport: Rule.RuleModule = {
const modulePath = resolve(importPath, context);
if (!modulePath) {
// 解析不到的情况,暂不处理
// If it cannot be resolved, it will not be dealt with for the time being.
return;
}
@@ -56,15 +56,15 @@ export const noPkgDirImport: Rule.RuleModule = {
return;
}
// 本地link会解析到node_modules目录需要拿到pkg name再次解析。
// The local link will resolve to the node_modules directory, and you need to get the pkg name to resolve it again.
const moduleRealPath = resolve(pkg.name, context);
if (
// 包名称就是引用路径
// The package name is the reference path
pkg.name === importPath ||
// 解析到其他包,如@type
// Parse to other packages, such as @type
!importPath.startsWith(pkg.name) ||
// 解析到自己包的文件
// Parse to the file of your own package
currentPkgPath === importPkgPath ||
!moduleRealPath ||
moduleRealPath.includes('node_modules')

View File

@@ -32,7 +32,7 @@ vi.mock('eslint-module-utils/readPkgUp', () => ({
const validCases = [
{
code: 'import "xxx"',
modulePath: undefined, // modulePath 为 空
modulePath: undefined, // modulePath is empty
moduleRealPath: undefined,
importPkgPath: 'path/to/import/pkg',
currentPkgPath: 'path/to/current/pkg',
@@ -48,7 +48,7 @@ const validCases = [
importPkgPath: 'path/to/import/pkg',
currentPkgPath: 'path/to/current/pkg',
pkg: {
name: 'some/pkg', // 包名称与引用路径相同
name: 'some/pkg', // The package name is the same as the reference path
exports: {},
},
},
@@ -59,7 +59,7 @@ const validCases = [
importPkgPath: 'path/to/import/pkg',
currentPkgPath: 'path/to/current/pkg',
pkg: {
name: undefined, // 解析到不规范配置的package.json
name: undefined, // Parse to the non-canonical package.json
},
},
{
@@ -69,7 +69,7 @@ const validCases = [
importPkgPath: 'path/to/import/pkg',
currentPkgPath: 'path/to/current/pkg',
pkg: {
name: '@types/pkg', // 解析到类型包
name: '@types/pkg', // Parse to type package
exports: {},
},
},
@@ -77,7 +77,7 @@ const validCases = [
code: "import pkg from 'pkg';",
modulePath: 'path/to/module',
moduleRealPath: 'path/to/module',
importPkgPath: 'path/to/same/pkg', // 相同路径
importPkgPath: 'path/to/same/pkg', // same path
currentPkgPath: 'path/to/same/pkg',
pkg: {
name: '@types/pkg',
@@ -98,7 +98,7 @@ const validCases = [
{
code: "import pkg from 'pkg';",
modulePath: 'path/to/module',
moduleRealPath: 'path/to/node_modules/pkg', // 解析到node_modules
moduleRealPath: 'path/to/node_modules/pkg', // Parse to node_modules
importPkgPath: 'path/to/import/pkg',
currentPkgPath: 'path/to/current/pkg',
pkg: {
@@ -134,7 +134,7 @@ const validCases = [
if (!c.modulePath) {
return {
code: c.code,
// TODO: 避免eslint duplication检测。可能需要改为其他方式
// TODO: Avoid eslint duplication. It may need to be changed to another way
settings: c,
};
}
@@ -167,7 +167,7 @@ const invalidCases = [
currentPkgPath: 'path/to/current/pkg',
pkg: {
name: 'pkg',
exports: undefined, // 为空
exports: undefined, // empty
},
messageId: 'noExportsCfg',
},

View File

@@ -56,7 +56,7 @@ export const disallowDepRule: Rule.RuleModule = {
return;
}
const [, blockVersion, tips] = definition;
// 没有提供 version 参数,判定为不允许所有版本号
// No version parameter is provided, and it is determined that all version numbers are not allowed
if (typeof blockVersion !== 'string' || blockVersion.length <= 0) {
context.report({
node,

View File

@@ -20,12 +20,12 @@ import reactPlugin from 'eslint-plugin-react';
const originRule = reactPlugin.rules['jsx-no-leaked-render'];
// 扩展react/jsx-no-leaked-render。增加判断 「&&」 表达式左边为 boolean null undefined TS类型,则不报错。
// Expand the react/jsx-no-leaked-render. If the left side of the "& &" expression is boolean, null, undefined TS type, no error will be reported.
export const tsxNoLeakedRender = ruleComposer.filterReports(
originRule,
problem => {
const { parent } = problem.node;
// 如果表达式是用于jsx属性则不需要修复。 如 <Comp prop={ { foo: 1 } && obj } />
// If the expression is used for jsx properties, it does not need to be fixed. Such as < Comp prop = {{foo: 1} & & obj}/>
if (
parent?.type === AST_NODE_TYPES.JSXExpressionContainer &&
parent?.parent?.type === AST_NODE_TYPES.JSXAttribute

View File

@@ -25,7 +25,7 @@ ruleTester.run('prefer-shallow', preferShallow, {
'new Foo()',
'useShallowedFooStore()',
'useFooStore((s) => s.value)',
'useFooStore(selector)', // 暂时豁免
'useFooStore(selector)', // Temporary exemption
'useShallowFooStore(() => ({}))',
'useFooStore(useShallow(() => ({})))',
'useFooStore(useShallow(() => ([])))',

View File

@@ -32,8 +32,8 @@ struct UserDeleteDataMap {
We
*/
enum AvatarMetaType {
UNKNOWN = 0, // 没有数据, 错误数据或者系统错误降级
RANDOM = 1, // 在修改 or 创建时,用户未指定 name 或者选中推荐的文字时,程序随机选择的头像
UNKNOWN = 0, // No data, incorrect data, or system error downgrade
RANDOM = 1, // When modifying or creating, the user does not specify a name or select the recommended text, the program randomly selects the avatar
}
`;

View File

@@ -46,8 +46,8 @@ enum Gender {
}
// const map<Gender, string> genderMap = {
// Gender.Male: '男性',
// Gender.Female: '女性',
// Gender. Male: 'Male',
// Gender. Female: 'Female',
// }
union FuncRequest {

View File

@@ -686,7 +686,7 @@ function convertFieldDefinition(
if (!isProto3) {
requiredness = optional ? 'optional' : 'required';
} else if (rule === 'required') {
// TODO: 处理 optional 的情况,需要修改 proto-parser
// TODO: Handle optional cases, need to modify proto-parser
requiredness = 'required';
}

View File

@@ -25,7 +25,7 @@ function requiredWithoutCache(src, onError?) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { Module } = require('module');
try {
// disable require 的缓存,这样可以改变了 mock 数据后,无需重启服务。
// Disable the required cache so that you can change the mock data without restarting the service.
const originCache = Module._cache;
Module._cache = {};
// eslint-disable-next-line security/detect-non-literal-require, @typescript-eslint/no-require-imports

View File

@@ -186,7 +186,7 @@ export class FilterTypesPlugin {
} else if (isIdentifier(fieldType)) {
const statement = getStatementById(fieldType, current);
if (isEnumDefinition(statement)) {
// 强制转位 number
// Forced indexing number
// @ts-expect-error fixme late
fieldType.type = SyntaxType.I32Keyword;
let namespace = current.unifyNamespace;

View File

@@ -55,15 +55,15 @@ export class MockPlugin implements IPlugin {
if (context) {
const { fieldDefinition } = context;
const fieldName = fieldDefinition.name.value;
// 各类 ID
// various types of ID
if (fieldName.toLocaleUpperCase().endsWith('ID')) {
value = String(faker.number.int());
}
// email 处理
// Email processing
if (fieldName.includes('Email')) {
value = `${faker.person.lastName()}@foo.com`;
}
// 直接映射值
// direct mapping value
value = StrMapper[fieldName] || value;
}
ctx.output = t.stringLiteral(value);
@@ -76,20 +76,20 @@ export class MockPlugin implements IPlugin {
const { fieldDefinition } = context;
const fieldName = fieldDefinition.name.value;
const formatName = fieldName.toLocaleUpperCase();
// 各类 ID
// various types of ID
if (formatName.endsWith('ID')) {
value = faker.number.int();
}
// 时间戳
// timestamp
if (formatName.endsWith('TIME') || formatName.includes('TIMESTAMP')) {
value = dayjs(faker.date.anytime()).valueOf();
}
// 类型状态
// type state
if (formatName.endsWith('STATUS') || formatName.includes('TYPE')) {
value = faker.number.int({ min: 0, max: 1 });
}
// 直接映射值
// direct mapping value
const mapVal = NumMapper[fieldName];
value = typeof mapVal !== 'undefined' ? mapVal : value;
}

View File

@@ -17,27 +17,27 @@
import { type IPlugin } from '@coze-arch/idl2ts-generator';
export interface ApiConfig {
// idl 入口
// IDL entrance
entries: Record<string, string>;
// idl 根目录
// IDL root directory
idlRoot: string;
// 服务别名
// 自定义 api 方法
// service alias
// Custom API method
commonCodePath: string;
// api 产物目录
// API Product Catalog
output: string;
// 仓库信息设置
// Warehouse information settings
repository?: {
// 仓库地址
// Warehouse address
url: string;
// clone 到本地的位置
// Clone to local location
dest: string;
};
// 插件
// plugin
plugins?: IPlugin[];
// 聚合导出的文件名
// aggregate exported filename
aggregationExport?: string;
// 格式化文件
// Format file
formatter: (name: string, content: string) => string;
idlFetchConfig?: {
source: string;
@@ -48,6 +48,6 @@ export interface ApiConfig {
}
export interface ApiTypeConfig extends ApiConfig {
// 需要过滤的方法
// Methods that require filtering
filters: Record<string, string[]>;
}

View File

@@ -163,7 +163,7 @@ export class ClientGenerator {
private processIdlAst(ast: IParseResultItem) {
try {
// 新的解析器貌似不是按原来位置排序的,这里要重新排序
// The new parser doesn't seem to be sorted by the original position, so it needs to be reordered here.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
ast.statements.sort((a, b) => a.loc!.start.line - b.loc!.start.line);
} catch (error) {

View File

@@ -139,14 +139,14 @@ export class AdapterPlugin implements IPlugin {
getAnnotation(f.annotations, 'api.converter') === 'atoi_comp_empty'
) {
if (isInt(f.fieldType)) {
// 类型转换为 string
// Type conversion to string
f.fieldType.type = SyntaxType.StringKeyword;
}
}
// api.converter int 以及 map 类型生效
// Api.converter works for int and map types
if (getAnnotation(f.annotations, 'api.converter') === 'itoa') {
if (isInt(f.fieldType)) {
// 类型转换为 string
// Type conversion to string
f.fieldType.type = SyntaxType.StringKeyword;
}
if (isMapType(f.fieldType)) {
@@ -156,7 +156,7 @@ export class AdapterPlugin implements IPlugin {
}
}
}
// item_converter list 类型生效
// item_converter for list types
if (
['atoi_comp_empty', 'itoa'].includes(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -168,24 +168,24 @@ export class AdapterPlugin implements IPlugin {
}
}
// 收集 decode encode 注解处理
// Collection decoding encoding annotation processing
if (getTypeFromDynamicJsonAnnotation(f.annotations)) {
decodeEncodeFields.push(f.name.value);
}
// api.json 注解处理
// api.json annotation processing
const jsonAnnotation = getAnnotation(f.annotations, 'api.json');
if (jsonAnnotation) {
f.extensionConfig = f.extensionConfig || {};
f.extensionConfig.key = jsonAnnotation;
}
// api.json_string 注解处理
// API. json_string annotation handling
const jsonStrAnnotation = getAnnotation(
f.annotations,
'api.json_string',
);
if (jsonStrAnnotation) {
if (isInt(f.fieldType)) {
// 类型转换为 string
// Type conversion to string
f.fieldType.type = SyntaxType.StringKeyword;
f.extensionConfig = f.extensionConfig || {};
f.extensionConfig.key = jsonStrAnnotation;

View File

@@ -403,7 +403,7 @@ export class ClientPlugin implements IPlugin {
});
const enumAst = t.tsEnumDeclaration(t.identifier(name.value), enumArr);
// 从后向前删除枚举项,避免索引变化影响
// Delete enumeration items from back to front to avoid the impact of index changes
enumItemIndexArray
.sort((a, b) => b - a)
.forEach(index => {

View File

@@ -21,7 +21,7 @@ import { type Contexts, HOOK } from '../context';
const MAGIC_COMMENT_KEY = '\n*@magic-comment';
// 忽略 struct 中的字段
// Ignore fields in struct
export class CommentFormatPlugin {
apply(p: Program<Contexts>) {
p.register(after('PARSE_ENTRY'), ctx => {

View File

@@ -26,7 +26,7 @@ interface IPops {
filter: Filter;
}
// 忽略 struct 中的字段
// Ignore fields in struct
export class IgnoreStructFiledPlugin {
private filter: Filter;
constructor({ filter }: IPops) {

View File

@@ -56,7 +56,7 @@ export class MetaPlugin implements IPlugin {
ctx => {
const node = ctx.node as ServiceDefinition;
node.functions.forEach(fun => {
// 过滤非泛化接口
// Filtering non-generalized interfaces
if (!fun.extensionConfig?.method) {
return;
}
@@ -103,7 +103,7 @@ export class MetaPlugin implements IPlugin {
schemaRoot: getSchemaRootByPath(ast.idlPath, this.options.idlRoot),
service,
} as IMeta;
// 不是 json 时,需要加上 serializer 标识
// When not json, you need to add the serializer flag.
if (extensionConfig?.serializer && extensionConfig?.serializer !== 'json') {
res.serializer = extensionConfig?.serializer;
}
@@ -117,7 +117,7 @@ export class MetaPlugin implements IPlugin {
if (isStructDefinition(statement)) {
const wholeBody = statement.fields.find(isFullBody);
if (wholeBody) {
// 处理 api.body="." 以及 api.full_body=''
// Handle api.body = "." and api.full_body = "
return `${id.value}['${getFieldsAlias(wholeBody)}']`;
} else {
return id.value;
@@ -184,7 +184,7 @@ export class MetaPlugin implements IPlugin {
}
});
}
// 如果没有指定根据method默认指定为query 或者 body
// If not specified, it is specified as query or body by default according to method.
if (!specificPositionFiled.has(alias)) {
const filedMapping = mapping[defaultPosition];
mapping[defaultPosition] = filedMapping

View File

@@ -110,7 +110,7 @@ export class MockTransformerPlugin implements IPlugin {
nextOrder[name] = index;
}
});
// 按照 mock 文件中的顺序优先排序
// Prioritize in order in the mock file
const getOrder = (name: string) =>
typeof mockVarOrder[name] !== 'undefined'
? mockVarOrder[name]
@@ -210,7 +210,7 @@ export class MockTransformerPlugin implements IPlugin {
if (isStructDefinition(statement)) {
const wholeBody = statement.fields.find(isFullBody);
if (wholeBody) {
// 处理 api.body="."
// Processing api.body = "."
const { annotations } = wholeBody;
if (hasDynamicJsonAnnotation(annotations)) {
return '{}';
@@ -273,7 +273,7 @@ export class MockTransformerPlugin implements IPlugin {
if (!fieldNames.has(fieldName)) {
return;
}
// 没有的,需要重新生成
// No, it needs to be regenerated.
newPros.push(
t.objectProperty(
fieldName.includes('-')
@@ -351,11 +351,11 @@ export class MockTransformerPlugin implements IPlugin {
const { valueType } = fieldType;
output = t.arrayExpression([this.processValue(valueType)]);
} else if (isSetType(fieldType)) {
// set 处理成array校验
// Set to array validation
const { valueType } = fieldType;
output = t.arrayExpression([this.processValue(valueType)]);
} else if (isIdentifier(fieldType)) {
// 引用类型
// reference type
const { refName, namespace } = parseIdFiledType(fieldType);
if (!namespace) {
output = t.callExpression(t.identifier(refName), []);
@@ -375,7 +375,7 @@ export class MockTransformerPlugin implements IPlugin {
throw new Error(`can not process fieldType : ${fieldType.type}`);
}
private processConst(constVal: ConstValue) {
// 暂时统一处理成0
// Temporarily unified processing to 0
if (isStringLiteral(constVal)) {
return t.stringLiteral(constVal.value);
}
@@ -410,11 +410,11 @@ export class MockTransformerPlugin implements IPlugin {
const comment = { type: 'CommentLine', value: commentValues } as any;
const target = this.findTarget(name.value, ctx);
if (target) {
// 需要更新注释
// Comments need to be updated
// target.trailingComments = [comment];
return;
}
// 枚举类型统一处理成常量
// Enumeration types are uniformly processed into constants
const builder = template(`var ${name.value}= () => %%value%% `);
const node = builder({
value: t.numericLiteral(values[0] || 0),
@@ -437,7 +437,7 @@ export class MockTransformerPlugin implements IPlugin {
// const variableDeclaration = t.addComment(
// ,
// 'leading',
// '暂时对const默认处理为0如有需要请自行重新赋值'
// 'Temporarily, the default processing for const is 0, please reassign it yourself if necessary '
// );
return node;
}

View File

@@ -29,7 +29,7 @@ import { type Options } from '../types';
import { type Contexts, HOOK } from '../context';
/**
* 提供统一 api 入口
* Provide unified API entry
*/
export class PkgEntryPlugin implements IPlugin {
private options: Options;
@@ -52,7 +52,7 @@ export class PkgEntryPlugin implements IPlugin {
);
this.funcs.set(
relativePath,
// 只支持单 service
// Only single service supported
meta[0].service,
);
return ctx;

View File

@@ -223,7 +223,7 @@ export class SchemaPlugin implements IPlugin {
};
return schema;
} else if (isSetType(fieldType)) {
// set 处理成array校验
// Set to array validation
const { valueType } = fieldType;
const schema: ListType = {
type: 'array',
@@ -231,7 +231,7 @@ export class SchemaPlugin implements IPlugin {
};
return schema;
} else if (isIdentifier(fieldType)) {
// 引用类型
// reference type
const { refName, namespace } = parseIdFiledType(fieldType);
if (!namespace) {
const schema: RefType = { $ref: `#/definitions/${refName}` };
@@ -249,7 +249,7 @@ export class SchemaPlugin implements IPlugin {
throw new Error(`can not process fieldType : ${fieldType.type}`);
}
private processConst(constVal: ConstValue) {
// 暂时统一处理成0
// Temporarily unified processing to 0
const schema = {} as ConstType;
if (isStringLiteral(constVal)) {
schema.const = constVal.value;

View File

@@ -29,11 +29,11 @@ export interface Options {
genMock: boolean;
genClient: boolean;
entryName?: string;
// createAPI 所在文件路径
// createAPI file path
commonCodePath?: string;
// decode encode 会丢失类型,这里提供一种方式,业务手动补充上对应的类型
// Decoding encoding will lose the type, here provides a way to manually add the corresponding type
patchTypesOutput?: string;
// patchTypesOutput 的别名,patch type 需要使用额外的 pkg 组织时需要提供
// PatchTypesOutput alias, patch type needs to be provided when using additional pkg organization
patchTypesAliasOutput?: string;
}

View File

@@ -42,11 +42,11 @@ export interface IMeta {
type Fields = string[];
export interface IHttpRpcMapping {
path?: Fields; // path参数
query?: Fields; // query参数
body?: Fields; // body 参数
header?: Fields; // header 参数
status_code?: Fields; // http状态码
path?: Fields; // path parameter
query?: Fields; // query parameters
body?: Fields; // Body parameters
header?: Fields; // header parameter
status_code?: Fields; // HTTP status code
cookie?: Fields; // cookie
entire_body?: Fields;
raw_body?: Fields;

View File

@@ -68,7 +68,7 @@ export function formatCode(code: string, root = '.') {
printWidth: 120,
singleQuote: true,
};
const file = path.resolve(process.cwd(), root, './for-prettier-bug'); // 这里一定要加多一级目录
const file = path.resolve(process.cwd(), root, './for-prettier-bug'); // Be sure to add an extra level catalog here.
const config = prettier.resolveConfig(file, { editorconfig: true });
return prettier.format(code, {
...(config || defaultConfig),
@@ -166,7 +166,7 @@ export function parseId(id: string) {
export function uniformNs(ns: string) {
if (ReservedKeyWord.includes(ns)) {
// 命中保留字,处理为下划线开头
// Hit the reserved word, treated as an underscore
return `_${ns}`;
}
return ns.replace(/\./g, '_');
@@ -182,7 +182,7 @@ export function getValuesFromEnum(params: h.EnumDefinition) {
if (h.isIntegerLiteral(initializer.value)) {
currentVal = Number(initializer.value.value);
} else if (h.isHexLiteral(initializer.value)) {
// 16进制
// hexadecimal
currentVal = Number(initializer.value.value);
}
enumArr.push(currentVal);
@@ -322,8 +322,8 @@ export function hasDynamicJsonAnnotation(annotations?: h.Annotations) {
}
/**
* api.(request|response).converter 中解析出前端与网关之间的真实类型,
* 能搞出这两个注解来,这个协议着实恶心😭
* Parse the real type between the front end and the gateway from api. (request | response).converter.
* To be able to come up with these two annotations, this protocol is disgusting😭
* @param annotations
* @returns
*/

View File

@@ -42,7 +42,7 @@ export class Program<C extends Ctxs = any> {
} = {};
/**
* 加载插件
* Load plugin
* @param plugins
*/
loadPlugins(plugins: IPlugin[]) {
@@ -51,10 +51,10 @@ export class Program<C extends Ctxs = any> {
}
}
/**
* 注册钩子
* @param event 事件名称
* @param handler 钩子
* @param priority 优先级,数值越小,优先级越高
* registration hook
* @param event name
* @param handler hook
* @Param priority, the smaller the value, the higher the priority
*/
register<
K extends keyof C,
@@ -87,7 +87,7 @@ export class Program<C extends Ctxs = any> {
}
}
/**
* 触发事件
* trigger event
* @param event
* @param args
* @returns

View File

@@ -20,20 +20,20 @@ import type { IMeta, CustomAPIMeta } from './types';
export interface ApiLike<T, K, O = unknown, B extends boolean = false> {
(req: T, option?: O extends object ? IOptions & O : IOptions): Promise<K>;
meta: IMeta;
/** fork 一份实例,该实例具有可中止请求的能力 */
/** Fork an instance that has the ability to abort requests */
withAbort: () => CancelAbleApi<T, K, O, B>;
}
export interface CancelAbleApi<T, K, O = unknown, B extends boolean = false>
extends ApiLike<T, K, O, B> {
// 中止请求
// abort request
abort: () => void;
// 是否是取消
// Is it cancelled?
isAborted: () => boolean;
}
/**
* 自定义构建 api 方法
* Custom build API method
* @param meta
* @param cancelable
* @param useCustom
@@ -56,7 +56,7 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
option = { ...(option || {}), ...customOption };
// 这里可以使用传进来的 req 作为默认映射,减少需要在 customAPI 中,需要手动绑定的情况
// Here, you can use the incoming req as the default mapping to reduce the need for manual binding in the customAPI
if (useCustom) {
const mappingKeys: string[] = Object.keys(meta.reqMapping)
.map(key => meta.reqMapping[key])
@@ -98,12 +98,12 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
function abort() {
/**
* 这里加上 pending 状态的原因是abortController.signal 的状态值只受控于 abortController.abort() 方法;
* 不管请求是否完成或者异常,只要调用 abortController.abort(), abortController.signal.aborted 必定为 true
* 这样不好判断请求是否真 aborted
* The reason for adding the pending state here is that the state value of abortController.signal is only controlled by the abortController.abort () method;
* No matter whether the request is completed or abnormal, as long as abortController.abort () is called, abortController.signal.aborted must be true.
* This makes it difficult to determine whether the request is really aborted.
*
* 这里改为,只有在请求 pending 的情况下,可执行 abort()
* isAborted === true 时,请求异常必定是因为手动 abort 导致的
* This is changed to abort () only if the request is pending.
* When isAborted === true, the request exception must be caused by manual abort
*/
if (pending === true && cancelable && abortController) {
abortController.abort();
@@ -128,7 +128,7 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
}
/**
* 一些非泛化的接口,可以使用改方法构建,方便统一管理接口
* Some non-generalized interfaces can be built using modified methods to facilitate unified management of interfaces
* @param customAPIMeta
* @param cancelable
* @returns

View File

@@ -30,11 +30,11 @@ export interface IMeta {
type Fields = string[];
export interface IHttpRpcMapping {
path?: Fields; // path参数
query?: Fields; // query参数
body?: Fields; // body 参数
header?: Fields; // header 参数
status_code?: Fields; // http状态码
path?: Fields; // path parameter
query?: Fields; // query parameters
body?: Fields; // Body parameters
header?: Fields; // header parameter
status_code?: Fields; // HTTP status code
cookie?: Fields; // cookie
entire_body?: Fields;
raw_body?: Fields;

View File

@@ -27,22 +27,22 @@ export interface ServiceConfig {
} & Omit<IdlConfig, 'clientFactory'>;
}
export interface IdlConfig {
// client 工厂方法,要求返回一个 fetchClient 函数,使用 meta 总的信息,可实现灵活的 client 配置
// The client factory method requires a fetchClient function to be returned, which uses the meta total information to achieve flexible client configuration
clientFactory?: (
meta: IMeta,
) => (uri: string, init: RequestInit, opt: any) => any;
// uri 前缀,如果 client 中设置了,这里可以不设置
// URI prefix, if set in client, you can leave it unset here
uriPrefix?: string;
getParams?: (key: string) => string;
// 服务级别的配置
// Service level configuration
services?: ServiceConfig;
// 开发时,如果本地校验失败,这里可回调,通常是弹 toast
// During development, if the local verification fails, it can be called back here, usually by playing toast.
onVerifyReqError?: (message: string, ctx: any) => void;
}
export interface IOptions {
config?: IdlConfig;
// 透传 request options 的选项
// Passthrough request options
requestOptions?: Record<string, any>;
[key: string]: any;
}
@@ -52,7 +52,7 @@ export interface PathPrams<T> {
}
export function getConfig(service: string, method: string): IdlConfig {
// 手动注册的配置优先级比全局变量高
// Manually registered configuration takes precedence over global variables
let config: IdlConfig | undefined = configCenter.getConfig(service);
if (!config) {
config = {};
@@ -137,7 +137,7 @@ export function normalizeRequest(
);
const { uriPrefix = '', clientFactory } = config;
if (!clientFactory) {
// todo 这里考虑给个默认的 client防止某些公共 package 在一些异常情况下使用
// Todo here considers giving a default client to prevent some public packages from being used in some abnormal cases
throw new Error('Lack of clientFactory config');
}
let uri = uriPrefix + apiUri;
@@ -149,11 +149,11 @@ export function normalizeRequest(
: 'application/json';
if (option?.requestOptions?.headers) {
headers = { ...headers, ...option.requestOptions.headers };
// 合并了 header,可删除
// Merged headers, can be deleted
delete option.requestOptions.headers;
}
if (meta.reqMapping.query && meta.reqMapping.query.length > 0) {
// 这里默认 skipNulls网关后端需要忽略 null
// The default here is skipNulls, and the gateway backend needs to ignore null.
uri = `${uri}?${qs.stringify(getValue(req, meta.reqMapping.query), {
skipNulls: true,
arrayFormat: 'comma',
@@ -168,7 +168,7 @@ export function normalizeRequest(
if (meta.reqMapping.entire_body && meta.reqMapping.entire_body.length > 0) {
if (meta.reqMapping.entire_body.length === 1) {
// 默认处理为 json ,如有其他场景需要支持,后需要再支持
// The default processing is json. If there are other scenarios that need to be supported, they need to be supported later.
requestOption.body = req[meta.reqMapping.entire_body[0]];
} else {
throw new Error('idl invalid entire_body should be only one filed');
@@ -203,7 +203,7 @@ export function normalizeRequest(
};
}
// 旧版的 ferry 中,即使 idl 没有声明body也需要加一个 空的 body
// In the old version of ferry, even if idl does not declare body, you need to add an empty body.
if (
!requestOption.body &&
['POST', 'PUT', 'PATCH'].includes(

View File

@@ -89,17 +89,17 @@ describe('PkgRootWebpackPlugin', () => {
new PkgRootWebpackPlugin(customOptions);
// 注意Object.assign 中后面的对象会覆盖前面的对象,所以默认配置会覆盖用户配置
// Note: Subsequent objects in Object.assign overwrite the preceding objects, so the default configuration overrides the user configuration
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalledWith({
customProp: 'customValue',
root: '@', // 被默认值覆盖
root: '@', // Overwritten by default
packagesDirs: [
'packages/project1',
'packages/project2',
'apps/app1',
'apps/app2',
],
excludeFolders: [], // 被默认值覆盖
excludeFolders: [], // Overwritten by default
});
});
@@ -110,9 +110,9 @@ describe('PkgRootWebpackPlugin', () => {
new PkgRootWebpackPlugin(customOptions);
// Object.assign 的行为:后面的对象会覆盖前面的对象属性
// Object.assign behavior: subsequent objects overwrite previous object properties
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalledWith({
root: '@', // 被默认值覆盖
root: '@', // Overwritten by default
packagesDirs: [
'packages/project1',
'packages/project2',
@@ -139,7 +139,7 @@ describe('PkgRootWebpackPlugin', () => {
});
it('验证所有导出都正确', () => {
// 验证模块导出了正确的类和默认导出
// Verify that the module exported the correct class and the default export
expect(PkgRootWebpackPlugin).toBeDefined();
expect(typeof PkgRootWebpackPlugin).toBe('function');
});
@@ -147,7 +147,7 @@ describe('PkgRootWebpackPlugin', () => {
it('应该正确处理 Rush 配置中的项目文件夹', () => {
new PkgRootWebpackPlugin();
// 验证传递给父类的 packagesDirs 包含所有项目文件夹
// Verify that the packagesDirs passed to the parent class contain all project folders
const call = (OriginPkgRootWebpackPlugin as any).mock.calls[0];
const options = call[0];
@@ -160,10 +160,10 @@ describe('PkgRootWebpackPlugin', () => {
});
it('测试插件基本功能正常工作', () => {
// 这个测试验证插件能正常实例化并调用父类构造函数
// This test verifies that the plugin can instantiate and call the parent class constructor normally
new PkgRootWebpackPlugin();
// 验证确实调用了父类构造函数
// Verify that the parent class constructor is indeed called
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalled();
});
});

View File

@@ -38,7 +38,7 @@ class PkgRootWebpackPlugin extends pkg_root_webpack_plugin_origin_1.default {
const mergedOptions = Object.assign({}, options || {}, {
root: '@',
packagesDirs: rushJsonPackagesDir,
// 排除apps/*,减少处理时间
// Exclude apps/* to reduce processing time
excludeFolders: [],
});
super(mergedOptions);

View File

@@ -41,7 +41,7 @@ class PkgRootWebpackPlugin extends OriginPkgRootWebpackPlugin {
const mergedOptions = Object.assign({}, options || {}, {
root: '@',
packagesDirs: rushJsonPackagesDir,
// 排除apps/*,减少处理时间
// Exclude apps/* to reduce processing time
excludeFolders: [],
});
super(mergedOptions);

View File

@@ -1,79 +1,79 @@
# @coze-arch/monorepo-kits
## 功能概述
/* Function Overview */
`@coze-arch/monorepo-kits` 是一个用于管理 monorepo 项目的工具包,提供了基于 Rush 框架的项目查找、依赖分析和配置管理功能。
/* "@Coze-arch/monorepo-kits" is a toolkit for managing monorepo projects, providing project lookup, dependency analysis, and configuration management capabilities based on the Rush framework. */
## 主要功能模块
/* Main Functional Modules */
### 1. 子包管理 (sub-packages.ts)
/* ###1. Subpackage management (sub-packages.ts) */
#### lookupSubPackages(packageName: string): string[]
- **功能**: 递归查找指定包的所有子依赖包
- **特性**: 使用缓存机制避免重复计算
- **返回**: 所有依赖包的名称数组(去重后)
/* - ** Function **: Recursively find all child dependencies of the specified package */
/* - ** Features **: Use caching mechanism to avoid double counting */
/* - ** Returns **: Array of names of all dependent packages (after deduplicate) */
#### getPackageLocation(packageName: string): string
- **功能**: 获取指定包的文件系统路径
- **返回**: 包的项目文件夹路径
/* - ** Function **: Get the file system path of the specified package */
/* - ** return **: the project folder path of the package */
#### getPackageJson(packageName: string): RushConfigurationProject['packageJson']
- **功能**: 获取指定包的 package.json 配置信息
- **返回**: 包的 package.json 对象
/* - ** Function **: Get the package.json configuration information of the specified package */
/* - ** returns **: package's package.json object */
### 2. Rush 配置管理 (rush-config.ts)
/* ###2. Rush configuration management (rush-config.ts) */
#### getRushConfiguration(): RushConfiguration
- **功能**: 获取 Rush 配置实例
- **特性**: 单例模式,首次调用时从默认位置加载配置,后续调用复用实例
- **返回**: RushConfiguration 对象
/* - ** Features **: Get Rush Configuration Instance */
/* - ** Features **: Singleton mode, first call loads configuration from default location, subsequent calls reuse instance */
/* - ** returns **: RushConfiguration object */
### 3. 项目查找 (lookup.ts)
/* ###3. Project lookup (lookup.ts) */
#### lookupTo(to: string): string[]
- **功能**: 查找指定包的直接依赖项
- **参数**: 目标包名称
- **返回**: 依赖包名称数组
/* - ** Features **: Find direct dependencies of a specified package */
/* - ** Parameter **: Target package name */
/* - ** Returns **: Array of dependency package names */
#### lookupFrom(from: string): void
- **功能**: 查找从指定包出发的相关信息(当前实现不完整)
- **参数**: 源包名称
/* - ** Features **: Find information about outgoing from a specified package (current implementation is incomplete) */
/* - ** parameter **: source package name */
#### lookupOnly(packageName: string): RushConfigurationProject
- **功能**: 查找并返回指定包的项目配置对象
- **参数**: 包名称
- **返回**: 完整的项目配置对象
/* - ** Features **: Find and return the project configuration object of the specified package */
/* - ** parameter **: package name */
/* - ** Return **: complete project configuration object */
## 依赖关系
/* ##dependencies */
- **主要依赖**: `@rushstack/rush-sdk@5.100.2`
- **开发依赖**: 包含 ESLintTypeScriptVitest 等工具链
/* - ** Major dependencies **: '@rushstack/rush-sdk@5.100.2' */
/* - ** Development dependencies **: Includes ESLint, TypeScript, Vitest and other toolchains */
## 使用场景
/* ##usage scenario */
1. **依赖分析**: 分析 monorepo 中包之间的依赖关系
2. **路径解析**: 获取包在文件系统中的实际位置
3. **配置查询**: 查询包的配置信息和元数据
4. **自动化工具**: 为构建脚本、部署工具等提供 monorepo 项目信息
/* 1. ** Dependency Analysis **: Analyze the dependencies between packages in Monorepo */
/* 2. ** Path parsing **: Get the actual location of the package in the file system */
/* 3. ** Configuration query **: Query the configuration information and metadata of the package */
/* 4. ** Automation Tools **: Provide monorepo project information for build scripts, deployment tools, etc */
## 架构特点
/* ##Architecture Features */
- **缓存优化**: 对递归依赖查找进行缓存,提高性能
- **错误处理**: 包含完善的包不存在异常处理
- **单例模式**: Rush 配置采用单例模式,避免重复加载
- **类型安全**: 基于 TypeScript提供完整的类型定义
/* - ** Cache optimization **: Cache recursive dependency lookups to improve performance */
/* - ** Error Handling **: Includes perfect package without exception handling */
/* - ** Singleton mode **: Rush configuration adopts singleton mode to avoid repeated loading */
/* Type safety: Based on TypeScript, complete type definition is provided */
## 代码结构
/* ##Code structure */
```
src/
├── index.ts # 主入口文件,导出所有公共 API
├─sub-packages.ts # 子包管理和依赖查找功能
├── rush-config.ts # Rush 配置管理
└── lookup.ts # 项目查找相关功能
/* < unk > ─ index.ts #Main entry file, export all public APIs */
/* < unk > Sub-packages.ts #Subpackage management and dependency lookup function */
/* 🥰 ─ rush-config.ts #Rush configuration management */
/* 🥰 ─ ─ lookup.ts #Project lookup related functions */
```
## API 导出
/* ##API export */
```typescript
export {
@@ -87,4 +87,4 @@ export { getRushConfiguration } from './rush-config';
export { lookupTo, lookupFrom, lookupOnly } from './lookup';
```
这个工具包为 monorepo 环境下的包管理、依赖分析和自动化工具开发提供了基础支持。
/* This toolkit provides fundamental support for package management, dependency analysis, and automated tool development in Monorepo environments. */

View File

@@ -80,5 +80,5 @@ const logger = new Logger();
export { logger };
/** @deprecated 该使用方式已废弃,请使用`import { logger } from '@coze-arch/rush-logger' */
/** @Deprecated This usage is deprecated, please use'import {logger} from '@code-arch/rush-logger' */
export default logger;