From 085d1c23523b5b7eb29aa01d634b3a7d215a413a Mon Sep 17 00:00:00 2001 From: Andrew Griess Date: Wed, 15 Jul 2026 11:15:57 -0500 Subject: [PATCH] Add UPC, SKU, and manufacturer index builder --- .gitignore | 19 +++++ indexes/manufacturer-index.json | 1 + indexes/sku-index.json | 1 + indexes/upc-index.json | 1 + tools/build-indexes.php | 140 ++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 .gitignore create mode 100644 indexes/manufacturer-index.json create mode 100644 indexes/sku-index.json create mode 100644 indexes/upc-index.json create mode 100644 tools/build-indexes.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..94dbf28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Generated exports +/exports/* +!/exports/.gitkeep + +# Generated indexes +/indexes/* +!/indexes/.gitkeep +!/indexes/upc-index.json +!/indexes/sku-index.json +!/indexes/manufacturer-index.json + +# Local and temporary files +*.tmp +*.bak +*.log +.DS_Store +Thumbs.db +.vscode/ +.idea/ diff --git a/indexes/manufacturer-index.json b/indexes/manufacturer-index.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/indexes/manufacturer-index.json @@ -0,0 +1 @@ +[] diff --git a/indexes/sku-index.json b/indexes/sku-index.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/indexes/sku-index.json @@ -0,0 +1 @@ +[] diff --git a/indexes/upc-index.json b/indexes/upc-index.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/indexes/upc-index.json @@ -0,0 +1 @@ +[] diff --git a/tools/build-indexes.php b/tools/build-indexes.php new file mode 100644 index 0000000..7322e41 --- /dev/null +++ b/tools/build-indexes.php @@ -0,0 +1,140 @@ +isFile() || strtolower($file->getExtension()) !== 'json') { + continue; + } + + $checked++; + $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; + } + + $upc = $record['upc'] ?? null; + $sku = $record['sku'] ?? null; + $manufacturer = $record['manufacturer'] ?? null; + + if (is_string($upc) && $upc !== '') { + if (isset($upcIndex[$upc])) { + $errors[] = "{$relativePath}: duplicate UPC {$upc}, already used by {$upcIndex[$upc]}"; + } else { + $upcIndex[$upc] = $relativePath; + } + } + + if ( + is_string($manufacturer) && + trim($manufacturer) !== '' + ) { + $manufacturerKey = strtolower(trim($manufacturer)); + + if (!isset($manufacturerIndex[$manufacturerKey])) { + $manufacturerIndex[$manufacturerKey] = []; + } + + $manufacturerIndex[$manufacturerKey][] = $relativePath; + + if (is_string($sku) && trim($sku) !== '') { + $skuKey = $manufacturerKey . ':' . strtolower(trim($sku)); + + if (isset($skuIndex[$skuKey])) { + $errors[] = "{$relativePath}: duplicate SKU key {$skuKey}, already used by {$skuIndex[$skuKey]}"; + } else { + $skuIndex[$skuKey] = $relativePath; + } + } + } +} + +if ($errors !== []) { + fwrite(STDERR, "Index build failed:\n\n"); + + foreach ($errors as $error) { + fwrite(STDERR, " - {$error}\n"); + } + + fwrite(STDERR, "\nChecked {$checked} product file(s).\n"); + exit(1); +} + +ksort($upcIndex, SORT_STRING); +ksort($skuIndex, SORT_STRING); +ksort($manufacturerIndex, SORT_STRING); + +foreach ($manufacturerIndex as &$paths) { + sort($paths, SORT_STRING); +} +unset($paths); + +$files = [ + $indexesDir . '/upc-index.json' => $upcIndex, + $indexesDir . '/sku-index.json' => $skuIndex, + $indexesDir . '/manufacturer-index.json' => $manufacturerIndex, +]; + +foreach ($files as $outputPath => $data) { + $json = json_encode( + $data, + JSON_PRETTY_PRINT | + JSON_UNESCAPED_SLASHES | + JSON_THROW_ON_ERROR + ); + + if (file_put_contents($outputPath, $json . PHP_EOL) === false) { + fwrite(STDERR, "Unable to write {$outputPath}\n"); + exit(1); + } +} + +echo "Index build complete.\n"; +echo "Products checked: {$checked}\n"; +echo "UPC entries: " . count($upcIndex) . "\n"; +echo "SKU entries: " . count($skuIndex) . "\n"; +echo "Manufacturers: " . count($manufacturerIndex) . "\n";