@ggts-sh/spec 0.43.0
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/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/artifact.d.ts +11 -0
- package/dist/artifact.d.ts.map +1 -0
- package/dist/artifact.js +71 -0
- package/dist/artifact.js.map +1 -0
- package/dist/builder-core.d.ts +100 -0
- package/dist/builder-core.d.ts.map +1 -0
- package/dist/builder-core.js +176 -0
- package/dist/builder-core.js.map +1 -0
- package/dist/builder-data.d.ts +36 -0
- package/dist/builder-data.d.ts.map +1 -0
- package/dist/builder-data.js +123 -0
- package/dist/builder-data.js.map +1 -0
- package/dist/builder-geoms.d.ts +128 -0
- package/dist/builder-geoms.d.ts.map +1 -0
- package/dist/builder-geoms.js +221 -0
- package/dist/builder-geoms.js.map +1 -0
- package/dist/builder-options.d.ts +323 -0
- package/dist/builder-options.d.ts.map +1 -0
- package/dist/builder-options.js +2 -0
- package/dist/builder-options.js.map +1 -0
- package/dist/builder-scales.d.ts +160 -0
- package/dist/builder-scales.d.ts.map +1 -0
- package/dist/builder-scales.js +322 -0
- package/dist/builder-scales.js.map +1 -0
- package/dist/builder.d.ts +242 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +42 -0
- package/dist/builder.js.map +1 -0
- package/dist/capabilities-data.d.ts +72 -0
- package/dist/capabilities-data.d.ts.map +1 -0
- package/dist/capabilities-data.js +337 -0
- package/dist/capabilities-data.js.map +1 -0
- package/dist/capabilities-helpers.d.ts +31 -0
- package/dist/capabilities-helpers.d.ts.map +1 -0
- package/dist/capabilities-helpers.js +41 -0
- package/dist/capabilities-helpers.js.map +1 -0
- package/dist/capabilities.d.ts +22 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +154 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/coord-helpers.d.ts +102 -0
- package/dist/coord-helpers.d.ts.map +1 -0
- package/dist/coord-helpers.js +90 -0
- package/dist/coord-helpers.js.map +1 -0
- package/dist/coord-reference-build.d.ts +50 -0
- package/dist/coord-reference-build.d.ts.map +1 -0
- package/dist/coord-reference-build.js +211 -0
- package/dist/coord-reference-build.js.map +1 -0
- package/dist/coord-reference.d.ts +52 -0
- package/dist/coord-reference.d.ts.map +1 -0
- package/dist/coord-reference.js +27 -0
- package/dist/coord-reference.js.map +1 -0
- package/dist/error-catalog.d.ts +258 -0
- package/dist/error-catalog.d.ts.map +1 -0
- package/dist/error-catalog.js +235 -0
- package/dist/error-catalog.js.map +1 -0
- package/dist/error-prose-shared.d.ts +100 -0
- package/dist/error-prose-shared.d.ts.map +1 -0
- package/dist/error-prose-shared.js +95 -0
- package/dist/error-prose-shared.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +52 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/coord-reference-data.d.ts +189 -0
- package/dist/generated/coord-reference-data.d.ts.map +1 -0
- package/dist/generated/coord-reference-data.js +212 -0
- package/dist/generated/coord-reference-data.js.map +1 -0
- package/dist/generated/geom-param-keys.d.ts +58 -0
- package/dist/generated/geom-param-keys.d.ts.map +1 -0
- package/dist/generated/geom-param-keys.js +223 -0
- package/dist/generated/geom-param-keys.js.map +1 -0
- package/dist/generated/geom-reference-data.d.ts +2377 -0
- package/dist/generated/geom-reference-data.d.ts.map +1 -0
- package/dist/generated/geom-reference-data.js +2790 -0
- package/dist/generated/geom-reference-data.js.map +1 -0
- package/dist/generated/guide-reference-data.d.ts +219 -0
- package/dist/generated/guide-reference-data.d.ts.map +1 -0
- package/dist/generated/guide-reference-data.js +253 -0
- package/dist/generated/guide-reference-data.js.map +1 -0
- package/dist/generated/plot-spec-validator.d.ts +2 -0
- package/dist/generated/plot-spec-validator.d.ts.map +1 -0
- package/dist/generated/plot-spec-validator.js +6274 -0
- package/dist/generated/plot-spec-validator.js.map +1 -0
- package/dist/generated/position-reference-data.d.ts +82 -0
- package/dist/generated/position-reference-data.d.ts.map +1 -0
- package/dist/generated/position-reference-data.js +181 -0
- package/dist/generated/position-reference-data.js.map +1 -0
- package/dist/generated/scale-reference-data.d.ts +8366 -0
- package/dist/generated/scale-reference-data.d.ts.map +1 -0
- package/dist/generated/scale-reference-data.js +9821 -0
- package/dist/generated/scale-reference-data.js.map +1 -0
- package/dist/generated/stat-reference-data.d.ts +241 -0
- package/dist/generated/stat-reference-data.d.ts.map +1 -0
- package/dist/generated/stat-reference-data.js +311 -0
- package/dist/generated/stat-reference-data.js.map +1 -0
- package/dist/geom-params-build.d.ts +3 -0
- package/dist/geom-params-build.d.ts.map +1 -0
- package/dist/geom-params-build.js +80 -0
- package/dist/geom-params-build.js.map +1 -0
- package/dist/geom-params.d.ts +13 -0
- package/dist/geom-params.d.ts.map +1 -0
- package/dist/geom-params.js +7 -0
- package/dist/geom-params.js.map +1 -0
- package/dist/geom-reference-build.d.ts +29 -0
- package/dist/geom-reference-build.d.ts.map +1 -0
- package/dist/geom-reference-build.js +221 -0
- package/dist/geom-reference-build.js.map +1 -0
- package/dist/geom-reference.d.ts +52 -0
- package/dist/geom-reference.d.ts.map +1 -0
- package/dist/geom-reference.js +72 -0
- package/dist/geom-reference.js.map +1 -0
- package/dist/guide-helpers.d.ts +20 -0
- package/dist/guide-helpers.d.ts.map +1 -0
- package/dist/guide-helpers.js +25 -0
- package/dist/guide-helpers.js.map +1 -0
- package/dist/guide-reference-build.d.ts +42 -0
- package/dist/guide-reference-build.d.ts.map +1 -0
- package/dist/guide-reference-build.js +180 -0
- package/dist/guide-reference-build.js.map +1 -0
- package/dist/guide-reference.d.ts +48 -0
- package/dist/guide-reference.d.ts.map +1 -0
- package/dist/guide-reference.js +32 -0
- package/dist/guide-reference.js.map +1 -0
- package/dist/hue-grey-palettes.d.ts +15 -0
- package/dist/hue-grey-palettes.d.ts.map +1 -0
- package/dist/hue-grey-palettes.js +77 -0
- package/dist/hue-grey-palettes.js.map +1 -0
- package/dist/index.d.ts +364 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +225 -0
- package/dist/index.js.map +1 -0
- package/dist/lint-catalog.d.ts +47 -0
- package/dist/lint-catalog.d.ts.map +1 -0
- package/dist/lint-catalog.js +39 -0
- package/dist/lint-catalog.js.map +1 -0
- package/dist/lint-layer-rules.d.ts +18 -0
- package/dist/lint-layer-rules.d.ts.map +1 -0
- package/dist/lint-layer-rules.js +145 -0
- package/dist/lint-layer-rules.js.map +1 -0
- package/dist/lint-scale-rules.d.ts +8 -0
- package/dist/lint-scale-rules.d.ts.map +1 -0
- package/dist/lint-scale-rules.js +254 -0
- package/dist/lint-scale-rules.js.map +1 -0
- package/dist/lint.d.ts +62 -0
- package/dist/lint.d.ts.map +1 -0
- package/dist/lint.js +57 -0
- package/dist/lint.js.map +1 -0
- package/dist/normalize-coord.d.ts +8 -0
- package/dist/normalize-coord.d.ts.map +1 -0
- package/dist/normalize-coord.js +123 -0
- package/dist/normalize-coord.js.map +1 -0
- package/dist/normalize-input-layers-marks.d.ts +208 -0
- package/dist/normalize-input-layers-marks.d.ts.map +1 -0
- package/dist/normalize-input-layers-marks.js +2 -0
- package/dist/normalize-input-layers-marks.js.map +1 -0
- package/dist/normalize-input-layers-special.d.ts +131 -0
- package/dist/normalize-input-layers-special.d.ts.map +1 -0
- package/dist/normalize-input-layers-special.js +2 -0
- package/dist/normalize-input-layers-special.js.map +1 -0
- package/dist/normalize-input.d.ts +81 -0
- package/dist/normalize-input.d.ts.map +1 -0
- package/dist/normalize-input.js +2 -0
- package/dist/normalize-input.js.map +1 -0
- package/dist/normalize-paint.d.ts +8 -0
- package/dist/normalize-paint.d.ts.map +1 -0
- package/dist/normalize-paint.js +83 -0
- package/dist/normalize-paint.js.map +1 -0
- package/dist/normalize-scales.d.ts +7 -0
- package/dist/normalize-scales.d.ts.map +1 -0
- package/dist/normalize-scales.js +90 -0
- package/dist/normalize-scales.js.map +1 -0
- package/dist/normalize.d.ts +46 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +279 -0
- package/dist/normalize.js.map +1 -0
- package/dist/paint-helpers.d.ts +45 -0
- package/dist/paint-helpers.d.ts.map +1 -0
- package/dist/paint-helpers.js +48 -0
- package/dist/paint-helpers.js.map +1 -0
- package/dist/pipeline-error-catalog.d.ts +319 -0
- package/dist/pipeline-error-catalog.d.ts.map +1 -0
- package/dist/pipeline-error-catalog.js +260 -0
- package/dist/pipeline-error-catalog.js.map +1 -0
- package/dist/portability-check.d.ts +35 -0
- package/dist/portability-check.d.ts.map +1 -0
- package/dist/portability-check.js +121 -0
- package/dist/portability-check.js.map +1 -0
- package/dist/portability-lossy.d.ts +19 -0
- package/dist/portability-lossy.d.ts.map +1 -0
- package/dist/portability-lossy.js +65 -0
- package/dist/portability-lossy.js.map +1 -0
- package/dist/portability.d.ts +23 -0
- package/dist/portability.d.ts.map +1 -0
- package/dist/portability.js +23 -0
- package/dist/portability.js.map +1 -0
- package/dist/portable-builder.d.ts +215 -0
- package/dist/portable-builder.d.ts.map +1 -0
- package/dist/portable-builder.js +27 -0
- package/dist/portable-builder.js.map +1 -0
- package/dist/portable-entry.d.ts +16 -0
- package/dist/portable-entry.d.ts.map +1 -0
- package/dist/portable-entry.js +14 -0
- package/dist/portable-entry.js.map +1 -0
- package/dist/position-reference-build.d.ts +29 -0
- package/dist/position-reference-build.d.ts.map +1 -0
- package/dist/position-reference-build.js +115 -0
- package/dist/position-reference-build.js.map +1 -0
- package/dist/position-reference.d.ts +34 -0
- package/dist/position-reference.d.ts.map +1 -0
- package/dist/position-reference.js +19 -0
- package/dist/position-reference.js.map +1 -0
- package/dist/runtime.d.ts +139 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scale-color-helpers.d.ts +121 -0
- package/dist/scale-color-helpers.d.ts.map +1 -0
- package/dist/scale-color-helpers.js +188 -0
- package/dist/scale-color-helpers.js.map +1 -0
- package/dist/scale-color-hue-grey.d.ts +52 -0
- package/dist/scale-color-hue-grey.d.ts.map +1 -0
- package/dist/scale-color-hue-grey.js +60 -0
- package/dist/scale-color-hue-grey.js.map +1 -0
- package/dist/scale-color-stops.d.ts +85 -0
- package/dist/scale-color-stops.d.ts.map +1 -0
- package/dist/scale-color-stops.js +87 -0
- package/dist/scale-color-stops.js.map +1 -0
- package/dist/scale-color-viridis.d.ts +52 -0
- package/dist/scale-color-viridis.d.ts.map +1 -0
- package/dist/scale-color-viridis.js +68 -0
- package/dist/scale-color-viridis.js.map +1 -0
- package/dist/scale-helpers.d.ts +20 -0
- package/dist/scale-helpers.d.ts.map +1 -0
- package/dist/scale-helpers.js +20 -0
- package/dist/scale-helpers.js.map +1 -0
- package/dist/scale-multi-helpers.d.ts +61 -0
- package/dist/scale-multi-helpers.d.ts.map +1 -0
- package/dist/scale-multi-helpers.js +147 -0
- package/dist/scale-multi-helpers.js.map +1 -0
- package/dist/scale-position-helpers.d.ts +81 -0
- package/dist/scale-position-helpers.d.ts.map +1 -0
- package/dist/scale-position-helpers.js +133 -0
- package/dist/scale-position-helpers.js.map +1 -0
- package/dist/scale-reference-build.d.ts +50 -0
- package/dist/scale-reference-build.d.ts.map +1 -0
- package/dist/scale-reference-build.js +147 -0
- package/dist/scale-reference-build.js.map +1 -0
- package/dist/scale-reference-classify-color.d.ts +11 -0
- package/dist/scale-reference-classify-color.d.ts.map +1 -0
- package/dist/scale-reference-classify-color.js +292 -0
- package/dist/scale-reference-classify-color.js.map +1 -0
- package/dist/scale-reference-classify-position.d.ts +10 -0
- package/dist/scale-reference-classify-position.d.ts.map +1 -0
- package/dist/scale-reference-classify-position.js +137 -0
- package/dist/scale-reference-classify-position.js.map +1 -0
- package/dist/scale-reference-classify-style.d.ts +10 -0
- package/dist/scale-reference-classify-style.d.ts.map +1 -0
- package/dist/scale-reference-classify-style.js +194 -0
- package/dist/scale-reference-classify-style.js.map +1 -0
- package/dist/scale-reference-classify-support.d.ts +37 -0
- package/dist/scale-reference-classify-support.d.ts.map +1 -0
- package/dist/scale-reference-classify-support.js +206 -0
- package/dist/scale-reference-classify-support.js.map +1 -0
- package/dist/scale-reference.d.ts +80 -0
- package/dist/scale-reference.d.ts.map +1 -0
- package/dist/scale-reference.js +85 -0
- package/dist/scale-reference.js.map +1 -0
- package/dist/scale-style-helpers.d.ts +158 -0
- package/dist/scale-style-helpers.d.ts.map +1 -0
- package/dist/scale-style-helpers.js +197 -0
- package/dist/scale-style-helpers.js.map +1 -0
- package/dist/schema-catalog.d.ts +62 -0
- package/dist/schema-catalog.d.ts.map +1 -0
- package/dist/schema-catalog.js +208 -0
- package/dist/schema-catalog.js.map +1 -0
- package/dist/schema-declarations.d.ts +1585 -0
- package/dist/schema-declarations.d.ts.map +1 -0
- package/dist/schema-declarations.js +51 -0
- package/dist/schema-declarations.js.map +1 -0
- package/dist/schema-decls-data.d.ts +58 -0
- package/dist/schema-decls-data.d.ts.map +1 -0
- package/dist/schema-decls-data.js +151 -0
- package/dist/schema-decls-data.js.map +1 -0
- package/dist/schema-decls-guides-theme.d.ts +166 -0
- package/dist/schema-decls-guides-theme.d.ts.map +1 -0
- package/dist/schema-decls-guides-theme.js +251 -0
- package/dist/schema-decls-guides-theme.js.map +1 -0
- package/dist/schema-decls-layers-col-boxplot.d.ts +118 -0
- package/dist/schema-decls-layers-col-boxplot.d.ts.map +1 -0
- package/dist/schema-decls-layers-col-boxplot.js +239 -0
- package/dist/schema-decls-layers-col-boxplot.js.map +1 -0
- package/dist/schema-decls-layers-count-pointrange.d.ts +89 -0
- package/dist/schema-decls-layers-count-pointrange.d.ts.map +1 -0
- package/dist/schema-decls-layers-count-pointrange.js +190 -0
- package/dist/schema-decls-layers-count-pointrange.js.map +1 -0
- package/dist/schema-decls-layers-crossbar-jitter.d.ts +129 -0
- package/dist/schema-decls-layers-crossbar-jitter.d.ts.map +1 -0
- package/dist/schema-decls-layers-crossbar-jitter.js +255 -0
- package/dist/schema-decls-layers-crossbar-jitter.js.map +1 -0
- package/dist/schema-decls-layers-point-path.d.ts +49 -0
- package/dist/schema-decls-layers-point-path.d.ts.map +1 -0
- package/dist/schema-decls-layers-point-path.js +156 -0
- package/dist/schema-decls-layers-point-path.js.map +1 -0
- package/dist/schema-decls-layers-sf-blank.d.ts +89 -0
- package/dist/schema-decls-layers-sf-blank.d.ts.map +1 -0
- package/dist/schema-decls-layers-sf-blank.js +254 -0
- package/dist/schema-decls-layers-sf-blank.js.map +1 -0
- package/dist/schema-decls-layers-text-map.d.ts +80 -0
- package/dist/schema-decls-layers-text-map.d.ts.map +1 -0
- package/dist/schema-decls-layers-text-map.js +151 -0
- package/dist/schema-decls-layers-text-map.js.map +1 -0
- package/dist/schema-decls-paint.d.ts +39 -0
- package/dist/schema-decls-paint.d.ts.map +1 -0
- package/dist/schema-decls-paint.js +95 -0
- package/dist/schema-decls-paint.js.map +1 -0
- package/dist/schema-decls-params-area-abline.d.ts +85 -0
- package/dist/schema-decls-params-area-abline.d.ts.map +1 -0
- package/dist/schema-decls-params-area-abline.js +259 -0
- package/dist/schema-decls-params-area-abline.js.map +1 -0
- package/dist/schema-decls-params-col-contour.d.ts +61 -0
- package/dist/schema-decls-params-col-contour.d.ts.map +1 -0
- package/dist/schema-decls-params-col-contour.js +202 -0
- package/dist/schema-decls-params-col-contour.js.map +1 -0
- package/dist/schema-decls-params-curve-label.d.ts +64 -0
- package/dist/schema-decls-params-curve-label.d.ts.map +1 -0
- package/dist/schema-decls-params-curve-label.js +204 -0
- package/dist/schema-decls-params-curve-label.js.map +1 -0
- package/dist/schema-decls-params-errorbar-position.d.ts +83 -0
- package/dist/schema-decls-params-errorbar-position.d.ts.map +1 -0
- package/dist/schema-decls-params-errorbar-position.js +264 -0
- package/dist/schema-decls-params-errorbar-position.js.map +1 -0
- package/dist/schema-decls-params-point-path.d.ts +61 -0
- package/dist/schema-decls-params-point-path.d.ts.map +1 -0
- package/dist/schema-decls-params-point-path.js +240 -0
- package/dist/schema-decls-params-point-path.js.map +1 -0
- package/dist/schema-decls-params-violin-summary.d.ts +78 -0
- package/dist/schema-decls-params-violin-summary.d.ts.map +1 -0
- package/dist/schema-decls-params-violin-summary.js +272 -0
- package/dist/schema-decls-params-violin-summary.js.map +1 -0
- package/dist/schema-decls-plot.d.ts +80 -0
- package/dist/schema-decls-plot.d.ts.map +1 -0
- package/dist/schema-decls-plot.js +222 -0
- package/dist/schema-decls-plot.js.map +1 -0
- package/dist/schema-decls-scales-guides.d.ts +291 -0
- package/dist/schema-decls-scales-guides.d.ts.map +1 -0
- package/dist/schema-decls-scales-guides.js +189 -0
- package/dist/schema-decls-scales-guides.js.map +1 -0
- package/dist/schema-decls-scales.d.ts +124 -0
- package/dist/schema-decls-scales.d.ts.map +1 -0
- package/dist/schema-decls-scales.js +279 -0
- package/dist/schema-decls-scales.js.map +1 -0
- package/dist/schema-imports.d.ts +1679 -0
- package/dist/schema-imports.d.ts.map +1 -0
- package/dist/schema-imports.js +104 -0
- package/dist/schema-imports.js.map +1 -0
- package/dist/schema-name-schemas.d.ts +18 -0
- package/dist/schema-name-schemas.d.ts.map +1 -0
- package/dist/schema-name-schemas.js +13 -0
- package/dist/schema-name-schemas.js.map +1 -0
- package/dist/schema-names.d.ts +53 -0
- package/dist/schema-names.d.ts.map +1 -0
- package/dist/schema-names.js +229 -0
- package/dist/schema-names.js.map +1 -0
- package/dist/schema-types.d.ts +336 -0
- package/dist/schema-types.d.ts.map +1 -0
- package/dist/schema-types.js +10 -0
- package/dist/schema-types.js.map +1 -0
- package/dist/schema.d.ts +38 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +34 -0
- package/dist/schema.js.map +1 -0
- package/dist/stat-reference-build.d.ts +24 -0
- package/dist/stat-reference-build.d.ts.map +1 -0
- package/dist/stat-reference-build.js +86 -0
- package/dist/stat-reference-build.js.map +1 -0
- package/dist/stat-reference.d.ts +33 -0
- package/dist/stat-reference.d.ts.map +1 -0
- package/dist/stat-reference.js +19 -0
- package/dist/stat-reference.js.map +1 -0
- package/dist/structural-gate.d.ts +15 -0
- package/dist/structural-gate.d.ts.map +1 -0
- package/dist/structural-gate.js +34 -0
- package/dist/structural-gate.js.map +1 -0
- package/dist/temporal-column.d.ts +33 -0
- package/dist/temporal-column.d.ts.map +1 -0
- package/dist/temporal-column.js +247 -0
- package/dist/temporal-column.js.map +1 -0
- package/dist/temporal-guides.d.ts +11 -0
- package/dist/temporal-guides.d.ts.map +1 -0
- package/dist/temporal-guides.js +11 -0
- package/dist/temporal-guides.js.map +1 -0
- package/dist/temporal-interval-schema.d.ts +9 -0
- package/dist/temporal-interval-schema.d.ts.map +1 -0
- package/dist/temporal-interval-schema.js +25 -0
- package/dist/temporal-interval-schema.js.map +1 -0
- package/dist/temporal-interval.d.ts +29 -0
- package/dist/temporal-interval.d.ts.map +1 -0
- package/dist/temporal-interval.js +122 -0
- package/dist/temporal-interval.js.map +1 -0
- package/dist/temporal-parse-core.d.ts +96 -0
- package/dist/temporal-parse-core.d.ts.map +1 -0
- package/dist/temporal-parse-core.js +235 -0
- package/dist/temporal-parse-core.js.map +1 -0
- package/dist/temporal-parse-format.d.ts +13 -0
- package/dist/temporal-parse-format.d.ts.map +1 -0
- package/dist/temporal-parse-format.js +180 -0
- package/dist/temporal-parse-format.js.map +1 -0
- package/dist/temporal-parse-schema.d.ts +11 -0
- package/dist/temporal-parse-schema.d.ts.map +1 -0
- package/dist/temporal-parse-schema.js +23 -0
- package/dist/temporal-parse-schema.js.map +1 -0
- package/dist/temporal-parse.d.ts +18 -0
- package/dist/temporal-parse.d.ts.map +1 -0
- package/dist/temporal-parse.js +183 -0
- package/dist/temporal-parse.js.map +1 -0
- package/dist/temporal-polyfill.d.ts +3 -0
- package/dist/temporal-polyfill.d.ts.map +1 -0
- package/dist/temporal-polyfill.js +25 -0
- package/dist/temporal-polyfill.js.map +1 -0
- package/dist/temporal-ticks.d.ts +20 -0
- package/dist/temporal-ticks.d.ts.map +1 -0
- package/dist/temporal-ticks.js +246 -0
- package/dist/temporal-ticks.js.map +1 -0
- package/dist/temporal.d.ts +109 -0
- package/dist/temporal.d.ts.map +1 -0
- package/dist/temporal.js +73 -0
- package/dist/temporal.js.map +1 -0
- package/dist/validate-data-checks-color-temporal.d.ts +58 -0
- package/dist/validate-data-checks-color-temporal.d.ts.map +1 -0
- package/dist/validate-data-checks-color-temporal.js +168 -0
- package/dist/validate-data-checks-color-temporal.js.map +1 -0
- package/dist/validate-data-checks-color.d.ts +28 -0
- package/dist/validate-data-checks-color.d.ts.map +1 -0
- package/dist/validate-data-checks-color.js +296 -0
- package/dist/validate-data-checks-color.js.map +1 -0
- package/dist/validate-data-checks-layer.d.ts +37 -0
- package/dist/validate-data-checks-layer.d.ts.map +1 -0
- package/dist/validate-data-checks-layer.js +343 -0
- package/dist/validate-data-checks-layer.js.map +1 -0
- package/dist/validate-data-checks-position.d.ts +45 -0
- package/dist/validate-data-checks-position.d.ts.map +1 -0
- package/dist/validate-data-checks-position.js +204 -0
- package/dist/validate-data-checks-position.js.map +1 -0
- package/dist/validate-data-checks-style-finite.d.ts +24 -0
- package/dist/validate-data-checks-style-finite.d.ts.map +1 -0
- package/dist/validate-data-checks-style-finite.js +40 -0
- package/dist/validate-data-checks-style-finite.js.map +1 -0
- package/dist/validate-data-checks-style-numeric.d.ts +26 -0
- package/dist/validate-data-checks-style-numeric.d.ts.map +1 -0
- package/dist/validate-data-checks-style-numeric.js +327 -0
- package/dist/validate-data-checks-style-numeric.js.map +1 -0
- package/dist/validate-data-checks-style.d.ts +14 -0
- package/dist/validate-data-checks-style.d.ts.map +1 -0
- package/dist/validate-data-checks-style.js +14 -0
- package/dist/validate-data-checks-style.js.map +1 -0
- package/dist/validate-data-checks-temporal.d.ts +57 -0
- package/dist/validate-data-checks-temporal.d.ts.map +1 -0
- package/dist/validate-data-checks-temporal.js +83 -0
- package/dist/validate-data-checks-temporal.js.map +1 -0
- package/dist/validate-data-checks.d.ts +31 -0
- package/dist/validate-data-checks.d.ts.map +1 -0
- package/dist/validate-data-checks.js +110 -0
- package/dist/validate-data-checks.js.map +1 -0
- package/dist/validate-data-evidence.d.ts +69 -0
- package/dist/validate-data-evidence.d.ts.map +1 -0
- package/dist/validate-data-evidence.js +329 -0
- package/dist/validate-data-evidence.js.map +1 -0
- package/dist/validate-data.d.ts +73 -0
- package/dist/validate-data.d.ts.map +1 -0
- package/dist/validate-data.js +30 -0
- package/dist/validate-data.js.map +1 -0
- package/dist/validate-map-errors.d.ts +32 -0
- package/dist/validate-map-errors.d.ts.map +1 -0
- package/dist/validate-map-errors.js +76 -0
- package/dist/validate-map-errors.js.map +1 -0
- package/dist/validate-map-forms.d.ts +43 -0
- package/dist/validate-map-forms.d.ts.map +1 -0
- package/dist/validate-map-forms.js +125 -0
- package/dist/validate-map-forms.js.map +1 -0
- package/dist/validate-map-path-keywords.d.ts +11 -0
- package/dist/validate-map-path-keywords.d.ts.map +1 -0
- package/dist/validate-map-path-keywords.js +95 -0
- package/dist/validate-map-path-keywords.js.map +1 -0
- package/dist/validate-map-path-unions.d.ts +27 -0
- package/dist/validate-map-path-unions.d.ts.map +1 -0
- package/dist/validate-map-path-unions.js +200 -0
- package/dist/validate-map-path-unions.js.map +1 -0
- package/dist/validate-schema-shape.d.ts +69 -0
- package/dist/validate-schema-shape.d.ts.map +1 -0
- package/dist/validate-schema-shape.js +156 -0
- package/dist/validate-schema-shape.js.map +1 -0
- package/dist/validate-schema-walk.d.ts +34 -0
- package/dist/validate-schema-walk.d.ts.map +1 -0
- package/dist/validate-schema-walk.js +216 -0
- package/dist/validate-schema-walk.js.map +1 -0
- package/dist/validate-structure-facet.d.ts +8 -0
- package/dist/validate-structure-facet.d.ts.map +1 -0
- package/dist/validate-structure-facet.js +67 -0
- package/dist/validate-structure-facet.js.map +1 -0
- package/dist/validate-structure-layer-computed-y.d.ts +14 -0
- package/dist/validate-structure-layer-computed-y.d.ts.map +1 -0
- package/dist/validate-structure-layer-computed-y.js +70 -0
- package/dist/validate-structure-layer-computed-y.js.map +1 -0
- package/dist/validate-structure-layer-ribbon.d.ts +8 -0
- package/dist/validate-structure-layer-ribbon.d.ts.map +1 -0
- package/dist/validate-structure-layer-ribbon.js +36 -0
- package/dist/validate-structure-layer-ribbon.js.map +1 -0
- package/dist/validate-structure-layer-rule.d.ts +14 -0
- package/dist/validate-structure-layer-rule.d.ts.map +1 -0
- package/dist/validate-structure-layer-rule.js +90 -0
- package/dist/validate-structure-layer-rule.js.map +1 -0
- package/dist/validate-structure-layer-shared.d.ts +12 -0
- package/dist/validate-structure-layer-shared.d.ts.map +1 -0
- package/dist/validate-structure-layer-shared.js +17 -0
- package/dist/validate-structure-layer-shared.js.map +1 -0
- package/dist/validate-structure-layers.d.ts +12 -0
- package/dist/validate-structure-layers.d.ts.map +1 -0
- package/dist/validate-structure-layers.js +292 -0
- package/dist/validate-structure-layers.js.map +1 -0
- package/dist/validate-structure-paint.d.ts +12 -0
- package/dist/validate-structure-paint.d.ts.map +1 -0
- package/dist/validate-structure-paint.js +87 -0
- package/dist/validate-structure-paint.js.map +1 -0
- package/dist/validate-structure-scales.d.ts +10 -0
- package/dist/validate-structure-scales.d.ts.map +1 -0
- package/dist/validate-structure-scales.js +242 -0
- package/dist/validate-structure-scales.js.map +1 -0
- package/dist/validate-structure-style-bins.d.ts +17 -0
- package/dist/validate-structure-style-bins.d.ts.map +1 -0
- package/dist/validate-structure-style-bins.js +150 -0
- package/dist/validate-structure-style-bins.js.map +1 -0
- package/dist/validate-structure.d.ts +16 -0
- package/dist/validate-structure.d.ts.map +1 -0
- package/dist/validate-structure.js +16 -0
- package/dist/validate-structure.js.map +1 -0
- package/dist/validate.d.ts +24 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +178 -0
- package/dist/validate.js.map +1 -0
- package/package.json +59 -0
- package/schema/v0.json +9618 -0
- package/src/artifact.ts +81 -0
- package/src/builder-core.ts +276 -0
- package/src/builder-data.ts +156 -0
- package/src/builder-geoms.ts +290 -0
- package/src/builder-options.ts +428 -0
- package/src/builder-scales.ts +443 -0
- package/src/builder.ts +125 -0
- package/src/capabilities-data.ts +336 -0
- package/src/capabilities-helpers.ts +54 -0
- package/src/capabilities.ts +159 -0
- package/src/coord-helpers.ts +177 -0
- package/src/coord-reference-build.ts +283 -0
- package/src/coord-reference.ts +75 -0
- package/src/error-catalog.ts +253 -0
- package/src/error-prose-shared.ts +106 -0
- package/src/errors.ts +87 -0
- package/src/generated/coord-reference-data.ts +235 -0
- package/src/generated/geom-param-keys.ts +222 -0
- package/src/generated/geom-reference-data.ts +3024 -0
- package/src/generated/guide-reference-data.ts +284 -0
- package/src/generated/plot-spec-validator.ts +7335 -0
- package/src/generated/position-reference-data.ts +191 -0
- package/src/generated/scale-reference-data.ts +10665 -0
- package/src/generated/stat-reference-data.ts +339 -0
- package/src/geom-params-build.ts +92 -0
- package/src/geom-params.ts +14 -0
- package/src/geom-reference-build.ts +292 -0
- package/src/geom-reference.ts +127 -0
- package/src/guide-helpers.ts +44 -0
- package/src/guide-reference-build.ts +249 -0
- package/src/guide-reference.ts +76 -0
- package/src/hue-grey-palettes.ts +82 -0
- package/src/index.ts +400 -0
- package/src/lint-catalog.ts +57 -0
- package/src/lint-layer-rules.ts +175 -0
- package/src/lint-scale-rules.ts +285 -0
- package/src/lint.ts +126 -0
- package/src/normalize-coord.ts +126 -0
- package/src/normalize-input-layers-marks.ts +276 -0
- package/src/normalize-input-layers-special.ts +252 -0
- package/src/normalize-input.ts +154 -0
- package/src/normalize-paint.ts +98 -0
- package/src/normalize-scales.ts +108 -0
- package/src/normalize.ts +403 -0
- package/src/paint-helpers.ts +98 -0
- package/src/pipeline-error-catalog.ts +278 -0
- package/src/portability-check.ts +155 -0
- package/src/portability-lossy.ts +81 -0
- package/src/portability.ts +31 -0
- package/src/portable-builder.ts +35 -0
- package/src/portable-entry.ts +37 -0
- package/src/position-reference-build.ts +164 -0
- package/src/position-reference.ts +41 -0
- package/src/runtime.ts +198 -0
- package/src/scale-color-helpers.ts +263 -0
- package/src/scale-color-hue-grey.ts +95 -0
- package/src/scale-color-stops.ts +177 -0
- package/src/scale-color-viridis.ts +99 -0
- package/src/scale-helpers.ts +264 -0
- package/src/scale-multi-helpers.ts +220 -0
- package/src/scale-position-helpers.ts +231 -0
- package/src/scale-reference-build.ts +222 -0
- package/src/scale-reference-classify-color.ts +334 -0
- package/src/scale-reference-classify-position.ts +164 -0
- package/src/scale-reference-classify-style.ts +229 -0
- package/src/scale-reference-classify-support.ts +298 -0
- package/src/scale-reference.ts +165 -0
- package/src/scale-style-helpers.ts +316 -0
- package/src/schema-catalog.ts +222 -0
- package/src/schema-declarations.ts +51 -0
- package/src/schema-decls-data.ts +272 -0
- package/src/schema-decls-guides-theme.ts +395 -0
- package/src/schema-decls-layers-col-boxplot.ts +410 -0
- package/src/schema-decls-layers-count-pointrange.ts +321 -0
- package/src/schema-decls-layers-crossbar-jitter.ts +443 -0
- package/src/schema-decls-layers-point-path.ts +246 -0
- package/src/schema-decls-layers-sf-blank.ts +408 -0
- package/src/schema-decls-layers-text-map.ts +259 -0
- package/src/schema-decls-paint.ts +124 -0
- package/src/schema-decls-params-area-abline.ts +440 -0
- package/src/schema-decls-params-col-contour.ts +333 -0
- package/src/schema-decls-params-curve-label.ts +343 -0
- package/src/schema-decls-params-errorbar-position.ts +446 -0
- package/src/schema-decls-params-point-path.ts +394 -0
- package/src/schema-decls-params-violin-summary.ts +447 -0
- package/src/schema-decls-plot.ts +385 -0
- package/src/schema-decls-scales-guides.ts +233 -0
- package/src/schema-decls-scales.ts +432 -0
- package/src/schema-imports.ts +116 -0
- package/src/schema-name-schemas.ts +37 -0
- package/src/schema-names.ts +243 -0
- package/src/schema-types.ts +400 -0
- package/src/schema.ts +287 -0
- package/src/stat-reference-build.ts +145 -0
- package/src/stat-reference.ts +38 -0
- package/src/structural-gate.ts +42 -0
- package/src/temporal-column.ts +323 -0
- package/src/temporal-guides.ts +32 -0
- package/src/temporal-interval-schema.ts +40 -0
- package/src/temporal-interval.ts +151 -0
- package/src/temporal-parse-core.ts +331 -0
- package/src/temporal-parse-format.ts +222 -0
- package/src/temporal-parse-schema.ts +38 -0
- package/src/temporal-parse.ts +259 -0
- package/src/temporal-polyfill.ts +27 -0
- package/src/temporal-ticks.ts +312 -0
- package/src/temporal.ts +112 -0
- package/src/validate-data-checks-color-temporal.ts +261 -0
- package/src/validate-data-checks-color.ts +395 -0
- package/src/validate-data-checks-layer.ts +492 -0
- package/src/validate-data-checks-position.ts +275 -0
- package/src/validate-data-checks-style-finite.ts +55 -0
- package/src/validate-data-checks-style-numeric.ts +455 -0
- package/src/validate-data-checks-style.ts +13 -0
- package/src/validate-data-checks-temporal.ts +129 -0
- package/src/validate-data-checks.ts +157 -0
- package/src/validate-data-evidence.ts +419 -0
- package/src/validate-data.ts +114 -0
- package/src/validate-map-errors.ts +126 -0
- package/src/validate-map-forms.ts +148 -0
- package/src/validate-map-path-keywords.ts +129 -0
- package/src/validate-map-path-unions.ts +281 -0
- package/src/validate-schema-shape.ts +232 -0
- package/src/validate-schema-walk.ts +219 -0
- package/src/validate-structure-facet.ts +76 -0
- package/src/validate-structure-layer-computed-y.ts +94 -0
- package/src/validate-structure-layer-ribbon.ts +61 -0
- package/src/validate-structure-layer-rule.ts +98 -0
- package/src/validate-structure-layer-shared.ts +29 -0
- package/src/validate-structure-layers.ts +395 -0
- package/src/validate-structure-paint.ts +101 -0
- package/src/validate-structure-scales.ts +278 -0
- package/src/validate-structure-style-bins.ts +167 -0
- package/src/validate-structure.ts +16 -0
- package/src/validate.ts +212 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-free structural checks for named color/fill schemes vs scale family.
|
|
3
|
+
* Layer grammar: validate-structure-layers.ts (+ layer-rule/ribbon/computed-y). Facet: validate-structure-facet.ts.
|
|
4
|
+
*/
|
|
5
|
+
import type { SpecError } from "./errors.js";
|
|
6
|
+
import {
|
|
7
|
+
CATEGORICAL_SCHEME_NAMES,
|
|
8
|
+
CYCLIC_SCHEME_NAMES,
|
|
9
|
+
SEQUENTIAL_SCHEME_NAMES,
|
|
10
|
+
} from "./schema-names.js";
|
|
11
|
+
|
|
12
|
+
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
13
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const CATEGORICAL_SCHEMES = new Set<string>(CATEGORICAL_SCHEME_NAMES);
|
|
17
|
+
const SEQUENTIAL_SCHEMES = new Set<string>(SEQUENTIAL_SCHEME_NAMES);
|
|
18
|
+
const CYCLIC_SCHEMES = new Set<string>(CYCLIC_SCHEME_NAMES);
|
|
19
|
+
|
|
20
|
+
/** Named color schemes must match the configured color scale family. */
|
|
21
|
+
const GUIDE_AESTHETICS = [
|
|
22
|
+
"x",
|
|
23
|
+
"y",
|
|
24
|
+
"color",
|
|
25
|
+
"fill",
|
|
26
|
+
"size",
|
|
27
|
+
"linewidth",
|
|
28
|
+
"alpha",
|
|
29
|
+
"shape",
|
|
30
|
+
"linetype",
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
/** Guide variants are constrained by aesthetic and explicit scale family. */
|
|
34
|
+
export function guideStructuralErrors(
|
|
35
|
+
guides: Record<string, unknown>,
|
|
36
|
+
scales: Record<string, unknown> | undefined,
|
|
37
|
+
): SpecError[] {
|
|
38
|
+
const errors: SpecError[] = [];
|
|
39
|
+
const check = (aesthetic: (typeof GUIDE_AESTHETICS)[number], guide: unknown, path: string) => {
|
|
40
|
+
if (!isRecord(guide) || typeof guide["type"] !== "string") return;
|
|
41
|
+
const type = guide["type"];
|
|
42
|
+
if (type === "none") return;
|
|
43
|
+
const scale = isRecord(scales?.[aesthetic]) ? scales?.[aesthetic] : undefined;
|
|
44
|
+
const scaleType = scale?.["type"];
|
|
45
|
+
if (guideIsValid(aesthetic, type, scaleType)) return;
|
|
46
|
+
errors.push({
|
|
47
|
+
code: "guide-aesthetic-incompatible",
|
|
48
|
+
path,
|
|
49
|
+
message: `The ${type} guide is incompatible with the ${aesthetic} aesthetic${typeof scaleType === "string" ? ` using a ${scaleType} scale` : ""}.`,
|
|
50
|
+
fix: {
|
|
51
|
+
description: guideFixDescription(aesthetic),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
for (const aesthetic of GUIDE_AESTHETICS) {
|
|
56
|
+
const top = guides[aesthetic];
|
|
57
|
+
check(aesthetic, top, `/guides/${aesthetic}`);
|
|
58
|
+
const scale = scales?.[aesthetic];
|
|
59
|
+
if (top === undefined && isRecord(scale))
|
|
60
|
+
check(aesthetic, scale["guide"], `/scales/${aesthetic}/guide`);
|
|
61
|
+
}
|
|
62
|
+
return errors;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function guideIsValid(aesthetic: string, type: string, scaleType: unknown): boolean {
|
|
66
|
+
if (aesthetic === "x" || aesthetic === "y") return type === "axis";
|
|
67
|
+
if (aesthetic !== "color" && aesthetic !== "fill") return type === "legend";
|
|
68
|
+
if (type === "legend") return scaleType !== "sequential" && scaleType !== "binned";
|
|
69
|
+
if (type === "colorbar") return scaleType === undefined || scaleType === "sequential";
|
|
70
|
+
return type === "colorsteps" && scaleType === "binned";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function guideFixDescription(aesthetic: string): string {
|
|
74
|
+
if (aesthetic === "x" || aesthetic === "y") {
|
|
75
|
+
return 'Use { type: "axis" } or { type: "none" } for positional aesthetics.';
|
|
76
|
+
}
|
|
77
|
+
if (aesthetic === "color" || aesthetic === "fill") {
|
|
78
|
+
return "Use legend for discrete colors, colorbar for sequential colors, colorsteps for binned colors, or none.";
|
|
79
|
+
}
|
|
80
|
+
return 'Use { type: "legend" } or { type: "none" } for mapped style aesthetics.';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Named color schemes must match the configured color scale family. */
|
|
84
|
+
export function colorScaleStructuralErrors(scales: Record<string, unknown>): SpecError[] {
|
|
85
|
+
const errors: SpecError[] = [];
|
|
86
|
+
for (const channel of ["color", "fill"] as const) {
|
|
87
|
+
const scale = scales[channel];
|
|
88
|
+
if (!isRecord(scale)) continue;
|
|
89
|
+
const type = scale["type"];
|
|
90
|
+
const scheme = scale["scheme"];
|
|
91
|
+
addBasicColorScaleErrors(errors, scale, channel, type);
|
|
92
|
+
|
|
93
|
+
addCyclicScaleErrors(errors, scale, channel, type, scheme);
|
|
94
|
+
|
|
95
|
+
if (
|
|
96
|
+
(type === "sequential" || type === "binned") &&
|
|
97
|
+
typeof scheme === "string" &&
|
|
98
|
+
CATEGORICAL_SCHEMES.has(scheme)
|
|
99
|
+
) {
|
|
100
|
+
errors.push({
|
|
101
|
+
code: "scale-scheme-type",
|
|
102
|
+
path: `/scales/${channel}/scheme`,
|
|
103
|
+
message: `The categorical scheme "${scheme}" cannot be used with a ${type} color scale.`,
|
|
104
|
+
fix: {
|
|
105
|
+
description: 'Use "viridis" or provide a sequential range of #rgb/#rrggbb stops.',
|
|
106
|
+
example: "viridis",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
} else if (type === "manual" && typeof scheme === "string" && SEQUENTIAL_SCHEMES.has(scheme)) {
|
|
110
|
+
// Ordinal may use sequential-family schemes (scale_*_viridis_d samples the
|
|
111
|
+
// ramp across the trained domain). Manual still rejects named schemes.
|
|
112
|
+
errors.push({
|
|
113
|
+
code: "scale-scheme-type",
|
|
114
|
+
path: `/scales/${channel}/scheme`,
|
|
115
|
+
message: `The sequential scheme "${scheme}" cannot be used with a manual color scale.`,
|
|
116
|
+
fix: {
|
|
117
|
+
description: "Use a categorical scheme or provide an ordinal range of CSS colors.",
|
|
118
|
+
example: "observable10",
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const transform = scale["transform"];
|
|
124
|
+
const temporal = scale["temporalKind"] !== undefined || scale["parse"] !== undefined;
|
|
125
|
+
const describedType = typeof type === "string" ? type : "inferred";
|
|
126
|
+
if (
|
|
127
|
+
typeof transform === "string" &&
|
|
128
|
+
transform !== "identity" &&
|
|
129
|
+
(temporal || type === "ordinal" || type === "manual" || type === "identity")
|
|
130
|
+
) {
|
|
131
|
+
errors.push({
|
|
132
|
+
code: "scale-type-transform-conflict",
|
|
133
|
+
path: `/scales/${channel}/transform`,
|
|
134
|
+
message: `The ${describedType} ${channel} scale cannot apply the ${transform} transform${temporal ? " to temporal values" : ""}.`,
|
|
135
|
+
fix: {
|
|
136
|
+
description:
|
|
137
|
+
"Remove the transform, or use a non-temporal sequential/binned quantitative scale.",
|
|
138
|
+
example: "identity",
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
addColorRangeErrors(errors, scale, channel, type);
|
|
144
|
+
}
|
|
145
|
+
return errors;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function addBasicColorScaleErrors(
|
|
149
|
+
errors: SpecError[],
|
|
150
|
+
scale: Record<string, unknown>,
|
|
151
|
+
channel: "color" | "fill",
|
|
152
|
+
type: unknown,
|
|
153
|
+
): void {
|
|
154
|
+
if ("range" in scale && scale["range"] !== undefined && !Array.isArray(scale["range"])) {
|
|
155
|
+
errors.push({
|
|
156
|
+
code: "invalid-type",
|
|
157
|
+
path: `/scales/${channel}/range`,
|
|
158
|
+
message: `scales.${channel}.range must be an array of colors (got ${typeof scale["range"]}).`,
|
|
159
|
+
fix: {
|
|
160
|
+
description: "Provide range as a JSON array of #rgb/#rrggbb colors.",
|
|
161
|
+
example: ["#f00", "#0f0", "#00f"],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (type === "binned" && scale["oob"] === "wrap") {
|
|
166
|
+
errors.push({
|
|
167
|
+
code: "scale-scheme-oob",
|
|
168
|
+
path: `/scales/${channel}/oob`,
|
|
169
|
+
message: `The binned ${channel} scale cannot use wrap out-of-bounds.`,
|
|
170
|
+
fix: {
|
|
171
|
+
description: 'Use "censor" or "squish" on binned color scales.',
|
|
172
|
+
example: "censor",
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function addCyclicScaleErrors(
|
|
179
|
+
errors: SpecError[],
|
|
180
|
+
scale: Record<string, unknown>,
|
|
181
|
+
channel: "color" | "fill",
|
|
182
|
+
type: unknown,
|
|
183
|
+
scheme: unknown,
|
|
184
|
+
): void {
|
|
185
|
+
if (typeof scheme !== "string" || !CYCLIC_SCHEMES.has(scheme)) return;
|
|
186
|
+
if (type !== undefined && type !== "sequential") {
|
|
187
|
+
const typeLabel = typeof type === "string" ? type : "this";
|
|
188
|
+
errors.push({
|
|
189
|
+
code: "scale-scheme-type",
|
|
190
|
+
path: `/scales/${channel}/scheme`,
|
|
191
|
+
message: `The cyclic scheme "${scheme}" cannot be used with a ${typeLabel} color scale.`,
|
|
192
|
+
fix: {
|
|
193
|
+
description: 'Use type "sequential" with an explicit domain period and oob "wrap".',
|
|
194
|
+
example: "sequential",
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (scale["oob"] === "censor" || scale["oob"] === "squish") {
|
|
199
|
+
errors.push({
|
|
200
|
+
code: "scale-scheme-oob",
|
|
201
|
+
path: `/scales/${channel}/oob`,
|
|
202
|
+
message: `The cyclic scheme "${scheme}" requires wrap out-of-bounds.`,
|
|
203
|
+
fix: {
|
|
204
|
+
description: 'Set oob to "wrap", or omit it (cyclic schemes default to wrap).',
|
|
205
|
+
example: "wrap",
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (!Array.isArray(scale["domain"]) || scale["domain"].length !== 2) {
|
|
210
|
+
errors.push({
|
|
211
|
+
code: "scale-cyclic-domain",
|
|
212
|
+
path: `/scales/${channel}/domain`,
|
|
213
|
+
message: `The cyclic scheme "${scheme}" requires an explicit two-value domain period.`,
|
|
214
|
+
fix: {
|
|
215
|
+
description: "Set domain to one period, for example [0, 360] for degrees.",
|
|
216
|
+
example: [0, 360],
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (scale["range"] !== undefined) {
|
|
221
|
+
errors.push({
|
|
222
|
+
code: "scale-scheme-type",
|
|
223
|
+
path: `/scales/${channel}/range`,
|
|
224
|
+
message: `The cyclic scheme "${scheme}" cannot be combined with an explicit range.`,
|
|
225
|
+
fix: { description: "Remove range and keep the named cyclic scheme, or drop the scheme." },
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
const transform = scale["transform"];
|
|
229
|
+
const temporal = scale["temporalKind"] !== undefined || scale["parse"] !== undefined;
|
|
230
|
+
if ((typeof transform === "string" && transform !== "identity") || temporal) {
|
|
231
|
+
errors.push({
|
|
232
|
+
code: "scale-type-transform-conflict",
|
|
233
|
+
path: `/scales/${channel}/transform`,
|
|
234
|
+
message: `The cyclic scheme "${scheme}" cannot apply a transform or temporal parser.`,
|
|
235
|
+
fix: {
|
|
236
|
+
description: "Remove transform and temporal options. Wrap in semantic space only.",
|
|
237
|
+
example: "identity",
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function addColorRangeErrors(
|
|
244
|
+
errors: SpecError[],
|
|
245
|
+
scale: Record<string, unknown>,
|
|
246
|
+
channel: "color" | "fill",
|
|
247
|
+
type: unknown,
|
|
248
|
+
): void {
|
|
249
|
+
const range = scale["range"];
|
|
250
|
+
const domain = scale["domain"];
|
|
251
|
+
if (
|
|
252
|
+
type === "manual" &&
|
|
253
|
+
Array.isArray(domain) &&
|
|
254
|
+
Array.isArray(range) &&
|
|
255
|
+
domain.length !== range.length
|
|
256
|
+
) {
|
|
257
|
+
errors.push({
|
|
258
|
+
code: "color-manual-domain-range",
|
|
259
|
+
path: `/scales/${channel}`,
|
|
260
|
+
message: `The manual ${channel} scale has ${String(domain.length)} domain values but ${String(range.length)} range colors.`,
|
|
261
|
+
fix: { description: "Provide exactly one range color for each explicit domain value." },
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
if (!Array.isArray(range)) return;
|
|
265
|
+
for (let index = 0; index < range.length; index++) {
|
|
266
|
+
const color: unknown = range[index];
|
|
267
|
+
if (typeof color !== "string" || /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(color)) continue;
|
|
268
|
+
errors.push({
|
|
269
|
+
code: "scale-range-color",
|
|
270
|
+
path: `/scales/${channel}/range/${index}`,
|
|
271
|
+
message: `The color stop "${color}" is not a supported hex color.`,
|
|
272
|
+
fix: {
|
|
273
|
+
description: "Use #rgb or #rrggbb syntax for custom color ranges.",
|
|
274
|
+
example: "#ff0000",
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural well-formedness for binned numeric/finite style scales.
|
|
3
|
+
* Mirrors runtime checks in scale-style-numeric.ts / scale-style-finite.ts:
|
|
4
|
+
* authored breaks must be finite + strictly increasing, and when both domain
|
|
5
|
+
* and breaks are authored their endpoints must agree.
|
|
6
|
+
*
|
|
7
|
+
* Independent of parseFailure and of data — recovery bounds must themselves
|
|
8
|
+
* be valid or the runtime throws style-binned-breaks / style-domain-invalid.
|
|
9
|
+
*/
|
|
10
|
+
import type { SpecError } from "./errors.js";
|
|
11
|
+
import { parseTemporalColumn } from "./temporal-column.js";
|
|
12
|
+
import { parseTemporal } from "./temporal-parse.js";
|
|
13
|
+
import { temporalParserUsable } from "./validate-data-checks-temporal.js";
|
|
14
|
+
|
|
15
|
+
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
16
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const BINNED_STYLE_AESTHETICS = ["size", "linewidth", "alpha", "shape", "linetype"] as const;
|
|
20
|
+
|
|
21
|
+
/** Mirror core cellToNumber for non-temporal style boundary resolution. */
|
|
22
|
+
function nonTemporalSemantic(value: unknown): number | undefined {
|
|
23
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : undefined;
|
|
24
|
+
if (value instanceof Date) {
|
|
25
|
+
const epochMs = value.getTime();
|
|
26
|
+
return Number.isFinite(epochMs) ? epochMs : undefined;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
29
|
+
if (typeof value === "string") {
|
|
30
|
+
const iso = parseTemporal(value, "iso");
|
|
31
|
+
if (iso.ok) return iso.epochMs;
|
|
32
|
+
if (value.trim() === "") return undefined;
|
|
33
|
+
const numeric = Number(value);
|
|
34
|
+
return Number.isFinite(numeric) ? numeric : undefined;
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function resolveBoundarySemantics(
|
|
40
|
+
values: readonly unknown[],
|
|
41
|
+
config: Record<string, unknown>,
|
|
42
|
+
): number[] | null {
|
|
43
|
+
const requestsTemporal =
|
|
44
|
+
config["temporalKind"] !== undefined ||
|
|
45
|
+
config["parse"] !== undefined ||
|
|
46
|
+
config["timezone"] !== undefined ||
|
|
47
|
+
config["disambiguation"] !== undefined;
|
|
48
|
+
|
|
49
|
+
if (!requestsTemporal) {
|
|
50
|
+
const mapped: number[] = [];
|
|
51
|
+
for (const value of values) {
|
|
52
|
+
const semantic = nonTemporalSemantic(value);
|
|
53
|
+
if (semantic === undefined) return null;
|
|
54
|
+
mapped.push(semantic);
|
|
55
|
+
}
|
|
56
|
+
return mapped;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Schema-invalid temporal inputs still reach structure checks; defer rather
|
|
60
|
+
// than throw inside the temporal helpers (same gate as data-aware checks).
|
|
61
|
+
if (!temporalParserUsable(config["parse"])) return null;
|
|
62
|
+
if (config["timezone"] !== undefined && typeof config["timezone"] !== "string") return null;
|
|
63
|
+
if (config["disambiguation"] !== undefined && typeof config["disambiguation"] !== "string") {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const options = {
|
|
68
|
+
...(typeof config["timezone"] === "string" && { timezone: config["timezone"] }),
|
|
69
|
+
...(typeof config["disambiguation"] === "string" && {
|
|
70
|
+
disambiguation: config["disambiguation"] as "compatible" | "earlier" | "later" | "reject",
|
|
71
|
+
}),
|
|
72
|
+
};
|
|
73
|
+
const parser = (config["parse"] ?? "auto") as Parameters<typeof parseTemporalColumn>[1];
|
|
74
|
+
const column = parseTemporalColumn(values, parser, options);
|
|
75
|
+
const mapped: number[] = [];
|
|
76
|
+
for (let index = 0; index < values.length; index++) {
|
|
77
|
+
if (column.valid[index] !== 1) return null;
|
|
78
|
+
const epochMs = column.semantic[index];
|
|
79
|
+
if (epochMs === undefined || !Number.isFinite(epochMs)) return null;
|
|
80
|
+
mapped.push(epochMs);
|
|
81
|
+
}
|
|
82
|
+
return mapped;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function isStrictlyIncreasing(boundaries: readonly number[]): boolean {
|
|
86
|
+
for (let index = 1; index < boundaries.length; index++) {
|
|
87
|
+
const prev = boundaries[index - 1];
|
|
88
|
+
const current = boundaries[index];
|
|
89
|
+
if (prev === undefined || current === undefined || current <= prev) return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Config-only checks for binned size/linewidth/alpha/shape/linetype scales.
|
|
96
|
+
* Runs whenever the scale object is schema-valid (same cadence as color
|
|
97
|
+
* structural checks).
|
|
98
|
+
*/
|
|
99
|
+
export function binnedStyleScaleStructuralErrors(scales: Record<string, unknown>): SpecError[] {
|
|
100
|
+
const errors: SpecError[] = [];
|
|
101
|
+
for (const aesthetic of BINNED_STYLE_AESTHETICS) {
|
|
102
|
+
const config = scales[aesthetic];
|
|
103
|
+
if (!isRecord(config) || config["type"] !== "binned") continue;
|
|
104
|
+
|
|
105
|
+
const authoredBreaks = Array.isArray(config["breaks"]) ? config["breaks"] : undefined;
|
|
106
|
+
if (authoredBreaks === undefined) continue;
|
|
107
|
+
|
|
108
|
+
// Schema already enforces minItems: 2; still guard for partial schema paths.
|
|
109
|
+
if (authoredBreaks.length < 2) {
|
|
110
|
+
errors.push({
|
|
111
|
+
code: "scale-binned-breaks",
|
|
112
|
+
path: `/scales/${aesthetic}/breaks`,
|
|
113
|
+
message: `The ${aesthetic} boundaries must be finite and strictly increasing.`,
|
|
114
|
+
fix: {
|
|
115
|
+
description: "Provide at least two strictly increasing boundary values.",
|
|
116
|
+
example: [0, 10, 20],
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const breakSemantics = resolveBoundarySemantics(authoredBreaks, config);
|
|
123
|
+
if (breakSemantics === null || !isStrictlyIncreasing(breakSemantics)) {
|
|
124
|
+
errors.push({
|
|
125
|
+
code: "scale-binned-breaks",
|
|
126
|
+
path: `/scales/${aesthetic}/breaks`,
|
|
127
|
+
message: `The ${aesthetic} boundaries must be finite and strictly increasing.`,
|
|
128
|
+
fix: {
|
|
129
|
+
description:
|
|
130
|
+
"Provide 2+ strictly increasing boundaries that parse under the scale's parser.",
|
|
131
|
+
example:
|
|
132
|
+
aesthetic === "size" || aesthetic === "linewidth" || aesthetic === "alpha"
|
|
133
|
+
? [0, 10, 20]
|
|
134
|
+
: [0, 1, 2],
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
// Malformed breaks are the primary diagnostic; skip domain agreement.
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const domain = Array.isArray(config["domain"]) ? config["domain"] : undefined;
|
|
142
|
+
if (domain === undefined || domain.length !== 2) continue;
|
|
143
|
+
|
|
144
|
+
const domainSemantics = resolveBoundarySemantics(domain, config);
|
|
145
|
+
if (domainSemantics === null || domainSemantics.length !== 2) {
|
|
146
|
+
// Unparseable domain is a separate runtime style-domain-invalid path; the
|
|
147
|
+
// censor-recovery check covers type-mismatch. Only emit agreement here when
|
|
148
|
+
// both sides fully resolve.
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const first = breakSemantics[0]!;
|
|
153
|
+
const last = breakSemantics.at(-1)!;
|
|
154
|
+
if (domainSemantics[0] !== first || domainSemantics[1] !== last) {
|
|
155
|
+
errors.push({
|
|
156
|
+
code: "scale-binned-domain",
|
|
157
|
+
path: `/scales/${aesthetic}/domain`,
|
|
158
|
+
message: `The ${aesthetic} binned domain must match its first and last boundaries.`,
|
|
159
|
+
fix: {
|
|
160
|
+
description: "Set domain to the first and last break values, or omit domain.",
|
|
161
|
+
example: [first, last],
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return errors;
|
|
167
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data-free structural grammar checks (tier-2, opt-in via validate options).
|
|
3
|
+
*
|
|
4
|
+
* Implementation:
|
|
5
|
+
* - validate-structure-layers.ts — geom channels, rule/ribbon/computed-y forms, M2 layer rules
|
|
6
|
+
* - validate-structure-scales.ts — named color/fill scheme vs family
|
|
7
|
+
* - validate-structure-style-bins.ts — binned style breaks/domain well-formedness
|
|
8
|
+
* - validate-structure-facet.ts — wrap XOR grid form
|
|
9
|
+
*
|
|
10
|
+
* Used only by validate() — not public surface.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export { layerStructuralErrors } from "./validate-structure-layers.js";
|
|
14
|
+
export { colorScaleStructuralErrors, guideStructuralErrors } from "./validate-structure-scales.js";
|
|
15
|
+
export { binnedStyleScaleStructuralErrors } from "./validate-structure-style-bins.js";
|
|
16
|
+
export { coordFacetStructuralErrors, facetStructuralErrors } from "./validate-structure-facet.js";
|
package/src/validate.ts
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec validation orchestrator — tier 1 (schema shape) plus opt-in tier 2
|
|
3
|
+
* (structural grammar, data-aware checks, optional lint).
|
|
4
|
+
*
|
|
5
|
+
* Tier-1 mechanism (decision 0004): TypeBox 1.x compiled checks plus
|
|
6
|
+
* `Value.Errors` over the same schemas that emit `schema/v0.json` — one
|
|
7
|
+
* artifact, no drift.
|
|
8
|
+
* Layer/plot shape walks: validate-schema-shape.ts (shared GEOM_BRANCHES;
|
|
9
|
+
* also hands per-layer branch-ok indices to the tier-2 structural gate).
|
|
10
|
+
* Raw TypeBox union noise is mapped to the agent error contract in
|
|
11
|
+
* validate-map-errors.ts (schema walk: validate-schema-walk.ts; channel/data
|
|
12
|
+
* form classification: validate-map-forms.ts).
|
|
13
|
+
* Data-free grammar rules live in validate-structure*.ts (layers / color
|
|
14
|
+
* schemes / facet form). Data-aware checks live in validate-data*.ts
|
|
15
|
+
* (evidence + checks modules, barrel at validate-data.ts).
|
|
16
|
+
*
|
|
17
|
+
* Output: `{ ok: true, spec }` or `{ ok: false, errors: SpecError[] }` with
|
|
18
|
+
* the agent error contract from errors.ts. Messages are snapshot-tested.
|
|
19
|
+
*/
|
|
20
|
+
import { Settings } from "typebox/system";
|
|
21
|
+
|
|
22
|
+
import type { SpecError } from "./errors.js";
|
|
23
|
+
// Precompiled at build time (scripts/gen-plot-validator.ts) — compiling the
|
|
24
|
+
// full plot union at runtime costs seconds; the generated module is pinned
|
|
25
|
+
// against a runtime-compiled validator by plot-spec-validator-generated.test.
|
|
26
|
+
import { Check as plotSpecSchemaCheck } from "./generated/plot-spec-validator.js";
|
|
27
|
+
import type { SpecAdvisory } from "./lint.js";
|
|
28
|
+
import { lintSpec } from "./lint.js";
|
|
29
|
+
import type { Aes, PortableSpec } from "./schema.js";
|
|
30
|
+
import { ensureTemporalPolyfill } from "./temporal-polyfill.js";
|
|
31
|
+
import type { ValidateOptions } from "./validate-data.js";
|
|
32
|
+
import {
|
|
33
|
+
dataChecks,
|
|
34
|
+
DEFAULT_VALIDATE_LIMITS,
|
|
35
|
+
jsonDepth,
|
|
36
|
+
resolveLayerFieldEvidence,
|
|
37
|
+
} from "./validate-data.js";
|
|
38
|
+
import { collectSchemaShapeErrors, GEOM_BRANCHES } from "./validate-schema-shape.js";
|
|
39
|
+
import { structuralGateErrors } from "./structural-gate.js";
|
|
40
|
+
import { facetStructuralErrors, layerStructuralErrors } from "./validate-structure.js";
|
|
41
|
+
|
|
42
|
+
export type ValidateResult =
|
|
43
|
+
| { ok: true; spec: PortableSpec; advisories?: SpecAdvisory[] }
|
|
44
|
+
| { ok: false; errors: SpecError[]; advisories?: SpecAdvisory[] };
|
|
45
|
+
|
|
46
|
+
function isRecord(v: unknown): v is Record<string, unknown> {
|
|
47
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validate a spec. Tier 1 (always): schema shape, no data needed. Tier 2
|
|
52
|
+
* (opt-in — pass an `options` argument, even `{}`): the grammar's structural
|
|
53
|
+
* rules (required channels per geom, bar/count y ban, rule forms) plus
|
|
54
|
+
* data-aware checks against the spec's inline data or the provided
|
|
55
|
+
* DataProfile, under documented input limits (DEFAULT_VALIDATE_LIMITS).
|
|
56
|
+
*
|
|
57
|
+
* On success, returns the input typed as PortableSpec (no copy is made).
|
|
58
|
+
*/
|
|
59
|
+
export function validate(input: unknown, options?: ValidateOptions): ValidateResult {
|
|
60
|
+
// Agent validate path may inspect temporal columns / IANA zones — load the
|
|
61
|
+
// polyfill here so lean `@ggts-sh/core/render` graphs never need it.
|
|
62
|
+
ensureTemporalPolyfill();
|
|
63
|
+
const limits = { ...DEFAULT_VALIDATE_LIMITS, ...options?.limits };
|
|
64
|
+
|
|
65
|
+
// Depth guard first: pathological nesting must not reach the schema walker.
|
|
66
|
+
if (jsonDepth(input, limits.maxDepth) > limits.maxDepth) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
errors: [
|
|
70
|
+
{
|
|
71
|
+
code: "validation-limit",
|
|
72
|
+
path: "",
|
|
73
|
+
message: `The spec nests deeper than ${limits.maxDepth} levels (documented maxDepth limit); validation refused.`,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const errors: SpecError[] = [];
|
|
80
|
+
// TypeBox Settings are process-global. Align with tsconfig exactOptionalPropertyTypes
|
|
81
|
+
// and raise maxErrors so Value.Errors is not truncated at the default of 8.
|
|
82
|
+
const previousMaxErrors = Settings.Get().maxErrors;
|
|
83
|
+
const previousExactOptional = Settings.Get().exactOptionalPropertyTypes;
|
|
84
|
+
Settings.Set({
|
|
85
|
+
maxErrors: Math.max(limits.maxDiagnostics, previousMaxErrors),
|
|
86
|
+
exactOptionalPropertyTypes: true,
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
// TypeBox's interpreted Value.Check / Value.Errors walk the cyclic schema
|
|
90
|
+
// graph for every inline row. Use the compiled plot validator for the
|
|
91
|
+
// common valid path, and Value.Errors only when building invalid diagnostics.
|
|
92
|
+
const schemaValid: boolean = (plotSpecSchemaCheck as (value: unknown) => boolean)(input);
|
|
93
|
+
|
|
94
|
+
// Tier-2 structural gate: run layerStructuralErrors only on branch-valid
|
|
95
|
+
// layers. When the compiled plot check passed, LayerSpec's geom-discriminated
|
|
96
|
+
// union already proves every layer matches its GEOM_BRANCHES member — skip
|
|
97
|
+
// a second interpreted walk. When it failed, reuse the shape walk's per-layer
|
|
98
|
+
// Value.Errors emptiness set (#1279).
|
|
99
|
+
let branchOkLayers: ReadonlySet<number> | "all" = "all";
|
|
100
|
+
|
|
101
|
+
if (!schemaValid) {
|
|
102
|
+
if (!isRecord(input)) {
|
|
103
|
+
return {
|
|
104
|
+
ok: false,
|
|
105
|
+
errors: [
|
|
106
|
+
{
|
|
107
|
+
code: "invalid-spec-root",
|
|
108
|
+
path: "",
|
|
109
|
+
message: `A plot spec must be a JSON object with a "layers" array (got ${Array.isArray(input) ? "an array" : typeof input}).`,
|
|
110
|
+
fix: {
|
|
111
|
+
description: "Provide an object with at least one layer.",
|
|
112
|
+
example: {
|
|
113
|
+
layers: [{ geom: "point", aes: { x: { field: "x" }, y: { field: "y" } } }],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const shape = collectSchemaShapeErrors(input);
|
|
122
|
+
errors.push(...shape.errors);
|
|
123
|
+
branchOkLayers = shape.branchOkLayerIndices;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// TypeBox-free structural gates (shared with pipeline render path).
|
|
127
|
+
if (schemaValid) {
|
|
128
|
+
errors.push(...structuralGateErrors(input));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// --- tier 2 (opt-in via options): structural grammar checks ----------------
|
|
132
|
+
// Required channels, the bar/count y ban, and the rule form rules are part
|
|
133
|
+
// of the tier-2 contract (the pipeline enforces them at render time with
|
|
134
|
+
// equivalent structured errors); tier 1 stays schema-shape-only so partial
|
|
135
|
+
// specs remain composable.
|
|
136
|
+
// Eligibility: record layers with a known geom whose branch is valid
|
|
137
|
+
// (see branchOkLayers above). Uses shared GEOM_BRANCHES for known-geom keys.
|
|
138
|
+
// --- tier 2 (opt-in): facet form rules --------------------------------------
|
|
139
|
+
// Runs for any record-valued facet, even when the facet is schema-invalid.
|
|
140
|
+
errors.push(
|
|
141
|
+
...collectLayerGrammarErrors(input, options, branchOkLayers),
|
|
142
|
+
...collectFacetGrammarErrors(input, options),
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// --- tier 2 (opt-in): data-aware checks + optional lint --------------------
|
|
146
|
+
// One resolveLayerFieldEvidence pass for plot + layer tables; dataChecks and
|
|
147
|
+
// lintSpec share it. On limit/profile errors, lint gets no shared map so it
|
|
148
|
+
// does not re-scan data that data-aware validation already refused.
|
|
149
|
+
const advisories = collectDataValidation(input, options, limits, errors);
|
|
150
|
+
const withAdvisories = advisories !== undefined && advisories.length > 0 ? { advisories } : {};
|
|
151
|
+
|
|
152
|
+
if (errors.length > limits.maxDiagnostics) {
|
|
153
|
+
const kept = errors.slice(0, limits.maxDiagnostics);
|
|
154
|
+
kept.push({
|
|
155
|
+
code: "validation-limit",
|
|
156
|
+
path: "",
|
|
157
|
+
message: `Diagnostics truncated: ${errors.length} problems found, showing the first ${limits.maxDiagnostics} (documented maxDiagnostics limit).`,
|
|
158
|
+
});
|
|
159
|
+
return { ok: false, errors: kept, ...withAdvisories };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (errors.length > 0) return { ok: false, errors, ...withAdvisories };
|
|
163
|
+
return { ok: true, spec: input as PortableSpec, ...withAdvisories };
|
|
164
|
+
} finally {
|
|
165
|
+
Settings.Set({
|
|
166
|
+
maxErrors: previousMaxErrors,
|
|
167
|
+
exactOptionalPropertyTypes: previousExactOptional,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function collectLayerGrammarErrors(
|
|
173
|
+
input: unknown,
|
|
174
|
+
options: ValidateOptions | undefined,
|
|
175
|
+
branchOkLayers: ReadonlySet<number> | "all",
|
|
176
|
+
): SpecError[] {
|
|
177
|
+
if (options === undefined || !isRecord(input) || !Array.isArray(input["layers"])) return [];
|
|
178
|
+
const errors: SpecError[] = [];
|
|
179
|
+
const plotAes = isRecord(input["aes"]) ? (input["aes"] as Aes) : undefined;
|
|
180
|
+
const layers = input["layers"] as unknown[];
|
|
181
|
+
for (let index = 0; index < layers.length; index++) {
|
|
182
|
+
const layer = layers[index];
|
|
183
|
+
if (!isRecord(layer)) continue;
|
|
184
|
+
const geom = layer["geom"];
|
|
185
|
+
if (typeof geom !== "string" || !Object.hasOwn(GEOM_BRANCHES, geom)) continue;
|
|
186
|
+
if (branchOkLayers !== "all" && !branchOkLayers.has(index)) continue;
|
|
187
|
+
errors.push(...layerStructuralErrors(layer, geom, index, plotAes));
|
|
188
|
+
}
|
|
189
|
+
return errors;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function collectFacetGrammarErrors(
|
|
193
|
+
input: unknown,
|
|
194
|
+
options: ValidateOptions | undefined,
|
|
195
|
+
): SpecError[] {
|
|
196
|
+
if (options === undefined || !isRecord(input) || !isRecord(input["facet"])) return [];
|
|
197
|
+
return facetStructuralErrors(input["facet"]);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function collectDataValidation(
|
|
201
|
+
input: unknown,
|
|
202
|
+
options: ValidateOptions | undefined,
|
|
203
|
+
limits: typeof DEFAULT_VALIDATE_LIMITS,
|
|
204
|
+
errors: SpecError[],
|
|
205
|
+
): SpecAdvisory[] | undefined {
|
|
206
|
+
if (options === undefined || !isRecord(input)) return undefined;
|
|
207
|
+
const layerResolved = resolveLayerFieldEvidence(input, options, limits);
|
|
208
|
+
errors.push(...dataChecks(input, options, limits, layerResolved));
|
|
209
|
+
if (options.lint !== true) return undefined;
|
|
210
|
+
const shared = layerResolved.status === "ok" ? layerResolved.plot : null;
|
|
211
|
+
return lintSpec(input, options, shared);
|
|
212
|
+
}
|