jtcsv 3.0.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +205 -146
- package/bin/jtcsv.ts +280 -202
- package/browser.d.ts +142 -0
- package/dist/benchmark.js +446 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/bin/jtcsv.js +1940 -0
- package/dist/bin/jtcsv.js.map +1 -0
- package/dist/csv-to-json.js +1261 -0
- package/dist/csv-to-json.js.map +1 -0
- package/dist/errors.js +291 -0
- package/dist/errors.js.map +1 -0
- package/dist/eslint.config.js +147 -0
- package/dist/eslint.config.js.map +1 -0
- package/dist/index-core.js +95 -0
- package/dist/index-core.js.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/json-save.js +229 -0
- package/dist/json-save.js.map +1 -0
- package/dist/json-to-csv.js +576 -0
- package/dist/json-to-csv.js.map +1 -0
- package/dist/jtcsv-core.cjs.js +336 -7
- package/dist/jtcsv-core.cjs.js.map +1 -1
- package/dist/jtcsv-core.esm.js +336 -7
- package/dist/jtcsv-core.esm.js.map +1 -1
- package/dist/jtcsv-core.umd.js +336 -7
- package/dist/jtcsv-core.umd.js.map +1 -1
- package/dist/jtcsv-full.cjs.js +336 -7
- package/dist/jtcsv-full.cjs.js.map +1 -1
- package/dist/jtcsv-full.esm.js +336 -7
- package/dist/jtcsv-full.esm.js.map +1 -1
- package/dist/jtcsv-full.umd.js +336 -7
- package/dist/jtcsv-full.umd.js.map +1 -1
- package/dist/jtcsv-workers.esm.js +9 -0
- package/dist/jtcsv-workers.esm.js.map +1 -1
- package/dist/jtcsv-workers.umd.js +9 -0
- package/dist/jtcsv-workers.umd.js.map +1 -1
- package/dist/jtcsv.cjs.js +1998 -2092
- package/dist/jtcsv.cjs.js.map +1 -1
- package/dist/jtcsv.esm.js +1994 -2092
- package/dist/jtcsv.esm.js.map +1 -1
- package/dist/jtcsv.umd.js +2157 -2251
- package/dist/jtcsv.umd.js.map +1 -1
- package/dist/plugins/express-middleware/index.js +350 -0
- package/dist/plugins/express-middleware/index.js.map +1 -0
- package/dist/plugins/fastify-plugin/index.js +315 -0
- package/dist/plugins/fastify-plugin/index.js.map +1 -0
- package/dist/plugins/hono/index.js +111 -0
- package/dist/plugins/hono/index.js.map +1 -0
- package/dist/plugins/nestjs/index.js +192 -0
- package/dist/plugins/nestjs/index.js.map +1 -0
- package/dist/plugins/nuxt/index.js +53 -0
- package/dist/plugins/nuxt/index.js.map +1 -0
- package/dist/plugins/remix/index.js +133 -0
- package/dist/plugins/remix/index.js.map +1 -0
- package/dist/plugins/sveltekit/index.js +155 -0
- package/dist/plugins/sveltekit/index.js.map +1 -0
- package/dist/plugins/trpc/index.js +136 -0
- package/dist/plugins/trpc/index.js.map +1 -0
- package/dist/run-demo.js +49 -0
- package/dist/run-demo.js.map +1 -0
- package/dist/src/browser/browser-functions.js +193 -0
- package/dist/src/browser/browser-functions.js.map +1 -0
- package/dist/src/browser/core.js +123 -0
- package/dist/src/browser/core.js.map +1 -0
- package/dist/src/browser/csv-to-json-browser.js +353 -0
- package/dist/src/browser/csv-to-json-browser.js.map +1 -0
- package/dist/src/browser/errors-browser.js +219 -0
- package/dist/src/browser/errors-browser.js.map +1 -0
- package/dist/src/browser/extensions/plugins.js +106 -0
- package/dist/src/browser/extensions/plugins.js.map +1 -0
- package/dist/src/browser/extensions/workers.js +66 -0
- package/dist/src/browser/extensions/workers.js.map +1 -0
- package/dist/src/browser/index.js +140 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/browser/json-to-csv-browser.js +225 -0
- package/dist/src/browser/json-to-csv-browser.js.map +1 -0
- package/dist/src/browser/streams.js +340 -0
- package/dist/src/browser/streams.js.map +1 -0
- package/dist/src/browser/workers/csv-parser.worker.js +264 -0
- package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/browser/workers/worker-pool.js +338 -0
- package/dist/src/browser/workers/worker-pool.js.map +1 -0
- package/dist/src/core/delimiter-cache.js +196 -0
- package/dist/src/core/delimiter-cache.js.map +1 -0
- package/dist/src/core/node-optimizations.js +279 -0
- package/dist/src/core/node-optimizations.js.map +1 -0
- package/dist/src/core/plugin-system.js +399 -0
- package/dist/src/core/plugin-system.js.map +1 -0
- package/dist/src/core/transform-hooks.js +348 -0
- package/dist/src/core/transform-hooks.js.map +1 -0
- package/dist/src/engines/fast-path-engine-new.js +262 -0
- package/dist/src/engines/fast-path-engine-new.js.map +1 -0
- package/dist/src/engines/fast-path-engine.js +671 -0
- package/dist/src/engines/fast-path-engine.js.map +1 -0
- package/dist/src/errors.js +18 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/formats/ndjson-parser.js +332 -0
- package/dist/src/formats/ndjson-parser.js.map +1 -0
- package/dist/src/formats/tsv-parser.js +230 -0
- package/dist/src/formats/tsv-parser.js.map +1 -0
- package/dist/src/index-with-plugins.js +259 -0
- package/dist/src/index-with-plugins.js.map +1 -0
- package/dist/src/types/index.js +3 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/bom-utils.js +267 -0
- package/dist/src/utils/bom-utils.js.map +1 -0
- package/dist/src/utils/encoding-support.js +77 -0
- package/dist/src/utils/encoding-support.js.map +1 -0
- package/dist/src/utils/schema-validator.js +609 -0
- package/dist/src/utils/schema-validator.js.map +1 -0
- package/dist/src/utils/transform-loader.js +281 -0
- package/dist/src/utils/transform-loader.js.map +1 -0
- package/dist/src/utils/validators.js +40 -0
- package/dist/src/utils/validators.js.map +1 -0
- package/dist/src/utils/zod-adapter.js +144 -0
- package/dist/src/utils/zod-adapter.js.map +1 -0
- package/{src → dist/src}/web-server/index.js +251 -286
- package/dist/src/web-server/index.js.map +1 -0
- package/dist/src/workers/csv-multithreaded.js +211 -0
- package/dist/src/workers/csv-multithreaded.js.map +1 -0
- package/dist/src/workers/csv-parser.worker.js +179 -0
- package/dist/src/workers/csv-parser.worker.js.map +1 -0
- package/dist/src/workers/worker-pool.js +228 -0
- package/dist/src/workers/worker-pool.js.map +1 -0
- package/dist/stream-csv-to-json.js +664 -0
- package/dist/stream-csv-to-json.js.map +1 -0
- package/dist/stream-json-to-csv.js +389 -0
- package/dist/stream-json-to-csv.js.map +1 -0
- package/examples/advanced/conditional-transformations.ts +2 -2
- package/examples/advanced/performance-optimization.ts +2 -2
- package/examples/cli-advanced-usage.md +2 -0
- package/examples/cli-tool.ts +1 -1
- package/examples/large-dataset-example.ts +2 -2
- package/examples/simple-usage.ts +2 -2
- package/examples/streaming-example.ts +1 -1
- package/index.d.ts +186 -15
- package/package.json +243 -305
- package/plugins.d.ts +37 -0
- package/schema.d.ts +103 -0
- package/src/browser/csv-to-json-browser.ts +233 -3
- package/src/browser/errors-browser.ts +45 -28
- package/src/browser/json-to-csv-browser.ts +81 -5
- package/src/browser/streams.ts +73 -6
- package/src/core/delimiter-cache.ts +21 -11
- package/src/core/plugin-system.ts +343 -155
- package/src/core/transform-hooks.ts +20 -12
- package/src/engines/fast-path-engine.ts +48 -32
- package/src/errors.ts +1 -72
- package/src/formats/ndjson-parser.ts +6 -0
- package/src/formats/tsv-parser.ts +6 -0
- package/src/types/index.ts +21 -1
- package/src/utils/validators.ts +35 -0
- package/src/web-server/index.ts +1 -1
- package/bin/jtcsv.js +0 -2532
- package/csv-to-json.js +0 -711
- package/errors.js +0 -394
- package/examples/advanced/conditional-transformations.js +0 -446
- package/examples/advanced/csv-parser.worker.js +0 -89
- package/examples/advanced/nested-objects-example.js +0 -306
- package/examples/advanced/performance-optimization.js +0 -504
- package/examples/advanced/run-demo-server.js +0 -116
- package/examples/cli-batch-processing.js +0 -38
- package/examples/cli-tool.js +0 -183
- package/examples/error-handling.js +0 -338
- package/examples/express-api.js +0 -164
- package/examples/large-dataset-example.js +0 -182
- package/examples/ndjson-processing.js +0 -434
- package/examples/plugin-excel-exporter.js +0 -406
- package/examples/schema-validation.js +0 -640
- package/examples/simple-usage.js +0 -282
- package/examples/streaming-example.js +0 -418
- package/examples/web-workers-advanced.js +0 -28
- package/index.js +0 -82
- package/json-save.js +0 -255
- package/json-to-csv.js +0 -668
- package/plugins/README.md +0 -91
- package/plugins/express-middleware/README.md +0 -83
- package/plugins/express-middleware/example.js +0 -135
- package/plugins/express-middleware/example.ts +0 -135
- package/plugins/express-middleware/index.d.ts +0 -114
- package/plugins/express-middleware/index.js +0 -512
- package/plugins/express-middleware/index.ts +0 -557
- package/plugins/express-middleware/package.json +0 -52
- package/plugins/fastify-plugin/index.js +0 -404
- package/plugins/fastify-plugin/index.ts +0 -443
- package/plugins/fastify-plugin/package.json +0 -55
- package/plugins/hono/README.md +0 -28
- package/plugins/hono/index.d.ts +0 -12
- package/plugins/hono/index.js +0 -36
- package/plugins/hono/index.ts +0 -226
- package/plugins/hono/package.json +0 -35
- package/plugins/nestjs/README.md +0 -35
- package/plugins/nestjs/index.d.ts +0 -25
- package/plugins/nestjs/index.js +0 -77
- package/plugins/nestjs/index.ts +0 -201
- package/plugins/nestjs/package.json +0 -37
- package/plugins/nextjs-api/README.md +0 -57
- package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
- package/plugins/nextjs-api/examples/ConverterComponent.tsx +0 -386
- package/plugins/nextjs-api/examples/api-convert.js +0 -67
- package/plugins/nextjs-api/examples/api-convert.ts +0 -67
- package/plugins/nextjs-api/index.js +0 -387
- package/plugins/nextjs-api/index.tsx +0 -339
- package/plugins/nextjs-api/package.json +0 -63
- package/plugins/nextjs-api/route.js +0 -370
- package/plugins/nextjs-api/route.ts +0 -370
- package/plugins/nuxt/README.md +0 -24
- package/plugins/nuxt/index.js +0 -21
- package/plugins/nuxt/index.ts +0 -94
- package/plugins/nuxt/package.json +0 -35
- package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
- package/plugins/nuxt/runtime/composables/useJtcsv.ts +0 -100
- package/plugins/nuxt/runtime/plugin.js +0 -6
- package/plugins/nuxt/runtime/plugin.ts +0 -71
- package/plugins/remix/README.md +0 -26
- package/plugins/remix/index.d.ts +0 -16
- package/plugins/remix/index.js +0 -62
- package/plugins/remix/index.ts +0 -260
- package/plugins/remix/package.json +0 -35
- package/plugins/sveltekit/README.md +0 -28
- package/plugins/sveltekit/index.d.ts +0 -17
- package/plugins/sveltekit/index.js +0 -54
- package/plugins/sveltekit/index.ts +0 -301
- package/plugins/sveltekit/package.json +0 -33
- package/plugins/trpc/README.md +0 -25
- package/plugins/trpc/index.d.ts +0 -7
- package/plugins/trpc/index.js +0 -32
- package/plugins/trpc/index.ts +0 -267
- package/plugins/trpc/package.json +0 -34
- package/src/browser/browser-functions.js +0 -219
- package/src/browser/core.js +0 -92
- package/src/browser/csv-to-json-browser.js +0 -722
- package/src/browser/errors-browser.js +0 -212
- package/src/browser/extensions/plugins.js +0 -92
- package/src/browser/extensions/workers.js +0 -39
- package/src/browser/index.js +0 -113
- package/src/browser/json-to-csv-browser.js +0 -319
- package/src/browser/streams.js +0 -403
- package/src/browser/workers/csv-parser.worker.js +0 -377
- package/src/browser/workers/worker-pool.js +0 -527
- package/src/core/delimiter-cache.js +0 -200
- package/src/core/node-optimizations.js +0 -408
- package/src/core/plugin-system.js +0 -494
- package/src/core/transform-hooks.js +0 -350
- package/src/engines/fast-path-engine-new.js +0 -338
- package/src/engines/fast-path-engine.js +0 -844
- package/src/errors.js +0 -26
- package/src/formats/ndjson-parser.js +0 -467
- package/src/formats/tsv-parser.js +0 -339
- package/src/index-with-plugins.js +0 -378
- package/src/utils/bom-utils.js +0 -259
- package/src/utils/encoding-support.js +0 -124
- package/src/utils/schema-validator.js +0 -594
- package/src/utils/transform-loader.js +0 -205
- package/src/utils/zod-adapter.js +0 -170
- package/stream-csv-to-json.js +0 -560
- package/stream-json-to-csv.js +0 -465
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../../src/utils/schema-validator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Schema Validator Utility\r\n * \r\n * Utility for loading and applying JSON schema validation in CLI\r\n */\r\n\r\nimport * as fs from 'fs';\r\nimport * as fsPromises from 'fs/promises';\r\nimport * as path from 'path';\r\nimport {\r\n ValidationError,\r\n SecurityError,\r\n ConfigurationError\r\n} from '../errors';\r\n\r\nexport interface SchemaRule {\r\n type?: string | string[];\r\n required?: boolean;\r\n min?: number;\r\n max?: number;\r\n pattern?: string | RegExp;\r\n enum?: any[];\r\n minLength?: number;\r\n maxLength?: number;\r\n minimum?: number;\r\n maximum?: number;\r\n exclusiveMinimum?: number;\r\n exclusiveMaximum?: number;\r\n multipleOf?: number;\r\n minItems?: number;\r\n maxItems?: number;\r\n uniqueItems?: boolean;\r\n items?: SchemaRule;\r\n properties?: Record<string, SchemaRule>;\r\n format?: string;\r\n}\r\n\r\nexport interface Schema extends Record<string, any> {\r\n properties?: Record<string, SchemaRule>;\r\n required?: string[];\r\n}\r\n\r\nexport interface ValidationErrorItem {\r\n row: number;\r\n type: string;\r\n field: string;\r\n message: string;\r\n value?: any;\r\n expected?: any;\r\n min?: number;\r\n max?: number;\r\n pattern?: string;\r\n allowed?: any[];\r\n}\r\n\r\nexport interface ValidationResult {\r\n valid: boolean;\r\n errors: ValidationErrorItem[];\r\n warnings: any[];\r\n summary: {\r\n totalRows: number;\r\n validRows: number;\r\n errorCount: number;\r\n warningCount: number;\r\n };\r\n}\r\n\r\nexport interface ApplySchemaValidationResult {\r\n valid: boolean;\r\n errors: Array<{ row: number; message: string; data: any }>;\r\n data: any[];\r\n summary: {\r\n totalRows: number;\r\n validRows: number;\r\n errorCount: number;\r\n errorRate: number;\r\n };\r\n}\r\n\r\nexport interface Validator {\r\n validate(data: any[], options?: { stopOnFirstError?: boolean; transform?: boolean }): ValidationResult;\r\n schema?(schema: any): void;\r\n field?(field: string, rule: any): void;\r\n}\r\n\r\n/**\r\n * Loads JSON schema from file or string\r\n * \r\n * @param schemaPathOrJson - Path to JSON file or JSON string\r\n * @returns Parsed JSON schema\r\n */\r\nexport function loadSchema(schemaPathOrJson: string): Schema {\r\n if (!schemaPathOrJson || typeof schemaPathOrJson !== 'string') {\r\n throw new ValidationError('Schema must be a string (JSON or file path)');\r\n }\r\n \r\n let schemaString = schemaPathOrJson;\r\n \r\n // Check if it's a file path (ends with .json or contains path separators)\r\n const isFilePath = schemaPathOrJson.endsWith('.json') || \r\n schemaPathOrJson.includes('/') || \r\n schemaPathOrJson.includes('\\\\');\r\n \r\n if (isFilePath) {\r\n // Validate file path\r\n const safePath = path.resolve(schemaPathOrJson);\r\n \r\n // Prevent directory traversal\r\n const normalizedPath = path.normalize(schemaPathOrJson);\r\n if (normalizedPath.includes('..') || \r\n /\\\\\\.\\.\\\\|\\/\\.\\.\\//.test(schemaPathOrJson) ||\r\n schemaPathOrJson.startsWith('..') ||\r\n schemaPathOrJson.includes('/..')) {\r\n throw new SecurityError('Directory traversal detected in schema file path');\r\n }\r\n \r\n // Check file exists and has .json extension\r\n if (!fs.existsSync(safePath)) {\r\n throw new ValidationError(`Schema file not found: ${schemaPathOrJson}`);\r\n }\r\n \r\n if (!safePath.toLowerCase().endsWith('.json')) {\r\n throw new ValidationError('Schema file must have .json extension');\r\n }\r\n \r\n try {\r\n schemaString = fs.readFileSync(safePath, 'utf8');\r\n } catch (error: any) {\r\n if (error.code === 'EACCES') {\r\n throw new SecurityError(`Permission denied reading schema file: ${schemaPathOrJson}`);\r\n }\r\n throw new ValidationError(`Failed to read schema file: ${error.message}`);\r\n }\r\n }\r\n \r\n // Parse JSON schema\r\n try {\r\n const schema = JSON.parse(schemaString) as Schema;\r\n \r\n // Validate basic schema structure\r\n if (typeof schema !== 'object' || schema === null) {\r\n throw new ValidationError('Schema must be a JSON object');\r\n }\r\n \r\n return schema;\r\n } catch (error: any) {\r\n if (error instanceof SyntaxError) {\r\n throw new ValidationError(`Invalid JSON in schema: ${error.message}`);\r\n }\r\n throw new ValidationError(`Failed to parse schema: ${error.message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a simple validator for fallback when @jtcsv/validator is not available\r\n */\r\nfunction createSimpleValidator(schema: Schema): Validator {\r\n return {\r\n validate(data: any[], options: { stopOnFirstError?: boolean; transform?: boolean } = {}): ValidationResult {\r\n const errors: ValidationErrorItem[] = [];\r\n const warnings: any[] = [];\r\n \r\n if (!Array.isArray(data)) {\r\n return {\r\n valid: false,\r\n errors: [{ \r\n row: 0, \r\n type: 'INVALID_DATA', \r\n field: '', \r\n message: 'Data must be an array' \r\n }],\r\n warnings: [],\r\n summary: {\r\n totalRows: 0,\r\n validRows: 0,\r\n errorCount: 1,\r\n warningCount: 0\r\n }\r\n };\r\n }\r\n \r\n for (let i = 0; i < data.length; i++) {\r\n const row = data[i];\r\n \r\n for (const [field, rule] of Object.entries(schema)) {\r\n const value = row[field];\r\n \r\n // Check required\r\n if (rule.required && (value === undefined || value === null || value === '')) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'REQUIRED',\r\n field,\r\n message: `Field \"${field}\" is required`,\r\n value\r\n });\r\n continue;\r\n }\r\n \r\n // Skip further validation if value is empty and not required\r\n if (value === undefined || value === null || value === '') {\r\n continue;\r\n }\r\n \r\n // Check type\r\n if (rule.type) {\r\n const types = Array.isArray(rule.type) ? rule.type : [rule.type];\r\n let typeValid = false;\r\n \r\n for (const type of types) {\r\n if (checkType(value, type)) {\r\n typeValid = true;\r\n break;\r\n }\r\n }\r\n \r\n if (!typeValid) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'TYPE',\r\n field,\r\n message: `Field \"${field}\" must be of type ${types.join(' or ')}`,\r\n value,\r\n expected: types\r\n });\r\n }\r\n }\r\n \r\n // Check min/max for strings\r\n if (rule.min !== undefined && typeof value === 'string' && value.length < rule.min) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'MIN_LENGTH',\r\n field,\r\n message: `Field \"${field}\" must be at least ${rule.min} characters`,\r\n value,\r\n min: rule.min\r\n });\r\n }\r\n \r\n if (rule.max !== undefined && typeof value === 'string' && value.length > rule.max) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'MAX_LENGTH',\r\n field,\r\n message: `Field \"${field}\" must be at most ${rule.max} characters`,\r\n value,\r\n max: rule.max\r\n });\r\n }\r\n \r\n // Check min/max for numbers\r\n if (rule.min !== undefined && typeof value === 'number' && value < rule.min) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'MIN_VALUE',\r\n field,\r\n message: `Field \"${field}\" must be at least ${rule.min}`,\r\n value,\r\n min: rule.min\r\n });\r\n }\r\n \r\n if (rule.max !== undefined && typeof value === 'number' && value > rule.max) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'MAX_VALUE',\r\n field,\r\n message: `Field \"${field}\" must be at most ${rule.max}`,\r\n value,\r\n max: rule.max\r\n });\r\n }\r\n \r\n // Check pattern\r\n if (rule.pattern && typeof value === 'string') {\r\n const pattern = rule.pattern instanceof RegExp ? rule.pattern : new RegExp(rule.pattern);\r\n if (!pattern.test(value)) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'PATTERN',\r\n field,\r\n message: `Field \"${field}\" must match pattern`,\r\n value,\r\n pattern: pattern.toString()\r\n });\r\n }\r\n }\r\n \r\n // Check enum\r\n if (rule.enum && Array.isArray(rule.enum) && !rule.enum.includes(value)) {\r\n errors.push({\r\n row: i + 1,\r\n type: 'ENUM',\r\n field,\r\n message: `Field \"${field}\" must be one of: ${rule.enum.join(', ')}`,\r\n value,\r\n allowed: rule.enum\r\n });\r\n }\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n warnings,\r\n summary: {\r\n totalRows: data.length,\r\n validRows: data.length - errors.length,\r\n errorCount: errors.length,\r\n warningCount: warnings.length\r\n }\r\n };\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Checks if value matches type\r\n */\r\nfunction checkType(value: any, type: string): boolean {\r\n switch (type) {\r\n case 'string':\r\n return typeof value === 'string';\r\n case 'number':\r\n return typeof value === 'number' && !isNaN(value);\r\n case 'boolean':\r\n return typeof value === 'boolean';\r\n case 'integer':\r\n return Number.isInteger(value);\r\n case 'float':\r\n return typeof value === 'number' && !Number.isInteger(value);\r\n case 'date':\r\n return value instanceof Date && !isNaN(value.getTime());\r\n case 'array':\r\n return Array.isArray(value);\r\n case 'object':\r\n return typeof value === 'object' && value !== null && !Array.isArray(value);\r\n default:\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Creates a validation hook for use with csvToJson/jsonToCsv hooks system\r\n * \r\n * @param schema - Schema object or path to schema file\r\n * @returns Validation hook function\r\n */\r\nexport function createValidationHook(schema: string | Schema): (row: any, index: number, context: any) => any {\r\n let schemaObj: Schema;\r\n \r\n if (typeof schema === 'string') {\r\n // Load schema from file or JSON string\r\n schemaObj = loadSchema(schema);\r\n } else if (typeof schema === 'object' && schema !== null) {\r\n // Use provided schema object\r\n schemaObj = schema;\r\n } else {\r\n throw new ValidationError('Schema must be an object or a path to a JSON file');\r\n }\r\n\r\n // Try to use @jtcsv/validator if available\r\n let validator: Validator;\r\n try {\r\n const JtcsvValidator = require('../../packages/jtcsv-validator/src/index');\r\n validator = new JtcsvValidator();\r\n \r\n // Convert simple schema format to validator format\r\n if ((schemaObj as any).fields) {\r\n // Assume it's already in validator format\r\n validator.schema!((schemaObj as any).fields);\r\n } else {\r\n // Convert simple field definitions\r\n Object.entries(schemaObj).forEach(([field, rule]) => {\r\n if (typeof rule === 'object') {\r\n validator.field!(field, rule);\r\n }\r\n });\r\n }\r\n } catch (error) {\r\n // Fallback to simple validation if validator is not available\r\n console.warn('@jtcsv/validator not available, using simple validation');\r\n validator = createSimpleValidator(schemaObj);\r\n }\r\n \r\n // Return a hook function compatible with hooks.perRow\r\n return function (row: any, index: number, context: any): any {\r\n try {\r\n const result = validator.validate([row], { \r\n stopOnFirstError: true,\r\n transform: false \r\n });\r\n \r\n if (!result.valid && result.errors.length > 0) {\r\n const error = result.errors[0];\r\n throw new ValidationError(\r\n `Row ${index + 1}: ${error.message} (field: ${error.field})`\r\n );\r\n }\r\n \r\n return row;\r\n } catch (error: any) {\r\n if (error instanceof ValidationError) {\r\n throw error;\r\n }\r\n // Log error but don't crash - return original row\r\n console.error(`Validation error at row ${index}: ${error.message}`);\r\n if (process.env['NODE_ENV'] === 'development') {\r\n console.error(error.stack);\r\n }\r\n return row;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Applies schema validation to data array\r\n * \r\n * @param data - Array of data to validate\r\n * @param schema - Schema object or path to schema file\r\n * @returns Validation result\r\n */\r\nexport function applySchemaValidation(data: any[], schema: string | Schema): ApplySchemaValidationResult {\r\n if (!Array.isArray(data)) {\r\n throw new ValidationError('Data must be an array');\r\n }\r\n \r\n const validationHook = createValidationHook(schema);\r\n const errors: Array<{ row: number; message: string; data: any }> = [];\r\n const validatedData: any[] = [];\r\n \r\n for (let i = 0; i < data.length; i++) {\r\n try {\r\n const validatedRow = validationHook(data[i], i, { operation: 'validate' });\r\n validatedData.push(validatedRow);\r\n } catch (error: any) {\r\n if (error instanceof ValidationError) {\r\n errors.push({\r\n row: i + 1,\r\n message: error.message,\r\n data: data[i]\r\n });\r\n } else {\r\n // Skip rows with non-validation errors\r\n validatedData.push(data[i]);\r\n }\r\n }\r\n }\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n data: validatedData,\r\n summary: {\r\n totalRows: data.length,\r\n validRows: validatedData.length,\r\n errorCount: errors.length,\r\n errorRate: data.length > 0 ? (errors.length / data.length) * 100 : 0\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Creates a TransformHooks instance with validation\r\n * \r\n * @param schema - Schema object or path to schema file\r\n * @returns TransformHooks instance\r\n */\r\nexport function createValidationHooks(schema: Schema): any {\n const { TransformHooks } = require('../core/transform-hooks');\n const hooks = new TransformHooks();\n \n const validationHook = createValidationHook(schema);\n hooks.perRow(validationHook);\r\n \r\n return hooks;\r\n}\r\n\r\n/**\r\n * Creates schema validators from JSON schema\r\n *\r\n * @param schema - JSON schema\r\n * @returns Validators object\r\n */\r\nexport function createSchemaValidators(schema: Schema): Record<string, any> {\r\n const validators: Record<string, any> = {};\r\n\r\n // Handle both JSON Schema format and simple format\r\n const properties = schema.properties || schema;\r\n const requiredFields = schema.required || [];\r\n\r\n if (!properties || typeof properties !== 'object') {\r\n return validators;\r\n }\r\n\r\n for (const [key, definition] of Object.entries(properties)) {\r\n const validator: any = {\r\n type: definition.type,\r\n required: requiredFields.includes(key)\r\n };\r\n\r\n // Add format function for dates and other formats\r\n if (definition.type === 'string' && definition.format) {\r\n validator.format = (value: any) => {\r\n // Handle date-time format\r\n if (definition.format === 'date-time') {\r\n if (value instanceof Date) {\r\n return value.toISOString();\r\n }\r\n /* istanbul ignore next */\r\n if (typeof value === 'string') {\r\n // Try to parse as date\r\n const date = new Date(value);\r\n if (!isNaN(date.getTime())) {\r\n return date.toISOString();\r\n }\r\n }\r\n }\r\n // Handle email format\r\n if (definition.format === 'email') {\r\n if (typeof value === 'string') {\r\n return value.toLowerCase().trim();\r\n }\r\n }\r\n // Handle uri format\r\n if (definition.format === 'uri') {\r\n if (typeof value === 'string') {\r\n return value.trim();\r\n }\r\n }\r\n return value;\r\n };\r\n }\r\n\r\n // Add validation function\r\n validator.validate = (value: any) => {\r\n if (value === null || value === undefined) {\r\n return !validator.required;\r\n }\r\n\r\n // Type validation\r\n if (definition.type === 'string' && typeof value !== 'string') {\r\n // For date-time format, also accept Date objects\r\n if (definition.format === 'date-time' && value instanceof Date) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n if (definition.type === 'number' && typeof value !== 'number') {\r\n return false;\r\n }\r\n if (definition.type === 'integer' && (!Number.isInteger(value) || typeof value !== 'number')) {\r\n return false;\r\n }\r\n if (definition.type === 'boolean' && typeof value !== 'boolean') {\r\n return false;\r\n }\r\n if (definition.type === 'array' && !Array.isArray(value)) {\r\n return false;\r\n }\r\n if (definition.type === 'object' && (typeof value !== 'object' || value === null || Array.isArray(value))) {\r\n return false;\r\n }\r\n\r\n // Additional constraints for strings\r\n if (definition.type === 'string') {\r\n if (definition.minLength !== undefined && value.length < definition.minLength) {\r\n return false;\r\n }\r\n if (definition.maxLength !== undefined && value.length > definition.maxLength) {\r\n return false;\r\n }\r\n if (definition.pattern && !new RegExp(definition.pattern).test(value)) {\r\n return false;\r\n }\r\n if (definition.format === 'email' && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {\r\n return false;\r\n }\r\n if (definition.format === 'uri') {\r\n try {\r\n new URL(value);\r\n } catch {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // Additional constraints for numbers\r\n if (definition.type === 'number' || definition.type === 'integer') {\r\n if (definition.minimum !== undefined && value < definition.minimum) {\r\n return false;\r\n }\r\n if (definition.maximum !== undefined && value > definition.maximum) {\r\n return false;\r\n }\r\n if (definition.exclusiveMinimum !== undefined && value <= definition.exclusiveMinimum) {\r\n return false;\r\n }\r\n if (definition.exclusiveMaximum !== undefined && value >= definition.exclusiveMaximum) {\r\n return false;\r\n }\r\n if (definition.multipleOf !== undefined && value % definition.multipleOf !== 0) {\r\n return false;\r\n }\r\n }\r\n\r\n // Additional constraints for arrays\r\n if (definition.type === 'array') {\r\n if (definition.minItems !== undefined && value.length < definition.minItems) {\r\n return false;\r\n }\r\n if (definition.maxItems !== undefined && value.length > definition.maxItems) {\r\n return false;\r\n }\r\n if (definition.uniqueItems && new Set(value).size !== value.length) {\r\n return false;\r\n }\r\n // Validate array items if schema is provided\r\n if (definition.items) {\r\n for (const item of value) {\r\n const itemValidator = createSchemaValidators({ properties: { item: definition.items } });\r\n if (itemValidator.item && !itemValidator.item.validate(item)) {\r\n return false;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Additional constraints for objects\r\n if (definition.type === 'object' && definition.properties) {\r\n const nestedValidators = createSchemaValidators(definition);\r\n for (const [nestedKey, nestedValidator] of Object.entries(nestedValidators)) {\r\n if (value[nestedKey] !== undefined && !nestedValidator.validate(value[nestedKey])) {\r\n return false;\r\n }\r\n if (nestedValidator.required && value[nestedKey] === undefined) {\r\n return false;\r\n }\r\n }\r\n }\r\n\r\n // Check enum\r\n if (definition.enum && !definition.enum.includes(value)) {\r\n return false;\r\n }\r\n\r\n return true;\r\n };\r\n\r\n validators[key] = validator;\r\n }\r\n\r\n return validators;\r\n}\r\n\r\n/**\r\n * Async version of loadSchema that reads file asynchronously\r\n * \r\n * @param schemaPathOrJson - Path to JSON file or JSON string\r\n * @returns Promise with parsed JSON schema\r\n */\r\nexport async function loadSchemaAsync(schemaPathOrJson: string): Promise<Schema> {\r\n if (!schemaPathOrJson || typeof schemaPathOrJson !== 'string') {\r\n throw new ValidationError('Schema must be a string (JSON or file path)');\r\n }\r\n \r\n let schemaString = schemaPathOrJson;\r\n \r\n // Check if it's a file path (ends with .json or contains path separators)\r\n const isFilePath = schemaPathOrJson.endsWith('.json') || \r\n schemaPathOrJson.includes('/') || \r\n schemaPathOrJson.includes('\\\\');\r\n \r\n if (isFilePath) {\r\n // Validate file path\r\n const safePath = path.resolve(schemaPathOrJson);\r\n \r\n // Prevent directory traversal\r\n const normalizedPath = path.normalize(schemaPathOrJson);\r\n if (normalizedPath.includes('..') || \r\n /\\\\\\.\\.\\\\|\\/\\.\\.\\//.test(schemaPathOrJson) ||\r\n schemaPathOrJson.startsWith('..') ||\r\n schemaPathOrJson.includes('/..')) {\r\n throw new SecurityError('Directory traversal detected in schema file path');\r\n }\r\n \r\n // Check file exists and has .json extension\r\n try {\r\n await fsPromises.access(safePath);\r\n } catch {\r\n throw new ValidationError(`Schema file not found: ${schemaPathOrJson}`);\r\n }\r\n \r\n if (!safePath.toLowerCase().endsWith('.json')) {\r\n throw new ValidationError('Schema file must have .json extension');\r\n }\r\n \r\n try {\r\n schemaString = await fsPromises.readFile(safePath, 'utf8');\r\n } catch (error: any) {\r\n if (error.code === 'EACCES') {\r\n throw new SecurityError(`Permission denied reading schema file: ${schemaPathOrJson}`);\r\n }\r\n throw new ValidationError(`Failed to read schema file: ${error.message}`);\r\n }\r\n }\r\n \r\n // Parse JSON schema\r\n try {\r\n const schema = JSON.parse(schemaString) as Schema;\r\n \r\n // Validate basic schema structure\r\n if (typeof schema !== 'object' || schema === null) {\r\n throw new ValidationError('Schema must be a JSON object');\r\n }\r\n \r\n return schema;\r\n } catch (error: any) {\r\n if (error instanceof SyntaxError) {\r\n throw new ValidationError(`Invalid JSON in schema: ${error.message}`);\r\n }\r\n throw new ValidationError(`Failed to parse schema: ${error.message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Async version of applySchemaValidation that uses worker threads for parallel validation\r\n * \r\n * @param data - Array of data to validate\r\n * @param schema - Schema object or path to schema file\r\n * @returns Promise with validation result\r\n */\r\nexport async function applySchemaValidationAsync(\r\n data: any[], \r\n schema: string | Schema\r\n): Promise<ApplySchemaValidationResult> {\r\n if (!Array.isArray(data)) {\r\n throw new ValidationError('Data must be an array');\r\n }\r\n \r\n const schemaObj = typeof schema === 'string' ? await loadSchemaAsync(schema) : schema;\r\n const validationHook = createValidationHook(schemaObj);\r\n \r\n // Use worker pool for parallel validation if data is large\r\n if (data.length > 1000) {\r\n const { createWorkerPool } = require('../workers/worker-pool');\r\n const pool = createWorkerPool({\r\n workerCount: Math.min(4, require('os').cpus().length),\r\n workerScript: require.resolve('./validation-worker.js')\r\n });\r\n \r\n try {\r\n const validationPromises = data.map((row, index) => \r\n pool.execute({ row, index, schema: schemaObj, operation: 'validate' })\r\n );\r\n \r\n const results = await Promise.all(validationPromises);\r\n const errors: Array<{ row: number; message: string; data: any }> = [];\r\n const validatedData: any[] = [];\r\n \r\n results.forEach((result, index) => {\r\n if (result.error) {\r\n errors.push({\r\n row: index + 1,\r\n message: result.error.message,\r\n data: data[index]\r\n });\r\n } else {\r\n validatedData.push(result.validatedRow);\r\n }\r\n });\r\n \r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n data: validatedData,\r\n summary: {\r\n totalRows: data.length,\r\n validRows: validatedData.length,\r\n errorCount: errors.length,\r\n errorRate: data.length > 0 ? (errors.length / data.length) * 100 : 0\r\n }\r\n };\r\n } finally {\r\n await pool.terminate();\r\n }\r\n }\r\n \r\n // For small datasets, validate synchronously\r\n return applySchemaValidation(data, schemaObj);\r\n}\r\n\r\n/**\r\n * Creates an async validation hook that can be used with async hooks\r\n * \r\n * @param schema - Schema object or path to schema file\r\n * @returns Async validation hook function\r\n */\r\nexport function createAsyncValidationHook(schema: string | Schema): (row: any, index: number, context: any) => Promise<unknown> {\r\n const syncHook = createValidationHook(schema);\r\n \r\n return async function (row: any, index: number, context: any): Promise<unknown> {\r\n return Promise.resolve(syncHook(row, index, context));\r\n };\r\n}\r\n\r\nexport default {\r\n loadSchema,\r\n loadSchemaAsync,\r\n createValidationHook,\r\n createAsyncValidationHook,\r\n applySchemaValidation,\r\n applySchemaValidationAsync,\r\n createValidationHooks,\r\n checkType,\r\n createSchemaValidators\r\n};\n"]}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.loadTransform = loadTransform;
|
|
37
|
+
exports.createTransformHook = createTransformHook;
|
|
38
|
+
exports.applyTransform = applyTransform;
|
|
39
|
+
exports.createTransformHooksWithTransform = createTransformHooksWithTransform;
|
|
40
|
+
exports.loadTransformAsync = loadTransformAsync;
|
|
41
|
+
exports.applyTransformAsync = applyTransformAsync;
|
|
42
|
+
exports.createAsyncTransformHook = createAsyncTransformHook;
|
|
43
|
+
exports.validateTransformSafety = validateTransformSafety;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const fsPromises = __importStar(require("fs/promises"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const vm = __importStar(require("vm"));
|
|
48
|
+
const errors_1 = require("../errors");
|
|
49
|
+
function validateTransformFunction(fn) {
|
|
50
|
+
if (typeof fn !== 'function') {
|
|
51
|
+
throw new errors_1.ValidationError('Transform must export a function');
|
|
52
|
+
}
|
|
53
|
+
const functionString = fn.toString();
|
|
54
|
+
const paramMatch = functionString.match(/\(([^)]*)\)/);
|
|
55
|
+
if (paramMatch) {
|
|
56
|
+
const params = paramMatch[1].split(',').map(p => p.trim()).filter(p => p);
|
|
57
|
+
if (params.length === 0 || params.length > 2) {
|
|
58
|
+
throw new errors_1.ValidationError('Transform function should accept 1-2 parameters: (row, index)');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function loadTransform(transformPath) {
|
|
64
|
+
if (!transformPath || typeof transformPath !== 'string') {
|
|
65
|
+
throw new errors_1.ValidationError('Transform path must be a string');
|
|
66
|
+
}
|
|
67
|
+
const safePath = path.resolve(transformPath);
|
|
68
|
+
const normalizedPath = path.normalize(transformPath);
|
|
69
|
+
if (normalizedPath.includes('..') ||
|
|
70
|
+
/\\\.\.\\|\/\.\.\//.test(transformPath) ||
|
|
71
|
+
transformPath.startsWith('..') ||
|
|
72
|
+
transformPath.includes('/..')) {
|
|
73
|
+
throw new errors_1.SecurityError('Directory traversal detected in transform file path');
|
|
74
|
+
}
|
|
75
|
+
if (!fs.existsSync(safePath)) {
|
|
76
|
+
throw new errors_1.ValidationError(`Transform file not found: ${transformPath}`);
|
|
77
|
+
}
|
|
78
|
+
if (!safePath.toLowerCase().endsWith('.js')) {
|
|
79
|
+
throw new errors_1.ValidationError('Transform file must have .js extension');
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const transformCode = fs.readFileSync(safePath, 'utf8');
|
|
83
|
+
const sandbox = {
|
|
84
|
+
console,
|
|
85
|
+
require,
|
|
86
|
+
module: { exports: {} },
|
|
87
|
+
exports: {},
|
|
88
|
+
__filename: safePath,
|
|
89
|
+
__dirname: path.dirname(safePath),
|
|
90
|
+
Buffer,
|
|
91
|
+
process: {
|
|
92
|
+
env: process.env,
|
|
93
|
+
cwd: process.cwd,
|
|
94
|
+
platform: process.platform
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
const context = vm.createContext(sandbox);
|
|
98
|
+
const script = new vm.Script(transformCode, { filename: safePath });
|
|
99
|
+
script.runInContext(context);
|
|
100
|
+
const transformFn = context.module.exports || context.exports;
|
|
101
|
+
const finalTransform = transformFn.default || transformFn;
|
|
102
|
+
validateTransformFunction(finalTransform);
|
|
103
|
+
return finalTransform;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (error instanceof errors_1.ValidationError || error instanceof errors_1.SecurityError) {
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
if (error.code === 'EACCES') {
|
|
110
|
+
throw new errors_1.SecurityError(`Permission denied reading transform file: ${transformPath}`);
|
|
111
|
+
}
|
|
112
|
+
throw new errors_1.ValidationError(`Failed to load transform function: ${error.message}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function createTransformHook(transform) {
|
|
116
|
+
let transformFn;
|
|
117
|
+
if (typeof transform === 'string') {
|
|
118
|
+
transformFn = loadTransform(transform);
|
|
119
|
+
}
|
|
120
|
+
else if (typeof transform === 'function') {
|
|
121
|
+
validateTransformFunction(transform);
|
|
122
|
+
transformFn = transform;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw new errors_1.ValidationError('Transform must be a function or a path to a JavaScript file');
|
|
126
|
+
}
|
|
127
|
+
return function (row, index, context) {
|
|
128
|
+
try {
|
|
129
|
+
return transformFn(row, index);
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
console.error(`Transform error at row ${index}: ${error.message}`);
|
|
133
|
+
if (process.env['NODE_ENV'] === 'development') {
|
|
134
|
+
console.error(error.stack);
|
|
135
|
+
}
|
|
136
|
+
return row;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function applyTransform(data, transform) {
|
|
141
|
+
if (!Array.isArray(data)) {
|
|
142
|
+
throw new errors_1.ValidationError('Data must be an array');
|
|
143
|
+
}
|
|
144
|
+
const transformHook = createTransformHook(transform);
|
|
145
|
+
return data.map((row, index) => {
|
|
146
|
+
return transformHook(row, index, { operation: 'applyTransform' });
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function createTransformHooksWithTransform(transform) {
|
|
150
|
+
const { TransformHooks } = require('../core/transform-hooks');
|
|
151
|
+
const hooks = new TransformHooks();
|
|
152
|
+
const transformHook = createTransformHook(transform);
|
|
153
|
+
hooks.perRow(transformHook);
|
|
154
|
+
return hooks;
|
|
155
|
+
}
|
|
156
|
+
async function loadTransformAsync(transformPath) {
|
|
157
|
+
if (!transformPath || typeof transformPath !== 'string') {
|
|
158
|
+
throw new errors_1.ValidationError('Transform path must be a string');
|
|
159
|
+
}
|
|
160
|
+
const safePath = path.resolve(transformPath);
|
|
161
|
+
const normalizedPath = path.normalize(transformPath);
|
|
162
|
+
if (normalizedPath.includes('..') ||
|
|
163
|
+
/\\\.\.\\|\/\.\.\//.test(transformPath) ||
|
|
164
|
+
transformPath.startsWith('..') ||
|
|
165
|
+
transformPath.includes('/..')) {
|
|
166
|
+
throw new errors_1.SecurityError('Directory traversal detected in transform file path');
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await fsPromises.access(safePath);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
throw new errors_1.ValidationError(`Transform file not found: ${transformPath}`);
|
|
173
|
+
}
|
|
174
|
+
if (!safePath.toLowerCase().endsWith('.js')) {
|
|
175
|
+
throw new errors_1.ValidationError('Transform file must have .js extension');
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const transformCode = await fsPromises.readFile(safePath, 'utf8');
|
|
179
|
+
const sandbox = {
|
|
180
|
+
console,
|
|
181
|
+
require,
|
|
182
|
+
module: { exports: {} },
|
|
183
|
+
exports: {},
|
|
184
|
+
__filename: safePath,
|
|
185
|
+
__dirname: path.dirname(safePath),
|
|
186
|
+
Buffer,
|
|
187
|
+
process: {
|
|
188
|
+
env: process.env,
|
|
189
|
+
cwd: process.cwd,
|
|
190
|
+
platform: process.platform
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const context = vm.createContext(sandbox);
|
|
194
|
+
const script = new vm.Script(transformCode, { filename: safePath });
|
|
195
|
+
script.runInContext(context);
|
|
196
|
+
const transformFn = context.module.exports || context.exports;
|
|
197
|
+
const finalTransform = transformFn.default || transformFn;
|
|
198
|
+
validateTransformFunction(finalTransform);
|
|
199
|
+
return finalTransform;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (error instanceof errors_1.ValidationError || error instanceof errors_1.SecurityError) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
if (error.code === 'EACCES') {
|
|
206
|
+
throw new errors_1.SecurityError(`Permission denied reading transform file: ${transformPath}`);
|
|
207
|
+
}
|
|
208
|
+
throw new errors_1.ValidationError(`Failed to load transform function: ${error.message}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function applyTransformAsync(data, transform) {
|
|
212
|
+
if (!Array.isArray(data)) {
|
|
213
|
+
throw new errors_1.ValidationError('Data must be an array');
|
|
214
|
+
}
|
|
215
|
+
if (data.length > 1000) {
|
|
216
|
+
const { createWorkerPool } = require('../workers/worker-pool');
|
|
217
|
+
const pool = createWorkerPool({
|
|
218
|
+
workerCount: Math.min(4, require('os').cpus().length),
|
|
219
|
+
workerScript: require.resolve('./transform-worker.js')
|
|
220
|
+
});
|
|
221
|
+
try {
|
|
222
|
+
const transformFn = typeof transform === 'string'
|
|
223
|
+
? await loadTransformAsync(transform)
|
|
224
|
+
: transform;
|
|
225
|
+
const transformPromises = data.map((row, index) => pool.execute({ row, index, transform: transformFn.toString() }));
|
|
226
|
+
const results = await Promise.all(transformPromises);
|
|
227
|
+
return results.map(result => result.transformedRow);
|
|
228
|
+
}
|
|
229
|
+
finally {
|
|
230
|
+
await pool.terminate();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return applyTransform(data, transform);
|
|
234
|
+
}
|
|
235
|
+
function createAsyncTransformHook(transform) {
|
|
236
|
+
const syncHook = createTransformHook(transform);
|
|
237
|
+
return async function (row, index, context) {
|
|
238
|
+
return Promise.resolve(syncHook(row, index, context));
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function validateTransformSafety(transformFn) {
|
|
242
|
+
const issues = [];
|
|
243
|
+
const functionString = transformFn.toString().toLowerCase();
|
|
244
|
+
const dangerousPatterns = [
|
|
245
|
+
'eval(',
|
|
246
|
+
'new function',
|
|
247
|
+
'settimeout',
|
|
248
|
+
'setinterval',
|
|
249
|
+
'process.exit',
|
|
250
|
+
'require(',
|
|
251
|
+
'fs.',
|
|
252
|
+
'child_process',
|
|
253
|
+
'exec(',
|
|
254
|
+
'spawn(',
|
|
255
|
+
'vm.run'
|
|
256
|
+
];
|
|
257
|
+
for (const pattern of dangerousPatterns) {
|
|
258
|
+
if (functionString.includes(pattern)) {
|
|
259
|
+
issues.push(`Potentially dangerous pattern detected: ${pattern}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (functionString.includes('while(true)') || functionString.includes('for(;;)')) {
|
|
263
|
+
issues.push('Potential infinite loop detected');
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
safe: issues.length === 0,
|
|
267
|
+
issues
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
exports.default = {
|
|
271
|
+
loadTransform,
|
|
272
|
+
loadTransformAsync,
|
|
273
|
+
createTransformHook,
|
|
274
|
+
createAsyncTransformHook,
|
|
275
|
+
applyTransform,
|
|
276
|
+
applyTransformAsync,
|
|
277
|
+
createTransformHooksWithTransform,
|
|
278
|
+
validateTransformFunction,
|
|
279
|
+
validateTransformSafety
|
|
280
|
+
};
|
|
281
|
+
//# sourceMappingURL=transform-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-loader.js","sourceRoot":"","sources":["../../../src/utils/transform-loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Transform Loader Utility\r\n * \r\n * Utility for loading and applying transform functions from JavaScript files\r\n */\r\n\r\nimport * as fs from 'fs';\r\nimport * as fsPromises from 'fs/promises';\r\nimport * as path from 'path';\r\nimport * as vm from 'vm';\r\nimport {\r\n ValidationError,\r\n SecurityError,\r\n ConfigurationError\r\n} from '../errors';\r\n\r\n/**\r\n * Validates transform function\r\n */\r\nfunction validateTransformFunction(fn: Function): boolean {\r\n if (typeof fn !== 'function') {\r\n throw new ValidationError('Transform must export a function');\r\n }\r\n \r\n // Check function arity (should accept 1-2 parameters)\r\n const functionString = fn.toString();\r\n const paramMatch = functionString.match(/\\(([^)]*)\\)/);\r\n if (paramMatch) {\r\n const params = paramMatch[1].split(',').map(p => p.trim()).filter(p => p);\r\n if (params.length === 0 || params.length > 2) {\r\n throw new ValidationError('Transform function should accept 1-2 parameters: (row, index)');\r\n }\r\n }\r\n \r\n return true;\r\n}\r\n\r\n/**\r\n * Loads transform function from a JavaScript file\r\n * \r\n * @param transformPath - Path to JavaScript file with transform function\r\n * @returns Transform function\r\n * \r\n * @example\r\n * // transform.js\r\n * module.exports = function(row, index) {\r\n * return { ...row, processed: true, index };\r\n * };\r\n * \r\n * // Usage\r\n * const transform = loadTransform('./transform.js');\r\n * const result = transform({ id: 1, name: 'John' }, 0);\r\n */\r\nexport function loadTransform(transformPath: string): Function {\r\n if (!transformPath || typeof transformPath !== 'string') {\r\n throw new ValidationError('Transform path must be a string');\r\n }\r\n \r\n // Validate file path\r\n const safePath = path.resolve(transformPath);\r\n \r\n // Prevent directory traversal\r\n const normalizedPath = path.normalize(transformPath);\r\n if (normalizedPath.includes('..') || \r\n /\\\\\\.\\.\\\\|\\/\\.\\.\\//.test(transformPath) ||\r\n transformPath.startsWith('..') ||\r\n transformPath.includes('/..')) {\r\n throw new SecurityError('Directory traversal detected in transform file path');\r\n }\r\n \r\n // Check file exists and has .js extension\r\n if (!fs.existsSync(safePath)) {\r\n throw new ValidationError(`Transform file not found: ${transformPath}`);\r\n }\r\n \r\n if (!safePath.toLowerCase().endsWith('.js')) {\r\n throw new ValidationError('Transform file must have .js extension');\r\n }\r\n \r\n try {\r\n // Read and evaluate the transform file in a safe context\r\n const transformCode = fs.readFileSync(safePath, 'utf8');\r\n \r\n // Create a safe context with limited access\r\n const sandbox = {\r\n console,\r\n require,\r\n module: { exports: {} },\r\n exports: {},\r\n __filename: safePath,\r\n __dirname: path.dirname(safePath),\r\n Buffer,\r\n process: {\r\n env: process.env,\r\n cwd: process.cwd,\r\n platform: process.platform\r\n }\r\n };\r\n \r\n // Create a context and run the code\r\n const context = vm.createContext(sandbox);\r\n const script = new vm.Script(transformCode, { filename: safePath });\r\n script.runInContext(context);\r\n \r\n // Get the exported function\r\n const transformFn = (context as any).module.exports || (context as any).exports;\r\n \r\n // Handle default export for ES6 modules\r\n const finalTransform = transformFn.default || transformFn;\r\n \r\n // Validate the transform function\r\n validateTransformFunction(finalTransform);\r\n \r\n return finalTransform;\r\n } catch (error: any) {\r\n if (error instanceof ValidationError || error instanceof SecurityError) {\r\n throw error;\r\n }\r\n \r\n if (error.code === 'EACCES') {\r\n throw new SecurityError(`Permission denied reading transform file: ${transformPath}`);\r\n }\r\n \r\n throw new ValidationError(`Failed to load transform function: ${error.message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Creates a transform hook for use with csvToJson/jsonToCsv hooks system\r\n * \r\n * @param transform - Transform function or path to transform file\r\n * @returns Transform hook function\r\n */\r\nexport function createTransformHook(transform: string | Function): (row: any, index: number, context: any) => any {\r\n let transformFn: Function;\r\n \r\n if (typeof transform === 'string') {\r\n // Load transform from file\r\n transformFn = loadTransform(transform);\r\n } else if (typeof transform === 'function') {\r\n // Use provided function\r\n validateTransformFunction(transform);\r\n transformFn = transform;\r\n } else {\r\n throw new ValidationError('Transform must be a function or a path to a JavaScript file');\r\n }\r\n \r\n // Return a hook function compatible with hooks.perRow\r\n return function (row: any, index: number, context: any): any {\r\n try {\r\n return transformFn(row, index);\r\n } catch (error: any) {\r\n // Log error but don't crash - return original row\r\n console.error(`Transform error at row ${index}: ${error.message}`);\r\n if (process.env['NODE_ENV'] === 'development') {\r\n console.error(error.stack);\r\n }\r\n return row;\r\n }\r\n };\r\n}\r\n\r\n/**\r\n * Applies transform to data array\r\n * \r\n * @param data - Array of data to transform\r\n * @param transform - Transform function or path to transform file\r\n * @returns Transformed data\r\n */\r\nexport function applyTransform(data: any[], transform: string | Function): any[] {\r\n if (!Array.isArray(data)) {\r\n throw new ValidationError('Data must be an array');\r\n }\r\n \r\n const transformHook = createTransformHook(transform);\r\n \r\n return data.map((row, index) => {\r\n return transformHook(row, index, { operation: 'applyTransform' });\r\n });\r\n}\r\n\r\n/**\r\n * Creates a TransformHooks instance with transform function\r\n * \r\n * @param transform - Transform function or path to transform file\r\n * @returns TransformHooks instance\r\n */\r\nexport function createTransformHooksWithTransform(transform: string | Function): any {\r\n const { TransformHooks } = require('../core/transform-hooks');\r\n const hooks = new TransformHooks();\r\n \r\n const transformHook = createTransformHook(transform);\r\n hooks.perRow(transformHook);\r\n \r\n return hooks;\r\n}\r\n\r\n/**\r\n * Async version of loadTransform that reads file asynchronously\r\n * \r\n * @param transformPath - Path to JavaScript file with transform function\r\n * @returns Promise with transform function\r\n */\r\nexport async function loadTransformAsync(transformPath: string): Promise<Function> {\r\n if (!transformPath || typeof transformPath !== 'string') {\r\n throw new ValidationError('Transform path must be a string');\r\n }\r\n \r\n // Validate file path\r\n const safePath = path.resolve(transformPath);\r\n \r\n // Prevent directory traversal\r\n const normalizedPath = path.normalize(transformPath);\r\n if (normalizedPath.includes('..') || \r\n /\\\\\\.\\.\\\\|\\/\\.\\.\\//.test(transformPath) ||\r\n transformPath.startsWith('..') ||\r\n transformPath.includes('/..')) {\r\n throw new SecurityError('Directory traversal detected in transform file path');\r\n }\r\n \r\n // Check file exists and has .js extension\r\n try {\r\n await fsPromises.access(safePath);\r\n } catch {\r\n throw new ValidationError(`Transform file not found: ${transformPath}`);\r\n }\r\n \r\n if (!safePath.toLowerCase().endsWith('.js')) {\r\n throw new ValidationError('Transform file must have .js extension');\r\n }\r\n \r\n try {\r\n // Read and evaluate the transform file in a safe context\r\n const transformCode = await fsPromises.readFile(safePath, 'utf8');\r\n \r\n // Create a safe context with limited access\r\n const sandbox = {\r\n console,\r\n require,\r\n module: { exports: {} },\r\n exports: {},\r\n __filename: safePath,\r\n __dirname: path.dirname(safePath),\r\n Buffer,\r\n process: {\r\n env: process.env,\r\n cwd: process.cwd,\r\n platform: process.platform\r\n }\r\n };\r\n \r\n // Create a context and run the code\r\n const context = vm.createContext(sandbox);\r\n const script = new vm.Script(transformCode, { filename: safePath });\r\n script.runInContext(context);\r\n \r\n // Get the exported function\r\n const transformFn = (context as any).module.exports || (context as any).exports;\r\n \r\n // Handle default export for ES6 modules\r\n const finalTransform = transformFn.default || transformFn;\r\n \r\n // Validate the transform function\r\n validateTransformFunction(finalTransform);\r\n \r\n return finalTransform;\r\n } catch (error: any) {\r\n if (error instanceof ValidationError || error instanceof SecurityError) {\r\n throw error;\r\n }\r\n \r\n if (error.code === 'EACCES') {\r\n throw new SecurityError(`Permission denied reading transform file: ${transformPath}`);\r\n }\r\n \r\n throw new ValidationError(`Failed to load transform function: ${error.message}`);\r\n }\r\n}\r\n\r\n/**\r\n * Async version of applyTransform that uses worker threads for parallel transformation\r\n * \r\n * @param data - Array of data to transform\r\n * @param transform - Transform function or path to transform file\r\n * @returns Promise with transformed data\r\n */\r\nexport async function applyTransformAsync(data: any[], transform: string | Function): Promise<any[]> {\r\n if (!Array.isArray(data)) {\r\n throw new ValidationError('Data must be an array');\r\n }\r\n \r\n // For large datasets, use worker pool\r\n if (data.length > 1000) {\r\n const { createWorkerPool } = require('../workers/worker-pool');\r\n const pool = createWorkerPool({\r\n workerCount: Math.min(4, require('os').cpus().length),\r\n workerScript: require.resolve('./transform-worker.js')\r\n });\r\n \r\n try {\r\n // Load transform function\r\n const transformFn = typeof transform === 'string' \r\n ? await loadTransformAsync(transform)\r\n : transform;\r\n \r\n // Execute transforms in parallel\r\n const transformPromises = data.map((row, index) => \r\n pool.execute({ row, index, transform: transformFn.toString() })\r\n );\r\n \r\n const results = await Promise.all(transformPromises);\r\n return results.map(result => result.transformedRow);\r\n } finally {\r\n await pool.terminate();\r\n }\r\n }\r\n \r\n // For small datasets, transform synchronously\r\n return applyTransform(data, transform);\r\n}\r\n\r\n/**\r\n * Creates an async transform hook that can be used with async hooks\r\n * \r\n * @param transform - Transform function or path to transform file\r\n * @returns Async transform hook function\r\n */\r\nexport function createAsyncTransformHook(transform: string | Function): (row: any, index: number, context: any) => Promise<any> {\r\n const syncHook = createTransformHook(transform);\r\n \r\n return async function (row: any, index: number, context: any): Promise<any> {\r\n return Promise.resolve(syncHook(row, index, context));\r\n };\r\n}\r\n\r\n/**\r\n * Validates that a transform function can be safely executed\r\n * \r\n * @param transformFn - Transform function to validate\r\n * @returns Validation result\r\n */\r\nexport function validateTransformSafety(transformFn: Function): { safe: boolean; issues: string[] } {\r\n const issues: string[] = [];\r\n \r\n // Check for dangerous patterns\r\n const functionString = transformFn.toString().toLowerCase();\r\n \r\n const dangerousPatterns = [\r\n 'eval(',\r\n 'new function',\r\n 'settimeout',\r\n 'setinterval',\r\n 'process.exit',\r\n 'require(',\r\n 'fs.',\r\n 'child_process',\r\n 'exec(',\r\n 'spawn(',\r\n 'vm.run'\r\n ];\r\n \r\n for (const pattern of dangerousPatterns) {\r\n if (functionString.includes(pattern)) {\r\n issues.push(`Potentially dangerous pattern detected: ${pattern}`);\r\n }\r\n }\r\n \r\n // Check for infinite loops\r\n if (functionString.includes('while(true)') || functionString.includes('for(;;)')) {\r\n issues.push('Potential infinite loop detected');\r\n }\r\n \r\n return {\r\n safe: issues.length === 0,\r\n issues\r\n };\r\n}\r\n\r\nexport default {\r\n loadTransform,\r\n loadTransformAsync,\r\n createTransformHook,\r\n createAsyncTransformHook,\r\n applyTransform,\r\n applyTransformAsync,\r\n createTransformHooksWithTransform,\r\n validateTransformFunction,\r\n validateTransformSafety\r\n};"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validators = void 0;
|
|
4
|
+
exports.isEmail = isEmail;
|
|
5
|
+
exports.isUrl = isUrl;
|
|
6
|
+
exports.isDate = isDate;
|
|
7
|
+
function isEmail(value) {
|
|
8
|
+
if (typeof value !== 'string') {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
|
|
12
|
+
}
|
|
13
|
+
function isUrl(value) {
|
|
14
|
+
if (typeof value !== 'string') {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
new URL(value);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function isDate(value) {
|
|
26
|
+
if (value instanceof Date) {
|
|
27
|
+
return !isNaN(value.getTime());
|
|
28
|
+
}
|
|
29
|
+
if (typeof value !== 'string') {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const date = new Date(value);
|
|
33
|
+
return !isNaN(date.getTime());
|
|
34
|
+
}
|
|
35
|
+
exports.validators = {
|
|
36
|
+
isEmail,
|
|
37
|
+
isUrl,
|
|
38
|
+
isDate
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../../../src/utils/validators.ts"],"names":[],"mappings":";;;AAAA,0BAKC;AAED,sBAUC;AAED,wBASC;AA5BD,SAAgB,OAAO,CAAC,KAAa;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,KAAK,CAAC,KAAa;IACjC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAgB,MAAM,CAAC,KAAoB;IACzC,IAAI,KAAK,YAAY,IAAI,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AAChC,CAAC;AAEY,QAAA,UAAU,GAAG;IACxB,OAAO;IACP,KAAK;IACL,MAAM;CACP,CAAC","sourcesContent":["export function isEmail(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value.trim());\n}\n\nexport function isUrl(value: string): boolean {\n if (typeof value !== 'string') {\n return false;\n }\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function isDate(value: string | Date): boolean {\n if (value instanceof Date) {\n return !isNaN(value.getTime());\n }\n if (typeof value !== 'string') {\n return false;\n }\n const date = new Date(value);\n return !isNaN(date.getTime());\n}\n\nexport const validators = {\n isEmail,\n isUrl,\n isDate\n};\n"]}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createZodValidationHook = createZodValidationHook;
|
|
4
|
+
exports.createYupValidationHook = createYupValidationHook;
|
|
5
|
+
exports.createValidatedParser = createValidatedParser;
|
|
6
|
+
exports.createAsyncValidatedParser = createAsyncValidatedParser;
|
|
7
|
+
exports.createAsyncZodValidationHook = createAsyncZodValidationHook;
|
|
8
|
+
exports.createAsyncYupValidationHook = createAsyncYupValidationHook;
|
|
9
|
+
const errors_1 = require("../errors");
|
|
10
|
+
function createZodValidationHook(zodSchema, options = {}) {
|
|
11
|
+
const { coerce = true, mode = 'strict' } = options;
|
|
12
|
+
let zod;
|
|
13
|
+
try {
|
|
14
|
+
zod = require('zod');
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
throw new Error('Zod is not installed. Please install zod: npm install zod');
|
|
18
|
+
}
|
|
19
|
+
if (!zodSchema || typeof zodSchema.safeParse !== 'function') {
|
|
20
|
+
throw new errors_1.ValidationError('Provided schema is not a valid Zod schema');
|
|
21
|
+
}
|
|
22
|
+
return function (row, index, context) {
|
|
23
|
+
try {
|
|
24
|
+
const result = zodSchema.safeParse(row);
|
|
25
|
+
if (!result.success) {
|
|
26
|
+
const errors = result.error.errors;
|
|
27
|
+
const firstError = errors[0];
|
|
28
|
+
const path = firstError.path?.join('.') || '';
|
|
29
|
+
const message = firstError.message;
|
|
30
|
+
if (mode === 'strict') {
|
|
31
|
+
throw new errors_1.ValidationError(`Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
console.warn(`Row ${index + 1}: ${path ? `Field "${path}": ` : ''}${message}`);
|
|
35
|
+
return row;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return result.data;
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (error instanceof errors_1.ValidationError) {
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
console.error(`Zod validation error at row ${index}: ${error.message}`);
|
|
45
|
+
if (process.env['NODE_ENV'] === 'development') {
|
|
46
|
+
console.error(error.stack);
|
|
47
|
+
}
|
|
48
|
+
return row;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function createYupValidationHook(yupSchema, options = {}) {
|
|
53
|
+
const { abortEarly = false, stripUnknown = true } = options;
|
|
54
|
+
let yup;
|
|
55
|
+
try {
|
|
56
|
+
yup = require('yup');
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new Error('Yup is not installed. Please install yup: npm install yup');
|
|
60
|
+
}
|
|
61
|
+
if (!yupSchema || typeof yupSchema.validate !== 'function') {
|
|
62
|
+
throw new errors_1.ValidationError('Provided schema is not a valid Yup schema');
|
|
63
|
+
}
|
|
64
|
+
return async function (row, index, context) {
|
|
65
|
+
try {
|
|
66
|
+
const validated = await yupSchema.validate(row, { abortEarly, stripUnknown });
|
|
67
|
+
return validated;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.name === 'ValidationError') {
|
|
71
|
+
throw new errors_1.ValidationError(`Row ${index + 1}: ${error.message}`);
|
|
72
|
+
}
|
|
73
|
+
console.error(`Yup validation error at row ${index}: ${error.message}`);
|
|
74
|
+
return row;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function createValidatedParser(schema, adapterOptions = {}) {
|
|
79
|
+
const { library = 'zod', ...options } = adapterOptions;
|
|
80
|
+
let validationHook;
|
|
81
|
+
if (library === 'zod') {
|
|
82
|
+
validationHook = createZodValidationHook(schema, options);
|
|
83
|
+
}
|
|
84
|
+
else if (library === 'yup') {
|
|
85
|
+
validationHook = createYupValidationHook(schema, options);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
throw new errors_1.ValidationError(`Unsupported validation library: ${library}`);
|
|
89
|
+
}
|
|
90
|
+
return async function (csv, parseOptions = {}) {
|
|
91
|
+
const { csvToJson } = require('../index');
|
|
92
|
+
const hooks = parseOptions.hooks || {};
|
|
93
|
+
const existingPerRow = hooks.perRow;
|
|
94
|
+
hooks.perRow = function (row, index, context) {
|
|
95
|
+
let validated = row;
|
|
96
|
+
if (existingPerRow) {
|
|
97
|
+
validated = existingPerRow(validated, index, context);
|
|
98
|
+
}
|
|
99
|
+
return validationHook(validated, index, context);
|
|
100
|
+
};
|
|
101
|
+
return csvToJson(csv, { ...parseOptions, hooks });
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function createAsyncValidatedParser(schema, adapterOptions = {}) {
|
|
105
|
+
const { library = 'zod', ...options } = adapterOptions;
|
|
106
|
+
return async function (csv, parseOptions = {}) {
|
|
107
|
+
const { csvToJson } = require('../index');
|
|
108
|
+
const { createWorkerPool } = require('../workers/worker-pool');
|
|
109
|
+
const pool = createWorkerPool({
|
|
110
|
+
workerCount: Math.min(4, require('os').cpus().length),
|
|
111
|
+
workerScript: require.resolve('./validation-worker.js')
|
|
112
|
+
});
|
|
113
|
+
try {
|
|
114
|
+
const data = await csvToJson(csv, parseOptions);
|
|
115
|
+
const validationPromises = data.map((row, index) => pool.execute({ row, index, schema, library, options }));
|
|
116
|
+
const validatedRows = await Promise.all(validationPromises);
|
|
117
|
+
return validatedRows;
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
await pool.terminate();
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function createAsyncZodValidationHook(zodSchema, options = {}) {
|
|
125
|
+
const hook = createZodValidationHook(zodSchema, options);
|
|
126
|
+
return async function (row, index, context) {
|
|
127
|
+
return Promise.resolve(hook(row, index, context));
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function createAsyncYupValidationHook(yupSchema, options = {}) {
|
|
131
|
+
const hook = createYupValidationHook(yupSchema, options);
|
|
132
|
+
return async function (row, index, context) {
|
|
133
|
+
return hook(row, index, context);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
exports.default = {
|
|
137
|
+
createZodValidationHook,
|
|
138
|
+
createYupValidationHook,
|
|
139
|
+
createValidatedParser,
|
|
140
|
+
createAsyncValidatedParser,
|
|
141
|
+
createAsyncZodValidationHook,
|
|
142
|
+
createAsyncYupValidationHook
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=zod-adapter.js.map
|