📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env node
|
||||
// Offline citation-library consistency checks. This intentionally does not
|
||||
// fetch URLs; it validates the local allow-list contract used by sanitizers.
|
||||
|
||||
import { loadLibrary, matchesFrameworkVersion } from '../lib/citations.mjs';
|
||||
|
||||
const URL_RE = /^https:\/\/[A-Za-z0-9.-]+\/\S*$/;
|
||||
const SKILL_REF_RE = /^[\w-]+:[\w-]+$/;
|
||||
const BANNED_STALE_URLS = new Set([
|
||||
'https://nextjs.org/docs/app/api-reference/functions/cache-life',
|
||||
'https://nextjs.org/docs/app/api-reference/functions/cache-tag',
|
||||
'https://nextjs.org/docs/app/api-reference/functions/revalidate-tag',
|
||||
'https://nextjs.org/docs/app/api-reference/functions/revalidate-path',
|
||||
'https://nextjs.org/docs/app/api-reference/functions/cache',
|
||||
]);
|
||||
|
||||
async function main() {
|
||||
const lib = await loadLibrary();
|
||||
const errors = [];
|
||||
|
||||
if (!Array.isArray(lib.urls)) errors.push('docs-library.urls must be an array');
|
||||
if (!Array.isArray(lib.ruleSkillRefs)) errors.push('docs-library.ruleSkillRefs must be an array');
|
||||
|
||||
for (const [i, entry] of (lib.urls ?? []).entries()) {
|
||||
const label = `urls[${i}]`;
|
||||
if (!URL_RE.test(entry?.url ?? '')) errors.push(`${label}.url must be an https URL`);
|
||||
if (BANNED_STALE_URLS.has(entry?.url)) {
|
||||
errors.push(`${label}.url uses a stale Next.js docs path: ${entry.url}`);
|
||||
}
|
||||
if (typeof entry.topic !== 'string' || entry.topic.trim() === '') errors.push(`${label}.topic is required`);
|
||||
if (!Array.isArray(entry.appliesTo)) errors.push(`${label}.appliesTo must be an array`);
|
||||
validateFrameworks(entry.applicableFrameworks, `${label}.applicableFrameworks`, errors);
|
||||
}
|
||||
|
||||
const seenRules = new Set();
|
||||
for (const [i, entry] of (lib.ruleSkillRefs ?? []).entries()) {
|
||||
const label = `ruleSkillRefs[${i}]`;
|
||||
const ref = `${entry?.skill ?? ''}:${entry?.rule ?? ''}`;
|
||||
if (!SKILL_REF_RE.test(ref)) errors.push(`${label} must contain skill + rule identifiers`);
|
||||
if (seenRules.has(ref)) errors.push(`${label} duplicate: ${ref}`);
|
||||
seenRules.add(ref);
|
||||
if (typeof (entry.description ?? entry.topic) !== 'string' || (entry.description ?? entry.topic).trim() === '') {
|
||||
errors.push(`${label}.topic or .description is required`);
|
||||
}
|
||||
validateFrameworks(entry.applicableFrameworks, `${label}.applicableFrameworks`, errors);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
for (const error of errors) console.error(`[check-citations] ${error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.error(`[check-citations] OK — ${lib.urls.length} URLs, ${lib.ruleSkillRefs.length} skill-rule refs`);
|
||||
}
|
||||
|
||||
function validateFrameworks(patterns, label, errors) {
|
||||
if (!Array.isArray(patterns) || patterns.length === 0) {
|
||||
errors.push(`${label} must be a non-empty array`);
|
||||
return;
|
||||
}
|
||||
for (const pattern of patterns) {
|
||||
if (typeof pattern !== 'string' || pattern.trim() === '') {
|
||||
errors.push(`${label} contains an empty pattern`);
|
||||
continue;
|
||||
}
|
||||
if (pattern === '*') continue;
|
||||
// Smoke-check parser coverage with a modern Next version. Unknown framework
|
||||
// patterns are still valid as long as the syntax is recognizable.
|
||||
if (!/^[\w-]+@(?:\*|\d+(?:\.\d+){0,2}|[<>]=?\s*\d+(?:\.\d+){0,2})(?:\s*\|\|\s*[\w-]+@(?:\*|\d+(?:\.\d+){0,2}|[<>]=?\s*\d+(?:\.\d+){0,2}))*$/.test(pattern)) {
|
||||
errors.push(`${label} has unsupported pattern: ${pattern}`);
|
||||
continue;
|
||||
}
|
||||
matchesFrameworkVersion(pattern, 'next', '16.0.0');
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('[check-citations] FAILED:', err.message);
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user