feat: manually mirror opencoze's code from bytedance

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

View File

@@ -0,0 +1,35 @@
// Documentation for this file: https://prettier.io/docs/en/options.html
module.exports = {
// We use a larger print width because Prettier's word-wrapping seems to be tuned
// for plain JavaScript without type annotations
printWidth: 80,
// Use .gitattributes to manage newlines
endOfLine: 'auto',
semi: true,
plugins: [require.resolve('prettier-plugin-packagejson')],
tabWidth: 2,
useTabs: false,
singleQuote: true,
trailingComma: 'all',
bracketSpacing: true,
jsxBracketSameLine: false,
arrowParens: 'avoid',
overrides: [
{
files: '.prettierrc',
options: { parser: 'json', trailingComma: 'none' },
},
{
files: '.babelrc',
options: { parser: 'json', trailingComma: 'none' },
},
{
files: '*.json',
options: { trailingComma: 'none' },
},
],
};

View File

@@ -0,0 +1,275 @@
# @coze-arch/eslint-config
A comprehensive ESLint configuration package for the Coze architecture ecosystem, providing standardized linting rules for JavaScript, TypeScript, React, and Node.js projects.
## Features
- 🔧 **Multi-environment support**: Separate configurations for web, node, and base environments
- 🎯 **TypeScript-first**: Full TypeScript support with advanced rules
- ⚛️ **React optimized**: Built-in React hooks and XSS protection rules
- 🔒 **Security focused**: Integrated security plugins and best practices
- 🎨 **Prettier integration**: Seamless code formatting with Prettier
- 📦 **Workspace-aware**: Import resolution for monorepo environments
- 🚫 **Dependency control**: Built-in rules to prevent disallowed dependencies
- 🧪 **Test-friendly**: Special configurations for test files
## Get Started
### Installation
```bash
# Install the package
pnpm add @coze-arch/eslint-config --save-dev
# Update workspace dependencies
rush update
```
### Basic Usage
Create an `eslint.config.js` file in your project root:
```javascript
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web', // or 'node' or 'base'
});
```
## API Reference
### `defineConfig(config)`
The main function to create ESLint configurations.
#### Parameters
- `config` (EnhanceESLintConfig): Configuration object
#### EnhanceESLintConfig Interface
```typescript
interface EnhanceESLintConfig extends ESLintConfig {
/**
* Project root directory
*/
packageRoot: string;
/**
* Configuration preset mode
*/
preset: 'web' | 'node' | 'base';
/**
* Additional configuration overrides
*/
overrides?: ESLintConfig[];
/**
* Custom ignore patterns
*/
ignores?: string[];
/**
* Custom rules
*/
rules?: Linter.RulesRecord;
/**
* ESLint settings
*/
settings?: any;
}
```
### Configuration Presets
#### Web Preset (`preset: 'web'`)
Optimized for React web applications:
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
});
```
**Includes:**
- React and React Hooks rules
- XSS protection with `eslint-plugin-risxss`
- Browser globals
- Restricted imports for architecture compliance
#### Node Preset (`preset: 'node'`)
Optimized for Node.js applications:
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'node',
});
```
**Includes:**
- Node.js globals and environment
- Security plugin for Node.js
- Server-side specific rules
#### Base Preset (`preset: 'base'`)
Minimal configuration for libraries:
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'base',
});
```
**Includes:**
- Core JavaScript and TypeScript rules
- Import resolution
- Common code quality rules
### Custom Configuration
#### Adding Custom Rules
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
rules: {
'no-console': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
},
});
```
#### Adding Overrides
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
overrides: [
{
files: ['**/*.test.ts', '**/*.spec.ts'],
rules: {
'max-lines': 'off',
},
},
],
});
```
#### Custom Ignores
```javascript
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
ignores: [
'custom-build/**',
'temp/**',
],
});
```
### CLI Scripts
The package provides convenient CLI scripts:
#### ESLint Script
```bash
# Using the built-in eslint script
npx eslint ./src
# Using the reslint alias
npx reslint ./src
```
#### Prettier Script
```bash
# Format code with Prettier
npx prettier --write ./src
```
## Development
### Project Structure
```
config/eslint-config/
├── src/
│ ├── index.js # Main entry point
│ └── define-config.ts # Configuration function
├── rules/ # Rule configurations
│ ├── common-standard.js # Common rules
│ ├── import.js # Import rules
│ ├── js-standard.js # JavaScript rules
│ ├── ts-standard.js # TypeScript rules
│ └── test-standard.js # Test file rules
├── scripts/
│ ├── reslint.sh # ESLint wrapper script
│ └── rprettier.sh # Prettier wrapper script
├── eslint.config.base.js # Base configuration
├── eslint.config.web.js # Web configuration
├── eslint.config.node.js # Node.js configuration
└── package.json
```
### Building
```bash
# Build the package
rush build --to @coze-arch/eslint-config
# Run linting
rush lint --to @coze-arch/eslint-config
```
### Testing
```bash
# Run tests
rush test --to @coze-arch/eslint-config
```
## Dependencies
### Main Dependencies
- **@typescript-eslint/eslint-plugin**: TypeScript-specific linting rules
- **@typescript-eslint/parser**: TypeScript parser for ESLint
- **eslint-plugin-react**: React-specific linting rules
- **eslint-plugin-react-hooks**: Rules for React Hooks
- **eslint-plugin-prettier**: Prettier integration
- **eslint-plugin-import**: Import/export syntax validation
- **eslint-plugin-security**: Security-focused linting rules
- **eslint-plugin-risxss**: XSS prevention for React
### Internal Dependencies
- **@coze-arch/eslint-plugin**: Custom rules for Coze architecture
- **@coze-arch/ts-config**: TypeScript configuration
### Build Tools
- **sucrase**: Fast TypeScript transpilation
- **prettier**: Code formatting
- **eslint**: Core linting engine
## License
Internal package for Coze architecture ecosystem.
---
For more information about ESLint configuration, visit the [ESLint documentation](https://eslint.org/docs/user-guide/configuring/).

View File

@@ -0,0 +1,8 @@
const { FlatCompat } = require('@eslint/eslintrc');
const compat = new FlatCompat({
baseDirectory: __dirname,
resolvePluginsRelativeTo: __dirname,
});
module.exports = { compat };

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,10 @@
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
require('eslint-plugin-prettier/recommended'),
...require('./rules/common-standard'),
...require('./rules/import'),
...require('./rules/js-standard'),
...require('./rules/ts-standard'),
...require('./rules/test-standard'),
];

View File

@@ -0,0 +1,13 @@
const path = require('path');
const { main } = require('./package.json');
const { defineConfig } = require(path.resolve(__dirname, main));
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'node',
rules: {
'@typescript-eslint/no-require-imports': 'off',
},
});

View File

@@ -0,0 +1,17 @@
const globals = require('globals');
const securityPlugin = require('eslint-plugin-security');
/** @type {(import('eslint').Linter.Config[])} */
module.exports = [
...require('./eslint.config.base.js'),
securityPlugin.configs.recommended,
{
languageOptions: {
globals: {
...globals.node,
NodeJS: true,
},
},
rules: {},
},
];

View File

@@ -0,0 +1,66 @@
const globals = require('globals');
/** @type {(import('eslint').Linter.Config[])} */
module.exports = [
...require('./eslint.config.base.js'),
{
plugins: {
// TODO: 需要根据不同类型配置plugin需要阅读源码确认是否影响性能
'react-hooks': require('eslint-plugin-react-hooks'),
react: require('eslint-plugin-react'),
risxss: require('eslint-plugin-risxss'),
},
languageOptions: {
globals: {
...globals.node,
...globals.browser,
JSX: true,
React: true,
},
},
settings: {
// for eslint-plugin-react
react: {
pragma: 'React',
version: '18.2',
},
},
rules: {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'risxss/catch-potential-xss-react': 'error',
'no-restricted-imports': [
'error',
{
patterns: [
{
group: ['@douyinfe/semi-ui', '@douyinfe/semi-ui/*'],
message:
'请勿直接使用@douyinfe/semi-ui, 请使用 @coze-arch/bot-semi',
},
{
group: ['@douyinfe/semi-ui/lib/es/*'],
message:
'如果你的代码为 import { foo } from "@douyinfe/semi-ui/lib/es/bar", 可以尝试替换为 import { foo } from "@coze-arch/bot-semi/Bar"',
},
{
group: ['@edenx/runtime/intl'],
message:
'请勿直接使用@edenx/runtime/intl, 请使用 @coze-arch/i18n',
},
{
group: ['@edenx/runtime/router'],
message:
'请勿直接使用@edenx/runtime/router, 请使用 react-router-dom',
},
{
group: ['@edenx/runtime/styled'],
message:
'请勿直接使用@edenx/runtime/styled, 请使用 styled-components',
},
],
},
],
},
},
];

View File

@@ -0,0 +1,76 @@
{
"name": "@coze-arch/eslint-config",
"version": "0.0.1",
"author": "fanwenjie.fe@bytedance.com",
"maintainers": [],
"main": "src/index.js",
"bin": {
"eslint": "./scripts/reslint.sh",
"prettier": "./scripts/rprettier.sh",
"reslint": "./scripts/reslint.sh"
},
"scripts": {
"build": "exit 0",
"dev": "npm run build -- -w",
"lint": "eslint ./ --cache --quiet",
"test": "exit",
"test:cov": "exit"
},
"dependencies": {
"@babel/eslint-parser": "~7.25.8",
"@babel/eslint-plugin": "~7.25.7",
"@babel/plugin-proposal-async-generator-functions": "~7.20.7",
"@babel/plugin-proposal-class-properties": "~7.18.6",
"@babel/plugin-proposal-decorators": "~7.23.6",
"@babel/plugin-proposal-do-expressions": "~7.23.3",
"@babel/plugin-proposal-export-default-from": "~7.23.3",
"@babel/plugin-proposal-export-namespace-from": "~7.18.9",
"@babel/plugin-proposal-function-bind": "~7.23.3",
"@babel/plugin-proposal-nullish-coalescing-operator": "~7.18.6",
"@babel/plugin-proposal-object-rest-spread": "~7.20.7",
"@babel/plugin-proposal-optional-catch-binding": "~7.18.6",
"@babel/plugin-proposal-optional-chaining": "~7.21.0",
"@babel/plugin-proposal-pipeline-operator": "~7.23.3",
"@babel/plugin-syntax-dynamic-import": "~7.8.3",
"@babel/plugin-syntax-jsx": "~7.23.3",
"@babel/preset-env": "~7.20.2",
"@babel/preset-react": "~7.13.13",
"@coze-arch/eslint-plugin": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@eslint/compat": "~1.2.0",
"@eslint/eslintrc": "~3.1.0",
"@rushstack/eslint-config": "~3.1.1",
"@stylistic/eslint-plugin-ts": "^2.8.0",
"@typescript-eslint/eslint-plugin": "^8.5.0",
"@typescript-eslint/parser": "~8.17.0",
"eslint": "~9.12.0",
"eslint-config-airbnb": "^18.0.1",
"eslint-config-prettier": "~9.1.0",
"eslint-config-react-app": "^7",
"eslint-define-config": "~1.12.0",
"eslint-import-resolver-typescript": "^3",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-cypress": "^2.6.1",
"eslint-plugin-eslint-comments": "~3.2.0",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-prettier": "~5.2.1",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "~7.37.1",
"eslint-plugin-react-hooks": "5.1.0-beta-26f2496093-20240514",
"eslint-plugin-redux-saga": "^1.1.0",
"eslint-plugin-risxss": "~2.1.0",
"eslint-plugin-security": "3.0.1",
"eslint-plugin-unicorn": "48.0.1",
"globals": "~15.11.0",
"json5": "^2.2.1",
"prettier": "~3.3.3",
"prettier-plugin-packagejson": "^2.3.0",
"sucrase": "^3.32.0"
},
"devDependencies": {
"@types/eslint": "~9.6.1",
"@types/node": "^18",
"typescript": "~5.8.2"
}
}

View File

@@ -0,0 +1,200 @@
const path = require('path');
const fs = require('fs');
const JSON5 = require('json5');
const noRestrictedSyntaxRule = [
'error',
{
selector: 'LabeledStatement',
message:
'Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.',
},
{
selector: 'WithStatement',
message:
'`with` is disallowed in strict mode because it makes code impossible to predict and optimize.',
},
];
const readBlockList = () =>
JSON5.parse(
fs.readFileSync(
// fixme @fanwenjie.fe
path.resolve(__dirname, '../../../disallowed_3rd_libraries.json'),
'utf-8',
),
);
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
// NOTE: 不能和下一项配置合并
{
ignores: [
'**/*.d.ts',
'**/.storybook/**',
'**/storybook-static/**',
'**/coverage/**',
'**/node_modules/**',
'**/build/**',
'**/__dist__/**',
'**/dist/**',
'**/es/**',
'**/lib/**',
'**/.codebase/**',
'**/.changeset/**',
'**/config/**',
'**/common/scripts/**',
'**/output/**',
'**/output_resource/**',
'**/__tests__/fixtures/**',
'**/__tests__/outputs/**',
'error-log-str.js',
'*.bundle.js',
'*.min.js',
'*.js.map',
'**/*.log',
'**/tsconfig.tsbuildinfo',
'**/.jscpd',
],
},
{
plugins: {
'@coze-arch': require('@coze-arch/eslint-plugin'),
'@coze-arch/zustand': require('@coze-arch/eslint-plugin/zustand'),
},
},
...require('@coze-arch/eslint-plugin').configs.recommended,
require('@coze-arch/eslint-plugin/zustand').configs.recommended,
{
files: ['**/*.?(m|c)?(j|t)s?(x)'], // 排除规则对package.json生效
plugins: {
prettier: require('eslint-plugin-prettier'),
'@babel': require('@babel/eslint-plugin'),
import: require('eslint-plugin-import'),
unicorn: require('eslint-plugin-unicorn'),
'@typescript-eslint': require('@typescript-eslint/eslint-plugin'),
'@stylistic/ts': require('@stylistic/eslint-plugin-ts'),
'eslint-comments': require('eslint-plugin-eslint-comments'),
},
rules: {
'@coze-arch/package-disallow-deps': ['error', readBlockList()],
'no-restricted-syntax': noRestrictedSyntaxRule,
'prettier/prettier': [
'warn',
require('../.prettierrc'),
{ usePrettierrc: false },
],
'no-empty': 'error',
'import/no-duplicates': 'error',
'unicorn/no-static-only-class': 'error',
curly: 'error',
'no-mixed-spaces-and-tabs': 'error',
'max-statements-per-line': 'error',
'rest-spread-spacing': 'error',
'max-len': [
'warn',
{
code: 120,
tabWidth: 2,
ignoreUrls: true,
ignoreStrings: true,
},
],
'no-unexpected-multiline': 'error',
'no-irregular-whitespace': [
'error',
{
skipStrings: true,
skipComments: true,
},
],
'no-var': 'error',
'prefer-const': 'error',
'no-inner-declarations': ['error', 'both'],
'no-self-assign': 'error',
'prefer-destructuring': [
'warn',
{
object: true,
array: false,
},
],
'no-sparse-arrays': 'error',
'no-new-object': 'error',
'object-shorthand': 'error',
'no-empty-pattern': 'error',
'no-unsafe-optional-chaining': 'error',
'no-class-assign': 'error',
'arrow-body-style': 'error',
'no-async-promise-executor': 'error',
'prefer-promise-reject-errors': 'error',
// TODO: complexity is stricter after we updated to eslint 9.
complexity: ['warn', 15],
'max-params': [
'error',
{
max: 3,
},
],
'no-extra-bind': 'error',
'no-prototype-builtins': 'error',
'new-parens': 'error',
'prefer-template': 'warn',
'no-multi-str': 'error',
'use-isnan': 'error',
'no-floating-decimal': 'error',
'guard-for-in': 'warn',
'for-direction': 'error',
'no-unmodified-loop-condition': 'error',
'no-unsafe-finally': 'error',
'no-cond-assign': ['error', 'always'],
'no-constant-condition': [
'error',
{
checkLoops: false,
},
],
'no-dupe-else-if': 'error',
'no-extra-boolean-cast': [
'error',
{
enforceForLogicalOperands: true,
},
],
'no-useless-catch': 'error',
'no-ex-assign': 'error',
'no-fallthrough': 'error',
'default-case': 'error',
'default-case-last': 'error',
'no-duplicate-case': 'error',
'no-case-declarations': 'error',
eqeqeq: 'error',
'no-compare-neg-zero': 'error',
'no-invalid-regexp': 'error',
'no-control-regex': 'error',
'no-empty-character-class': 'error',
'no-with': 'error',
'no-eval': 'error',
'no-new-wrappers': 'error',
'no-global-assign': 'error',
'no-debugger': 'error',
'no-caller': 'error',
'prefer-rest-params': 'error',
'no-implicit-coercion': [
'error',
{
allow: ['!!'],
},
],
'array-bracket-newline': ['error', 'consistent'],
'eslint-comments/require-description': 'warn',
'eslint-comments/no-unused-disable': 'error',
'max-lines': [
'error',
{ max: 500, skipComments: true, skipBlankLines: true },
],
'no-unused-labels': 'error',
},
},
];

View File

@@ -0,0 +1,80 @@
const importPlugin = require('eslint-plugin-import');
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
{
files: ['**/*.?(m|c)?(j|t)s?(x)'],
settings: {
// TODO: 全局保留一份配置
'import/resolver': {
node: {
moduleDirectory: ['node_modules', 'src'],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
rules: {
'import/no-cycle': ['error', { ignoreExternal: true }],
'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: true,
},
],
'import/no-relative-packages': 'error',
'import/extensions': 'off',
'import/order': [
'warn',
{
groups: [
'builtin',
'external',
['internal', 'parent', 'sibling', 'index'],
'unknown',
],
pathGroups: [
{
pattern: 'react*',
group: 'builtin',
position: 'before',
},
{
pattern: '@/**',
group: 'internal',
position: 'before',
},
{
pattern: './*.+(css|sass|less|scss|pcss|styl)',
patternOptions: { dot: true, nocomment: true },
group: 'unknown',
position: 'after',
},
],
alphabetize: {
order:
'desc' /* sort in ascending order. Options: ['ignore', 'asc', 'desc'] */,
caseInsensitive: true /* ignore case. Options: [true, false] */,
},
pathGroupsExcludedImportTypes: ['builtin'],
'newlines-between': 'always',
},
],
},
},
{
files: ['**/*.?(m|c)ts?(x)'],
...importPlugin.configs.typescript,
settings: {
'import/resolver': {
typescript: true,
node: true,
},
},
rules: {
// TODO: 目前由于 edenx 会动态生成一些插件模块,因此启动会报错
// 后续需要修复问题,启动下述规则
// "import/no-unresolved": "error"
},
},
];

View File

@@ -0,0 +1,163 @@
const babelOptions = {
plugins: [
[
require.resolve('@babel/plugin-proposal-decorators'),
{
legacy: true,
},
],
[
require.resolve('@babel/plugin-proposal-class-properties'),
{
loose: true,
},
],
require.resolve('@babel/plugin-proposal-object-rest-spread'),
require.resolve('@babel/plugin-proposal-optional-catch-binding'),
require.resolve('@babel/plugin-proposal-async-generator-functions'),
require.resolve('@babel/plugin-proposal-export-namespace-from'),
require.resolve('@babel/plugin-proposal-export-default-from'),
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
require.resolve('@babel/plugin-proposal-optional-chaining'),
[
require.resolve('@babel/plugin-proposal-pipeline-operator'),
{
proposal: 'minimal',
},
],
require.resolve('@babel/plugin-proposal-do-expressions'),
require.resolve('@babel/plugin-proposal-function-bind'),
require.resolve('@babel/plugin-syntax-dynamic-import'),
require.resolve('@babel/plugin-syntax-jsx'),
],
};
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
{
files: ['**/*.?(m|c)js?(x)'],
rules: {
'no-import-assign': 'error',
'no-extra-semi': 'error',
'no-undef': 'error',
'no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
},
],
'comma-dangle': ['error', 'always-multiline'],
'no-array-constructor': 'error',
'dot-notation': 'error',
'constructor-super': 'error',
'no-this-before-super': 'error',
'no-useless-constructor': 'error',
'getter-return': [
'error',
{
allowImplicit: true,
},
],
'no-setter-return': 'error',
'no-dupe-class-members': 'error',
'default-param-last': 'error',
'no-func-assign': 'error',
'no-unsafe-negation': 'error',
'valid-typeof': 'error',
'no-empty-function': 'error',
quotes: [
'error',
'single',
{
avoidEscape: true,
},
],
'no-loss-of-precision': 'error',
'no-magic-numbers': [
'warn',
{
ignoreArrayIndexes: true,
ignoreDefaultValues: true,
enforceConst: true,
ignore: [0, 1, -1],
ignoreClassFieldInitialValues: true,
},
],
'no-unreachable': 'error',
'no-throw-literal': 'error',
'no-implied-eval': 'error',
'no-new-symbol': 'error',
'no-obj-calls': 'error',
camelcase: [
'error',
{
properties: 'never',
allow: ['^UNSAFE_'],
ignoreDestructuring: true,
},
],
'unicorn/filename-case': [
'error',
{
cases: {
kebabCase: true,
},
},
],
'max-lines-per-function': [
'error',
{
max: 300,
IIFEs: true,
},
],
},
languageOptions: {
parser: require('@babel/eslint-parser'),
parserOptions: {
ecmaVersion: 11,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
legacyDecorators: true,
},
requireConfigFile: false,
babelOptions,
},
},
},
{
// for jsx
files: ['**/*.?(m|c)jsx'],
rules: {
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'unicorn/filename-case': [
'warn',
{
cases: {
kebabCase: true,
snakeCase: true,
pascalCase: true,
},
ignore: ['^(?!.*?\\.jsx$)(?!.*?\\.tsx$).+'],
},
],
'max-lines-per-function': [
'warn',
{
max: 300,
IIFEs: true,
},
],
'max-lines': [
'error',
{
max: 500,
skipComments: true,
skipBlankLines: true,
},
],
},
},
];

View File

@@ -0,0 +1,53 @@
const globals = require('globals');
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
{
files: [
'**/*.{test,spec}.?(m|c){js,ts}?(x)',
'**/{tests,__tests__,__test__}/**/*.?(m|c){js,ts}?(x)',
],
languageOptions: {
globals: {
...globals.jest,
vi: 'readonly',
},
},
rules: {
'max-lines': 'off',
'max-lines-per-function': 'off',
'no-magic-numbers': 'off',
'no-restricted-syntax': 'off',
'import/no-named-as-default-member': 'off',
'@coze-arch/max-line-per-function': 'off',
'@coze-arch/no-deep-relative-import': 'off',
'@typescript-eslint/consistent-type-assertions': 'off',
},
},
{
files: [
'**/*.{test,spec}.?(m|c)ts?(x)',
'**/{tests,__tests__,__test__}/**/*.?(m|c)ts?(x)',
],
rules: {
'@stylistic/ts/member-delimiter-style': [
'warn',
{
multiline: {
delimiter: 'semi',
requireLast: true,
},
singleline: {
delimiter: 'semi',
requireLast: false,
},
},
],
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-magic-numbers': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@coze-arch/no-batch-import-or-export': 'off',
},
},
];

View File

@@ -0,0 +1,371 @@
/** @type {(import('eslint').Linter.Config)[]} */
module.exports = [
{
files: ['**/*.?(m|c)ts?(x)'],
rules: {
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/prefer-namespace-keyword': 'off',
'@typescript-eslint/dot-notation': 'error',
'@typescript-eslint/require-await': 'error',
'max-lines': [
'error',
{
max: 500,
skipComments: true,
skipBlankLines: true,
},
],
'@typescript-eslint/no-array-constructor': 'error',
'@typescript-eslint/prefer-for-of': 'warn',
'@typescript-eslint/prefer-literal-enum-member': 'error',
'@typescript-eslint/no-duplicate-enum-values': 'error',
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/unified-signatures': 'error',
'@typescript-eslint/no-this-alias': 'error',
'@typescript-eslint/method-signature-style': 'error',
'@typescript-eslint/no-misused-new': 'error',
'@typescript-eslint/consistent-type-assertions': [
'error',
{
assertionStyle: 'as',
objectLiteralTypeAssertions: 'never',
},
],
'@typescript-eslint/no-non-null-assertion': 'error',
'@typescript-eslint/no-extra-non-null-assertion': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
'@typescript-eslint/ban-ts-comment': [
'error',
{
'ts-expect-error': 'allow-with-description',
},
],
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/prefer-as-const': 'error',
'@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
'@typescript-eslint/no-empty-interface': 'error',
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
'@typescript-eslint/no-invalid-void-type': 'error',
'@typescript-eslint/no-namespace': 'error',
'@typescript-eslint/no-require-imports': 'error',
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/no-unused-vars': [
'error',
{
vars: 'all',
args: 'none', // function arguments should not force to match this rule.
argsIgnorePattern: '^_', // 规范允许下划线
ignoreRestSiblings: true, //使用rest语法如 `var { foo, ...rest } = data`) 忽略foo。
destructuredArrayIgnorePattern: '^_', //结构数组允许使用_
caughtErrors: 'none',
// "caughtErrorsIgnorePattern": "^e$"
},
],
'@stylistic/ts/quotes': [
'error',
'single',
{
avoidEscape: true,
},
],
'@typescript-eslint/no-magic-numbers': [
'warn',
{
ignoreArrayIndexes: true,
ignoreDefaultValues: true,
ignoreEnums: true,
ignoreNumericLiteralTypes: true,
enforceConst: true,
ignore: [-1, 0, 1],
ignoreTypeIndexes: true,
ignoreReadonlyClassProperties: true,
ignoreClassFieldInitialValues: true,
},
],
'@stylistic/ts/no-extra-semi': 'error',
'@typescript-eslint/no-dupe-class-members': 'error',
'@typescript-eslint/no-useless-constructor': 'error',
'@typescript-eslint/default-param-last': 'error',
'@typescript-eslint/no-loss-of-precision': 'error',
'@stylistic/ts/comma-dangle': [
'error',
{
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
enums: 'always-multiline',
generics: 'ignore',
tuples: 'always-multiline',
functions: 'always-multiline',
},
],
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-extraneous-class': 'error',
'no-import-assign': 'off',
'no-undef': 'off',
'dot-notation': 'off',
'constructor-super': 'off',
'no-this-before-super': 'off',
'getter-return': 'off',
'no-setter-return': 'off',
'no-func-assign': 'off',
'no-unsafe-negation': 'off',
'valid-typeof': 'off',
'no-unreachable': 'off',
'no-throw-literal': 'off',
'no-implied-eval': 'off',
'no-new-symbol': 'off',
'no-obj-calls': 'off',
camelcase: 'off',
'no-const-assign': 'off',
'no-dupe-args': 'off',
'no-dupe-class-members': 'off',
'no-dupe-keys': 'off',
'no-redeclare': 'off',
'no-array-constructor': 'off',
'no-empty-function': 'off',
'no-extra-semi': 'off',
'no-loss-of-precision': 'off',
'no-unused-vars': 'off',
'default-param-last': 'off',
'no-useless-constructor': 'off',
quotes: 'off',
'comma-dangle': 'off',
indent: 'off',
'no-magic-numbers': 'off',
'@typescript-eslint/naming-convention': [
'error',
{
selector: ['default', 'variableLike'],
format: ['camelCase', 'UPPER_CASE'],
},
{
selector: ['class', 'interface', 'typeLike'],
format: ['PascalCase'],
},
{
selector: ['variable'],
format: ['UPPER_CASE', 'camelCase'],
modifiers: ['global', 'exported'],
},
{
selector: 'objectLiteralProperty',
format: null,
},
{
selector: 'enumMember',
format: ['UPPER_CASE', 'PascalCase'],
},
{
selector: 'typeProperty',
format: ['camelCase', 'snake_case'],
},
{
selector: 'function',
format: ['camelCase'],
leadingUnderscore: 'forbid',
trailingUnderscore: 'forbid',
},
{
selector: 'parameter',
format: ['camelCase'],
leadingUnderscore: 'allow',
trailingUnderscore: 'forbid',
},
{
selector: 'variable',
modifiers: ['destructured'],
format: [
'camelCase',
'PascalCase',
'snake_case',
'strictCamelCase',
'StrictPascalCase',
'UPPER_CASE',
],
},
{
selector: 'import',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
},
],
'unicorn/filename-case': [
'error',
{
cases: {
kebabCase: true,
},
},
],
'max-lines-per-function': [
'warn',
{
max: 120,
IIFEs: true,
},
],
},
languageOptions: {
parser: require('@typescript-eslint/parser'),
parserOptions: {
ecmaVersion: 11,
projectService: true,
sourceType: 'module',
ecmaFeatures: {
jsx: true,
legacyDecorators: true,
},
},
},
},
{
files: ['**/*.?(m|c)tsx'],
rules: {
'@typescript-eslint/naming-convention': [
'error',
{
selector: ['default', 'variableLike'],
format: ['camelCase', 'UPPER_CASE'],
},
{
selector: ['class', 'interface', 'typeLike'],
format: ['PascalCase'],
},
{
selector: ['variable'],
format: ['UPPER_CASE', 'camelCase', 'PascalCase'],
modifiers: ['global', 'exported'],
},
{
selector: 'objectLiteralProperty',
format: null,
},
{
selector: 'enumMember',
format: ['UPPER_CASE', 'PascalCase'],
},
{
selector: 'typeProperty',
format: ['camelCase', 'snake_case'],
},
{
selector: 'parameter',
format: ['camelCase'],
leadingUnderscore: 'allow',
trailingUnderscore: 'forbid',
},
{
selector: 'parameter',
format: ['camelCase', 'snake_case'],
modifiers: ['destructured'],
},
{
selector: 'variable',
modifiers: ['destructured'],
format: [
'camelCase',
'PascalCase',
'snake_case',
'strictCamelCase',
'StrictPascalCase',
'UPPER_CASE',
],
},
{
selector: 'import',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
},
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
leadingUnderscore: 'forbid',
trailingUnderscore: 'forbid',
},
{
selector: 'variable',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
leadingUnderscore: 'allow',
},
],
'unicorn/filename-case': [
'warn',
{
cases: {
kebabCase: true,
snakeCase: true,
pascalCase: true,
},
ignore: ['^(?!.*?\\.jsx$)(?!.*?\\.tsx$).+'],
},
],
'max-lines-per-function': [
'warn',
{
max: 300,
IIFEs: true,
},
],
},
},
// TODO: 之前overides的内容后需可考虑直接合入上面标准配置
{
files: ['**/*.?(m|c)ts?(x)'],
rules: {
'@typescript-eslint/consistent-type-imports': [
'error',
{
fixStyle: 'inline-type-imports',
},
],
// 这些规则都是从 packages/config/.eslintrc.react.js 复制迁移过来
// 后续在做调整
'@typescript-eslint/no-redundant-type-constituents': 0,
'@typescript-eslint/no-throw-literal': 'off',
'@typescript-eslint/no-unnecessary-condition': 0,
'@typescript-eslint/prefer-optional-chain': 0,
'@typescript-eslint/indent': 0,
'@babel/new-cap': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
// TODO: 后续开启
// 'import/no-cycle': 'error',
'@typescript-eslint/prefer-string-starts-ends-with': 0,
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 0,
'@typescript-eslint/no-implied-eval': 0, // warning
// TODO: 打开下面这些配置
// fix: https://stackoverflow.com/questions/63961803/eslint-says-all-enums-in-typescript-app-are-already-declared-in-the-upper-scope
// 'no-shadow': 'off',
// '@typescript-eslint/no-shadow': ['error'],
// '@typescript-eslint/consistent-type-imports': [
// 'error',
// {
// fixStyle: 'inline-type-imports',
// },
// ],
// according to: https://typescript-eslint.io/linting/troubleshooting/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
// 'no-undef': 'off',
// 'no-unused-vars': 'off',
// '@typescript-eslint/no-unused-vars': [
// 'error',
// {
// vars: 'all',
// args: 'none', // function arguments should not force to match this rule.
// ignoreRestSiblings: false,
// },
// ],
// complexity: ['error', { max: 15 }],
// 后面统一使用CustomError后 再开启
'@coze-arch/no-new-error': 'off',
},
},
];

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
# 某些系统可能没有 realpath 命令,
if ! command -v realpath &>/dev/null; then
echo "未找到 realpath 命令"
echo "请执行以下命令安装必要依赖"
echo " brew install coreutils"
exit 1
fi
ROOT_DIR=$(realpath "$BASE_DIR/../")
args=("--cache")
if [ "$CI" = "true" ]; then
args+=("--quiet")
fi
bash "$ROOT_DIR/node_modules/.bin/eslint" "${args[@]}" "$@"

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
# 某些系统可能没有 realpath 命令,
if ! command -v realpath &>/dev/null; then
echo "未找到 realpath 命令"
echo "请执行以下命令安装必要依赖"
echo " brew install coreutils"
exit 1
fi
ROOT_DIR=$(realpath "$BASE_DIR/../")
bash "$ROOT_DIR/node_modules/.bin/prettier" "$@"

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import fs from 'fs';
import type { Linter } from 'eslint';
import { includeIgnoreFile } from '@eslint/compat';
type ESLintConfigMode = 'web' | 'node' | 'base';
type ESLintConfig = Linter.Config;
type Rules = Linter.RulesRecord;
export interface EnhanceESLintConfig extends ESLintConfig {
/**
* project root dir
*/
packageRoot: string;
/**
* config mode
*/
preset: ESLintConfigMode;
/** overrides config */
overrides: ESLintConfig[];
}
/**
* Define an ESLint config.
*
* @param config ESLint config.
* @returns ESLint config.
*/
export const defineConfig = (config: EnhanceESLintConfig): ESLintConfig[] => {
const {
packageRoot,
preset,
overrides = [],
ignores = [],
rules,
settings,
...userConfig
} = config;
if (!packageRoot) {
throw new Error('should provider "packageRoot" params');
}
const defaultRules: Rules = {};
const ignorePath = path.resolve(packageRoot, '.gitignore');
return [
...require(`../eslint.config.${preset}.js`),
fs.existsSync(ignorePath) ? includeIgnoreFile(ignorePath) : {},
// root ignore file
includeIgnoreFile(path.resolve(__dirname, '../../../.gitignore')),
{
ignores,
},
{
files: ['**/*.?(m|c)?(j|t)s?(x)'],
settings: {
...settings,
'import/resolver': {
typescript: {
project: packageRoot,
},
},
},
plugins: {},
rules: {
...defaultRules,
...rules,
},
...userConfig,
},
...overrides,
];
};

View File

@@ -0,0 +1,12 @@
require('sucrase/register/ts');
const { defineConfig } = require('./define-config');
// node@16 没有 structuredClone 方法导致报错:
// ReferenceError: Error while loading rule '@typescript-eslint/naming-convention': structuredClone is not defined
// 此处做个简单 polyfill
if (typeof structuredClone === 'undefined') {
global.structuredClone = obj => JSON.parse(JSON.stringify(obj));
}
module.exports = { defineConfig };

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"sourceMap": false,
"lib": ["ES2021"],
"esModuleInterop": true,
"types": ["node"],
"rootDir": "./src",
"outDir": "dist",
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["./src", "./src/**/*.json"],
"references": [
{
"path": "../../infra/eslint-plugin/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,18 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "vitest.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"sourceMap": false,
"lib": ["ES2021"],
"esModuleInterop": true
}
}

View File

@@ -0,0 +1,225 @@
# @coze-arch/postcss-config
A shared PostCSS configuration for Coze architecture projects that provides a standardized set of PostCSS plugins for modern CSS preprocessing and Tailwind CSS integration.
## Features
- **PostCSS Import**: Process `@import` statements and inline imported files
- **Tailwind CSS Nesting**: Full support for CSS nesting with Tailwind CSS compatibility
- **Autoprefixer**: Automatic vendor prefixing for cross-browser compatibility
- **Modern CSS Support**: Enhanced pseudo-class support with `:is()` functionality
- **Zero Configuration**: Works out of the box with sensible defaults
- **Optimized Build**: Configured for both development and production workflows
## Get Started
### Installation
```bash
# Install as a workspace dependency
npm install @coze-arch/postcss-config@workspace:*
# Update rush dependencies
rush update
```
### Basic Usage
Create a `postcss.config.js` file in your project root:
```javascript
module.exports = require('@coze-arch/postcss-config');
```
Or extend the configuration:
```javascript
const baseConfig = require('@coze-arch/postcss-config');
module.exports = {
...baseConfig,
plugins: {
...baseConfig.plugins,
// Add your custom plugins here
'postcss-custom-plugin': {},
},
};
```
### Integration with Build Tools
#### Webpack
```javascript
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader', // Will automatically use postcss.config.js
],
},
],
},
};
```
#### Vite
```javascript
// vite.config.js
export default {
css: {
postcss: require('@coze-arch/postcss-config'),
},
};
```
#### Rsbuild
```javascript
// rsbuild.config.js
export default {
tools: {
postcss: require('@coze-arch/postcss-config'),
},
};
```
## API Reference
### Default Configuration
The package exports a PostCSS configuration object with the following plugins:
```javascript
{
plugins: {
'postcss-import': {},
'tailwindcss/nesting': 'postcss-nesting',
'tailwindcss': {},
'autoprefixer': {},
'@csstools/postcss-is-pseudo-class': {},
}
}
```
### Plugin Details
#### postcss-import
- **Purpose**: Processes `@import` statements and inlines imported CSS files
- **Configuration**: Default settings (empty object)
- **Use Case**: Modular CSS organization and file imports
#### tailwindcss/nesting
- **Purpose**: Enables CSS nesting syntax compatible with Tailwind CSS
- **Configuration**: Uses `postcss-nesting` as the nesting implementation
- **Use Case**: Writing nested CSS with Tailwind utility classes
#### tailwindcss
- **Purpose**: Processes Tailwind CSS utility classes and directives
- **Configuration**: Default settings (reads from `tailwind.config.js`)
- **Use Case**: Utility-first CSS framework integration
#### autoprefixer
- **Purpose**: Automatically adds vendor prefixes to CSS properties
- **Configuration**: Default settings (uses browserslist configuration)
- **Use Case**: Cross-browser compatibility without manual prefixing
#### @csstools/postcss-is-pseudo-class
- **Purpose**: Transforms `:is()` pseudo-class for better browser support
- **Configuration**: Default settings
- **Use Case**: Modern CSS pseudo-class support in older browsers
### Customization Examples
#### Adding Custom Plugins
```javascript
const baseConfig = require('@coze-arch/postcss-config');
module.exports = {
...baseConfig,
plugins: {
...baseConfig.plugins,
'postcss-custom-properties': {
preserve: false,
},
'cssnano': {
preset: 'default',
},
},
};
```
#### Plugin Order Customization
```javascript
const baseConfig = require('@coze-arch/postcss-config');
module.exports = {
plugins: {
'postcss-import': baseConfig.plugins['postcss-import'],
'custom-plugin': {},
'tailwindcss/nesting': baseConfig.plugins['tailwindcss/nesting'],
'tailwindcss': baseConfig.plugins['tailwindcss'],
'autoprefixer': baseConfig.plugins['autoprefixer'],
'@csstools/postcss-is-pseudo-class': baseConfig.plugins['@csstools/postcss-is-pseudo-class'],
},
};
```
## Development
### Project Structure
```
config/postcss-config/
├── src/
│ └── index.js # Main configuration export
├── package.json # Package configuration
├── eslint.config.js # ESLint configuration
├── tsconfig.*.json # TypeScript configurations
└── README.md # This file
```
### Development Commands
```bash
# Lint the code
rush lint
# Run all checks
rush build
```
### Contributing
1. Follow the existing code style and configuration patterns
2. Ensure all linting passes before submitting changes
3. Test the configuration with actual PostCSS processing
4. Update documentation for any configuration changes
## Dependencies
### Runtime Dependencies
- **postcss**: Core PostCSS processor
- **postcss-import**: Import processing plugin
- **postcss-loader**: Webpack integration
- **postcss-nesting**: CSS nesting support
- **@tailwindcss/nesting**: Tailwind-compatible nesting
- **@csstools/postcss-is-pseudo-class**: Modern pseudo-class support
### Development Dependencies
- **@coze-arch/eslint-config**: Shared ESLint configuration
- **@coze-arch/ts-config**: Shared TypeScript configuration
- **@types/node**: Node.js type definitions
## License
Internal use within Coze architecture projects.

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,6 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
preset: 'node',
packageRoot: __dirname,
});

View File

@@ -0,0 +1,27 @@
{
"name": "@coze-arch/postcss-config",
"version": "0.0.1",
"author": "huangjian@bytedance.com",
"maintainers": [],
"main": "src/index.js",
"scripts": {
"build": "exit",
"dev": "npm run build -- -w",
"lint": "eslint ./ --cache --quiet",
"test": "exit",
"test:cov": "exit"
},
"dependencies": {
"@csstools/postcss-is-pseudo-class": "^4.0.5",
"@tailwindcss/nesting": "latest",
"postcss": "^8.4.32",
"postcss-import": "^16.1.0",
"postcss-loader": "^7.3.3",
"postcss-nesting": "^12.1.0"
},
"devDependencies": {
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@types/node": "^18"
}
}

View File

@@ -0,0 +1,9 @@
module.exports = {
plugins: {
'postcss-import': {},
'tailwindcss/nesting': 'postcss-nesting',
tailwindcss: {},
autoprefixer: {},
'@csstools/postcss-is-pseudo-class': {},
},
};

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"sourceMap": false,
"esModuleInterop": true,
"types": [],
"rootDir": "./src",
"outDir": "dist",
"allowJs": true,
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["./src", "./src/**/*.json"],
"references": [
{
"path": "../eslint-config/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,17 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "vitest.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"sourceMap": false,
"esModuleInterop": true
}
}

View File

@@ -0,0 +1,61 @@
# @coze-arch/rsbuild-config
rsbuild config
## Overview
This package is part of the Coze Studio monorepo and provides ui component functionality. It includes plugin.
## Getting Started
### Installation
Add this package to your `package.json`:
```json
{
"dependencies": {
"@coze-arch/rsbuild-config": "workspace:*"
}
}
```
Then run:
```bash
rush update
```
### Usage
```typescript
import { /* exported functions/components */ } from '@coze-arch/rsbuild-config';
// Example usage
// TODO: Add specific usage examples
```
## Features
- Plugin
## API Reference
Please refer to the TypeScript definitions for detailed API documentation.
## Development
This package is built with:
- TypeScript
- Modern JavaScript
- Vitest for testing
- ESLint for code quality
## Contributing
This package is part of the Coze Studio monorepo. Please follow the monorepo contribution guidelines.
## License
Apache-2.0

View File

@@ -0,0 +1,12 @@
{
"operationSettings": [
{
"operationName": "test:cov",
"outputFolderNames": ["coverage"]
},
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,7 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'node',
rules: {},
});

View File

@@ -0,0 +1,42 @@
{
"name": "@coze-arch/rsbuild-config",
"version": "0.0.1",
"description": "rsbuild config ",
"license": "Apache-2.0",
"author": "fanwenjie.fe@bytedance.com",
"maintainers": [],
"main": "src/index.ts",
"scripts": {
"build": "exit 0",
"lint": "eslint ./ --cache",
"test": "vitest --run --passWithNoTests",
"test:cov": "npm run test -- --coverage"
},
"dependencies": {
"@coze-arch/bot-env": "workspace:*",
"@coze-arch/pkg-root-webpack-plugin": "workspace:*",
"@coze-arch/semi-theme-hand01": "0.0.6-alpha.346d77",
"@coze-common/assets": "workspace:*",
"@douyinfe/semi-rspack-plugin": "2.61.0",
"@rsbuild/core": "~1.1.0",
"@rsbuild/plugin-less": "~1.1.0",
"@rsbuild/plugin-react": "~1.1.0",
"@rsbuild/plugin-sass": "~1.1.0",
"@rsbuild/plugin-svgr": "~1.0.6",
"postcss": "^8.4.32",
"postcss-nesting": "^12.1.0",
"tailwindcss": "~3.3.3"
},
"devDependencies": {
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@coze-arch/vitest-config": "workspace:*",
"@types/node": "^18",
"@vitest/coverage-v8": "~3.0.5",
"sucrase": "^3.32.0",
"typescript": "~5.8.2",
"vitest": "~3.0.5",
"webpack": "~5.91.0"
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { pluginSvgr } from '@rsbuild/plugin-svgr';
import { pluginSass } from '@rsbuild/plugin-sass';
import { pluginReact } from '@rsbuild/plugin-react';
import { pluginLess } from '@rsbuild/plugin-less';
import { type RsbuildConfig, mergeRsbuildConfig } from '@rsbuild/core';
import { PkgRootWebpackPlugin } from '@coze-arch/pkg-root-webpack-plugin';
import { GLOBAL_ENVS } from '@coze-arch/bot-env';
import { SemiRspackPlugin } from '@douyinfe/semi-rspack-plugin';
const getDefine = () => {
const define = {};
Object.keys(GLOBAL_ENVS).forEach(key => {
// 在rspack的define中字符串需要前后拼接上双引号才能在代码中作为字符串使用。
if (typeof GLOBAL_ENVS[key] === 'string') {
define[key] = `"${GLOBAL_ENVS[key]}"`;
} else {
define[key] = GLOBAL_ENVS[key];
}
});
return define;
};
export const overrideBrowserslist = [
'chrome >= 51',
'edge >= 15',
'firefox >= 54',
'safari >= 10',
'ios_saf >= 10',
];
const generateCdnPrefix = () => {
if (process.env.CDN_INNER_CN) {
return `https://${process.env.CDN_INNER_CN}/${process.env.CDN_PATH_PREFIX ? `${process.env.CDN_PATH_PREFIX}/` : ''}`;
}
return '/';
};
export const defineConfig = (options: Partial<RsbuildConfig>) => {
const cdnPrefix = generateCdnPrefix();
const port = 8080;
const commonAssertsUrl = path.dirname(
require.resolve('@coze-common/assets/package.json'),
);
const config: RsbuildConfig = {
dev: {
client: {
port,
host: '127.0.0.1',
protocol: 'ws',
},
},
server: {
port,
},
plugins: [
pluginReact(),
pluginSvgr({
mixedImport: true,
svgrOptions: {
exportType: 'named',
},
}),
pluginLess({
lessLoaderOptions: {
additionalData: `@import "${path.resolve(
commonAssertsUrl,
'style/variables.less',
)}";`,
},
}),
pluginSass({
sassLoaderOptions: {
sassOptions: {
silenceDeprecations: ['mixed-decls', 'import', 'function-units'],
},
},
}),
],
output: {
filenameHash: true,
assetPrefix: cdnPrefix,
injectStyles: true,
cssModules: {
auto: true,
},
sourceMap: {
js: 'source-map',
},
overrideBrowserslist,
},
source: {
define: getDefine(),
alias: {
'@coze-arch/semi-theme-hand01': path.dirname(
require.resolve('@coze-arch/semi-theme-hand01/package.json'),
),
},
include: [
// 以下几个包包含未降级的 ES 2022 语法private methods需要参与打包
/\/node_modules\/(marked|@dagrejs|@tanstack)\//,
],
},
tools: {
postcss: (opts, { addPlugins }) => {
addPlugins([
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('tailwindcss/nesting')(require('postcss-nesting')),
]);
},
rspack: (_, { appendPlugins }) => {
appendPlugins([
new PkgRootWebpackPlugin(),
new SemiRspackPlugin({
theme: '@coze-arch/semi-theme-hand01',
}),
]);
},
},
};
return mergeRsbuildConfig(config, options);
};

