chore: format all common files (#431)

This commit is contained in:
tecvan 2025-07-31 21:46:47 +08:00 committed by GitHub
parent 8136ddd82d
commit 40088b0a05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
60 changed files with 658 additions and 288 deletions

View File

@ -18,46 +18,41 @@ import type {
IPlugin, IPlugin,
IHooks, IHooks,
IPromptsHookParams, IPromptsHookParams,
} from "rush-init-project-plugin"; } from 'rush-init-project-plugin';
import { readFileSync } from 'fs'; import { readFileSync } from 'fs';
import path from 'path'; import path from 'path';
import JSON5 from '../../autoinstallers/plugins/node_modules/json5' import JSON5 from '../../autoinstallers/plugins/node_modules/json5';
const rushJson = JSON5.parse( const rushJson = JSON5.parse(
readFileSync( readFileSync(path.resolve(__dirname, '../../../rush.json')).toString('utf-8'),
path.resolve(__dirname, '../../../rush.json')
).toString('utf-8')
); );
export default class SelectTeamPlugin implements IPlugin { export default class SelectTeamPlugin implements IPlugin {
apply(hooks: IHooks): void { apply(hooks: IHooks): void {
hooks.prompts.tap("SelectTeamPlugin", (prompts: IPromptsHookParams) => { hooks.prompts.tap('SelectTeamPlugin', (prompts: IPromptsHookParams) => {
// Leave only the prefix team- // Leave only the prefix team-
const teamNamePrefix = /^team-/; const teamNamePrefix = /^team-/;
const choices = rushJson.allowedProjectTags.filter( const choices = rushJson.allowedProjectTags
teamName => teamNamePrefix.test(teamName) .filter(teamName => teamNamePrefix.test(teamName))
).map( .map(teamName => teamName.replace(teamNamePrefix, ''));
teamName => teamName.replace(teamNamePrefix, '')
);
// Unshift an issue, causing the user to display the issue after selecting a template. // Unshift an issue, causing the user to display the issue after selecting a template.
prompts.promptQueue.unshift({ prompts.promptQueue.unshift({
type: "list", type: 'list',
name: "team", name: 'team',
message: "Select your team", message: 'Select your team',
choices, choices,
default: 0, // Default choices [0] default: 0, // Default choices [0]
}); });
const projectFolderPrompt = prompts.promptQueue.find( const projectFolderPrompt = prompts.promptQueue.find(
item => item.name === 'projectFolder' item => item.name === 'projectFolder',
); );
projectFolderPrompt.default = (answers) => { projectFolderPrompt.default = answers => {
// Remove the scope from the folder name, such as @code-arch/foo - > foo // Remove the scope from the folder name, such as @code-arch/foo - > foo
const folderDir = answers.packageName.split('/').slice(-1)[0]; const folderDir = answers.packageName.split('/').slice(-1)[0];
return `frontend/packages/${answers.team}/${folderDir}`; return `frontend/packages/${answers.team}/${folderDir}`;
} };
}); });
} }
} }

View File

@ -18,7 +18,11 @@ import type { ILogger } from 'rush-init-project-plugin';
// eslint-disable-next-line @infra/no-deep-relative-import // eslint-disable-next-line @infra/no-deep-relative-import
import { spawnSync } from 'child_process'; import { spawnSync } from 'child_process';
const exec = (logger: ILogger, cmd: string, args: string[]): string | undefined => { const exec = (
logger: ILogger,
cmd: string,
args: string[],
): string | undefined => {
try { try {
if (!cmd) { if (!cmd) {
return undefined; return undefined;

View File

@ -21,8 +21,8 @@ import SetDefaultAuthorPlugin from '../_plugins/SetDefaultAuthorPlugin';
const config: IConfig = { const config: IConfig = {
plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()], plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()],
defaultProjectConfiguration: { defaultProjectConfiguration: {
tags:['level-3'] tags: ['level-3'],
} },
}; };
export default config; export default config;

View File

@ -40,7 +40,6 @@
"react-dom": "~18.2.0", "react-dom": "~18.2.0",
"storybook": "^7.6.7", "storybook": "^7.6.7",
"stylelint": "^15.11.0", "stylelint": "^15.11.0",
"vite-plugin-svgr": "~3.3.0", "vite-plugin-svgr": "~3.3.0",
"vitest": "~3.0.5" "vitest": "~3.0.5"
}, },
@ -49,3 +48,4 @@
"react-dom": ">=18.2.0" "react-dom": ">=18.2.0"
} }
} }

View File

@ -21,8 +21,8 @@ import SetDefaultAuthorPlugin from '../_plugins/SetDefaultAuthorPlugin';
const config: IConfig = { const config: IConfig = {
plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()], plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()],
defaultProjectConfiguration: { defaultProjectConfiguration: {
tags:['level-3'] tags: ['level-3'],
} },
}; };
export default config; export default config;

View File

@ -19,8 +19,8 @@
"@coze-arch/vitest-config": "workspace:*", "@coze-arch/vitest-config": "workspace:*",
"@types/node": "^18", "@types/node": "^18",
"@vitest/coverage-v8": "~3.0.5", "@vitest/coverage-v8": "~3.0.5",
"sucrase": "^3.32.0",
"vitest": "~3.0.5", "vitest": "~3.0.5"
"sucrase": "^3.32.0"
} }
} }

View File

@ -21,8 +21,8 @@ import SetDefaultAuthorPlugin from '../_plugins/SetDefaultAuthorPlugin';
const config: IConfig = { const config: IConfig = {
plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()], plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()],
defaultProjectConfiguration: { defaultProjectConfiguration: {
tags:['level-4'] tags: ['level-4'],
} },
}; };
export default config; export default config;

View File

@ -26,9 +26,9 @@
}, },
"devDependencies": { "devDependencies": {
"@coze-arch/eslint-config": "workspace:*", "@coze-arch/eslint-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*", "@coze-arch/ts-config": "workspace:*",
"@coze-arch/vitest-config": "workspace:*", "@coze-arch/vitest-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*",
"@rsbuild/core": "^0.2.18", "@rsbuild/core": "^0.2.18",
"@rsbuild/plugin-react": "^0.2.18", "@rsbuild/plugin-react": "^0.2.18",
"@slardar/web": "1.7.0", "@slardar/web": "1.7.0",
@ -39,7 +39,7 @@
"postcss": "^8.4.32", "postcss": "^8.4.32",
"postcss-loader": "^7.3.3", "postcss-loader": "^7.3.3",
"tailwindcss": "~3.3.3", "tailwindcss": "~3.3.3",
"vitest": "~3.0.5" "vitest": "~3.0.5"
} }
} }

View File

@ -21,8 +21,8 @@ import SetDefaultAuthorPlugin from '../_plugins/SetDefaultAuthorPlugin';
const config: IConfig = { const config: IConfig = {
plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()], plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()],
defaultProjectConfiguration: { defaultProjectConfiguration: {
tags:['level-4'] tags: ['level-4'],
} },
}; };
export default config; export default config;

