diff --git a/.gitignore b/.gitignore index 94dbf28..22c7999 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ # Generated exports /exports/* !/exports/.gitkeep +!/exports/catalog-latest.json +!/exports/catalog-latest.json.gz # Generated indexes /indexes/* diff --git a/exports/catalog-latest.json b/exports/catalog-latest.json new file mode 100644 index 0000000..6dce910 --- /dev/null +++ b/exports/catalog-latest.json @@ -0,0 +1,7 @@ +{ + "format": "roundcount-catalog", + "catalog_version": 1, + "generated_at": "2026-07-15T16:19:54+00:00", + "product_count": 0, + "products": [] +} diff --git a/exports/catalog-latest.json.gz b/exports/catalog-latest.json.gz new file mode 100644 index 0000000..f40d557 Binary files /dev/null and b/exports/catalog-latest.json.gz differ diff --git a/tools/build-export.php b/tools/build-export.php new file mode 100644 index 0000000..433936b --- /dev/null +++ b/tools/build-export.php @@ -0,0 +1,132 @@ +isFile() || strtolower($file->getExtension()) !== 'json') { + continue; + } + + $path = $file->getPathname(); + $relativePath = substr($path, strlen($root) + 1); + + $raw = file_get_contents($path); + + if ($raw === false) { + $errors[] = "{$relativePath}: unable to read file"; + continue; + } + + try { + $record = json_decode($raw, true, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $exception) { + $errors[] = "{$relativePath}: invalid JSON: {$exception->getMessage()}"; + continue; + } + + if (!is_array($record)) { + $errors[] = "{$relativePath}: root value must be an object"; + continue; + } + + $record['_catalog_path'] = $relativePath; + $products[] = $record; +} + +if ($errors !== []) { + fwrite(STDERR, "Export build failed:\n\n"); + + foreach ($errors as $error) { + fwrite(STDERR, " - {$error}\n"); + } + + exit(1); +} + +usort( + $products, + static function (array $left, array $right): int { + $leftManufacturer = strtolower((string) ($left['manufacturer'] ?? '')); + $rightManufacturer = strtolower((string) ($right['manufacturer'] ?? '')); + + $manufacturerCompare = $leftManufacturer <=> $rightManufacturer; + + if ($manufacturerCompare !== 0) { + return $manufacturerCompare; + } + + $leftName = strtolower((string) ($left['product_name'] ?? '')); + $rightName = strtolower((string) ($right['product_name'] ?? '')); + + return $leftName <=> $rightName; + } +); + +$export = [ + 'format' => 'roundcount-catalog', + 'catalog_version' => 1, + 'generated_at' => gmdate('c'), + 'product_count' => count($products), + 'products' => $products, +]; + +try { + $json = json_encode( + $export, + JSON_PRETTY_PRINT | + JSON_UNESCAPED_SLASHES | + JSON_THROW_ON_ERROR + ) . PHP_EOL; +} catch (JsonException $exception) { + fwrite(STDERR, "Unable to encode catalog export: {$exception->getMessage()}\n"); + exit(1); +} + +$jsonPath = $exportsDir . '/catalog-latest.json'; +$gzipPath = $exportsDir . '/catalog-latest.json.gz'; + +if (file_put_contents($jsonPath, $json) === false) { + fwrite(STDERR, "Unable to write {$jsonPath}\n"); + exit(1); +} + +$compressed = gzencode($json, 9); + +if ($compressed === false) { + fwrite(STDERR, "Unable to compress catalog export\n"); + exit(1); +} + +if (file_put_contents($gzipPath, $compressed) === false) { + fwrite(STDERR, "Unable to write {$gzipPath}\n"); + exit(1); +} + +echo "Catalog export complete.\n"; +echo "Products exported: " . count($products) . "\n"; +echo "JSON: exports/catalog-latest.json\n"; +echo "Gzip: exports/catalog-latest.json.gz\n";