View File

@@ -0,0 +1,34 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"module": "CommonJS",
"target": "ES2020",
"moduleResolution": "node",
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["src"],
"exclude": ["node_modules", "dist"],
"references": [
{
"path": "../eslint-config/tsconfig.build.json"
},
{
"path": "../../infra/plugins/pkg-root-webpack-plugin/tsconfig.build.json"
},
{
"path": "../../packages/arch/bot-env/tsconfig.build.json"
},
{
"path": "../../packages/common/assets/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
},
{
"path": "../vitest-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"exclude": ["**/*"],
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
]
}

View File

@@ -0,0 +1,18 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"module": "CommonJS",
"target": "ES2020",
"moduleResolution": "node"
},
"include": ["__tests__", "vitest.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,22 @@
/*
* 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 { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'node',
});

View File

@@ -0,0 +1,39 @@
module.exports = {
extends: [
'stylelint-config-standard',
'stylelint-config-standard-less',
'stylelint-config-clean-order',
],
plugins: ['./plugins/plugin-disallow-nesting-level-one-global.js'],
rules: {
// 变量命名规则,适应仓库内的代码风格
'custom-property-pattern': '^([A-Za-z0-9]*)([-_]+[A-Za-z0-9]+)*$',
// 对于less函数判断有问题
'less/no-duplicate-variables': null,
'media-feature-range-notation': null,
'max-nesting-depth': [
3,
{
ignore: ['pseudo-classes'],
ignoreRules: ['/:global/'],
message: 'Expected nesting depth to be no more than 3.',
},
],
'plugin/disallow-first-level-global': true,
'selector-class-pattern': [
'^([a-z][a-z0-9]*)(-[a-z0-9]+)*(_[a-z0-9]+)?$',
{
resolveNestedSelectors: true,
message: 'Expected class pattern is $block-$element_$modifier.',
},
],
'declaration-no-important': true,
'color-function-notation': null,
'at-rule-no-unknown': [
true,
{
ignoreAtRules: ['tailwind'],
},
],
},
};

View File

@@ -0,0 +1,250 @@
# @coze-arch/stylelint-config
A comprehensive and opinionated stylelint configuration package designed for Coze's frontend projects. This package provides a standardized set of CSS/Less linting rules that enforce consistent code style, maintainability, and best practices across the codebase.
## Features
- 🔧 **Pre-configured Rules**: Built on top of industry-standard configurations including `stylelint-config-standard`, `stylelint-config-standard-less`, and `stylelint-config-clean-order`
- 📏 **BEM-style Class Naming**: Enforces `$block-$element_$modifier` naming pattern for CSS classes
- 🏗️ **Nesting Control**: Limits CSS nesting depth to 3 levels for better readability and performance
- 🚫 **Custom Rules**: Includes custom plugins to prevent first-level `:global` selectors and enforce coding standards
- 🎨 **Less Support**: Full support for Less syntax and variables
- 📋 **Property Ordering**: Automatic CSS property ordering for consistent code structure
-**Tailwind Compatible**: Configured to work seamlessly with Tailwind CSS
## Get Started
### Installation
Add the package to your project:
```bash
# In your project's package.json
{
"devDependencies": {
"@coze-arch/stylelint-config": "workspace:*"
}
}
```
Then run:
```bash
rush update
```
### Basic Usage
Create a `.stylelintrc.js` file in your project root:
```javascript
const { defineConfig } = require('@coze-arch/stylelint-config');
module.exports = defineConfig({
extends: [],
rules: {
// Add your custom rules here
}
});
```
Or use the configuration directly:
```javascript
module.exports = {
extends: ['@coze-arch/stylelint-config']
};
```
## API Reference
### `defineConfig(config)`
The main configuration function that extends the base stylelint configuration.
**Parameters:**
- `config` (Config): Stylelint configuration object
**Returns:**
- `Config`: Extended stylelint configuration
**Example:**
```javascript
const { defineConfig } = require('@coze-arch/stylelint-config');
module.exports = defineConfig({
extends: ['stylelint-config-recommended-scss'],
rules: {
'color-hex-length': 'long',
'declaration-block-trailing-semicolon': 'always'
},
ignoreFiles: ['dist/**/*']
});
```
## Configuration Rules
### Class Naming Pattern
The configuration enforces BEM-style class naming with the pattern: `$block-$element_$modifier`
```css
/* ✅ Good */
.button { }
.button-large { }
.button-large_disabled { }
.nav-item { }
.nav-item_active { }
/* ❌ Bad */
.Button { }
.button_large_disabled { }
.nav-item-active-disabled { }
.camelCaseClass { }
```
### Nesting Depth
Maximum nesting depth is limited to 3 levels (excluding pseudo-classes):
```less
/* ✅ Good */
.component {
.header {
.title {
color: blue;
}
}
}
/* ❌ Bad */
.component {
.header {
.title {
.text {
.span { // Too deep!
color: blue;
}
}
}
}
}
```
### Global Selectors
First-level `:global` selectors are disallowed:
```less
/* ❌ Bad */
:global {
.some-class {
color: red;
}
}
/* ✅ Good */
.component {
:global {
.some-class {
color: red;
}
}
}
```
### Important Declarations
The use of `!important` is prohibited:
```css
/* ❌ Bad */
.class {
color: red !important;
}
/* ✅ Good */
.class {
color: red;
}
```
## Examples
### Basic Less File
```less
// Good example following all rules
.card {
padding: 16px;
border: 1px solid #ccc;
border-radius: 4px;
&-header {
margin-bottom: 12px;
font-weight: bold;
&_featured {
background-color: #f0f0f0;
}
}
&-content {
line-height: 1.5;
}
}
```
### With Tailwind Classes
```less
.custom-component {
@apply flex items-center justify-between;
&-item {
@apply px-4 py-2 rounded;
&_active {
@apply bg-blue-500 text-white;
}
}
}
```
## Development
### Running Examples
Test the configuration against example files:
```bash
rush stylelint-config example
```
This will run stylelint against the files in the `examples/` directory.
### Custom Rules
The package includes a custom plugin located at `plugins/plugin-disallow-nesting-level-one-global.js` that prevents first-level `:global` selectors.
## Dependencies
### Runtime Dependencies
This package has no runtime dependencies.
### Development Dependencies
- **stylelint**: ^15.11.0 - Core stylelint engine
- **stylelint-config-standard**: ^34.0.0 - Standard CSS rules
- **stylelint-config-standard-less**: ^2.0.0 - Less-specific rules
- **stylelint-config-clean-order**: ^5.2.0 - CSS property ordering
- **stylelint-config-rational-order**: ^0.1.2 - Alternative property ordering
- **sucrase**: ^3.32.0 - TypeScript compilation
## License
Apache-2.0 License
---
For more information about stylelint configuration options, visit the [official stylelint documentation](https://stylelint.io/user-guide/configuration/).

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["./output"]
}
]
}

View File

@@ -0,0 +1,6 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
preset: 'node',
packageRoot: __dirname,
});

View File

@@ -0,0 +1,54 @@
// bad
.a1_b1_c1 {
margin: auto;
}
// bad
.a2-b2_c2-d2 {
margin: auto;
}
// bad
.a3-b3_c3_d3 {
margin: auto;
}
// bad
.a4-b4 {
&_c4_d4 {
margin: auto;
}
}
// bad
.a5-cammelCase {
margin: auto;
}
// good
.a5-b5-c5 {
margin: auto;
}
// good
.a6-b6-c6_d6 {
margin: auto;
}
// good
.a7_b7 {
margin: auto;
}
// good
.a8 {
&-b8 {
&-c8 {
margin: auto;
}
&_d8 {
margin: auto;
}
}
}

View File

@@ -0,0 +1,17 @@
// bad
// bad
/* stylelint-disable plugin/disallow-first-level-global */
:global {
.semi-button {
width: 300px;
}
}
// ok
.a {
:global {
.semi-button {
width: 300px;
}
}
}

View File

@@ -0,0 +1,28 @@
// bad
.a1 {
.b1 {
.c1 {
.d1 {
.e1 {
margin: auto;
}
}
}
}
}
// good
.a2 .b2 .c2 .d2 .e2 {
margin: auto;
}
// still good
.a3 .b3 {
.c3 {
.d3 {
.e3 {
margin: auto;
}
}
}
}

View File

@@ -0,0 +1,10 @@
// avoid
.a {
opacity: 0 !important;
}
// if you have to
.b {
/* stylelint-disable-next-line declaration-no-important */
opacity: 0 !important;
}

View File

@@ -0,0 +1,27 @@
{
"name": "@coze-arch/stylelint-config",
"version": "1.0.0",
"description": "",
"keywords": [],
"license": "Apache-2.0",
"author": "liukaizhan.038@bytedance.com",
"main": "src/index.js",
"scripts": {
"build": "exit 0",
"example": "stylelint './examples/*.{css,less}'",
"lint": "eslint ./"
},
"dependencies": {},
"devDependencies": {
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@types/node": "^18",
"stylelint": "^15.11.0",
"stylelint-config-clean-order": "^5.2.0",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-recommended": "^13.0.0",
"stylelint-config-standard": "^34.0.0",
"stylelint-config-standard-less": "^2.0.0",
"sucrase": "^3.32.0"
}
}

View File

@@ -0,0 +1,28 @@
const stylelint = require('stylelint');
const ruleName = 'plugin/disallow-first-level-global';
module.exports = stylelint.createPlugin(ruleName, function (ruleValue) {
if (ruleValue === null || ruleValue === undefined || ruleValue === false) {
return () => {
// Nop.
};
}
return function (postcssRoot, postcssResult) {
postcssRoot.walkRules(rule => {
if (rule.parent.type === 'root' && /:global/.test(rule.selector)) {
stylelint.utils.report({
ruleName,
result: postcssResult,
node: rule,
message: 'Disallow :global class with nesting level of 1',
});
}
});
};
});
module.exports.ruleName = ruleName;
module.exports.messages = stylelint.utils.ruleMessages(ruleName, {
expected: 'Disallow :global class with nesting level of 1',
});

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import { type Config } from 'stylelint';
/**
* Define an Lint config.
*
* @param config StyleLint config.
* @returns StyleLint config.
*/
export const defineConfig = (config: Config): Config => {
const { extends: rawExtends, rules = {}, ...userConfig } = config;
return {
// @ts-expect-error -- linter-disable-autofix
extends: [path.resolve(__dirname, '../.stylelintrc.js'), ...rawExtends],
rules: {
...rules,
},
...userConfig,
};
};

View File

@@ -0,0 +1,5 @@
require('sucrase/register/ts');
const { defineConfig } = require('./define-config');
module.exports = { defineConfig };

View File

@@ -0,0 +1,22 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"include": ["src"],
"compilerOptions": {
"sourceMap": false,
"esModuleInterop": true,
"target": "ESNext",
"strictNullChecks": true,
"rootDir": "./src",
"outDir": "./output",
"tsBuildInfoFile": "output/tsconfig.build.tsbuildinfo"
},
"references": [
{
"path": "../eslint-config/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,19 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "vitest.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"sourceMap": false,
"esModuleInterop": true,
"target": "ESNext",
"strictNullChecks": true
}
}

View File

@@ -0,0 +1,276 @@
# @coze-arch/tailwind-config
A comprehensive Tailwind CSS configuration package for the Coze design system, providing consistent theming, color palettes, and semantic design tokens across all applications.
## Features
- 🎨 **Complete Design System**: Pre-configured colors, spacing, typography, and component styles
- 🌙 **Dark Mode Support**: Built-in light/dark theme switching with CSS variables
- 🎯 **Semantic Classes**: Meaningful utility classes like `coz-fg-primary`, `coz-bg-secondary`
- 🧩 **Component-Ready**: Pre-defined styles for buttons, inputs, and other UI components
- 🎨 **Rich Color Palette**: Extensive color system including brand, functional, and semantic colors
- 📐 **Consistent Spacing**: Standardized spacing system across all dimensions
- 🔧 **Design Token Integration**: Support for converting design tokens to Tailwind config
## Get Started
### Installation
```bash
# Install the package in your workspace
pnpm add @coze-arch/tailwind-config@workspace:*
# Update Rush to install dependencies
rush update
```
### Basic Usage
In your `tailwind.config.js`:
```javascript
const cozeConfig = require('@coze-arch/tailwind-config');
module.exports = {
...cozeConfig,
content: [
'./src/**/*.{js,ts,jsx,tsx}',
// your content paths
],
// extend or override as needed
theme: {
extend: {
...cozeConfig.theme.extend,
// your custom extensions
},
},
};
```
### Using the Coze Plugin
For semantic utilities and CSS variables:
```javascript
const cozePlugin = require('@coze-arch/tailwind-config/coze');
module.exports = {
// ... your config
plugins: [
cozePlugin,
// other plugins
],
};
```
### Design Token Integration
Convert design tokens to Tailwind configuration:
```javascript
import { designTokenToTailwindConfig, getPackagesContents } from '@coze-arch/tailwind-config/design-token';
const tokenConfig = designTokenToTailwindConfig(yourDesignTokens);
module.exports = {
content: [
'./src/**/*.{js,ts,jsx,tsx}',
...getPackagesContents(), // Auto-discover package contents
],
theme: {
extend: tokenConfig,
},
};
```
## API Reference
### Main Configuration
The default export provides a complete Tailwind configuration with:
#### Colors
```javascript
// Brand colors
'text-brand-5' // Primary brand color
'bg-brand-1' // Light brand background
'border-brand-3' // Brand border
// Semantic colors
'text-foreground-3' // Primary text
'text-foreground-2' // Secondary text
'bg-background-1' // Primary background
'bg-background-0' // Secondary background
// Functional colors
'text-red-5' // Error/danger
'text-yellow-5' // Warning
'text-green-5' // Success
```
#### Spacing & Sizing
```javascript
// Semantic spacing
'p-normal' // 32px padding
'm-small' // 20px margin
'gap-mini' // 16px gap
// Precise spacing
'w-320px' // 320px width
'h-240px' // 240px height
'p-24px' // 24px padding
```
#### Typography
```javascript
// Font sizes
'text-mini' // 10px
'text-base' // 12px
'text-lg' // 14px
'text-xl' // 15px
'text-xxl' // 16px
'text-24px' // 24px
```
### Coze Plugin
The Coze plugin adds semantic utility classes and CSS variables:
```javascript
// Semantic foreground classes
'coz-fg-primary' // Primary text color
'coz-fg-secondary' // Secondary text color
'coz-fg-hglt' // Highlight text color
// Semantic background classes
'coz-bg-primary' // Primary background
'coz-bg-secondary' // Secondary background
'coz-mg-hglt' // Highlight background
// Component-specific classes
'coz-btn-rounded-normal' // Button border radius
'coz-input-height-large' // Input height
'coz-shadow-large' // Large shadow
```
### Design Token Functions
#### `designTokenToTailwindConfig(tokenJson)`
Converts design tokens to Tailwind configuration:
```javascript
const tokenConfig = designTokenToTailwindConfig({
palette: {
light: { 'primary-500': '#3b82f6' },
dark: { 'primary-500': '#60a5fa' }
},
tokens: {
color: {
light: { 'primary-color': 'var(primary-500)' },
dark: { 'primary-color': 'var(primary-500)' }
},
spacing: {
'spacing-sm': '8px',
'spacing-md': '16px'
}
}
});
```
#### `getPackagesContents(subPath?)`
Auto-discovers package source files for content configuration:
```javascript
const contents = getPackagesContents();
// Returns: [
// '/path/to/package1/src/**/*.{ts,tsx}',
// '/path/to/package2/src/**/*.{ts,tsx}',
// ...
// ]
```
## Development
### Project Structure
```
src/
├── index.js # Main Tailwind configuration
├── coze.js # Coze plugin with semantic utilities
├── design-token.ts # Design token conversion utilities
├── light.js # Light theme CSS variables
└── dark.js # Dark theme CSS variables
```
### Theme System
The package uses CSS variables for theming:
```css
:root {
--coze-brand-5: 81, 71, 255;
--coze-fg-3: 15, 21, 40;
--coze-bg-1: 247, 247, 252;
}
.dark {
--coze-brand-5: 166, 166, 255;
--coze-fg-3: 255, 255, 255;
--coze-bg-1: 24, 28, 43;
}
```
Colors are defined as RGB values to support alpha transparency:
```css
.text-brand-5 {
color: rgba(var(--coze-brand-5), 1);
}
.bg-brand-1 {
background-color: rgba(var(--coze-brand-1), var(--coze-brand-1-alpha));
}
```
### Adding New Colors
1. Add the RGB values to `light.js` and `dark.js`
2. Add alpha values for transparency support
3. Update the main configuration in `index.js`
4. Add semantic classes to `coze.js` if needed
### Testing
```bash
# Run linting
pnpm lint
# Build (no-op for this package)
pnpm build
```
## Dependencies
### Runtime Dependencies
- **tailwindcss** (~3.3.3) - Core Tailwind CSS framework
- **@tailwindcss/forms** (^0.5.7) - Form styling plugin
- **@tailwindcss/nesting** (latest) - CSS nesting support
- **postcss** (^8.4.32) - CSS transformation tool
- **postcss-loader** (^7.3.3) - Webpack PostCSS loader
- **autoprefixer** (^10.4.16) - CSS vendor prefixing
### Development Dependencies
- **@coze-arch/eslint-config** (workspace:*) - Shared ESLint configuration
- **@coze-arch/ts-config** (workspace:*) - Shared TypeScript configuration
- **@types/node** (^18) - Node.js type definitions
## License
This package is part of the Coze architecture and follows the project's licensing terms.

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,7 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
preset: 'node',
packageRoot: __dirname,
rules: {},
});

View File

@@ -0,0 +1,35 @@
{
"name": "@coze-arch/tailwind-config",
"version": "0.0.1",
"author": "huangjian@bytedance.com",
"maintainers": [],
"exports": {
".": "./src/index.js",
"./coze": "./src/coze.js",
"./design-token": "./src/design-token.ts"
},
"main": "src/index.js",
"scripts": {
"build": "exit",
"dev": "npm run build -- -w",
"lint": "eslint ./ --cache --quiet",
"test": "exit",
"test:cov": "exit"
},
"dependencies": {
"@coze-arch/monorepo-kits": "workspace:*",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/nesting": "latest",
"autoprefixer": "^10.4.16",
"fast-glob": "^3.2.11",
"postcss": "^8.4.32",
"postcss-loader": "^7.3.3",
"tailwindcss": "~3.3.3"
},
"devDependencies": {
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@types/node": "^18"
}
}

View File

@@ -0,0 +1,258 @@
// tailwindcss-plugin.js
const plugin = require('tailwindcss/plugin');
// theme colors
const lightModeVariables = require('./light');
const darkModeVariables = require('./dark');
// 用于生成 CSS 变量的帮助函数
function generateCssVariables(variables, theme) {
return Object.entries(variables).reduce((acc, [key, value]) => {
acc[`--${key}`] = theme ? theme(value) : value;
return acc;
}, {});
}
// 样式语义化
function generateSemanticVariables(semantics, theme, property) {
return Object.entries(semantics).map(([key, value]) => ({
[`.${key}`]: {
[property]: theme(value),
},
}));
}
const semanticForeground = {
/* Theme */
'coz-fg-hglt-plus': 'colors.foreground.5',
'coz-fg-hglt-plus-dim': 'colors.foreground.5',
'coz-fg-hglt': 'colors.brand.5',
'coz-fg-hglt-dim': 'colors.brand.3',
'coz-fg-plus': 'colors.foreground.4',
'coz-fg': 'colors.foreground.3',
'coz-fg-primary': 'colors.foreground.3',
'coz-fg-secondary': 'colors.foreground.2',
'coz-fg-dim': 'colors.foreground.1',
'coz-fg-white': 'colors.foreground.7',
'coz-fg-white-dim': 'colors.foreground.white',
'coz-fg-hglt-ai': 'colors.purple.5',
'coz-fg-hglt-ai-dim': 'colors.purple.3',
/* Functional Color */
'coz-fg-hglt-red': 'colors.red.5',
'coz-fg-hglt-red-dim': 'colors.red.3',
'coz-fg-hglt-yellow': 'colors.yellow.5',
'coz-fg-hglt-yellow-dim': 'colors.yellow.3',
'coz-fg-hglt-green': 'colors.green.5',
'coz-fg-hglt-green-dim': 'colors.green.3',
/* Chart, Tag Only */
'coz-fg-color-orange': 'colors.yellow.5',
'coz-fg-color-orange-dim': 'colors.yellow.3',
'coz-fg-color-emerald': 'colors.green.5',
'coz-fg-color-emerald-dim': 'colors.green.3',
'coz-fg-color-cyan': 'colors.cyan.50',
'coz-fg-color-cyan-dim': 'colors.cyan.30',
'coz-fg-color-blue': 'colors.blue.50',
'coz-fg-color-blue-dim': 'colors.blue.30',
'coz-fg-color-purple': 'colors.purple.50',
'coz-fg-color-purple-dim': 'colors.purple.30',
'coz-fg-color-magenta': 'colors.magenta.50',
'coz-fg-color-magenta-dim': 'colors.magenta.3',
'coz-fg-color-yellow': 'colors.yellow.50',
'coz-fg-color-yellow-dim': 'colors.yellow.30',
/* Code Only */
'coz-fg-hglt-orange': 'colors.orange.5',
'coz-fg-hglt-orange-dim': 'colors.orange.3',
'coz-fg-hglt-emerald': 'colors.emerald.5',
'coz-fg-hglt-emerald-dim': 'colors.emerald.3',
'coz-fg-hglt-cyan': 'colors.cyan.5',
'coz-fg-hglt-cyan-dim': 'colors.cyan.3',
'coz-fg-hglt-blue': 'colors.blue.5',
'coz-fg-hglt-blue-dim': 'colors.blue.3',
'coz-fg-hglt-purple': 'colors.purple.5',
'coz-fg-hglt-purple-dim': 'colors.purple.3',
'coz-fg-hglt-magenta': 'colors.magenta.5',
'coz-fg-hglt-magenta-dim': 'colors.magenta.3',
/* branding Only */
'coz-fg-color-brand': 'colors.brand.50',
'coz-fg-color-brand-dim': 'colors.brand.30',
'coz-fg-color-alternative': 'colors.alternative.50',
'coz-fg-color-alternative-dim': 'colors.alternative.30',
};
const semanticMiddleground = {
/* Theme */
'coz-mg-hglt-plus-pressed': 'colors.brand.7',
'coz-mg-hglt-plus-hovered': 'colors.brand.6',
'coz-mg-hglt-plus': 'colors.brand.5',
'coz-mg-hglt-plus-dim': 'colors.brand.3',
'coz-mg-hglt-secondary-pressed': 'colors.brand.2',
'coz-mg-hglt-secondary-hovered': 'colors.brand.1',
'coz-mg-hglt-secondary': 'colors.brand.0',
'coz-mg-hglt-secondary-red': 'colors.red.0',
'coz-mg-hglt-secondary-yellow': 'colors.yellow.0',
'coz-mg-hglt-secondary-green': 'colors.green.0',
'coz-mg-plus-pressed': 'colors.background.8',
'coz-mg-plus-hovered': 'colors.background.7',
'coz-mg-plus': 'colors.background.6',
'coz-mg-hglt-pressed': 'colors.brand.3',
'coz-mg-hglt-hovered': 'colors.brand.2',
'coz-mg-hglt-plus-ai-pressed': 'colors.purple.7',
'coz-mg-hglt-plus-ai-hovered': 'colors.purple.6',
'coz-mg-hglt-plus-ai': 'colors.purple.5',
'coz-mg-hglt-plus-ai-dim': 'colors.purple.3',
'coz-mg-hglt': 'colors.brand.1',
'coz-mg-hglt-ai-pressed': 'colors.purple.3',
'coz-mg-hglt-ai-hovered': 'colors.purple.2',
'coz-mg-hglt-ai': 'colors.purple.1',
/* Functional Color */
'coz-mg-hglt-plus-red-pressed': 'colors.red.7',
'coz-mg-hglt-plus-red-hovered': 'colors.red.6',
'coz-mg-hglt-plus-red': 'colors.red.5',
'coz-mg-hglt-plus-red-dim': 'colors.red.3',
'coz-mg-hglt-plus-yellow-pressed': 'colors.yellow.7',
'coz-mg-hglt-plus-yellow-hovered': 'colors.yellow.6',
'coz-mg-hglt-plus-yellow': 'colors.yellow.5',
'coz-mg-hglt-plus-yellow-dim': 'colors.yellow.3',
'coz-mg-hglt-plus-green-pressed': 'colors.green.7',
'coz-mg-hglt-plus-green-hovered': 'colors.green.6',
'coz-mg-hglt-plus-green': 'colors.green.5',
'coz-mg-hglt-plus-green-dim': 'colors.green.3',
'coz-mg-hglt-red-pressed': 'colors.red.3',
'coz-mg-hglt-red-hovered': 'colors.red.2',
'coz-mg-hglt-red': 'colors.red.1',
'coz-mg-hglt-yellow-pressed': 'colors.yellow.3',
'coz-mg-hglt-yellow-hovered': 'colors.yellow.2',
'coz-mg-hglt-yellow': 'colors.yellow.1',
'coz-mg-hglt-green-pressed': 'colors.green.3',
'coz-mg-hglt-green-hovered': 'colors.green.2',
'coz-mg-hglt-green': 'colors.green.1',
/* Card, Tag, Avatar Only */
'coz-mg-color-plus-orange': 'colors.yellow.5',
'coz-mg-color-plus-emerald': 'colors.green.5',
'coz-mg-color-plus-cyan': 'colors.cyan.50',
'coz-mg-color-plus-blue': 'colors.blue.50',
'coz-mg-color-plus-purple': 'colors.purple.50',
'coz-mg-color-plus-magenta': 'colors.magenta.50',
'coz-mg-color-plus-yellow': 'colors.yellow.50',
'coz-mg-color-orange-pressed': 'colors.yellow.3',
'coz-mg-color-orange-hovered': 'colors.yellow.2',
'coz-mg-color-orange': 'colors.yellow.1',
'coz-mg-color-emerald-pressed': 'colors.green.3',
'coz-mg-color-emerald-hovered': 'colors.green.2',
'coz-mg-color-emerald': 'colors.green.1',
'coz-mg-color-cyan-pressed': 'colors.cyan.30',
'coz-mg-color-cyan-hovered': 'colors.cyan.20',
'coz-mg-color-cyan': 'colors.cyan.10',
'coz-mg-color-blue-pressed': 'colors.blue.30',
'coz-mg-color-blue-hovered': 'colors.blue.20',
'coz-mg-color-blue': 'colors.blue.10',
'coz-mg-color-purple-pressed': 'colors.purple.30',
'coz-mg-color-purple-hovered': 'colors.purple.20',
'coz-mg-color-purple': 'colors.purple.10',
'coz-mg-color-magenta-pressed': 'colors.magenta.30',
'coz-mg-color-magenta-hovered': 'colors.magenta.20',
'coz-mg-color-magenta': 'colors.magenta.10',
'coz-mg-primary-pressed': 'colors.background.7',
'coz-mg-primary-hovered': 'colors.background.6',
'coz-mg-primary': 'colors.background.5',
'coz-mg-secondary-pressed': 'colors.background.6',
'coz-mg-secondary-hovered': 'colors.background.5',
'coz-mg-secondary': 'colors.background.4',
'coz-mg': 'colors.background.4',
'coz-mg-mask': 'colors.mask.5',
'coz-mg-table-fixed-hovered': 'colors.background.0',
'coz-mg-card-pressed': 'colors.background.3',
'coz-mg-card-hovered': 'colors.background.3',
'coz-mg-card': 'colors.background.3',
/** brand */
'coz-mg-color-plus-brand': 'colors.brand.50',
};
const semanticBackground = {
'coz-bg-max': 'colors.background.3',
'coz-bg-plus': 'colors.background.2',
'coz-bg-primary': 'colors.background.1',
'coz-bg': 'colors.background.1',
'coz-bg-secondary': 'colors.background.0',
};
const semanticShadow = {
'coz-shadow': 'boxShadow.normal',
'coz-shadow-large': 'boxShadow.large',
'coz-shadow-default': 'boxShadow.normal',
'coz-shadow-small': 'boxShadow.small',
};
// Add button rounded definitions
const buttonRounded = {
'coz-btn-rounded-large': 'btnBorderRadius.large',
'coz-btn-rounded-normal': 'btnBorderRadius.normal',
'coz-btn-rounded-small': 'btnBorderRadius.small',
'coz-btn-rounded-mini': 'btnBorderRadius.mini',
};
const inputRounded = {
'coz-input-rounded-large': 'inputBorderRadius.large',
'coz-input-rounded-normal': 'inputBorderRadius.normal',
'coz-input-rounded-small': 'inputBorderRadius.small',
};
const inputHeight = {
'coz-input-height-large': 'inputHeight.large',
'coz-input-height-normal': 'inputHeight.normal',
'coz-input-height-small': 'inputHeight.small',
};
const semanticStroke = {
'coz-stroke-hglt': 'colors.brand.5',
'coz-stroke-plus': 'colors.stroke.6',
'coz-stroke-primary': 'colors.stroke.5',
'coz-stroke-hglt-red': 'colors.red.5',
'coz-stroke-hglt-yellow': 'colors.yellow.5',
'coz-stroke-hglt-green': 'colors.green.5',
'coz-stroke-color-orange': 'colors.yellow.5',
'coz-stroke-color-emerald': 'colors.green.5',
'coz-stroke-color-cyan': 'colors.cyan.50',
'coz-stroke-color-blue': 'colors.blue.50',
'coz-stroke-color-purple': 'colors.purple.50',
'coz-stroke-color-magenta': 'colors.magenta.50',
'coz-stroke-color-yellow': 'colors.yellow.50',
'coz-stroke-color-brand': 'colors.brand.50',
'coz-stroke-opaque': 'colors.stroke.opaque',
'coz-stroke-max': 'colors.stroke.max',
};
module.exports = plugin(function ({ addBase, addUtilities, theme }) {
addBase({
':root': generateCssVariables(lightModeVariables),
'.dark': generateCssVariables(darkModeVariables),
});
addBase({
':root': {
...generateCssVariables(semanticForeground, theme),
...generateCssVariables(semanticMiddleground, theme),
...generateCssVariables(semanticBackground, theme),
...generateCssVariables(semanticStroke, theme),
...generateCssVariables(semanticShadow, theme),
...generateCssVariables(buttonRounded, theme),
...generateCssVariables(inputRounded, theme),
...generateCssVariables(inputHeight, theme),
},
});
addUtilities([
...generateSemanticVariables(semanticForeground, theme, 'color'),
...generateSemanticVariables(
semanticMiddleground,
theme,
'background-color',
),
...generateSemanticVariables(semanticBackground, theme, 'background-color'),
...generateSemanticVariables(semanticStroke, theme, 'border-color'),
...generateSemanticVariables(semanticShadow, theme, 'box-shadow'),
...generateSemanticVariables(buttonRounded, theme, 'border-radius'),
...generateSemanticVariables(inputRounded, theme, 'border-radius'),
...generateSemanticVariables(inputHeight, theme, 'height'),
]);
});

View File

@@ -0,0 +1,180 @@
// 暗色模式的 CSS 变量
const darkModeVariables = {
background: '2, 8, 23',
foreground: '249, 249, 249',
icon: '221, 0%, 90%',
'icon-dark': '221, 0%, 10%',
'icon-gray': '221, 0%, 100%',
'coze-fg-revert': '0, 0, 0',
'coze-fg-white': '255, 255, 255',
'coze-fg-7': '255, 255, 255',
'coze-fg-6': '0, 0, 0',
'coze-fg-5': '0, 0, 0',
'coze-fg-4': '255, 255, 255',
'coze-fg-3': '255, 255, 255',
'coze-fg-2': '255, 255, 255',
'coze-fg-1': '255, 255, 255',
'coze-bg-9': '255, 255, 255',
'coze-bg-8': '237, 240, 255',
'coze-bg-7': '237, 240, 255',
'coze-bg-6': '237, 240, 255',
'coze-bg-5': '241, 243, 255',
'coze-bg-4': '241, 243, 255',
'coze-bg-3': '39, 43, 58',
'coze-bg-2': '28, 32, 48',
'coze-bg-1': '24, 28, 43',
'coze-bg-0': '20 ,24, 37',
'coze-stroke-5': '153, 182, 255',
'coze-stroke-6': '153, 182, 255',
'coze-stroke-7': '233, 237, 255',
'coze-stroke-opaque': '41, 45, 60',
'coze-mask-5': '0, 0, 0',
'coze-shadow-0': '0, 0, 0',
'coze-brand-50': '85, 91, 255',
'coze-brand-30': '66, 88, 255',
'coze-brand-7': '194, 194, 255',
'coze-brand-6': '184, 184, 255',
'coze-brand-5': '166, 166, 255',
'coze-brand-3': '94, 94, 255',
'coze-brand-2': '89, 89, 255',
'coze-brand-1': '76, 76, 255',
'coze-brand-0': '76, 76, 255',
'coze-red-7': '255, 97, 110',
'coze-red-6': '255, 82, 96',
'coze-red-5': '255, 38, 56',
'coze-red-3': '245, 37, 54',
'coze-red-2': '245, 37, 54',
'coze-red-1': '242, 36, 53',
'coze-yellow-50': '255, 191, 0',
'coze-yellow-30': '156, 117, 0',
'coze-yellow-7': '255, 161, 84',
'coze-yellow-6': '255, 148, 61',
'coze-yellow-5': '255, 122, 13',
'coze-yellow-3': '194, 88, 2',
'coze-yellow-2': '191, 87, 2',
'coze-yellow-1': '178, 80, 0',
'coze-green-7': '0, 219, 69',
'coze-green-6': '0, 209, 66',
'coze-green-5': '0, 191, 64',
'coze-green-3': '0, 133, 53',
'coze-green-2': '0, 128, 51',
'coze-green-1': '0, 122, 41',
'coze-orange-5': '251, 173, 115',
'coze-orange-3': '199, 93, 18',
'coze-emerald-5': '48, 242, 161',
'coze-emerald-3': '6, 140, 102',
'coze-emerald-50': '0, 191, 128',
'coze-emerald-30': '0, 133, 88',
'coze-emerald-20': '0, 128, 85',
'coze-emerald-10': '0, 115, 76',
'coze-cyan-5': '57, 215, 229',
'coze-cyan-3': '8, 130, 163',
'coze-cyan-50': '0, 170, 204',
'coze-cyan-30': '0, 125, 150',
'coze-cyan-20': '0, 121, 145',
'coze-cyan-10': '0, 110, 133',
'coze-blue-5': '120, 176, 255',
'coze-blue-3': '60, 111, 229',
'coze-blue-50': '64, 128, 255',
'coze-blue-30': '23, 100, 255',
'coze-blue-20': '18, 97, 255',
'coze-blue-10': '8, 91, 255',
'coze-purple-7': '233, 189, 255',
'coze-purple-6': '229, 176, 255',
'coze-purple-5': '221, 153, 255',
'coze-purple-3': '189, 56, 255',
'coze-purple-2': '187, 51, 255',
'coze-purple-1': '181, 33, 255',
'coze-purple-50': '202, 97, 255',
'coze-purple-30': '185, 46, 255',
'coze-purple-20': '184, 41, 255',
'coze-purple-10': '180, 31, 255',
'coze-magenta-5': '255, 148, 210',
'coze-magenta-3': '250, 30, 188',
'coze-magenta-50': '255, 77, 195',
'coze-magenta-30': '255, 15, 175',
'coze-magenta-20': '255, 10, 173',
'coze-magenta-10': '255, 0, 169',
'coze-alternative-50': '202, 242, 0',
'coze-alternative-30': '111, 133, 0',
/* alpha */
'coze-fg-1-alpha': '0.22',
'coze-fg-2-alpha': '0.39',
'coze-fg-3-alpha': '0.79',
'coze-fg-4-alpha': '1',
'coze-fg-5-alpha': '1',
'coze-fg-6-alpha': '0.22',
'coze-fg-7-alpha': '1',
'coze-fg-revert-alpha': '1',
'coze-fg-white-alpha': '0.22',
'coze-bg-0-alpha': '1',
'coze-bg-1-alpha': '1',
'coze-bg-2-alpha': '1',
'coze-bg-3-alpha': '1',
'coze-bg-4-alpha': '0.02',
'coze-bg-5-alpha': '0.05',
'coze-bg-6-alpha': '0.08',
'coze-bg-7-alpha': '0.11',
'coze-bg-8-alpha': '0.14',
'coze-bg-9-alpha': '0.17',
'coze-stroke-5-alpha': '0.12',
'coze-stroke-6-alpha': '0.17',
'coze-stroke-7-alpha': '0.21',
'coze-brand-0-alpha': '0.2',
'coze-brand-1-alpha': '0.2',
'coze-brand-2-alpha': '0.32',
'coze-brand-3-alpha': '0.37',
'coze-brand-30-alpha': '0.41',
'coze-brand-50-alpha': '1',
'coze-red-1-alpha': '0.20',
'coze-red-2-alpha': '0.33',
'coze-red-3-alpha': '0.39',
'coze-yellow-50-alpha': '1',
'coze-yellow-30-alpha': '0.36',
'coze-yellow-1-alpha': '0.20',
'coze-yellow-2-alpha': '0.32',
'coze-yellow-3-alpha': '0.37',
'coze-green-1-alpha': '0.20',
'coze-green-2-alpha': '0.34',
'coze-green-3-alpha': '0.39',
'coze-orange-3-alpha': '0.36',
'coze-orange-5-alpha': '0.36',
'coze-emerald-5-alpha': '1',
'coze-emerald-3-alpha': '0.35',
'coze-emerald-50-alpha': '1',
'coze-emerald-30-alpha': '0.38',
'coze-emerald-20-alpha': '0.33',
'coze-emerald-10-alpha': '0.2',
'coze-cyan-5-alpha': '1',
'coze-cyan-3-alpha': '0.36',
'coze-cyan-50-alpha': '1',
'coze-cyan-30-alpha': '0.39',
'coze-cyan-20-alpha': '0.33',
'coze-cyan-10-alpha': '0.20',
'coze-blue-5-alpha': '1',
'coze-blue-3-alpha': '0.37',
'coze-blue-50-alpha': '1',
'coze-blue-30-alpha': '0.4',
'coze-blue-20-alpha': '0.34',
'coze-blue-10-alpha': '0.2',
'coze-purple-7-alpha': '1',
'coze-purple-6-alpha': '1',
'coze-purple-5-alpha': '1',
'coze-purple-3-alpha': '0.36',
'coze-purple-2-alpha': '0.31',
'coze-purple-1-alpha': '0.2',
'coze-purple-50-alpha': '1',
'coze-purple-30-alpha': '0.38',
'coze-purple-20-alpha': '0.33',
'coze-purple-10-alpha': '0.2',
'coze-magenta-5-alpha': '1',
'coze-magenta-3-alpha': '0.35',
'coze-magenta-50-alpha': '1',
'coze-magenta-30-alpha': '0.36',
'coze-magenta-20-alpha': '0.31',
'coze-magenta-10-alpha': '0.2',
'coze-alternative-30-alpha': '0.34',
};
module.exports = darkModeVariables;

View File

@@ -0,0 +1,108 @@
/*
* 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.
*/
// 消费者和生产者公共的 tailwind 配置和工具函数
export function designTokenToTailwindConfig(
tokenJson: Record<string, unknown>,
) {
const res = {
colors: {},
spacing: {},
borderRadius: {},
};
const palette = tokenJson.palette ?? {};
const tokens = tokenJson.tokens ?? {};
for (const [k, v] of Object.entries(tokens)) {
switch (k) {
case 'color': {
res.colors = colorTransformer(
v,
genColorValueFormatter(
palette as Record<string, Record<string, string>>,
),
);
break;
}
case 'spacing': {
res.spacing = spacingTransformer(v);
break;
}
case 'border-radius': {
res.borderRadius = borderRadiusTransformer(v);
break;
}
default: {
break;
}
}
}
return res;
}
function colorTransformer(
colorObj: Record<string, Record<string, string>>,
valueFormatter: (theme: string, colorValue: string) => string,
) {
const res = {};
for (const theme of Object.keys(colorObj)) {
const valueObj = colorObj[theme];
for (const [colorKey, colorValue] of Object.entries(valueObj)) {
const newColorKey = `${colorKey.split('-color-')?.[1] ?? ''}-${theme}`;
res[newColorKey] = valueFormatter(theme, colorValue);
}
}
return res;
}
function genColorValueFormatter(
palette: Record<string, Record<string, string>>,
) {
return (theme: string, colorValue: string) => {
const re = /var\((.+?)\)/;
const match = colorValue.match(re);
const whole = match?.[0] ?? '';
if (!whole) {
return colorValue;
}
const key = match?.[1] ?? '';
const valueObj = palette[theme];
const v = valueObj[key];
return colorValue.replace(whole, v);
};
}
function spacingTransformer(spacingObj: Record<string, string>) {
const res = {};
for (const [k, v] of Object.entries(spacingObj)) {
const newKey = `${k.replace('$spacing-', '')}`;
res[newKey] = v;
}
return res;
}
function borderRadiusTransformer(borderRadiusObj: Record<string, string>) {
const res = {};
for (const [k, v] of Object.entries(borderRadiusObj)) {
const newKey = `${k.replace('--semi-border-radius-', '')}`;
res[newKey] = v;
}
return res;
}
// 获取其他packages并且拼接上 /src/**/*.{ts,tsx}
export { getTailwindContents } from './tailwind-contents';

View File

@@ -0,0 +1,387 @@
module.exports = {
darkMode: 'class',
prefix: '',
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
foreground: {
DEFAULT: 'rgba(var(--foreground), 1)',
revert: 'rgba(var(--coze-fg-revert), var(--coze-fg-revert-alpha))',
white: 'rgba(var(--coze-fg-white), var(--coze-fg-white-alpha))',
7: 'rgba(var(--coze-fg-7), 1)',
6: 'rgba(var(--coze-fg-6), 1)',
5: 'rgba(var(--coze-fg-5), var(--coze-fg-5-alpha))',
4: 'rgba(var(--coze-fg-4), var(--coze-fg-4-alpha))',
3: 'rgba(var(--coze-fg-3), var(--coze-fg-3-alpha))',
2: 'rgba(var(--coze-fg-2), var(--coze-fg-2-alpha))',
1: 'rgba(var(--coze-fg-1), var(--coze-fg-1-alpha))',
},
background: {
DEFAULT: 'rgba(var(--background), 1)',
9: 'rgba(var(--coze-bg-9), var(--coze-bg-9-alpha))',
8: 'rgba(var(--coze-bg-8), var(--coze-bg-8-alpha))',
7: 'rgba(var(--coze-bg-7), var(--coze-bg-7-alpha))',
6: 'rgba(var(--coze-bg-6), var(--coze-bg-6-alpha))',
5: 'rgba(var(--coze-bg-5), var(--coze-bg-5-alpha))',
4: 'rgba(var(--coze-bg-4), var(--coze-bg-4-alpha))',
3: 'rgba(var(--coze-bg-3), var(--coze-bg-3-alpha))',
2: 'rgba(var(--coze-bg-2), var(--coze-bg-2-alpha))',
1: 'rgba(var(--coze-bg-1), var(--coze-bg-1-alpha))',
0: 'rgba(var(--coze-bg-0), 1)',
},
brand: {
DEFAULT: 'rgba(var(--coze-brand-7), 1)',
linear: 'rgba(var(--coze-brand-5), 0)',
50: 'rgba(var(--coze-brand-50), var(--coze-brand-50-alpha))',
30: 'rgba(var(--coze-brand-30), var(--coze-brand-30-alpha))',
7: 'rgba(var(--coze-brand-7), 1)',
6: 'rgba(var(--coze-brand-6), 1)',
5: 'rgba(var(--coze-brand-5), 1)',
3: 'rgba(var(--coze-brand-3), var(--coze-brand-3-alpha))',
2: 'rgba(var(--coze-brand-2), var(--coze-brand-2-alpha))',
1: 'rgba(var(--coze-brand-1), var(--coze-brand-1-alpha))',
0: 'rgba(var(--coze-brand-0), var(--coze-brand-0-alpha))',
},
red: {
DEFAULT: 'rgba(var(--coze-red-7), 1)',
linear: 'rgba(var(--coze-red-5), 0)',
7: 'rgba(var(--coze-red-7), 1)',
6: 'rgba(var(--coze-red-6), 1)',
5: 'rgba(var(--coze-red-5), 1)',
3: 'rgba(var(--coze-red-3), var(--coze-red-3-alpha))',
2: 'rgba(var(--coze-red-2), var(--coze-red-2-alpha))',
1: 'rgba(var(--coze-red-1), var(--coze-red-1-alpha))',
0: 'rgba(var(--coze-red-0), var(--coze-red-0-alpha))',
},
yellow: {
DEFAULT: 'rgba(var(--coze-yellow-7), 1)',
linear: 'rgba(var(--coze-yellow-5), 0)',
50: 'rgba(var(--coze-yellow-50), var(--coze-yellow-50-alpha))',
30: 'rgba(var(--coze-yellow-30), var(--coze-yellow-30-alpha))',
7: 'rgba(var(--coze-yellow-7), 1)',
6: 'rgba(var(--coze-yellow-6), 1)',
5: 'rgba(var(--coze-yellow-5), 1)',
3: 'rgba(var(--coze-yellow-3), var(--coze-yellow-3-alpha))',
2: 'rgba(var(--coze-yellow-2), var(--coze-yellow-2-alpha))',
1: 'rgba(var(--coze-yellow-1), var(--coze-yellow-1-alpha))',
0: 'rgba(var(--coze-yellow-0), var(--coze-yellow-0-alpha))',
},
green: {
DEFAULT: 'rgba(var(--coze-green-7), 1)',
linear: 'rgba(var(--coze-green-5), 0)',
7: 'rgba(var(--coze-green-7), 1)',
6: 'rgba(var(--coze-green-6), 1)',
5: 'rgba(var(--coze-green-5), 1)',
3: 'rgba(var(--coze-green-3), var(--coze-green-3-alpha))',
2: 'rgba(var(--coze-green-2), var(--coze-green-2-alpha))',
1: 'rgba(var(--coze-green-1), var(--coze-green-1-alpha))',
0: 'rgba(var(--coze-green-0), var(--coze-green-0-alpha))',
},
emerald: {
DEFAULT: 'rgba(var(--coze-emerald-5), 1)',
linear: 'rgba(var(--coze-emerald-5), 0)',
50: 'rgba(var(--coze-emerald-50), var(--coze-emerald-50-alpha))',
30: 'rgba(var(--coze-emerald-30), var(--coze-emerald-30-alpha))',
20: 'rgba(var(--coze-emerald-20), 1)',
10: 'rgba(var(--coze-emerald-10), 1)',
5: 'rgba(var(--coze-emerald-5), 1)',
3: 'rgba(var(--coze-emerald-3), var(--coze-emerald-3-alpha))',
},
orange: {
DEFAULT: 'rgba(var(--coze-orange-5), 1)',
linear: 'rgba(var(--coze-orange-5), 0)',
5: 'rgba(var(--coze-orange-5), 1)',
3: 'rgba(var(--coze-orange-3), var(--coze-orange-3-alpha))',
1: 'rgba(var(--coze-orange-1), var(--coze-orange-1-alpha))',
},
alternative: {
DEFAULT: 'rgba(var(--coze-alternative-50), 1)',
50: 'rgba(var(--coze-alternative-50), 1)',
30: 'rgba(var(--coze-alternative-30), var(--coze-alternative-30-alpha))',
},
cyan: {
DEFAULT: 'rgba(var(--coze-cyan-5), 1)',
linear: 'rgba(var(--coze-cyan-5), 0)',
50: 'rgba(var(--coze-cyan-50), var(--coze-cyan-50-alpha))',
30: 'rgba(var(--coze-cyan-30), var(--coze-cyan-30-alpha))',
20: 'rgba(var(--coze-cyan-20), var(--coze-cyan-20-alpha))',
10: 'rgba(var(--coze-cyan-10), var(--coze-cyan-10-alpha))',
5: 'rgba(var(--coze-cyan-5), 1)',
3: 'rgba(var(--coze-cyan-3), var(--coze-cyan-3-alpha))',
},
blue: {
DEFAULT: 'rgba(var(--coze-blue-5), 1)',
linear: 'rgba(var(--coze-blue-5), 0)',
50: 'rgba(var(--coze-blue-50), var(--coze-blue-50-alpha))',
30: 'rgba(var(--coze-blue-30), var(--coze-blue-30-alpha))',
20: 'rgba(var(--coze-blue-20), var(--coze-blue-20-alpha))',
10: 'rgba(var(--coze-blue-10), var(--coze-blue-10-alpha))',
5: 'rgba(var(--coze-blue-5), var(--coze-blue-5-alpha))',
3: 'rgba(var(--coze-blue-3), var(--coze-blue-3-alpha))',
},
purple: {
DEFAULT: 'rgba(var(--coze-purple-5), 1)',
linear: 'rgba(var(--coze-purple-5), 0)',
50: 'rgba(var(--coze-purple-50), var(--coze-purple-50-alpha))',
30: 'rgba(var(--coze-purple-30), var(--coze-purple-30-alpha))',
20: 'rgba(var(--coze-purple-20), var(--coze-purple-20-alpha))',
10: 'rgba(var(--coze-purple-10), var(--coze-purple-10-alpha))',
7: 'rgba(var(--coze-purple-7), 1)',
6: 'rgba(var(--coze-purple-6), 1)',
5: 'rgba(var(--coze-purple-5), 1)',
3: 'rgba(var(--coze-purple-3), var(--coze-purple-3-alpha))',
2: 'rgba(var(--coze-purple-2), var(--coze-purple-2-alpha))',
1: 'rgba(var(--coze-purple-1), var(--coze-purple-1-alpha))',
},
magenta: {
DEFAULT: 'rgba(var(--coze-magenta-5), 1)',
linear: 'rgba(var(--coze-magenta-5), 0)',
50: 'rgba(var(--coze-magenta-50), var(--coze-magenta-50-alpha))',
30: 'rgba(var(--coze-magenta-30), var(--coze-magenta-30-alpha))',
20: 'rgba(var(--coze-magenta-20), var(--coze-magenta-20-alpha))',
10: 'rgba(var(--coze-magenta-10), var(--coze-magenta-10-alpha))',
5: 'rgba(var(--coze-magenta-5), 1)',
3: 'rgba(var(--coze-magenta-3), var(--coze-magenta-3-alpha))',
},
black: {
DEFAULT: 'rgb(var(--black-6))',
7: 'rgb(var(--black-7))',
6: 'rgb(var(--black-6))',
5: 'rgb(var(--black-5))',
4: 'rgb(var(--black-4))',
3: 'rgb(var(--black-3))',
2: 'rgb(var(--black-2))',
1: 'rgb(var(--black-1))',
},
white: {
DEFAULT: 'rgb(var(--white-1))',
6: 'rgb(var(--white-6))',
5: 'rgb(var(--white-5))',
4: 'rgb(var(--white-4))',
3: 'rgb(var(--white-3))',
2: 'rgb(var(--white-2))',
1: 'rgb(var(--white-1))',
},
stroke: {
DEFAULT: 'rgba(var(--coze-stroke-5), var(--coze-stroke-5-alpha))',
max: 'rgba(var(--coze-stroke-7), var(--coze-stroke-7-alpha))',
6: 'rgba(var(--coze-stroke-6), var(--coze-stroke-6-alpha))',
5: 'rgba(var(--coze-stroke-5), var(--coze-stroke-5-alpha))',
opaque: 'rgb(var(--coze-stroke-opaque))',
},
mask: {
DEFAULT: 'rgba(var(--coze-mask-5), 0.4)',
5: 'rgba(var(--coze-mask-5), 0.4)',
},
icon: {
DEFAULT: 'hsl(var(--icon))',
gray: 'hsl(var(--icon-gray))',
dark: 'hsl(var(--icon-dark))',
},
fornax: {
DEFAULT: 'rgba(var(--coze-fornax-7), 1)',
7: 'var(--coze-fornax-7)',
},
},
fontSize: {
mini: 'var(--coze-10)',
base: 'var(--coze-12)',
lg: 'var(--coze-14)',
xl: 'var(--coze-15)',
xxl: 'var(--coze-16)',
'18px': 'var(--coze-18)',
'20px': 'var(--coze-20)',
'22px': 'var(--coze-22)',
'24px': 'var(--coze-24)',
'26px': 'var(--coze-26)',
'28px': 'var(--coze-28)',
'30px': 'var(--coze-30)',
'32px': 'var(--coze-32)',
'36px': 'var(--coze-36)',
'48px': 'var(--coze-48)',
'64px': 'var(--coze-64)',
},
spacing: {
DEFAULT: 'var(--coze-8)',
xxl: 'var(--coze-96)',
xl: 'var(--coze-80)',
md: 'var(--coze-64)',
mm: 'var(--coze-48)',
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-20)',
mini: 'var(--coze-16)',
'1080px': 'var(--coze-1080)',
'800px': 'var(--coze-800)',
'640px': 'var(--coze-640)',
'480px': 'var(--coze-480)',
'320px': 'var(--coze-320)',
'240px': 'var(--coze-240)',
'200px': 'var(--coze-200)',
'160px': 'var(--coze-160)',
'120px': 'var(--coze-120)',
'96px': 'var(--coze-96)',
'80px': 'var(--coze-80)',
'64px': 'var(--coze-64)',
'48px': 'var(--coze-48)',
'40px': 'var(--coze-40)',
'32px': 'var(--coze-32)',
'30px': 'var(--coze-30)',
'28px': 'var(--coze-28)',
'26px': 'var(--coze-26)',
'24px': 'var(--coze-24)',
'22px': 'var(--coze-22)',
'20px': 'var(--coze-20)',
'18px': 'var(--coze-18)',
'16px': 'var(--coze-16)',
'15px': 'var(--coze-15)',
'14px': 'var(--coze-14)',
'12px': 'var(--coze-12)',
'10px': 'var(--coze-10)',
'9px': 'var(--coze-9)',
'8px': 'var(--coze-8)',
'6px': 'var(--coze-6)',
'5px': 'var(--coze-5)',
'4px': 'var(--coze-4)',
'3px': 'var(--coze-3)',
'2px': 'var(--coze-2)',
'1px': 'var(--coze-1)',
},
borderWidth: {
DEFAULT: 'var(--coze-1)',
normal: 'var(--coze-1)',
half: 'var(--coze-0-5)',
},
borderRadius: {
DEFAULT: 'var(--coze-8)',
ultra: 'var(--coze-40)',
xxl: 'var(--coze-24)',
xl: 'var(--coze-16)',
md: 'var(--coze-12)',
m: 'var(--coze-10)',
normal: 'var(--coze-8)',
small: 'var(--coze-6)',
little: 'var(--coze-5)',
mini: 'var(--coze-4)',
tiny: 'var(--coze-2)',
},
btnBorderRadius: {
large: 'var(--coze-10)',
normal: 'var(--coze-8)',
small: 'var(--coze-5)',
mini: 'var(--coze-4)',
},
inputBorderRadius: {
large: 'var(--coze-10)',
normal: 'var(--coze-8)',
small: 'var(--coze-6)',
},
inputHeight: {
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-24)',
},
height: {
DEFAULT: 'var(--coze-32)',
'1080px': 'var(--coze-1080)',
'800px': 'var(--coze-800)',
'640px': 'var(--coze-640)',
'480px': 'var(--coze-480)',
'320px': 'var(--coze-320)',
'240px': 'var(--coze-240)',
'200px': 'var(--coze-200)',
'160px': 'var(--coze-160)',
'120px': 'var(--coze-120)',
xxl: 'var(--coze-96)',
xl: 'var(--coze-80)',
md: 'var(--coze-64)',
m: 'var(--coze-48)',
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-24)',
petite: 'var(--coze-18)',
mini: 'var(--coze-16)',
},
minHeight: {
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-24)',
petite: 'var(--coze-18)',
mini: 'var(--coze-16)',
},
lineHeight: {
mini: 'var(--coze-16)',
'12px': 'var(--coze-12)',
'14px': 'var(--coze-14)',
'16px': 'var(--coze-16)',
'20px': 'var(--coze-20)',
'22px': 'var(--coze-22)',
'24px': 'var(--coze-24)',
'28px': 'var(--coze-28)',
'36px': 'var(--coze-36)',
},
width: {
DEFAULT: 'var(--coze-32)',
'1080px': 'var(--coze-1080)',
'800px': 'var(--coze-800)',
'640px': 'var(--coze-640)',
'480px': 'var(--coze-480)',
'320px': 'var(--coze-320)',
'240px': 'var(--coze-240)',
'200px': 'var(--coze-200)',
'160px': 'var(--coze-160)',
'120px': 'var(--coze-120)',
xxl: 'var(--coze-96)',
xl: 'var(--coze-80)',
md: 'var(--coze-64)',
m: 'var(--coze-48)',
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-24)',
petite: 'var(--coze-18)',
mini: 'var(--coze-16)',
},
minWidth: {
large: 'var(--coze-40)',
normal: 'var(--coze-32)',
small: 'var(--coze-24)',
petite: 'var(--coze-18)',
mini: 'var(--coze-16)',
},
fill: theme => ({
DEFAULT: theme('colors.foreground.5'),
dark: theme('colors.foreground.5'),
light: theme('colors.foreground.3'),
black: theme('colors.black'),
white: theme('colors.white'),
}),
boxShadow: {
DEFAULT:
'0 4px 12px 0px rgba(var(--coze-shadow-0), 0.08), 0px 8px 24px 0px rgba(var(--coze-shadow-0), 0.04)',
small:
'0px 2px 6px 0px rgba(var(--coze-shadow-0), 0.04), 0px 4px 12px 0px rgba(var(--coze-shadow-0), 0.02)',
normal:
'0 4px 12px 0px rgba(var(--coze-shadow-0), 0.08), 0px 8px 24px 0px rgba(var(--coze-shadow-0), 0.04)',
large:
'0px 8px 24px 0px rgba(var(--coze-shadow-0), 0.16), 0px 16px 48px 0px rgba(var(--coze-shadow-0), 0.08)',
},
keyframes: {
'icon-down': {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(90deg)' },
},
'icon-up': {
'0%': { transform: 'rotate(90deg)' },
'100%': { transform: 'rotate(0deg)' },
},
},
animation: {
'icon-down': 'icon-down 0.2s ease-out',
'icon-up': 'icon-up 0.2s ease-out',
loading: '',
},
},
},
plugins: [],
};

View File

@@ -0,0 +1,251 @@
// 浅色模式的 CSS 变量
const lightModeVariables = {
background: '255, 255, 255',
foreground: '28, 28, 35',
icon: '221, 0%, 10%',
'icon-dark': '221, 0%, 10%',
'icon-gray': '221, 0%, 90%',
'black-7': '0, 0, 0',
'black-6': '16, 16, 16',
'black-5': '54, 61, 77',
'black-4': '102, 102, 104',
'black-3': '149, 149, 151',
'black-2': '173, 173, 175',
'black-1': '220, 220, 222',
'white-6': '209, 209, 211',
'white-5': '219, 219, 220',
'white-4': '228, 228, 230',
'white-3': '238, 238, 239',
'white-2': '248, 248, 248',
'white-1': '255, 255, 255',
'coze-fg-revert': '255, 255, 255',
'coze-fg-white': '255, 255, 255',
'coze-fg-7': '255, 255, 255',
'coze-fg-6': '255, 255, 255',
'coze-fg-5': '255, 255, 255',
'coze-fg-4': '8, 13, 30',
'coze-fg-3': '15, 21, 40',
'coze-fg-2': '32, 41, 69',
'coze-fg-1': '55, 67, 106',
// TODO: 需要删除bg9
'coze-bg-9': '6, 7, 9',
'coze-bg-8': '68, 83, 130',
'coze-bg-7': '75, 90, 140',
'coze-bg-6': '82, 100, 154',
'coze-bg-5': '87, 104, 161',
'coze-bg-4': '90, 108, 167',
'coze-bg-3': '255, 255, 255',
'coze-bg-2': '252, 252, 255',
'coze-bg-1': '247, 247, 252',
'coze-bg-0': '240, 240, 247',
'coze-stroke-5': '82, 100, 154',
'coze-stroke-6': '68, 83, 130',
'coze-stroke-7': '55, 67, 106',
'coze-stroke-opaque': '226, 228, 239',
'coze-mask-5': '0, 0, 0',
'coze-shadow-0': '0, 0, 0',
'coze-brand-50': '102, 108, 255',
'coze-brand-30': '163, 166, 255',
'coze-brand-7': '65, 43, 255',
'coze-brand-6': '69, 56, 255',
'coze-brand-5': '81, 71, 255',
'coze-brand-3': '150, 159, 255',
'coze-brand-2': '161, 170, 255',
'coze-brand-1': '171, 181, 255',
'coze-brand-0': '181, 191, 255',
'coze-red-7': '222, 22, 39',
'coze-red-6': '227, 36, 52',
'coze-red-5': '229, 50, 65',
'coze-red-3': '250, 138, 148',
'coze-red-2': '252, 149, 157',
'coze-red-1': '255, 163, 171',
'coze-red-0': '255, 173, 180',
'coze-yellow-50': '242, 182, 0',
'coze-yellow-30': '245, 184, 0',
'coze-yellow-7': '229, 104, 0',
'coze-yellow-6': '242, 109, 0',
'coze-yellow-5': '255, 115, 0',
'coze-yellow-3': '242, 161, 94',
'coze-yellow-2': '242, 169, 109',
'coze-yellow-1': '240, 174, 120',
'coze-yellow-0': '239, 179, 130',
'coze-green-7': '0, 161, 54',
'coze-green-6': '0, 168, 56',
'coze-green-5': '0, 178, 60',
'coze-green-3': '79, 201, 120',
'coze-green-2': '93, 207, 131',
'coze-green-1': '105, 209, 140',
'coze-green-0': '116, 212, 149',
'coze-orange-5': '199, 66, 0',
'coze-orange-3': '242, 148, 65',
'coze-emerald-5': '0, 128, 74',
'coze-emerald-3': '41, 204, 114',
'coze-emerald-50': '0, 184, 122',
'coze-emerald-30': '54, 209, 158',
'coze-emerald-20': '66, 214, 165',
'coze-emerald-10': '103, 229, 188',
'coze-cyan-5': '0, 124, 135',
'coze-cyan-3': '47, 196, 189',
'coze-cyan-50': '0, 163, 163',
'coze-cyan-30': '62, 199, 199',
'coze-cyan-20': '73, 204, 204',
'coze-cyan-10': '84, 209, 209',
'coze-blue-5': '43, 87, 217',
'coze-blue-3': '120, 170, 250',
'coze-blue-50': '61, 121, 242',
'coze-blue-30': '131, 172, 252',
'coze-blue-20': '141, 178, 252',
'coze-blue-10': '153, 187, 255',
'coze-purple-7': '148, 0, 222',
'coze-purple-6': '157, 0, 235',
'coze-purple-5': '167, 0, 250',
'coze-purple-3': '213, 128, 255',
'coze-purple-2': '218, 145, 255',
'coze-purple-1': '224, 163, 255',
'coze-purple-50': '192, 66, 255',
'coze-purple-30': '217, 143, 255',
'coze-purple-20': '221, 153, 255',
'coze-purple-10': '224, 163, 255',
'coze-magenta-5': '209, 0, 157',
'coze-magenta-3': '245, 120, 197',
'coze-magenta-50': '242, 48, 177',
'coze-magenta-30': '252, 134, 213',
'coze-magenta-20': '252, 144, 216',
'coze-magenta-10': '255, 158, 222',
'coze-alternative-50': '191, 229, 0',
'coze-alternative-30': '175, 209, 0',
'coze-1080': '1080px',
'coze-800': '800px',
'coze-640': '640px',
'coze-480': '480px',
'coze-320': '320px',
'coze-240': '240px',
'coze-200': '200px',
'coze-160': '160px',
'coze-120': '120px',
'coze-96': '96px',
'coze-80': '80px',
'coze-64': '64px',
'coze-48': '48px',
'coze-40': '40px',
'coze-38': '38px',
'coze-36': '36px',
'coze-32': '32px',
'coze-30': '30px',
'coze-28': '28px',
'coze-26': '26px',
'coze-24': '24px',
'coze-22': '22px',
'coze-20': '20px',
'coze-18': '18px',
'coze-16': '16px',
'coze-15': '15px',
'coze-14': '14px',
'coze-12': '12px',
'coze-10': '10px',
'coze-9': '9px',
'coze-8': '8px',
'coze-6': '6px',
'coze-5': '5px',
'coze-4': '4px',
'coze-3': '3px',
'coze-2': '2px',
'coze-1': '1px',
// TODO: rspress编译不出来需要通过一些工具处理目前没有用到暂时注释处理
// 'coze-0.5': '0.5px',
'coze-0-5': '0.5px',
/* alpha */
'coze-fg-1-alpha': '0.38',
'coze-fg-2-alpha': '0.62',
'coze-fg-3-alpha': '0.82',
'coze-fg-4-alpha': '0.9',
'coze-fg-5-alpha': '1',
'coze-fg-6-alpha': '1',
'coze-fg-7-alpha': '1',
'coze-fg-revert-alpha': '1',
'coze-fg-white-alpha': '1',
'coze-bg-0-alpha': '1',
'coze-bg-1-alpha': '1',
'coze-bg-2-alpha': '1',
'coze-bg-3-alpha': '1',
'coze-bg-4-alpha': '0.04',
'coze-bg-5-alpha': '0.08',
'coze-bg-6-alpha': '0.13',
'coze-bg-7-alpha': '0.19',
'coze-bg-8-alpha': '0.25',
// TODO: 需要删除bg9
'coze-bg-9-alpha': '0.16',
'coze-stroke-5-alpha': '0.13',
'coze-stroke-6-alpha': '0.25',
'coze-stroke-7-alpha': '0.38',
'coze-brand-0-alpha': '0.23',
'coze-brand-1-alpha': '0.3',
'coze-brand-2-alpha': '0.38',
'coze-brand-3-alpha': '0.45',
'coze-brand-5-alpha': '1',
'coze-brand-6-alpha': '1',
'coze-brand-7-alpha': '1',
'coze-brand-30-alpha': '0.45',
'coze-brand-50-alpha': '1',
'coze-red-0-alpha': '0.23',
'coze-red-1-alpha': '0.3',
'coze-red-2-alpha': '0.38',
'coze-red-3-alpha': '0.45',
'coze-yellow-50-alpha': '1',
'coze-yellow-30-alpha': '0.45',
'coze-yellow-0-alpha': '0.23',
'coze-yellow-1-alpha': '0.3',
'coze-yellow-2-alpha': '0.38',
'coze-yellow-3-alpha': '0.45',
'coze-yellow-5-alpha': '1',
'coze-yellow-6-alpha': '1',
'coze-yellow-7-alpha': '1',
'coze-green-0-alpha': '0.23',
'coze-green-1-alpha': '0.3',
'coze-green-2-alpha': '0.38',
'coze-green-3-alpha': '0.45',
'coze-green-5-alpha': '1',
'coze-green-6-alpha': '1',
'coze-green-7-alpha': '1',
'coze-orange-5-alpha': '1',
'coze-orange-3-alpha': '0.45',
'coze-emerald-5-alpha': '1',
'coze-emerald-3-alpha': '0.45',
'coze-emerald-50-alpha': '1',
'coze-emerald-30-alpha': '0.55',
'coze-emerald-20-alpha': '0.45',
'coze-emerald-10-alpha': '0.2',
'coze-cyan-5-alpha': '1',
'coze-cyan-3-alpha': '0.45',
'coze-cyan-50-alpha': '1',
'coze-cyan-30-alpha': '0.45',
'coze-cyan-20-alpha': '0.38',
'coze-cyan-10-alpha': '0.3',
'coze-blue-5-alpha': '1',
'coze-blue-3-alpha': '0.45',
'coze-blue-50-alpha': '1',
'coze-blue-30-alpha': '0.45',
'coze-blue-20-alpha': '0.38',
'coze-blue-10-alpha': '0.3',
'coze-purple-7-alpha': '1',
'coze-purple-6-alpha': '1',
'coze-purple-5-alpha': '1',
'coze-purple-3-alpha': '0.45',
'coze-purple-2-alpha': '0.38',
'coze-purple-1-alpha': '0.3',
'coze-purple-50-alpha': '1',
'coze-purple-30-alpha': '0.45',
'coze-purple-20-alpha': '0.38',
'coze-purple-10-alpha': '0.3',
'coze-magenta-5-alpha': '1',
'coze-magenta-3-alpha': '0.45',
'coze-magenta-50-alpha': '1',
'coze-magenta-30-alpha': '0.45',
'coze-magenta-20-alpha': '0.38',
'coze-magenta-10-alpha': '0.3',
'coze-alternative-30-alpha': '0.45',
'coze-alternative-50-alpha': '1',
};
module.exports = lightModeVariables;

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import path from 'path';
import glob from 'fast-glob';
import {
lookupSubPackages,
getPackageLocation,
getPackageJson,
} from '@coze-arch/monorepo-kits';
export const getTailwindContents = (projectRoot: string) => {
if (!projectRoot) {
throw new Error('projectRoot is required');
}
const contents = [path.resolve(__dirname, '../src/**/*.{tsx,ts}')];
const subPackages = lookupSubPackages(projectRoot);
const packageLocations = subPackages
.filter(p => {
const packageJson = getPackageJson(p);
const deps = [
...Object.keys(packageJson.dependencies || {}),
...Object.keys(packageJson.devDependencies || {}),
...Object.keys(packageJson.peerDependencies || {}),
];
return deps.includes('react');
})
.map(getPackageLocation);
contents.push(
...packageLocations
.filter(r => !!r)
.map(location => path.resolve(location, 'src/**/*.{ts,tsx}'))
.filter(pattern => glob.sync(pattern).length > 0),
);
// 兼容 coze-design 内部 tailwind 样式
contents.push('./node_modules/@coze-arch/coze-design/**/*.{js,jsx}');
return contents;
};

View File

@@ -0,0 +1,25 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"sourceMap": false,
"esModuleInterop": true,
"types": [],
"rootDir": "./src",
"outDir": "dist",
"allowJs": true,
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["./src/**/*.ts", "./src/**/*.json"],
"references": [
{
"path": "../eslint-config/tsconfig.build.json"
},
{
"path": "../../infra/utils/monorepo-kits/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,17 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "vitest.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"sourceMap": false,
"esModuleInterop": true
}
}

View File

@@ -0,0 +1,292 @@
# @coze-arch/ts-config
> Shared TypeScript configuration presets for the Coze Bot Studio platform
## Project Overview
This package provides standardized TypeScript configuration presets for all projects within the Coze Bot Studio monorepo. It offers multiple configuration options optimized for different project types (web applications, Node.js services, and base configurations) while ensuring consistency across the entire platform. The configurations include strict type checking, modern JavaScript features, and appropriate compiler options for optimal development experience and build performance.
## Features
- **Multiple Configuration Presets**: Web, Node.js, and base configurations for different project types
- **Strict Type Checking**: Comprehensive TypeScript strict mode settings for enhanced code quality
- **Modern JavaScript Support**: Target ES2022 with support for latest JavaScript features
- **Path Mapping**: Built-in support for module path resolution and aliases
- **Monorepo Optimized**: Configured for Rush.js monorepo structure with workspace references
- **Development Friendly**: Source maps, incremental compilation, and fast build settings
- **Library Support**: Appropriate settings for both applications and reusable libraries
## Get Started
### Installation
Add this package to your `package.json` dependencies and set it to `workspace:*` version:
```json
{
"devDependencies": {
"@coze-arch/ts-config": "workspace:*"
}
}
```
Then run:
```bash
rush update
```
### Basic Usage
#### Web Application Configuration
Create a `tsconfig.json` file in your project root:
```json
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}
```
#### Node.js Service Configuration
```json
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": [
"src/**/*"
]
}
```
#### Base Configuration (Library)
```json
{
"extends": "@coze-arch/ts-config/tsconfig.base.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"outDir": "./dist"
}
}
```
#### Build Configuration
For projects that need separate build configurations:
```json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"sourceMap": false,
"removeComments": true
},
"exclude": [
"**/*.test.ts",
"**/*.spec.ts",
"__tests__/**/*"
]
}
```
## API Reference
### Available Configurations
#### `tsconfig.web.json`
Optimized for web applications with React support.
**Key Features:**
- JSX support with `react-jsx` runtime
- DOM and ES2022 library support
- Module resolution optimized for web bundlers
- Strict mode enabled for better type safety
```json
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"@/*": ["*"],
"@components/*": ["components/*"]
}
}
}
```
#### `tsconfig.node.json`
Configured for Node.js applications and services.
**Key Features:**
- Node.js library support
- CommonJS and ES module interoperability
- Optimized for server-side development
- Appropriate module resolution for Node.js
```json
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"types": ["node", "jest"]
}
}
```
#### `tsconfig.base.json`
Base configuration suitable for libraries and shared packages.
**Key Features:**
- Minimal library dependencies
- Declaration file generation ready
- Flexible target environments
- Core TypeScript strict settings
### Common Compiler Options
All configurations include these base settings:
```typescript
{
"strict": true, // Enable all strict type checking
"noImplicitReturns": true, // Error on missing return statements
"noFallthroughCasesInSwitch": true, // Error on fallthrough cases
"noUncheckedIndexedAccess": true, // Strict array/object access
"exactOptionalPropertyTypes": true, // Exact optional property matching
"skipLibCheck": true, // Skip type checking of declaration files
"forceConsistentCasingInFileNames": true // Enforce consistent file naming
}
```
## Advanced Usage
### Project References
For monorepo projects with dependencies:
```json
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"references": [
{ "path": "../shared-utils" },
{ "path": "../ui-components" }
],
"compilerOptions": {
"composite": true
}
}
```
### Custom Path Mapping
```json
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@utils/*": ["src/utils/*"],
"@components/*": ["src/components/*"],
"@shared/*": ["../shared/src/*"]
}
}
}
```
### Environment-Specific Configurations
**Development:**
```json
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"sourceMap": true,
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo"
}
}
```
**Production:**
```json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"sourceMap": false,
"removeComments": true,
"declaration": false
}
}
```
## Development
### Available Scripts
The configurations are static JSON files, but the package includes:
- Validation scripts to ensure configuration consistency
- Example projects demonstrating proper usage
- Documentation updates when TypeScript evolves
### Project Structure
```
.
├── tsconfig.base.json # Base configuration
├── tsconfig.web.json # Web application preset
├── tsconfig.node.json # Node.js service preset
├── global.d.ts # Global type declarations
└── examples/ # Usage examples
├── web-app/
├── node-service/
└── library/
```
### Adding New Configurations
When adding new TypeScript configurations:
1. Extend from `tsconfig.base.json` for consistency
2. Document the specific use case and target environment
3. Include example usage in the `examples/` directory
4. Update this README with the new configuration options
### TypeScript Version Compatibility
This package is maintained to be compatible with:
- TypeScript 4.9+
- Node.js 18+
- Modern bundlers (Webpack 5, Vite, Rspack, etc.)
## Dependencies
This package has minimal dependencies:
### Development Dependencies
- `@coze-arch/eslint-config` - ESLint configuration for linting this package
- `typescript` - TypeScript compiler for validation
### Peer Dependencies
- `typescript` ^4.9.0 - Required by consuming projects
## License
Apache-2.0

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["./dist"]
}
]
}

View File

@@ -0,0 +1,13 @@
{
"$schema": "../../../rushx-config.schema.json",
"packageAudit": {
"enable": true,
"rules": [
[
"essential-config-file",
"error",
{ "essentialFiles": ["OWNERS", "eslint.config.js"] }
]
]
}
}

View File

@@ -0,0 +1 @@
module.exports = [];

0
frontend/config/ts-config/global.d.ts vendored Normal file
View File

View File

@@ -0,0 +1,22 @@
{
"name": "@coze-arch/ts-config",
"version": "1.0.0",
"description": "",
"keywords": [],
"license": "Apache-2.0",
"author": "fanwenjie.fe@bytedance.com",
"bin": {
"rtsc": "./scripts/rtsc.sh",
"tsc": "./scripts/rtsc.sh"
},
"scripts": {
"build": "exit",
"lint": "exit",
"test": "exit",
"test:cov": "exit 0"
},
"devDependencies": {
"eslint": "~9.12.0",
"typescript": "~5.8.2"
}
}

View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
# 某些系统可能没有 realpath 命令,
if ! command -v realpath &>/dev/null; then
echo "未找到 realpath 命令"
echo "请执行以下命令安装必要依赖"
echo " brew install coreutils"
exit 1
fi
ROOT_DIR=$(realpath "$BASE_DIR/../")
bash "$ROOT_DIR/node_modules/.bin/tsc" "$@"

View File

@@ -0,0 +1,49 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
"allowJs": false,
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"declaration": true,
"composite": true,
"incremental": true,
"strictNullChecks": true,
"noImplicitAny": false,
"strictBindCallApply": false,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"module": "CommonJS",
"noFallthroughCasesInSwitch": true,
// 这个普遍反馈会让代码变得啰嗦,暂定遵循原本 bot 的设置,关闭
"noImplicitReturns": false,
"removeComments": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"disableReferencedProjectLoad": true,
// "disableSolutionSearching": true,
// "disableSourceOfProjectReferenceRedirect": true,
"target": "es2018"
},
"watchOptions": {
"fallbackPolling": "dynamicpriority",
"synchronousWatchDirectory": false,
"watchDirectory": "fixedChunkSizePolling",
"watchFile": "useFsEventsOnParentDirectory",
"excludeDirectories": [
"../../**/__tests__/",
"../../**/__coverage__/",
"../../**/__mocks__/",
"/**/node_modules/**"
],
"excludeFiles": [
"../../**/__tests__",
"../../**/__coverage__",
"../../**/__mocks__",
"/**/node_modules/**"
]
}
}

