97 lines
2.9 KiB
JavaScript
97 lines
2.9 KiB
JavaScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = path.resolve(__dirname, '..');
|
|
const trackingFile = path.join(repoRoot, 'src/lib/tracking.ts');
|
|
const sourceRoots = [
|
|
path.join(repoRoot, 'src/pages'),
|
|
path.join(repoRoot, 'src/components'),
|
|
path.join(repoRoot, 'src/content')
|
|
];
|
|
|
|
function walk(dir) {
|
|
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
return walk(fullPath);
|
|
}
|
|
if (/\.(astro|tsx|ts|jsx|js)$/.test(entry.name)) {
|
|
return [fullPath];
|
|
}
|
|
return [];
|
|
});
|
|
}
|
|
|
|
function readTrackEvents() {
|
|
const source = fs.readFileSync(trackingFile, 'utf8');
|
|
const objectMatch = source.match(/TRACK_EVENTS\s*=\s*\{([\s\S]*?)\}\s*as const/);
|
|
if (!objectMatch) {
|
|
throw new Error('Unable to parse TRACK_EVENTS from src/lib/tracking.ts');
|
|
}
|
|
|
|
const entries = [...objectMatch[1].matchAll(/(\w+)\s*:\s*'([^']+)'/g)].map((match) => ({
|
|
key: match[1],
|
|
value: match[2]
|
|
}));
|
|
|
|
return new Map(entries.map(({ key, value }) => [key, value]));
|
|
}
|
|
|
|
const knownEvents = readTrackEvents();
|
|
const usedEventKeys = new Set();
|
|
const usedRawEvents = new Set();
|
|
const legacyAttrs = [];
|
|
|
|
for (const sourceRoot of sourceRoots) {
|
|
for (const filePath of walk(sourceRoot)) {
|
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
|
|
for (const match of content.matchAll(/TRACK_EVENTS\.(\w+)/g)) {
|
|
usedEventKeys.add(match[1]);
|
|
}
|
|
|
|
for (const match of content.matchAll(/data-track="([^"]+)"/g)) {
|
|
usedRawEvents.add(match[1]);
|
|
}
|
|
|
|
if (content.includes('data-track-legacy=')) {
|
|
legacyAttrs.push(path.relative(repoRoot, filePath));
|
|
}
|
|
}
|
|
}
|
|
|
|
const usedEvents = new Set(
|
|
[...usedEventKeys]
|
|
.filter((key) => knownEvents.has(key))
|
|
.map((key) => knownEvents.get(key))
|
|
.concat([...usedRawEvents])
|
|
);
|
|
|
|
const missingEvents = [...knownEvents.entries()]
|
|
.filter(([_, value]) => !usedEvents.has(value))
|
|
.map(([key, value]) => `${key}=${value}`);
|
|
|
|
const unexpectedEvents = [...usedEvents].filter(
|
|
(value) => ![...knownEvents.values()].includes(value)
|
|
);
|
|
|
|
if (legacyAttrs.length || missingEvents.length || unexpectedEvents.length) {
|
|
console.error('Tracking contract validation failed.');
|
|
if (legacyAttrs.length) {
|
|
console.error(`Legacy tracking attrs found in: ${legacyAttrs.join(', ')}`);
|
|
}
|
|
if (missingEvents.length) {
|
|
console.error(`Known events missing from active source: ${missingEvents.join(', ')}`);
|
|
}
|
|
if (unexpectedEvents.length) {
|
|
console.error(`Unknown tracking events found in active source: ${unexpectedEvents.join(', ')}`);
|
|
}
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('Tracking contract validation passed.');
|
|
console.log(`Known events (${knownEvents.size}): ${[...knownEvents.values()].join(', ')}`);
|
|
console.log(`Active events used (${usedEvents.size}): ${[...usedEvents].join(', ')}`);
|