feat: move clean up summary as a blocking error

This commit is contained in:
tdgao
2026-08-26 18:35:07 -06:00
parent 5dcd66f27f
commit 3ec0dfcf35
5 changed files with 40 additions and 13 deletions
@@ -21,7 +21,7 @@ const summaryErrorCodes: readonly ProjectTextValidationCode[] = [
'text-banned-link',
'summary-link',
]
const summaryWarningCodes: readonly ProjectTextValidationCode[] = ['summary-matches-title']
const summaryRequiredCodes: readonly ProjectTextValidationCode[] = ['summary-matches-title']
const descriptionErrorCodes: readonly ProjectTextValidationCode[] = [
'text-slur',
'text-profanity',
@@ -151,10 +151,10 @@ export const projectValidationNags: Nag[] = [
defaultMessage: 'Review the project summary',
}),
description: (context) =>
getFailureDescription(context, ['summary'], 'warn', summaryWarningCodes),
status: 'warning',
getFailureDescription(context, ['summary'], 'error', summaryRequiredCodes),
status: 'required',
shouldShow: (context) =>
getFirstFailure(context, ['summary'], 'warn', summaryWarningCodes) !== undefined,
getFirstFailure(context, ['summary'], 'error', summaryRequiredCodes) !== undefined,
link: {
path: 'settings',
title: defineMessage({
@@ -189,7 +189,7 @@ export const projectValidationNags: Nag[] = [
defaultMessage: 'Clean up the summary',
}),
description: (context) => getCodedFailureDescription(context, 'summary-special-formatting'),
status: 'warning',
status: 'required',
shouldShow: (context) => getCodedFailure(context, 'summary-special-formatting') !== undefined,
link: {
path: 'settings',
@@ -366,7 +366,7 @@
"defaultMessage": "The detected slur “{value}” is not allowed."
},
"project.text-validation.summary-matches-title": {
"defaultMessage": "A project summary should not be the same as its title."
"defaultMessage": "A project summary cannot be the same as it's title."
},
"project.text-validation.summary-too-short": {
"defaultMessage": "Your summary is {length, plural, one {# character} other {# characters}}. At least {minChars, plural, one {# character} other {# characters}} is recommended to create an informative and enticing summary."
@@ -84,7 +84,7 @@ const messages = defineMessages({
},
summaryMatchesTitle: {
id: 'project.text-validation.summary-matches-title',
defaultMessage: 'A project summary should not be the same as its title.',
defaultMessage: "A project summary cannot be the same as it's title.",
},
summaryTooShort: {
id: 'project.text-validation.summary-too-short',
@@ -138,8 +138,8 @@ export function normalizeProjectFieldText(value: string) {
}
export function projectSummaryMatchesTitle(summary: string, title: string) {
const normalizedSummary = normalizeProjectFieldText(summary)
const normalizedTitle = normalizeProjectFieldText(title)
const normalizedSummary = normalizeProjectFieldText(summary).replace(/\s+/g, '')
const normalizedTitle = normalizeProjectFieldText(title).replace(/\s+/g, '')
return normalizedSummary.length > 0 && normalizedSummary === normalizedTitle
}
@@ -353,7 +353,7 @@ export function validateProjectSummary(
return [
{
code: 'summary-matches-title',
severity: 'warn',
severity: 'error',
message: messages.summaryMatchesTitle,
},
]
@@ -372,7 +372,7 @@ export function validateProjectSummary(
if (hasProjectSummaryFormatting(summary) || containsExplicitLink) {
results.push({
code: containsExplicitLink ? 'summary-link' : 'summary-special-formatting',
severity: containsExplicitLink ? 'error' : 'warn',
severity: 'error',
message: messages.summarySpecialFormatting,
})
}
@@ -15,8 +15,9 @@ import {
validateProjectTitle,
} from './index.ts'
test('compares summaries and titles after trimming and Unicode normalization', () => {
test('compares summaries and titles without whitespace and after Unicode normalization', () => {
assert.equal(projectSummaryMatchesTitle(' Caf\u00e9 ', 'Cafe\u0301'), true)
assert.equal(projectSummaryMatchesTitle('Project summary', 'Projectsummary'), true)
assert.equal(projectSummaryMatchesTitle('Project summary', 'Project title'), false)
assert.equal(projectSummaryMatchesTitle('', ''), false)
})
@@ -127,7 +128,11 @@ test('validates project summaries', () => {
validateProjectSummary(' Caf\u00e9 ', 'Cafe\u0301')[0]?.message.id,
'project.text-validation.summary-matches-title',
)
assert.equal(validateProjectSummary(' Caf\u00e9 ', 'Cafe\u0301')[0]?.severity, 'warn')
assert.equal(validateProjectSummary(' Caf\u00e9 ', 'Cafe\u0301')[0]?.severity, 'error')
assert.equal(
validateProjectSummary(' Caf\u00e9 ', 'Cafe\u0301')[0]?.message.defaultMessage,
"A project summary cannot be the same as it's title.",
)
assert.deepEqual(validateProjectSummary('Short summary', 'Project title'), [
{
code: 'summary-too-short',
@@ -148,6 +153,7 @@ test('validates project summaries', () => {
validateProjectSummary('# Short summary', 'Project title').map(({ code }) => code),
['summary-too-short', 'summary-special-formatting'],
)
assert.equal(validateProjectSummary('# Short summary', 'Project title')[1]?.severity, 'error')
assert.equal(
validateProjectSummary('# Short summary', 'Project title')[1]?.message.defaultMessage,
summaryContentMessage,
@@ -87,6 +87,12 @@ test('reports whether a project has field validation failures', () => {
})
assert.equal(hasProjectFieldValidationFailures(validProject), false)
assert.equal(hasProjectFieldValidationFailures(invalidProject), true)
assert.equal(
hasProjectFieldValidationFailures(
createProject({ name: 'Ordinary Tools', summary: 'Ordinary Tools' }),
),
true,
)
})
test('treats version numbers and explicit summary links as errors', () => {
@@ -148,3 +154,18 @@ test('reports summary recommendations without invalidating the project', () => {
})
assert.equal(hasProjectFieldValidationFailures(project), false)
})
test('treats summary formatting as a field validation failure', () => {
const project = createProject({ summary: '# A formatted project summary' })
const result = validateProjectFields(project)
assert.equal(result.valid, false)
assert.deepEqual(
result.failures.map(({ code, severity }) => ({ code, severity })),
[
{ code: 'summary-too-short', severity: 'warn' },
{ code: 'summary-special-formatting', severity: 'error' },
],
)
assert.equal(hasProjectFieldValidationFailures(project), true)
})