View File

@@ -0,0 +1,8 @@
{
"compilerOptions": {
"rootDir": "./scripts",
"outDir": "./dist",
"composite": true,
"tsBuildInfoFile": "dist/build.tsbuildinfo"
}
}

View File

@@ -0,0 +1,12 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"extends": "./tsconfig.base.json",
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ES2019"
},
"ts-node": {
"files": true
}
}

View File

@@ -0,0 +1,10 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"extends": "./tsconfig.base.json",
"files": ["./global.d.ts"],
"compilerOptions": {
"declaration": true,
"jsx": "preserve",
"lib": ["dom", "dom.iterable", "esnext"]
}
}

View File

@@ -0,0 +1,217 @@
# @coze-arch/vitest-config
> Shared Vitest configuration for the Coze architecture ecosystem
A unified testing configuration package that provides optimized Vitest setups for Node.js and web applications in the Coze monorepo. This package simplifies test configuration management and ensures consistency across all projects.
## Features
- **Multiple Presets**: Pre-configured setups for `default`, `node`, and `web` environments
- **TypeScript Support**: Built-in TypeScript path mapping with `vite-tsconfig-paths`
- **React Testing**: Web preset includes React plugin for component testing
- **Coverage Reporting**: Comprehensive coverage configuration with multiple reporters
- **Performance Optimized**: Fork-based test execution with configurable pool options
- **Semi-UI Compatibility**: Special handling for Semi Design components
- **Flexible Configuration**: Easy to extend and customize for specific project needs
## Get Started
### Installation
Add the package to your project:
```bash
# In your package.json
{
"devDependencies": {
"@coze-arch/vitest-config": "workspace:*"
}
}
```
Then run:
```bash
rush update
```
### Basic Usage
Create a `vitest.config.ts` file in your project root:
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web', // or 'node' or 'default'
});
```
## API Reference
### `defineConfig(config, otherConfig?)`
The main configuration function that creates a Vitest configuration based on your requirements.
#### Parameters
**config** (`VitestConfig`):
- `dirname` (string, required): The project root directory (`__dirname`)
- `preset` (string, required): Configuration preset - `'default'` | `'node'` | `'web'`
- All other Vitest configuration options
**otherConfig** (`OtherConfig`, optional):
- `fixSemi` (boolean): Enable Semi Design component compatibility fixes
#### Examples
**Default Configuration:**
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'default',
});
```
**Node.js Application:**
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'node',
test: {
include: ['src/**/*.test.ts'],
exclude: ['src/**/*.browser.test.ts'],
},
});
```
**React/Web Application:**
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web',
test: {
include: ['src/**/*.{test,spec}.{ts,tsx}'],
setupFiles: ['./src/test-setup.ts'],
},
});
```
**With Semi Design Components:**
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web',
}, {
fixSemi: true,
});
```
**Custom Coverage Configuration:**
```typescript
import { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig({
dirname: __dirname,
preset: 'web',
test: {
coverage: {
all: true,
threshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
},
},
});
```
### Available Presets
#### `default`
- Basic Vitest configuration
- TypeScript path mapping
- Fork-based test execution
- Coverage reporting disabled by default
#### `node`
- Extends default preset
- Optimized for Node.js applications
- No browser-specific plugins
#### `web`
- Extends default preset
- Includes React plugin for JSX/TSX support
- Uses `happy-dom` environment for DOM testing
- Optimized for frontend applications
### Built-in Features
**Test Execution:**
- Pool: `forks` with 1-32 workers
- Parallel hook execution
- Global test APIs enabled
- Silent mode in CI environments
**Coverage:**
- Provider: V8
- Formats: Cobertura, Text, HTML, Clover, JSON
- Includes: `src/**/*.ts`, `src/**/*.tsx`
- Excludes: Standard Vitest defaults
**TypeScript:**
- Automatic path mapping via `vite-tsconfig-paths`
- Resolve main fields: `main`, `module`, `exports`
## Development
### Scripts
```bash
# Lint the code
rush lint
# Development mode
rush dev
```
### Project Structure
```
src/
├── index.js # CommonJS entry point with Sucrase
├── define-config.ts # Main configuration function
├── preset-default.ts # Base configuration preset
├── preset-node.ts # Node.js specific preset
├── preset-web.ts # Web/React specific preset
└── tsc-only.ts # TypeScript-only mock file
```
## Dependencies
### Production Dependencies
- `vite-tsconfig-paths`: TypeScript path mapping support
### Development Dependencies
- `vitest`: Core testing framework
- `@vitejs/plugin-react`: React support for web preset
- `@vitest/coverage-v8`: Coverage reporting
- `happy-dom`: Lightweight DOM environment
- `sucrase`: Fast TypeScript compilation
## License
This package is part of the Coze architecture ecosystem and follows the project's licensing terms.

View File

@@ -0,0 +1,8 @@
{
"operationSettings": [
{
"operationName": "ts-check",
"outputFolderNames": ["dist"]
}
]
}

View File

@@ -0,0 +1,6 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
preset: 'node',
packageRoot: __dirname,
});

View File

@@ -0,0 +1,25 @@
{
"name": "@coze-arch/vitest-config",
"version": "0.0.1",
"author": "fanwenjie.fe@bytedance.com",
"maintainers": [],
"main": "src/index.js",
"types": "src/define-config.ts",
"scripts": {
"dev": "npm run build -- -w",
"lint": "eslint ./ --cache --quiet"
},
"dependencies": {
"vite-tsconfig-paths": "^4.2.1"
},
"devDependencies": {
"@coze-arch/eslint-config": "workspace:*",
"@coze-arch/ts-config": "workspace:*",
"@types/node": "^18",
"@vitejs/plugin-react": "^4.2.1",
"@vitest/coverage-v8": "~3.0.5",
"happy-dom": "^12.10.3",
"sucrase": "^3.32.0",
"vitest": "~3.0.5"
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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 { resolve } from 'path';
import { mergeConfig, type UserConfig } from 'vitest/config';
import { webPreset } from './preset-web';
import { nodePreset } from './preset-node';
import { defaultVitestConfig } from './preset-default';
export interface VitestConfig extends UserConfig {
/**
* A string representing the project root directory.
*/
dirname: string;
/**
* A string representing the preset configuration style, which can be one of 'default', 'node', or 'web'.
*/
preset: 'default' | 'node' | 'web';
}
const calBasePreset = (preset: string) => {
switch (preset) {
case 'node':
return nodePreset;
case 'web':
return webPreset;
default:
return defaultVitestConfig;
}
};
export interface OtherConfig {
/**
* 用于修复semi的package.json导出的配置问题
*/
fixSemi: boolean;
}
export const defineConfig = (
config: VitestConfig,
otherConfig?: OtherConfig,
): UserConfig => {
const { dirname, preset, ...userVitestConfig } = config;
if (typeof dirname !== 'string') {
throw new Error('define VitestConfig need a dirname.');
}
const baseConfig = calBasePreset(preset);
if (otherConfig?.fixSemi) {
const alias = [
{
find: /^@douyinfe\/semi-ui$/,
replacement: '@douyinfe/semi-ui/lib/es',
},
{
find: /^@douyinfe\/semi-foundation$/,
replacement: '@douyinfe/semi-foundation/lib/es',
},
{
find: 'lottie-web',
replacement: resolve(__dirname, './tsc-only.ts'),
},
];
if (Array.isArray(userVitestConfig.test?.alias)) {
alias.push(...userVitestConfig.test.alias);
} else if (typeof userVitestConfig.test?.alias === 'object') {
alias.push(
...Object.entries(userVitestConfig.test.alias).map(([key, value]) => ({
find: key,
replacement: value,
})),
);
}
userVitestConfig.test = {
...userVitestConfig.test,
alias,
};
}
return mergeConfig(baseConfig, userVitestConfig);
};

View File

@@ -0,0 +1,6 @@
require('sucrase/register/ts');
process.env.VITE_CJS_IGNORE_WARNING = true;
const { defineConfig } = require('./define-config');
module.exports = { defineConfig };

View File

@@ -0,0 +1,56 @@
/*
* 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 { coverageConfigDefaults, type UserConfig } from 'vitest/config';
import tsconfigPaths from 'vite-tsconfig-paths';
export const defaultVitestConfig: UserConfig = {
plugins: [tsconfigPaths()],
resolve: {
// 优先识别 main如果没有配置 main则识别 module
mainFields: ['main', 'module', 'exports'],
},
server: {
hmr: {
port: undefined,
},
},
test: {
testTimeout: 10 * 1000,
pool: 'forks',
poolOptions: {
forks: {
maxForks: 32,
minForks: 1,
},
},
sequence: {
// vitest 2.0之后,所有钩子默认串行运行
hooks: 'parallel',
},
globals: true,
mockReset: false,
silent: process.env.CI === 'true',
coverage: {
// 逐步对各包开启
all: false,
include: ['src/**/*.ts', 'src/**/*.tsx'],
exclude: coverageConfigDefaults.exclude,
provider: 'v8',
reporter: ['cobertura', 'text', 'html', 'clover', 'json', 'json-summary'],
},
},
};

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { mergeConfig } from 'vitest/config';
import { defaultVitestConfig } from './preset-default';
export const nodePreset = mergeConfig(defaultVitestConfig, {});

View File

@@ -0,0 +1,30 @@
/*
* 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 { mergeConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import { defaultVitestConfig } from './preset-default';
export const webPreset = mergeConfig(defaultVitestConfig, {
plugins: [react()],
test: {
environment: 'happy-dom',
framework: {
hmr: 'page',
},
},
});

View File

@@ -0,0 +1,17 @@
/*
* 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.
*/
// TODO: should be remove

View File

@@ -0,0 +1,19 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "./tsconfig.json",
"compilerOptions": {
"types": [],
"rootDir": "./src",
"outDir": "dist",
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["./src/tsc-only.ts"],
"references": [
{
"path": "../eslint-config/tsconfig.build.json"
},
{
"path": "../ts-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,12 @@
{
"extends": "@coze-arch/ts-config/tsconfig.node.json",
"compilerOptions": {
"rootDir": "./src",
"emitDeclarationOnly": true,
"moduleResolution": "NodeNext",
"allowImportingTsExtensions": true,
"outDir": "dist",
"types": ["vitest/globals"]
},
"include": ["src"]
}