#!/usr/bin/env node /** * Download official EN16931 and PEPPOL test samples for conformance testing */ import * as https from 'https'; import * as fs from 'fs'; import * as path from 'path'; import { createWriteStream } from 'fs'; import { pipeline } from 'stream/promises'; import { fileURLToPath } from 'url'; interface TestSampleSource { name: string; description: string; repository: string; branch: string; paths: string[]; targetDir: string; } const TEST_SAMPLE_SOURCES: TestSampleSource[] = [ { name: 'PEPPOL BIS 3.0 Examples', description: 'Official PEPPOL BIS Billing 3.0 example files', repository: 'OpenPEPPOL/peppol-bis-invoice-3', branch: 'master', paths: [ 'rules/examples/Allowance-example.xml', 'rules/examples/base-example.xml', 'rules/examples/base-negative-inv-correction.xml', 'rules/examples/vat-category-E.xml', 'rules/examples/vat-category-O.xml', 'rules/examples/vat-category-S.xml', 'rules/examples/vat-category-Z.xml', 'rules/examples/vat-category-AE.xml', 'rules/examples/vat-category-K.xml', 'rules/examples/vat-category-G.xml' ], targetDir: 'peppol-bis3' }, { name: 'CEN TC434 Test Files', description: 'European Committee for Standardization test files', repository: 'ConnectingEurope/eInvoicing-EN16931', branch: 'master', paths: [ 'ubl/examples/ubl-tc434-example1.xml', 'ubl/examples/ubl-tc434-example2.xml', 'ubl/examples/ubl-tc434-example3.xml', 'ubl/examples/ubl-tc434-example4.xml', 'ubl/examples/ubl-tc434-example5.xml', 'ubl/examples/ubl-tc434-example6.xml', 'ubl/examples/ubl-tc434-example7.xml', 'ubl/examples/ubl-tc434-example8.xml', 'ubl/examples/ubl-tc434-example9.xml', 'cii/examples/cii-tc434-example1.xml', 'cii/examples/cii-tc434-example2.xml', 'cii/examples/cii-tc434-example3.xml', 'cii/examples/cii-tc434-example4.xml', 'cii/examples/cii-tc434-example5.xml', 'cii/examples/cii-tc434-example6.xml', 'cii/examples/cii-tc434-example7.xml', 'cii/examples/cii-tc434-example8.xml', 'cii/examples/cii-tc434-example9.xml' ], targetDir: 'cen-tc434' }, { name: 'PEPPOL Validation Artifacts', description: 'PEPPOL validation test files', repository: 'OpenPEPPOL/peppol-bis-invoice-3', branch: 'master', paths: [ 'rules/unit-UBL/PEPPOL-EN16931-UBL.xml' ], targetDir: 'peppol-validation' } ]; /** * Download a file from GitHub */ async function downloadFile( repo: string, branch: string, filePath: string, targetPath: string ): Promise { const url = `https://raw.githubusercontent.com/${repo}/${branch}/${filePath}`; return new Promise((resolve, reject) => { https.get(url, (response) => { if (response.statusCode === 404) { console.warn(` āš ļø File not found: ${filePath}`); resolve(); return; } if (response.statusCode !== 200) { reject(new Error(`Failed to download ${url}: ${response.statusCode}`)); return; } const dir = path.dirname(targetPath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } const file = createWriteStream(targetPath); response.pipe(file); file.on('finish', () => { file.close(); console.log(` āœ… Downloaded: ${path.basename(filePath)}`); resolve(); }); file.on('error', (err) => { fs.unlink(targetPath, () => {}); // Delete incomplete file reject(err); }); }).on('error', reject); }); } /** * Download test samples from a source */ async function downloadTestSamples(source: TestSampleSource): Promise { console.log(`\nšŸ“¦ ${source.name}`); console.log(` ${source.description}`); console.log(` Repository: ${source.repository}`); const baseDir = path.join('test-samples', source.targetDir); for (const filePath of source.paths) { const fileName = path.basename(filePath); const targetPath = path.join(baseDir, fileName); try { await downloadFile(source.repository, source.branch, filePath, targetPath); } catch (error) { console.error(` āŒ Error downloading ${fileName}: ${error.message}`); } } } /** * Create metadata file for downloaded samples */ function createMetadata(sources: TestSampleSource[]): void { const metadata = { downloadDate: new Date().toISOString(), sources: sources.map(s => ({ name: s.name, repository: s.repository, branch: s.branch, fileCount: s.paths.length })), totalFiles: sources.reduce((sum, s) => sum + s.paths.length, 0) }; const metadataPath = path.join('test-samples', 'metadata.json'); fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2)); console.log('\nšŸ“ Created metadata.json'); } /** * Main function */ async function main() { console.log('šŸš€ Downloading official EN16931 test samples...\n'); // Create base directory if (!fs.existsSync('test-samples')) { fs.mkdirSync('test-samples'); } // Download samples from each source for (const source of TEST_SAMPLE_SOURCES) { await downloadTestSamples(source); } // Create metadata file createMetadata(TEST_SAMPLE_SOURCES); console.log('\n✨ Test sample download complete!'); console.log('šŸ“ Samples saved to: test-samples/'); // Count total files const totalFiles = TEST_SAMPLE_SOURCES.reduce((sum, s) => sum + s.paths.length, 0); console.log(`šŸ“Š Total files: ${totalFiles}`); } // Run if executed directly const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); if (import.meta.url === `file://${process.argv[1]}`) { main().catch(console.error); } export { downloadTestSamples, TEST_SAMPLE_SOURCES };