@pega/commitlint-plugin
Advanced tools
Comparing version 0.8.0 to 0.9.0
250
index.js
@@ -5,24 +5,10 @@ /* eslint-disable sonarjs/cognitive-complexity */ | ||
/** | ||
* @template [Value=never] | ||
* @typedef {import('@commitlint/types').Rule<Value>} Rule<Value> | ||
*/ | ||
/** | ||
* @template [Value=never] | ||
* @typedef {import('@commitlint/types').SyncRule<Value>} SyncRule<Value> | ||
*/ | ||
/** | ||
* @template [Value=never] | ||
* @typedef {import('@commitlint/types').AsyncRule<Value>} AsyncRule<Value> | ||
*/ | ||
const { fork } = require('child_process'); | ||
// Type rules as Record<string, Rule<any>> to allow it to match Plugin type while still having types for rule parameters. | ||
const /** @type {{ rules: Record<string, Rule<any>> } }} */ Plugin = { | ||
const /** @type {{ rules: Record<string, import('@commitlint/types').Rule<any>> } }} */ Plugin = { | ||
rules: { | ||
'@pega/multi-scope-enum': | ||
/** @type {SyncRule<{ scopes?: string[]; separator?: string | RegExp; trim?: boolean; }>} */ ( | ||
/** @satisfies {import('@commitlint/types').SyncRule<{ scopes?: string[]; separator?: string | RegExp; trim?: boolean; }>} */ | ||
( | ||
{ scope }, | ||
@@ -48,24 +34,24 @@ enable = 'always', | ||
'@pega/header-reference': /** @type {SyncRule} */ ( | ||
{ header, references }, | ||
enable = 'always' | ||
) => { | ||
if (!header) return [true, '']; | ||
'@pega/header-reference': | ||
/** @satisfies {import('@commitlint/types').SyncRule} */ | ||
({ header, references }, enable = 'always') => { | ||
if (!header) return [true, '']; | ||
if (enable === 'always') { | ||
if (enable === 'always') { | ||
return [ | ||
references.some(({ raw }) => header.includes(raw)), | ||
'Header must contain a reference id.' | ||
]; | ||
} | ||
// enable === 'never' | ||
return [ | ||
references.some(({ raw }) => header.includes(raw)), | ||
'Header must contain a reference id.' | ||
!references.some(({ raw }) => header.includes(raw)), | ||
'Header must not contain a reference id.' | ||
]; | ||
} | ||
}, | ||
// enable === 'never' | ||
return [ | ||
!references.some(({ raw }) => header.includes(raw)), | ||
'Header must not contain a reference id.' | ||
]; | ||
}, | ||
'@pega/reference-action-enum': | ||
/** @type {SyncRule<{ actions?: string[]; caseSensitive?: boolean; }>} */ ( | ||
/** @satisfies {import('@commitlint/types').SyncRule<{ actions?: string[]; caseSensitive?: boolean; }>} */ | ||
( | ||
{ references }, | ||
@@ -113,7 +99,4 @@ enable = 'always', | ||
'@pega/reference-order': | ||
/** @type {SyncRule<{ prefixes?: string[]; ascending?: boolean; }>} */ ( | ||
{ references }, | ||
enable = 'always', | ||
{ prefixes = ['#'], ascending = true } = {} | ||
) => { | ||
/** @satisfies {import('@commitlint/types').SyncRule<{ prefixes?: string[]; ascending?: boolean; }>} */ | ||
({ references }, enable = 'always', { prefixes = ['#'], ascending = true } = {}) => { | ||
if (references.length < 2 || enable !== 'always') return [true, '']; | ||
@@ -171,125 +154,132 @@ | ||
'@pega/agile-studio': /** @type {SyncRule<{ prefixes?: string[]; }>} */ ( | ||
{ footer }, | ||
enable = 'always', | ||
{ prefixes = ['#'] } = {} | ||
) => { | ||
if (enable !== 'always' || !footer) return [true, '']; | ||
'@pega/agile-studio': | ||
/** @satisfies {import('@commitlint/types').SyncRule<{ prefixes?: string[]; }>} */ | ||
({ footer }, enable = 'always', { prefixes = ['#'] } = {}) => { | ||
if (enable !== 'always' || !footer) return [true, '']; | ||
if (footer.indexOf('AgileStudio:') !== footer.lastIndexOf('AgileStudio:')) { | ||
return [false, 'Multiple Agile Studio notes found.']; | ||
} | ||
if (footer.indexOf('AgileStudio:') !== footer.lastIndexOf('AgileStudio:')) { | ||
return [false, 'Multiple Agile Studio notes found.']; | ||
} | ||
const [, agileStudioNote] = /^AgileStudio: (.+)$/m.exec(footer) ?? []; | ||
const [, agileStudioNote] = /^AgileStudio: (.+)$/m.exec(footer) ?? []; | ||
if (!agileStudioNote) return [true, '']; | ||
if (!agileStudioNote) return [true, '']; | ||
if (/\.$/.test(agileStudioNote)) { | ||
return [false, 'Agile Studio note should not end in a period.']; | ||
} | ||
if (/\.$/.test(agileStudioNote)) { | ||
return [false, 'Agile Studio note should not end in a period.']; | ||
} | ||
if (/,[^ ]/.test(agileStudioNote)) { | ||
return [false, 'Agile Studio ids should be separated by a comma and space.']; | ||
} | ||
if (/,[^ ]/.test(agileStudioNote)) { | ||
return [false, 'Agile Studio ids should be separated by a comma and space.']; | ||
} | ||
// Check if id is a case id. | ||
const idRegExp = new RegExp(`^(?:${prefixes.join('|')})[0-9-]+$`); | ||
// Check if id is a case id. | ||
const idRegExp = new RegExp(`^(?:${prefixes.join('|')})[0-9-]+$`); | ||
for (const id of agileStudioNote.split(', ')) { | ||
if (!idRegExp.test(id)) { | ||
return [false, `Agile Studio id does not match expected format "${id}".`]; | ||
for (const id of agileStudioNote.split(', ')) { | ||
if (!idRegExp.test(id)) { | ||
return [false, `Agile Studio id does not match expected format "${id}".`]; | ||
} | ||
} | ||
} | ||
return [true, '']; | ||
}, | ||
return [true, '']; | ||
}, | ||
'@pega/open-agile': /** @type {SyncRule<{ prefixes?: string[]; }>} */ ( | ||
{ footer }, | ||
enable = 'always', | ||
{ prefixes = ['#'] } = {} | ||
) => { | ||
if (enable !== 'always' || !footer) return [true, '']; | ||
'@pega/open-agile': | ||
/** @satisfies {import('@commitlint/types').SyncRule<{ prefixes?: string[]; }>} */ | ||
({ footer }, enable = 'always', { prefixes = ['#'] } = {}) => { | ||
if (enable !== 'always' || !footer) return [true, '']; | ||
if (footer.indexOf('OpenAgile:') !== footer.lastIndexOf('OpenAgile:')) { | ||
return [false, 'Multiple Open Agile notes found.']; | ||
} | ||
if (footer.indexOf('OpenAgile:') !== footer.lastIndexOf('OpenAgile:')) { | ||
return [false, 'Multiple Open Agile notes found.']; | ||
} | ||
const [, openAgileNote] = /^OpenAgile: (.+)$/m.exec(footer) ?? []; | ||
const [, openAgileNote] = /^OpenAgile: (.+)$/m.exec(footer) ?? []; | ||
if (!openAgileNote) return [true, '']; | ||
if (!openAgileNote) return [true, '']; | ||
if (/\.$/.test(openAgileNote)) { | ||
return [false, 'Open Agile note should not end in a period.']; | ||
} | ||
if (/\.$/.test(openAgileNote)) { | ||
return [false, 'Open Agile note should not end in a period.']; | ||
} | ||
if (/,[^ ]/.test(openAgileNote)) { | ||
return [false, 'Open Agile id pairs should be separated by a comma and space.']; | ||
} | ||
if (/,[^ ]/.test(openAgileNote)) { | ||
return [false, 'Open Agile id pairs should be separated by a comma and space.']; | ||
} | ||
// Check if id pair is a case id followed by a base64 hash. | ||
const idPairRegExp = new RegExp(`^(?:${prefixes.join('|')})[A-Z0-9]+ [a-zA-Z0-9=_-]+$`); | ||
// Check if id pair is a case id followed by a base64 hash. | ||
const idPairRegExp = new RegExp(`^(?:${prefixes.join('|')})[A-Z0-9]+ [a-zA-Z0-9=_-]+$`); | ||
for (const idPair of openAgileNote.split(', ')) { | ||
if (!idPairRegExp.test(idPair)) { | ||
return [false, `Open Agile id pair does not match expected format "${idPair}".`]; | ||
for (const idPair of openAgileNote.split(', ')) { | ||
if (!idPairRegExp.test(idPair)) { | ||
return [false, `Open Agile id pair does not match expected format "${idPair}".`]; | ||
} | ||
} | ||
} | ||
return [true, '']; | ||
}, | ||
return [true, '']; | ||
}, | ||
'@pega/merge-commit': /** @type {SyncRule} */ ({ merge }, enable = 'never') => { | ||
if (enable !== 'never') return [true, '']; | ||
'@pega/merge-commit': | ||
/** @satisfies {import('@commitlint/types').SyncRule} */ | ||
({ merge }, enable = 'never') => { | ||
if (enable !== 'never') return [true, '']; | ||
return [!merge, 'Merge commits are not allowed.']; | ||
}, | ||
return [!merge, 'Merge commits are not allowed.']; | ||
}, | ||
'@pega/revert-commit': /** @type {SyncRule} */ ({ revert }, enable = 'never') => { | ||
if (enable !== 'never') return [true, '']; | ||
'@pega/revert-commit': | ||
/** @satisfies {import('@commitlint/types').SyncRule} */ | ||
({ revert }, enable = 'never') => { | ||
if (enable !== 'never') return [true, '']; | ||
return [!revert, 'Revert commits are not allowed.']; | ||
}, | ||
return [!revert, 'Revert commits are not allowed.']; | ||
}, | ||
'@pega/spellcheck': /** @type {AsyncRule<{ ignorePrefixes?: string[]; }>} */ async ( | ||
{ raw }, | ||
enable = 'always', | ||
{ ignorePrefixes = [] } = {} | ||
) => { | ||
if (enable !== 'always') return [true, '']; | ||
'@pega/spellcheck': | ||
/** @satisfies {import('@commitlint/types').AsyncRule<{ ignorePrefixes?: string[]; }>} */ | ||
async ({ raw }, enable = 'always', { ignorePrefixes = [] } = {}) => { | ||
if (enable !== 'always') return [true, '']; | ||
const cspell = fork(require.resolve('cspell/bin'), ['--no-summary', '--unique', 'stdin'], { | ||
stdio: 'pipe' | ||
}); | ||
const cspell = fork( | ||
require.resolve('cspell/bin'), | ||
['--no-summary', '--unique', 'stdin'], | ||
{ | ||
stdio: 'pipe' | ||
} | ||
); | ||
cspell.stdin?.write( | ||
raw | ||
.split('\n') | ||
.filter(s => !s.startsWith('#') && ignorePrefixes.some(prefix => !s.startsWith(prefix))) | ||
.join('\n') | ||
); | ||
cspell.stdin?.end(); | ||
cspell.stdin?.write( | ||
raw | ||
.split('\n') | ||
.filter( | ||
s => !s.startsWith('#') && ignorePrefixes.some(prefix => !s.startsWith(prefix)) | ||
) | ||
.join('\n') | ||
); | ||
cspell.stdin?.end(); | ||
/** @type {Buffer[]} */ | ||
const out = []; | ||
let outLen = 0; | ||
cspell.stdout?.on('data', chunk => { | ||
out.push(chunk); | ||
outLen += Buffer.byteLength(chunk); | ||
}); | ||
/** @type {Buffer[]} */ | ||
const out = []; | ||
let outLen = 0; | ||
cspell.stdout?.on('data', chunk => { | ||
out.push(chunk); | ||
outLen += Buffer.byteLength(chunk); | ||
}); | ||
return new Promise(resolve => { | ||
cspell.on('exit', code => { | ||
if (code === 0) resolve([true, '']); | ||
return new Promise(resolve => { | ||
cspell.on('exit', code => { | ||
if (code === 0) resolve([true, '']); | ||
const output = Buffer.concat(out, outLen).toString('utf-8'); | ||
const output = Buffer.concat(out, outLen).toString('utf-8'); | ||
const words = [...output.matchAll(/^.+:\d+:\d+ - Unknown word \((.*)\)$/gm)].map( | ||
([, word]) => word | ||
); | ||
const words = [...output.matchAll(/^.+:\d+:\d+ - Unknown word \((.*)\)$/gm)].map( | ||
([, word]) => word | ||
); | ||
resolve([false, `Unknown word${words.length === 1 ? '' : 's'} [${words.join(', ')}].`]); | ||
resolve([ | ||
false, | ||
`Unknown word${words.length === 1 ? '' : 's'} [${words.join(', ')}].` | ||
]); | ||
}); | ||
}); | ||
}); | ||
} | ||
} | ||
} | ||
@@ -296,0 +286,0 @@ }; |
{ | ||
"name": "@pega/commitlint-plugin", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "Pega front-end commitlint plugin.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
23210
230