@contrail/cli 3.4.5 → 3.4.6-alpha.cffb28e
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 +1 -1
- package/dist/commands/groups/import.js +4 -1
- package/dist/commands/load-local/index.js +25 -30
- package/dist/helpers/pipeline/formatters.d.ts +2 -3
- package/dist/helpers/pipeline/formatters.js +63 -63
- package/node_modules/@contrail/entity-compare/CHANGELOG.md +13 -0
- package/node_modules/@contrail/entity-compare/README.md +0 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/entity-compare.client.d.ts +36 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/entity-compare.client.js +118 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/index.d.ts +1 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/index.js +17 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/mockData.d.ts +11 -0
- package/node_modules/@contrail/entity-compare/lib/entity-compare/mockData.js +99 -0
- package/node_modules/@contrail/entity-compare/lib/index.d.ts +1 -0
- package/node_modules/@contrail/entity-compare/lib/index.js +17 -0
- package/node_modules/@contrail/entity-compare/package.json +45 -0
- package/node_modules/@contrail/loader/lib/__mocks__/@contrail/cache.d.ts +2 -0
- package/node_modules/@contrail/loader/lib/__mocks__/@contrail/cache.js +18 -0
- package/node_modules/@contrail/loader/lib/base-processor.d.ts +17 -0
- package/node_modules/@contrail/loader/lib/base-processor.js +26 -0
- package/node_modules/@contrail/loader/lib/color-processor.d.ts +19 -0
- package/node_modules/@contrail/loader/lib/color-processor.js +76 -0
- package/node_modules/@contrail/loader/lib/color-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/color-processor.spec.js +307 -0
- package/node_modules/@contrail/loader/lib/common/conditional-columns.d.ts +16 -0
- package/node_modules/@contrail/loader/lib/common/conditional-columns.js +84 -0
- package/node_modules/@contrail/loader/lib/common/conditional-columns.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/conditional-columns.spec.js +644 -0
- package/node_modules/@contrail/loader/lib/common/constants.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/constants.js +4 -0
- package/node_modules/@contrail/loader/lib/common/csv-file-helper.d.ts +6 -0
- package/node_modules/@contrail/loader/lib/common/csv-file-helper.js +66 -0
- package/node_modules/@contrail/loader/lib/common/csv-file-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/csv-file-helper.spec.js +34 -0
- package/node_modules/@contrail/loader/lib/common/data-transformer-functions.d.ts +32 -0
- package/node_modules/@contrail/loader/lib/common/data-transformer-functions.js +309 -0
- package/node_modules/@contrail/loader/lib/common/data-transformer.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/data-transformer.spec.js +744 -0
- package/node_modules/@contrail/loader/lib/common/entities-helper.d.ts +33 -0
- package/node_modules/@contrail/loader/lib/common/entities-helper.js +300 -0
- package/node_modules/@contrail/loader/lib/common/entities-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/entities-helper.spec.js +287 -0
- package/node_modules/@contrail/loader/lib/common/entity-builder-helpers.d.ts +6 -0
- package/node_modules/@contrail/loader/lib/common/entity-builder-helpers.js +114 -0
- package/node_modules/@contrail/loader/lib/common/entity-builder-helpers.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/entity-builder-helpers.spec.js +137 -0
- package/node_modules/@contrail/loader/lib/common/file-helper.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/common/file-helper.js +37 -0
- package/node_modules/@contrail/loader/lib/common/file-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/file-helper.spec.js +65 -0
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.d.ts +42 -0
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.js +162 -0
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/size-range-helpers.spec.js +320 -0
- package/node_modules/@contrail/loader/lib/common/type-helper.d.ts +18 -0
- package/node_modules/@contrail/loader/lib/common/type-helper.js +232 -0
- package/node_modules/@contrail/loader/lib/common/type-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/type-helper.spec.js +110 -0
- package/node_modules/@contrail/loader/lib/common/util.d.ts +11 -0
- package/node_modules/@contrail/loader/lib/common/util.js +85 -0
- package/node_modules/@contrail/loader/lib/common/util.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/util.spec.js +109 -0
- package/node_modules/@contrail/loader/lib/constants.d.ts +29 -0
- package/node_modules/@contrail/loader/lib/constants.js +32 -0
- package/node_modules/@contrail/loader/lib/custom-entity-processor.d.ts +20 -0
- package/node_modules/@contrail/loader/lib/custom-entity-processor.js +59 -0
- package/node_modules/@contrail/loader/lib/custom-entity-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/custom-entity-processor.spec.js +161 -0
- package/node_modules/@contrail/loader/lib/entities-v2/base-processor-v2.d.ts +27 -0
- package/node_modules/@contrail/loader/lib/entities-v2/base-processor-v2.js +55 -0
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.d.ts +19 -0
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.js +92 -0
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/colors-v2/color-processor-v2.spec.js +456 -0
- package/node_modules/@contrail/loader/lib/entities-v2/custom-entities-v2/custom-entity-processor-v2.d.ts +20 -0
- package/node_modules/@contrail/loader/lib/entities-v2/custom-entities-v2/custom-entity-processor-v2.js +75 -0
- package/node_modules/@contrail/loader/lib/entities-v2/custom-entities-v2/custom-entity-processor-v2.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/custom-entities-v2/custom-entity-processor-v2.spec.js +211 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.d.ts +33 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.js +298 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.spec.js +137 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.d.ts +36 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.js +316 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.spec.js +973 -0
- package/node_modules/@contrail/loader/lib/entities-v2/file-preprocessor-v2.d.ts +40 -0
- package/node_modules/@contrail/loader/lib/entities-v2/file-preprocessor-v2.js +276 -0
- package/node_modules/@contrail/loader/lib/entities-v2/file-preprocessor-v2.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/file-preprocessor-v2.spec.js +161 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.d.ts +49 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.js +388 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/assortment-processor.spec.js +411 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-helper.d.ts +20 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-helper.js +193 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-helper.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-helper.spec.js +190 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.d.ts +37 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.js +271 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-processor.spec.js +654 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/partial-assortment-processor.d.ts +35 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/partial-assortment-processor.js +242 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/partial-assortment-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/partial-assortment-processor.spec.js +167 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/project-item-processor.d.ts +20 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/project-item-processor.js +104 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/project-item-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/project-item-processor.spec.js +172 -0
- package/node_modules/@contrail/loader/lib/entity-processor.d.ts +34 -0
- package/node_modules/@contrail/loader/lib/entity-processor.js +214 -0
- package/node_modules/@contrail/loader/lib/entity-processor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/entity-processor.spec.js +693 -0
- package/node_modules/@contrail/loader/lib/file-preprocessor.d.ts +31 -0
- package/node_modules/@contrail/loader/lib/file-preprocessor.js +212 -0
- package/node_modules/@contrail/loader/lib/file-preprocessor.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/file-preprocessor.spec.js +151 -0
- package/node_modules/@contrail/loader/lib/index.d.ts +9 -941
- package/node_modules/@contrail/loader/lib/index.js +25 -12492
- package/node_modules/@contrail/loader/lib/mockData.d.ts +36 -0
- package/node_modules/@contrail/loader/lib/mockData.js +209 -0
- package/node_modules/@contrail/loader/lib/pipeline/assortment-execute-helpers.d.ts +9 -0
- package/node_modules/@contrail/loader/lib/pipeline/assortment-execute-helpers.js +226 -0
- package/node_modules/@contrail/loader/lib/pipeline/assortment-execute-helpers.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/assortment-execute-helpers.spec.js +305 -0
- package/node_modules/@contrail/loader/lib/pipeline/coerce-values-by-type.d.ts +7 -0
- package/node_modules/@contrail/loader/lib/pipeline/coerce-values-by-type.js +133 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute-multi-type.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute-multi-type.spec.js +454 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute.js +271 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/execute.spec.js +186 -0
- package/node_modules/@contrail/loader/lib/pipeline/index.d.ts +7 -0
- package/node_modules/@contrail/loader/lib/pipeline/index.js +29 -0
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.d.ts +38 -0
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.js +517 -0
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.spec.js +170 -0
- package/node_modules/@contrail/loader/lib/pipeline/loader-pipeline.d.ts +10 -0
- package/node_modules/@contrail/loader/lib/pipeline/loader-pipeline.js +26 -0
- package/node_modules/@contrail/loader/lib/pipeline/loader-pipeline.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/loader-pipeline.spec.js +125 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.js +219 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/preview.spec.js +155 -0
- package/node_modules/@contrail/loader/lib/pipeline/project-item-execute-helpers.d.ts +5 -0
- package/node_modules/@contrail/loader/lib/pipeline/project-item-execute-helpers.js +580 -0
- package/node_modules/@contrail/loader/lib/pipeline/transform.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/pipeline/transform.js +356 -0
- package/node_modules/@contrail/loader/lib/pipeline/transform.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/transform.spec.js +442 -0
- package/node_modules/@contrail/loader/lib/pipeline/types.d.ts +251 -0
- package/node_modules/@contrail/loader/lib/pipeline/types.js +140 -0
- package/node_modules/@contrail/loader/lib/pipeline/validate.d.ts +2 -0
- package/node_modules/@contrail/loader/lib/pipeline/validate.js +1217 -0
- package/node_modules/@contrail/loader/lib/pipeline/validate.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/pipeline/validate.spec.js +1214 -0
- package/node_modules/@contrail/loader/lib/processor-registry.d.ts +3 -0
- package/node_modules/@contrail/loader/lib/processor-registry.js +53 -0
- package/node_modules/@contrail/loader/lib/processor-registry.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/processor-registry.spec.js +8 -0
- package/node_modules/@contrail/loader/package.json +9 -11
- package/node_modules/@contrail/telemetry/CHANGELOG.md +24 -0
- package/node_modules/@contrail/telemetry/README.md +1 -0
- package/node_modules/@contrail/telemetry/lib/index.d.ts +1 -0
- package/node_modules/@contrail/telemetry/lib/index.js +17 -0
- package/node_modules/@contrail/telemetry/lib/logger/index.d.ts +3 -0
- package/node_modules/@contrail/telemetry/lib/logger/index.js +30 -0
- package/node_modules/@contrail/telemetry/package.json +44 -0
- package/node_modules/@pinojs/redact/.github/dependabot.yml +13 -0
- package/node_modules/@pinojs/redact/.github/workflows/ci.yml +48 -0
- package/node_modules/@pinojs/redact/.github/workflows/publish-release.yml +43 -0
- package/node_modules/@pinojs/redact/LICENSE +21 -0
- package/node_modules/@pinojs/redact/README.md +350 -0
- package/node_modules/@pinojs/redact/benchmarks/basic.js +184 -0
- package/node_modules/@pinojs/redact/eslint.config.js +1 -0
- package/node_modules/@pinojs/redact/index.d.ts +52 -0
- package/node_modules/@pinojs/redact/index.js +529 -0
- package/node_modules/@pinojs/redact/index.test-d.ts +22 -0
- package/node_modules/@pinojs/redact/package.json +37 -0
- package/node_modules/@pinojs/redact/scripts/sync-version.mjs +20 -0
- package/node_modules/@pinojs/redact/test/actual-redact-comparison.test.js +211 -0
- package/node_modules/@pinojs/redact/test/index.test.js +824 -0
- package/node_modules/@pinojs/redact/test/integration.test.js +390 -0
- package/node_modules/@pinojs/redact/test/multiple-wildcards.test.js +227 -0
- package/node_modules/@pinojs/redact/test/prototype-pollution.test.js +223 -0
- package/node_modules/@pinojs/redact/test/selective-clone.test.js +115 -0
- package/node_modules/@pinojs/redact/tsconfig.json +19 -0
- package/node_modules/atomic-sleep/.travis.yml +11 -0
- package/node_modules/atomic-sleep/LICENSE +22 -0
- package/node_modules/atomic-sleep/index.js +38 -0
- package/node_modules/atomic-sleep/package.json +37 -0
- package/node_modules/atomic-sleep/readme.md +58 -0
- package/node_modules/atomic-sleep/test.js +47 -0
- package/node_modules/on-exit-leak-free/.github/dependabot.yml +12 -0
- package/node_modules/on-exit-leak-free/.github/workflows/ci.yml +46 -0
- package/node_modules/on-exit-leak-free/LICENSE +21 -0
- package/node_modules/on-exit-leak-free/README.md +54 -0
- package/node_modules/on-exit-leak-free/index.js +108 -0
- package/node_modules/on-exit-leak-free/package.json +37 -0
- package/node_modules/on-exit-leak-free/test/base.test.js +30 -0
- package/node_modules/on-exit-leak-free/test/event-emitter-leak.test.js +23 -0
- package/node_modules/on-exit-leak-free/test/fixtures/beforeExit.js +33 -0
- package/node_modules/on-exit-leak-free/test/fixtures/close.js +21 -0
- package/node_modules/on-exit-leak-free/test/fixtures/gc-not-close.js +24 -0
- package/node_modules/on-exit-leak-free/test/fixtures/unregister.js +24 -0
- package/node_modules/pino/.nojekyll +0 -0
- package/node_modules/pino/.prettierignore +1 -0
- package/node_modules/pino/CNAME +1 -0
- package/node_modules/pino/CONTRIBUTING.md +30 -0
- package/node_modules/pino/LICENSE +21 -0
- package/node_modules/pino/README.md +177 -0
- package/node_modules/pino/SECURITY.md +87 -0
- package/node_modules/pino/benchmarks/basic.bench.js +95 -0
- package/node_modules/pino/benchmarks/child-child.bench.js +52 -0
- package/node_modules/pino/benchmarks/child-creation.bench.js +73 -0
- package/node_modules/pino/benchmarks/child.bench.js +62 -0
- package/node_modules/pino/benchmarks/deep-object.bench.js +88 -0
- package/node_modules/pino/benchmarks/formatters.bench.js +50 -0
- package/node_modules/pino/benchmarks/internal/custom-levels.js +67 -0
- package/node_modules/pino/benchmarks/internal/just-pino-heavy.bench.js +76 -0
- package/node_modules/pino/benchmarks/internal/just-pino.bench.js +182 -0
- package/node_modules/pino/benchmarks/internal/parent-vs-child.bench.js +75 -0
- package/node_modules/pino/benchmarks/internal/redact.bench.js +86 -0
- package/node_modules/pino/benchmarks/long-string.bench.js +81 -0
- package/node_modules/pino/benchmarks/multi-arg.bench.js +193 -0
- package/node_modules/pino/benchmarks/multistream.js +98 -0
- package/node_modules/pino/benchmarks/object.bench.js +82 -0
- package/node_modules/pino/benchmarks/utils/generate-benchmark-doc.js +36 -0
- package/node_modules/pino/benchmarks/utils/runbench.js +138 -0
- package/node_modules/pino/benchmarks/utils/wrap-log-level.js +55 -0
- package/node_modules/pino/bin.js +6 -0
- package/node_modules/pino/browser.js +547 -0
- package/node_modules/pino/build/sync-version.js +25 -0
- package/node_modules/pino/docs/api.md +1593 -0
- package/node_modules/pino/docs/asynchronous.md +40 -0
- package/node_modules/pino/docs/benchmarks.md +55 -0
- package/node_modules/pino/docs/browser.md +278 -0
- package/node_modules/pino/docs/bundling.md +40 -0
- package/node_modules/pino/docs/child-loggers.md +95 -0
- package/node_modules/pino/docs/diagnostics.md +16 -0
- package/node_modules/pino/docs/ecosystem.md +86 -0
- package/node_modules/pino/docs/help.md +345 -0
- package/node_modules/pino/docs/lts.md +64 -0
- package/node_modules/pino/docs/pretty.md +35 -0
- package/node_modules/pino/docs/redaction.md +135 -0
- package/node_modules/pino/docs/transports.md +1376 -0
- package/node_modules/pino/docs/web.md +309 -0
- package/node_modules/pino/eslint.config.js +28 -0
- package/node_modules/pino/examples/basic.js +43 -0
- package/node_modules/pino/examples/transport.js +68 -0
- package/node_modules/pino/favicon.ico +0 -0
- package/node_modules/pino/file.js +12 -0
- package/node_modules/pino/inc-version.sh +42 -0
- package/node_modules/pino/index.html +55 -0
- package/node_modules/pino/lib/caller.js +30 -0
- package/node_modules/pino/lib/constants.js +28 -0
- package/node_modules/pino/lib/deprecations.js +8 -0
- package/node_modules/pino/lib/levels.js +241 -0
- package/node_modules/pino/lib/meta.js +3 -0
- package/node_modules/pino/lib/multistream.js +203 -0
- package/node_modules/pino/lib/proto.js +256 -0
- package/node_modules/pino/lib/redaction.js +114 -0
- package/node_modules/pino/lib/symbols.js +74 -0
- package/node_modules/pino/lib/time.js +39 -0
- package/node_modules/pino/lib/tools.js +427 -0
- package/node_modules/pino/lib/transport-stream.js +56 -0
- package/node_modules/pino/lib/transport.js +289 -0
- package/node_modules/pino/lib/worker.js +194 -0
- package/node_modules/pino/package.json +120 -0
- package/node_modules/pino/pino.d.ts +908 -0
- package/node_modules/pino/pino.js +234 -0
- package/node_modules/pino/test/basic.test.js +886 -0
- package/node_modules/pino/test/broken-pipe.test.js +59 -0
- package/node_modules/pino/test/browser-child.test.js +132 -0
- package/node_modules/pino/test/browser-disabled.test.js +87 -0
- package/node_modules/pino/test/browser-early-console-freeze.test.js +12 -0
- package/node_modules/pino/test/browser-is-level-enabled.test.js +101 -0
- package/node_modules/pino/test/browser-levels.test.js +241 -0
- package/node_modules/pino/test/browser-serializers.test.js +352 -0
- package/node_modules/pino/test/browser-timestamp.test.js +88 -0
- package/node_modules/pino/test/browser-transmit.test.js +417 -0
- package/node_modules/pino/test/browser.test.js +698 -0
- package/node_modules/pino/test/complex-objects.test.js +36 -0
- package/node_modules/pino/test/crlf.test.js +34 -0
- package/node_modules/pino/test/custom-levels.test.js +267 -0
- package/node_modules/pino/test/diagnostics.test.js +107 -0
- package/node_modules/pino/test/error-key.test.js +37 -0
- package/node_modules/pino/test/error.test.js +403 -0
- package/node_modules/pino/test/escaping.test.js +93 -0
- package/node_modules/pino/test/esm/esm.mjs +14 -0
- package/node_modules/pino/test/esm/index.test.js +21 -0
- package/node_modules/pino/test/esm/named-exports.mjs +29 -0
- package/node_modules/pino/test/exit.test.js +79 -0
- package/node_modules/pino/test/fixtures/broken-pipe/basic.js +9 -0
- package/node_modules/pino/test/fixtures/broken-pipe/destination.js +10 -0
- package/node_modules/pino/test/fixtures/broken-pipe/syncfalse.js +12 -0
- package/node_modules/pino/test/fixtures/console-transport.js +13 -0
- package/node_modules/pino/test/fixtures/crashing-transport.js +13 -0
- package/node_modules/pino/test/fixtures/default-exit.js +8 -0
- package/node_modules/pino/test/fixtures/destination-exit.js +8 -0
- package/node_modules/pino/test/fixtures/eval/index.js +13 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/14-files.js +3 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/2-files.js +3 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file1.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file10.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file11.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file12.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file13.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file14.js +11 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file2.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file3.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file4.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file5.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file6.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file7.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file8.js +5 -0
- package/node_modules/pino/test/fixtures/eval/node_modules/file9.js +5 -0
- package/node_modules/pino/test/fixtures/noop-transport.js +10 -0
- package/node_modules/pino/test/fixtures/pretty/null-prototype.js +8 -0
- package/node_modules/pino/test/fixtures/stdout-hack-protection.js +11 -0
- package/node_modules/pino/test/fixtures/syncfalse-child.js +6 -0
- package/node_modules/pino/test/fixtures/syncfalse-exit.js +9 -0
- package/node_modules/pino/test/fixtures/syncfalse-flush-exit.js +10 -0
- package/node_modules/pino/test/fixtures/syncfalse.js +6 -0
- package/node_modules/pino/test/fixtures/syntax-error-esm.mjs +2 -0
- package/node_modules/pino/test/fixtures/to-file-transport-with-transform.js +20 -0
- package/node_modules/pino/test/fixtures/to-file-transport.js +13 -0
- package/node_modules/pino/test/fixtures/to-file-transport.mjs +8 -0
- package/node_modules/pino/test/fixtures/transport/index.js +12 -0
- package/node_modules/pino/test/fixtures/transport/package.json +5 -0
- package/node_modules/pino/test/fixtures/transport-exit-immediately-with-async-dest.js +16 -0
- package/node_modules/pino/test/fixtures/transport-exit-immediately.js +11 -0
- package/node_modules/pino/test/fixtures/transport-exit-on-ready.js +12 -0
- package/node_modules/pino/test/fixtures/transport-invalid-node-options.js +26 -0
- package/node_modules/pino/test/fixtures/transport-main.js +9 -0
- package/node_modules/pino/test/fixtures/transport-many-lines.js +29 -0
- package/node_modules/pino/test/fixtures/transport-preload-main.mjs +13 -0
- package/node_modules/pino/test/fixtures/transport-preload.mjs +13 -0
- package/node_modules/pino/test/fixtures/transport-string-stdout.js +9 -0
- package/node_modules/pino/test/fixtures/transport-transform.js +21 -0
- package/node_modules/pino/test/fixtures/transport-uses-pino-config.js +33 -0
- package/node_modules/pino/test/fixtures/transport-with-on-exit.js +12 -0
- package/node_modules/pino/test/fixtures/transport-worker-data.js +19 -0
- package/node_modules/pino/test/fixtures/transport-worker-name.js +24 -0
- package/node_modules/pino/test/fixtures/transport-worker.js +15 -0
- package/node_modules/pino/test/fixtures/transport-wrong-export-type.js +3 -0
- package/node_modules/pino/test/fixtures/ts/to-file-transport-native.mts +15 -0
- package/node_modules/pino/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
- package/node_modules/pino/test/fixtures/ts/to-file-transport.ts +11 -0
- package/node_modules/pino/test/fixtures/ts/transpile.cjs +36 -0
- package/node_modules/pino/test/fixtures/ts/transport-exit-immediately-with-async-dest.ts +15 -0
- package/node_modules/pino/test/fixtures/ts/transport-exit-immediately.ts +10 -0
- package/node_modules/pino/test/fixtures/ts/transport-exit-on-ready.ts +11 -0
- package/node_modules/pino/test/fixtures/ts/transport-main.ts +8 -0
- package/node_modules/pino/test/fixtures/ts/transport-string-stdout.ts +8 -0
- package/node_modules/pino/test/fixtures/ts/transport-worker.ts +14 -0
- package/node_modules/pino/test/formatters.test.js +364 -0
- package/node_modules/pino/test/helper.d.ts +4 -0
- package/node_modules/pino/test/helper.js +155 -0
- package/node_modules/pino/test/hooks.test.js +114 -0
- package/node_modules/pino/test/http.test.js +214 -0
- package/node_modules/pino/test/internals/version.test.js +17 -0
- package/node_modules/pino/test/is-level-enabled.test.js +179 -0
- package/node_modules/pino/test/jest/basic.spec.js +10 -0
- package/node_modules/pino/test/levels.test.js +810 -0
- package/node_modules/pino/test/metadata.test.js +120 -0
- package/node_modules/pino/test/mixin-merge-strategy.test.js +57 -0
- package/node_modules/pino/test/mixin.test.js +241 -0
- package/node_modules/pino/test/multistream.test.js +729 -0
- package/node_modules/pino/test/redact.test.js +893 -0
- package/node_modules/pino/test/serializers.test.js +257 -0
- package/node_modules/pino/test/stdout-protection.test.js +41 -0
- package/node_modules/pino/test/syncfalse.test.js +186 -0
- package/node_modules/pino/test/timestamp-nano.test.js +37 -0
- package/node_modules/pino/test/timestamp.test.js +124 -0
- package/node_modules/pino/test/transport/big.test.js +42 -0
- package/node_modules/pino/test/transport/bundlers-support.test.js +99 -0
- package/node_modules/pino/test/transport/caller.test.js +24 -0
- package/node_modules/pino/test/transport/core.test.js +733 -0
- package/node_modules/pino/test/transport/core.transpiled.test.ts +114 -0
- package/node_modules/pino/test/transport/crash.test.js +36 -0
- package/node_modules/pino/test/transport/module-link.test.js +241 -0
- package/node_modules/pino/test/transport/native-type-stripping.test.mjs +151 -0
- package/node_modules/pino/test/transport/node-options.test.js +116 -0
- package/node_modules/pino/test/transport/pipeline.test.js +137 -0
- package/node_modules/pino/test/transport/preload.test.js +54 -0
- package/node_modules/pino/test/transport/repl.test.js +15 -0
- package/node_modules/pino/test/transport/sync-false.test.js +67 -0
- package/node_modules/pino/test/transport/sync-true.test.js +57 -0
- package/node_modules/pino/test/transport/targets.test.js +48 -0
- package/node_modules/pino/test/transport/uses-pino-config.test.js +166 -0
- package/node_modules/pino/test/transport-stream.test.js +40 -0
- package/node_modules/pino/test/types/pino-import.test-d.cts +30 -0
- package/node_modules/pino/test/types/pino-multistream.test-d.ts +28 -0
- package/node_modules/pino/test/types/pino-top-export.test-d.ts +34 -0
- package/node_modules/pino/test/types/pino-transport.test-d.ts +156 -0
- package/node_modules/pino/test/types/pino-type-only.test-d.ts +75 -0
- package/node_modules/pino/test/types/pino.test-d.ts +683 -0
- package/node_modules/pino/test/types/pino.ts +91 -0
- package/node_modules/pino/tsconfig.json +14 -0
- package/node_modules/pino-abstract-transport/.github/dependabot.yml +13 -0
- package/node_modules/pino-abstract-transport/.github/workflows/ci.yml +80 -0
- package/node_modules/pino-abstract-transport/.husky/pre-commit +4 -0
- package/node_modules/pino-abstract-transport/LICENSE +21 -0
- package/node_modules/pino-abstract-transport/README.md +171 -0
- package/node_modules/pino-abstract-transport/index.d.ts +122 -0
- package/node_modules/pino-abstract-transport/index.js +128 -0
- package/node_modules/pino-abstract-transport/package.json +41 -0
- package/node_modules/pino-abstract-transport/test/base.test.js +473 -0
- package/node_modules/pino-abstract-transport/test/fixtures/transport-async-iteration.js +22 -0
- package/node_modules/pino-abstract-transport/test/fixtures/transport-on-data.js +22 -0
- package/node_modules/pino-abstract-transport/test/fixtures/transport-transform.js +24 -0
- package/node_modules/pino-abstract-transport/test/fixtures/worker-pipeline.js +15 -0
- package/node_modules/pino-abstract-transport/test/match.js +24 -0
- package/node_modules/pino-abstract-transport/test/types/index.test-d.ts +31 -0
- package/node_modules/pino-abstract-transport/test/worker.test.js +372 -0
- package/node_modules/pino-std-serializers/.editorconfig +13 -0
- package/node_modules/pino-std-serializers/.github/dependabot.yml +13 -0
- package/node_modules/pino-std-serializers/.github/workflows/ci.yml +81 -0
- package/node_modules/pino-std-serializers/LICENSE +7 -0
- package/node_modules/pino-std-serializers/Readme.md +182 -0
- package/node_modules/pino-std-serializers/eslint.config.js +7 -0
- package/node_modules/pino-std-serializers/index.d.ts +145 -0
- package/node_modules/pino-std-serializers/index.js +36 -0
- package/node_modules/pino-std-serializers/lib/err-helpers.js +118 -0
- package/node_modules/pino-std-serializers/lib/err-proto.js +48 -0
- package/node_modules/pino-std-serializers/lib/err-with-cause.js +48 -0
- package/node_modules/pino-std-serializers/lib/err.js +45 -0
- package/node_modules/pino-std-serializers/lib/req.js +100 -0
- package/node_modules/pino-std-serializers/lib/res.js +47 -0
- package/node_modules/pino-std-serializers/package.json +42 -0
- package/node_modules/pino-std-serializers/test/err-with-cause.test.js +187 -0
- package/node_modules/pino-std-serializers/test/err.test.js +200 -0
- package/node_modules/pino-std-serializers/test/req.test.js +477 -0
- package/node_modules/pino-std-serializers/test/res.test.js +120 -0
- package/node_modules/pino-std-serializers/test/types/index.test-d.ts +71 -0
- package/node_modules/pino-std-serializers/tsconfig.json +13 -0
- package/node_modules/process-warning/.gitattributes +2 -0
- package/node_modules/process-warning/.github/dependabot.yml +13 -0
- package/node_modules/process-warning/.github/workflows/ci.yml +22 -0
- package/node_modules/process-warning/LICENSE +21 -0
- package/node_modules/process-warning/README.md +118 -0
- package/node_modules/process-warning/benchmarks/warn.js +25 -0
- package/node_modules/process-warning/eslint.config.js +6 -0
- package/node_modules/process-warning/examples/example.js +11 -0
- package/node_modules/process-warning/index.js +124 -0
- package/node_modules/process-warning/package.json +73 -0
- package/node_modules/process-warning/test/emit-interpolated-string.test.js +34 -0
- package/node_modules/process-warning/test/emit-once-only.test.js +33 -0
- package/node_modules/process-warning/test/emit-reset.test.js +40 -0
- package/node_modules/process-warning/test/emit-set.test.js +35 -0
- package/node_modules/process-warning/test/emit-unlimited.test.js +42 -0
- package/node_modules/process-warning/test/index.test.js +99 -0
- package/node_modules/process-warning/test/issue-88.test.js +38 -0
- package/node_modules/process-warning/test/jest.test.js +24 -0
- package/node_modules/process-warning/test/no-warnings.test.js +80 -0
- package/node_modules/process-warning/test/promise.js +10 -0
- package/node_modules/process-warning/types/index.d.ts +37 -0
- package/node_modules/process-warning/types/index.test-d.ts +36 -0
- package/node_modules/quick-format-unescaped/.github/workflows/ci.yml +21 -0
- package/node_modules/quick-format-unescaped/LICENSE +21 -0
- package/node_modules/quick-format-unescaped/benchmark.js +24 -0
- package/node_modules/quick-format-unescaped/index.js +109 -0
- package/node_modules/quick-format-unescaped/package.json +29 -0
- package/node_modules/quick-format-unescaped/readme.md +66 -0
- package/node_modules/quick-format-unescaped/test/index.js +136 -0
- package/node_modules/real-require/LICENSE.md +21 -0
- package/node_modules/real-require/README.md +51 -0
- package/node_modules/real-require/package.json +49 -0
- package/node_modules/real-require/src/index.js +14 -0
- package/node_modules/safe-stable-stringify/LICENSE +21 -0
- package/node_modules/safe-stable-stringify/esm/package.json +4 -0
- package/node_modules/safe-stable-stringify/esm/wrapper.d.ts +4 -0
- package/node_modules/safe-stable-stringify/esm/wrapper.js +6 -0
- package/node_modules/safe-stable-stringify/index.d.ts +22 -0
- package/node_modules/safe-stable-stringify/index.js +612 -0
- package/node_modules/safe-stable-stringify/package.json +65 -0
- package/node_modules/safe-stable-stringify/readme.md +177 -0
- package/node_modules/sonic-boom/.eslintignore +2 -0
- package/node_modules/sonic-boom/.taprc +3 -0
- package/node_modules/sonic-boom/LICENSE +21 -0
- package/node_modules/sonic-boom/README.md +153 -0
- package/node_modules/sonic-boom/bench.js +98 -0
- package/node_modules/sonic-boom/check.js +18 -0
- package/node_modules/sonic-boom/example.js +8 -0
- package/node_modules/sonic-boom/fixtures/firehose.js +22 -0
- package/node_modules/sonic-boom/index.js +733 -0
- package/node_modules/sonic-boom/package.json +52 -0
- package/node_modules/sonic-boom/test/destroy.test.js +49 -0
- package/node_modules/sonic-boom/test/end.test.js +98 -0
- package/node_modules/sonic-boom/test/flush-sync.test.js +140 -0
- package/node_modules/sonic-boom/test/flush.test.js +419 -0
- package/node_modules/sonic-boom/test/fsync.test.js +63 -0
- package/node_modules/sonic-boom/test/helper.js +42 -0
- package/node_modules/sonic-boom/test/minlength.test.js +35 -0
- package/node_modules/sonic-boom/test/mode.test.js +116 -0
- package/node_modules/sonic-boom/test/periodicflush.test.js +61 -0
- package/node_modules/sonic-boom/test/reopen.test.js +239 -0
- package/node_modules/sonic-boom/test/retry.test.js +414 -0
- package/node_modules/sonic-boom/test/sync.test.js +261 -0
- package/node_modules/sonic-boom/test/write.test.js +515 -0
- package/node_modules/sonic-boom/types/index.d.ts +63 -0
- package/node_modules/sonic-boom/types/tests/test.ts +4 -0
- package/node_modules/split2/LICENSE +13 -0
- package/node_modules/split2/README.md +85 -0
- package/node_modules/split2/bench.js +27 -0
- package/node_modules/split2/index.js +141 -0
- package/node_modules/split2/package.json +39 -0
- package/node_modules/split2/test.js +409 -0
- package/node_modules/thread-stream/.github/dependabot.yml +13 -0
- package/node_modules/thread-stream/.github/workflows/ci.yml +74 -0
- package/node_modules/thread-stream/.husky/pre-commit +4 -0
- package/node_modules/thread-stream/CLAUDE.md +53 -0
- package/node_modules/thread-stream/LICENSE +21 -0
- package/node_modules/thread-stream/README.md +135 -0
- package/node_modules/thread-stream/bench.js +85 -0
- package/node_modules/thread-stream/eslint.config.js +10 -0
- package/node_modules/thread-stream/index.d.ts +92 -0
- package/node_modules/thread-stream/index.js +541 -0
- package/node_modules/thread-stream/lib/indexes.js +9 -0
- package/node_modules/thread-stream/lib/wait.js +68 -0
- package/node_modules/thread-stream/lib/worker.js +179 -0
- package/node_modules/thread-stream/package.json +52 -0
- package/node_modules/thread-stream/test/base.test.js +259 -0
- package/node_modules/thread-stream/test/bench.test.js +38 -0
- package/node_modules/thread-stream/test/bundlers.test.js +59 -0
- package/node_modules/thread-stream/test/close-on-gc.js +37 -0
- package/node_modules/thread-stream/test/commonjs-fallback.test.js +75 -0
- package/node_modules/thread-stream/test/context.test.js +21 -0
- package/node_modules/thread-stream/test/create-and-exit.js +16 -0
- package/node_modules/thread-stream/test/custom-worker.js +9 -0
- package/node_modules/thread-stream/test/dir with spaces/test-package.zip +0 -0
- package/node_modules/thread-stream/test/emit-event.js +22 -0
- package/node_modules/thread-stream/test/end.test.js +56 -0
- package/node_modules/thread-stream/test/error.js +14 -0
- package/node_modules/thread-stream/test/esm.test.mjs +46 -0
- package/node_modules/thread-stream/test/event.test.js +24 -0
- package/node_modules/thread-stream/test/exit.js +14 -0
- package/node_modules/thread-stream/test/get-context.js +22 -0
- package/node_modules/thread-stream/test/helper.d.ts +1 -0
- package/node_modules/thread-stream/test/helper.js +26 -0
- package/node_modules/thread-stream/test/indexes.test.js +11 -0
- package/node_modules/thread-stream/test/multibyte-chars.test.mjs +75 -0
- package/node_modules/thread-stream/test/on-message.js +18 -0
- package/node_modules/thread-stream/test/pkg/index.js +37 -0
- package/node_modules/thread-stream/test/pkg/pkg.config.json +14 -0
- package/node_modules/thread-stream/test/pkg/pkg.test.js +45 -0
- package/node_modules/thread-stream/test/port.js +16 -0
- package/node_modules/thread-stream/test/post-message.test.js +23 -0
- package/node_modules/thread-stream/test/string-limit-2.test.js +35 -0
- package/node_modules/thread-stream/test/string-limit.test.js +37 -0
- package/node_modules/thread-stream/test/syntax-error.mjs +2 -0
- package/node_modules/thread-stream/test/thread-management.test.js +138 -0
- package/node_modules/thread-stream/test/to-file-on-destroy.js +23 -0
- package/node_modules/thread-stream/test/to-file-on-final.js +24 -0
- package/node_modules/thread-stream/test/to-file.js +12 -0
- package/node_modules/thread-stream/test/to-file.mjs +8 -0
- package/node_modules/thread-stream/test/to-next.js +9 -0
- package/node_modules/thread-stream/test/transpiled.test.js +29 -0
- package/node_modules/thread-stream/test/ts/to-file.ts +10 -0
- package/node_modules/thread-stream/test/ts/transpile.sh +19 -0
- package/node_modules/thread-stream/test/ts-commonjs-default-export.zip +0 -0
- package/node_modules/thread-stream/test/ts-native.test.mjs +35 -0
- package/node_modules/thread-stream/test/ts-node-fallback.test.js +35 -0
- package/node_modules/thread-stream/test/uncaughtException.js +21 -0
- package/node_modules/thread-stream/test/unhandledRejection.js +21 -0
- package/node_modules/thread-stream/test/yarnrc.yml +7 -0
- package/node_modules/thread-stream/tsconfig.json +8 -0
- package/oclif.manifest.json +6 -7
- package/package.json +11 -3
- package/node_modules/@contrail/loader/lib/index.js.map +0 -1
|
@@ -0,0 +1,1217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validate = void 0;
|
|
4
|
+
const types_1 = require("@contrail/types");
|
|
5
|
+
const entity_processor_v2_1 = require("../entities-v2/entity-processor-v2");
|
|
6
|
+
const processor_registry_1 = require("../processor-registry");
|
|
7
|
+
const entities_helper_1 = require("../entities-v2/entities-helper");
|
|
8
|
+
const types_2 = require("./types");
|
|
9
|
+
const CONFIG_CATEGORY = types_2.PreValidationCategory.CONFIG;
|
|
10
|
+
const MISSING_REQUIRED_FIELD_CATEGORY = types_2.PreValidationCategory.MISSING_REQUIRED_FIELD;
|
|
11
|
+
const REFERENCE_NOT_FOUND_CATEGORY = types_2.PreValidationCategory.REFERENCE_DATA_NOT_FOUND;
|
|
12
|
+
const FAMILY_INCONSISTENT_CATEGORY = types_2.PreValidationCategory.FAMILY_PROPERTY_VALUES_INCONSISTENT;
|
|
13
|
+
const SELF_REFERENCE_CATEGORY = types_2.PreValidationCategory.SELF_REFERENCE;
|
|
14
|
+
function isEmpty(value) {
|
|
15
|
+
return value === null || value === undefined || value === '';
|
|
16
|
+
}
|
|
17
|
+
function forEachRow(rows, callback) {
|
|
18
|
+
rows.forEach((row, index) => callback(row, index + 2));
|
|
19
|
+
}
|
|
20
|
+
const PROPERTY_TYPE_DISPLAY = {
|
|
21
|
+
choice: 'SINGLE_SELECT',
|
|
22
|
+
multi_select: 'MULTI_SELECT',
|
|
23
|
+
};
|
|
24
|
+
async function validate(rows, config, columnAnalysis, client) {
|
|
25
|
+
const issues = [];
|
|
26
|
+
if (!rows?.length) {
|
|
27
|
+
return buildResult(issues);
|
|
28
|
+
}
|
|
29
|
+
const processorIssues = runProcessorValidation(rows, config);
|
|
30
|
+
issues.push(...processorIssues);
|
|
31
|
+
const itemNameIssues = validateItemNames(rows, config);
|
|
32
|
+
issues.push(...itemNameIssues);
|
|
33
|
+
const identifierConflictIssues = validateStaticIdentifierConflicts(config);
|
|
34
|
+
issues.push(...identifierConflictIssues);
|
|
35
|
+
const projectItemColumnIssues = validateProjectItemColumns(rows, config);
|
|
36
|
+
issues.push(...projectItemColumnIssues);
|
|
37
|
+
if (client && projectItemColumnIssues.length === 0) {
|
|
38
|
+
const resolutionIssues = await validateAndResolveProjectIdentifiers(rows, config, client);
|
|
39
|
+
issues.push(...resolutionIssues);
|
|
40
|
+
}
|
|
41
|
+
const assortmentColumnIssues = validateAssortmentColumns(rows, config);
|
|
42
|
+
issues.push(...assortmentColumnIssues);
|
|
43
|
+
if (client && assortmentColumnIssues.length === 0) {
|
|
44
|
+
const assortmentIssues = await validateAndResolveAssortmentIdentifiers(rows, config, client);
|
|
45
|
+
issues.push(...assortmentIssues);
|
|
46
|
+
}
|
|
47
|
+
const partialUpdateIssues = validatePartialAssortmentConfig(rows, config);
|
|
48
|
+
issues.push(...partialUpdateIssues);
|
|
49
|
+
const typePathExistenceIssues = validateTypePathExistence(columnAnalysis.typesByPath);
|
|
50
|
+
issues.push(...typePathExistenceIssues);
|
|
51
|
+
const familyConsistencyIssues = validateFamilyPropertyConsistency(rows, config, columnAnalysis.typesByPath);
|
|
52
|
+
issues.push(...familyConsistencyIssues);
|
|
53
|
+
const suffixIssues = validateAllOverrideSuffixes(rows, config, columnAnalysis);
|
|
54
|
+
issues.push(...suffixIssues);
|
|
55
|
+
const selfRefIssues = validateSelfReferences(rows, config, columnAnalysis.typesByPath);
|
|
56
|
+
issues.push(...selfRefIssues);
|
|
57
|
+
const optionSetIssues = validateOptionSets(rows, columnAnalysis.typePropertyMaps);
|
|
58
|
+
issues.push(...optionSetIssues);
|
|
59
|
+
const booleanIssues = validateBooleanFormats(rows, columnAnalysis.typePropertyMaps);
|
|
60
|
+
issues.push(...booleanIssues);
|
|
61
|
+
const multiSelectIssues = validateMultiSelectFormats(rows, columnAnalysis.typePropertyMaps);
|
|
62
|
+
issues.push(...multiSelectIssues);
|
|
63
|
+
const unmappedIssues = generateUnmappedWarnings(columnAnalysis);
|
|
64
|
+
issues.push(...unmappedIssues);
|
|
65
|
+
const precisionIssues = validateNumberPrecision(rows, columnAnalysis.typePropertyMaps);
|
|
66
|
+
issues.push(...precisionIssues);
|
|
67
|
+
return buildResult(issues);
|
|
68
|
+
}
|
|
69
|
+
exports.validate = validate;
|
|
70
|
+
function getFederatedIdKeyForLoadType(loadTypes) {
|
|
71
|
+
const itemBasedLoadTypes = [types_2.LoadType.ITEM, types_2.LoadType.PROJECT_ITEM, types_2.LoadType.ASSORTMENT];
|
|
72
|
+
const isItemBased = loadTypes.some((lt) => itemBasedLoadTypes.includes(lt));
|
|
73
|
+
return isItemBased ? 'itemFamilyFederatedId' : 'federatedId';
|
|
74
|
+
}
|
|
75
|
+
function runStructuralValidation(rows, config) {
|
|
76
|
+
const loaderProcess = (0, types_2.toLoaderProcessCompat)(config);
|
|
77
|
+
const federatedIdKey = getFederatedIdKeyForLoadType(config.loadType);
|
|
78
|
+
const result = entity_processor_v2_1.EntityProcessorV2.validateLoadFile(rows, loaderProcess, federatedIdKey);
|
|
79
|
+
const issues = [];
|
|
80
|
+
for (const error of result.generalErrors ?? []) {
|
|
81
|
+
issues.push({
|
|
82
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
83
|
+
category: CONFIG_CATEGORY,
|
|
84
|
+
columnName: '',
|
|
85
|
+
propertySlug: '',
|
|
86
|
+
propertyType: '',
|
|
87
|
+
message: error.message,
|
|
88
|
+
affectedRows: [],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
for (const warning of result.generalWarnings ?? []) {
|
|
92
|
+
issues.push({
|
|
93
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
94
|
+
category: CONFIG_CATEGORY,
|
|
95
|
+
columnName: '',
|
|
96
|
+
propertySlug: '',
|
|
97
|
+
propertyType: '',
|
|
98
|
+
message: warning.message,
|
|
99
|
+
affectedRows: [],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return issues;
|
|
103
|
+
}
|
|
104
|
+
function runProcessorValidation(rows, config) {
|
|
105
|
+
const entityTypes = (0, types_2.loadTypeToEntityTypes)(config.loadType);
|
|
106
|
+
const invalidLoadTypes = config.loadType.filter((lt, i) => {
|
|
107
|
+
const singleResult = (0, types_2.loadTypeToEntityTypes)([lt]);
|
|
108
|
+
return singleResult.length === 0;
|
|
109
|
+
});
|
|
110
|
+
if (invalidLoadTypes.length > 0) {
|
|
111
|
+
throw new Error(`Unsupported LoadTypes detected: ${invalidLoadTypes.join(', ')}`);
|
|
112
|
+
}
|
|
113
|
+
const processor = (0, processor_registry_1.getProcessorForEntityTypes)(entityTypes);
|
|
114
|
+
if (!processor?.validateLoadFile) {
|
|
115
|
+
throw new Error(`Processor for entity types [${entityTypes.join(', ')}] does not implement validateLoadFile`);
|
|
116
|
+
}
|
|
117
|
+
const loaderProcess = (0, types_2.toLoaderProcessCompat)(config);
|
|
118
|
+
const validationResult = processor.validateLoadFile(rows, loaderProcess);
|
|
119
|
+
const issues = [];
|
|
120
|
+
for (const error of validationResult?.generalErrors ?? []) {
|
|
121
|
+
issues.push({
|
|
122
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
123
|
+
category: CONFIG_CATEGORY,
|
|
124
|
+
columnName: '',
|
|
125
|
+
propertySlug: '',
|
|
126
|
+
propertyType: '',
|
|
127
|
+
message: error.message,
|
|
128
|
+
affectedRows: [],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
for (const warning of validationResult?.generalWarnings ?? []) {
|
|
132
|
+
issues.push({
|
|
133
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
134
|
+
category: CONFIG_CATEGORY,
|
|
135
|
+
columnName: '',
|
|
136
|
+
propertySlug: '',
|
|
137
|
+
propertyType: '',
|
|
138
|
+
message: warning.message,
|
|
139
|
+
affectedRows: [],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
for (const error of validationResult?.errors ?? []) {
|
|
143
|
+
for (const colIssue of error.columnIssues ?? []) {
|
|
144
|
+
issues.push({
|
|
145
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
146
|
+
category: CONFIG_CATEGORY,
|
|
147
|
+
columnName: colIssue.columnName,
|
|
148
|
+
propertySlug: colIssue.columnName,
|
|
149
|
+
propertyType: '',
|
|
150
|
+
message: colIssue.message,
|
|
151
|
+
affectedRows: [{ row: error.rowNumber, value: colIssue.data }],
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const warning of validationResult?.warnings ?? []) {
|
|
156
|
+
for (const colIssue of warning.columnIssues ?? []) {
|
|
157
|
+
issues.push({
|
|
158
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
159
|
+
category: CONFIG_CATEGORY,
|
|
160
|
+
columnName: colIssue.columnName,
|
|
161
|
+
propertySlug: colIssue.columnName,
|
|
162
|
+
propertyType: '',
|
|
163
|
+
message: colIssue.message,
|
|
164
|
+
affectedRows: [{ row: warning.rowNumber, value: colIssue.data }],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return issues;
|
|
169
|
+
}
|
|
170
|
+
function validateOptionSets(rows, typePropertyMaps) {
|
|
171
|
+
const { optionSetUsingTypePropertiesBySlug } = typePropertyMaps;
|
|
172
|
+
const issues = [];
|
|
173
|
+
const skipColumns = new Set();
|
|
174
|
+
const affectedRowsByColumn = {};
|
|
175
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
176
|
+
for (const [key, value] of Object.entries(row)) {
|
|
177
|
+
if (isEmpty(value))
|
|
178
|
+
continue;
|
|
179
|
+
if (!optionSetUsingTypePropertiesBySlug[key])
|
|
180
|
+
continue;
|
|
181
|
+
if (!affectedRowsByColumn[key])
|
|
182
|
+
affectedRowsByColumn[key] = [];
|
|
183
|
+
affectedRowsByColumn[key].push({ row: rowNumber, value: String(value) });
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
for (const [slug, property] of Object.entries(optionSetUsingTypePropertiesBySlug)) {
|
|
187
|
+
if (!affectedRowsByColumn[slug])
|
|
188
|
+
continue;
|
|
189
|
+
if (!property.typePropertyOptionSetId) {
|
|
190
|
+
issues.push({
|
|
191
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
192
|
+
category: types_2.PreValidationCategory.OPTION_SET,
|
|
193
|
+
columnName: slug,
|
|
194
|
+
propertySlug: property.slug,
|
|
195
|
+
propertyType: property.propertyType,
|
|
196
|
+
message: `Property "${slug}" is type ${PROPERTY_TYPE_DISPLAY[property.propertyType] ?? property.propertyType} but has no option set attached. Attach an option set to this property or change the property type.`,
|
|
197
|
+
affectedRows: affectedRowsByColumn[slug],
|
|
198
|
+
});
|
|
199
|
+
skipColumns.add(slug);
|
|
200
|
+
}
|
|
201
|
+
else if (!property.options || property.options.length === 0) {
|
|
202
|
+
issues.push({
|
|
203
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
204
|
+
category: types_2.PreValidationCategory.OPTION_SET,
|
|
205
|
+
columnName: slug,
|
|
206
|
+
propertySlug: property.slug,
|
|
207
|
+
propertyType: property.propertyType,
|
|
208
|
+
message: `Option set for property "${slug}" is empty. Values in this column cannot be validated. Populate the option set or remove data from this column.`,
|
|
209
|
+
affectedRows: affectedRowsByColumn[slug],
|
|
210
|
+
});
|
|
211
|
+
skipColumns.add(slug);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const issuesByColumn = {};
|
|
215
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
216
|
+
for (const [key, value] of Object.entries(row)) {
|
|
217
|
+
if (isEmpty(value))
|
|
218
|
+
continue;
|
|
219
|
+
const property = optionSetUsingTypePropertiesBySlug[key];
|
|
220
|
+
if (!property)
|
|
221
|
+
continue;
|
|
222
|
+
if (skipColumns.has(key))
|
|
223
|
+
continue;
|
|
224
|
+
if (property.propertyType === 'choice') {
|
|
225
|
+
const isValidByValue = property.optionLookupByValue?.[value];
|
|
226
|
+
const isValidByDisplay = property.optionLookupByDisplay?.[value];
|
|
227
|
+
if (!isValidByValue && !isValidByDisplay) {
|
|
228
|
+
trackMissingValue(issuesByColumn, key, property, String(value), rowNumber);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (property.propertyType === 'multi_select') {
|
|
232
|
+
const values = String(value)
|
|
233
|
+
.split(',')
|
|
234
|
+
.map((v) => v.trim());
|
|
235
|
+
for (const val of values) {
|
|
236
|
+
if (!val)
|
|
237
|
+
continue;
|
|
238
|
+
const isValidByValue = property.optionLookupByValue?.[val];
|
|
239
|
+
const isValidByDisplay = property.optionLookupByDisplay?.[val];
|
|
240
|
+
if (!isValidByValue && !isValidByDisplay) {
|
|
241
|
+
trackMissingValue(issuesByColumn, key, property, val, rowNumber);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
for (const [columnName, data] of Object.entries(issuesByColumn)) {
|
|
248
|
+
for (const [missingValue, affectedRows] of data.missingValues) {
|
|
249
|
+
issues.push({
|
|
250
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
251
|
+
category: types_2.PreValidationCategory.OPTION_SET,
|
|
252
|
+
columnName,
|
|
253
|
+
propertySlug: data.property.slug,
|
|
254
|
+
propertyType: data.property.propertyType,
|
|
255
|
+
message: `Value "${missingValue}" is not in the option set for property "${columnName}".`,
|
|
256
|
+
affectedRows,
|
|
257
|
+
suggestedFix: {
|
|
258
|
+
type: types_2.SuggestedFixType.ADD_OPTION_SET_VALUES,
|
|
259
|
+
details: {
|
|
260
|
+
propertySlug: data.property.slug,
|
|
261
|
+
missingValue,
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return issues;
|
|
268
|
+
}
|
|
269
|
+
function trackMissingValue(tracker, columnName, property, value, rowNumber) {
|
|
270
|
+
if (!tracker[columnName]) {
|
|
271
|
+
tracker[columnName] = { property, missingValues: new Map() };
|
|
272
|
+
}
|
|
273
|
+
const existing = tracker[columnName].missingValues.get(value) || [];
|
|
274
|
+
existing.push({ row: rowNumber, value });
|
|
275
|
+
tracker[columnName].missingValues.set(value, existing);
|
|
276
|
+
}
|
|
277
|
+
function validateBooleanFormats(rows, typePropertyMaps) {
|
|
278
|
+
const { typePropertiesBySlug } = typePropertyMaps;
|
|
279
|
+
const issuesByColumn = {};
|
|
280
|
+
const validBooleanValues = new Set(['true', 'false', 'yes', 'no', '1', '0']);
|
|
281
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
282
|
+
for (const [key, value] of Object.entries(row)) {
|
|
283
|
+
const property = typePropertiesBySlug[key];
|
|
284
|
+
if (!property || property.propertyType !== 'boolean')
|
|
285
|
+
continue;
|
|
286
|
+
if (isEmpty(value) || typeof value === 'boolean')
|
|
287
|
+
continue;
|
|
288
|
+
const strVal = String(value).toLowerCase().trim();
|
|
289
|
+
if (!validBooleanValues.has(strVal)) {
|
|
290
|
+
if (!issuesByColumn[key])
|
|
291
|
+
issuesByColumn[key] = [];
|
|
292
|
+
issuesByColumn[key].push({ row: rowNumber, value: String(value) });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
return Object.entries(issuesByColumn).map(([columnName, affectedRows]) => ({
|
|
297
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
298
|
+
category: types_2.PreValidationCategory.FORMAT_BOOLEAN,
|
|
299
|
+
columnName,
|
|
300
|
+
propertySlug: typePropertiesBySlug[columnName]?.slug ?? columnName,
|
|
301
|
+
propertyType: 'boolean',
|
|
302
|
+
message: `Column "${columnName}" contains non-standard boolean values.`,
|
|
303
|
+
affectedRows,
|
|
304
|
+
}));
|
|
305
|
+
}
|
|
306
|
+
function validateMultiSelectFormats(rows, typePropertyMaps) {
|
|
307
|
+
const { optionSetUsingTypePropertiesBySlug } = typePropertyMaps;
|
|
308
|
+
const issues = [];
|
|
309
|
+
const semicolonColumns = {};
|
|
310
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
311
|
+
for (const [key, value] of Object.entries(row)) {
|
|
312
|
+
const property = optionSetUsingTypePropertiesBySlug[key];
|
|
313
|
+
if (!property || property.propertyType !== 'multi_select')
|
|
314
|
+
continue;
|
|
315
|
+
if (isEmpty(value))
|
|
316
|
+
continue;
|
|
317
|
+
const strVal = String(value);
|
|
318
|
+
if (strVal.includes(';') && !strVal.includes(',')) {
|
|
319
|
+
if (!semicolonColumns[key])
|
|
320
|
+
semicolonColumns[key] = [];
|
|
321
|
+
semicolonColumns[key].push({ row: rowNumber, value: strVal });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
for (const [columnName, affectedRows] of Object.entries(semicolonColumns)) {
|
|
326
|
+
const property = optionSetUsingTypePropertiesBySlug[columnName];
|
|
327
|
+
issues.push({
|
|
328
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
329
|
+
category: types_2.PreValidationCategory.FORMAT_MULTI_SELECT,
|
|
330
|
+
columnName,
|
|
331
|
+
propertySlug: property?.slug ?? columnName,
|
|
332
|
+
propertyType: 'multi_select',
|
|
333
|
+
message: `Column "${columnName}" appears to use semicolons instead of commas as a multi-select separator.`,
|
|
334
|
+
affectedRows,
|
|
335
|
+
suggestedFix: {
|
|
336
|
+
type: types_2.SuggestedFixType.CHANGE_SEPARATOR,
|
|
337
|
+
details: { from: ';', to: ',' },
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return issues;
|
|
342
|
+
}
|
|
343
|
+
function validateItemNames(rows, config) {
|
|
344
|
+
const itemBasedLoadTypes = [types_2.LoadType.ITEM, types_2.LoadType.PROJECT_ITEM, types_2.LoadType.ASSORTMENT];
|
|
345
|
+
const isItemBased = config.loadType.some((lt) => itemBasedLoadTypes.includes(lt));
|
|
346
|
+
if (!isItemBased)
|
|
347
|
+
return [];
|
|
348
|
+
const issues = [];
|
|
349
|
+
const nameKey = 'name';
|
|
350
|
+
const familyFedIdKey = 'itemFamilyFederatedId';
|
|
351
|
+
const optionNameKey = 'optionName';
|
|
352
|
+
const optionFedIdKey = 'itemOptionFederatedId';
|
|
353
|
+
const emptyNameRows = [];
|
|
354
|
+
const emptyFamilyFedIdRows = [];
|
|
355
|
+
const optionFedIdWithoutNameRows = [];
|
|
356
|
+
const optionNameWithoutFedIdRows = [];
|
|
357
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
358
|
+
const nameVal = row[nameKey];
|
|
359
|
+
if (isEmpty(nameVal)) {
|
|
360
|
+
emptyNameRows.push({ row: rowNumber, value: String(nameVal ?? '') });
|
|
361
|
+
}
|
|
362
|
+
const familyFedIdVal = row[familyFedIdKey];
|
|
363
|
+
if (isEmpty(familyFedIdVal)) {
|
|
364
|
+
emptyFamilyFedIdRows.push({ row: rowNumber, value: String(familyFedIdVal ?? '') });
|
|
365
|
+
}
|
|
366
|
+
const hasOptionFedId = !isEmpty(row[optionFedIdKey]);
|
|
367
|
+
const hasOptionName = !isEmpty(row[optionNameKey]);
|
|
368
|
+
if (hasOptionFedId && !hasOptionName) {
|
|
369
|
+
optionFedIdWithoutNameRows.push({ row: rowNumber, value: String(row[optionFedIdKey]) });
|
|
370
|
+
}
|
|
371
|
+
else if (hasOptionName && !hasOptionFedId) {
|
|
372
|
+
optionNameWithoutFedIdRows.push({ row: rowNumber, value: String(row[optionNameKey]) });
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
if (emptyNameRows.length > 0) {
|
|
376
|
+
issues.push({
|
|
377
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
378
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
379
|
+
columnName: nameKey,
|
|
380
|
+
propertySlug: 'name',
|
|
381
|
+
propertyType: 'string',
|
|
382
|
+
message: `"name" cannot be empty for item families. ${emptyNameRows.length} row(s) have an empty name.`,
|
|
383
|
+
affectedRows: emptyNameRows,
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
if (emptyFamilyFedIdRows.length > 0) {
|
|
387
|
+
issues.push({
|
|
388
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
389
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
390
|
+
columnName: familyFedIdKey,
|
|
391
|
+
propertySlug: 'itemFamilyFederatedId',
|
|
392
|
+
propertyType: 'string',
|
|
393
|
+
message: `"itemFamilyFederatedId" cannot be empty. ${emptyFamilyFedIdRows.length} row(s) have an empty itemFamilyFederatedId.`,
|
|
394
|
+
affectedRows: emptyFamilyFedIdRows,
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
if (optionFedIdWithoutNameRows.length > 0) {
|
|
398
|
+
issues.push({
|
|
399
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
400
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
401
|
+
columnName: optionNameKey,
|
|
402
|
+
propertySlug: 'optionName',
|
|
403
|
+
propertyType: 'string',
|
|
404
|
+
message: `"optionName" is required when "itemOptionFederatedId" is provided. ${optionFedIdWithoutNameRows.length} row(s) have an itemOptionFederatedId but no optionName.`,
|
|
405
|
+
affectedRows: optionFedIdWithoutNameRows,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
if (optionNameWithoutFedIdRows.length > 0) {
|
|
409
|
+
issues.push({
|
|
410
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
411
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
412
|
+
columnName: optionFedIdKey,
|
|
413
|
+
propertySlug: 'itemOptionFederatedId',
|
|
414
|
+
propertyType: 'string',
|
|
415
|
+
message: `"itemOptionFederatedId" is required when "optionName" is provided. ${optionNameWithoutFedIdRows.length} row(s) have an optionName but no itemOptionFederatedId.`,
|
|
416
|
+
affectedRows: optionNameWithoutFedIdRows,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
return issues;
|
|
420
|
+
}
|
|
421
|
+
function validateTypePathExistence(typesByPath) {
|
|
422
|
+
const issues = [];
|
|
423
|
+
for (const [typePath, entry] of Object.entries(typesByPath)) {
|
|
424
|
+
if (entry.error) {
|
|
425
|
+
issues.push({
|
|
426
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
427
|
+
category: CONFIG_CATEGORY,
|
|
428
|
+
columnName: 'typePath',
|
|
429
|
+
propertySlug: '',
|
|
430
|
+
propertyType: '',
|
|
431
|
+
message: `Type "${typePath}" does not exist. Check that the typePath is correct.`,
|
|
432
|
+
affectedRows: [],
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return issues;
|
|
437
|
+
}
|
|
438
|
+
function validateFamilyPropertyConsistency(rows, config, typesByPath) {
|
|
439
|
+
const itemBasedLoadTypes = [types_2.LoadType.ITEM, types_2.LoadType.PROJECT_ITEM, types_2.LoadType.ASSORTMENT];
|
|
440
|
+
const isItemBased = config.loadType.some((lt) => itemBasedLoadTypes.includes(lt));
|
|
441
|
+
if (!isItemBased)
|
|
442
|
+
return [];
|
|
443
|
+
const familyPropertyLevels = {};
|
|
444
|
+
const typesWithFamilyLevels = new Set(['item', 'project-item']);
|
|
445
|
+
for (const typePath of Object.keys(typesByPath)) {
|
|
446
|
+
if (!typesWithFamilyLevels.has(typePath))
|
|
447
|
+
continue;
|
|
448
|
+
const typeObj = typesByPath[typePath];
|
|
449
|
+
if (!typeObj?.type?.typeProperties)
|
|
450
|
+
continue;
|
|
451
|
+
for (const prop of typeObj.type.typeProperties) {
|
|
452
|
+
if (isFamilyLevelProperty(prop.propertyLevel)) {
|
|
453
|
+
const level = prop.propertyLevel || 'family-default';
|
|
454
|
+
familyPropertyLevels[prop.slug] = level;
|
|
455
|
+
if (prop.propertyLevel === types_1.PropertyLevel.OVERRIDABLE) {
|
|
456
|
+
familyPropertyLevels[prop.slug + 'Family'] = types_1.PropertyLevel.FAMILY;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
const familyPropertySlugs = new Set(Object.keys(familyPropertyLevels));
|
|
462
|
+
if (familyPropertySlugs.size === 0)
|
|
463
|
+
return [];
|
|
464
|
+
const familyGroups = {};
|
|
465
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
466
|
+
const famId = row.itemFamilyFederatedId;
|
|
467
|
+
if (!famId)
|
|
468
|
+
return;
|
|
469
|
+
if (!familyGroups[famId]) {
|
|
470
|
+
familyGroups[famId] = { rows: [], rowNumbers: [] };
|
|
471
|
+
}
|
|
472
|
+
familyGroups[famId].rows.push(row);
|
|
473
|
+
familyGroups[famId].rowNumbers.push(rowNumber);
|
|
474
|
+
});
|
|
475
|
+
const issues = [];
|
|
476
|
+
const inconsistenciesBySlug = {};
|
|
477
|
+
for (const [famId, group] of Object.entries(familyGroups)) {
|
|
478
|
+
if (group.rows.length <= 1)
|
|
479
|
+
continue;
|
|
480
|
+
for (const slug of familyPropertySlugs) {
|
|
481
|
+
const valuesWithRows = new Map();
|
|
482
|
+
for (let i = 0; i < group.rows.length; i++) {
|
|
483
|
+
const row = group.rows[i];
|
|
484
|
+
if (!(slug in row))
|
|
485
|
+
continue;
|
|
486
|
+
const val = String(row[slug] ?? '');
|
|
487
|
+
const existing = valuesWithRows.get(val) || [];
|
|
488
|
+
existing.push(group.rowNumbers[i]);
|
|
489
|
+
valuesWithRows.set(val, existing);
|
|
490
|
+
}
|
|
491
|
+
if (valuesWithRows.size <= 1)
|
|
492
|
+
continue;
|
|
493
|
+
if (!inconsistenciesBySlug[slug]) {
|
|
494
|
+
inconsistenciesBySlug[slug] = { families: [] };
|
|
495
|
+
}
|
|
496
|
+
inconsistenciesBySlug[slug].families.push({
|
|
497
|
+
familyId: famId,
|
|
498
|
+
values: new Set(valuesWithRows.keys()),
|
|
499
|
+
rowNumbers: group.rowNumbers,
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
for (const [slug, data] of Object.entries(inconsistenciesBySlug)) {
|
|
504
|
+
const affectedRows = [];
|
|
505
|
+
const familyDetails = [];
|
|
506
|
+
for (const family of data.families) {
|
|
507
|
+
const valuesStr = Array.from(family.values).map((v) => `"${v}"`).join(', ');
|
|
508
|
+
familyDetails.push(`family "${family.familyId}" has values: ${valuesStr}`);
|
|
509
|
+
for (const rowNum of family.rowNumbers) {
|
|
510
|
+
affectedRows.push({ row: rowNum, value: slug });
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
const level = familyPropertyLevels[slug];
|
|
514
|
+
let message;
|
|
515
|
+
if (level === types_1.PropertyLevel.FAMILY || level === 'family-default') {
|
|
516
|
+
message = `Family-level property "${slug}" has inconsistent values across rows for the same family. All rows sharing an itemFamilyFederatedId must have the same value for family properties. ${familyDetails.join('; ')}.`;
|
|
517
|
+
}
|
|
518
|
+
else if (level === types_1.PropertyLevel.ALL) {
|
|
519
|
+
message = `All-level property "${slug}" has inconsistent values across rows for the same family. Without a "Family"/"Option" suffix, this column applies the same value to both family and option — so all rows for the same itemFamilyFederatedId must agree. If you need different values per option, split this into "${slug}Family" and "${slug}Option" columns. ${familyDetails.join('; ')}.`;
|
|
520
|
+
}
|
|
521
|
+
else if (level === types_1.PropertyLevel.OVERRIDABLE) {
|
|
522
|
+
message = `Override-level property "${slug}" has inconsistent values across rows for the same family. Without a "Family"/"Option" suffix, this column applies the same value to both family and option — so all rows for the same itemFamilyFederatedId must agree. If you need different values per option, split this into "${slug}Family" and "${slug}Option" columns. ${familyDetails.join('; ')}.`;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
message = `Property "${slug}" has inconsistent values across rows for the same family. All rows sharing an itemFamilyFederatedId must have the same value. ${familyDetails.join('; ')}.`;
|
|
526
|
+
}
|
|
527
|
+
issues.push({
|
|
528
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
529
|
+
category: FAMILY_INCONSISTENT_CATEGORY,
|
|
530
|
+
columnName: slug,
|
|
531
|
+
propertySlug: slug,
|
|
532
|
+
propertyType: '',
|
|
533
|
+
message,
|
|
534
|
+
affectedRows,
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return issues;
|
|
538
|
+
}
|
|
539
|
+
function isFamilyLevelProperty(propertyLevel) {
|
|
540
|
+
if (!propertyLevel)
|
|
541
|
+
return true;
|
|
542
|
+
return [
|
|
543
|
+
types_1.PropertyLevel.FAMILY,
|
|
544
|
+
types_1.PropertyLevel.ALL,
|
|
545
|
+
types_1.PropertyLevel.OVERRIDABLE,
|
|
546
|
+
].includes(propertyLevel);
|
|
547
|
+
}
|
|
548
|
+
function validateAllOverrideSuffixes(rows, config, columnAnalysis) {
|
|
549
|
+
const loadTypeHasRoles = [types_2.LoadType.ITEM, types_2.LoadType.PROJECT_ITEM];
|
|
550
|
+
const hasRoles = config.loadType.some((lt) => loadTypeHasRoles.includes(lt));
|
|
551
|
+
if (!hasRoles)
|
|
552
|
+
return [];
|
|
553
|
+
const allOverrideSlugs = new Set();
|
|
554
|
+
const allOverrideLabels = new Map();
|
|
555
|
+
for (const typePath of Object.keys(columnAnalysis.typesByPath)) {
|
|
556
|
+
const typeObj = columnAnalysis.typesByPath[typePath];
|
|
557
|
+
if (!typeObj?.type?.typeProperties)
|
|
558
|
+
continue;
|
|
559
|
+
for (const prop of typeObj.type.typeProperties) {
|
|
560
|
+
if (prop.propertyLevel === types_1.PropertyLevel.ALL ||
|
|
561
|
+
prop.propertyLevel === types_1.PropertyLevel.OVERRIDABLE) {
|
|
562
|
+
allOverrideSlugs.add(prop.slug);
|
|
563
|
+
if (prop.label) {
|
|
564
|
+
allOverrideLabels.set(prop.label, prop.slug);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (allOverrideSlugs.size === 0)
|
|
570
|
+
return [];
|
|
571
|
+
const issues = [];
|
|
572
|
+
const csvHeaders = rows.length > 0 ? Object.keys(rows[0]) : [];
|
|
573
|
+
for (const header of csvHeaders) {
|
|
574
|
+
const matchedSlug = allOverrideSlugs.has(header)
|
|
575
|
+
? header
|
|
576
|
+
: allOverrideLabels.get(header);
|
|
577
|
+
if (!matchedSlug)
|
|
578
|
+
continue;
|
|
579
|
+
const affectedRows = [];
|
|
580
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
581
|
+
const val = row[header];
|
|
582
|
+
if (!isEmpty(val)) {
|
|
583
|
+
affectedRows.push({ row: rowNumber, value: String(val) });
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
if (affectedRows.length === 0) {
|
|
587
|
+
affectedRows.push({ row: 2, value: '' });
|
|
588
|
+
}
|
|
589
|
+
issues.push({
|
|
590
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
591
|
+
category: CONFIG_CATEGORY,
|
|
592
|
+
columnName: header,
|
|
593
|
+
propertySlug: matchedSlug,
|
|
594
|
+
propertyType: '',
|
|
595
|
+
message: `Column "${header}" targets an all-level or override-level property without a "Family" or "Option" suffix. The loader cannot determine whether this value should apply to the family, the option, or both. Use "${matchedSlug}Family" and/or "${matchedSlug}Option" columns instead.`,
|
|
596
|
+
affectedRows,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
return issues;
|
|
600
|
+
}
|
|
601
|
+
async function validateAndResolveProjectIdentifiers(rows, config, client) {
|
|
602
|
+
const isProjectItemLoad = config.loadType.some((lt) => lt === types_2.LoadType.PROJECT_ITEM);
|
|
603
|
+
if (!isProjectItemLoad)
|
|
604
|
+
return [];
|
|
605
|
+
const hasWorkspaceIdentifier = rows.some((row) => row.workspaceIdentifier);
|
|
606
|
+
if (hasWorkspaceIdentifier) {
|
|
607
|
+
return validateWorkspaceIdentifiers(rows, client);
|
|
608
|
+
}
|
|
609
|
+
return validateProjectIds(rows, client);
|
|
610
|
+
}
|
|
611
|
+
async function validateWorkspaceIdentifiers(rows, client) {
|
|
612
|
+
const issues = [];
|
|
613
|
+
const cache = {};
|
|
614
|
+
const uniqueIdentifiers = new Set();
|
|
615
|
+
for (const row of rows) {
|
|
616
|
+
if (row.workspaceIdentifier)
|
|
617
|
+
uniqueIdentifiers.add(row.workspaceIdentifier);
|
|
618
|
+
}
|
|
619
|
+
for (const wsIdentifier of uniqueIdentifiers) {
|
|
620
|
+
try {
|
|
621
|
+
const project = await resolveProjectIdFromWorkspace(client, wsIdentifier);
|
|
622
|
+
cache[wsIdentifier] = project;
|
|
623
|
+
if (!project) {
|
|
624
|
+
const affectedRows = [];
|
|
625
|
+
rows.forEach((row, index) => {
|
|
626
|
+
if (row.workspaceIdentifier === wsIdentifier) {
|
|
627
|
+
affectedRows.push({ row: index + 2, value: wsIdentifier });
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
issues.push({
|
|
631
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
632
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
633
|
+
columnName: 'workspaceIdentifier',
|
|
634
|
+
propertySlug: 'workspaceIdentifier',
|
|
635
|
+
propertyType: 'string',
|
|
636
|
+
message: `Could not resolve workspace identifier "${wsIdentifier}" to a project. Verify the workspace exists and is a PROJECT type workspace.`,
|
|
637
|
+
affectedRows,
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
catch (e) {
|
|
642
|
+
issues.push({
|
|
643
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
644
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
645
|
+
columnName: 'workspaceIdentifier',
|
|
646
|
+
propertySlug: 'workspaceIdentifier',
|
|
647
|
+
propertyType: 'string',
|
|
648
|
+
message: `Failed to resolve workspace identifier "${wsIdentifier}": ${e.message}`,
|
|
649
|
+
affectedRows: [],
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (issues.length === 0) {
|
|
654
|
+
for (const row of rows) {
|
|
655
|
+
if (row.workspaceIdentifier) {
|
|
656
|
+
const project = cache[row.workspaceIdentifier];
|
|
657
|
+
row.projectId = project.id;
|
|
658
|
+
row.projectName = project.name;
|
|
659
|
+
delete row.workspaceIdentifier;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return issues;
|
|
664
|
+
}
|
|
665
|
+
async function validateProjectIds(rows, client) {
|
|
666
|
+
const issues = [];
|
|
667
|
+
const nameCache = {};
|
|
668
|
+
const uniqueProjectIds = new Set();
|
|
669
|
+
for (const row of rows) {
|
|
670
|
+
if (row.projectId)
|
|
671
|
+
uniqueProjectIds.add(row.projectId);
|
|
672
|
+
}
|
|
673
|
+
if (uniqueProjectIds.size === 0)
|
|
674
|
+
return [];
|
|
675
|
+
for (const projectId of uniqueProjectIds) {
|
|
676
|
+
try {
|
|
677
|
+
const project = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
678
|
+
entityName: 'project',
|
|
679
|
+
id: projectId,
|
|
680
|
+
skipHydrateRelationships: true,
|
|
681
|
+
});
|
|
682
|
+
if (!project) {
|
|
683
|
+
const affectedRows = [];
|
|
684
|
+
rows.forEach((row, index) => {
|
|
685
|
+
if (row.projectId === projectId) {
|
|
686
|
+
affectedRows.push({ row: index + 2, value: projectId });
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
issues.push({
|
|
690
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
691
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
692
|
+
columnName: 'projectId',
|
|
693
|
+
propertySlug: 'projectId',
|
|
694
|
+
propertyType: 'string',
|
|
695
|
+
message: `Project "${projectId}" not found. Verify the project ID is correct and the project exists.`,
|
|
696
|
+
affectedRows,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
else {
|
|
700
|
+
nameCache[projectId] = project.name || project.identifier || projectId;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
catch (e) {
|
|
704
|
+
const affectedRows = [];
|
|
705
|
+
rows.forEach((row, index) => {
|
|
706
|
+
if (row.projectId === projectId) {
|
|
707
|
+
affectedRows.push({ row: index + 2, value: projectId });
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
issues.push({
|
|
711
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
712
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
713
|
+
columnName: 'projectId',
|
|
714
|
+
propertySlug: 'projectId',
|
|
715
|
+
propertyType: 'string',
|
|
716
|
+
message: `Failed to validate project "${projectId}": ${e.message}`,
|
|
717
|
+
affectedRows,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (issues.length === 0) {
|
|
722
|
+
for (const row of rows) {
|
|
723
|
+
if (row.projectId && nameCache[row.projectId]) {
|
|
724
|
+
row.projectName = nameCache[row.projectId];
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return issues;
|
|
729
|
+
}
|
|
730
|
+
async function resolveProjectIdFromWorkspace(client, workspaceIdentifier) {
|
|
731
|
+
const workspaces = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
732
|
+
entityName: 'workspace',
|
|
733
|
+
criteria: {
|
|
734
|
+
identifier: workspaceIdentifier,
|
|
735
|
+
workspaceType: 'PROJECT',
|
|
736
|
+
},
|
|
737
|
+
skipHydrateRelationships: true,
|
|
738
|
+
});
|
|
739
|
+
if (!workspaces?.length)
|
|
740
|
+
return null;
|
|
741
|
+
const workspaceId = workspaces[0]?.id;
|
|
742
|
+
if (!workspaceId)
|
|
743
|
+
return null;
|
|
744
|
+
const workspace = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
745
|
+
entityName: 'workspace',
|
|
746
|
+
id: workspaceId,
|
|
747
|
+
relations: ['project'],
|
|
748
|
+
skipHydrateRelationships: true,
|
|
749
|
+
});
|
|
750
|
+
const project = workspace?.project;
|
|
751
|
+
if (!project?.id)
|
|
752
|
+
return null;
|
|
753
|
+
return { id: project.id, name: project.name || project.id };
|
|
754
|
+
}
|
|
755
|
+
function validateProjectItemColumns(rows, config) {
|
|
756
|
+
const isProjectItemLoad = config.loadType.some((lt) => lt === types_2.LoadType.PROJECT_ITEM);
|
|
757
|
+
if (!isProjectItemLoad)
|
|
758
|
+
return [];
|
|
759
|
+
const issues = [];
|
|
760
|
+
const hasWorkspaceIdentifier = rows.some((row) => row.workspaceIdentifier !== undefined);
|
|
761
|
+
const hasProjectId = rows.some((row) => row.projectId !== undefined);
|
|
762
|
+
if (hasWorkspaceIdentifier && hasProjectId) {
|
|
763
|
+
issues.push({
|
|
764
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
765
|
+
category: CONFIG_CATEGORY,
|
|
766
|
+
columnName: 'workspaceIdentifier / projectId',
|
|
767
|
+
propertySlug: '',
|
|
768
|
+
propertyType: '',
|
|
769
|
+
message: 'Rows contain both "workspaceIdentifier" and "projectId" columns. Use one or the other to identify the target project.',
|
|
770
|
+
affectedRows: [],
|
|
771
|
+
});
|
|
772
|
+
return issues;
|
|
773
|
+
}
|
|
774
|
+
if (!hasWorkspaceIdentifier && !hasProjectId) {
|
|
775
|
+
issues.push({
|
|
776
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
777
|
+
category: CONFIG_CATEGORY,
|
|
778
|
+
columnName: 'workspaceIdentifier / projectId',
|
|
779
|
+
propertySlug: '',
|
|
780
|
+
propertyType: '',
|
|
781
|
+
message: 'PROJECT_ITEM loads require a "workspaceIdentifier" or "projectId" column (or a config-level workspaceIdentifier) to identify the target project.',
|
|
782
|
+
affectedRows: [],
|
|
783
|
+
});
|
|
784
|
+
return issues;
|
|
785
|
+
}
|
|
786
|
+
const columnName = hasWorkspaceIdentifier ? 'workspaceIdentifier' : 'projectId';
|
|
787
|
+
const emptyRows = [];
|
|
788
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
789
|
+
if (isEmpty(row[columnName])) {
|
|
790
|
+
emptyRows.push({ row: rowNumber, value: '' });
|
|
791
|
+
}
|
|
792
|
+
});
|
|
793
|
+
if (emptyRows.length > 0) {
|
|
794
|
+
issues.push({
|
|
795
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
796
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
797
|
+
columnName,
|
|
798
|
+
propertySlug: columnName,
|
|
799
|
+
propertyType: 'string',
|
|
800
|
+
message: `"${columnName}" cannot be empty for project-item rows. ${emptyRows.length} row(s) have an empty value.`,
|
|
801
|
+
affectedRows: emptyRows,
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
return issues;
|
|
805
|
+
}
|
|
806
|
+
function validateStaticIdentifierConflicts(config) {
|
|
807
|
+
const issues = [];
|
|
808
|
+
const conditionalTargets = new Set((config.conditionalColumns || []).map((col) => col.toProperty));
|
|
809
|
+
const staticFields = [
|
|
810
|
+
{ field: 'workspaceIdentifier', value: config.workspaceIdentifier },
|
|
811
|
+
{ field: 'projectId', value: config.projectId },
|
|
812
|
+
{ field: 'assortmentId', value: config.assortmentId },
|
|
813
|
+
{ field: 'assortmentIdentifier', value: config.assortmentIdentifier },
|
|
814
|
+
];
|
|
815
|
+
for (const { field, value } of staticFields) {
|
|
816
|
+
if (value && conditionalTargets.has(field)) {
|
|
817
|
+
issues.push({
|
|
818
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
819
|
+
category: CONFIG_CATEGORY,
|
|
820
|
+
columnName: field,
|
|
821
|
+
propertySlug: field,
|
|
822
|
+
propertyType: 'string',
|
|
823
|
+
message: `"${field}" is set as a static config value and also as a conditionalColumns target. Use one or the other.`,
|
|
824
|
+
affectedRows: [],
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return issues;
|
|
829
|
+
}
|
|
830
|
+
function validateAssortmentColumns(rows, config) {
|
|
831
|
+
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
832
|
+
if (!isAssortmentLoad)
|
|
833
|
+
return [];
|
|
834
|
+
const issues = [];
|
|
835
|
+
const hasAssortmentId = rows.some((row) => row.assortmentId !== undefined);
|
|
836
|
+
const hasAssortmentIdentifier = rows.some((row) => row.assortmentIdentifier !== undefined);
|
|
837
|
+
const assortmentIdFromConditions = (config.conditionalColumns || []).some((col) => (col.toProperty === 'assortmentId' || col.toProperty === 'assortmentIdentifier') && col.conditions?.length);
|
|
838
|
+
if (!hasAssortmentId && !hasAssortmentIdentifier) {
|
|
839
|
+
issues.push({
|
|
840
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
841
|
+
category: CONFIG_CATEGORY,
|
|
842
|
+
columnName: 'assortmentId / assortmentIdentifier',
|
|
843
|
+
propertySlug: '',
|
|
844
|
+
propertyType: '',
|
|
845
|
+
message: 'ASSORTMENT loads require an "assortmentId" or "assortmentIdentifier" column (or a config-level assortmentId/assortmentIdentifier) to identify the target assortment.',
|
|
846
|
+
affectedRows: [],
|
|
847
|
+
});
|
|
848
|
+
return issues;
|
|
849
|
+
}
|
|
850
|
+
const bothRows = [];
|
|
851
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
852
|
+
const hasId = !isEmpty(row.assortmentId);
|
|
853
|
+
const hasIdent = !isEmpty(row.assortmentIdentifier);
|
|
854
|
+
if (hasId && hasIdent) {
|
|
855
|
+
bothRows.push({ row: rowNumber, value: `${row.assortmentId} / ${row.assortmentIdentifier}` });
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
if (bothRows.length > 0) {
|
|
859
|
+
issues.push({
|
|
860
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
861
|
+
category: CONFIG_CATEGORY,
|
|
862
|
+
columnName: 'assortmentId / assortmentIdentifier',
|
|
863
|
+
propertySlug: '',
|
|
864
|
+
propertyType: '',
|
|
865
|
+
message: `${bothRows.length} row(s) have both "assortmentId" and "assortmentIdentifier". Each row must use one or the other.`,
|
|
866
|
+
affectedRows: bothRows,
|
|
867
|
+
});
|
|
868
|
+
return issues;
|
|
869
|
+
}
|
|
870
|
+
const emptyIdRows = [];
|
|
871
|
+
const emptyIdentRows = [];
|
|
872
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
873
|
+
if (hasAssortmentId && row.assortmentId !== undefined) {
|
|
874
|
+
if (isEmpty(row.assortmentId)) {
|
|
875
|
+
emptyIdRows.push({ row: rowNumber, value: '' });
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
else if (hasAssortmentId && row.assortmentId === undefined && !assortmentIdFromConditions) {
|
|
879
|
+
emptyIdRows.push({ row: rowNumber, value: '' });
|
|
880
|
+
}
|
|
881
|
+
if (hasAssortmentIdentifier && row.assortmentIdentifier !== undefined) {
|
|
882
|
+
if (isEmpty(row.assortmentIdentifier)) {
|
|
883
|
+
emptyIdentRows.push({ row: rowNumber, value: '' });
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
if (emptyIdRows.length > 0) {
|
|
888
|
+
issues.push({
|
|
889
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
890
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
891
|
+
columnName: 'assortmentId',
|
|
892
|
+
propertySlug: 'assortmentId',
|
|
893
|
+
propertyType: 'string',
|
|
894
|
+
message: `"assortmentId" cannot be empty for assortment rows. ${emptyIdRows.length} row(s) have an empty value.`,
|
|
895
|
+
affectedRows: emptyIdRows,
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
if (emptyIdentRows.length > 0) {
|
|
899
|
+
issues.push({
|
|
900
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
901
|
+
category: MISSING_REQUIRED_FIELD_CATEGORY,
|
|
902
|
+
columnName: 'assortmentIdentifier',
|
|
903
|
+
propertySlug: 'assortmentIdentifier',
|
|
904
|
+
propertyType: 'string',
|
|
905
|
+
message: `"assortmentIdentifier" cannot be empty for assortment rows. ${emptyIdentRows.length} row(s) have an empty value.`,
|
|
906
|
+
affectedRows: emptyIdentRows,
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
return issues;
|
|
910
|
+
}
|
|
911
|
+
async function validateAndResolveAssortmentIdentifiers(rows, config, client) {
|
|
912
|
+
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
913
|
+
if (!isAssortmentLoad)
|
|
914
|
+
return [];
|
|
915
|
+
const hasAssortmentIdentifier = rows.some((row) => row.assortmentIdentifier);
|
|
916
|
+
if (hasAssortmentIdentifier) {
|
|
917
|
+
return resolveAssortmentIdentifiers(rows, client);
|
|
918
|
+
}
|
|
919
|
+
return validateAssortmentIds(rows, client);
|
|
920
|
+
}
|
|
921
|
+
async function resolveAssortmentIdentifiers(rows, client) {
|
|
922
|
+
const issues = [];
|
|
923
|
+
const cache = {};
|
|
924
|
+
const uniqueIdentifiers = new Set();
|
|
925
|
+
for (const row of rows) {
|
|
926
|
+
if (row.assortmentIdentifier)
|
|
927
|
+
uniqueIdentifiers.add(row.assortmentIdentifier);
|
|
928
|
+
}
|
|
929
|
+
for (const identifier of uniqueIdentifiers) {
|
|
930
|
+
try {
|
|
931
|
+
const assortments = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
932
|
+
entityName: 'assortment',
|
|
933
|
+
criteria: { identifier },
|
|
934
|
+
skipHydrateRelationships: true,
|
|
935
|
+
});
|
|
936
|
+
if (!assortments?.length) {
|
|
937
|
+
cache[identifier] = null;
|
|
938
|
+
const affectedRows = [];
|
|
939
|
+
rows.forEach((row, index) => {
|
|
940
|
+
if (row.assortmentIdentifier === identifier) {
|
|
941
|
+
affectedRows.push({ row: index + 2, value: identifier });
|
|
942
|
+
}
|
|
943
|
+
});
|
|
944
|
+
issues.push({
|
|
945
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
946
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
947
|
+
columnName: 'assortmentIdentifier',
|
|
948
|
+
propertySlug: 'assortmentIdentifier',
|
|
949
|
+
propertyType: 'string',
|
|
950
|
+
message: `Assortment with identifier "${identifier}" not found. Verify the identifier is correct and the assortment exists.`,
|
|
951
|
+
affectedRows,
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
const assortment = assortments[0];
|
|
956
|
+
cache[identifier] = { id: assortment.id, name: assortment.name || assortment.id };
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
catch (e) {
|
|
960
|
+
issues.push({
|
|
961
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
962
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
963
|
+
columnName: 'assortmentIdentifier',
|
|
964
|
+
propertySlug: 'assortmentIdentifier',
|
|
965
|
+
propertyType: 'string',
|
|
966
|
+
message: `Failed to resolve assortment identifier "${identifier}": ${e.message}`,
|
|
967
|
+
affectedRows: [],
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
if (issues.length === 0) {
|
|
972
|
+
for (const row of rows) {
|
|
973
|
+
if (row.assortmentIdentifier) {
|
|
974
|
+
const assortment = cache[row.assortmentIdentifier];
|
|
975
|
+
row.assortmentId = assortment.id;
|
|
976
|
+
row.assortmentName = assortment.name;
|
|
977
|
+
delete row.assortmentIdentifier;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
return issues;
|
|
982
|
+
}
|
|
983
|
+
async function validateAssortmentIds(rows, client) {
|
|
984
|
+
const issues = [];
|
|
985
|
+
const nameCache = {};
|
|
986
|
+
const uniqueIds = new Set();
|
|
987
|
+
for (const row of rows) {
|
|
988
|
+
if (row.assortmentId)
|
|
989
|
+
uniqueIds.add(row.assortmentId);
|
|
990
|
+
}
|
|
991
|
+
if (uniqueIds.size === 0)
|
|
992
|
+
return [];
|
|
993
|
+
for (const assortmentId of uniqueIds) {
|
|
994
|
+
try {
|
|
995
|
+
const assortment = await (0, entities_helper_1.retryOnTimeout)(client, entities_helper_1.EntitiesLambdaCallType.GET, {
|
|
996
|
+
entityName: 'assortment',
|
|
997
|
+
id: assortmentId,
|
|
998
|
+
skipHydrateRelationships: true,
|
|
999
|
+
});
|
|
1000
|
+
if (assortment) {
|
|
1001
|
+
nameCache[assortmentId] = assortment.name || assortmentId;
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
catch (e) {
|
|
1005
|
+
const affectedRows = [];
|
|
1006
|
+
rows.forEach((row, index) => {
|
|
1007
|
+
if (row.assortmentId === assortmentId) {
|
|
1008
|
+
affectedRows.push({ row: index + 2, value: assortmentId });
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
const parsedDetails = typeof e?.details === 'string' ? JSON.parse(e.details).statusCode : e?.details?.statusCode;
|
|
1012
|
+
const message = parsedDetails === 404
|
|
1013
|
+
? `Assortment "${assortmentId}" not found. Verify the assortment ID is correct and the assortment exists.`
|
|
1014
|
+
: `Failed to validate assortment "${assortmentId}": ${e.message}`;
|
|
1015
|
+
issues.push({
|
|
1016
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
1017
|
+
category: REFERENCE_NOT_FOUND_CATEGORY,
|
|
1018
|
+
columnName: 'assortmentId',
|
|
1019
|
+
propertySlug: 'assortmentId',
|
|
1020
|
+
propertyType: 'string',
|
|
1021
|
+
message,
|
|
1022
|
+
affectedRows,
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
if (issues.length === 0) {
|
|
1027
|
+
for (const row of rows) {
|
|
1028
|
+
if (row.assortmentId && nameCache[row.assortmentId]) {
|
|
1029
|
+
row.assortmentName = nameCache[row.assortmentId];
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
return issues;
|
|
1034
|
+
}
|
|
1035
|
+
function validatePartialAssortmentConfig(rows, config) {
|
|
1036
|
+
const isAssortmentLoad = config.loadType.some((lt) => lt === types_2.LoadType.ASSORTMENT);
|
|
1037
|
+
if (!isAssortmentLoad || !config.partialAssortmentUpdate)
|
|
1038
|
+
return [];
|
|
1039
|
+
const issues = [];
|
|
1040
|
+
if (!config.assortmentItemDropField) {
|
|
1041
|
+
issues.push({
|
|
1042
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
1043
|
+
category: CONFIG_CATEGORY,
|
|
1044
|
+
columnName: 'assortmentItemDropField',
|
|
1045
|
+
propertySlug: 'assortmentItemDropField',
|
|
1046
|
+
propertyType: 'string',
|
|
1047
|
+
message: 'partialAssortmentUpdate is enabled but assortmentItemDropField is not set. Specify which column identifies items to drop.',
|
|
1048
|
+
affectedRows: [],
|
|
1049
|
+
});
|
|
1050
|
+
return issues;
|
|
1051
|
+
}
|
|
1052
|
+
const hasDropField = rows.some((row) => row[config.assortmentItemDropField] !== undefined);
|
|
1053
|
+
if (!hasDropField) {
|
|
1054
|
+
issues.push({
|
|
1055
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
1056
|
+
category: CONFIG_CATEGORY,
|
|
1057
|
+
columnName: config.assortmentItemDropField,
|
|
1058
|
+
propertySlug: config.assortmentItemDropField,
|
|
1059
|
+
propertyType: 'string',
|
|
1060
|
+
message: `partialAssortmentUpdate requires the drop field column "${config.assortmentItemDropField}" to be present in the data.`,
|
|
1061
|
+
affectedRows: [],
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
return issues;
|
|
1065
|
+
}
|
|
1066
|
+
function validateSelfReferences(rows, config, typesByPath) {
|
|
1067
|
+
const itemBasedLoadTypes = [types_2.LoadType.ITEM, types_2.LoadType.PROJECT_ITEM, types_2.LoadType.ASSORTMENT];
|
|
1068
|
+
const isItemBased = config.loadType.some((lt) => itemBasedLoadTypes.includes(lt));
|
|
1069
|
+
const columnChecks = buildObjectRefColumnChecks(typesByPath, isItemBased);
|
|
1070
|
+
if (columnChecks.length === 0)
|
|
1071
|
+
return [];
|
|
1072
|
+
const selfRefsByColumn = {};
|
|
1073
|
+
forEachRow(rows, (row, rowNumber) => {
|
|
1074
|
+
for (const check of columnChecks) {
|
|
1075
|
+
const refValue = row[check.columnName];
|
|
1076
|
+
if (isEmpty(refValue))
|
|
1077
|
+
continue;
|
|
1078
|
+
const refStr = String(refValue);
|
|
1079
|
+
for (const fedIdKey of check.federatedIdKeys) {
|
|
1080
|
+
const ownId = row[fedIdKey];
|
|
1081
|
+
if (!ownId)
|
|
1082
|
+
continue;
|
|
1083
|
+
if (refStr === String(ownId)) {
|
|
1084
|
+
if (!selfRefsByColumn[check.columnName])
|
|
1085
|
+
selfRefsByColumn[check.columnName] = [];
|
|
1086
|
+
selfRefsByColumn[check.columnName].push({ row: rowNumber, value: refStr });
|
|
1087
|
+
break;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
});
|
|
1092
|
+
const issues = [];
|
|
1093
|
+
for (const [columnName, affectedRows] of Object.entries(selfRefsByColumn)) {
|
|
1094
|
+
issues.push({
|
|
1095
|
+
severity: types_2.PreValidationSeverity.ERROR,
|
|
1096
|
+
category: SELF_REFERENCE_CATEGORY,
|
|
1097
|
+
columnName,
|
|
1098
|
+
propertySlug: columnName,
|
|
1099
|
+
propertyType: 'object_reference',
|
|
1100
|
+
message: `Object reference property "${columnName}" contains self-referencing values. ${affectedRows.length} row(s) reference their own federatedId, which creates circular references and causes issues with publishing and data integrity.`,
|
|
1101
|
+
affectedRows,
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
return issues;
|
|
1105
|
+
}
|
|
1106
|
+
function buildObjectRefColumnChecks(typesByPath, isItemBased) {
|
|
1107
|
+
const checks = [];
|
|
1108
|
+
for (const typePath of Object.keys(typesByPath)) {
|
|
1109
|
+
const typeObj = typesByPath[typePath];
|
|
1110
|
+
for (const prop of typeObj?.objectReferenceProperties ?? []) {
|
|
1111
|
+
if (!isItemBased) {
|
|
1112
|
+
checks.push({ columnName: prop.slug, federatedIdKeys: ['federatedId'] });
|
|
1113
|
+
continue;
|
|
1114
|
+
}
|
|
1115
|
+
const level = prop.propertyLevel;
|
|
1116
|
+
if (level === types_1.PropertyLevel.FAMILY) {
|
|
1117
|
+
checks.push({ columnName: prop.slug, federatedIdKeys: ['itemFamilyFederatedId'] });
|
|
1118
|
+
}
|
|
1119
|
+
else if (level === types_1.PropertyLevel.OPTION) {
|
|
1120
|
+
checks.push({ columnName: prop.slug, federatedIdKeys: ['itemOptionFederatedId'] });
|
|
1121
|
+
}
|
|
1122
|
+
else if (level === types_1.PropertyLevel.OVERRIDABLE || level === types_1.PropertyLevel.ALL) {
|
|
1123
|
+
checks.push({ columnName: prop.slug + 'Family', federatedIdKeys: ['itemFamilyFederatedId'] });
|
|
1124
|
+
checks.push({ columnName: prop.slug + 'Option', federatedIdKeys: ['itemOptionFederatedId'] });
|
|
1125
|
+
}
|
|
1126
|
+
else {
|
|
1127
|
+
checks.push({ columnName: prop.slug, federatedIdKeys: ['itemFamilyFederatedId'] });
|
|
1128
|
+
}
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
return checks;
|
|
1132
|
+
}
|
|
1133
|
+
const NUMERIC_PROPERTY_TYPES = new Set(['number', 'currency', 'percent', 'sequence']);
|
|
1134
|
+
function validateNumberPrecision(rows, typePropertyMaps) {
|
|
1135
|
+
const { typePropertiesBySlug } = typePropertyMaps;
|
|
1136
|
+
const issuesByColumn = {};
|
|
1137
|
+
rows.forEach((row, index) => {
|
|
1138
|
+
const rowNumber = index + 2;
|
|
1139
|
+
for (const [key, value] of Object.entries(row)) {
|
|
1140
|
+
const property = typePropertiesBySlug[key];
|
|
1141
|
+
if (!property || !NUMERIC_PROPERTY_TYPES.has(property.propertyType))
|
|
1142
|
+
continue;
|
|
1143
|
+
const precision = property.numberFormat?.precision;
|
|
1144
|
+
if (precision === null || precision === undefined)
|
|
1145
|
+
continue;
|
|
1146
|
+
if (typeof value !== 'number')
|
|
1147
|
+
continue;
|
|
1148
|
+
if (Number(value.toFixed(precision)) !== value) {
|
|
1149
|
+
if (!issuesByColumn[key])
|
|
1150
|
+
issuesByColumn[key] = { affectedRows: [], precision };
|
|
1151
|
+
issuesByColumn[key].affectedRows.push({ row: rowNumber, value: String(value) });
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
});
|
|
1155
|
+
return Object.entries(issuesByColumn).map(([columnName, { affectedRows, precision }]) => ({
|
|
1156
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
1157
|
+
category: types_2.PreValidationCategory.FORMAT_NUMBER_PRECISION,
|
|
1158
|
+
columnName,
|
|
1159
|
+
propertySlug: typePropertiesBySlug[columnName]?.slug ?? columnName,
|
|
1160
|
+
propertyType: typePropertiesBySlug[columnName]?.propertyType ?? 'number',
|
|
1161
|
+
message: `Column "${columnName}" contains values that exceed the configured precision of ${precision} decimal place${precision === 1 ? '' : 's'}. These values will be truncated when saved.`,
|
|
1162
|
+
affectedRows,
|
|
1163
|
+
}));
|
|
1164
|
+
}
|
|
1165
|
+
function generateUnmappedWarnings(columnAnalysis) {
|
|
1166
|
+
const issues = [];
|
|
1167
|
+
for (const col of columnAnalysis.columns) {
|
|
1168
|
+
if (!col.isMapped) {
|
|
1169
|
+
issues.push({
|
|
1170
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
1171
|
+
category: types_2.PreValidationCategory.UNMAPPED_COLUMN,
|
|
1172
|
+
columnName: col.csvHeader,
|
|
1173
|
+
propertySlug: '',
|
|
1174
|
+
propertyType: '',
|
|
1175
|
+
message: `CSV column '${col.csvHeader}' does not match any property on the type definition`,
|
|
1176
|
+
affectedRows: [],
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
for (const prop of columnAnalysis.unmappedTypeProperties) {
|
|
1181
|
+
issues.push({
|
|
1182
|
+
severity: types_2.PreValidationSeverity.WARNING,
|
|
1183
|
+
category: types_2.PreValidationCategory.UNMAPPED_TYPE_PROPERTY,
|
|
1184
|
+
columnName: '',
|
|
1185
|
+
propertySlug: prop.slug,
|
|
1186
|
+
propertyType: prop.propertyType ?? '',
|
|
1187
|
+
message: `Type property key '${prop.slug}' with label '${prop.label}' has no corresponding column in the CSV`,
|
|
1188
|
+
affectedRows: [],
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
return issues;
|
|
1192
|
+
}
|
|
1193
|
+
function buildResult(issues) {
|
|
1194
|
+
let errorCount = 0;
|
|
1195
|
+
let warningCount = 0;
|
|
1196
|
+
let infoCount = 0;
|
|
1197
|
+
const countsByCategory = {};
|
|
1198
|
+
for (const issue of issues) {
|
|
1199
|
+
if (issue.severity === types_2.PreValidationSeverity.ERROR)
|
|
1200
|
+
errorCount++;
|
|
1201
|
+
else if (issue.severity === types_2.PreValidationSeverity.WARNING)
|
|
1202
|
+
warningCount++;
|
|
1203
|
+
else
|
|
1204
|
+
infoCount++;
|
|
1205
|
+
countsByCategory[issue.category] = (countsByCategory[issue.category] || 0) + 1;
|
|
1206
|
+
}
|
|
1207
|
+
return {
|
|
1208
|
+
valid: errorCount === 0,
|
|
1209
|
+
issues,
|
|
1210
|
+
summary: {
|
|
1211
|
+
errorCount,
|
|
1212
|
+
warningCount,
|
|
1213
|
+
infoCount,
|
|
1214
|
+
countsByCategory,
|
|
1215
|
+
},
|
|
1216
|
+
};
|
|
1217
|
+
}
|