refactor(forms): enable approved Form A placements by default
This commit is contained in:
41 files changed
+862
-523
No files matched your search
@@ -36,7 +36,7 @@ function hasTerminalSlash(url) {
|
||||
return pathname !== '/' && pathname.endsWith('/');
|
||||
}
|
||||
|
||||
const formAProductionUrls = new Map([
|
||||
const formAContactLandingUrls = new Map([
|
||||
['/contact', 'https://form.jotform.com/262946078314059?formContext=contact&language=en'],
|
||||
['/es/contact', 'https://form.jotform.com/262946078314059?formContext=contact&language=es'],
|
||||
['/lp/aba-therapy', 'https://form.jotform.com/262946078314059?formContext=landing&language=en'],
|
||||
@@ -61,7 +61,7 @@ const formAConsultationDrawerUrls = new Map([
|
||||
['/es/learner-social-club', 'https://form.jotform.com/262946078314059?formContext=consultation&language=es'],
|
||||
]);
|
||||
|
||||
const formAIsolatedStaticUrls = new Map([...formAProductionUrls, ...formAConsultationStaticUrls]);
|
||||
const formAStaticUrls = new Map([...formAContactLandingUrls, ...formAConsultationStaticUrls]);
|
||||
|
||||
function iframeSources(html) {
|
||||
// Astro correctly escapes query separators in serialized HTML attributes.
|
||||
@@ -81,7 +81,7 @@ function formAAdapters(html) {
|
||||
function unsafeSignals(html, allowApprovedFormA = false) {
|
||||
const signals = [];
|
||||
if (!allowApprovedFormA && /<iframe\b[^>]*\bsrc=["'][^"']*jotform/i.test(html)) signals.push('active Jotform iframe');
|
||||
if (!allowApprovedFormA && /262946078314059/i.test(html)) signals.push('isolated-test Form A identifier');
|
||||
if (!allowApprovedFormA && /262946078314059/i.test(html)) signals.push('disabled Form A identifier');
|
||||
if (/<script\b[^>]*\bsrc=["'][^"']*(?:jotform|googletagmanager|google-analytics|doubleclick)/i.test(html)) signals.push('active vendor tracking/form script');
|
||||
if (!allowApprovedFormA && /data-(?:form|forms)-mode=["']live["']/i.test(html)) signals.push('live form mode');
|
||||
if (/api\.azinstitute4autism\.com/i.test(html)) signals.push('production API origin');
|
||||
@@ -89,12 +89,13 @@ function unsafeSignals(html, allowApprovedFormA = false) {
|
||||
return signals;
|
||||
}
|
||||
|
||||
export async function verifyArtifact(root, mode = 'staging') {
|
||||
const formAEnabled = mode === 'isolated-test' || mode === 'production';
|
||||
const production = mode === 'production';
|
||||
const stagingPolicy = mode === 'staging' || mode === 'isolated-test';
|
||||
const staticFormAUrls = production ? formAProductionUrls : mode === 'isolated-test' ? formAIsolatedStaticUrls : new Map();
|
||||
const deferredFormAUrls = mode === 'isolated-test' ? formAConsultationDrawerUrls : new Map();
|
||||
export async function verifyArtifact(root, mode = 'staging', forms = 'live') {
|
||||
if (!['staging', 'indexing'].includes(mode)) throw new Error('Artifact mode must be staging or indexing; form availability is selected separately with --forms=live|off|mock.');
|
||||
if (!['live', 'off', 'mock'].includes(forms)) throw new Error('Artifact forms must be live, off, or mock.');
|
||||
const formAEnabled = forms === 'live';
|
||||
const stagingPolicy = mode === 'staging';
|
||||
const staticFormAUrls = formAEnabled ? formAStaticUrls : new Map();
|
||||
const deferredFormAUrls = formAEnabled ? formAConsultationDrawerUrls : new Map();
|
||||
const htmlFiles = (await fg('**/*.html', { cwd: root, absolute: true })).sort();
|
||||
const routes = [];
|
||||
const canonicalMap = new Map();
|
||||
@@ -133,13 +134,21 @@ export async function verifyArtifact(root, mode = 'staging') {
|
||||
}
|
||||
});
|
||||
const adapters = formAAdapters(html);
|
||||
for (const url of iframeSources(html)) {
|
||||
if (url !== expectedFormAUrl) errors.push(`${route}: unauthorized iframe source`);
|
||||
}
|
||||
for (const url of deferredIframeSources(html)) {
|
||||
if (url !== expectedDeferredFormAUrl) errors.push(`${route}: unauthorized deferred iframe source`);
|
||||
}
|
||||
if (expectedFormAUrl && deferredIframeSources(html).length) errors.push(`${route}: unexpected deferred frame`);
|
||||
if (expectedDeferredFormAUrl && iframeSources(html).length) errors.push(`${route}: drawer must not load before activation`);
|
||||
if (/<script[^>]*data-portal-payload[^>]*>\s*(?!null\s*<)[\s\S]*?\"streams\"[\s\S]*?<\/script>/i.test(html)) errors.push(`${route}: private portal ciphertext is not an approved release artifact`);
|
||||
if (!title) errors.push(`${route}: missing title`);
|
||||
if (!canonical) errors.push(`${route}: missing canonical`);
|
||||
if (!robots) errors.push(`${route}: missing robots directive`);
|
||||
if (trailingSlashUrls.length) errors.push(`${route}: root-relative URL(s) end in a slash: ${trailingSlashUrls.join(', ')}`);
|
||||
if (stagingPolicy && robots !== 'noindex,nofollow') errors.push(`${route}: staging robots is ${robots ?? 'missing'}`);
|
||||
if (production && robots === 'noindex,nofollow') errors.push(`${route}: production artifact is noindex`);
|
||||
if (!stagingPolicy && robots === 'noindex,nofollow') errors.push(`${route}: production artifact is noindex`);
|
||||
if (canonical) {
|
||||
const prior = canonicalMap.get(canonical);
|
||||
if (prior) errors.push(`${route}: duplicate canonical ${canonical} (also ${prior})`);
|
||||
@@ -150,18 +159,16 @@ export async function verifyArtifact(root, mode = 'staging') {
|
||||
if (formAEnabled) {
|
||||
if (expectedFormAUrl) {
|
||||
if (jotformFrames.length !== 1 || jotformFrames[0] !== expectedFormAUrl) errors.push(`${route}: missing or invalid approved Form A iframe URL`);
|
||||
const expectedMode = production ? 'live' : 'isolated-test';
|
||||
const expectedEnvironment = production ? 'production' : 'isolated-test';
|
||||
if (adapters.length !== 1 || !adapters[0].includes(`data-form-mode="${expectedMode}"`) || !adapters[0].includes(`data-form-environment="${expectedEnvironment}"`)) {
|
||||
errors.push(`${route}: Form A adapter lacks the approved ${expectedMode} ${expectedEnvironment} gate`);
|
||||
if (adapters.length !== 1 || !adapters[0].includes('data-form-mode="live"')) {
|
||||
errors.push(`${route}: Form A adapter lacks live mode`);
|
||||
}
|
||||
formAIframes += jotformFrames.length;
|
||||
} else if (expectedDeferredFormAUrl) {
|
||||
if (jotformFrames.length || deferredJotformFrames.length !== 1 || deferredJotformFrames[0] !== expectedDeferredFormAUrl) {
|
||||
errors.push(`${route}: missing or invalid deferred consultation Form A iframe URL`);
|
||||
}
|
||||
if (adapters.length !== 1 || !adapters[0].includes('data-form-mode="isolated-test"') || !adapters[0].includes('data-form-environment="isolated-test"') || !adapters[0].includes('data-jotform-deferred="true"')) {
|
||||
errors.push(`${route}: deferred consultation adapter lacks the approved isolated-test gate`);
|
||||
if (adapters.length !== 1 || !adapters[0].includes('data-form-mode="live"') || !adapters[0].includes('data-jotform-deferred="true"')) {
|
||||
errors.push(`${route}: deferred consultation adapter lacks the live deferred configuration`);
|
||||
}
|
||||
deferredFormAIframes += deferredJotformFrames.length;
|
||||
} else if (jotformFrames.length || deferredJotformFrames.length || adapters.length || /262946078314059/i.test(html)) {
|
||||
@@ -205,14 +212,15 @@ export async function verifyArtifact(root, mode = 'staging') {
|
||||
if (formAEnabled) {
|
||||
const expectedFormAFiles = new Set([...staticFormAUrls.keys(), ...deferredFormAUrls.keys()].map((route) => route === '/' ? 'index.html' : `${route.slice(1)}/index.html`));
|
||||
const unexpectedFormAFiles = formAResourceFiles.filter((file) => !expectedFormAFiles.has(file));
|
||||
if (unexpectedFormAFiles.length) errors.push(`Form A identifier appears outside approved production routes: ${unexpectedFormAFiles.join(', ')}`);
|
||||
if (unexpectedFormAFiles.length) errors.push(`Form A identifier appears outside approved routes: ${unexpectedFormAFiles.join(', ')}`);
|
||||
if (formAIframes !== staticFormAUrls.size) errors.push(`${mode} artifact has ${formAIframes} approved static Form A iframe(s), expected ${staticFormAUrls.size}`);
|
||||
if (deferredFormAIframes !== deferredFormAUrls.size) errors.push(`${mode} artifact has ${deferredFormAIframes} approved deferred Form A iframe(s), expected ${deferredFormAUrls.size}`);
|
||||
} else if (formAResourceFiles.length) {
|
||||
errors.push(`isolated-test Form A identifier appears in artifact: ${formAResourceFiles.join(', ')}`);
|
||||
errors.push(`disabled Form A identifier appears in artifact: ${formAResourceFiles.join(', ')}`);
|
||||
}
|
||||
return {
|
||||
mode,
|
||||
forms,
|
||||
htmlRoutes: htmlFiles.length,
|
||||
sitemapUrls: sitemapRoutes.length,
|
||||
hreflangLinks,
|
||||
@@ -232,8 +240,8 @@ export async function verifyArtifact(root, mode = 'staging') {
|
||||
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname)) {
|
||||
const mode = process.argv.find((arg) => arg.startsWith('--mode='))?.slice('--mode='.length) ?? 'staging';
|
||||
const root = process.argv.find((arg) => arg.startsWith('--root='))?.slice('--root='.length) ?? 'dist';
|
||||
if (!['staging', 'indexing', 'isolated-test', 'production'].includes(mode)) throw new Error(`Unsupported mode: ${mode}`);
|
||||
const result = await verifyArtifact(path.resolve(root), mode);
|
||||
const forms = process.argv.find((arg) => arg.startsWith('--forms='))?.slice('--forms='.length) ?? 'live';
|
||||
const result = await verifyArtifact(path.resolve(root), mode, forms);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
if (!result.passed) process.exitCode = 1;
|
||||
}
|
||||
Reference in new issue
Block a user