@@ -7,31 +7,16 @@ import { execFileSync } from "node:child_process";
77import path from "node:path" ;
88import { fileURLToPath } from "node:url" ;
99import {
10- checkEntryBasics ,
10+ empty ,
11+ ENTRY_CHECKS ,
1112 checkPreviewVocabulary ,
1213 checkFeatured ,
1314 checkAiGuide ,
14- checkAttributionWaiver ,
15- checkAiTag ,
16- checkCreditPlaceholders ,
17- checkLimits ,
18- checkKnownKeys ,
19- checkActiveIsSettled ,
20- checkPreviewField ,
2115 checkThumbManifest ,
22- checkAddedDate ,
23- checkAttributionConsistency ,
2416 checkCategoryReadmeRows ,
2517 checkComparisonLicences ,
2618 checkCategorySets ,
2719 checkCountTables ,
28- checkDeprecationReason ,
29- checkEngineFields ,
30- checkEntryUrl ,
31- checkEvidenceDates ,
32- checkFieldTypes ,
33- checkFormatVocabulary ,
34- checkLicenseVocabulary ,
3520 checkLicenceGuide ,
3621 checkLineEndings ,
3722 checkEntryCount ,
@@ -40,15 +25,8 @@ import {
4025 categoryFormOptions ,
4126 hasEmoji ,
4227 checkRepoFiles ,
43- checkMaintenance ,
44- checkNonCommercialEvidence ,
4528 checkPublisherConsistency ,
46- checkSpdxConsistency ,
4729 checkStacks ,
48- checkTagsRestatePublisher ,
49- checkTaxonomyValues ,
50- checkTitleMatchesName ,
51- checkValueAliases ,
5230 checkValueSpellings ,
5331 markdownAnchors ,
5432} from "./checks.mjs" ;
@@ -115,13 +93,6 @@ function repoFiles() {
11593 }
11694}
11795
118- function isEmptyField ( v ) {
119- if ( v === undefined || v === null ) return true ;
120- if ( typeof v === "string" && v . trim ( ) === "" ) return true ;
121- if ( Array . isArray ( v ) && v . length === 0 ) return true ;
122- return false ;
123- }
124-
12596function relFromRoot ( file ) {
12697 return path . relative ( ROOT , file ) . split ( path . sep ) . join ( "/" ) ;
12798}
@@ -192,8 +163,8 @@ function coverageReport(entries) {
192163 for ( const meta of entries ) {
193164 const cat = String ( meta . category || "?" ) ;
194165 byCat . set ( cat , ( byCat . get ( cat ) || 0 ) + 1 ) ;
195- if ( ! isEmptyField ( meta . license_spdx ) ) spdx += 1 ;
196- if ( ! isEmptyField ( meta . publisher ) ) publisher += 1 ;
166+ if ( ! empty ( meta . license_spdx ) ) spdx += 1 ;
167+ if ( ! empty ( meta . publisher ) ) publisher += 1 ;
197168 }
198169 const n = entries . length ;
199170 const pct = ( c ) => ( n ? ( ( 100 * c ) / n ) . toFixed ( 1 ) : "0.0" ) ;
@@ -206,7 +177,12 @@ function coverageReport(entries) {
206177 return lines . join ( "\n" ) ;
207178}
208179
209- function main ( ) {
180+ /**
181+ * Every repository check, over this checkout. Returns the errors and what
182+ * the CLI summary prints; the CLI below exits on errors. Importable, so the
183+ * tests run it (#255).
184+ */
185+ export function validateRepo ( ) {
210186 const errors = [ ] ;
211187 // "In the future" means after tomorrow in UTC, so no time zone's today fails.
212188 const today = latestAllowedDate ( ) ;
@@ -237,33 +213,9 @@ function main() {
237213 const stem = path . basename ( file , ".md" ) ;
238214 const catReadme = path . join ( path . dirname ( file ) , "README.md" ) ;
239215 const readmeText = linkTarget ( catReadme ) . exists ? readText ( catReadme ) : null ;
240- errors . push (
241- ...checkEntryBasics ( rel , meta , body , { stem, dirName : path . basename ( path . dirname ( file ) ) , categories, readmeText, today } )
242- ) ;
243- errors . push ( ...checkKnownKeys ( rel , meta ) ) ;
244- errors . push ( ...checkCreditPlaceholders ( rel , meta ) ) ;
245- errors . push ( ...checkLimits ( rel , meta ) ) ;
246- errors . push ( ...checkAiTag ( rel , meta , body ) ) ;
247- errors . push ( ...checkAttributionWaiver ( rel , meta , body , vocab ) ) ;
248- // V24 types commercial and attribution_required (a quoted "true" is text).
249- errors . push ( ...checkFieldTypes ( rel , meta ) ) ;
250- errors . push ( ...checkEntryUrl ( rel , meta ) ) ;
251- errors . push ( ...checkLicenseVocabulary ( rel , meta , vocab ) ) ;
252- errors . push ( ...checkSpdxConsistency ( rel , meta , vocab , spdxAllowed ) ) ;
253- errors . push ( ...checkAttributionConsistency ( rel , meta , body , vocab ) ) ;
254- errors . push ( ...checkEvidenceDates ( rel , meta , body , today ) ) ;
255- errors . push ( ...checkDeprecationReason ( rel , meta , body , vocab ) ) ;
256- errors . push ( ...checkTaxonomyValues ( rel , meta ) ) ;
257- errors . push ( ...checkValueAliases ( rel , meta , aliases ) ) ;
258- errors . push ( ...checkFormatVocabulary ( rel , meta , formatVocab ) ) ;
259- errors . push ( ...checkTagsRestatePublisher ( rel , meta ) ) ;
260- errors . push ( ...checkMaintenance ( rel , meta ) ) ;
261- errors . push ( ...checkEngineFields ( rel , meta ) ) ;
262- errors . push ( ...checkActiveIsSettled ( rel , meta ) ) ;
263- errors . push ( ...checkNonCommercialEvidence ( rel , meta , body ) ) ;
264- errors . push ( ...checkPreviewField ( rel , meta ) ) ;
265- errors . push ( ...checkTitleMatchesName ( rel , meta , body ) ) ;
266- errors . push ( ...checkAddedDate ( rel , meta , today ) ) ;
216+ // Every per-entry check, from one list (checks.mjs ENTRY_CHECKS, #255).
217+ const ctx = { vocab, spdxAllowed, aliases, formatVocab, today, stem, dirName : path . basename ( path . dirname ( file ) ) , categories, readmeText } ;
218+ for ( const check of ENTRY_CHECKS ) errors . push ( ...check . run ( rel , meta , body , ctx ) ) ;
267219 if ( meta . id ) {
268220 const id = String ( meta . id ) ;
269221 if ( ids . has ( id ) ) errors . push ( `duplicate id "${ id } ": ${ ids . get ( id ) } and ${ rel } ` ) ;
@@ -373,16 +325,18 @@ function main() {
373325
374326 errors . push ( ...checkRepoFiles ( repoFiles ( ) ) ) ;
375327
328+ return { errors, entries, entryCount : entryFiles . length , idCount : ids . size , stackCount : stackFiles . length } ;
329+ }
330+
331+ function main ( ) {
332+ const { errors, entries, entryCount, idCount, stackCount } = validateRepo ( ) ;
376333 if ( errors . length ) {
377334 console . error ( `validate failed (${ errors . length } ):` ) ;
378335 for ( const e of errors ) console . error ( ` - ${ e } ` ) ;
379336 process . exit ( 1 ) ;
380337 }
381-
382- console . log (
383- `validate ok: ${ entryFiles . length } entries, ${ ids . size } ids, ${ stackFiles . length } stacks, no broken links`
384- ) ;
338+ console . log ( `validate ok: ${ entryCount } entries, ${ idCount } ids, ${ stackCount } stacks, no broken links` ) ;
385339 console . log ( coverageReport ( entries ) ) ;
386340}
387341
388- main ( ) ;
342+ if ( process . argv [ 1 ] && path . resolve ( process . argv [ 1 ] ) === fileURLToPath ( import . meta . url ) ) main ( ) ;
0 commit comments