View File

@ -16,6 +16,9 @@
"test:cov": "npm run test -- --coverage" "test:cov": "npm run test -- --coverage"
}, },
"dependencies": { "dependencies": {
"@coze-arch/bot-api": "workspace:*",
"@coze-arch/i18n": "workspace:*",
"@coze-arch/logger": "workspace:*",
"@douyinfe/semi-icons": "^2.36.0", "@douyinfe/semi-icons": "^2.36.0",
"@douyinfe/semi-ui": "2.61.0", "@douyinfe/semi-ui": "2.61.0",
"immer": "^10.0.3", "immer": "^10.0.3",
@ -23,18 +26,15 @@
"react-dom": "~18.2.0", "react-dom": "~18.2.0",
"react-error-boundary": "^4.0.9", "react-error-boundary": "^4.0.9",
"react-router-dom": "^6.11.1", "react-router-dom": "^6.11.1",
"zustand": "^4.4.7", "zustand": "^4.4.7"
"@coze-arch/logger": "workspace:*",
"@coze-arch/i18n": "workspace:*",
"@coze-arch/bot-api": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@douyinfe/semi-rspack-plugin": "~2.48.0",
"@edenx/plugin-tailwind": "1.51.0",
"@coze-arch/eslint-config": "workspace:*", "@coze-arch/eslint-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*", "@coze-arch/ts-config": "workspace:*",
"@coze-arch/vitest-config": "workspace:*", "@coze-arch/vitest-config": "workspace:*",
"@coze-arch/stylelint-config": "workspace:*", "@douyinfe/semi-rspack-plugin": "~2.48.0",
"@edenx/plugin-tailwind": "1.51.0",
"@rspack/cli": "0.4.0", "@rspack/cli": "0.4.0",
"@rspack/core": "0.4.0", "@rspack/core": "0.4.0",
"@rspack/plugin-react-refresh": "0.4.0", "@rspack/plugin-react-refresh": "0.4.0",
@ -52,7 +52,7 @@
"tailwindcss": "~3.3.3", "tailwindcss": "~3.3.3",
"ts-morph": "^20.0.0", "ts-morph": "^20.0.0",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"vitest": "~3.0.5" "vitest": "~3.0.5"
} }
} }

View File

@ -27,7 +27,7 @@ browserClient('init', {
bid: '', bid: '',
}); });
browserClient('start'); browserClient('start');
reporter.init(browserClient) reporter.init(browserClient);
const root = createRoot(document.getElementById('root')); const root = createRoot(document.getElementById('root'));
root.render(<RouterProvider router={router} />); root.render(<RouterProvider router={router} />);

View File

@ -21,8 +21,8 @@ import SetDefaultAuthorPlugin from '../_plugins/SetDefaultAuthorPlugin';
const config: IConfig = { const config: IConfig = {
plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()], plugins: [new SetDefaultAuthorPlugin(), new SelectTeamPlugin()],
defaultProjectConfiguration: { defaultProjectConfiguration: {
tags:['level-3'] tags: ['level-3'],
} },
}; };
export default config; export default config;

View File

@ -4,8 +4,7 @@
"description": "{{ description }}", "description": "{{ description }}",
"license": "Apache-2.0", "license": "Apache-2.0",
"author": "{{ authorName }}", "author": "{{ authorName }}",
"maintainers": [ "maintainers": [],
],
"main": "src/index.ts", "main": "src/index.ts",
"unpkg": "./dist/umd/index.js", "unpkg": "./dist/umd/index.js",
"module": "./dist/esm/index.js", "module": "./dist/esm/index.js",
@ -63,7 +62,6 @@
"storybook": "^7.6.7", "storybook": "^7.6.7",
"stylelint": "^15.11.0", "stylelint": "^15.11.0",
"tailwindcss": "~3.3.3", "tailwindcss": "~3.3.3",
"vite-plugin-svgr": "~3.3.0", "vite-plugin-svgr": "~3.3.0",
"vitest": "~3.0.5" "vitest": "~3.0.5"
}, },
@ -72,3 +70,4 @@
"react-dom": ">=18.2.0" "react-dom": ">=18.2.0"
} }
} }

View File

@ -3,3 +3,4 @@
"@eslint/compat": "^1.2.2" "@eslint/compat": "^1.2.2"
} }
} }

View File

@ -21,3 +21,4 @@
"@types/node": "^18.6.3" "@types/node": "^18.6.3"
} }
} }

View File

@ -17,3 +17,4 @@
"typescript": "^5.0.0" "typescript": "^5.0.0"
} }
} }

View File

