Merge pull request #485 from frauniki/add-prettier-ci
chore: Add Prettier format check to CI and format code
This commit is contained in:
@@ -51,3 +51,21 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
- name: Run E2E Tests
|
- name: Run E2E Tests
|
||||||
run: npm run test:e2e
|
run: npm run test:e2e
|
||||||
|
prettier:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20.x'
|
||||||
|
cache: 'npm'
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
- name: Run Prettier
|
||||||
|
run: npm run format:check
|
||||||
|
- name: Prettier Output
|
||||||
|
if: failure()
|
||||||
|
run: |
|
||||||
|
echo "Prettier check failed. Please run 'npm run format' to fix formatting issues."
|
||||||
|
exit 1
|
||||||
|
|||||||
@@ -51,6 +51,7 @@
|
|||||||
"deploy:patch": "npm version patch && npm run deploy:build",
|
"deploy:patch": "npm version patch && npm run deploy:build",
|
||||||
"lint": "eslint src --ext ts && tsc --noEmit",
|
"lint": "eslint src --ext ts && tsc --noEmit",
|
||||||
"format": "prettier --write src",
|
"format": "prettier --write src",
|
||||||
|
"format:check": "prettier --check src",
|
||||||
"test": "node --no-warnings --experimental-vm-modules $( [ -f ./node_modules/.bin/jest ] && echo ./node_modules/.bin/jest || which jest ) test/unit",
|
"test": "node --no-warnings --experimental-vm-modules $( [ -f ./node_modules/.bin/jest ] && echo ./node_modules/.bin/jest || which jest ) test/unit",
|
||||||
"test:all": "npm run test:unit:docker && npm run test:e2e:docker",
|
"test:all": "npm run test:unit:docker && npm run test:e2e:docker",
|
||||||
"test:docker-build": "docker build -t oco-test -f test/Dockerfile .",
|
"test:docker-build": "docker build -t oco-test -f test/Dockerfile .",
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ export class AzureEngine implements AiEngine {
|
|||||||
if (message?.content === null) {
|
if (message?.content === null) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = message?.content;
|
let content = message?.content;
|
||||||
return removeContentTags(content, 'think');
|
return removeContentTags(content, 'think');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
+1
-1
@@ -7,4 +7,4 @@ export class GroqEngine extends OpenAiEngine {
|
|||||||
config.baseURL = 'https://api.groq.com/openai/v1';
|
config.baseURL = 'https://api.groq.com/openai/v1';
|
||||||
super(config);
|
super(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,10 @@ export class MistralAiEngine implements AiEngine {
|
|||||||
if (!config.baseURL) {
|
if (!config.baseURL) {
|
||||||
this.client = new Mistral({ apiKey: config.apiKey });
|
this.client = new Mistral({ apiKey: config.apiKey });
|
||||||
} else {
|
} else {
|
||||||
this.client = new Mistral({ apiKey: config.apiKey, serverURL: config.baseURL });
|
this.client = new Mistral({
|
||||||
|
apiKey: config.apiKey,
|
||||||
|
serverURL: config.baseURL
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +53,12 @@ export class MistralAiEngine implements AiEngine {
|
|||||||
|
|
||||||
const completion = await this.client.chat.complete(params);
|
const completion = await this.client.chat.complete(params);
|
||||||
|
|
||||||
if (!completion.choices)
|
if (!completion.choices) throw Error('No completion choice available.');
|
||||||
throw Error('No completion choice available.')
|
|
||||||
|
|
||||||
const message = completion.choices[0].message;
|
const message = completion.choices[0].message;
|
||||||
|
|
||||||
if (!message || !message.content)
|
if (!message || !message.content)
|
||||||
throw Error('No completion choice available.')
|
throw Error('No completion choice available.');
|
||||||
|
|
||||||
let content = message.content as string;
|
let content = message.content as string;
|
||||||
return removeContentTags(content, 'think');
|
return removeContentTags(content, 'think');
|
||||||
|
|||||||
+36
-36
@@ -6,42 +6,42 @@ import { AiEngine, AiEngineConfig } from './Engine';
|
|||||||
interface MLXConfig extends AiEngineConfig {}
|
interface MLXConfig extends AiEngineConfig {}
|
||||||
|
|
||||||
export class MLXEngine implements AiEngine {
|
export class MLXEngine implements AiEngine {
|
||||||
config: MLXConfig;
|
config: MLXConfig;
|
||||||
client: AxiosInstance;
|
client: AxiosInstance;
|
||||||
|
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.client = axios.create({
|
this.client = axios.create({
|
||||||
url: config.baseURL
|
url: config.baseURL
|
||||||
? `${config.baseURL}/${config.apiKey}`
|
? `${config.baseURL}/${config.apiKey}`
|
||||||
: 'http://localhost:8080/v1/chat/completions',
|
: 'http://localhost:8080/v1/chat/completions',
|
||||||
headers: { 'Content-Type': 'application/json' }
|
headers: { 'Content-Type': 'application/json' }
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateCommitMessage(
|
||||||
|
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>
|
||||||
|
): Promise<string | undefined> {
|
||||||
|
const params = {
|
||||||
|
messages,
|
||||||
|
temperature: 0,
|
||||||
|
top_p: 0.1,
|
||||||
|
repetition_penalty: 1.5,
|
||||||
|
stream: false
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const response = await this.client.post(
|
||||||
|
this.client.getUri(this.config),
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
const choices = response.data.choices;
|
||||||
|
const message = choices[0].message;
|
||||||
|
let content = message?.content;
|
||||||
|
return removeContentTags(content, 'think');
|
||||||
|
} catch (err: any) {
|
||||||
|
const message = err.response?.data?.error ?? err.message;
|
||||||
|
throw new Error(`MLX provider error: ${message}`);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
async generateCommitMessage(
|
|
||||||
messages: Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>):
|
|
||||||
Promise<string | undefined> {
|
|
||||||
const params = {
|
|
||||||
messages,
|
|
||||||
temperature: 0,
|
|
||||||
top_p: 0.1,
|
|
||||||
repetition_penalty: 1.5,
|
|
||||||
stream: false
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
const response = await this.client.post(
|
|
||||||
this.client.getUri(this.config),
|
|
||||||
params
|
|
||||||
);
|
|
||||||
|
|
||||||
const choices = response.data.choices;
|
|
||||||
const message = choices[0].message;
|
|
||||||
let content = message?.content;
|
|
||||||
return removeContentTags(content, 'think');
|
|
||||||
} catch (err: any) {
|
|
||||||
const message = err.response?.data?.error ?? err.message;
|
|
||||||
throw new Error(`MLX provider error: ${message}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ export class OllamaEngine implements AiEngine {
|
|||||||
|
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
|
||||||
// Combine base headers with custom headers
|
// Combine base headers with custom headers
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
...config.customHeaders
|
...config.customHeaders
|
||||||
};
|
};
|
||||||
|
|
||||||
this.client = axios.create({
|
this.client = axios.create({
|
||||||
url: config.baseURL
|
url: config.baseURL
|
||||||
? `${config.baseURL}/${config.apiKey}`
|
? `${config.baseURL}/${config.apiKey}`
|
||||||
|
|||||||
@@ -18,18 +18,18 @@ export class OpenAiEngine implements AiEngine {
|
|||||||
const clientOptions: OpenAI.ClientOptions = {
|
const clientOptions: OpenAI.ClientOptions = {
|
||||||
apiKey: config.apiKey
|
apiKey: config.apiKey
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.baseURL) {
|
if (config.baseURL) {
|
||||||
clientOptions.baseURL = config.baseURL;
|
clientOptions.baseURL = config.baseURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.customHeaders) {
|
if (config.customHeaders) {
|
||||||
const headers = parseCustomHeaders(config.customHeaders);
|
const headers = parseCustomHeaders(config.customHeaders);
|
||||||
if (Object.keys(headers).length > 0) {
|
if (Object.keys(headers).length > 0) {
|
||||||
clientOptions.defaultHeaders = headers;
|
clientOptions.defaultHeaders = headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client = new OpenAI(clientOptions);
|
this.client = new OpenAI(clientOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ export class OpenAiEngine implements AiEngine {
|
|||||||
this.config.maxTokensInput - this.config.maxTokensOutput
|
this.config.maxTokensInput - this.config.maxTokensOutput
|
||||||
)
|
)
|
||||||
throw new Error(GenerateCommitMessageErrorEnum.tooMuchTokens);
|
throw new Error(GenerateCommitMessageErrorEnum.tooMuchTokens);
|
||||||
|
|
||||||
const completion = await this.client.chat.completions.create(params);
|
const completion = await this.client.chat.completions.create(params);
|
||||||
|
|
||||||
const message = completion.choices[0].message;
|
const message = completion.choices[0].message;
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ const generateCommitMessageChatCompletionPrompt = async (
|
|||||||
fullGitMojiSpec: boolean,
|
fullGitMojiSpec: boolean,
|
||||||
context: string
|
context: string
|
||||||
): Promise<Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>> => {
|
): Promise<Array<OpenAI.Chat.Completions.ChatCompletionMessageParam>> => {
|
||||||
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(fullGitMojiSpec, context);
|
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
||||||
|
fullGitMojiSpec,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
|
const chatContextAsCompletionRequest = [...INIT_MESSAGES_PROMPT];
|
||||||
|
|
||||||
@@ -38,7 +41,7 @@ const ADJUSTMENT_FACTOR = 20;
|
|||||||
export const generateCommitMessageByDiff = async (
|
export const generateCommitMessageByDiff = async (
|
||||||
diff: string,
|
diff: string,
|
||||||
fullGitMojiSpec: boolean = false,
|
fullGitMojiSpec: boolean = false,
|
||||||
context: string = ""
|
context: string = ''
|
||||||
): Promise<string> => {
|
): Promise<string> => {
|
||||||
try {
|
try {
|
||||||
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
const INIT_MESSAGES_PROMPT = await getMainCommitPrompt(
|
||||||
@@ -75,7 +78,7 @@ export const generateCommitMessageByDiff = async (
|
|||||||
const messages = await generateCommitMessageChatCompletionPrompt(
|
const messages = await generateCommitMessageChatCompletionPrompt(
|
||||||
diff,
|
diff,
|
||||||
fullGitMojiSpec,
|
fullGitMojiSpec,
|
||||||
context,
|
context
|
||||||
);
|
);
|
||||||
|
|
||||||
const engine = getEngine();
|
const engine = getEngine();
|
||||||
|
|||||||
@@ -56,10 +56,11 @@ const llmReadableRules: {
|
|||||||
blankline: (key, applicable) =>
|
blankline: (key, applicable) =>
|
||||||
`There should ${applicable} be a blank line at the beginning of the ${key}.`,
|
`There should ${applicable} be a blank line at the beginning of the ${key}.`,
|
||||||
caseRule: (key, applicable, value: string | Array<string>) =>
|
caseRule: (key, applicable, value: string | Array<string>) =>
|
||||||
`The ${key} should ${applicable} be in ${Array.isArray(value)
|
`The ${key} should ${applicable} be in ${
|
||||||
? `one of the following case:
|
Array.isArray(value)
|
||||||
|
? `one of the following case:
|
||||||
- ${value.join('\n - ')}.`
|
- ${value.join('\n - ')}.`
|
||||||
: `${value} case.`
|
: `${value} case.`
|
||||||
}`,
|
}`,
|
||||||
emptyRule: (key, applicable) => `The ${key} should ${applicable} be empty.`,
|
emptyRule: (key, applicable) => `The ${key} should ${applicable} be empty.`,
|
||||||
enumRule: (key, applicable, value: string | Array<string>) =>
|
enumRule: (key, applicable, value: string | Array<string>) =>
|
||||||
@@ -67,17 +68,18 @@ const llmReadableRules: {
|
|||||||
- ${Array.isArray(value) ? value.join('\n - ') : value}.`,
|
- ${Array.isArray(value) ? value.join('\n - ') : value}.`,
|
||||||
enumTypeRule: (key, applicable, value: string | Array<string>, prompt) =>
|
enumTypeRule: (key, applicable, value: string | Array<string>, prompt) =>
|
||||||
`The ${key} should ${applicable} be one of the following values:
|
`The ${key} should ${applicable} be one of the following values:
|
||||||
- ${Array.isArray(value)
|
- ${
|
||||||
|
Array.isArray(value)
|
||||||
? value
|
? value
|
||||||
.map((v) => {
|
.map((v) => {
|
||||||
const description = getTypeRuleExtraDescription(v, prompt);
|
const description = getTypeRuleExtraDescription(v, prompt);
|
||||||
if (description) {
|
if (description) {
|
||||||
return `${v} (${description})`;
|
return `${v} (${description})`;
|
||||||
} else return v;
|
} else return v;
|
||||||
})
|
})
|
||||||
.join('\n - ')
|
.join('\n - ')
|
||||||
: value
|
: value
|
||||||
}.`,
|
}.`,
|
||||||
fullStopRule: (key, applicable, value: string) =>
|
fullStopRule: (key, applicable, value: string) =>
|
||||||
`The ${key} should ${applicable} end with '${value}'.`,
|
`The ${key} should ${applicable} end with '${value}'.`,
|
||||||
maxLengthRule: (key, applicable, value: string) =>
|
maxLengthRule: (key, applicable, value: string) =>
|
||||||
@@ -214,16 +216,20 @@ const STRUCTURE_OF_COMMIT = config.OCO_OMIT_SCOPE
|
|||||||
const GEN_COMMITLINT_CONSISTENCY_PROMPT = (
|
const GEN_COMMITLINT_CONSISTENCY_PROMPT = (
|
||||||
prompts: string[]
|
prompts: string[]
|
||||||
): OpenAI.Chat.Completions.ChatCompletionMessageParam[] => [
|
): OpenAI.Chat.Completions.ChatCompletionMessageParam[] => [
|
||||||
{
|
{
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages for two different changes in a single codebase and output them in the provided JSON format: one for a bug fix and another for a new feature.
|
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages for two different changes in a single codebase and output them in the provided JSON format: one for a bug fix and another for a new feature.
|
||||||
|
|
||||||
Here are the specific requirements and conventions that should be strictly followed:
|
Here are the specific requirements and conventions that should be strictly followed:
|
||||||
|
|
||||||
Commit Message Conventions:
|
Commit Message Conventions:
|
||||||
- The commit message consists of three parts: Header, Body, and Footer.
|
- The commit message consists of three parts: Header, Body, and Footer.
|
||||||
- Header:
|
- Header:
|
||||||
- Format: ${config.OCO_OMIT_SCOPE ? '`<type>: <subject>`' : '`<type>(<scope>): <subject>`'}
|
- Format: ${
|
||||||
|
config.OCO_OMIT_SCOPE
|
||||||
|
? '`<type>: <subject>`'
|
||||||
|
: '`<type>(<scope>): <subject>`'
|
||||||
|
}
|
||||||
- ${prompts.join('\n- ')}
|
- ${prompts.join('\n- ')}
|
||||||
|
|
||||||
JSON Output Format:
|
JSON Output Format:
|
||||||
@@ -246,9 +252,9 @@ Additional Details:
|
|||||||
- Allowing the server to listen on a port specified through the environment variable is considered a new feature.
|
- Allowing the server to listen on a port specified through the environment variable is considered a new feature.
|
||||||
|
|
||||||
Example Git Diff is to follow:`
|
Example Git Diff is to follow:`
|
||||||
},
|
},
|
||||||
INIT_DIFF_PROMPT
|
INIT_DIFF_PROMPT
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prompt to have LLM generate a message using @commitlint rules.
|
* Prompt to have LLM generate a message using @commitlint rules.
|
||||||
@@ -262,25 +268,30 @@ const INIT_MAIN_PROMPT = (
|
|||||||
prompts: string[]
|
prompts: string[]
|
||||||
): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({
|
): OpenAI.Chat.Completions.ChatCompletionMessageParam => ({
|
||||||
role: 'system',
|
role: 'system',
|
||||||
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${config.OCO_WHY ? 'and WHY the changes were done' : ''
|
content: `${IDENTITY} Your mission is to create clean and comprehensive commit messages in the given @commitlint convention and explain WHAT were the changes ${
|
||||||
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
|
config.OCO_WHY ? 'and WHY the changes were done' : ''
|
||||||
${config.OCO_EMOJI
|
}. I'll send you an output of 'git diff --staged' command, and you convert it into a commit message.
|
||||||
? 'Use GitMoji convention to preface the commit.'
|
${
|
||||||
: 'Do not preface the commit with anything.'
|
config.OCO_EMOJI
|
||||||
}
|
? 'Use GitMoji convention to preface the commit.'
|
||||||
${config.OCO_DESCRIPTION
|
: 'Do not preface the commit with anything.'
|
||||||
? 'Add a short description of WHY the changes are done after the commit message. Don\'t start it with "This commit", just describe the changes.'
|
}
|
||||||
: "Don't add any descriptions to the commit, only commit message."
|
${
|
||||||
}
|
config.OCO_DESCRIPTION
|
||||||
|
? 'Add a short description of WHY the changes are done after the commit message. Don\'t start it with "This commit", just describe the changes.'
|
||||||
|
: "Don't add any descriptions to the commit, only commit message."
|
||||||
|
}
|
||||||
Use the present tense. Use ${language} to answer.
|
Use the present tense. Use ${language} to answer.
|
||||||
${config.OCO_ONE_LINE_COMMIT
|
${
|
||||||
? 'Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change.'
|
config.OCO_ONE_LINE_COMMIT
|
||||||
: ''
|
? 'Craft a concise commit message that encapsulates all changes made, with an emphasis on the primary updates. If the modifications share a common theme or scope, mention it succinctly; otherwise, leave the scope out to maintain focus. The goal is to provide a clear and unified overview of the changes in a one single message, without diverging into a list of commit per file change.'
|
||||||
}
|
: ''
|
||||||
${config.OCO_OMIT_SCOPE
|
}
|
||||||
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
|
${
|
||||||
: ''
|
config.OCO_OMIT_SCOPE
|
||||||
}
|
? 'Do not include a scope in the commit message format. Use the format: <type>: <subject>'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
You will strictly follow the following conventions to generate the content of the commit message:
|
You will strictly follow the following conventions to generate the content of the commit message:
|
||||||
- ${prompts.join('\n- ')}
|
- ${prompts.join('\n- ')}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const getJSONBlock = (input: string): string => {
|
|||||||
if (jsonIndex > -1) {
|
if (jsonIndex > -1) {
|
||||||
input = input.slice(jsonIndex + 8);
|
input = input.slice(jsonIndex + 8);
|
||||||
const endJsonIndex = input.search('```');
|
const endJsonIndex = input.search('```');
|
||||||
input = input.slice(0, endJsonIndex);
|
input = input.slice(0, endJsonIndex);
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
};
|
};
|
||||||
|
|||||||
+14
-14
@@ -155,9 +155,9 @@ const INIT_MAIN_PROMPT = (
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const INIT_DIFF_PROMPT: OpenAI.Chat.Completions.ChatCompletionMessageParam =
|
export const INIT_DIFF_PROMPT: OpenAI.Chat.Completions.ChatCompletionMessageParam =
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: `diff --git a/src/server.ts b/src/server.ts
|
content: `diff --git a/src/server.ts b/src/server.ts
|
||||||
index ad4db42..f3b18a9 100644
|
index ad4db42..f3b18a9 100644
|
||||||
--- a/src/server.ts
|
--- a/src/server.ts
|
||||||
+++ b/src/server.ts
|
+++ b/src/server.ts
|
||||||
@@ -181,7 +181,7 @@ export const INIT_DIFF_PROMPT: OpenAI.Chat.Completions.ChatCompletionMessagePara
|
|||||||
+app.listen(process.env.PORT || PORT, () => {
|
+app.listen(process.env.PORT || PORT, () => {
|
||||||
+ console.log(\`Server listening on port \${PORT}\`);
|
+ console.log(\`Server listening on port \${PORT}\`);
|
||||||
});`
|
});`
|
||||||
};
|
};
|
||||||
|
|
||||||
const COMMIT_TYPES = {
|
const COMMIT_TYPES = {
|
||||||
fix: '🐛',
|
fix: '🐛',
|
||||||
@@ -193,19 +193,19 @@ const generateCommitString = (
|
|||||||
message: string
|
message: string
|
||||||
): string => {
|
): string => {
|
||||||
const cleanMessage = removeConventionalCommitWord(message);
|
const cleanMessage = removeConventionalCommitWord(message);
|
||||||
return config.OCO_EMOJI
|
return config.OCO_EMOJI ? `${COMMIT_TYPES[type]} ${cleanMessage}` : message;
|
||||||
? `${COMMIT_TYPES[type]} ${cleanMessage}`
|
|
||||||
: message;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getConsistencyContent = (translation: ConsistencyPrompt) => {
|
const getConsistencyContent = (translation: ConsistencyPrompt) => {
|
||||||
const fixMessage = config.OCO_OMIT_SCOPE && translation.commitFixOmitScope
|
const fixMessage =
|
||||||
? translation.commitFixOmitScope
|
config.OCO_OMIT_SCOPE && translation.commitFixOmitScope
|
||||||
: translation.commitFix;
|
? translation.commitFixOmitScope
|
||||||
|
: translation.commitFix;
|
||||||
|
|
||||||
const featMessage = config.OCO_OMIT_SCOPE && translation.commitFeatOmitScope
|
const featMessage =
|
||||||
? translation.commitFeatOmitScope
|
config.OCO_OMIT_SCOPE && translation.commitFeatOmitScope
|
||||||
: translation.commitFeat;
|
? translation.commitFeatOmitScope
|
||||||
|
: translation.commitFeat;
|
||||||
|
|
||||||
const fix = generateCommitString('fix', fixMessage);
|
const fix = generateCommitString('fix', fixMessage);
|
||||||
const feat = config.OCO_ONE_LINE_COMMIT
|
const feat = config.OCO_ONE_LINE_COMMIT
|
||||||
@@ -250,7 +250,7 @@ export const getMainCommitPrompt = async (
|
|||||||
INIT_DIFF_PROMPT,
|
INIT_DIFF_PROMPT,
|
||||||
INIT_CONSISTENCY_PROMPT(
|
INIT_CONSISTENCY_PROMPT(
|
||||||
commitLintConfig.consistency[
|
commitLintConfig.consistency[
|
||||||
translation.localLanguage
|
translation.localLanguage
|
||||||
] as ConsistencyPrompt
|
] as ConsistencyPrompt
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,20 +4,23 @@
|
|||||||
* @param tag The tag name without angle brackets (e.g., 'think' for '<think></think>')
|
* @param tag The tag name without angle brackets (e.g., 'think' for '<think></think>')
|
||||||
* @returns The content with the specified tags and their contents removed, and trimmed
|
* @returns The content with the specified tags and their contents removed, and trimmed
|
||||||
*/
|
*/
|
||||||
export function removeContentTags<T extends string | null | undefined>(content: T, tag: string): T {
|
export function removeContentTags<T extends string | null | undefined>(
|
||||||
|
content: T,
|
||||||
|
tag: string
|
||||||
|
): T {
|
||||||
if (!content || typeof content !== 'string') {
|
if (!content || typeof content !== 'string') {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic implementation for other cases
|
// Dynamic implementation for other cases
|
||||||
const openTag = `<${tag}>`;
|
const openTag = `<${tag}>`;
|
||||||
const closeTag = `</${tag}>`;
|
const closeTag = `</${tag}>`;
|
||||||
|
|
||||||
// Parse the content and remove tags
|
// Parse the content and remove tags
|
||||||
let result = '';
|
let result = '';
|
||||||
let skipUntil: number | null = null;
|
let skipUntil: number | null = null;
|
||||||
let depth = 0;
|
let depth = 0;
|
||||||
|
|
||||||
for (let i = 0; i < content.length; i++) {
|
for (let i = 0; i < content.length; i++) {
|
||||||
// Check for opening tag
|
// Check for opening tag
|
||||||
if (content.substring(i, i + openTag.length) === openTag) {
|
if (content.substring(i, i + openTag.length) === openTag) {
|
||||||
@@ -29,7 +32,10 @@ export function removeContentTags<T extends string | null | undefined>(content:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check for closing tag
|
// Check for closing tag
|
||||||
else if (content.substring(i, i + closeTag.length) === closeTag && depth > 0) {
|
else if (
|
||||||
|
content.substring(i, i + closeTag.length) === closeTag &&
|
||||||
|
depth > 0
|
||||||
|
) {
|
||||||
depth--;
|
depth--;
|
||||||
if (depth === 0) {
|
if (depth === 0) {
|
||||||
i = i + closeTag.length - 1; // Skip the closing tag
|
i = i + closeTag.length - 1; // Skip the closing tag
|
||||||
@@ -37,7 +43,7 @@ export function removeContentTags<T extends string | null | undefined>(content:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only add character if not inside a tag
|
// Only add character if not inside a tag
|
||||||
if (skipUntil === null) {
|
if (skipUntil === null) {
|
||||||
result += content[i];
|
result += content[i];
|
||||||
|
|||||||
Reference in New Issue
Block a user