99 lines
4.6 KiB
TypeScript
99 lines
4.6 KiB
TypeScript
#!/usr/bin/env tsx
|
|
/**
|
|
* apps/web/scripts/order-blog-post-mirror-smoke.ts (v1.9.0, Ken)
|
|
*
|
|
* The per-order Blurt announcement was rewritten to MIRROR the order detail page:
|
|
* og-image header, an H1 headline, a DETAILS block (pay/accept + methods, posted /
|
|
* expires dates, optional location, "✓ Verified"), the full order Terms WITH markdown,
|
|
* a bold tagline, and the shareable link. Pins:
|
|
* - publish.ts builds that structure programmatically (og-image.png, "# ", DETAILS,
|
|
* Terms heading, tagline, check_out, dates via formatDayMonth) and reuses the
|
|
* order_detail.* labels so the two surfaces can't drift
|
|
* - OrderPostContext carries the fields the body needs, and the caller passes them
|
|
* - the old flat body_buy/body_sell templates are gone; the new label keys exist in
|
|
* all 10 locales (title_buy/title_sell kept for the headline)
|
|
*
|
|
* Greps strip comments first.
|
|
*/
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { SUPPORTED_LOCALES } from '../src/lib/i18n/locales';
|
|
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
const WEB = resolve(HERE, '..');
|
|
const SRC = resolve(WEB, 'src');
|
|
const LOCALES = resolve(SRC, 'lib', 'i18n', 'locales');
|
|
let pass = 0,
|
|
fail = 0;
|
|
const ok = (m: string) => (pass++, console.log(` \u2713 ${m}`));
|
|
const bad = (m: string, d = '') => (fail++, console.log(` \u2717 ${m}${d ? `\n ${d}` : ''}`));
|
|
const strip = (s: string) =>
|
|
s
|
|
.replace(/\/\*[\s\S]*?\*\//g, '')
|
|
.replace(/<!--[\s\S]*?-->/g, '')
|
|
.replace(/(^|[^:])\/\/[^\n]*/g, '$1');
|
|
const read = (p: string) => strip(readFileSync(p, 'utf8'));
|
|
const LOCS = SUPPORTED_LOCALES.map((l) => l.code);
|
|
|
|
// publish.ts body assembly.
|
|
{
|
|
const pub = read(resolve(SRC, 'lib', 'syndication', 'publish.ts'));
|
|
const checks: Array<[string, boolean]> = [
|
|
['leads with morphit.io/og-image.png', /morphit\.io\/og-image\.png/.test(pub)],
|
|
['H1 headline (# ${title})', /`#\s*\$\{title\}`/.test(pub)],
|
|
['DETAILS label', /syndicate\.order_post\.details/.test(pub)],
|
|
['Terms heading', /syndicate\.order_post\.terms_heading/.test(pub)],
|
|
['tagline', /syndicate\.order_post\.tagline/.test(pub)],
|
|
['check_out line', /syndicate\.order_post\.check_out/.test(pub)],
|
|
['dates via formatDayMonth', /formatDayMonth\(/.test(pub)],
|
|
['reuses detail pay/accept labels', /order_detail\.i_can_pay_with/.test(pub)],
|
|
['sell side uses "I will accept"', /syndicate\.order_post\.i_will_accept/.test(pub)],
|
|
['fee shows Verified', /order_detail\.fee_verified/.test(pub)],
|
|
['location omitted when blank', /ctx\.locationRegion\s*&&/.test(pub)]
|
|
];
|
|
for (const [n, okp] of checks) okp ? ok(`publish.ts: ${n}`) : bad(`publish.ts: ${n}`);
|
|
|
|
// OrderPostContext carries the mirror fields
|
|
const ctxFields = ['paymentMethodNames', 'createdAtIso', 'expiresAtIso', 'locationRegion', 'terms'];
|
|
const missing = ctxFields.filter((f) => !new RegExp(`readonly ${f}\\??:`).test(pub));
|
|
missing.length === 0
|
|
? ok('OrderPostContext carries the mirror fields')
|
|
: bad('OrderPostContext fields', `missing: ${missing.join(', ')}`);
|
|
}
|
|
|
|
// Caller passes the mirror fields.
|
|
{
|
|
const post = read(resolve(SRC, 'routes', '[lang]', 'post', '+page.svelte'));
|
|
/paymentMethodNames:\s*displayNamesForMethods\(/.test(post) &&
|
|
/createdAtIso:\s*new Date\(\)\.toISOString\(\)/.test(post) &&
|
|
/expiresAtIso:/.test(post) &&
|
|
/terms:\s*terms\.trim\(\)/.test(post)
|
|
? ok('caller passes methods, dates, location, terms')
|
|
: bad('caller passes the mirror fields');
|
|
}
|
|
|
|
// Locales: old flat body gone; new label keys present in all 10.
|
|
{
|
|
const NEW = ['details', 'terms_heading', 'tagline', 'check_out', 'i_will_accept'];
|
|
let allNew = true;
|
|
let noOld = true;
|
|
for (const loc of LOCS) {
|
|
const op = JSON.parse(readFileSync(resolve(LOCALES, `${loc}.json`), 'utf8')).syndicate
|
|
?.order_post ?? {};
|
|
for (const k of NEW) if (typeof op[k] !== 'string') (allNew = false), bad(`${loc}.${k} present`);
|
|
if ('body_buy' in op || 'body_sell' in op) (noOld = false), bad(`${loc}: body_buy/body_sell removed`);
|
|
if (typeof op.title_buy !== 'string' || typeof op.title_sell !== 'string')
|
|
bad(`${loc}: title_buy/title_sell kept`);
|
|
}
|
|
if (allNew) ok('all 10 locales carry details/terms_heading/tagline/check_out/i_will_accept');
|
|
if (noOld) ok('flat body_buy/body_sell removed from all 10');
|
|
}
|
|
|
|
console.log('\n' + '\u2500'.repeat(56));
|
|
if (fail > 0) {
|
|
console.log(`\u2717 order-blog-post-mirror smoke FAILED (${fail})`);
|
|
process.exit(1);
|
|
}
|
|
console.log('\u2713 blog announcement mirrors the detail page; labels reused; 10 locales clean');
|
|
console.log(`\u2713 all ${pass} order-blog-post-mirror scenarios passed`);
|