@ -1,3 +1,19 @@
/*
* 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 { Command } from 'commander'; import { Command } from 'commander';
import { CliOptions } from '../types/config'; import { CliOptions } from '../types/config';
@ -14,7 +30,11 @@ export const createProgram = (): Command => {
program program
.requiredOption('-r, --root <directory>', '需要处理的根目录') .requiredOption('-r, --root <directory>', '需要处理的根目录')
.option('-e, --exts <extensions>', '文件扩展名,用逗号分隔 (例: ts,js,go)', '') .option(
'-e, --exts <extensions>',
'文件扩展名,用逗号分隔 (例: ts,js,go)',
'',
)
.option('--access-key-id <key>', '火山引擎 Access Key ID') .option('--access-key-id <key>', '火山引擎 Access Key ID')
.option('--secret-access-key <key>', '火山引擎 Secret Access Key') .option('--secret-access-key <key>', '火山引擎 Secret Access Key')
.option('--region <region>', '火山引擎服务区域', 'cn-beijing') .option('--region <region>', '火山引擎服务区域', 'cn-beijing')
@ -48,7 +68,7 @@ export const parseOptions = (program: Command): CliOptions => {
dryRun: options.dryRun, dryRun: options.dryRun,
verbose: options.verbose, verbose: options.verbose,
output: options.output, output: options.output,
config: options.config config: options.config,
}; };
}; };

View File

@ -1,4 +1,25 @@
import { AppConfig, CliOptions, TranslationConfig, ProcessingConfig } from '../types/config'; /*
* 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 {
AppConfig,
CliOptions,
TranslationConfig,
ProcessingConfig,
} from '../types/config';
import { deepMerge } from '../utils/fp'; import { deepMerge } from '../utils/fp';
/** /**
@ -13,28 +34,63 @@ const DEFAULT_CONFIG: AppConfig = {
targetLanguage: 'en', targetLanguage: 'en',
maxRetries: 3, maxRetries: 3,
timeout: 30000, timeout: 30000,
concurrency: 3 concurrency: 3,
}, },
processing: { processing: {
defaultExtensions: [ defaultExtensions: [
'ts', 'tsx', 'js', 'jsx', 'go', 'md', 'txt', 'json', 'ts',
'yaml', 'yml', 'toml', 'ini', 'conf', 'config', 'tsx',
'sh', 'bash', 'zsh', 'fish', 'py', 'css', 'scss', 'sass', 'less', 'js',
'html', 'htm', 'xml', 'php', 'rb', 'rs', 'java', 'c', 'h', 'jsx',
'cpp', 'cxx', 'cc', 'hpp', 'cs', 'thrift' 'go',
'md',
'txt',
'json',
'yaml',
'yml',
'toml',
'ini',
'conf',
'config',
'sh',
'bash',
'zsh',
'fish',
'py',
'css',
'scss',
'sass',
'less',
'html',
'htm',
'xml',
'php',
'rb',
'rs',
'java',
'c',
'h',
'cpp',
'cxx',
'cc',
'hpp',
'cs',
'thrift',
], ],
outputFormat: 'console' outputFormat: 'console',
}, },
git: { git: {
ignorePatterns: ['node_modules/**', '.git/**', 'dist/**', 'build/**'], ignorePatterns: ['node_modules/**', '.git/**', 'dist/**', 'build/**'],
includeUntracked: false includeUntracked: false,
} },
}; };
/** /**
* Load configuration from file * Load configuration from file
*/ */
export const loadConfigFromFile = async (configPath: string): Promise<Partial<AppConfig>> => { export const loadConfigFromFile = async (
configPath: string,
): Promise<Partial<AppConfig>> => {
try { try {
const fs = await import('fs/promises'); const fs = await import('fs/promises');
const configContent = await fs.readFile(configPath, 'utf-8'); const configContent = await fs.readFile(configPath, 'utf-8');
@ -48,11 +104,19 @@ export const loadConfigFromFile = async (configPath: string): Promise<Partial<Ap
/** /**
* Create configuration from command line options * Create configuration from command line options
*/ */
export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig> => { export const createConfigFromOptions = (
options: CliOptions,
): Partial<AppConfig> => {
const config: Partial<AppConfig> = {}; const config: Partial<AppConfig> = {};
// translation configuration // translation configuration
if (options.accessKeyId || options.secretAccessKey || options.region || options.sourceLanguage || options.targetLanguage) { if (
options.accessKeyId ||
options.secretAccessKey ||
options.region ||
options.sourceLanguage ||
options.targetLanguage
) {
config.translation = {} as Partial<TranslationConfig>; config.translation = {} as Partial<TranslationConfig>;
if (options.accessKeyId) { if (options.accessKeyId) {
config.translation!.accessKeyId = options.accessKeyId; config.translation!.accessKeyId = options.accessKeyId;
@ -90,10 +154,9 @@ export const createConfigFromOptions = (options: CliOptions): Partial<AppConfig>
* merge configuration * merge configuration
*/ */
export const mergeConfigs = (...configs: Partial<AppConfig>[]): AppConfig => { export const mergeConfigs = (...configs: Partial<AppConfig>[]): AppConfig => {
return configs.reduce( return configs.reduce((merged, config) => deepMerge(merged, config), {
(merged, config) => deepMerge(merged, config), ...DEFAULT_CONFIG,
{ ...DEFAULT_CONFIG } }) as AppConfig;
) as AppConfig;
}; };
/** /**
@ -118,41 +181,65 @@ export const loadConfig = async (options: CliOptions): Promise<AppConfig> => {
/** /**
* verify configuration * verify configuration
*/ */
export const validateConfig = (config: AppConfig): { valid: boolean; errors: string[] } => { export const validateConfig = (
config: AppConfig,
): { valid: boolean; errors: string[] } => {
const errors: string[] = []; const errors: string[] = [];
// Verify Volcano Engine Access Key ID // Verify Volcano Engine Access Key ID
if (!config.translation.accessKeyId) { if (!config.translation.accessKeyId) {
errors.push('火山引擎 Access Key ID 未设置请通过环境变量VOLC_ACCESS_KEY_ID或--access-key-id参数提供'); errors.push(
'火山引擎 Access Key ID 未设置请通过环境变量VOLC_ACCESS_KEY_ID或--access-key-id参数提供',
);
} }
// Verify Volcano Engine Secret Access Key // Verify Volcano Engine Secret Access Key
if (!config.translation.secretAccessKey) { if (!config.translation.secretAccessKey) {
errors.push('火山引擎 Secret Access Key 未设置请通过环境变量VOLC_SECRET_ACCESS_KEY或--secret-access-key参数提供'); errors.push(
'火山引擎 Secret Access Key 未设置请通过环境变量VOLC_SECRET_ACCESS_KEY或--secret-access-key参数提供',
);
} }
// validation area // validation area
const validRegions = ['cn-beijing', 'ap-southeast-1', 'us-east-1']; const validRegions = ['cn-beijing', 'ap-southeast-1', 'us-east-1'];
if (!validRegions.includes(config.translation.region)) { if (!validRegions.includes(config.translation.region)) {
console.warn(`未知的区域: ${config.translation.region},建议使用: ${validRegions.join(', ')}`); console.warn(
`未知的区域: ${config.translation.region},建议使用: ${validRegions.join(
', ',
)}`,
);
} }
// Verify language code // Verify language code
const validLanguages = ['zh', 'en', 'ja', 'ko', 'fr', 'de', 'es', 'pt', 'ru']; const validLanguages = ['zh', 'en', 'ja', 'ko', 'fr', 'de', 'es', 'pt', 'ru'];
if (!validLanguages.includes(config.translation.sourceLanguage)) { if (!validLanguages.includes(config.translation.sourceLanguage)) {
console.warn(`未知的源语言: ${config.translation.sourceLanguage},建议使用: ${validLanguages.join(', ')}`); console.warn(
`未知的源语言: ${
config.translation.sourceLanguage
}建议使用: ${validLanguages.join(', ')}`,
);
} }
if (!validLanguages.includes(config.translation.targetLanguage)) { if (!validLanguages.includes(config.translation.targetLanguage)) {
console.warn(`未知的目标语言: ${config.translation.targetLanguage},建议使用: ${validLanguages.join(', ')}`); console.warn(
`未知的目标语言: ${
config.translation.targetLanguage
}建议使用: ${validLanguages.join(', ')}`,
);
} }
// validation concurrency // validation concurrency
if (config.translation.concurrency < 1 || config.translation.concurrency > 10) { if (
config.translation.concurrency < 1 ||
config.translation.concurrency > 10
) {
errors.push('并发数应该在1-10之间'); errors.push('并发数应该在1-10之间');
} }
// verification timeout // verification timeout
if (config.translation.timeout < 1000 || config.translation.timeout > 300000) { if (
config.translation.timeout < 1000 ||
config.translation.timeout > 300000
) {
errors.push('超时时间应该在1000-300000毫秒之间'); errors.push('超时时间应该在1000-300000毫秒之间');
} }
@ -162,7 +249,10 @@ export const validateConfig = (config: AppConfig): { valid: boolean; errors: str
/** /**
* Print configuration information * Print configuration information
*/ */
export const printConfigInfo = (config: AppConfig, verbose: boolean = false): void => { export const printConfigInfo = (
config: AppConfig,
verbose: boolean = false,
): void => {
console.log('🔧 当前配置:'); console.log('🔧 当前配置:');
console.log(` 区域: ${config.translation.region}`); console.log(` 区域: ${config.translation.region}`);
console.log(` 源语言: ${config.translation.sourceLanguage}`); console.log(` 源语言: ${config.translation.sourceLanguage}`);
@ -172,11 +262,23 @@ export const printConfigInfo = (config: AppConfig, verbose: boolean = false): vo
console.log(` 输出格式: ${config.processing.outputFormat}`); console.log(` 输出格式: ${config.processing.outputFormat}`);
if (verbose) { if (verbose) {
console.log(` Access Key ID: ${config.translation.accessKeyId ? '已设置' : '未设置'}`); console.log(
console.log(` Secret Access Key: ${config.translation.secretAccessKey ? '已设置' : '未设置'}`); ` Access Key ID: ${
config.translation.accessKeyId ? '已设置' : '未设置'
}`,
);
console.log(
` Secret Access Key: ${
config.translation.secretAccessKey ? '已设置' : '未设置'
}`,
);
console.log(` 超时时间: ${config.translation.timeout}ms`); console.log(` 超时时间: ${config.translation.timeout}ms`);
console.log(` 默认扩展名: ${config.processing.defaultExtensions.join(', ')}`); console.log(
` 默认扩展名: ${config.processing.defaultExtensions.join(', ')}`,
);
console.log(` 忽略模式: ${config.git.ignorePatterns.join(', ')}`); console.log(` 忽略模式: ${config.git.ignorePatterns.join(', ')}`);
console.log(` 包含未跟踪文件: ${config.git.includeUntracked ? '是' : '否'}`); console.log(
` 包含未跟踪文件: ${config.git.includeUntracked ? '是' : '否'}`,
);
} }
}; };

View File

@ -1,3 +1,19 @@
/*
* 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.
*/
#!/usr/bin/env node #!/usr/bin/env node
import { createProgram, parseOptions, showHelp } from './cli/command'; import { createProgram, parseOptions, showHelp } from './cli/command';
@ -102,7 +118,9 @@ async function processRepository(
console.log(`\n📝 ${file.path}:`); console.log(`\n📝 ${file.path}:`);
translations.forEach((translation, index) => { translations.forEach((translation, index) => {
console.log( console.log(
` ${index + 1}. "${translation.original}" → "${translation.translated}"`, ` ${index + 1}. "${translation.original}" → "${
translation.translated
}"`,
); );
}); });
} }
@ -116,10 +134,7 @@ async function processRepository(
); );
const operation = { file: file.path, replacements }; const operation = { file: file.path, replacements };
const result = await replaceCommentsInFile( const result = await replaceCommentsInFile(file, operation);
file,
operation,
);
if (!result.success) { if (!result.success) {
throw new Error(result.error || '文件替换失败'); throw new Error(result.error || '文件替换失败');

View File

@ -1,10 +1,26 @@
/*
* 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 { import {
SourceFile, SourceFile,
ChineseComment, ChineseComment,
ParsedComment, ParsedComment,
FileWithComments, FileWithComments,
CommentType, CommentType,
MultiLineContext MultiLineContext,
} from '../types/index'; } from '../types/index';
import { getCommentPatterns } from '../utils/language'; import { getCommentPatterns } from '../utils/language';
import { containsChinese, cleanCommentText } from '../utils/chinese'; import { containsChinese, cleanCommentText } from '../utils/chinese';
@ -74,7 +90,9 @@ const parseSingleLineComments = (
// Multiple protections against infinite loops // Multiple protections against infinite loops
matchCount++; matchCount++;
if (matchCount > maxMatches) { if (matchCount > maxMatches) {
console.warn(`⚠️ 单行匹配次数过多,中断处理: ${line.substring(0, 50)}...`); console.warn(
`⚠️ 单行匹配次数过多,中断处理: ${line.substring(0, 50)}...`,
);
break; break;
} }
@ -246,7 +264,6 @@ const parseMultiLineComments = (
const commentContent = line.substring(0, endMatch.index!); const commentContent = line.substring(0, endMatch.index!);
commentLines.push(commentContent); commentLines.push(commentContent);
comments.push({ comments.push({
content: commentLines.join('\n'), content: commentLines.join('\n'),
startLine: commentStart!.line, startLine: commentStart!.line,
@ -302,7 +319,10 @@ export const filterChineseComments = (
for (const comment of comments) { for (const comment of comments) {
if (comment.type === 'multi-line' && comment.content.includes('\n')) { if (comment.type === 'multi-line' && comment.content.includes('\n')) {
// Multi-line comments: line-by-line processing // Multi-line comments: line-by-line processing
const multiLineResults = processMultiLineCommentForChinese(comment, language); const multiLineResults = processMultiLineCommentForChinese(
comment,
language,
);
result.push(...multiLineResults); result.push(...multiLineResults);
} else if (containsChinese(comment.content)) { } else if (containsChinese(comment.content)) {
// Single-line comments or single-line multi-line comments // Single-line comments or single-line multi-line comments
@ -350,8 +370,8 @@ const processMultiLineCommentForChinese = (
isPartOfMultiLine: true, isPartOfMultiLine: true,
originalComment: comment, originalComment: comment,
lineIndexInComment: lineIndex, lineIndexInComment: lineIndex,
totalLinesInComment: lines.length totalLinesInComment: lines.length,
} },
}; };
result.push(lineComment); result.push(lineComment);
@ -393,7 +413,9 @@ export const detectChineseInFile = (file: SourceFile): ChineseComment[] => {
/** /**
* Batch detection of Chinese comments in multiple files * Batch detection of Chinese comments in multiple files
*/ */
export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] => { export const detectChineseInFiles = (
files: SourceFile[],
): FileWithComments[] => {
const results: FileWithComments[] = []; const results: FileWithComments[] = [];
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
@ -428,7 +450,9 @@ export const detectChineseInFiles = (files: SourceFile[]): FileWithComments[] =>
/** /**
* Get annotation statistics * Get annotation statistics
*/ */
export const getCommentStats = (files: SourceFile[]): { export const getCommentStats = (
files: SourceFile[],
): {
totalFiles: number; totalFiles: number;
filesWithComments: number; filesWithComments: number;
totalComments: number; totalComments: number;
@ -441,12 +465,15 @@ export const getCommentStats = (files: SourceFile[]): {
const commentsByType: Record<CommentType, number> = { const commentsByType: Record<CommentType, number> = {
'single-line': 0, 'single-line': 0,
'multi-line': 0, 'multi-line': 0,
'documentation': 0 documentation: 0,
}; };
files.forEach(file => { files.forEach(file => {
const allComments = parseComments(file); const allComments = parseComments(file);
const chineseCommentsInFile = filterChineseComments(allComments, file.language); const chineseCommentsInFile = filterChineseComments(
allComments,
file.language,
);
if (chineseCommentsInFile.length > 0) { if (chineseCommentsInFile.length > 0) {
filesWithComments++; filesWithComments++;
@ -465,6 +492,6 @@ export const getCommentStats = (files: SourceFile[]): {
filesWithComments, filesWithComments,
totalComments, totalComments,
chineseComments, chineseComments,
commentsByType commentsByType,
}; };
}; };

View File

@ -1,13 +1,35 @@
/*
* 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 { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { SourceFile, FileScanConfig, Result } from '../types/index'; import { SourceFile, FileScanConfig, Result } from '../types/index';
import { detectLanguage, filterFilesByExtensions, isTextFile } from '../utils/language'; import {
detectLanguage,
filterFilesByExtensions,
isTextFile,
} from '../utils/language';
import { getGitTrackedFiles, getAllGitFiles } from '../utils/git'; import { getGitTrackedFiles, getAllGitFiles } from '../utils/git';
import { tryCatch } from '../utils/fp'; import { tryCatch } from '../utils/fp';
/** /**
* Read the file contents and create a SourceFile object * Read the file contents and create a SourceFile object
*/ */
export const readSourceFile = async (filePath: string): Promise<Result<SourceFile>> => { export const readSourceFile = async (
filePath: string,
): Promise<Result<SourceFile>> => {
return tryCatch(async () => { return tryCatch(async () => {
const content = await fs.readFile(filePath, 'utf-8'); const content = await fs.readFile(filePath, 'utf-8');
const language = detectLanguage(filePath); const language = detectLanguage(filePath);
@ -15,7 +37,7 @@ export const readSourceFile = async (filePath: string): Promise<Result<SourceFil
return { return {
path: filePath, path: filePath,
content, content,
language language,
}; };
}); });
}; };
@ -23,14 +45,17 @@ export const readSourceFile = async (filePath: string): Promise<Result<SourceFil
/** /**
* Batch reading of source files * Batch reading of source files
*/ */
export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]> => { export const readSourceFiles = async (
filePaths: string[],
): Promise<SourceFile[]> => {
const results = await Promise.allSettled( const results = await Promise.allSettled(
filePaths.map(path => readSourceFile(path)) filePaths.map(path => readSourceFile(path)),
); );
return results return results
.filter((result): result is PromiseFulfilledResult<Result<SourceFile>> => .filter(
result.status === 'fulfilled' && result.value.success (result): result is PromiseFulfilledResult<Result<SourceFile>> =>
result.status === 'fulfilled' && result.value.success,
) )
.map(result => (result.value as { success: true; data: SourceFile }).data); .map(result => (result.value as { success: true; data: SourceFile }).data);
}; };
@ -38,7 +63,9 @@ export const readSourceFiles = async (filePaths: string[]): Promise<SourceFile[]
/** /**
* Get the source code file in the Git repository * Get the source code file in the Git repository
*/ */
export const getSourceFiles = async (config: FileScanConfig): Promise<Result<string[]>> => { export const getSourceFiles = async (
config: FileScanConfig,
): Promise<Result<string[]>> => {
const { root, extensions, includeUntracked } = config; const { root, extensions, includeUntracked } = config;
return tryCatch(async () => { return tryCatch(async () => {
@ -66,7 +93,9 @@ export const getSourceFiles = async (config: FileScanConfig): Promise<Result<str
/** /**
* Scan and read all source code files * Scan and read all source code files
*/ */
export const scanSourceFiles = async (config: FileScanConfig): Promise<Result<SourceFile[]>> => { export const scanSourceFiles = async (
config: FileScanConfig,
): Promise<Result<SourceFile[]>> => {
return tryCatch(async () => { return tryCatch(async () => {
const filesResult = await getSourceFiles(config); const filesResult = await getSourceFiles(config);
@ -94,28 +123,32 @@ export const isFileAccessible = async (filePath: string): Promise<boolean> => {
/** /**
* Get file statistics * Get file statistics
*/ */
export const getFileStats = async (filePaths: string[]): Promise<{ export const getFileStats = async (
filePaths: string[],
): Promise<{
total: number; total: number;
accessible: number; accessible: number;
textFiles: number; textFiles: number;
supportedFiles: number; supportedFiles: number;
}> => { }> => {
const accessibilityResults = await Promise.allSettled( const accessibilityResults = await Promise.allSettled(
filePaths.map(isFileAccessible) filePaths.map(isFileAccessible),
); );
const accessible = accessibilityResults.filter( const accessible = accessibilityResults.filter(
(result): result is PromiseFulfilledResult<boolean> => (result): result is PromiseFulfilledResult<boolean> =>
result.status === 'fulfilled' && result.value result.status === 'fulfilled' && result.value,
).length; ).length;
const textFiles = filePaths.filter(isTextFile).length; const textFiles = filePaths.filter(isTextFile).length;
const supportedFiles = filePaths.filter(path => detectLanguage(path) !== 'other').length; const supportedFiles = filePaths.filter(
path => detectLanguage(path) !== 'other',
).length;
return { return {
total: filePaths.length, total: filePaths.length,
accessible, accessible,
textFiles, textFiles,
supportedFiles supportedFiles,
}; };
}; };

View File

@ -1,3 +1,19 @@
/*
* 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 { import {
ProcessingReport, ProcessingReport,
ProcessingStats, ProcessingStats,
@ -203,13 +219,17 @@ export const generateMarkdownReport = (report: ProcessingReport): string => {
? '⏭️' ? '⏭️'
: '🔄'; : '🔄';
markdown += `| ${detail.file} | ${status} | ${detail.commentCount} | ${duration} | ${detail.errorMessage || '-'} |\n`; markdown += `| ${detail.file} | ${status} | ${
detail.commentCount
} | ${duration} | ${detail.errorMessage || '-'} |\n`;
}); });
if (stats.errors.length > 0) { if (stats.errors.length > 0) {
markdown += '\n## ❌ 错误详情\n\n'; markdown += '\n## ❌ 错误详情\n\n';
stats.errors.forEach((error, index) => { stats.errors.forEach((error, index) => {
markdown += `${index + 1}. **${error.file}**\n \`\`\`\n ${error.error}\n \`\`\`\n\n`; markdown += `${index + 1}. **${error.file}**\n \`\`\`\n ${
error.error
}\n \`\`\`\n\n`;
}); });
} }
@ -276,7 +296,9 @@ export class ProgressDisplay {
const speed = current / elapsed; const speed = current / elapsed;
const eta = speed > 0 ? (this.total - current) / speed : 0; const eta = speed > 0 ? (this.total - current) / speed : 0;
let line = `进度: ${current}/${this.total} (${percentage}%) | 耗时: ${elapsed.toFixed(1)}s`; let line = `进度: ${current}/${
this.total
} (${percentage}%) | 耗时: ${elapsed.toFixed(1)}s`;
if (eta > 0) { if (eta > 0) {
line += ` | 预计剩余: ${eta.toFixed(1)}s`; line += ` | 预计剩余: ${eta.toFixed(1)}s`;

View File

@ -1,3 +1,19 @@
/*
* 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 { import {
TranslationResult, TranslationResult,
TranslationContext, TranslationContext,
@ -7,7 +23,10 @@ import {
import { TranslationConfig } from '../types/config'; import { TranslationConfig } from '../types/config';
import { retry, chunk } from '../utils/fp'; import { retry, chunk } from '../utils/fp';
import { isValidTranslation } from '../utils/chinese'; import { isValidTranslation } from '../utils/chinese';
import { translate as volcTranslate, TranslateConfig as VolcTranslateConfig } from '../volc/translate'; import {
translate as volcTranslate,
TranslateConfig as VolcTranslateConfig,
} from '../volc/translate';
/** /**
* Translation services * Translation services
@ -101,7 +120,9 @@ export class TranslationService {
return result; return result;
} catch (error) { } catch (error) {
throw new TranslationError( throw new TranslationError(
`Translation failed: ${error instanceof Error ? error.message : String(error)}`, `Translation failed: ${
error instanceof Error ? error.message : String(error)
}`,
comment, comment,
); );
} }
@ -163,7 +184,10 @@ export class TranslationService {
const result: TranslationResult = { const result: TranslationResult = {
original: item.comment.content, original: item.comment.content,
translated, translated,
confidence: this.calculateConfidence(translated, item.comment.content), confidence: this.calculateConfidence(
translated,
item.comment.content,
),
}; };
// cache results // cache results
@ -190,7 +214,11 @@ export class TranslationService {
}; };
}); });
console.warn(`批量翻译失败: ${error instanceof Error ? error.message : String(error)}`); console.warn(
`批量翻译失败: ${
error instanceof Error ? error.message : String(error)
}`,
);
} }
} }

View File

@ -1,3 +1,19 @@
/*
* 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.
*/
/** /**
* Source file language type * Source file language type
*/ */
@ -183,10 +199,7 @@ export type Result<T, E = Error> =
* translation error * translation error
*/ */
export class TranslationError extends Error { export class TranslationError extends Error {
constructor( constructor(message: string, public originalComment: string) {
message: string,
public originalComment: string,
) {
super(message); super(message);
this.name = 'TranslationError'; this.name = 'TranslationError';
} }

View File

@ -1,8 +1,25 @@
/*
* 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.
*/
/** /**
* Unicode Range Regular Expressions for Chinese Characters * Unicode Range Regular Expressions for Chinese Characters
*/ */
const CHINESE_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/; const CHINESE_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/;
const CHINESE_EXTRACT_REGEX = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3000-\u303f\uff00-\uffef]+/g; const CHINESE_EXTRACT_REGEX =
/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3000-\u303f\uff00-\uffef]+/g;
/** /**
* Detect whether the text contains Chinese characters * Detect whether the text contains Chinese characters
@ -31,7 +48,10 @@ export const countChineseCharacters = (text: string): number => {
/** /**
* Detect whether the text is mainly composed of Chinese * Detect whether the text is mainly composed of Chinese
*/ */
export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boolean => { export const isPrimarilyChinese = (
text: string,
threshold: number = 0.5,
): boolean => {
const totalLength = text.length; const totalLength = text.length;
if (totalLength === 0) return false; if (totalLength === 0) return false;
@ -45,7 +65,7 @@ export const isPrimarilyChinese = (text: string, threshold: number = 0.5): boole
export const cleanCommentText = ( export const cleanCommentText = (
text: string, text: string,
commentType: 'single-line' | 'multi-line', commentType: 'single-line' | 'multi-line',
language?: string language?: string,
): string => { ): string => {
let cleaned = text; let cleaned = text;
@ -100,7 +120,10 @@ export const cleanCommentText = (
/** /**
* Verify whether the translation result is valid. * Verify whether the translation result is valid.
*/ */
export const isValidTranslation = (original: string, translated: string): boolean => { export const isValidTranslation = (
original: string,
translated: string,
): boolean => {
// basic verification // basic verification
if (!translated || translated.trim().length === 0) { if (!translated || translated.trim().length === 0) {
return false; return false;

View File

@ -1,3 +1,19 @@
/*
* 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 { SourceFileLanguage, CommentPattern } from '../types/index'; import { SourceFileLanguage, CommentPattern } from '../types/index';
/** /**
@ -7,44 +23,44 @@ export const detectLanguage = (filePath: string): SourceFileLanguage => {
const ext = filePath.toLowerCase().split('.').pop(); const ext = filePath.toLowerCase().split('.').pop();
const languageMap: Record<string, SourceFileLanguage> = { const languageMap: Record<string, SourceFileLanguage> = {
'ts': 'typescript', ts: 'typescript',
'tsx': 'typescript', tsx: 'typescript',
'js': 'javascript', js: 'javascript',
'jsx': 'javascript', jsx: 'javascript',
'go': 'go', go: 'go',
'md': 'markdown', md: 'markdown',
'txt': 'text', txt: 'text',
'json': 'json', json: 'json',
'yaml': 'yaml', yaml: 'yaml',
'yml': 'yaml', yml: 'yaml',
'toml': 'toml', toml: 'toml',
'ini': 'ini', ini: 'ini',
'conf': 'ini', conf: 'ini',
'config': 'ini', config: 'ini',
'sh': 'shell', sh: 'shell',
'bash': 'shell', bash: 'shell',
'zsh': 'shell', zsh: 'shell',
'fish': 'shell', fish: 'shell',
'py': 'python', py: 'python',
'css': 'css', css: 'css',
'scss': 'css', scss: 'css',
'sass': 'css', sass: 'css',
'less': 'css', less: 'css',
'html': 'html', html: 'html',
'htm': 'html', htm: 'html',
'xml': 'xml', xml: 'xml',
'php': 'php', php: 'php',
'rb': 'ruby', rb: 'ruby',
'rs': 'rust', rs: 'rust',
'java': 'java', java: 'java',
'c': 'c', c: 'c',
'h': 'c', h: 'c',
'cpp': 'cpp', cpp: 'cpp',
'cxx': 'cpp', cxx: 'cpp',
'cc': 'cpp', cc: 'cpp',
'hpp': 'cpp', hpp: 'cpp',
'cs': 'csharp', cs: 'csharp',
'thrift': 'thrift' thrift: 'thrift',
}; };
return languageMap[ext || ''] || 'other'; return languageMap[ext || ''] || 'other';
@ -55,19 +71,52 @@ export const detectLanguage = (filePath: string): SourceFileLanguage => {
*/ */
export const filterFilesByExtensions = ( export const filterFilesByExtensions = (
files: string[], files: string[],
extensions: string[] extensions: string[],
): string[] => { ): string[] => {
if (extensions.length === 0) { if (extensions.length === 0) {
// Default supported text file extensions // Default supported text file extensions
const defaultExtensions = [ const defaultExtensions = [
'.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json', '.ts',
'.yaml', '.yml', '.toml', '.ini', '.conf', '.config', '.tsx',
'.sh', '.bash', '.zsh', '.fish', '.py', '.css', '.scss', '.sass', '.less', '.js',
'.html', '.htm', '.xml', '.php', '.rb', '.rs', '.java', '.c', '.h', '.jsx',
'.cpp', '.cxx', '.cc', '.hpp', '.cs', '.thrift' '.go',
'.md',
'.txt',
'.json',
'.yaml',
'.yml',
'.toml',
'.ini',
'.conf',
'.config',
'.sh',
'.bash',
'.zsh',
'.fish',
'.py',
'.css',
'.scss',
'.sass',
'.less',
'.html',
'.htm',
'.xml',
'.php',
'.rb',
'.rs',
'.java',
'.c',
'.h',
'.cpp',
'.cxx',
'.cc',
'.hpp',
'.cs',
'.thrift',
]; ];
return files.filter(file => return files.filter(file =>
defaultExtensions.some(ext => file.toLowerCase().endsWith(ext)) defaultExtensions.some(ext => file.toLowerCase().endsWith(ext)),
); );
} }
@ -85,123 +134,125 @@ export const filterFilesByExtensions = (
/** /**
* Obtain comment modes for different programming languages * Obtain comment modes for different programming languages
*/ */
export const getCommentPatterns = (language: SourceFileLanguage): CommentPattern | null => { export const getCommentPatterns = (
language: SourceFileLanguage,
): CommentPattern | null => {
const commentPatterns: Record<SourceFileLanguage, CommentPattern> = { const commentPatterns: Record<SourceFileLanguage, CommentPattern> = {
typescript: { typescript: {
single: /(?:^|[^:])\s*\/\/(.*)$/gm, single: /(?:^|[^:])\s*\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
javascript: { javascript: {
single: /(?:^|[^:])\s*\/\/(.*)$/gm, single: /(?:^|[^:])\s*\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
go: { go: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
markdown: { markdown: {
single: /<!--(.*)-->/g, single: /<!--(.*)-->/g,
multiStart: /<!--/g, multiStart: /<!--/g,
multiEnd: /-->/g multiEnd: /-->/g,
}, },
text: { text: {
single: /^(.*)$/gm, // Every line of a text file can be a comment single: /^(.*)$/gm, // Every line of a text file can be a comment
multiStart: /^/g, multiStart: /^/g,
multiEnd: /$/g multiEnd: /$/g,
}, },
json: { json: {
single: /\/\/(.*)$/gm, // JSON usually doesn't support comments, but some tools do single: /\/\/(.*)$/gm, // JSON usually doesn't support comments, but some tools do
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
yaml: { yaml: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // YAML does not support multi-line comments multiStart: /^$/g, // YAML does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g,
}, },
toml: { toml: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // TOML does not support multi-line comments multiStart: /^$/g, // TOML does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g,
}, },
ini: { ini: {
single: /[;#](.*)$/gm, // INI file support; and #as comments single: /[;#](.*)$/gm, // INI file support; and #as comments
multiStart: /^$/g, // INI does not support multi-line comments multiStart: /^$/g, // INI does not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g,
}, },
shell: { shell: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /^$/g, // Shell scripts do not support multi-line comments multiStart: /^$/g, // Shell scripts do not support multi-line comments
multiEnd: /^$/g multiEnd: /^$/g,
}, },
python: { python: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /"""[\s\S]*?$/gm, // Python docstring multiStart: /"""[\s\S]*?$/gm, // Python docstring
multiEnd: /[\s\S]*?"""/gm multiEnd: /[\s\S]*?"""/gm,
}, },
css: { css: {
single: /^$/g, // CSS does not support single-line comments single: /^$/g, // CSS does not support single-line comments
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
html: { html: {
single: /^$/g, // HTML does not support single-line comments single: /^$/g, // HTML does not support single-line comments
multiStart: /<!--/g, multiStart: /<!--/g,
multiEnd: /-->/g multiEnd: /-->/g,
}, },
xml: { xml: {
single: /^$/g, // XML does not support single-line comments single: /^$/g, // XML does not support single-line comments
multiStart: /<!--/g, multiStart: /<!--/g,
multiEnd: /-->/g multiEnd: /-->/g,
}, },
php: { php: {
single: /(?:\/\/|#)(.*)$/gm, // PHP supports//and #as single-line comments single: /(?:\/\/|#)(.*)$/gm, // PHP supports//and #as single-line comments
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
ruby: { ruby: {
single: /#(.*)$/gm, single: /#(.*)$/gm,
multiStart: /=begin/g, multiStart: /=begin/g,
multiEnd: /=end/g multiEnd: /=end/g,
}, },
rust: { rust: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
java: { java: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
c: { c: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
cpp: { cpp: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
csharp: { csharp: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
thrift: { thrift: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
}, },
other: { other: {
single: /\/\/(.*)$/gm, single: /\/\/(.*)$/gm,
multiStart: /\/\*/g, multiStart: /\/\*/g,
multiEnd: /\*\//g multiEnd: /\*\//g,
} },
}; };
return commentPatterns[language] || null; return commentPatterns[language] || null;
@ -220,14 +271,47 @@ export const isSupportedFile = (filePath: string): boolean => {
*/ */
export const isTextFile = (filePath: string): boolean => { export const isTextFile = (filePath: string): boolean => {
const textExtensions = [ const textExtensions = [
'.ts', '.tsx', '.js', '.jsx', '.go', '.md', '.txt', '.json', '.ts',
'.css', '.scss', '.sass', '.less', '.html', '.htm', '.xml', '.tsx',
'.yaml', '.yml', '.toml', '.ini', '.conf', '.config', '.js',
'.sh', '.bash', '.zsh', '.fish', '.py', '.java', '.c', '.cpp', '.h', '.hpp', '.cs', '.jsx',
'.php', '.rb', '.rs', '.kt', '.swift', '.dart', '.scala', '.thrift' '.go',
'.md',
'.txt',
'.json',
'.css',
'.scss',
'.sass',
'.less',
'.html',
'.htm',
'.xml',
'.yaml',
'.yml',
'.toml',
'.ini',
'.conf',
'.config',
'.sh',
'.bash',
'.zsh',
'.fish',
'.py',
'.java',
'.c',
'.cpp',
'.h',
'.hpp',
'.cs',
'.php',
'.rb',
'.rs',
'.kt',
'.swift',
'.dart',
'.scala',
'.thrift',
]; ];
return textExtensions.some(ext => return textExtensions.some(ext => filePath.toLowerCase().endsWith(ext));
filePath.toLowerCase().endsWith(ext)
);
}; };

View File

@ -1,3 +1,19 @@
/*
* 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.
*/
/* /*
Copyright (year) Beijing Volcano Engine Technology Ltd. Copyright (year) Beijing Volcano Engine Technology Ltd.
@ -304,7 +320,10 @@ function queryParamsToString(params: QueryParams): string {
return undefined; return undefined;
} }
if (Array.isArray(val)) { if (Array.isArray(val)) {
return `${escapedKey}=${val.map(uriEscape).sort().join(`&${escapedKey}=`)}`; return `${escapedKey}=${val
.map(uriEscape)
.sort()
.join(`&${escapedKey}=`)}`;
} }
return `${escapedKey}=${uriEscape(val)}`; return `${escapedKey}=${uriEscape(val)}`;
}) })

View File

@ -19,3 +19,4 @@
"@types/node": "^18.11.9" "@types/node": "^18.11.9"
} }
} }

View File

@ -16,3 +16,4 @@
"typescript": "~5.8.2" "typescript": "~5.8.2"
} }
} }

View File

@ -65,13 +65,11 @@
* "This monorepo consumes packages from an Artifactory private NPM registry." * "This monorepo consumes packages from an Artifactory private NPM registry."
*/ */
// "introduction": "", // "introduction": "",
/** /**
* Overrides the message that normally says: * Overrides the message that normally says:
* "Please contact the repository maintainers for help with setting up an Artifactory user account." * "Please contact the repository maintainers for help with setting up an Artifactory user account."
*/ */
// "obtainAnAccount": "", // "obtainAnAccount": "",
/** /**
* Overrides the message that normally says: * Overrides the message that normally says:
* "Please open this URL in your web browser:" * "Please open this URL in your web browser:"
@ -79,26 +77,22 @@
* The "artifactoryWebsiteUrl" string is printed after this message. * The "artifactoryWebsiteUrl" string is printed after this message.
*/ */
// "visitWebsite": "", // "visitWebsite": "",
/** /**
* Overrides the message that normally says: * Overrides the message that normally says:
* "Your user name appears in the upper-right corner of the JFrog website." * "Your user name appears in the upper-right corner of the JFrog website."
*/ */
// "locateUserName": "", // "locateUserName": "",
/** /**
* Overrides the message that normally says: * Overrides the message that normally says:
* "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key' * "Click 'Edit Profile' on the JFrog website. Click the 'Generate API Key'
* button if you haven't already done so previously." * button if you haven't already done so previously."
*/ */
// "locateApiKey": "" // "locateApiKey": ""
/** /**
* Overrides the message that normally prompts: * Overrides the message that normally prompts:
* "What is your Artifactory user name?" * "What is your Artifactory user name?"
*/ */
// "userNamePrompt": "" // "userNamePrompt": ""
/** /**
* Overrides the message that normally prompts: * Overrides the message that normally prompts:
* "What is your Artifactory API key?" * "What is your Artifactory API key?"

View File

@ -40,24 +40,20 @@
* (Required) The name of the the Azure storage account to use for build cache. * (Required) The name of the the Azure storage account to use for build cache.
*/ */
// "storageAccountName": "example", // "storageAccountName": "example",
/** /**
* (Required) The name of the container in the Azure storage account to use for build cache. * (Required) The name of the container in the Azure storage account to use for build cache.
*/ */
// "storageContainerName": "my-container", // "storageContainerName": "my-container",
/** /**
* The Azure environment the storage account exists in. Defaults to AzurePublicCloud. * The Azure environment the storage account exists in. Defaults to AzurePublicCloud.
* *
* Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment" * Possible values: "AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment"
*/ */
// "azureEnvironment": "AzurePublicCloud", // "azureEnvironment": "AzurePublicCloud",
/** /**
* An optional prefix for cache item blob names. * An optional prefix for cache item blob names.
*/ */
// "blobPrefix": "my-prefix", // "blobPrefix": "my-prefix",
/** /**
* If set to true, allow writing to the cache. Defaults to false. * If set to true, allow writing to the cache. Defaults to false.
*/ */
@ -73,25 +69,21 @@
* Example: "my-bucket" * Example: "my-bucket"
*/ */
// "s3Bucket": "my-bucket", // "s3Bucket": "my-bucket",
/** /**
* (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache. * (Required unless s3Bucket is specified) The Amazon S3 endpoint of the bucket to use for build cache.
* This should not include any path; use the s3Prefix to set the path. * This should not include any path; use the s3Prefix to set the path.
* Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000" * Examples: "my-bucket.s3.us-east-2.amazonaws.com" or "http://localhost:9000"
*/ */
// "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com", // "s3Endpoint": "https://my-bucket.s3.us-east-2.amazonaws.com",
/** /**
* (Required) The Amazon S3 region of the bucket to use for build cache. * (Required) The Amazon S3 region of the bucket to use for build cache.
* Example: "us-east-1" * Example: "us-east-1"
*/ */
// "s3Region": "us-east-1", // "s3Region": "us-east-1",
/** /**
* An optional prefix ("folder") for cache items. It should not start with "/". * An optional prefix ("folder") for cache items. It should not start with "/".
*/ */
// "s3Prefix": "my-prefix", // "s3Prefix": "my-prefix",
/** /**
* If set to true, allow writing to the cache. Defaults to false. * If set to true, allow writing to the cache. Defaults to false.
*/ */

View File

@ -2,7 +2,7 @@
* This configuration file manages Rush's cobuild feature. * This configuration file manages Rush's cobuild feature.
* More documentation is available on the Rush website: https://rushjs.io * More documentation is available on the Rush website: https://rushjs.io
*/ */
{ {
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json", "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/cobuild.schema.json",
/** /**

View File

@ -17,9 +17,7 @@
* If the main project should include other unrelated Rush projects, add it to the "projectSettings" section, * If the main project should include other unrelated Rush projects, add it to the "projectSettings" section,
* and then specify those projects in the "additionalProjectsToInclude" list. * and then specify those projects in the "additionalProjectsToInclude" list.
*/ */
"deploymentProjectNames": [ "deploymentProjectNames": ["@coze-studio/app"],
"@coze-studio/app"
],
// solve deploy error: ERROR: Symlink targets not under folder // solve deploy error: ERROR: Symlink targets not under folder
"dependencySettings": [], "dependencySettings": [],

View File

@ -28,10 +28,7 @@
}, },
"globalPeerDependencyRules": {}, "globalPeerDependencyRules": {},
"globalPackageExtensions": {}, "globalPackageExtensions": {},
"globalNeverBuiltDependencies": [ "globalNeverBuiltDependencies": ["canvas", "better-sqlite3"],
"canvas",
"better-sqlite3"
],
"globalAllowedDeprecatedVersions": {}, "globalAllowedDeprecatedVersions": {},
"globalPatchedDependencies": {}, "globalPatchedDependencies": {},
"unsupportedPackageJsonSettings": {} "unsupportedPackageJsonSettings": {}