/** A variable the site knows, as the "Insert variable" menu lists it. */ interface KnownVariable { name: string; } /** Variables that differ from one page to the next. */ const PER_PAGE = /%(title|excerpt|focuskw|category|primary_category|date|author|term|term_description|search_query|customfield\([^)]*\)|customterm\([^)]*\))%/i; /** * Templates that print one page each, and the variables that tell those * pages apart; without one, every page of the kind prints the same text. */ const NEEDS: { field: RegExp; kind: string; variables: string[] }[] = [ { field: /^pt_.+(? { const warnings: string[] = []; const typed = template.trim(); if (typed === '') return warnings; const known = (token: string): boolean => { const base = token.replace(/\(.*\)%$/, ''); return variables.some( variable => variable.name === token || variable.name.startsWith(`${base}(`) || variable.name === `${base}%` ); }; const unknown = Array.from( new Set(Array.from(typed.matchAll(/%[a-z_]+(?:\([^)]*\))?%/gi), m => m[0])) ).filter(token => !known(token)); if (unknown.length > 0) { warnings.push( `${unknown.join(', ')} ${unknown.length === 1 ? 'is not a variable' : 'are not variables'} this site knows, so ${unknown.length === 1 ? 'it prints' : 'they print'} nothing.` ); } const need = NEEDS.find(rule => rule.field.test(field)); if ( need && !need.variables.some(variable => typed.toLowerCase().includes(variable)) ) { warnings.push( `Every ${need.kind} gets this same title: add ${need.variables.join(' or ')} so each one reads as its own page.` ); } else if (DESCRIPTIONS.test(field) && !PER_PAGE.test(typed)) { warnings.push( 'Every page gets this same description: add %excerpt%, %title% or another variable of the page.' ); } return warnings; };