feat: Add Pinyin processing functionality to string utilities
- Introduce ProcessPinyin function to convert Chinese characters to Pinyin with customizable options for tone and separator. - Register the new Pinyin process in the utils package for easy access. - Add comprehensive unit tests for various Pinyin conversion scenarios to ensure accuracy and reliability.
This commit is contained in:
parent
46b0947dfd
commit
efb9da57c1
7 changed files with 1106 additions and 0 deletions
1
go.mod
1
go.mod
|
|
@ -98,6 +98,7 @@ require (
|
|||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/montanaflynn/stats v0.7.1 // indirect
|
||||
github.com/mozillazg/go-pinyin v0.20.0 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
|
|
|||
2
go.sum
2
go.sum
|
|
@ -189,6 +189,8 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
|
|||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ=
|
||||
github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
|
|
|
|||
968
utils/README.md
Normal file
968
utils/README.md
Normal file
|
|
@ -0,0 +1,968 @@
|
|||
# Yao Utils Module
|
||||
|
||||
A Go module for utility functions with TypeScript API support.
|
||||
|
||||
## Usage in TypeScript
|
||||
|
||||
You can use the Utils module in TypeScript through the Process API. Below are examples of common operations with return type descriptions.
|
||||
|
||||
### String Operations
|
||||
|
||||
#### Concatenate strings
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Joins an array of values with a separator
|
||||
* @param values - Array of values to join
|
||||
* @param separator - String separator
|
||||
* @returns string - Joined string
|
||||
*/
|
||||
const joined = Process("utils.str.Join", ["Hello", "World"], " ");
|
||||
// Returns: "Hello World"
|
||||
```
|
||||
|
||||
#### Join file paths
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Joins path segments into a single path
|
||||
* @param ...paths - Path segments to join
|
||||
* @returns string - Joined path
|
||||
*/
|
||||
const path = Process("utils.str.JoinPath", "path", "to", "file.txt");
|
||||
// Returns: "path/to/file.txt"
|
||||
```
|
||||
|
||||
#### Generate UUID
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Generates a UUID string
|
||||
* @returns string - UUID string
|
||||
*/
|
||||
const uuid = Process("utils.str.UUID");
|
||||
// Returns: "550e8400-e29b-41d4-a716-446655440000" (example)
|
||||
```
|
||||
|
||||
#### Convert Chinese to Pinyin
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Converts Chinese characters to Pinyin
|
||||
* @param text - Chinese text to convert
|
||||
* @param options - Optional configuration
|
||||
* @returns string - Pinyin text
|
||||
*/
|
||||
const pinyin = Process("utils.str.Pinyin", "你好");
|
||||
// Returns: "ni hao"
|
||||
|
||||
// With options
|
||||
const pinyinWithTone = Process("utils.str.Pinyin", "你好", {
|
||||
tone: true,
|
||||
separator: "-",
|
||||
});
|
||||
// Returns: "ni3-hao3"
|
||||
```
|
||||
|
||||
#### Convert hex to string
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Converts a hexadecimal string to a regular string
|
||||
* @param hex - Hexadecimal string
|
||||
* @returns string - Decoded string
|
||||
*/
|
||||
const text = Process("utils.str.Hex", "48656c6c6f20576f726c64");
|
||||
// Returns: "Hello World"
|
||||
```
|
||||
|
||||
### Date and Time
|
||||
|
||||
#### Get current timestamp
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the current Unix timestamp (seconds)
|
||||
* @returns number - Unix timestamp
|
||||
*/
|
||||
const timestamp = Process("utils.now.Timestamp");
|
||||
// Returns: 1625097600 (example)
|
||||
```
|
||||
|
||||
#### Get current timestamp in milliseconds
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the current Unix timestamp in milliseconds
|
||||
* @returns number - Unix timestamp in milliseconds
|
||||
*/
|
||||
const timestampMs = Process("utils.now.Timestampms");
|
||||
// Returns: 1625097600000 (example)
|
||||
```
|
||||
|
||||
#### Get current date
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the current date in YYYY-MM-DD format
|
||||
* @returns string - Current date
|
||||
*/
|
||||
const date = Process("utils.now.Date");
|
||||
// Returns: "2023-07-01"
|
||||
```
|
||||
|
||||
#### Get current time
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the current time in HH:MM:SS format
|
||||
* @returns string - Current time
|
||||
*/
|
||||
const time = Process("utils.now.Time");
|
||||
// Returns: "12:34:56"
|
||||
```
|
||||
|
||||
#### Get current date and time
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the current date and time in YYYY-MM-DD HH:MM:SS format
|
||||
* @returns string - Current date and time
|
||||
*/
|
||||
const dateTime = Process("utils.now.DateTime");
|
||||
// Returns: "2023-07-01 12:34:56"
|
||||
```
|
||||
|
||||
#### Sleep for a duration
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Pauses execution for a specified time
|
||||
* @param milliseconds - Time to sleep in milliseconds
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.time.Sleep", 1000);
|
||||
// Sleeps for 1 second
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
#### Throw forbidden error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a 403 Forbidden error
|
||||
* @param message - Optional error message
|
||||
* @throws Exception with code 403
|
||||
*/
|
||||
Process("utils.throw.Forbidden", "Access denied");
|
||||
```
|
||||
|
||||
#### Throw unauthorized error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a 401 Unauthorized error
|
||||
* @param message - Optional error message
|
||||
* @throws Exception with code 401
|
||||
*/
|
||||
Process("utils.throw.Unauthorized", "Authentication required");
|
||||
```
|
||||
|
||||
#### Throw not found error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a 404 Not Found error
|
||||
* @param message - Optional error message
|
||||
* @throws Exception with code 404
|
||||
*/
|
||||
Process("utils.throw.NotFound", "Resource not found");
|
||||
```
|
||||
|
||||
#### Throw bad request error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a 400 Bad Request error
|
||||
* @param message - Optional error message
|
||||
* @throws Exception with code 400
|
||||
*/
|
||||
Process("utils.throw.BadRequest", "Invalid parameters");
|
||||
```
|
||||
|
||||
#### Throw internal error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a 500 Internal Error
|
||||
* @param message - Optional error message
|
||||
* @throws Exception with code 500
|
||||
*/
|
||||
Process("utils.throw.InternalError", "Something went wrong");
|
||||
```
|
||||
|
||||
#### Throw custom exception
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a custom exception with specified message and code
|
||||
* @param message - Error message
|
||||
* @param code - Error code
|
||||
* @throws Exception with specified code
|
||||
*/
|
||||
Process("utils.throw.Exception", "Payment required", 402);
|
||||
```
|
||||
|
||||
### URL Handling
|
||||
|
||||
#### Parse query string
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Parses a URL query string into a map
|
||||
* @param queryString - URL query string
|
||||
* @returns object - Map of query parameters
|
||||
*/
|
||||
const query = Process("utils.url.ParseQuery", "name=John&age=30");
|
||||
// Returns: { name: ["John"], age: ["30"] }
|
||||
```
|
||||
|
||||
#### Parse URL
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Parses a URL into its components
|
||||
* @param url - URL to parse
|
||||
* @returns object - URL components
|
||||
*/
|
||||
const urlParts = Process(
|
||||
"utils.url.ParseURL",
|
||||
"https://example.com:8080/path?q=search"
|
||||
);
|
||||
// Returns: {
|
||||
// scheme: "https",
|
||||
// host: "example.com:8080",
|
||||
// domain: "example.com",
|
||||
// path: "/path",
|
||||
// port: "8080",
|
||||
// query: { q: ["search"] },
|
||||
// url: "https://example.com:8080/path?q=search"
|
||||
// }
|
||||
```
|
||||
|
||||
#### Convert to query parameters
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Converts various data types to query parameters
|
||||
* @param data - Data to convert (map, url.Values, etc.)
|
||||
* @returns string - Query parameter string
|
||||
*/
|
||||
const params = Process("utils.url.QueryParam", {
|
||||
name: "John",
|
||||
tags: ["dev", "admin"],
|
||||
});
|
||||
// Returns: "name=John&tags=dev&tags=admin"
|
||||
```
|
||||
|
||||
### Formatting and Output
|
||||
|
||||
#### Print formatted string
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Prints a formatted string to stdout
|
||||
* @param format - Format string
|
||||
* @param ...args - Arguments for format
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.fmt.Printf", "Hello, %s!", "World");
|
||||
// Prints: Hello, World!
|
||||
```
|
||||
|
||||
#### Print colored string
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Prints a colored formatted string to stdout
|
||||
* @param color - Color name (red, green, blue, etc.)
|
||||
* @param format - Format string
|
||||
* @param ...args - Arguments for format
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.fmt.ColorPrintf", "green", "Success: %s", "Operation completed");
|
||||
// Prints: Success: Operation completed (in green)
|
||||
|
||||
// Available colors:
|
||||
// red, green, yellow, blue, magenta, cyan, white, black
|
||||
// hired, higreen, hiyellow, hiblue, himagenta, hicyan, hiwhite, hiblack
|
||||
```
|
||||
|
||||
### Tree Operations
|
||||
|
||||
#### Flatten tree to array
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Flattens a hierarchical tree structure to a flat array
|
||||
* @param tree - Tree structure (array of nodes with children)
|
||||
* @param options - Optional configuration
|
||||
* @returns array - Flattened array
|
||||
*/
|
||||
const flat = Process("utils.tree.Flatten", [
|
||||
{
|
||||
id: 1,
|
||||
name: "Parent",
|
||||
children: [
|
||||
{ id: 2, name: "Child 1" },
|
||||
{ id: 3, name: "Child 2" },
|
||||
],
|
||||
},
|
||||
]);
|
||||
// Returns: [
|
||||
// { id: 1, name: "Parent", parent: null },
|
||||
// { id: 2, name: "Child 1", parent: 1 },
|
||||
// { id: 3, name: "Child 2", parent: 1 }
|
||||
// ]
|
||||
|
||||
// With custom options
|
||||
const customFlat = Process(
|
||||
"utils.tree.Flatten",
|
||||
[{ uid: 1, title: "Parent", items: [{ uid: 2, title: "Child" }] }],
|
||||
{ primary: "uid", children: "items", parent: "parentId" }
|
||||
);
|
||||
// Returns: [
|
||||
// { uid: 1, title: "Parent", parentId: null },
|
||||
// { uid: 2, title: "Child", parentId: 1 }
|
||||
// ]
|
||||
```
|
||||
|
||||
### JSON Operations
|
||||
|
||||
#### Validate JSON structure
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Validates a JSON structure against rules
|
||||
* @param data - JSON data to validate
|
||||
* @param rules - Validation rules
|
||||
* @returns boolean - True if valid, false otherwise
|
||||
*/
|
||||
const isValid = Process("utils.json.Validate", { name: "John", age: 30 }, [
|
||||
{ haskey: "name" },
|
||||
{ haskey: "age" },
|
||||
]);
|
||||
// Returns: true
|
||||
```
|
||||
|
||||
### Flow Control
|
||||
|
||||
#### Conditional processing (IF)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Conditionally executes a process based on conditions
|
||||
* @param conditions - Array of condition objects
|
||||
* @returns any - Result of the executed process
|
||||
*/
|
||||
const result = Process(
|
||||
"utils.flow.IF",
|
||||
{
|
||||
when: [{ operator: "eq", value: 1, field: "status" }],
|
||||
process: "scripts.test.active",
|
||||
args: ["User is active"],
|
||||
},
|
||||
{
|
||||
when: [{ operator: "eq", value: 0, field: "status" }],
|
||||
process: "scripts.test.inactive",
|
||||
args: ["User is inactive"],
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
#### Case statement
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Executes the first matching case based on conditions
|
||||
* @param ...cases - Case objects with conditions
|
||||
* @returns any - Result of the executed process
|
||||
*/
|
||||
const result = Process(
|
||||
"utils.flow.Case",
|
||||
{
|
||||
when: [{ operator: "eq", value: "admin", field: "role" }],
|
||||
process: "scripts.user.adminPanel",
|
||||
args: [],
|
||||
},
|
||||
{
|
||||
when: [{ operator: "eq", value: "user", field: "role" }],
|
||||
process: "scripts.user.userDashboard",
|
||||
args: [],
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
#### For loop
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Executes a process multiple times in a loop
|
||||
* @param from - Starting index (inclusive)
|
||||
* @param to - Ending index (exclusive)
|
||||
* @param processConfig - Process configuration
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.flow.For", 0, 5, {
|
||||
process: "scripts.test.log",
|
||||
args: ["Loop index: ::value"],
|
||||
});
|
||||
// Calls scripts.test.log 5 times with indexes 0-4
|
||||
```
|
||||
|
||||
#### Each loop (iterate over array or map)
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Iterates over an array or map and executes a process for each item
|
||||
* @param data - Array or map to iterate over
|
||||
* @param processConfig - Process configuration
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.flow.Each", ["apple", "banana", "orange"], {
|
||||
process: "scripts.test.log",
|
||||
args: ["Item: ::value at index ::key"],
|
||||
});
|
||||
|
||||
// Also works with objects
|
||||
Process(
|
||||
"utils.flow.Each",
|
||||
{ name: "John", age: 30 },
|
||||
{
|
||||
process: "scripts.test.log",
|
||||
args: ["::key = ::value"],
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
#### Return value
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Returns values as-is, useful for terminating process chains
|
||||
* @param ...values - Values to return
|
||||
* @returns any - The provided values
|
||||
*/
|
||||
const result = Process("utils.flow.Return", "Done", { status: "success" });
|
||||
// Returns: ["Done", { status: "success" }]
|
||||
```
|
||||
|
||||
#### Throw error
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Throws a custom error with message and code
|
||||
* @param message - Error message
|
||||
* @param code - Error code
|
||||
* @throws Exception with the specified code
|
||||
*/
|
||||
Process("utils.flow.Throw", "Operation failed", 500);
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
#### Get environment variable
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the value of an environment variable
|
||||
* @param name - Environment variable name
|
||||
* @returns string - Environment variable value
|
||||
*/
|
||||
const dbHost = Process("utils.env.Get", "DB_HOST");
|
||||
```
|
||||
|
||||
#### Set environment variable
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Sets the value of an environment variable
|
||||
* @param name - Environment variable name
|
||||
* @param value - Environment variable value
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.env.Set", "APP_MODE", "production");
|
||||
```
|
||||
|
||||
#### Get multiple environment variables
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets multiple environment variables
|
||||
* @param ...names - Environment variable names
|
||||
* @returns object - Map of environment variables
|
||||
*/
|
||||
const config = Process("utils.env.GetMany", "DB_HOST", "DB_PORT", "DB_USER");
|
||||
// Returns: { "DB_HOST": "localhost", "DB_PORT": "5432", "DB_USER": "postgres" }
|
||||
```
|
||||
|
||||
#### Set multiple environment variables
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Sets multiple environment variables
|
||||
* @param variables - Map of environment variables
|
||||
* @returns null
|
||||
*/
|
||||
Process("utils.env.SetMany", {
|
||||
API_KEY: "abc123",
|
||||
API_SECRET: "xyz789",
|
||||
API_URL: "https://api.example.com",
|
||||
});
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
#### Generate JWT token
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Generates a JWT token
|
||||
* @param id - User ID or subject identifier
|
||||
* @param data - Data to include in the token
|
||||
* @param options - JWT options (optional)
|
||||
* @returns object - JWT token and expiration
|
||||
*/
|
||||
const token = Process(
|
||||
"utils.jwt.Make",
|
||||
1,
|
||||
{ name: "John", role: "admin" },
|
||||
{
|
||||
timeout: 3600,
|
||||
subject: "Authentication",
|
||||
issuer: "YaoApp",
|
||||
}
|
||||
);
|
||||
// Returns: {
|
||||
// token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||
// expires_at: 1625097600
|
||||
// }
|
||||
```
|
||||
|
||||
#### Verify JWT token
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Verifies a JWT token
|
||||
* @param token - JWT token to verify
|
||||
* @returns object - Token claims
|
||||
* @throws Exception if token is invalid
|
||||
*/
|
||||
const claims = Process(
|
||||
"utils.jwt.Verify",
|
||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
);
|
||||
// Returns: { id: 1, sid: "session_id", data: { name: "John", role: "admin" }, ... }
|
||||
```
|
||||
|
||||
#### Verify password
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Verifies a password against a hash
|
||||
* @param password - Plain text password
|
||||
* @param hash - Bcrypt hash to compare against
|
||||
* @returns boolean - True if password matches
|
||||
* @throws Exception if password is invalid
|
||||
*/
|
||||
const isValid = Process("utils.pwd.Verify", "mypassword", "$2a$10$...");
|
||||
// Returns: true
|
||||
// Throws exception if invalid
|
||||
```
|
||||
|
||||
### Captcha
|
||||
|
||||
#### Generate captcha
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Generates a captcha
|
||||
* @param options - Captcha options
|
||||
* @returns object - Captcha ID and image/audio content
|
||||
*/
|
||||
const captcha = Process("utils.captcha.Make", {
|
||||
width: 240,
|
||||
height: 80,
|
||||
length: 6,
|
||||
type: "image", // or "audio"
|
||||
lang: "en",
|
||||
});
|
||||
// Returns: {
|
||||
// id: "captcha_id",
|
||||
// content: "data:image/png;base64,..." // base64 encoded image or audio
|
||||
// }
|
||||
```
|
||||
|
||||
#### Verify captcha
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Verifies a captcha code
|
||||
* @param id - Captcha ID
|
||||
* @param code - User input code
|
||||
* @returns boolean - True if captcha is valid
|
||||
* @throws Exception if captcha is invalid
|
||||
*/
|
||||
const isValid = Process("utils.captcha.Verify", "captcha_id", "123456");
|
||||
// Returns: true
|
||||
// Throws exception if invalid
|
||||
```
|
||||
|
||||
### Array Operations
|
||||
|
||||
#### Get array values by column name
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Extracts values from a specific column in an array of records
|
||||
* @param records - Array of records
|
||||
* @param column - Column name to extract
|
||||
* @returns array - Extracted values
|
||||
*/
|
||||
const ids = Process(
|
||||
"utils.arr.Column",
|
||||
[
|
||||
{ id: 1, name: "John" },
|
||||
{ id: 2, name: "Jane" },
|
||||
{ id: 3, name: "Bob" },
|
||||
],
|
||||
"id"
|
||||
);
|
||||
// Returns: [1, 2, 3]
|
||||
```
|
||||
|
||||
#### Keep only specific columns
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Keeps only specified columns in an array of records
|
||||
* @param records - Array of records
|
||||
* @param columns - Columns to keep
|
||||
* @returns array - Records with only specified columns
|
||||
*/
|
||||
const simplified = Process(
|
||||
"utils.arr.Keep",
|
||||
[
|
||||
{ id: 1, name: "John", email: "john@example.com", role: "admin" },
|
||||
{ id: 2, name: "Jane", email: "jane@example.com", role: "user" },
|
||||
],
|
||||
["id", "name"]
|
||||
);
|
||||
// Returns: [
|
||||
// { id: 1, name: "John" },
|
||||
// { id: 2, name: "Jane" }
|
||||
// ]
|
||||
```
|
||||
|
||||
#### Pluck values from records
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Transforms an array of records based on specified columns
|
||||
* @param columns - Columns to include
|
||||
* @param data - Input data
|
||||
* @returns array - Transformed data
|
||||
*/
|
||||
const users = Process(
|
||||
"utils.arr.Pluck",
|
||||
["id", "full_name"],
|
||||
[
|
||||
{ id: 1, first_name: "John", last_name: "Doe" },
|
||||
{ id: 2, first_name: "Jane", last_name: "Smith" },
|
||||
]
|
||||
);
|
||||
// Can transform data based on column mapping
|
||||
```
|
||||
|
||||
#### Split records into columns and values
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Splits records into column names and value arrays
|
||||
* @param records - Array of records
|
||||
* @returns object - Contains columns array and values matrix
|
||||
*/
|
||||
const split = Process("utils.arr.Split", [
|
||||
{ id: 1, name: "John", age: 30 },
|
||||
{ id: 2, name: "Jane", age: 25 },
|
||||
]);
|
||||
// Returns: {
|
||||
// columns: ["id", "name", "age"],
|
||||
// values: [
|
||||
// [1, "John", 30],
|
||||
// [2, "Jane", 25]
|
||||
// ]
|
||||
// }
|
||||
```
|
||||
|
||||
#### Get array indexes
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets the indexes of an array
|
||||
* @param array - Input array
|
||||
* @returns array - Array indexes
|
||||
*/
|
||||
const indexes = Process("utils.arr.Indexes", ["apple", "banana", "orange"]);
|
||||
// Returns: [0, 1, 2]
|
||||
```
|
||||
|
||||
#### Convert array to tree structure
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Converts a flat array to a tree structure
|
||||
* @param records - Array of records
|
||||
* @param options - Tree configuration
|
||||
* @returns array - Tree structure
|
||||
*/
|
||||
const tree = Process(
|
||||
"utils.arr.Tree",
|
||||
[
|
||||
{ id: 1, parent_id: null, name: "Parent" },
|
||||
{ id: 2, parent_id: 1, name: "Child 1" },
|
||||
{ id: 3, parent_id: 1, name: "Child 2" },
|
||||
],
|
||||
{
|
||||
parent: "parent_id",
|
||||
empty: null,
|
||||
children: "children",
|
||||
id: "id",
|
||||
}
|
||||
);
|
||||
// Returns hierarchical tree structure
|
||||
```
|
||||
|
||||
#### Remove duplicate values
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Removes duplicate values from an array
|
||||
* @param array - Input array
|
||||
* @returns array - Array with unique values
|
||||
*/
|
||||
const unique = Process("utils.arr.Unique", [1, 2, 2, 3, 3, 3, 4]);
|
||||
// Returns: [1, 2, 3, 4]
|
||||
```
|
||||
|
||||
#### Get item by index
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets an item from an array by index
|
||||
* @param array - Input array
|
||||
* @param index - Array index
|
||||
* @returns any - Item at the specified index
|
||||
*/
|
||||
const item = Process("utils.arr.Get", ["apple", "banana", "orange"], 1);
|
||||
// Returns: "banana"
|
||||
```
|
||||
|
||||
#### Set values in array of maps
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Sets a value for a specific key in all maps in an array
|
||||
* @param array - Array of maps
|
||||
* @param key - Key to set
|
||||
* @param value - Value to set
|
||||
* @returns array - Updated array
|
||||
*/
|
||||
const updated = Process(
|
||||
"utils.arr.MapSet",
|
||||
[
|
||||
{ id: 1, name: "John" },
|
||||
{ id: 2, name: "Jane" },
|
||||
],
|
||||
"active",
|
||||
true
|
||||
);
|
||||
// Returns: [
|
||||
// { id: 1, name: "John", active: true },
|
||||
// { id: 2, name: "Jane", active: true }
|
||||
// ]
|
||||
```
|
||||
|
||||
### Map Operations
|
||||
|
||||
#### Get a value from a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets a value from a map by key
|
||||
* @param map - Input map
|
||||
* @param key - Key to retrieve
|
||||
* @returns any - Value associated with the key
|
||||
*/
|
||||
const name = Process("utils.map.Get", { id: 1, name: "John", age: 30 }, "name");
|
||||
// Returns: "John"
|
||||
```
|
||||
|
||||
#### Set a value in a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Sets a value in a map
|
||||
* @param map - Input map
|
||||
* @param key - Key to set
|
||||
* @param value - Value to set
|
||||
* @returns object - Updated map
|
||||
*/
|
||||
const updated = Process("utils.map.Set", { name: "John" }, "age", 30);
|
||||
// Returns: { name: "John", age: 30 }
|
||||
```
|
||||
|
||||
#### Delete a key from a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Deletes a key from a map
|
||||
* @param map - Input map
|
||||
* @param key - Key to delete
|
||||
* @returns object - Updated map
|
||||
*/
|
||||
const smaller = Process(
|
||||
"utils.map.Del",
|
||||
{ id: 1, name: "John", temp: "xyz" },
|
||||
"temp"
|
||||
);
|
||||
// Returns: { id: 1, name: "John" }
|
||||
```
|
||||
|
||||
#### Delete multiple keys from a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Deletes multiple keys from a map
|
||||
* @param map - Input map
|
||||
* @param ...keys - Keys to delete
|
||||
* @returns object - Updated map
|
||||
*/
|
||||
const filtered = Process(
|
||||
"utils.map.DelMany",
|
||||
{ id: 1, name: "John", password: "secret", token: "xyz" },
|
||||
"password",
|
||||
"token"
|
||||
);
|
||||
// Returns: { id: 1, name: "John" }
|
||||
```
|
||||
|
||||
#### Get all keys from a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets all keys from a map
|
||||
* @param map - Input map
|
||||
* @returns array - Array of keys
|
||||
*/
|
||||
const keys = Process("utils.map.Keys", { id: 1, name: "John", age: 30 });
|
||||
// Returns: ["id", "name", "age"]
|
||||
```
|
||||
|
||||
#### Get all values from a map
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Gets all values from a map
|
||||
* @param map - Input map
|
||||
* @returns array - Array of values
|
||||
*/
|
||||
const values = Process("utils.map.Values", { id: 1, name: "John", age: 30 });
|
||||
// Returns: [1, "John", 30]
|
||||
```
|
||||
|
||||
#### Convert map to array
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Converts a map to an array of key-value pairs
|
||||
* @param map - Input map
|
||||
* @returns array - Array of key-value objects
|
||||
*/
|
||||
const array = Process("utils.map.Array", { id: 1, name: "John" });
|
||||
// Returns: [
|
||||
// { key: "id", value: 1 },
|
||||
// { key: "name", value: "John" }
|
||||
// ]
|
||||
```
|
||||
|
||||
## Complete Workflow Example
|
||||
|
||||
```typescript
|
||||
// Generate a UUID
|
||||
const id = Process("utils.str.UUID");
|
||||
|
||||
// Get current timestamp
|
||||
const timestamp = Process("utils.now.Timestamp");
|
||||
|
||||
// Create a path
|
||||
const path = Process("utils.str.JoinPath", "data", id, "file.txt");
|
||||
|
||||
// Print colored info
|
||||
Process("utils.fmt.ColorPrintf", "blue", "Processing request with ID: %s", id);
|
||||
|
||||
// Parse URL parameters
|
||||
const url = "https://example.com/api?token=123&id=" + id;
|
||||
const parsedUrl = Process("utils.url.ParseURL", url);
|
||||
|
||||
// Handle errors conditionally
|
||||
if (!parsedUrl.query.token) {
|
||||
Process("utils.throw.Unauthorized", "Missing token");
|
||||
}
|
||||
|
||||
// Generate a JWT token
|
||||
const token = Process(
|
||||
"utils.jwt.Make",
|
||||
1,
|
||||
{ id: id, timestamp: timestamp },
|
||||
{
|
||||
timeout: 3600,
|
||||
subject: "API Access",
|
||||
}
|
||||
);
|
||||
|
||||
// Use flow control for conditional processing
|
||||
Process(
|
||||
"utils.flow.Case",
|
||||
{
|
||||
when: [{ operator: "gt", value: 0, field: "status" }],
|
||||
process: "utils.flow.Return",
|
||||
args: [{ token: token.token, path: path }],
|
||||
},
|
||||
{
|
||||
when: [{ operator: "eq", value: 0, field: "status" }],
|
||||
process: "utils.throw.BadRequest",
|
||||
args: ["Invalid status"],
|
||||
}
|
||||
);
|
||||
|
||||
// Get current date and time
|
||||
const now = Process("utils.now.DateTime");
|
||||
|
||||
// Print a success message
|
||||
Process("utils.fmt.ColorPrintf", "green", "Operation completed at %s", now);
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The utils module provides a variety of helper functions for common operations.
|
||||
- String utilities help with text manipulation, path joining, and UUID generation.
|
||||
- Date/time functions provide current date and time in various formats.
|
||||
- Error handling functions provide standardized HTTP error responses.
|
||||
- URL functions help parse and manipulate URL strings and query parameters.
|
||||
- Formatting functions allow console output with color support.
|
||||
- Flow control functions provide conditional execution and iteration capabilities.
|
||||
- Environment functions allow reading and writing environment variables.
|
||||
- Authentication functions handle JWT tokens and password verification.
|
||||
- Array and map functions provide powerful data manipulation capabilities.
|
||||
|
|
@ -31,6 +31,7 @@ func testPrepare() {
|
|||
process.Register("utils.str.Join", str.ProcessJoin)
|
||||
process.Register("utils.str.JoinPath", str.ProcessJoinPath)
|
||||
process.Register("utils.str.UUID", str.ProcessUUID)
|
||||
process.Register("utils.str.Pinyin", str.ProcessPinyin)
|
||||
|
||||
process.Register("utils.now.Time", datetime.ProcessTime)
|
||||
process.Register("utils.now.Date", datetime.ProcessDate)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ func Init() {
|
|||
process.Register("utils.str.Join", str.ProcessJoin)
|
||||
process.Register("utils.str.JoinPath", str.ProcessJoinPath)
|
||||
process.Register("utils.str.UUID", str.ProcessUUID)
|
||||
process.Register("utils.str.Pinyin", str.ProcessPinyin)
|
||||
|
||||
// Array
|
||||
process.Alias("xiang.helper.ArrayPluck", "utils.arr.Pluck")
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mozillazg/go-pinyin"
|
||||
"github.com/yaoapp/gou/process"
|
||||
"github.com/yaoapp/kun/maps"
|
||||
)
|
||||
|
||||
// ProcessJoin utils.str.Join
|
||||
|
|
@ -36,3 +38,54 @@ func ProcessUUID(process *process.Process) interface{} {
|
|||
uuid := uuid.New()
|
||||
return uuid.String()
|
||||
}
|
||||
|
||||
// ProcessPinyin utils.str.Pinyin converts Chinese characters to Pinyin
|
||||
// Args:
|
||||
// - arg[0]: string, the Chinese characters to convert
|
||||
// - arg[1]: map (optional) configuration options
|
||||
// {
|
||||
// "tone": bool, // whether to include tone marks, default: false
|
||||
// "separator": string // separator between pinyin, default: " "
|
||||
// }
|
||||
func ProcessPinyin(process *process.Process) interface{} {
|
||||
process.ValidateArgNums(1)
|
||||
seed := process.ArgsString(0)
|
||||
|
||||
// Create converter with settings
|
||||
a := pinyin.NewArgs()
|
||||
a.Style = pinyin.Normal // default style
|
||||
separator := " " // default separator
|
||||
|
||||
// Apply custom settings if provided
|
||||
if process.NumOfArgs() > 1 {
|
||||
confMap := process.ArgsMap(1, maps.MapStrAny{})
|
||||
|
||||
// Check if tone is enabled
|
||||
toneVal, hasTone := confMap["tone"]
|
||||
|
||||
if hasTone {
|
||||
if tone, ok := toneVal.(bool); ok && tone {
|
||||
a.Style = pinyin.Tone
|
||||
}
|
||||
}
|
||||
|
||||
// Check custom separator
|
||||
if sep, ok := confMap["separator"].(string); ok {
|
||||
separator = sep
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to Pinyin
|
||||
result := pinyin.Pinyin(seed, a)
|
||||
|
||||
// Convert 2D array to 1D array
|
||||
pinyinStr := make([]string, 0, len(result))
|
||||
for _, py := range result {
|
||||
if len(py) > 0 {
|
||||
pinyinStr = append(pinyinStr, py[0])
|
||||
}
|
||||
}
|
||||
|
||||
final := strings.Join(pinyinStr, separator)
|
||||
return final
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,3 +49,83 @@ func TestProcessStrHex(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
assert.Nil(t, res)
|
||||
}
|
||||
|
||||
func TestProcessPinyin(t *testing.T) {
|
||||
testPrepare()
|
||||
|
||||
// Test default settings (no tone, space separator)
|
||||
res := process.New("utils.str.Pinyin", "你好世界").Run().(string)
|
||||
assert.Equal(t, "ni hao shi jie", res)
|
||||
|
||||
// Test with tone enabled and custom separator
|
||||
config := map[string]interface{}{
|
||||
"tone": true,
|
||||
"separator": "-",
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好世界", config).Run().(string)
|
||||
assert.Equal(t, "nǐ-hǎo-shì-jiè", res)
|
||||
|
||||
// Test with only custom separator
|
||||
config = map[string]interface{}{
|
||||
"separator": "_",
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好世界", config).Run().(string)
|
||||
assert.Equal(t, "ni_hao_shi_jie", res)
|
||||
|
||||
// Test with empty string
|
||||
res = process.New("utils.str.Pinyin", "").Run().(string)
|
||||
assert.Equal(t, "", res)
|
||||
|
||||
// Test with Chinese characters only
|
||||
res = process.New("utils.str.Pinyin", "你好").Run().(string)
|
||||
assert.Equal(t, "ni hao", res)
|
||||
|
||||
// Test with multiple words and spaces
|
||||
res = process.New("utils.str.Pinyin", "中国 北京").Run().(string)
|
||||
assert.Equal(t, "zhong guo bei jing", res)
|
||||
|
||||
// Test with multiple consecutive spaces
|
||||
res = process.New("utils.str.Pinyin", "你好 世界").Run().(string)
|
||||
assert.Equal(t, "ni hao shi jie", res)
|
||||
|
||||
// Test with leading and trailing spaces
|
||||
res = process.New("utils.str.Pinyin", " 你好世界 ").Run().(string)
|
||||
assert.Equal(t, "ni hao shi jie", res)
|
||||
|
||||
// Test with mixed Chinese and English
|
||||
res = process.New("utils.str.Pinyin", "Hello你好World世界").Run().(string)
|
||||
assert.Equal(t, "ni hao shi jie", res)
|
||||
|
||||
// Test with numbers and punctuation
|
||||
res = process.New("utils.str.Pinyin", "你好2023!世界。").Run().(string)
|
||||
assert.Equal(t, "ni hao shi jie", res)
|
||||
|
||||
// Test with multi-character separator
|
||||
config = map[string]interface{}{
|
||||
"separator": "==",
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好世界", config).Run().(string)
|
||||
assert.Equal(t, "ni==hao==shi==jie", res)
|
||||
|
||||
// Test with empty separator
|
||||
config = map[string]interface{}{
|
||||
"separator": "",
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好世界", config).Run().(string)
|
||||
assert.Equal(t, "nihaoshijie", res)
|
||||
|
||||
// Test with special characters as separator
|
||||
config = map[string]interface{}{
|
||||
"separator": "★",
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好世界", config).Run().(string)
|
||||
assert.Equal(t, "ni★hao★shi★jie", res)
|
||||
|
||||
// Test with multiple words and tone
|
||||
// Create a fresh config map to avoid reference issues
|
||||
toneConfig := map[string]interface{}{
|
||||
"tone": true,
|
||||
}
|
||||
res = process.New("utils.str.Pinyin", "你好美丽的世界", toneConfig).Run().(string)
|
||||
assert.Equal(t, "nǐ hǎo měi lì de shì jiè", res)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue