├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── design_proposal.md ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── automerge-dependabot.yml │ ├── build-docs.yml │ ├── create-bumb-version-pr.yml │ ├── publish-style-spec.yml │ └── test-all.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .nvmrc ├── CHANGELOG.md ├── CODE-OF-CONDUCT.md ├── COMMUNITY.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── SECURITY_POLICY.txt ├── bin ├── gl-style-format.ts ├── gl-style-migrate.ts └── gl-style-validate.ts ├── build ├── bump-version-changelog.js ├── expressions_patrial.md ├── generate-docs.ts ├── generate-style-spec.ts ├── release-notes.js └── rollup_plugin_minify_style_spec.ts ├── docs ├── README.md ├── assets │ ├── extra.css │ ├── hillshade_methods.png │ └── logo.svg ├── deprecations.md ├── sprite.md └── types.md ├── eslint.config.js ├── mkdocs.yml ├── package-lock.json ├── package.json ├── rollup.config.ts ├── src ├── declass.test.ts ├── declass.ts ├── deref.test.ts ├── deref.ts ├── diff.test.ts ├── diff.ts ├── empty.test.ts ├── empty.ts ├── error │ ├── parsing_error.ts │ └── validation_error.ts ├── expression │ ├── compound_expression.ts │ ├── definitions │ │ ├── assertion.ts │ │ ├── at.ts │ │ ├── case.ts │ │ ├── coalesce.ts │ │ ├── coercion.ts │ │ ├── collator.ts │ │ ├── comparison.ts │ │ ├── distance.ts │ │ ├── format.ts │ │ ├── global_state.ts │ │ ├── image.ts │ │ ├── in.ts │ │ ├── index.ts │ │ ├── index_of.ts │ │ ├── interpolate.ts │ │ ├── length.ts │ │ ├── let.ts │ │ ├── literal.ts │ │ ├── match.ts │ │ ├── number_format.ts │ │ ├── slice.ts │ │ ├── step.ts │ │ ├── var.ts │ │ └── within.ts │ ├── evaluation_context.ts │ ├── expression.test.ts │ ├── expression.ts │ ├── index.test.ts │ ├── index.ts │ ├── parsing_context.ts │ ├── parsing_error.ts │ ├── runtime_error.ts │ ├── scope.ts │ ├── stops.test.ts │ ├── stops.ts │ ├── types.ts │ ├── types │ │ ├── collator.ts │ │ ├── color.test.ts │ │ ├── color.ts │ │ ├── color_array.test.ts │ │ ├── color_array.ts │ │ ├── color_spaces.test.ts │ │ ├── color_spaces.ts │ │ ├── formatted.ts │ │ ├── number_array.test.ts │ │ ├── number_array.ts │ │ ├── padding.test.ts │ │ ├── padding.ts │ │ ├── parse_css_color.test.ts │ │ ├── parse_css_color.ts │ │ ├── projection_definition.test.ts │ │ ├── projection_definition.ts │ │ ├── resolved_image.ts │ │ ├── variable_anchor_offset_collection.test.ts │ │ └── variable_anchor_offset_collection.ts │ ├── values.test.ts │ └── values.ts ├── feature_filter │ ├── README.md │ ├── convert.ts │ ├── feature_filter.test.ts │ └── index.ts ├── format.test.ts ├── format.ts ├── function │ ├── convert.ts │ ├── index.test.ts │ └── index.ts ├── group_by_layout.test.ts ├── group_by_layout.ts ├── index.test.ts ├── index.ts ├── migrate.test.ts ├── migrate.ts ├── migrate │ ├── expressions.ts │ ├── migrate_colors.test.ts │ ├── migrate_colors.ts │ ├── v8.test.ts │ └── v8.ts ├── point2d.ts ├── read_style.ts ├── reference │ ├── latest.ts │ └── v8.json ├── tiles_and_coordinates.ts ├── util │ ├── cheap_ruler.ts │ ├── classify_rings.test.ts │ ├── classify_rings.ts │ ├── deep_equal.ts │ ├── extend.ts │ ├── geometry_util.ts │ ├── get_own.test.ts │ ├── get_own.ts │ ├── get_type.ts │ ├── interpolate-primitives.test.ts │ ├── interpolate-primitives.ts │ ├── is_object_literal.ts │ ├── properties.ts │ ├── ref_properties.ts │ ├── result.ts │ └── unbundle_jsonlint.ts ├── validate │ ├── validate.ts │ ├── validate_array.ts │ ├── validate_boolean.ts │ ├── validate_color.test.ts │ ├── validate_color.ts │ ├── validate_color_array.test.ts │ ├── validate_color_array.ts │ ├── validate_constants.ts │ ├── validate_enum.ts │ ├── validate_expression.ts │ ├── validate_filter.ts │ ├── validate_formatted.ts │ ├── validate_function.ts │ ├── validate_glyphs_url.ts │ ├── validate_image.ts │ ├── validate_layer.test.ts │ ├── validate_layer.ts │ ├── validate_layout_property.ts │ ├── validate_light.ts │ ├── validate_number.ts │ ├── validate_number_array.test.ts │ ├── validate_number_array.ts │ ├── validate_object.test.ts │ ├── validate_object.ts │ ├── validate_padding.test.ts │ ├── validate_padding.ts │ ├── validate_paint_property.ts │ ├── validate_projection.test.ts │ ├── validate_projection.ts │ ├── validate_projectiondefinition.test.ts │ ├── validate_projectiondefinition.ts │ ├── validate_property.ts │ ├── validate_raster_dem_source.test.ts │ ├── validate_raster_dem_source.ts │ ├── validate_sky.test.ts │ ├── validate_sky.ts │ ├── validate_source.ts │ ├── validate_sprite.test.ts │ ├── validate_sprite.ts │ ├── validate_state.test.ts │ ├── validate_state.ts │ ├── validate_string.ts │ ├── validate_terrain.test.ts │ ├── validate_terrain.ts │ ├── validate_variable_anchor_offset_collection.test.ts │ └── validate_variable_anchor_offset_collection.ts ├── validate_style.min.ts ├── validate_style.ts └── visit.ts ├── test ├── build │ └── style-spec.test.ts ├── integration │ ├── expression │ │ ├── expression.test.ts │ │ └── tests │ │ │ ├── abs │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── acos │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── all │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── short-circuiting │ │ │ │ └── test.json │ │ │ ├── any │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── short-circuiting │ │ │ │ └── test.json │ │ │ ├── array │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── default-value │ │ │ │ └── test.json │ │ │ ├── implicit-1 │ │ │ │ └── test.json │ │ │ ├── implicit-2 │ │ │ │ └── test.json │ │ │ ├── implicit-3 │ │ │ │ └── test.json │ │ │ ├── item-type-and-length │ │ │ │ └── test.json │ │ │ └── item-type │ │ │ │ └── test.json │ │ │ ├── asin │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── at │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── infer-array-type │ │ │ │ └── test.json │ │ │ ├── atan │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── boolean │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── default-value │ │ │ │ └── test.json │ │ │ ├── case │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── infer-array-type │ │ │ │ └── test.json │ │ │ └── precedence │ │ │ │ └── test.json │ │ │ ├── ceil │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── coalesce │ │ │ ├── argument-type-mismatch │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── error │ │ │ │ └── test.json │ │ │ ├── infer-array-type │ │ │ │ └── test.json │ │ │ ├── inference │ │ │ │ └── test.json │ │ │ └── null │ │ │ │ └── test.json │ │ │ ├── collator │ │ │ ├── accent-equals-de │ │ │ │ └── test.json │ │ │ ├── accent-lt-en │ │ │ │ └── test.json │ │ │ ├── accent-not-equals-en │ │ │ │ └── test.json │ │ │ ├── base-default-locale │ │ │ │ └── test.json │ │ │ ├── base-equals-en │ │ │ │ └── test.json │ │ │ ├── base-gt-en │ │ │ │ └── test.json │ │ │ ├── case-lteq-en │ │ │ │ └── test.json │ │ │ ├── case-not-equals-en │ │ │ │ └── test.json │ │ │ ├── case-omitted-en │ │ │ │ └── test.json │ │ │ ├── comparison-number-error │ │ │ │ └── test.json │ │ │ ├── diacritic-omitted-en │ │ │ │ └── test.json │ │ │ ├── equals-non-string-error │ │ │ │ └── test.json │ │ │ ├── non-object-error │ │ │ │ └── test.json │ │ │ ├── variant-equals-en │ │ │ │ └── test.json │ │ │ └── variant-gteq-en │ │ │ │ └── test.json │ │ │ ├── concat │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── coercion │ │ │ │ └── test.json │ │ │ ├── constant-folding │ │ │ ├── evaluation-error │ │ │ │ └── test.json │ │ │ ├── to-color-inferred │ │ │ │ └── test.json │ │ │ ├── to-color │ │ │ │ └── test.json │ │ │ └── var │ │ │ │ └── test.json │ │ │ ├── cos │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── distance │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── divide │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── downcase │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── e │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── elevation │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── equal │ │ │ ├── array │ │ │ │ └── test.json │ │ │ ├── collator-value │ │ │ │ └── test.json │ │ │ ├── color │ │ │ │ └── test.json │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── null-lhs │ │ │ │ └── test.json │ │ │ ├── null-rhs │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── object │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── feature-state │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── expression-arg │ │ │ │ └── test.json │ │ │ ├── floor │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── format │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── coercion │ │ │ │ └── test.json │ │ │ ├── data-driven-font │ │ │ │ └── test.json │ │ │ ├── data-driven-scale │ │ │ │ └── test.json │ │ │ ├── data-driven-vertical-align │ │ │ │ └── test.json │ │ │ ├── image-sections │ │ │ │ └── test.json │ │ │ ├── implicit-assert │ │ │ │ └── test.json │ │ │ ├── implicit-coerce │ │ │ │ └── test.json │ │ │ ├── implicit-omit │ │ │ │ └── test.json │ │ │ ├── implicit │ │ │ │ └── test.json │ │ │ ├── to-string │ │ │ │ └── test.json │ │ │ └── unknown-vertical-align │ │ │ │ └── test.json │ │ │ ├── geometry-type │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── get │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── from-literal--missing │ │ │ │ └── test.json │ │ │ ├── from-literal │ │ │ │ └── test.json │ │ │ └── from-object-property │ │ │ │ └── test.json │ │ │ ├── global-state │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── greater │ │ │ ├── boolean │ │ │ │ └── test.json │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── null │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── string-and-value │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── greater_or_equal │ │ │ ├── boolean │ │ │ │ └── test.json │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── null │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── string-and-value │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── has │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── heatmap-density │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── id │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── image │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── coalesce │ │ │ │ └── test.json │ │ │ ├── compound │ │ │ │ └── test.json │ │ │ └── implicit-assert │ │ │ │ └── test.json │ │ │ ├── in │ │ │ ├── assert-array │ │ │ │ └── test.json │ │ │ ├── assert-string │ │ │ │ └── test.json │ │ │ ├── basic-array │ │ │ │ └── test.json │ │ │ ├── basic-string │ │ │ │ └── test.json │ │ │ ├── invalid-haystack │ │ │ │ └── test.json │ │ │ └── invalid-needle │ │ │ │ └── test.json │ │ │ ├── index-of │ │ │ ├── assert-array │ │ │ │ └── test.json │ │ │ ├── assert-string │ │ │ │ └── test.json │ │ │ ├── basic-array │ │ │ │ └── test.json │ │ │ ├── basic-string │ │ │ │ └── test.json │ │ │ ├── invalid-haystack │ │ │ │ └── test.json │ │ │ ├── invalid-needle │ │ │ │ └── test.json │ │ │ └── with-from-index │ │ │ │ └── test.json │ │ │ ├── interpolate-hcl │ │ │ └── linear │ │ │ │ └── test.json │ │ │ ├── interpolate-lab │ │ │ └── linear │ │ │ │ └── test.json │ │ │ ├── interpolate │ │ │ ├── cubic-bezier-3-args │ │ │ │ └── test.json │ │ │ ├── cubic-bezier-5-args │ │ │ │ └── test.json │ │ │ ├── cubic-bezier-invalid-control-point │ │ │ │ └── test.json │ │ │ ├── cubic-bezier │ │ │ │ └── test.json │ │ │ ├── duplicate_stops │ │ │ │ └── test.json │ │ │ ├── exponential-number-array │ │ │ │ └── test.json │ │ │ ├── exponential-single-stop │ │ │ │ └── test.json │ │ │ ├── exponential-string-array │ │ │ │ └── test.json │ │ │ ├── exponential-uninterpolatable-numeric-array │ │ │ │ └── test.json │ │ │ ├── exponential │ │ │ │ └── test.json │ │ │ ├── infer-array-type │ │ │ │ └── test.json │ │ │ ├── linear-color │ │ │ │ └── test.json │ │ │ ├── linear-many-stops │ │ │ │ └── test.json │ │ │ ├── linear │ │ │ │ └── test.json │ │ │ └── projection │ │ │ │ ├── higher-than-stop │ │ │ │ └── test.json │ │ │ │ ├── linear │ │ │ │ └── test.json │ │ │ │ ├── lower-than-stop │ │ │ │ └── test.json │ │ │ │ └── same-from-to │ │ │ │ └── test.json │ │ │ ├── is-supported-script │ │ │ └── default │ │ │ │ └── test.json │ │ │ ├── legacy │ │ │ ├── categorical │ │ │ │ ├── array-default │ │ │ │ │ └── test.json │ │ │ │ ├── array │ │ │ │ │ └── test.json │ │ │ │ ├── boolean-default │ │ │ │ │ └── test.json │ │ │ │ ├── boolean │ │ │ │ │ └── test.json │ │ │ │ ├── color-default │ │ │ │ │ └── test.json │ │ │ │ ├── color │ │ │ │ │ └── test.json │ │ │ │ ├── number-default │ │ │ │ │ └── test.json │ │ │ │ ├── number │ │ │ │ │ └── test.json │ │ │ │ ├── string-default │ │ │ │ │ └── test.json │ │ │ │ ├── string │ │ │ │ │ └── test.json │ │ │ │ └── tokens │ │ │ │ │ └── test.json │ │ │ ├── exponential │ │ │ │ ├── array-default │ │ │ │ │ └── test.json │ │ │ │ ├── array │ │ │ │ │ └── test.json │ │ │ │ ├── base │ │ │ │ │ └── test.json │ │ │ │ ├── color-default │ │ │ │ │ └── test.json │ │ │ │ ├── color-hcl │ │ │ │ │ └── test.json │ │ │ │ ├── color-lab │ │ │ │ │ └── test.json │ │ │ │ ├── color │ │ │ │ │ └── test.json │ │ │ │ ├── composite-default │ │ │ │ │ └── test.json │ │ │ │ ├── composite │ │ │ │ │ └── test.json │ │ │ │ ├── duplicate-stops │ │ │ │ │ └── test.json │ │ │ │ ├── implicit │ │ │ │ │ └── test.json │ │ │ │ ├── number-default │ │ │ │ │ └── test.json │ │ │ │ └── number │ │ │ │ │ └── test.json │ │ │ ├── identity │ │ │ │ ├── array-default │ │ │ │ │ └── test.json │ │ │ │ ├── array │ │ │ │ │ └── test.json │ │ │ │ ├── boolean-default │ │ │ │ │ └── test.json │ │ │ │ ├── boolean │ │ │ │ │ └── test.json │ │ │ │ ├── color-default │ │ │ │ │ └── test.json │ │ │ │ ├── color │ │ │ │ │ └── test.json │ │ │ │ ├── color_array │ │ │ │ │ └── test.json │ │ │ │ ├── enum-default │ │ │ │ │ └── test.json │ │ │ │ ├── enum │ │ │ │ │ └── test.json │ │ │ │ ├── number-default │ │ │ │ │ └── test.json │ │ │ │ ├── number │ │ │ │ │ └── test.json │ │ │ │ ├── number_array │ │ │ │ │ └── test.json │ │ │ │ ├── padding │ │ │ │ │ └── test.json │ │ │ │ ├── string-default │ │ │ │ │ └── test.json │ │ │ │ └── string │ │ │ │ │ └── test.json │ │ │ └── interval │ │ │ │ ├── array-default │ │ │ │ └── test.json │ │ │ │ ├── array │ │ │ │ └── test.json │ │ │ │ ├── color-default │ │ │ │ └── test.json │ │ │ │ ├── color │ │ │ │ └── test.json │ │ │ │ ├── composite-default │ │ │ │ └── test.json │ │ │ │ ├── composite │ │ │ │ └── test.json │ │ │ │ ├── duplicate-stops │ │ │ │ └── test.json │ │ │ │ ├── implicit │ │ │ │ └── test.json │ │ │ │ ├── number-default │ │ │ │ └── test.json │ │ │ │ ├── number │ │ │ │ └── test.json │ │ │ │ ├── string-default │ │ │ │ └── test.json │ │ │ │ ├── string │ │ │ │ └── test.json │ │ │ │ ├── tokens-property │ │ │ │ └── test.json │ │ │ │ └── tokens-zoom │ │ │ │ └── test.json │ │ │ ├── length │ │ │ ├── array │ │ │ │ └── test.json │ │ │ ├── implicit │ │ │ │ └── test.json │ │ │ ├── invalid │ │ │ │ └── test.json │ │ │ └── string │ │ │ │ └── test.json │ │ │ ├── less │ │ │ ├── boolean │ │ │ │ └── test.json │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── null │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── string-and-value │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── less_or_equal │ │ │ ├── boolean │ │ │ │ └── test.json │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── null │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── string-and-value │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── let │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── expected-value │ │ │ │ └── test.json │ │ │ ├── invalid-name │ │ │ │ └── test.json │ │ │ ├── nested │ │ │ │ └── test.json │ │ │ ├── property-function │ │ │ │ └── test.json │ │ │ ├── shadow │ │ │ │ └── test.json │ │ │ ├── unbound │ │ │ │ └── test.json │ │ │ └── zoom │ │ │ │ └── test.json │ │ │ ├── literal │ │ │ ├── boolean-array │ │ │ │ └── test.json │ │ │ ├── empty │ │ │ │ └── test.json │ │ │ ├── infer-empty-array-type │ │ │ │ └── test.json │ │ │ ├── literal-false │ │ │ │ └── test.json │ │ │ ├── literal-null │ │ │ │ └── test.json │ │ │ ├── literal-number │ │ │ │ └── test.json │ │ │ ├── literal-string │ │ │ │ └── test.json │ │ │ ├── literal-true │ │ │ │ └── test.json │ │ │ ├── mixed-primitive-array │ │ │ │ └── test.json │ │ │ ├── multiple-args │ │ │ │ └── test.json │ │ │ ├── nested-array │ │ │ │ └── test.json │ │ │ ├── number-array │ │ │ │ └── test.json │ │ │ ├── object │ │ │ │ └── test.json │ │ │ ├── string-array │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── u2028u2029 │ │ │ │ └── test.json │ │ │ ├── ln │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── ln2 │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── log10 │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── log2 │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── match │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ ├── arity-2 │ │ │ │ └── test.json │ │ │ ├── arity-3 │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── empty-case │ │ │ │ └── test.json │ │ │ ├── infer-array-type │ │ │ │ └── test.json │ │ │ ├── label-array │ │ │ │ └── test.json │ │ │ ├── label-boolean │ │ │ │ └── test.json │ │ │ ├── label-non-integer │ │ │ │ └── test.json │ │ │ ├── label-null │ │ │ │ └── test.json │ │ │ ├── label-number │ │ │ │ └── test.json │ │ │ ├── label-object │ │ │ │ └── test.json │ │ │ ├── label-overflow │ │ │ │ └── test.json │ │ │ ├── label-string-invalid-identifier │ │ │ │ └── test.json │ │ │ ├── label-string │ │ │ │ └── test.json │ │ │ ├── mismatch-input │ │ │ │ └── test.json │ │ │ ├── mismatch-label-1 │ │ │ │ └── test.json │ │ │ ├── mismatch-label-2 │ │ │ │ └── test.json │ │ │ ├── mismatch-output │ │ │ │ └── test.json │ │ │ ├── mixed-type │ │ │ │ └── test.json │ │ │ ├── multi-value │ │ │ │ └── test.json │ │ │ ├── unreachable-branch-1 │ │ │ │ └── test.json │ │ │ └── unreachable-branch-2 │ │ │ │ └── test.json │ │ │ ├── max │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── min │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── minus │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── inference-arity-2 │ │ │ │ └── test.json │ │ │ ├── mod │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── not │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── not_equal │ │ │ ├── mismatch │ │ │ │ └── test.json │ │ │ ├── number │ │ │ │ └── test.json │ │ │ ├── string │ │ │ │ └── test.json │ │ │ └── value │ │ │ │ └── test.json │ │ │ ├── number-format │ │ │ ├── currency │ │ │ │ └── test.json │ │ │ ├── default │ │ │ │ └── test.json │ │ │ └── precision │ │ │ │ └── test.json │ │ │ ├── number │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── default-value │ │ │ │ └── test.json │ │ │ ├── object │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── default-value │ │ │ │ └── test.json │ │ │ └── implicit │ │ │ │ └── test.json │ │ │ ├── parse │ │ │ ├── empty │ │ │ │ └── test.json │ │ │ ├── non-array │ │ │ │ └── test.json │ │ │ ├── non-string │ │ │ │ └── test.json │ │ │ └── unknown-expression │ │ │ │ └── test.json │ │ │ ├── pi │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── plus │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── pow │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── properties │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── resolved-locale │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── rgb │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── rgba │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── out-of-bounds │ │ │ │ └── test.json │ │ │ ├── round │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── sin │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── slice │ │ │ ├── array-one-index │ │ │ │ └── test.json │ │ │ ├── array-two-indexes │ │ │ │ └── test.json │ │ │ ├── invalid-inputs │ │ │ │ └── test.json │ │ │ ├── string-one-index │ │ │ │ └── test.json │ │ │ └── string-two-indexes │ │ │ │ └── test.json │ │ │ ├── sqrt │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── step │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── duplicate_stops │ │ │ │ └── test.json │ │ │ └── projection │ │ │ │ ├── step-array │ │ │ │ └── test.json │ │ │ │ └── step-primitive │ │ │ │ └── test.json │ │ │ ├── string │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── default-value │ │ │ │ └── test.json │ │ │ ├── tan │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── times │ │ │ ├── arity-0 │ │ │ │ └── test.json │ │ │ ├── arity-1 │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── to-boolean │ │ │ ├── 2-ary │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── to-color │ │ │ ├── 2-ary │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── color │ │ │ │ └── test.json │ │ │ ├── to-number │ │ │ ├── 2-ary │ │ │ │ └── test.json │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── to-rgba │ │ │ ├── alpha │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ └── zero │ │ │ │ └── test.json │ │ │ ├── to-string │ │ │ ├── 2-ary │ │ │ │ └── test.json │ │ │ ├── basic │ │ │ │ └── test.json │ │ │ ├── color │ │ │ │ └── test.json │ │ │ └── implicit │ │ │ │ └── test.json │ │ │ ├── typecheck │ │ │ ├── array-invalid-item │ │ │ │ └── test.json │ │ │ ├── array-item-subtyping │ │ │ │ └── test.json │ │ │ ├── array-length-subtyping--no-length │ │ │ │ └── test.json │ │ │ ├── array-length-subtyping │ │ │ │ └── test.json │ │ │ └── array-wrong-length │ │ │ │ └── test.json │ │ │ ├── typeof │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── upcase │ │ │ └── basic │ │ │ │ └── test.json │ │ │ ├── within │ │ │ ├── invalid-geojson │ │ │ │ └── test.json │ │ │ ├── line-within-collection-of-multipolygons │ │ │ │ └── test.json │ │ │ ├── line-within-collection-of-polygons │ │ │ │ └── test.json │ │ │ ├── line-within-polygon │ │ │ │ └── test.json │ │ │ ├── line-within-polygons │ │ │ │ └── test.json │ │ │ ├── lines-within-polygon │ │ │ │ └── test.json │ │ │ ├── lines-within-polygons │ │ │ │ └── test.json │ │ │ ├── meridian-issue-line-1 │ │ │ │ └── test.json │ │ │ ├── meridian-issue-line-2 │ │ │ │ └── test.json │ │ │ ├── meridian-issue-point-1 │ │ │ │ └── test.json │ │ │ ├── meridian-issue-point-2 │ │ │ │ └── test.json │ │ │ ├── non-supported │ │ │ │ └── test.json │ │ │ ├── point-on-boundary-1 │ │ │ │ └── test.json │ │ │ ├── point-on-boundary-2 │ │ │ │ └── test.json │ │ │ ├── point-on-boundary-3 │ │ │ │ └── test.json │ │ │ ├── point-within-collection-of-multipolygons │ │ │ │ └── test.json │ │ │ ├── point-within-collection-of-polygons │ │ │ │ └── test.json │ │ │ ├── point-within-polygon │ │ │ │ └── test.json │ │ │ ├── point-within-polygons │ │ │ │ └── test.json │ │ │ ├── points-within-polygon │ │ │ │ └── test.json │ │ │ └── points-within-polygons │ │ │ │ └── test.json │ │ │ └── zoom │ │ │ ├── basic │ │ │ └── test.json │ │ │ ├── invalid-nested-1 │ │ │ └── test.json │ │ │ ├── invalid-nested-2 │ │ │ └── test.json │ │ │ ├── invalid-nested-3 │ │ │ └── test.json │ │ │ ├── invalid-nested-4 │ │ │ └── test.json │ │ │ ├── invalid-nested-5 │ │ │ └── test.json │ │ │ ├── invalid-no-curve │ │ │ └── test.json │ │ │ ├── nested-coalesce │ │ │ └── test.json │ │ │ └── nested-let │ │ │ └── test.json │ └── style-spec │ │ ├── tests │ │ ├── bad-color.input.json │ │ ├── bad-color.output-api-supported.json │ │ ├── bad-color.output.json │ │ ├── center-altitude.input.json │ │ ├── center-altitude.output-api-supported.json │ │ ├── center-altitude.output.json │ │ ├── constants.input.json │ │ ├── constants.output-api-supported.json │ │ ├── constants.output.json │ │ ├── extrakeys.input.json │ │ ├── extrakeys.output-api-supported.json │ │ ├── extrakeys.output.json │ │ ├── filters.input.json │ │ ├── filters.output-api-supported.json │ │ ├── filters.output.json │ │ ├── functions.input.json │ │ ├── functions.output-api-supported.json │ │ ├── functions.output.json │ │ ├── layers.input.json │ │ ├── layers.output-api-supported.json │ │ ├── layers.output.json │ │ ├── light-arbitrary.input.json │ │ ├── light-arbitrary.output-api-supported.json │ │ ├── light-arbitrary.output.json │ │ ├── light-malformed-color.input.json │ │ ├── light-malformed-color.output.json │ │ ├── light.input.json │ │ ├── light.output-api-supported.json │ │ ├── light.output.json │ │ ├── malformed-glyphs-type.input.json │ │ ├── malformed-glyphs-type.output-api-supported.json │ │ ├── malformed-glyphs-type.output.json │ │ ├── malformed-glyphs.input.json │ │ ├── malformed-glyphs.output-api-supported.json │ │ ├── malformed-glyphs.output.json │ │ ├── map-properties.input.json │ │ ├── map-properties.output-api-supported.json │ │ ├── map-properties.output.json │ │ ├── metadata.input.json │ │ ├── metadata.output-api-supported.json │ │ ├── metadata.output.json │ │ ├── missing-glyphs.input.json │ │ ├── missing-glyphs.output-api-supported.json │ │ ├── missing-glyphs.output.json │ │ ├── no-sources.input.json │ │ ├── no-sources.output-api-supported.json │ │ ├── no-sources.output.json │ │ ├── non-mapbox-references.input.json │ │ ├── non-mapbox-references.output-api-supported.json │ │ ├── non-mapbox-references.output.json │ │ ├── numbers.input.json │ │ ├── numbers.output-api-supported.json │ │ ├── numbers.output.json │ │ ├── pitch.input.json │ │ ├── pitch.output-api-supported.json │ │ ├── pitch.output.json │ │ ├── projection.input.json │ │ ├── projection.output.json │ │ ├── properties.input.json │ │ ├── properties.output-api-supported.json │ │ ├── properties.output.json │ │ ├── required.input.json │ │ ├── required.output-api-supported.json │ │ ├── required.output.json │ │ ├── roll.input.json │ │ ├── roll.output-api-supported.json │ │ ├── roll.output.json │ │ ├── root-properties.input.json │ │ ├── root-properties.output-api-supported.json │ │ ├── root-properties.output.json │ │ ├── sources.input.json │ │ ├── sources.output-api-supported.json │ │ ├── sources.output.json │ │ ├── state.input.json │ │ ├── state.output.json │ │ ├── terrain.input.json │ │ ├── terrain.output.json │ │ ├── text-field-format.input.json │ │ ├── text-field-format.output-api-supported.json │ │ ├── text-field-format.output.json │ │ ├── text-font.input.json │ │ ├── text-font.output-api-supported.json │ │ ├── text-font.output.json │ │ ├── unknown-keys-nested.input.json │ │ ├── unknown-keys-nested.output-api-supported.json │ │ └── unknown-keys-nested.output.json │ │ └── validate_spec.test.ts └── lib │ ├── geometry.ts │ ├── json-diff.ts │ └── util.ts ├── tsconfig.json ├── vitest.config.build.ts ├── vitest.config.integration.ts └── vitest.config.unit.ts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [maplibre] 2 | open_collective: maplibre 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/design_proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Design Proposal 3 | about: Make a design proposal 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Design Proposal: PUT TITLE HERE 11 | 12 | ## Motivation 13 | 14 | Describe the problem you would like to solve. 15 | 16 | ## Proposed Change 17 | 18 | Describe what you would like to do to solve the problem. This part is the actual design proposal and can be extensive with multiple subsections. 19 | 20 | ## API Modifications 21 | 22 | Outline what modifications you expect on the API due to your change. 23 | 24 | ## Migration Plan and Compatibility 25 | 26 | If your proposal replaces existing functionality, write a migration plan how users can get to the new functionality. 27 | 28 | Make a statement about the compatibility of your new functionality with existing functionality. 29 | 30 | ## Rejected Alternatives 31 | 32 | Discuss what alternatives to your proposed change you considered and why you rejected them. 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Launch Checklist 2 | 3 | 4 | 5 | 6 | - [ ] Confirm **your changes do not include backports from Mapbox projects** (unless with compliant license) - if you are not sure about this, please ask! 7 | - [ ] Briefly describe the changes in this PR. 8 | - [ ] Link to related issues. 9 | - [ ] Include before/after visuals or gifs if this PR includes visual changes. 10 | - [ ] Write tests for all new functionality. 11 | - [ ] Document any changes to public APIs. 12 | - [ ] Post benchmark scores. 13 | - [ ] Add an entry to `CHANGELOG.md` under the `## main` section. 14 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | open-pull-requests-limit: 20 13 | versioning-strategy: increase 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "weekly" 18 | - package-ecosystem: "npm" 19 | directory: "/docs" 20 | schedule: 21 | interval: "weekly" 22 | open-pull-requests-limit: 5 23 | versioning-strategy: increase -------------------------------------------------------------------------------- /.github/workflows/automerge-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: Automerge Dependabot 2 | 3 | on: pull_request 4 | 5 | permissions: write-all 6 | 7 | jobs: 8 | dependabot: 9 | runs-on: ubuntu-latest 10 | if: ${{ github.actor == 'dependabot[bot]' }} 11 | steps: 12 | - name: Dependabot metadata 13 | id: metadata 14 | uses: dependabot/fetch-metadata@v2.4.0 15 | with: 16 | github-token: "${{ secrets.GITHUB_TOKEN }}" 17 | - name: Approve Dependabot PRs 18 | run: gh pr review --approve "$PR_URL" 19 | env: 20 | PR_URL: ${{github.event.pull_request.html_url}} 21 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 22 | - name: Enable auto-merge for Dependabot PRs 23 | run: gh pr merge --auto --squash "$PR_URL" 24 | env: 25 | PR_URL: ${{github.event.pull_request.html_url}} 26 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 27 | -------------------------------------------------------------------------------- /.github/workflows/build-docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs - Build (& Deploy) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | build-test-deploy: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version-file: '.nvmrc' 19 | 20 | - name: Install NPM packages 21 | run: npm ci 22 | 23 | - name: Build style spec 24 | run: | 25 | npm run generate-style-spec 26 | npm run generate-typings 27 | 28 | - name: Build docs 29 | run: npm run mkdocs-build 30 | 31 | 32 | - name: Deploy 33 | if: github.ref == 'refs/heads/main' 34 | uses: JamesIves/github-pages-deploy-action@v4 35 | with: 36 | branch: gh-pages 37 | folder: site 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .eslintcache 3 | tsc 4 | dist 5 | .DS_Store 6 | */**/*.g.ts 7 | .cache 8 | coverage/ 9 | site/ 10 | docs/* 11 | !docs/assets/extra.css 12 | !docs/assets/logo.svg 13 | !docs/README.md 14 | !docs/types.md 15 | !docs/sprite.md 16 | !docs/deprecations.md -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.10 2 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of conduct 2 | 3 | [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://github.com/maplibre/maplibre/blob/main/CODE_OF_CONDUCT.md) 4 | 5 | -------------------------------------------------------------------------------- /COMMUNITY.md: -------------------------------------------------------------------------------- 1 | # MapLibre Community 2 | 3 | See https://maplibre.org/community/ 4 | -------------------------------------------------------------------------------- /SECURITY_POLICY.txt: -------------------------------------------------------------------------------- 1 | For an up-to-date policy refer to 2 | https://github.com/maplibre/maplibre/blob/main/SECURITY_POLICY.txt 3 | -------------------------------------------------------------------------------- /bin/gl-style-format.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import fs from 'fs'; 4 | import minimist from 'minimist'; 5 | import {format} from '../src/format'; 6 | const argv = minimist(process.argv.slice(2)); 7 | 8 | if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) { 9 | help(); 10 | } else { 11 | console.log(format(JSON.parse(fs.readFileSync(argv._[0]).toString()), argv.space)); 12 | } 13 | 14 | function help() { 15 | console.log('usage:'); 16 | console.log(' gl-style-format source.json > destination.json'); 17 | console.log(''); 18 | console.log('options:'); 19 | console.log(' --space '); 20 | console.log(' Number of spaces in output (default "2")'); 21 | console.log(' Pass "0" for minified output.'); 22 | } 23 | -------------------------------------------------------------------------------- /bin/gl-style-migrate.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import fs from 'fs'; 4 | import minimist from 'minimist'; 5 | import {format} from '../src/format'; 6 | import {migrate} from '../src/migrate'; 7 | const argv = minimist(process.argv.slice(2)); 8 | 9 | if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) { 10 | help(); 11 | } else { 12 | console.log(format(migrate(JSON.parse(fs.readFileSync(argv._[0]).toString())))); 13 | } 14 | 15 | function help() { 16 | console.log('usage:'); 17 | console.log(' gl-style-migrate style-v7.json > style-v8.json'); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /build/bump-version-changelog.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * This script updates the changelog.md file with the version given in the arguments 5 | * It replaces ## main with ## 6 | * Removes _...Add new stuff here..._ 7 | * And adds on top a ## main with add stuff here. 8 | */ 9 | 10 | import {readFileSync, writeFileSync} from 'fs'; 11 | 12 | const changelogPath = 'CHANGELOG.md'; 13 | let changelog = readFileSync(changelogPath, 'utf8'); 14 | changelog = changelog.replace('## main', `## ${process.argv[2]}`); 15 | changelog = changelog.replaceAll('- _...Add new stuff here..._\n', ''); 16 | changelog = `## main 17 | 18 | ### ✨ Features and improvements 19 | - _...Add new stuff here..._ 20 | 21 | ### 🐞 Bug fixes 22 | - _...Add new stuff here..._ 23 | 24 | ` + changelog; 25 | 26 | writeFileSync(changelogPath, changelog, 'utf8'); 27 | -------------------------------------------------------------------------------- /build/rollup_plugin_minify_style_spec.ts: -------------------------------------------------------------------------------- 1 | import {Plugin} from 'rollup'; 2 | 3 | function replacer(key: string, value: any) { 4 | return (key === 'doc' || key === 'example' || key === 'sdk-support') ? undefined : value; 5 | } 6 | 7 | export default function minifyStyleSpec(): Plugin { 8 | return { 9 | name: 'minify-style-spec', 10 | transform: (source, id) => { 11 | if (!/reference[\\/]v[0-9]+\.json$/.test(id)) { 12 | return; 13 | } 14 | 15 | const spec = JSON.parse(source); 16 | 17 | delete spec['expression_name']; 18 | 19 | return { 20 | code: JSON.stringify(spec, replacer, 0), 21 | map: {mappings: ''} 22 | }; 23 | } 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /docs/assets/extra.css: -------------------------------------------------------------------------------- 1 | 2 | [data-md-color-scheme="default"] { 3 | --md-primary-fg-color: #295DAA; 4 | --md-accent-fg-color: #568ad6; 5 | } 6 | 7 | [data-md-color-scheme="slate"] { 8 | --md-primary-fg-color: #295DAA; 9 | --md-accent-fg-color: #568ad6; 10 | } 11 | -------------------------------------------------------------------------------- /docs/assets/hillshade_methods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maplibre/maplibre-style-spec/177ecf5324faebaa3820a81cb3cc8762007ecd59/docs/assets/hillshade_methods.png -------------------------------------------------------------------------------- /src/empty.test.ts: -------------------------------------------------------------------------------- 1 | import {emptyStyle} from './empty'; 2 | import {validateStyleMin} from './validate_style.min'; 3 | import {describe, test, expect} from 'vitest'; 4 | 5 | describe('empty', () => { 6 | test('it generates something', () => { 7 | const style = emptyStyle(); 8 | expect(style).toBeTruthy(); 9 | }); 10 | 11 | test('generated empty style is a valid style', () => { 12 | const errors = validateStyleMin(emptyStyle()); 13 | expect(errors).toHaveLength(0); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/empty.ts: -------------------------------------------------------------------------------- 1 | import {latest} from './reference/latest'; 2 | import {StyleSpecification} from './types.g'; 3 | 4 | export function emptyStyle(): StyleSpecification { 5 | const style = {}; 6 | 7 | const version = latest['$version']; 8 | for (const styleKey in latest['$root']) { 9 | const specification = latest['$root'][styleKey]; 10 | 11 | if (specification.required) { 12 | let value = null; 13 | if (styleKey === 'version') { 14 | value = version; 15 | } else { 16 | if (specification.type === 'array') { 17 | value = []; 18 | } else { 19 | value = {}; 20 | } 21 | } 22 | 23 | if (value != null) { 24 | style[styleKey] = value; 25 | } 26 | } 27 | } 28 | 29 | return style as StyleSpecification; 30 | } 31 | -------------------------------------------------------------------------------- /src/error/parsing_error.ts: -------------------------------------------------------------------------------- 1 | // Note: Do not inherit from Error. It breaks when transpiling to ES5. 2 | 3 | export class ParsingError { 4 | message: string; 5 | error: Error; 6 | line: number; 7 | 8 | constructor(error: Error) { 9 | this.error = error; 10 | this.message = error.message; 11 | const match = error.message.match(/line (\d+)/); 12 | this.line = match ? parseInt(match[1], 10) : 0; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/error/validation_error.ts: -------------------------------------------------------------------------------- 1 | // Note: Do not inherit from Error. It breaks when transpiling to ES5. 2 | 3 | export class ValidationError { 4 | message: string; 5 | identifier: string; 6 | line: number; 7 | 8 | constructor(key: string, value: any & { 9 | __line__: number; 10 | }, message: string, identifier?: string | null) { 11 | this.message = (key ? `${key}: ` : '') + message; 12 | if (identifier) this.identifier = identifier; 13 | 14 | if (value !== null && value !== undefined && value.__line__) { 15 | this.line = value.__line__; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/expression/expression.ts: -------------------------------------------------------------------------------- 1 | import type {Type} from './types'; 2 | import type {ParsingContext} from './parsing_context'; 3 | import type {EvaluationContext} from './evaluation_context'; 4 | 5 | /** 6 | * Expression 7 | */ 8 | export interface Expression { 9 | readonly type: Type; 10 | evaluate(ctx: EvaluationContext): any; 11 | eachChild(fn: (a: Expression) => void): void; 12 | /** 13 | * Statically analyze the expression, attempting to enumerate possible outputs. Returns 14 | * false if the complete set of outputs is statically undecidable, otherwise true. 15 | */ 16 | outputDefined(): boolean; 17 | } 18 | 19 | export type ExpressionParser = (args: ReadonlyArray, context: ParsingContext) => Expression; 20 | export type ExpressionRegistration = { 21 | new (...args: any): Expression; 22 | } & { 23 | readonly parse: ExpressionParser; 24 | }; 25 | export type ExpressionRegistry = {[_: string]: ExpressionRegistration}; 26 | -------------------------------------------------------------------------------- /src/expression/parsing_error.ts: -------------------------------------------------------------------------------- 1 | export class ExpressionParsingError extends Error { 2 | key: string; 3 | message: string; 4 | constructor(key: string, message: string) { 5 | super(message); 6 | this.message = message; 7 | this.key = key; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/expression/runtime_error.ts: -------------------------------------------------------------------------------- 1 | export class RuntimeError extends Error { 2 | constructor(message: string) { 3 | super(message); 4 | this.name = 'RuntimeError'; 5 | } 6 | 7 | toJSON() { 8 | return this.message; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/expression/scope.ts: -------------------------------------------------------------------------------- 1 | import type {Expression} from './expression'; 2 | 3 | /** 4 | * Tracks `let` bindings during expression parsing. 5 | * @private 6 | */ 7 | export class Scope { 8 | parent: Scope; 9 | bindings: {[_: string]: Expression}; 10 | constructor(parent?: Scope, bindings: Array<[string, Expression]> = []) { 11 | this.parent = parent; 12 | this.bindings = {}; 13 | for (const [name, expression] of bindings) { 14 | this.bindings[name] = expression; 15 | } 16 | } 17 | 18 | concat(bindings: Array<[string, Expression]>) { 19 | return new Scope(this, bindings); 20 | } 21 | 22 | get(name: string): Expression { 23 | if (this.bindings[name]) { return this.bindings[name]; } 24 | if (this.parent) { return this.parent.get(name); } 25 | throw new Error(`${name} not found in scope.`); 26 | } 27 | 28 | has(name: string): boolean { 29 | if (this.bindings[name]) return true; 30 | return this.parent ? this.parent.has(name) : false; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/expression/stops.test.ts: -------------------------------------------------------------------------------- 1 | import {findStopLessThanOrEqualTo} from './stops'; 2 | import {describe, test, expect} from 'vitest'; 3 | 4 | describe('findStopLessThanOrEqualTo', () => { 5 | test('When the input > all stops it returns the last stop.', () => { 6 | const index = findStopLessThanOrEqualTo([0, 1, 2, 3, 4, 5, 6, 7], 8); 7 | expect(index).toBe(7); 8 | }); 9 | 10 | test('When more than one stop has the same value it always returns the last stop', () => { 11 | let index; 12 | 13 | index = findStopLessThanOrEqualTo([0.5, 0.5], 0.5); 14 | expect(index).toBe(1); 15 | 16 | index = findStopLessThanOrEqualTo([0.5, 0.5, 0.5], 0.5); 17 | expect(index).toBe(2); 18 | 19 | index = findStopLessThanOrEqualTo([0.4, 0.5, 0.5, 0.6, 0.7], 0.5); 20 | expect(index).toBe(2); 21 | 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /src/expression/types/resolved_image.ts: -------------------------------------------------------------------------------- 1 | export type ResolvedImageOptions = { 2 | name: string; 3 | available: boolean; 4 | }; 5 | 6 | export class ResolvedImage { 7 | name: string; 8 | available: boolean; 9 | 10 | constructor(options: ResolvedImageOptions) { 11 | this.name = options.name; 12 | this.available = options.available; 13 | } 14 | 15 | toString(): string { 16 | return this.name; 17 | } 18 | 19 | static fromString(name: string): ResolvedImage | null { 20 | if (!name) return null; // treat empty values as no image 21 | return new ResolvedImage({name, available: false}); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/format.test.ts: -------------------------------------------------------------------------------- 1 | import {format} from './format'; 2 | import {describe, test, expect} from 'vitest'; 3 | function roundtrip(style) { 4 | return JSON.parse(format(style)); 5 | } 6 | 7 | describe('format', () => { 8 | 9 | test('orders top-level keys', () => { 10 | expect(Object.keys(roundtrip({ 11 | 'layers': [], 12 | 'other': {}, 13 | 'sources': {}, 14 | 'glyphs': '', 15 | 'sprite': '', 16 | 'version': 6 17 | }))).toEqual(['version', 'sources', 'sprite', 'glyphs', 'layers', 'other']); 18 | }); 19 | 20 | test('orders layer keys', () => { 21 | expect(Object.keys(roundtrip({ 22 | 'layers': [{ 23 | 'paint': {}, 24 | 'layout': {}, 25 | 'id': 'id', 26 | 'type': 'type' 27 | }] 28 | }).layers[0])).toEqual(['id', 'type', 'layout', 'paint']); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/point2d.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface Point2D { 3 | x: number; 4 | y: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/read_style.ts: -------------------------------------------------------------------------------- 1 | import {ParsingError} from './error/parsing_error'; 2 | import jsonlint from '@mapbox/jsonlint-lines-primitives'; 3 | import type {StyleSpecification} from './types.g'; 4 | 5 | export function readStyle(style: StyleSpecification | string | Buffer): StyleSpecification { 6 | if (style instanceof String || typeof style === 'string' || style instanceof Buffer) { 7 | try { 8 | return jsonlint.parse(style.toString()); 9 | } catch (e) { 10 | throw new ParsingError(e); 11 | } 12 | } 13 | 14 | return style as StyleSpecification; 15 | } 16 | -------------------------------------------------------------------------------- /src/reference/latest.ts: -------------------------------------------------------------------------------- 1 | 2 | import latest from './v8.json' with { type: 'json' }; 3 | export {latest} 4 | export default latest as any 5 | -------------------------------------------------------------------------------- /src/util/deep_equal.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Deeply compares two object literals. 3 | * 4 | * @private 5 | */ 6 | 7 | export function deepEqual(a?: unknown | null, b?: unknown | null): boolean { 8 | if (Array.isArray(a)) { 9 | if (!Array.isArray(b) || a.length !== b.length) return false; 10 | for (let i = 0; i < a.length; i++) { 11 | if (!deepEqual(a[i], b[i])) return false; 12 | } 13 | return true; 14 | } 15 | if (typeof a === 'object' && a !== null && b !== null) { 16 | if (!(typeof b === 'object')) return false; 17 | const keys = Object.keys(a); 18 | if (keys.length !== Object.keys(b).length) return false; 19 | for (const key in a) { 20 | if (!deepEqual(a[key], b[key])) return false; 21 | } 22 | return true; 23 | } 24 | return a === b; 25 | } -------------------------------------------------------------------------------- /src/util/extend.ts: -------------------------------------------------------------------------------- 1 | export function extendBy(output: any, ...inputs: Array) { 2 | for (const input of inputs) { 3 | for (const k in input) { 4 | output[k] = input[k]; 5 | } 6 | } 7 | return output; 8 | } 9 | -------------------------------------------------------------------------------- /src/util/get_own.ts: -------------------------------------------------------------------------------- 1 | type HasOwnPropertyFn = (obj: TObject, key: PropertyKey) => key is keyof TObject; 2 | 3 | // polyfill for Object.hasOwn 4 | const hasOwnProperty: HasOwnPropertyFn = 5 | (Object.hasOwn as HasOwnPropertyFn) || 6 | function hasOwnProperty(object: T, key: PropertyKey): key is keyof T { 7 | return Object.prototype.hasOwnProperty.call(object, key); 8 | }; 9 | 10 | export function getOwn(object: T, key: PropertyKey): T[keyof T] | undefined { 11 | return hasOwnProperty(object, key) ? object[key] : undefined; 12 | } 13 | -------------------------------------------------------------------------------- /src/util/get_type.ts: -------------------------------------------------------------------------------- 1 | export function getType(val: unknown): string { 2 | if (val instanceof Number) { 3 | return 'number'; 4 | } else if (val instanceof String) { 5 | return 'string'; 6 | } else if (val instanceof Boolean) { 7 | return 'boolean'; 8 | } else if (Array.isArray(val)) { 9 | return 'array'; 10 | } else if (val === null) { 11 | return 'null'; 12 | } else { 13 | return typeof val; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/util/interpolate-primitives.test.ts: -------------------------------------------------------------------------------- 1 | import {interpolateArray, interpolateNumber} from './interpolate-primitives'; 2 | import {describe, test, expect} from 'vitest'; 3 | 4 | describe('interpolate', () => { 5 | 6 | test('interpolate number', () => { 7 | expect(interpolateNumber(-5, 5, 0.00)).toBe(-5.0); 8 | expect(interpolateNumber(-5, 5, 0.25)).toBe(-2.5); 9 | expect(interpolateNumber(-5, 5, 0.50)).toBe(0); 10 | expect(interpolateNumber(-5, 5, 0.75)).toBe(2.5); 11 | expect(interpolateNumber(-5, 5, 1.00)).toBe(5.0); 12 | 13 | expect(interpolateNumber(0, 1, 0.5)).toBe(0.5); 14 | expect(interpolateNumber(-10, -5, 0.5)).toBe(-7.5); 15 | expect(interpolateNumber(5, 10, 0.5)).toBe(7.5); 16 | }); 17 | 18 | test('interpolate array', () => { 19 | expect(interpolateArray([0, 0, 0, 0], [1, 2, 3, 4], 0.5)).toEqual([0.5, 1, 3 / 2, 2]); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/util/interpolate-primitives.ts: -------------------------------------------------------------------------------- 1 | export function interpolateNumber(from: number, to: number, t: number): number { 2 | return from + t * (to - from); 3 | } 4 | 5 | export function interpolateArray(from: T, to: T, t: number): T { 6 | return from.map((d, i) => { 7 | return interpolateNumber(d, to[i], t); 8 | }) as T; 9 | } 10 | -------------------------------------------------------------------------------- /src/util/is_object_literal.ts: -------------------------------------------------------------------------------- 1 | export function isObjectLiteral( 2 | anything: unknown 3 | ): anything is Record { 4 | return Boolean(anything) && anything.constructor === Object; 5 | } -------------------------------------------------------------------------------- /src/util/properties.ts: -------------------------------------------------------------------------------- 1 | import type {StylePropertySpecification} from '..'; 2 | 3 | export function supportsPropertyExpression(spec: StylePropertySpecification): boolean { 4 | return spec['property-type'] === 'data-driven' || spec['property-type'] === 'cross-faded-data-driven'; 5 | } 6 | 7 | export function supportsZoomExpression(spec: StylePropertySpecification): boolean { 8 | return !!spec.expression && spec.expression.parameters.indexOf('zoom') > -1; 9 | } 10 | 11 | export function supportsInterpolation(spec: StylePropertySpecification): boolean { 12 | return !!spec.expression && spec.expression.interpolated; 13 | } 14 | -------------------------------------------------------------------------------- /src/util/ref_properties.ts: -------------------------------------------------------------------------------- 1 | 2 | export const refProperties = ['type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout']; 3 | -------------------------------------------------------------------------------- /src/util/result.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A type used for returning and propagating errors. The first element of the union 3 | * represents success and contains a value, and the second represents an error and 4 | * contains an error value. 5 | * @private 6 | */ 7 | export type Result = { 8 | result: 'success'; 9 | value: T; 10 | } | { 11 | result: 'error'; 12 | value: E; 13 | }; 14 | 15 | export function success(value: T): Result { 16 | return {result: 'success', value}; 17 | } 18 | 19 | export function error(value: E): Result { 20 | return {result: 'error', value}; 21 | } 22 | -------------------------------------------------------------------------------- /src/util/unbundle_jsonlint.ts: -------------------------------------------------------------------------------- 1 | // Turn jsonlint-lines-primitives objects into primitive objects 2 | export function unbundle(value: unknown) { 3 | if (value instanceof Number || value instanceof String || value instanceof Boolean) { 4 | return value.valueOf(); 5 | } else { 6 | return value; 7 | } 8 | } 9 | 10 | export function deepUnbundle(value: unknown): unknown { 11 | if (Array.isArray(value)) { 12 | return value.map(deepUnbundle); 13 | } else if (value instanceof Object && !(value instanceof Number || value instanceof String || value instanceof Boolean)) { 14 | const unbundledValue: {[key: string]: unknown} = {}; 15 | for (const key in value) { 16 | unbundledValue[key] = deepUnbundle(value[key]); 17 | } 18 | return unbundledValue; 19 | } 20 | 21 | return unbundle(value); 22 | } 23 | -------------------------------------------------------------------------------- /src/validate/validate_boolean.ts: -------------------------------------------------------------------------------- 1 | 2 | import {getType} from '../util/get_type'; 3 | import {ValidationError} from '../error/validation_error'; 4 | 5 | export function validateBoolean(options) { 6 | const value = options.value; 7 | const key = options.key; 8 | const type = getType(value); 9 | 10 | if (type !== 'boolean') { 11 | return [new ValidationError(key, value, `boolean expected, ${type} found`)]; 12 | } 13 | 14 | return []; 15 | } 16 | -------------------------------------------------------------------------------- /src/validate/validate_color.ts: -------------------------------------------------------------------------------- 1 | import {ValidationError} from '../error/validation_error'; 2 | import {getType} from '../util/get_type'; 3 | import {Color} from '../expression/types/color'; 4 | 5 | export function validateColor(options) { 6 | const key = options.key; 7 | const value = options.value; 8 | const type = getType(value); 9 | 10 | if (type !== 'string') { 11 | return [new ValidationError(key, value, `color expected, ${type} found`)]; 12 | } 13 | 14 | if (!Color.parse(String(value))) { // cast String object to string primitive 15 | return [new ValidationError(key, value, `color expected, "${value}" found`)]; 16 | } 17 | 18 | return []; 19 | } 20 | -------------------------------------------------------------------------------- /src/validate/validate_color_array.ts: -------------------------------------------------------------------------------- 1 | import {ValidationError} from '../error/validation_error'; 2 | import {getType} from '../util/get_type'; 3 | import {validateColor} from './validate_color'; 4 | 5 | export function validateColorArray(options) { 6 | const key = options.key; 7 | const value = options.value; 8 | const type = getType(value); 9 | 10 | if (type === 'array') { 11 | 12 | if (value.length < 1) { 13 | return [new ValidationError(key, value, 'array length at least 1 expected, length 0 found')]; 14 | } 15 | 16 | let errors = []; 17 | for (let i = 0; i < value.length; i++) { 18 | errors = errors.concat(validateColor({ 19 | key: `${key}[${i}]`, 20 | value: value[i], 21 | valueSpec: {} 22 | })); 23 | } 24 | return errors; 25 | } else { 26 | return validateColor({ 27 | key, 28 | value, 29 | valueSpec: {} 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/validate/validate_constants.ts: -------------------------------------------------------------------------------- 1 | 2 | import {ValidationError} from '../error/validation_error'; 3 | 4 | export function validateConstants(options) { 5 | const key = options.key; 6 | const constants = options.value; 7 | 8 | if (constants) { 9 | return [new ValidationError(key, constants, 'constants have been deprecated as of v8')]; 10 | } else { 11 | return []; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/validate/validate_enum.ts: -------------------------------------------------------------------------------- 1 | 2 | import {ValidationError} from '../error/validation_error'; 3 | import {unbundle} from '../util/unbundle_jsonlint'; 4 | 5 | export function validateEnum(options) { 6 | const key = options.key; 7 | const value = options.value; 8 | const valueSpec = options.valueSpec; 9 | const errors = []; 10 | 11 | if (Array.isArray(valueSpec.values)) { // <=v7 12 | if (valueSpec.values.indexOf(unbundle(value)) === -1) { 13 | errors.push(new ValidationError(key, value, `expected one of [${valueSpec.values.join(', ')}], ${JSON.stringify(value)} found`)); 14 | } 15 | } else { // >=v8 16 | if (Object.keys(valueSpec.values).indexOf(unbundle(value) as string) === -1) { 17 | errors.push(new ValidationError(key, value, `expected one of [${Object.keys(valueSpec.values).join(', ')}], ${JSON.stringify(value)} found`)); 18 | } 19 | } 20 | return errors; 21 | } 22 | -------------------------------------------------------------------------------- /src/validate/validate_formatted.ts: -------------------------------------------------------------------------------- 1 | import {validateExpression} from './validate_expression'; 2 | import {validateString} from './validate_string'; 3 | 4 | export function validateFormatted(options: any) { 5 | if (validateString(options).length === 0) { 6 | return []; 7 | } 8 | 9 | return validateExpression(options); 10 | } 11 | -------------------------------------------------------------------------------- /src/validate/validate_glyphs_url.ts: -------------------------------------------------------------------------------- 1 | 2 | import {ValidationError} from '../error/validation_error'; 3 | import {validateString} from './validate_string'; 4 | 5 | export function validateGlyphsUrl(options) { 6 | const value = options.value; 7 | const key = options.key; 8 | 9 | const errors = validateString(options); 10 | if (errors.length) return errors; 11 | 12 | if (value.indexOf('{fontstack}') === -1) { 13 | errors.push(new ValidationError(key, value, '"glyphs" url must include a "{fontstack}" token')); 14 | } 15 | 16 | if (value.indexOf('{range}') === -1) { 17 | errors.push(new ValidationError(key, value, '"glyphs" url must include a "{range}" token')); 18 | } 19 | 20 | return errors; 21 | } 22 | -------------------------------------------------------------------------------- /src/validate/validate_image.ts: -------------------------------------------------------------------------------- 1 | import {validateExpression} from './validate_expression'; 2 | import {validateString} from './validate_string'; 3 | 4 | export function validateImage(options: any) { 5 | if (validateString(options).length === 0) { 6 | return []; 7 | } 8 | 9 | return validateExpression(options); 10 | } 11 | -------------------------------------------------------------------------------- /src/validate/validate_layer.test.ts: -------------------------------------------------------------------------------- 1 | import {validate} from './validate'; 2 | import {validateLayer} from './validate_layer'; 3 | import v8 from '../reference/v8.json' with {type: 'json'}; 4 | import {expect, test} from 'vitest'; 5 | 6 | test.each([ 7 | ['number', 1], 8 | ['string', '__proto__'], 9 | ['boolean', true], 10 | ['array', [{}]], 11 | ['null', null], 12 | ])('Should return error if layer value is %s instead of an object', (valueType, value) => { 13 | const errors = validateLayer({ 14 | validateSpec: validate, 15 | value: value, 16 | styleSpec: v8, 17 | style: {} as any, 18 | }); 19 | expect(errors).toHaveLength(1); 20 | expect(errors[0].message).toBe(`object expected, ${valueType} found`); 21 | }); 22 | -------------------------------------------------------------------------------- /src/validate/validate_layout_property.ts: -------------------------------------------------------------------------------- 1 | 2 | import {validateProperty} from './validate_property'; 3 | 4 | export function validateLayoutProperty(options) { 5 | return validateProperty(options, 'layout'); 6 | } 7 | -------------------------------------------------------------------------------- /src/validate/validate_number.ts: -------------------------------------------------------------------------------- 1 | 2 | import {getType} from '../util/get_type'; 3 | import {ValidationError} from '../error/validation_error'; 4 | 5 | export function validateNumber(options) { 6 | const key = options.key; 7 | const value = options.value; 8 | const valueSpec = options.valueSpec; 9 | let type = getType(value); 10 | 11 | if (type === 'number' && value !== value) { 12 | type = 'NaN'; 13 | } 14 | 15 | if (type !== 'number') { 16 | return [new ValidationError(key, value, `number expected, ${type} found`)]; 17 | } 18 | 19 | if ('minimum' in valueSpec && value < valueSpec.minimum) { 20 | return [new ValidationError(key, value, `${value} is less than the minimum value ${valueSpec.minimum}`)]; 21 | } 22 | 23 | if ('maximum' in valueSpec && value > valueSpec.maximum) { 24 | return [new ValidationError(key, value, `${value} is greater than the maximum value ${valueSpec.maximum}`)]; 25 | } 26 | 27 | return []; 28 | } 29 | -------------------------------------------------------------------------------- /src/validate/validate_paint_property.ts: -------------------------------------------------------------------------------- 1 | 2 | import {validateProperty} from './validate_property'; 3 | 4 | export function validatePaintProperty(options) { 5 | return validateProperty(options, 'paint'); 6 | } 7 | -------------------------------------------------------------------------------- /src/validate/validate_state.test.ts: -------------------------------------------------------------------------------- 1 | import {validateState} from './validate_state'; 2 | import {describe, test, expect} from 'vitest'; 3 | 4 | describe('Validate state', () => { 5 | test('Should return no error if type is an object', () => { 6 | const errors = validateState({key: 'state', value: {a: 1}}); 7 | expect(errors).toHaveLength(0); 8 | }); 9 | 10 | test('Should return error if type is not an object', () => { 11 | const errors = validateState({key: 'state', value: 3}); 12 | expect(errors).toHaveLength(1); 13 | expect(errors[0].message).toBe('state: object expected, number found'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/validate/validate_state.ts: -------------------------------------------------------------------------------- 1 | import {ValidationError} from '../error/validation_error'; 2 | import {getType} from '../util/get_type'; 3 | import {isObjectLiteral} from '../util/is_object_literal'; 4 | 5 | interface ValidateStateOptions { 6 | key: 'state'; 7 | value: unknown; 8 | } 9 | 10 | export function validateState(options: ValidateStateOptions): ValidationError[] { 11 | if (!isObjectLiteral(options.value)) { 12 | return [ 13 | new ValidationError( 14 | options.key, 15 | options.value, 16 | `object expected, ${getType(options.value)} found` 17 | ), 18 | ]; 19 | } 20 | 21 | return []; 22 | } 23 | -------------------------------------------------------------------------------- /src/validate/validate_string.ts: -------------------------------------------------------------------------------- 1 | 2 | import {getType} from '../util/get_type'; 3 | import {ValidationError} from '../error/validation_error'; 4 | 5 | export function validateString(options) { 6 | const value = options.value; 7 | const key = options.key; 8 | const type = getType(value); 9 | 10 | if (type !== 'string') { 11 | return [new ValidationError(key, value, `string expected, ${type} found`)]; 12 | } 13 | 14 | return []; 15 | } 16 | -------------------------------------------------------------------------------- /test/integration/expression/tests/abs/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "abs", 4 | [ 5 | "get", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | { 13 | "properties": { 14 | "x": -2 15 | } 16 | } 17 | ], 18 | [ 19 | {}, 20 | { 21 | "properties": { 22 | "x": 2 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": -1.1 31 | } 32 | } 33 | ] 34 | ], 35 | "expected": { 36 | "compiled": { 37 | "result": "success", 38 | "isFeatureConstant": false, 39 | "isZoomConstant": true, 40 | "type": "number" 41 | }, 42 | "outputs": [ 43 | 2, 44 | 2, 45 | 1.1 46 | ] 47 | } 48 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/acos/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "acos", 4 | 0.5 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 1.04719 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/all/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "boolean" 17 | }, 18 | "outputs": [ 19 | true 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/all/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all", 4 | false 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "boolean" 18 | }, 19 | "outputs": [ 20 | false 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/all/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "boolean", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "inputs": [ 20 | [ 21 | {}, 22 | { 23 | "properties": { 24 | "x": true, 25 | "y": false 26 | } 27 | } 28 | ], 29 | [ 30 | {}, 31 | { 32 | "properties": { 33 | "x": true, 34 | "y": true 35 | } 36 | } 37 | ] 38 | ], 39 | "expected": { 40 | "compiled": { 41 | "result": "success", 42 | "isFeatureConstant": false, 43 | "isZoomConstant": true, 44 | "type": "boolean" 45 | }, 46 | "outputs": [ 47 | false, 48 | true 49 | ] 50 | } 51 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/all/short-circuiting/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all", 4 | false, 5 | [ 6 | "error", 7 | "unreachable" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | {} 14 | ] 15 | ], 16 | "expected": { 17 | "compiled": { 18 | "result": "success", 19 | "isFeatureConstant": true, 20 | "isZoomConstant": true, 21 | "type": "boolean" 22 | }, 23 | "outputs": [ 24 | false 25 | ] 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/any/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "any" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "boolean" 17 | }, 18 | "outputs": [ 19 | false 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/any/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "any", 4 | false 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "boolean" 18 | }, 19 | "outputs": [ 20 | false 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/any/short-circuiting/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "any", 4 | true, 5 | [ 6 | "error", 7 | "unreachable" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | {} 14 | ] 15 | ], 16 | "expected": { 17 | "compiled": { 18 | "result": "success", 19 | "isFeatureConstant": true, 20 | "isZoomConstant": true, 21 | "type": "boolean" 22 | }, 23 | "outputs": [ 24 | true 25 | ] 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/array/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "array", 4 | [ 5 | "literal", 6 | [ 7 | 1, 8 | 2, 9 | 3 10 | ] 11 | ] 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | {} 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "success", 22 | "isFeatureConstant": true, 23 | "isZoomConstant": true, 24 | "type": "array" 25 | }, 26 | "outputs": [ 27 | [ 28 | 1, 29 | 2, 30 | 3 31 | ] 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/array/default-value/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "array", 4 | "number", 5 | null, 6 | [ 7 | "get", 8 | "x" 9 | ], 10 | [ 11 | "literal", 12 | [ 13 | 0 14 | ] 15 | ] 16 | ], 17 | "inputs": [ 18 | [ 19 | {}, 20 | {} 21 | ], 22 | [ 23 | {}, 24 | { 25 | "properties": { 26 | "x": [] 27 | } 28 | } 29 | ], 30 | [ 31 | {}, 32 | { 33 | "properties": { 34 | "x": [ 35 | "1" 36 | ] 37 | } 38 | } 39 | ] 40 | ], 41 | "expected": { 42 | "compiled": { 43 | "result": "success", 44 | "isFeatureConstant": false, 45 | "isZoomConstant": true, 46 | "type": "array" 47 | }, 48 | "outputs": [ 49 | [ 50 | 0 51 | ], 52 | [], 53 | [ 54 | 0 55 | ] 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/array/implicit-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "at", 4 | 0, 5 | [ 6 | "get", 7 | "array" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "array": [ 16 | 0, 17 | 1, 18 | 2 19 | ] 20 | } 21 | } 22 | ], 23 | [ 24 | {}, 25 | { 26 | "properties": { 27 | "array": "not" 28 | } 29 | } 30 | ] 31 | ], 32 | "expected": { 33 | "compiled": { 34 | "result": "success", 35 | "isFeatureConstant": false, 36 | "isZoomConstant": true, 37 | "type": "value" 38 | }, 39 | "outputs": [ 40 | 0, 41 | { 42 | "error": "Expected value to be of type array, but found string instead." 43 | } 44 | ] 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/asin/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "asin", 4 | 0.5 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 0.523598 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/at/infer-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "string", 4 | "property-type": "data-driven", 5 | "expression": { 6 | "parameters": [ 7 | "zoom", 8 | "feature" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "at", 14 | 1, 15 | [ 16 | "literal", 17 | [ 18 | 1, 19 | 2, 20 | 3 21 | ] 22 | ] 23 | ], 24 | "inputs": [], 25 | "expected": { 26 | "compiled": { 27 | "result": "error", 28 | "errors": [ 29 | { 30 | "key": "[2]", 31 | "error": "Expected array but found array instead." 32 | } 33 | ] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/atan/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "atan", 4 | 1 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 0.785398 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/case/infer-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "case", 15 | [ 16 | "boolean", 17 | [ 18 | "get", 19 | "x" 20 | ] 21 | ], 22 | [ 23 | "literal", 24 | [ 25 | "one" 26 | ] 27 | ], 28 | [ 29 | "literal", 30 | [ 31 | "one", 32 | "two" 33 | ] 34 | ] 35 | ], 36 | "inputs": [], 37 | "expected": { 38 | "compiled": { 39 | "result": "success", 40 | "isFeatureConstant": false, 41 | "isZoomConstant": true, 42 | "type": "array" 43 | }, 44 | "outputs": [] 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/case/precedence/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "boolean", 4 | [ 5 | "all", 6 | false, 7 | [ 8 | "case", 9 | true, 10 | true, 11 | true 12 | ] 13 | ] 14 | ], 15 | "inputs": [ 16 | [ 17 | {}, 18 | {} 19 | ] 20 | ], 21 | "expected": { 22 | "compiled": { 23 | "result": "success", 24 | "isFeatureConstant": true, 25 | "isZoomConstant": true, 26 | "type": "boolean" 27 | }, 28 | "outputs": [ 29 | false 30 | ] 31 | } 32 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/coalesce/argument-type-mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "string", 4 | "property-type": "data-driven", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "coalesce", 15 | [ 16 | "get", 17 | "a" 18 | ], 19 | 5 20 | ], 21 | "expected": { 22 | "compiled": { 23 | "result": "error", 24 | "errors": [ 25 | { 26 | "key": "[2]", 27 | "error": "Expected string but found number instead." 28 | } 29 | ] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/coalesce/infer-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "coalesce", 15 | [ 16 | "literal", 17 | [ 18 | "one" 19 | ] 20 | ], 21 | [ 22 | "literal", 23 | [ 24 | "one", 25 | "two" 26 | ] 27 | ], 28 | null 29 | ], 30 | "inputs": [], 31 | "expected": { 32 | "compiled": { 33 | "result": "error", 34 | "errors": [ 35 | { 36 | "key": "[3]", 37 | "error": "Expected array but found null instead." 38 | } 39 | ] 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/coalesce/null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expectExpressionType": null, 3 | "expression": [ 4 | "coalesce", 5 | [ 6 | "get", 7 | "z" 8 | ], 9 | 0 10 | ], 11 | "inputs": [ 12 | [ 13 | {}, 14 | { 15 | "properties": { 16 | "z": 1 17 | } 18 | } 19 | ], 20 | [ 21 | {}, 22 | { 23 | "properties": { 24 | "z": null 25 | } 26 | } 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": false, 33 | "isZoomConstant": true, 34 | "type": "value" 35 | }, 36 | "outputs": [ 37 | 1, 38 | 0 39 | ] 40 | } 41 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/collator/comparison-number-error/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<", 4 | 1, 5 | 2, 6 | [ 7 | "collator", 8 | { 9 | "case-sensitive": false, 10 | "diacritic-sensitive": false 11 | } 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "error", 17 | "errors": [ 18 | { 19 | "key": "", 20 | "error": "Cannot use collator to compare non-string types." 21 | } 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/collator/equals-non-string-error/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | 1, 5 | 2, 6 | [ 7 | "collator", 8 | { 9 | "case-sensitive": false, 10 | "diacritic-sensitive": false 11 | } 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "error", 17 | "errors": [ 18 | { 19 | "key": "", 20 | "error": "Cannot use collator to compare non-string types." 21 | } 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/collator/non-object-error/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | "foo", 5 | "bar", 6 | [ 7 | "collator", 8 | [ 9 | "subexpression" 10 | ] 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "error", 16 | "errors": [ 17 | { 18 | "key": "[3]", 19 | "error": "Collator options argument must be an object." 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/concat/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "concat" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "string" 17 | }, 18 | "outputs": [ 19 | "" 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/concat/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "concat", 4 | "foo" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "string" 18 | }, 19 | "outputs": [ 20 | "foo" 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/concat/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "concat", 4 | "a", 5 | "b", 6 | "c" 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "string" 20 | }, 21 | "outputs": [ 22 | "abc" 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/concat/coercion/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "concat", 4 | [ 5 | "get", 6 | "a" 7 | ], 8 | [ 9 | "get", 10 | "1" 11 | ], 12 | [ 13 | "get", 14 | "true" 15 | ] 16 | ], 17 | "inputs": [ 18 | [ 19 | {}, 20 | { 21 | "properties": { 22 | "1": 1, 23 | "a": "a", 24 | "true": true 25 | } 26 | } 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": false, 33 | "isZoomConstant": true, 34 | "type": "string" 35 | }, 36 | "outputs": [ 37 | "a1true" 38 | ] 39 | } 40 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/constant-folding/to-color-inferred/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "color", 4 | "property-type": "data-driven", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": "red", 14 | "inputs": [ 15 | [ 16 | {}, 17 | {} 18 | ] 19 | ], 20 | "expected": { 21 | "compiled": { 22 | "result": "success", 23 | "isFeatureConstant": true, 24 | "isZoomConstant": true, 25 | "type": "color" 26 | }, 27 | "outputs": [ 28 | [ 29 | 1, 30 | 0, 31 | 0, 32 | 1 33 | ] 34 | ] 35 | } 36 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/constant-folding/to-color/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-color", 4 | "red" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "color" 18 | }, 19 | "outputs": [ 20 | [ 21 | 1, 22 | 0, 23 | 0, 24 | 1 25 | ] 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/constant-folding/var/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | 1, 6 | "b", 7 | 2, 8 | [ 9 | "+", 10 | [ 11 | "+", 12 | [ 13 | "var", 14 | "a" 15 | ], 16 | [ 17 | "var", 18 | "b" 19 | ] 20 | ], 21 | [ 22 | "var", 23 | "a" 24 | ] 25 | ] 26 | ], 27 | "inputs": [ 28 | [ 29 | {}, 30 | {} 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "success", 36 | "isFeatureConstant": true, 37 | "isZoomConstant": true, 38 | "type": "number" 39 | }, 40 | "outputs": [ 41 | 4 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/cos/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "cos", 4 | 0 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 1 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/divide/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "/", 4 | 10, 5 | 5 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "success", 16 | "isFeatureConstant": true, 17 | "isZoomConstant": true, 18 | "type": "number" 19 | }, 20 | "outputs": [ 21 | 2 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/downcase/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "downcase", 4 | "StRiNg" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "string" 18 | }, 19 | "outputs": [ 20 | "string" 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/e/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "e" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "number" 17 | }, 18 | "outputs": [ 19 | 2.71828 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "literal", 10 | [ 11 | 1 12 | ] 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "error", 18 | "errors": [ 19 | { 20 | "key": "[2]", 21 | "error": "\"==\" comparisons are not supported for type 'array'." 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/color/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "to-color", 10 | "red" 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "error", 16 | "errors": [ 17 | { 18 | "key": "[2]", 19 | "error": "\"==\" comparisons are not supported for type 'color'." 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/null-lhs/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | null, 5 | [ 6 | "get", 7 | "x" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": {} 15 | } 16 | ], 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": 1 22 | } 23 | } 24 | ] 25 | ], 26 | "expected": { 27 | "compiled": { 28 | "result": "success", 29 | "isFeatureConstant": false, 30 | "isZoomConstant": true, 31 | "type": "boolean" 32 | }, 33 | "outputs": [ 34 | true, 35 | false 36 | ] 37 | } 38 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/null-rhs/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | null, 5 | [ 6 | "get", 7 | "x" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": {} 15 | } 16 | ], 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": 1 22 | } 23 | } 24 | ] 25 | ], 26 | "expected": { 27 | "compiled": { 28 | "result": "success", 29 | "isFeatureConstant": false, 30 | "isZoomConstant": true, 31 | "type": "boolean" 32 | }, 33 | "outputs": [ 34 | true, 35 | false 36 | ] 37 | } 38 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "number", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "get", 13 | "y" 14 | ] 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": 1, 22 | "y": 1 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": 1, 31 | "y": 2 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": 1, 40 | "y": "1" 41 | } 42 | } 43 | ] 44 | ], 45 | "expected": { 46 | "compiled": { 47 | "result": "success", 48 | "isFeatureConstant": false, 49 | "isZoomConstant": true, 50 | "type": "boolean" 51 | }, 52 | "outputs": [ 53 | true, 54 | false, 55 | false 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/object/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "literal", 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "error", 16 | "errors": [ 17 | { 18 | "key": "[2]", 19 | "error": "\"==\" comparisons are not supported for type 'object'." 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/equal/string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "get", 13 | "y" 14 | ] 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": "1", 22 | "y": "1" 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": "1", 31 | "y": 2 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": "1", 40 | "y": 1 41 | } 42 | } 43 | ] 44 | ], 45 | "expected": { 46 | "compiled": { 47 | "result": "success", 48 | "isFeatureConstant": false, 49 | "isZoomConstant": true, 50 | "type": "boolean" 51 | }, 52 | "outputs": [ 53 | true, 54 | false, 55 | false 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/feature-state/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "feature-state", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ], 14 | [ 15 | {}, 16 | { 17 | "featureState": {} 18 | } 19 | ], 20 | [ 21 | {}, 22 | { 23 | "featureState": { 24 | "x": 1 25 | } 26 | } 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": false, 33 | "isZoomConstant": true, 34 | "type": "number" 35 | }, 36 | "outputs": [ 37 | { 38 | "error": "Expected value to be of type number, but found null instead." 39 | }, 40 | { 41 | "error": "Expected value to be of type number, but found null instead." 42 | }, 43 | 1 44 | ] 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/feature-state/expression-arg/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "feature-state", 6 | [ 7 | "at", 8 | 1, 9 | ["literal", ["e", "x", "e"]] 10 | ] 11 | ] 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | { 17 | "featureState": { 18 | "x": 1 19 | } 20 | } 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": false, 27 | "isZoomConstant": true, 28 | "type": "number" 29 | }, 30 | "outputs": [ 31 | 1 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/format/data-driven-scale/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "format", 4 | "a", 5 | { 6 | "text-font": [ 7 | "array", 8 | [ 9 | "string", 10 | [ 11 | "get", 12 | "text-font" 13 | ] 14 | ] 15 | ] 16 | } 17 | ], 18 | "inputs": [ 19 | [ 20 | {}, 21 | { 22 | "properties": { 23 | "text-font": "test" 24 | } 25 | } 26 | ] 27 | ], 28 | "expected": { 29 | "compiled": { 30 | "result": "error", 31 | "errors": [ 32 | { 33 | "key": "[1]", 34 | "error": "Expected array but found array instead." 35 | } 36 | ] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/format/implicit-assert/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "p" 7 | ] 8 | ], 9 | "propertySpec": { 10 | "type": "formatted", 11 | "property-type": "data-driven", 12 | "expression": { 13 | "interpolated": true, 14 | "parameters": [ 15 | "zoom", 16 | "feature" 17 | ] 18 | } 19 | }, 20 | "expected": { 21 | "compiled": { 22 | "result": "error", 23 | "errors": [ 24 | { 25 | "key": "", 26 | "error": "Expected formatted but found number instead." 27 | } 28 | ] 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/format/to-string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-string", 4 | [ 5 | "format", 6 | "a", 7 | {}, 8 | "b", 9 | { 10 | "font-scale": 2 11 | }, 12 | "c", 13 | { 14 | "text-font": [ 15 | "literal", 16 | [ 17 | "a", 18 | "b" 19 | ] 20 | ] 21 | } 22 | ] 23 | ], 24 | "inputs": [ 25 | [ 26 | {}, 27 | {} 28 | ] 29 | ], 30 | "expected": { 31 | "compiled": { 32 | "result": "success", 33 | "isFeatureConstant": true, 34 | "isZoomConstant": true, 35 | "type": "string" 36 | }, 37 | "outputs": [ 38 | "abc" 39 | ] 40 | } 41 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/format/unknown-vertical-align/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "format", 4 | "a", 5 | { 6 | "vertical-align": "unknown" 7 | } 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "error", 12 | "errors": [ 13 | { 14 | "key": "", 15 | "error": "'vertical-align' must be one of: 'bottom', 'center', 'top' but found 'unknown' instead." 16 | } 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/geometry-type/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "geometry-type" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | { 9 | "geometry": { 10 | "type": "LineString", 11 | "coordinates": 12 | [[0, 0], [10, 0]] 13 | } 14 | } 15 | ] 16 | ], 17 | "expected": { 18 | "compiled": { 19 | "result": "success", 20 | "isFeatureConstant": false, 21 | "isZoomConstant": true, 22 | "type": "string" 23 | }, 24 | "outputs": [ 25 | "LineString" 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/integration/expression/tests/get/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ], 14 | [ 15 | {}, 16 | { 17 | "properties": { 18 | "x": 1 19 | } 20 | } 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": false, 27 | "isZoomConstant": true, 28 | "type": "number" 29 | }, 30 | "outputs": [ 31 | { 32 | "error": "Expected value to be of type number, but found null instead." 33 | }, 34 | 1 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/get/from-literal--missing/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "x", 7 | [ 8 | "literal", 9 | { 10 | "y": 0 11 | } 12 | ] 13 | ] 14 | ], 15 | "inputs": [ 16 | [ 17 | {}, 18 | {} 19 | ] 20 | ], 21 | "expected": { 22 | "compiled": { 23 | "result": "error", 24 | "errors": [ 25 | { 26 | "key": "", 27 | "error": "Expected value to be of type number, but found null instead." 28 | } 29 | ] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/get/from-literal/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "x", 7 | [ 8 | "literal", 9 | { 10 | "x": 0 11 | } 12 | ] 13 | ] 14 | ], 15 | "inputs": [ 16 | [ 17 | {}, 18 | {} 19 | ] 20 | ], 21 | "expected": { 22 | "compiled": { 23 | "result": "success", 24 | "isFeatureConstant": true, 25 | "isZoomConstant": true, 26 | "type": "number" 27 | }, 28 | "outputs": [ 29 | 0 30 | ] 31 | } 32 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/get/from-object-property/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "x", 7 | [ 8 | "object", 9 | [ 10 | "get", 11 | "a" 12 | ] 13 | ] 14 | ] 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "a": { 22 | "x": 1 23 | } 24 | } 25 | } 26 | ] 27 | ], 28 | "expected": { 29 | "compiled": { 30 | "result": "success", 31 | "isFeatureConstant": false, 32 | "isZoomConstant": true, 33 | "type": "number" 34 | }, 35 | "outputs": [ 36 | 1 37 | ] 38 | } 39 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/global-state/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "global-state", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ], 14 | [ 15 | { 16 | "globalState": {} 17 | }, 18 | {} 19 | ], 20 | [ 21 | { 22 | "globalState": { 23 | "x": 1 24 | } 25 | }, 26 | {} 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": true, 33 | "isZoomConstant": true, 34 | "type": "number" 35 | }, 36 | "outputs": [ 37 | { 38 | "error": "Expected value to be of type number, but found null instead." 39 | }, 40 | { 41 | "error": "Expected value to be of type number, but found null instead." 42 | }, 43 | 1 44 | ] 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater/boolean/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "boolean", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "[1]", 25 | "error": "\">\" comparisons are not supported for type 'boolean'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater/null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">", 4 | null, 5 | null 6 | ], 7 | "expected": { 8 | "compiled": { 9 | "result": "error", 10 | "errors": [ 11 | { 12 | "key": "[1]", 13 | "error": "\">\" comparisons are not supported for type 'null'." 14 | } 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater/number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">", 4 | [ 5 | "number", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "inputs": [ 20 | [ 21 | {}, 22 | { 23 | "properties": { 24 | "x": 1, 25 | "y": 1 26 | } 27 | } 28 | ], 29 | [ 30 | {}, 31 | { 32 | "properties": { 33 | "x": 1, 34 | "y": 2 35 | } 36 | } 37 | ], 38 | [ 39 | {}, 40 | { 41 | "properties": { 42 | "x": 2, 43 | "y": 1 44 | } 45 | } 46 | ] 47 | ], 48 | "expected": { 49 | "compiled": { 50 | "result": "success", 51 | "isFeatureConstant": false, 52 | "isZoomConstant": true, 53 | "type": "boolean" 54 | }, 55 | "outputs": [ 56 | false, 57 | false, 58 | true 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater_or_equal/boolean/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">=", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "boolean", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "[1]", 25 | "error": "\">=\" comparisons are not supported for type 'boolean'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater_or_equal/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">=", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater_or_equal/null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">=", 4 | null, 5 | null 6 | ], 7 | "expected": { 8 | "compiled": { 9 | "result": "error", 10 | "errors": [ 11 | { 12 | "key": "[1]", 13 | "error": "\">=\" comparisons are not supported for type 'null'." 14 | } 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/greater_or_equal/number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | ">=", 4 | [ 5 | "number", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "inputs": [ 20 | [ 21 | {}, 22 | { 23 | "properties": { 24 | "x": 1, 25 | "y": 1 26 | } 27 | } 28 | ], 29 | [ 30 | {}, 31 | { 32 | "properties": { 33 | "x": 1, 34 | "y": 2 35 | } 36 | } 37 | ], 38 | [ 39 | {}, 40 | { 41 | "properties": { 42 | "x": 2, 43 | "y": 1 44 | } 45 | } 46 | ] 47 | ], 48 | "expected": { 49 | "compiled": { 50 | "result": "success", 51 | "isFeatureConstant": false, 52 | "isZoomConstant": true, 53 | "type": "boolean" 54 | }, 55 | "outputs": [ 56 | true, 57 | false, 58 | true 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/has/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "has", 4 | "x" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ], 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "x": 1 16 | } 17 | } 18 | ], 19 | [ 20 | {}, 21 | { 22 | "properties": { 23 | "x": 0 24 | } 25 | } 26 | ], 27 | [ 28 | {}, 29 | { 30 | "properties": { 31 | "x": false 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": null 40 | } 41 | } 42 | ] 43 | ], 44 | "expected": { 45 | "compiled": { 46 | "result": "success", 47 | "isFeatureConstant": false, 48 | "isZoomConstant": true, 49 | "type": "boolean" 50 | }, 51 | "outputs": [ 52 | false, 53 | true, 54 | true, 55 | true, 56 | true 57 | ] 58 | } 59 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/id/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "id" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ], 10 | [ 11 | {}, 12 | { 13 | "id": 1 14 | } 15 | ], 16 | [ 17 | {}, 18 | { 19 | "id": "one" 20 | } 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": false, 27 | "isZoomConstant": true, 28 | "type": "value" 29 | }, 30 | "outputs": [ 31 | null, 32 | 1, 33 | "one" 34 | ] 35 | } 36 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/image/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "image", 4 | "monument-15" 5 | ], 6 | "inputs": [ 7 | [ 8 | { 9 | "availableImages": [ 10 | "monument-15" 11 | ] 12 | }, 13 | {} 14 | ] 15 | ], 16 | "expected": { 17 | "compiled": { 18 | "result": "success", 19 | "isFeatureConstant": true, 20 | "isZoomConstant": true, 21 | "type": "resolvedImage" 22 | }, 23 | "outputs": [ 24 | { 25 | "name": "monument-15", 26 | "available": true 27 | } 28 | ] 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/image/coalesce/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "coalesce", 4 | [ 5 | "image", 6 | "foo" 7 | ], 8 | [ 9 | "image", 10 | "bar" 11 | ], 12 | [ 13 | "image", 14 | "monument-15" 15 | ] 16 | ], 17 | "propertySpec": { 18 | "type": "resolvedImage", 19 | "property-type": "data-driven", 20 | "expression": { 21 | "interpolated": true, 22 | "parameters": [ 23 | "zoom", 24 | "feature" 25 | ] 26 | } 27 | }, 28 | "inputs": [ 29 | [ 30 | { 31 | "availableImages": [ 32 | "monument-15" 33 | ] 34 | }, 35 | {} 36 | ] 37 | ], 38 | "expected": { 39 | "compiled": { 40 | "result": "success", 41 | "isFeatureConstant": true, 42 | "isZoomConstant": true, 43 | "type": "resolvedImage" 44 | }, 45 | "outputs": [ 46 | { 47 | "name": "monument-15", 48 | "available": true 49 | } 50 | ] 51 | } 52 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/image/compound/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "image", 4 | [ 5 | "get", 6 | "icon" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | { 12 | "availableImages": [ 13 | "monument-15" 14 | ] 15 | }, 16 | { 17 | "properties": { 18 | "icon": "monument-15" 19 | } 20 | } 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": false, 27 | "isZoomConstant": true, 28 | "type": "resolvedImage" 29 | }, 30 | "outputs": [ 31 | { 32 | "name": "monument-15", 33 | "available": true 34 | } 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/image/implicit-assert/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "icon" 7 | ] 8 | ], 9 | "propertySpec": { 10 | "type": "resolvedImage", 11 | "property-type": "data-driven", 12 | "expression": { 13 | "interpolated": true, 14 | "parameters": [ 15 | "zoom", 16 | "feature" 17 | ] 18 | } 19 | }, 20 | "expected": { 21 | "compiled": { 22 | "result": "error", 23 | "errors": [ 24 | { 25 | "key": "", 26 | "error": "Expected resolvedImage but found number instead." 27 | } 28 | ] 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/cubic-bezier-3-args/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "interpolate", 6 | [ 7 | "cubic-bezier", 8 | 0, 9 | 0, 10 | 1 11 | ], 12 | [ 13 | "number", 14 | [ 15 | "get", 16 | "x" 17 | ] 18 | ], 19 | 0, 20 | 0, 21 | 100, 22 | 100 23 | ] 24 | ], 25 | "inputs": [], 26 | "expected": { 27 | "compiled": { 28 | "result": "error", 29 | "errors": [ 30 | { 31 | "key": "[1][1]", 32 | "error": "Cubic bezier interpolation requires four numeric arguments with values between 0 and 1." 33 | } 34 | ] 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/cubic-bezier-5-args/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "interpolate", 6 | [ 7 | "cubic-bezier", 8 | 0, 9 | 0, 10 | 1, 11 | 1, 12 | 1 13 | ], 14 | [ 15 | "number", 16 | [ 17 | "get", 18 | "x" 19 | ] 20 | ], 21 | 0, 22 | 0, 23 | 100, 24 | 100 25 | ] 26 | ], 27 | "inputs": [], 28 | "expected": { 29 | "compiled": { 30 | "result": "error", 31 | "errors": [ 32 | { 33 | "key": "[1][1]", 34 | "error": "Cubic bezier interpolation requires four numeric arguments with values between 0 and 1." 35 | } 36 | ] 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/cubic-bezier-invalid-control-point/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "interpolate", 6 | [ 7 | "cubic-bezier", 8 | 0, 9 | 1.75, 10 | 1, 11 | 1 12 | ], 13 | [ 14 | "number", 15 | [ 16 | "get", 17 | "x" 18 | ] 19 | ], 20 | 0, 21 | 0, 22 | 100, 23 | 100 24 | ] 25 | ], 26 | "inputs": [], 27 | "expected": { 28 | "compiled": { 29 | "result": "error", 30 | "errors": [ 31 | { 32 | "key": "[1][1]", 33 | "error": "Cubic bezier interpolation requires four numeric arguments with values between 0 and 1." 34 | } 35 | ] 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/duplicate_stops/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "interpolate", 4 | [ 5 | "linear" 6 | ], 7 | 0, 8 | 0, 9 | 1, 10 | 0, 11 | 2 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | {} 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "[5]", 25 | "error": "Input/output pairs for \"interpolate\" expressions must be arranged with input values in strictly ascending order." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/exponential-single-stop/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "interpolate", 6 | [ 7 | "exponential", 8 | 2 9 | ], 10 | [ 11 | "number", 12 | [ 13 | "get", 14 | "x" 15 | ] 16 | ], 17 | 1, 18 | 2 19 | ] 20 | ], 21 | "inputs": [ 22 | [ 23 | {}, 24 | { 25 | "properties": { 26 | "x": 0 27 | } 28 | } 29 | ], 30 | [ 31 | {}, 32 | { 33 | "properties": { 34 | "x": 1 35 | } 36 | } 37 | ], 38 | [ 39 | {}, 40 | { 41 | "properties": { 42 | "x": 2 43 | } 44 | } 45 | ] 46 | ], 47 | "expected": { 48 | "compiled": { 49 | "result": "success", 50 | "isFeatureConstant": false, 51 | "isZoomConstant": true, 52 | "type": "number" 53 | }, 54 | "outputs": [ 55 | 2, 56 | 2, 57 | 2 58 | ] 59 | } 60 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/exponential-string-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "interpolate", 4 | [ 5 | "exponential", 6 | 2 7 | ], 8 | [ 9 | "number", 10 | [ 11 | "get", 12 | "x" 13 | ] 14 | ], 15 | 1, 16 | [ 17 | "literal", 18 | [ 19 | "a" 20 | ] 21 | ], 22 | 3, 23 | [ 24 | "literal", 25 | [ 26 | "b" 27 | ] 28 | ] 29 | ], 30 | "inputs": [], 31 | "expected": { 32 | "compiled": { 33 | "result": "error", 34 | "errors": [ 35 | { 36 | "key": "", 37 | "error": "Type array is not interpolatable." 38 | } 39 | ] 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/exponential-uninterpolatable-numeric-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "interpolate", 4 | [ 5 | "exponential", 6 | 2 7 | ], 8 | [ 9 | "number", 10 | [ 11 | "get", 12 | "x" 13 | ] 14 | ], 15 | 1, 16 | [ 17 | "array", 18 | "number", 19 | [ 20 | "get", 21 | "array" 22 | ] 23 | ], 24 | 3, 25 | [ 26 | "array", 27 | "number", 28 | [ 29 | "get", 30 | "array_two" 31 | ] 32 | ] 33 | ], 34 | "inputs": [], 35 | "expected": { 36 | "compiled": { 37 | "result": "error", 38 | "errors": [ 39 | { 40 | "key": "", 41 | "error": "Type array is not interpolatable." 42 | } 43 | ] 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/infer-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "step", 15 | [ 16 | "number", 17 | [ 18 | "get", 19 | "x" 20 | ] 21 | ], 22 | [ 23 | "literal", 24 | [ 25 | "one" 26 | ] 27 | ], 28 | 10, 29 | [ 30 | "literal", 31 | [ 32 | "one", 33 | "two" 34 | ] 35 | ] 36 | ], 37 | "inputs": [], 38 | "expected": { 39 | "compiled": { 40 | "result": "success", 41 | "isFeatureConstant": false, 42 | "isZoomConstant": true, 43 | "type": "array" 44 | }, 45 | "outputs": [] 46 | } 47 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/projection/higher-than-stop/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "projectionDefinition", 4 | "property-type": "data-constant", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "interpolate", 14 | [ 15 | "linear" 16 | ], 17 | [ 18 | "zoom" 19 | ], 20 | 0, 21 | "vertical-perspective", 22 | 4, 23 | "mercator" 24 | ], 25 | "inputs": [ 26 | [ 27 | { 28 | "zoom": 5 29 | }, 30 | {} 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "success", 36 | "isFeatureConstant": true, 37 | "isZoomConstant": false, 38 | "type": "projectionDefinition" 39 | }, 40 | "outputs": [ 41 | "mercator" 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/interpolate/projection/lower-than-stop/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "projectionDefinition", 4 | "property-type": "data-constant", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "interpolate", 14 | [ 15 | "linear" 16 | ], 17 | [ 18 | "zoom" 19 | ], 20 | 8, 21 | "vertical-perspective", 22 | 10, 23 | "mercator" 24 | ], 25 | "inputs": [ 26 | [ 27 | { 28 | "zoom": 5 29 | }, 30 | {} 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "success", 36 | "isFeatureConstant": true, 37 | "isZoomConstant": false, 38 | "type": "projectionDefinition" 39 | }, 40 | "outputs": [ 41 | "vertical-perspective" 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/is-supported-script/default/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "is-supported-script", 4 | [ 5 | "get", 6 | "x" 7 | ] 8 | ], 9 | "description": "'is-supported-script' always returns true when run without global context providing an 'isSupportedScript' function (as in the expression tests). The 'is-supported-script' render tests provide the necessary global context and exercise the functionality.", 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "x": "שָׁלוֹם" 16 | } 17 | } 18 | ], 19 | [ 20 | {}, 21 | { 22 | "properties": { 23 | "x": "देवनागरी" 24 | } 25 | } 26 | ] 27 | ], 28 | "expected": { 29 | "compiled": { 30 | "result": "success", 31 | "isFeatureConstant": false, 32 | "isZoomConstant": true, 33 | "type": "boolean" 34 | }, 35 | "outputs": [ 36 | true, 37 | true 38 | ] 39 | } 40 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/legacy/exponential/base/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": { 3 | "type": "exponential", 4 | "base": 0.5, 5 | "stops": [ 6 | [ 7 | 0, 8 | 0 9 | ], 10 | [ 11 | 1, 12 | 1 13 | ] 14 | ] 15 | }, 16 | "propertySpec": { 17 | "type": "number", 18 | "property-type": "data-driven", 19 | "expression": { 20 | "interpolated": true, 21 | "parameters": [ 22 | "zoom", 23 | "feature" 24 | ] 25 | } 26 | }, 27 | "inputs": [ 28 | [ 29 | { 30 | "zoom": 0.5 31 | }, 32 | {} 33 | ] 34 | ], 35 | "expected": { 36 | "compiled": { 37 | "result": "success", 38 | "isFeatureConstant": true, 39 | "isZoomConstant": false, 40 | "type": "number" 41 | }, 42 | "outputs": [ 43 | 0.585786 44 | ] 45 | } 46 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/legacy/exponential/duplicate-stops/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": { 3 | "type": "exponential", 4 | "stops": [ 5 | [ 6 | 0, 7 | 10 8 | ], 9 | [ 10 | 1, 11 | 20 12 | ], 13 | [ 14 | 1, 15 | 25 16 | ], 17 | [ 18 | 2, 19 | 30 20 | ] 21 | ] 22 | }, 23 | "propertySpec": { 24 | "type": "number", 25 | "property-type": "data-driven", 26 | "expression": { 27 | "interpolated": true, 28 | "parameters": [ 29 | "zoom", 30 | "feature" 31 | ] 32 | } 33 | }, 34 | "inputs": [ 35 | [ 36 | { 37 | "zoom": 1 38 | }, 39 | {} 40 | ] 41 | ], 42 | "expected": { 43 | "compiled": { 44 | "result": "success", 45 | "isFeatureConstant": true, 46 | "isZoomConstant": false, 47 | "type": "number" 48 | }, 49 | "outputs": [ 50 | 20 51 | ] 52 | } 53 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/legacy/interval/duplicate-stops/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": { 3 | "type": "interval", 4 | "stops": [ 5 | [ 6 | 0, 7 | "a" 8 | ], 9 | [ 10 | 1, 11 | "b" 12 | ], 13 | [ 14 | 1, 15 | "c" 16 | ], 17 | [ 18 | 2, 19 | "d" 20 | ] 21 | ] 22 | }, 23 | "propertySpec": { 24 | "type": "string", 25 | "property-type": "data-driven", 26 | "expression": { 27 | "interpolated": true, 28 | "parameters": [ 29 | "zoom", 30 | "feature" 31 | ] 32 | } 33 | }, 34 | "inputs": [ 35 | [ 36 | { 37 | "zoom": 1 38 | }, 39 | {} 40 | ] 41 | ], 42 | "expected": { 43 | "compiled": { 44 | "result": "success", 45 | "isFeatureConstant": true, 46 | "isZoomConstant": false, 47 | "type": "string" 48 | }, 49 | "outputs": [ 50 | "b" 51 | ] 52 | } 53 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/length/array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "length", 4 | [ 5 | "array", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | { 16 | "properties": { 17 | "x": [ 18 | 1, 19 | 2, 20 | 3, 21 | 4, 22 | 5 23 | ] 24 | } 25 | } 26 | ] 27 | ], 28 | "expected": { 29 | "compiled": { 30 | "result": "success", 31 | "isFeatureConstant": false, 32 | "isZoomConstant": true, 33 | "type": "number" 34 | }, 35 | "outputs": [ 36 | 5 37 | ] 38 | } 39 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/length/implicit/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "length", 4 | [ 5 | "get", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | { 13 | "properties": { 14 | "x": "a string" 15 | } 16 | } 17 | ], 18 | [ 19 | {}, 20 | { 21 | "properties": { 22 | "x": [] 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": 0 31 | } 32 | } 33 | ] 34 | ], 35 | "expected": { 36 | "compiled": { 37 | "result": "success", 38 | "isFeatureConstant": false, 39 | "isZoomConstant": true, 40 | "type": "number" 41 | }, 42 | "outputs": [ 43 | 8, 44 | 0, 45 | { 46 | "error": "Expected value to be of type string or array, but found number instead." 47 | } 48 | ] 49 | } 50 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/length/invalid/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "length", 4 | 0 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "error", 15 | "errors": [ 16 | { 17 | "key": "", 18 | "error": "Expected argument of type string or array, but found number instead." 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/length/string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "length", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | { 16 | "properties": { 17 | "x": "a string" 18 | } 19 | } 20 | ] 21 | ], 22 | "expected": { 23 | "compiled": { 24 | "result": "success", 25 | "isFeatureConstant": false, 26 | "isZoomConstant": true, 27 | "type": "number" 28 | }, 29 | "outputs": [ 30 | 8 31 | ] 32 | } 33 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less/boolean/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "boolean", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "[1]", 25 | "error": "\"<\" comparisons are not supported for type 'boolean'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less/null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<", 4 | null, 5 | null 6 | ], 7 | "expected": { 8 | "compiled": { 9 | "result": "error", 10 | "errors": [ 11 | { 12 | "key": "[1]", 13 | "error": "\"<\" comparisons are not supported for type 'null'." 14 | } 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less/number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<", 4 | [ 5 | "number", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "inputs": [ 20 | [ 21 | {}, 22 | { 23 | "properties": { 24 | "x": 1, 25 | "y": 1 26 | } 27 | } 28 | ], 29 | [ 30 | {}, 31 | { 32 | "properties": { 33 | "x": 1, 34 | "y": 2 35 | } 36 | } 37 | ], 38 | [ 39 | {}, 40 | { 41 | "properties": { 42 | "x": 2, 43 | "y": 1 44 | } 45 | } 46 | ] 47 | ], 48 | "expected": { 49 | "compiled": { 50 | "result": "success", 51 | "isFeatureConstant": false, 52 | "isZoomConstant": true, 53 | "type": "boolean" 54 | }, 55 | "outputs": [ 56 | false, 57 | true, 58 | false 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less_or_equal/boolean/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<=", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "boolean", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "[1]", 25 | "error": "\"<=\" comparisons are not supported for type 'boolean'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less_or_equal/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<=", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/less_or_equal/null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "<=", 4 | null, 5 | null 6 | ], 7 | "expected": { 8 | "compiled": { 9 | "result": "error", 10 | "errors": [ 11 | { 12 | "key": "[1]", 13 | "error": "\"<=\" comparisons are not supported for type 'null'." 14 | } 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | [ 6 | "number", 7 | [ 8 | "get", 9 | "a" 10 | ] 11 | ], 12 | "b", 13 | [ 14 | "number", 15 | [ 16 | "get", 17 | "b" 18 | ] 19 | ], 20 | [ 21 | "+", 22 | [ 23 | "+", 24 | [ 25 | "var", 26 | "a" 27 | ], 28 | [ 29 | "var", 30 | "b" 31 | ] 32 | ], 33 | [ 34 | "var", 35 | "a" 36 | ] 37 | ] 38 | ], 39 | "inputs": [ 40 | [ 41 | {}, 42 | { 43 | "properties": { 44 | "a": 1, 45 | "b": 2 46 | } 47 | } 48 | ] 49 | ], 50 | "expected": { 51 | "compiled": { 52 | "result": "success", 53 | "isFeatureConstant": false, 54 | "isZoomConstant": true, 55 | "type": "number" 56 | }, 57 | "outputs": [ 58 | 4 59 | ] 60 | } 61 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/invalid-name/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "$a", 5 | 1, 6 | [ 7 | "var", 8 | "$a" 9 | ] 10 | ], 11 | "inputs": [], 12 | "expected": { 13 | "compiled": { 14 | "result": "error", 15 | "errors": [ 16 | { 17 | "key": "[1]", 18 | "error": "Variable names must contain only alphanumeric characters or '_'." 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/nested/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | [ 6 | "number", 7 | [ 8 | "get", 9 | "a" 10 | ] 11 | ], 12 | [ 13 | "let", 14 | "b", 15 | [ 16 | "+", 17 | 1, 18 | [ 19 | "var", 20 | "a" 21 | ] 22 | ], 23 | [ 24 | "+", 25 | [ 26 | "var", 27 | "a" 28 | ], 29 | [ 30 | "var", 31 | "b" 32 | ] 33 | ] 34 | ] 35 | ], 36 | "inputs": [ 37 | [ 38 | {}, 39 | { 40 | "properties": { 41 | "a": 1 42 | } 43 | } 44 | ] 45 | ], 46 | "expected": { 47 | "compiled": { 48 | "result": "success", 49 | "isFeatureConstant": false, 50 | "isZoomConstant": true, 51 | "type": "number" 52 | }, 53 | "outputs": [ 54 | 3 55 | ] 56 | } 57 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/property-function/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | [ 6 | "get", 7 | "x" 8 | ], 9 | [ 10 | "+", 11 | 1, 12 | [ 13 | "number", 14 | [ 15 | "var", 16 | "a" 17 | ] 18 | ] 19 | ] 20 | ], 21 | "inputs": [ 22 | [ 23 | {}, 24 | { 25 | "properties": { 26 | "x": 5 27 | } 28 | } 29 | ] 30 | ], 31 | "expected": { 32 | "compiled": { 33 | "result": "success", 34 | "isFeatureConstant": false, 35 | "isZoomConstant": true, 36 | "type": "number" 37 | }, 38 | "outputs": [ 39 | 6 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/shadow/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | [ 6 | "get", 7 | "one" 8 | ], 9 | [ 10 | "let", 11 | "a", 12 | [ 13 | "get", 14 | "two" 15 | ], 16 | [ 17 | "var", 18 | "a" 19 | ] 20 | ] 21 | ], 22 | "inputs": [ 23 | [ 24 | {}, 25 | { 26 | "properties": { 27 | "one": 1, 28 | "two": 2 29 | } 30 | } 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "success", 36 | "isFeatureConstant": false, 37 | "isZoomConstant": true, 38 | "type": "value" 39 | }, 40 | "outputs": [ 41 | 2 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/let/unbound/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "a", 5 | 1, 6 | [ 7 | "+", 8 | [ 9 | "+", 10 | [ 11 | "var", 12 | "a" 13 | ], 14 | [ 15 | "var", 16 | "b" 17 | ] 18 | ], 19 | [ 20 | "var", 21 | "a" 22 | ] 23 | ] 24 | ], 25 | "expected": { 26 | "compiled": { 27 | "result": "error", 28 | "errors": [ 29 | { 30 | "key": "[3][1][2][1]", 31 | "error": "Unknown variable \"b\". Make sure \"b\" has been bound in an enclosing \"let\" expression before using it." 32 | } 33 | ] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/boolean-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | [ 5 | true, 6 | false 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "array" 21 | }, 22 | "outputs": [ 23 | [ 24 | true, 25 | false 26 | ] 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/empty/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "error", 14 | "errors": [ 15 | { 16 | "key": "", 17 | "error": "'literal' expression requires exactly one argument, but found 0 instead." 18 | } 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/infer-empty-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "number", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "literal", 15 | [] 16 | ], 17 | "inputs": [], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "array" 24 | }, 25 | "outputs": [] 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/literal-false/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | false 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "boolean" 18 | }, 19 | "outputs": [ 20 | false 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/literal-null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | null 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "null" 18 | }, 19 | "outputs": [ 20 | null 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/literal-number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | 7.5 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 7.5 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/literal-string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | "hello" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "string" 18 | }, 19 | "outputs": [ 20 | "hello" 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/literal-true/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | true 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "boolean" 18 | }, 19 | "outputs": [ 20 | true 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/mixed-primitive-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | [ 5 | 1, 6 | "2" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "array" 21 | }, 22 | "outputs": [ 23 | [ 24 | 1, 25 | "2" 26 | ] 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/multiple-args/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | {}, 5 | [] 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "error", 16 | "errors": [ 17 | { 18 | "key": "", 19 | "error": "'literal' expression requires exactly one argument, but found 2 instead." 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/nested-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | [ 5 | 1, 6 | [ 7 | 3, 8 | 4 9 | ] 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | {} 16 | ] 17 | ], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "array" 24 | }, 25 | "outputs": [ 26 | [ 27 | 1, 28 | [ 29 | 3, 30 | 4 31 | ] 32 | ] 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/number-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | [ 5 | 1, 6 | 2 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "array" 21 | }, 22 | "outputs": [ 23 | [ 24 | 1, 25 | 2 26 | ] 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/object/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | { 5 | "x": 1 6 | } 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "object" 20 | }, 21 | "outputs": [ 22 | { 23 | "x": 1 24 | } 25 | ] 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/string-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "literal", 4 | [ 5 | "1", 6 | "2" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "array" 21 | }, 22 | "outputs": [ 23 | [ 24 | "1", 25 | "2" 26 | ] 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": "ahoy!", 3 | "inputs": [ 4 | [ 5 | {}, 6 | {} 7 | ] 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "success", 12 | "isFeatureConstant": true, 13 | "isZoomConstant": true, 14 | "type": "string" 15 | }, 16 | "outputs": [ 17 | "ahoy!" 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/literal/u2028u2029/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": "ah

oy!", 3 | "inputs": [ 4 | [ 5 | {}, 6 | {} 7 | ] 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "success", 12 | "isFeatureConstant": true, 13 | "isZoomConstant": true, 14 | "type": "string" 15 | }, 16 | "outputs": [ 17 | "ah

oy!" 18 | ] 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/ln/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "ln", 4 | [ 5 | "e" 6 | ] 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "number" 20 | }, 21 | "outputs": [ 22 | 1 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/ln2/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "ln2" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "number" 17 | }, 18 | "outputs": [ 19 | 0.693147 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/log10/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "log10", 4 | 100 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 2 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/log2/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "log2", 4 | 1024 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 10 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match" 4 | ], 5 | "expected": { 6 | "compiled": { 7 | "result": "error", 8 | "errors": [ 9 | { 10 | "key": "", 11 | "error": "Expected at least 4 arguments, but found only 0." 12 | } 13 | ] 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | "x" 5 | ], 6 | "expected": { 7 | "compiled": { 8 | "result": "error", 9 | "errors": [ 10 | { 11 | "key": "", 12 | "error": "Expected at least 4 arguments, but found only 1." 13 | } 14 | ] 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/arity-2/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | "x", 5 | "y" 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "error", 16 | "errors": [ 17 | { 18 | "key": "", 19 | "error": "Expected at least 4 arguments, but found only 2." 20 | } 21 | ] 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/arity-3/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | "x", 5 | "y", 6 | "z" 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "error", 17 | "errors": [ 18 | { 19 | "key": "", 20 | "error": "Expected at least 4 arguments, but found only 3." 21 | } 22 | ] 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/empty-case/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [], 9 | "thing one", 10 | "thing two" 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "error", 15 | "errors": [ 16 | { 17 | "key": "[2]", 18 | "error": "Expected at least one branch label." 19 | } 20 | ] 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/infer-array-type/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "match", 15 | [ 16 | "number", 17 | [ 18 | "get", 19 | "x" 20 | ] 21 | ], 22 | 0, 23 | [ 24 | "literal", 25 | [ 26 | "one" 27 | ] 28 | ], 29 | 10, 30 | [ 31 | "literal", 32 | [ 33 | "one", 34 | "two" 35 | ] 36 | ], 37 | [ 38 | "literal", 39 | [ 40 | "one", 41 | "two", 42 | "three" 43 | ] 44 | ] 45 | ], 46 | "inputs": [], 47 | "expected": { 48 | "compiled": { 49 | "result": "success", 50 | "isFeatureConstant": false, 51 | "isZoomConstant": true, 52 | "type": "array" 53 | }, 54 | "outputs": [] 55 | } 56 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/label-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | "x", 5 | [ 6 | "string", 7 | [ 8 | "get", 9 | "y" 10 | ] 11 | ], 12 | "thing one", 13 | "thing two" 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "error", 18 | "errors": [ 19 | { 20 | "key": "[2]", 21 | "error": "Branch labels must be numbers or strings." 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/label-non-integer/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | 1, 5 | 1.5, 6 | "thing one", 7 | "thing two" 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "error", 12 | "errors": [ 13 | { 14 | "key": "[2]", 15 | "error": "Numeric branch labels must be integer values." 16 | } 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/label-null/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | null, 5 | null, 6 | "match", 7 | "otherwise" 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | { 13 | "properties": {} 14 | } 15 | ] 16 | ], 17 | "expected": { 18 | "compiled": { 19 | "result": "error", 20 | "errors": [ 21 | { 22 | "key": "[2]", 23 | "error": "Branch labels must be numbers or strings." 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/label-object/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | "x", 5 | {}, 6 | "thing one", 7 | "thing two" 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "error", 12 | "errors": [ 13 | { 14 | "key": "[2]", 15 | "error": "Branch labels must be numbers or strings." 16 | } 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/label-overflow/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | 0, 5 | 10000000000000000, 6 | "thing one", 7 | "thing two" 8 | ], 9 | "expected": { 10 | "compiled": { 11 | "result": "error", 12 | "errors": [ 13 | { 14 | "key": "[2]", 15 | "error": "Branch labels must be integers no larger than 9007199254740991." 16 | } 17 | ] 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/mismatch-input/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | 0, 12 | "match", 13 | "otherwise" 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "error", 18 | "errors": [ 19 | { 20 | "key": "[1]", 21 | "error": "Expected number but found string instead." 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/mismatch-label-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | "a", 9 | "the letter a", 10 | 0, 11 | "the number 0", 12 | true, 13 | "The Truth", 14 | "otherwise" 15 | ], 16 | "expected": { 17 | "compiled": { 18 | "result": "error", 19 | "errors": [ 20 | { 21 | "key": "[4]", 22 | "error": "Expected string but found number instead." 23 | } 24 | ] 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/mismatch-label-2/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "0", 10 | 0 11 | ], 12 | "zero", 13 | "otherwise" 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "error", 18 | "errors": [ 19 | { 20 | "key": "[2]", 21 | "error": "Expected string but found number instead." 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/mismatch-output/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | "0", 12 | "match", 13 | false 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "error", 18 | "errors": [ 19 | { 20 | "key": "[4]", 21 | "error": "Expected string but found boolean instead." 22 | } 23 | ] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/unreachable-branch-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | "0", 12 | "match", 13 | "0", 14 | "match", 15 | "otherwise" 16 | ], 17 | "expected": { 18 | "compiled": { 19 | "result": "error", 20 | "errors": [ 21 | { 22 | "key": "[4]", 23 | "error": "Branch labels must be unique." 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/match/unreachable-branch-2/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "match", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "0", 13 | "1" 14 | ], 15 | "match", 16 | [ 17 | "0", 18 | "2" 19 | ], 20 | "match", 21 | "otherwise" 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "error", 26 | "errors": [ 27 | { 28 | "key": "[4]", 29 | "error": "Branch labels must be unique." 30 | } 31 | ] 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/max/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all", 4 | [ 5 | "<", 6 | [ 7 | "max" 8 | ], 9 | 0 10 | ], 11 | [ 12 | "==", 13 | 0, 14 | [ 15 | "/", 16 | 1, 17 | [ 18 | "max" 19 | ] 20 | ] 21 | ] 22 | ], 23 | "inputs": [ 24 | [ 25 | {}, 26 | {} 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": true, 33 | "isZoomConstant": true, 34 | "type": "boolean" 35 | }, 36 | "outputs": [ 37 | true 38 | ] 39 | } 40 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/max/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "max", 4 | 1 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 1 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/max/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "max", 4 | 0, 5 | -1, 6 | 100 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "number" 20 | }, 21 | "outputs": [ 22 | 100 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/min/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "all", 4 | [ 5 | ">", 6 | [ 7 | "min" 8 | ], 9 | 0 10 | ], 11 | [ 12 | "==", 13 | 0, 14 | [ 15 | "/", 16 | 1, 17 | [ 18 | "min" 19 | ] 20 | ] 21 | ] 22 | ], 23 | "inputs": [ 24 | [ 25 | {}, 26 | {} 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": true, 33 | "isZoomConstant": true, 34 | "type": "boolean" 35 | }, 36 | "outputs": [ 37 | true 38 | ] 39 | } 40 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/min/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "min", 4 | 1 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 1 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/min/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "min", 4 | 0, 5 | -1, 6 | 10 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "number" 20 | }, 21 | "outputs": [ 22 | -1 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/minus/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "-" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "error", 14 | "errors": [ 15 | { 16 | "key": "", 17 | "error": "Expected arguments of type (number, number) | (number), but found () instead." 18 | } 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/minus/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "-", 4 | 5 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | -5 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/minus/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "-", 4 | 5, 5 | 7 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "success", 16 | "isFeatureConstant": true, 17 | "isZoomConstant": true, 18 | "type": "number" 19 | }, 20 | "outputs": [ 21 | -2 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/minus/inference-arity-2/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "-", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | 7 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "x": 0 16 | } 17 | } 18 | ] 19 | ], 20 | "expected": { 21 | "compiled": { 22 | "result": "success", 23 | "isFeatureConstant": false, 24 | "isZoomConstant": true, 25 | "type": "number" 26 | }, 27 | "outputs": [ 28 | -7 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/mod/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "%", 4 | 18, 5 | 12 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "success", 16 | "isFeatureConstant": true, 17 | "isZoomConstant": true, 18 | "type": "number" 19 | }, 20 | "outputs": [ 21 | 6 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/not/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "!", 4 | [ 5 | "boolean", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | { 16 | "properties": { 17 | "x": true 18 | } 19 | } 20 | ], 21 | [ 22 | {}, 23 | { 24 | "properties": { 25 | "x": false 26 | } 27 | } 28 | ] 29 | ], 30 | "expected": { 31 | "compiled": { 32 | "result": "success", 33 | "isFeatureConstant": false, 34 | "isZoomConstant": true, 35 | "type": "boolean" 36 | }, 37 | "outputs": [ 38 | false, 39 | true 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/not_equal/mismatch/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "!=", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "number", 13 | [ 14 | "get", 15 | "y" 16 | ] 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Cannot compare types 'string' and 'number'." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/not_equal/number/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "!=", 4 | [ 5 | "number", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "get", 13 | "y" 14 | ] 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": 1, 22 | "y": 1 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": 1, 31 | "y": "1" 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": 1, 40 | "y": 2 41 | } 42 | } 43 | ] 44 | ], 45 | "expected": { 46 | "compiled": { 47 | "result": "success", 48 | "isFeatureConstant": false, 49 | "isZoomConstant": true, 50 | "type": "boolean" 51 | }, 52 | "outputs": [ 53 | false, 54 | true, 55 | true 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/not_equal/string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "!=", 4 | [ 5 | "string", 6 | [ 7 | "get", 8 | "x" 9 | ] 10 | ], 11 | [ 12 | "get", 13 | "y" 14 | ] 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "x": "1", 22 | "y": "1" 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "x": "1", 31 | "y": 1 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": "1", 40 | "y": "2" 41 | } 42 | } 43 | ] 44 | ], 45 | "expected": { 46 | "compiled": { 47 | "result": "success", 48 | "isFeatureConstant": false, 49 | "isZoomConstant": true, 50 | "type": "boolean" 51 | }, 52 | "outputs": [ 53 | false, 54 | true, 55 | true 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/number-format/currency/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number-format", 4 | 123456.789, 5 | { 6 | "locale": [ 7 | "get", 8 | "locale" 9 | ], 10 | "currency": [ 11 | "get", 12 | "currency" 13 | ] 14 | } 15 | ], 16 | "inputs": [ 17 | [ 18 | {}, 19 | { 20 | "properties": { 21 | "locale": "en-US", 22 | "currency": "JPY" 23 | } 24 | } 25 | ], 26 | [ 27 | {}, 28 | { 29 | "properties": { 30 | "locale": "en-US", 31 | "currency": "EUR" 32 | } 33 | } 34 | ] 35 | ], 36 | "expected": { 37 | "compiled": { 38 | "result": "success", 39 | "isFeatureConstant": false, 40 | "isZoomConstant": true, 41 | "type": "string" 42 | }, 43 | "outputs": [ 44 | "¥123,457", 45 | "€123,456.79" 46 | ] 47 | } 48 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/number-format/default/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number-format", 4 | 123456.789, 5 | {} 6 | ], 7 | "inputs": [ 8 | [ 9 | {}, 10 | {} 11 | ] 12 | ], 13 | "expected": { 14 | "compiled": { 15 | "result": "success", 16 | "isFeatureConstant": true, 17 | "isZoomConstant": true, 18 | "type": "string" 19 | }, 20 | "outputs": [ 21 | "123,456.789" 22 | ] 23 | } 24 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/number/default-value/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "number", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | -1 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "x": 1 16 | } 17 | } 18 | ], 19 | [ 20 | {}, 21 | { 22 | "properties": { 23 | "x": "1" 24 | } 25 | } 26 | ], 27 | [ 28 | {}, 29 | { 30 | "properties": { 31 | "x": false 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": null 40 | } 41 | } 42 | ] 43 | ], 44 | "expected": { 45 | "compiled": { 46 | "result": "success", 47 | "isFeatureConstant": false, 48 | "isZoomConstant": true, 49 | "type": "number" 50 | }, 51 | "outputs": [ 52 | 1, 53 | -1, 54 | -1, 55 | -1 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/object/implicit/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "get", 4 | "b", 5 | [ 6 | "get", 7 | "a" 8 | ] 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "a": { 16 | "b": 0 17 | } 18 | } 19 | } 20 | ], 21 | [ 22 | {}, 23 | { 24 | "properties": { 25 | "a": "not" 26 | } 27 | } 28 | ] 29 | ], 30 | "expected": { 31 | "compiled": { 32 | "result": "success", 33 | "isFeatureConstant": false, 34 | "isZoomConstant": true, 35 | "type": "value" 36 | }, 37 | "outputs": [ 38 | 0, 39 | { 40 | "error": "Expected value to be of type object, but found string instead." 41 | } 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/parse/empty/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [], 3 | "expected": { 4 | "compiled": { 5 | "result": "error", 6 | "errors": [ 7 | { 8 | "key": "", 9 | "error": "Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []]." 10 | } 11 | ] 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/parse/non-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | [ 5 | "-", 6 | 0, 7 | {} 8 | ], 9 | 10 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "error", 14 | "errors": [ 15 | { 16 | "key": "[1][2]", 17 | "error": "Bare objects invalid. Use [\"literal\", {...}] instead." 18 | } 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/parse/non-string/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | 1, 4 | 2 5 | ], 6 | "expected": { 7 | "compiled": { 8 | "result": "error", 9 | "errors": [ 10 | { 11 | "key": "[0]", 12 | "error": "Expression name must be a string, but found number instead. If you wanted a literal array, use [\"literal\", [...]]." 13 | } 14 | ] 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/parse/unknown-expression/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | [ 5 | "*", 6 | 1, 7 | 2, 8 | 3, 9 | [ 10 | "FAKE-EXPRESSION", 11 | 1 12 | ] 13 | ], 14 | 10 15 | ], 16 | "expected": { 17 | "compiled": { 18 | "result": "error", 19 | "errors": [ 20 | { 21 | "key": "[1][4][0]", 22 | "error": "Unknown expression \"FAKE-EXPRESSION\". If you wanted a literal array, use [\"literal\", [...]]." 23 | } 24 | ] 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/pi/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "pi" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "number" 17 | }, 18 | "outputs": [ 19 | 3.14159 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/plus/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "number" 17 | }, 18 | "outputs": [ 19 | 0 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/plus/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | 1 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 1 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/plus/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | 1, 5 | 2, 6 | 3, 7 | 4 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "number" 21 | }, 22 | "outputs": [ 23 | 10 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/pow/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "^", 4 | 4, 5 | [ 6 | "number", 7 | [ 8 | "get", 9 | "x" 10 | ] 11 | ] 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | { 17 | "properties": { 18 | "x": 2 19 | } 20 | } 21 | ], 22 | [ 23 | {}, 24 | { 25 | "properties": { 26 | "x": 0.5 27 | } 28 | } 29 | ] 30 | ], 31 | "expected": { 32 | "compiled": { 33 | "result": "success", 34 | "isFeatureConstant": false, 35 | "isZoomConstant": true, 36 | "type": "number" 37 | }, 38 | "outputs": [ 39 | 16, 40 | 2 41 | ] 42 | } 43 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/properties/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "properties" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | { 9 | "properties": { 10 | "x": 5 11 | } 12 | } 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": false, 19 | "isZoomConstant": true, 20 | "type": "object" 21 | }, 22 | "outputs": [ 23 | { 24 | "x": 5 25 | } 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/resolved-locale/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "==", 4 | [ 5 | "resolved-locale", 6 | [ 7 | "collator", 8 | { 9 | "case-sensitive": true, 10 | "diacritic-sensitive": true, 11 | "locale": "en" 12 | } 13 | ] 14 | ], 15 | "en" 16 | ], 17 | "inputs": [ 18 | [ 19 | {}, 20 | {} 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": true, 27 | "isZoomConstant": true, 28 | "type": "boolean" 29 | }, 30 | "outputs": [ 31 | true 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/rgb/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "rgb", 4 | 0, 5 | 0, 6 | 255 7 | ], 8 | "inputs": [ 9 | [ 10 | {}, 11 | {} 12 | ] 13 | ], 14 | "expected": { 15 | "compiled": { 16 | "result": "success", 17 | "isFeatureConstant": true, 18 | "isZoomConstant": true, 19 | "type": "color" 20 | }, 21 | "outputs": [ 22 | [ 23 | 0, 24 | 0, 25 | 1, 26 | 1 27 | ] 28 | ] 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/rgba/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "rgba", 4 | 0, 5 | 0, 6 | 255, 7 | 1 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "color" 21 | }, 22 | "outputs": [ 23 | [ 24 | 0, 25 | 0, 26 | 1, 27 | 1 28 | ] 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/sin/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "sin", 4 | 0 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 0 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/sqrt/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "sqrt", 4 | [ 5 | "get", 6 | "x" 7 | ] 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | { 13 | "properties": { 14 | "x": 4 15 | } 16 | } 17 | ], 18 | [ 19 | {}, 20 | { 21 | "properties": { 22 | "x": 0.25 23 | } 24 | } 25 | ] 26 | ], 27 | "expected": { 28 | "compiled": { 29 | "result": "success", 30 | "isFeatureConstant": false, 31 | "isZoomConstant": true, 32 | "type": "number" 33 | }, 34 | "outputs": [ 35 | 2, 36 | 0.5 37 | ] 38 | } 39 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/step/duplicate_stops/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "step", 4 | 0, 5 | "a", 6 | 0, 7 | "b", 8 | 0, 9 | "c" 10 | ], 11 | "inputs": [ 12 | [ 13 | {}, 14 | {} 15 | ] 16 | ], 17 | "expected": { 18 | "compiled": { 19 | "result": "error", 20 | "errors": [ 21 | { 22 | "key": "[5]", 23 | "error": "Input/output pairs for \"step\" expressions must be arranged with input values in strictly ascending order." 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/step/projection/step-array/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "projectionDefinition", 4 | "property-type": "data-constant", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "step", 14 | [ 15 | "zoom" 16 | ], 17 | ["literal", ["vertical-perspective","mercator",0.9]], 18 | 10, 19 | "mercator" 20 | ], 21 | "inputs": [ 22 | [ 23 | { 24 | "zoom": 5 25 | }, 26 | {} 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": true, 33 | "isZoomConstant": false, 34 | "type": "projectionDefinition" 35 | }, 36 | "outputs": [ 37 | [ 38 | "vertical-perspective", 39 | "mercator", 40 | 0.9 41 | ] 42 | ] 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/step/projection/step-primitive/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "projectionDefinition", 4 | "property-type": "data-constant", 5 | "expression": { 6 | "interpolated": true, 7 | "parameters": [ 8 | "zoom" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "step", 14 | [ 15 | "zoom" 16 | ], 17 | "vertical-perspective", 18 | 10, 19 | "mercator" 20 | ], 21 | "inputs": [ 22 | [ 23 | { 24 | "zoom": 5 25 | }, 26 | {} 27 | ] 28 | ], 29 | "expected": { 30 | "compiled": { 31 | "result": "success", 32 | "isFeatureConstant": true, 33 | "isZoomConstant": false, 34 | "type": "projectionDefinition" 35 | }, 36 | "outputs": [ 37 | 38 | "vertical-perspective" 39 | 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/string/default-value/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "string", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | "default" 9 | ], 10 | "inputs": [ 11 | [ 12 | {}, 13 | { 14 | "properties": { 15 | "x": "1" 16 | } 17 | } 18 | ], 19 | [ 20 | {}, 21 | { 22 | "properties": { 23 | "x": 1 24 | } 25 | } 26 | ], 27 | [ 28 | {}, 29 | { 30 | "properties": { 31 | "x": false 32 | } 33 | } 34 | ], 35 | [ 36 | {}, 37 | { 38 | "properties": { 39 | "x": null 40 | } 41 | } 42 | ] 43 | ], 44 | "expected": { 45 | "compiled": { 46 | "result": "success", 47 | "isFeatureConstant": false, 48 | "isZoomConstant": true, 49 | "type": "string" 50 | }, 51 | "outputs": [ 52 | "1", 53 | "default", 54 | "default", 55 | "default" 56 | ] 57 | } 58 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/tan/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "tan", 4 | 0.7853981633974483 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 0.999999 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/times/arity-0/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "*" 4 | ], 5 | "inputs": [ 6 | [ 7 | {}, 8 | {} 9 | ] 10 | ], 11 | "expected": { 12 | "compiled": { 13 | "result": "success", 14 | "isFeatureConstant": true, 15 | "isZoomConstant": true, 16 | "type": "number" 17 | }, 18 | "outputs": [ 19 | 1 20 | ] 21 | } 22 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/times/arity-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "*", 4 | 0 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "number" 18 | }, 19 | "outputs": [ 20 | 0 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/times/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "*", 4 | 3, 5 | 2, 6 | 0.5, 7 | 2 8 | ], 9 | "inputs": [ 10 | [ 11 | {}, 12 | {} 13 | ] 14 | ], 15 | "expected": { 16 | "compiled": { 17 | "result": "success", 18 | "isFeatureConstant": true, 19 | "isZoomConstant": true, 20 | "type": "number" 21 | }, 22 | "outputs": [ 23 | 6 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-boolean/2-ary/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-boolean", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "get", 10 | "y" 11 | ] 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | {} 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Expected one argument." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-color/color/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-color", 4 | [ 5 | "rgba", 6 | 0, 7 | 0, 8 | 0, 9 | 1 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | {} 16 | ] 17 | ], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "color" 24 | }, 25 | "outputs": [ 26 | [ 27 | 0, 28 | 0, 29 | 0, 30 | 1 31 | ] 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-rgba/alpha/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-rgba", 4 | [ 5 | "rgba", 6 | 0, 7 | 128, 8 | 255, 9 | 0.5 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | {} 16 | ] 17 | ], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "array" 24 | }, 25 | "outputs": [ 26 | [ 27 | 0, 28 | 128, 29 | 255, 30 | 0.5 31 | ] 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-rgba/zero/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-rgba", 4 | [ 5 | "rgba", 6 | 0, 7 | 0, 8 | 0, 9 | 0 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | {} 16 | ] 17 | ], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "array" 24 | }, 25 | "outputs": [ 26 | [ 27 | 0, 28 | 0, 29 | 0, 30 | 0 31 | ] 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-string/2-ary/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-string", 4 | [ 5 | "get", 6 | "x" 7 | ], 8 | [ 9 | "get", 10 | "y" 11 | ] 12 | ], 13 | "inputs": [ 14 | [ 15 | {}, 16 | {} 17 | ] 18 | ], 19 | "expected": { 20 | "compiled": { 21 | "result": "error", 22 | "errors": [ 23 | { 24 | "key": "", 25 | "error": "Expected one argument." 26 | } 27 | ] 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-string/color/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "to-string", 4 | [ 5 | "rgba", 6 | 85, 7 | 255, 8 | 0, 9 | 0.5 10 | ] 11 | ], 12 | "inputs": [ 13 | [ 14 | {}, 15 | {} 16 | ] 17 | ], 18 | "expected": { 19 | "compiled": { 20 | "result": "success", 21 | "isFeatureConstant": true, 22 | "isZoomConstant": true, 23 | "type": "string" 24 | }, 25 | "outputs": [ 26 | "rgba(85,255,0,0.5)" 27 | ] 28 | } 29 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/to-string/implicit/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "get", 4 | "p" 5 | ], 6 | "propertySpec": { 7 | "type": "string", 8 | "property-type": "data-driven", 9 | "expression": { 10 | "interpolated": true, 11 | "parameters": [ 12 | "zoom", 13 | "feature" 14 | ] 15 | } 16 | }, 17 | "inputs": [ 18 | [ 19 | {}, 20 | { 21 | "properties": {} 22 | } 23 | ], 24 | [ 25 | {}, 26 | { 27 | "properties": { 28 | "p": 0 29 | } 30 | } 31 | ], 32 | [ 33 | {}, 34 | { 35 | "properties": { 36 | "p": "a" 37 | } 38 | } 39 | ] 40 | ], 41 | "expected": { 42 | "compiled": { 43 | "result": "success", 44 | "isFeatureConstant": false, 45 | "isZoomConstant": true, 46 | "type": "string" 47 | }, 48 | "outputs": [ 49 | "", 50 | "0", 51 | "a" 52 | ] 53 | } 54 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/typecheck/array-invalid-item/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "length": 2, 6 | "property-type": "data-driven", 7 | "expression": { 8 | "parameters": [ 9 | "zoom", 10 | "feature" 11 | ] 12 | } 13 | }, 14 | "expression": [ 15 | "array", 16 | "number", 17 | 2, 18 | [ 19 | "get", 20 | "x" 21 | ] 22 | ], 23 | "inputs": [], 24 | "expected": { 25 | "compiled": { 26 | "result": "error", 27 | "errors": [ 28 | { 29 | "key": "", 30 | "error": "Expected array but found array instead." 31 | } 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/typecheck/array-item-subtyping/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "property-type": "data-driven", 5 | "expression": { 6 | "parameters": [ 7 | "zoom", 8 | "feature" 9 | ] 10 | } 11 | }, 12 | "expression": [ 13 | "array", 14 | "number", 15 | 2, 16 | [ 17 | "get", 18 | "x" 19 | ] 20 | ], 21 | "inputs": [], 22 | "expected": { 23 | "compiled": { 24 | "result": "success", 25 | "isFeatureConstant": false, 26 | "isZoomConstant": true, 27 | "type": "array" 28 | }, 29 | "outputs": [] 30 | } 31 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/typecheck/array-length-subtyping--no-length/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "number", 5 | "length": 3, 6 | "property-type": "data-driven", 7 | "expression": { 8 | "parameters": [ 9 | "zoom", 10 | "feature" 11 | ] 12 | } 13 | }, 14 | "expression": [ 15 | "array", 16 | "number", 17 | [ 18 | "get", 19 | "x" 20 | ] 21 | ], 22 | "inputs": [], 23 | "expected": { 24 | "compiled": { 25 | "result": "error", 26 | "errors": [ 27 | { 28 | "key": "", 29 | "error": "Expected array but found array instead." 30 | } 31 | ] 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/typecheck/array-length-subtyping/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "string", 5 | "property-type": "data-driven", 6 | "expression": { 7 | "parameters": [ 8 | "zoom", 9 | "feature" 10 | ] 11 | } 12 | }, 13 | "expression": [ 14 | "array", 15 | "string", 16 | 2, 17 | [ 18 | "get", 19 | "x" 20 | ] 21 | ], 22 | "inputs": [], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": false, 27 | "isZoomConstant": true, 28 | "type": "array" 29 | }, 30 | "outputs": [] 31 | } 32 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/typecheck/array-wrong-length/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "propertySpec": { 3 | "type": "array", 4 | "value": "number", 5 | "length": 3, 6 | "property-type": "data-driven", 7 | "expression": { 8 | "parameters": [ 9 | "zoom", 10 | "feature" 11 | ] 12 | } 13 | }, 14 | "expression": [ 15 | "array", 16 | "number", 17 | 2, 18 | [ 19 | "get", 20 | "x" 21 | ] 22 | ], 23 | "inputs": [], 24 | "expected": { 25 | "compiled": { 26 | "result": "error", 27 | "errors": [ 28 | { 29 | "key": "", 30 | "error": "Expected array but found array instead." 31 | } 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/upcase/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "upcase", 4 | "string" 5 | ], 6 | "inputs": [ 7 | [ 8 | {}, 9 | {} 10 | ] 11 | ], 12 | "expected": { 13 | "compiled": { 14 | "result": "success", 15 | "isFeatureConstant": true, 16 | "isZoomConstant": true, 17 | "type": "string" 18 | }, 19 | "outputs": [ 20 | "STRING" 21 | ] 22 | } 23 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/basic/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "interpolate", 4 | [ 5 | "linear" 6 | ], 7 | [ 8 | "zoom" 9 | ], 10 | 0, 11 | 0, 12 | 30, 13 | 30 14 | ], 15 | "inputs": [ 16 | [ 17 | { 18 | "zoom": 5 19 | }, 20 | {} 21 | ] 22 | ], 23 | "expected": { 24 | "compiled": { 25 | "result": "success", 26 | "isFeatureConstant": true, 27 | "isZoomConstant": false, 28 | "type": "number" 29 | }, 30 | "outputs": [ 31 | 5 32 | ] 33 | } 34 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-nested-1/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | 0.5, 5 | [ 6 | "interpolate", 7 | [ 8 | "linear" 9 | ], 10 | [ 11 | "zoom" 12 | ], 13 | 0, 14 | 0, 15 | 1, 16 | 1 17 | ] 18 | ], 19 | "inputs": [ 20 | [ 21 | {}, 22 | {} 23 | ] 24 | ], 25 | "expected": { 26 | "compiled": { 27 | "result": "error", 28 | "errors": [ 29 | { 30 | "key": "", 31 | "error": "\"zoom\" expression may only be used as input to a top-level \"step\" or \"interpolate\" expression." 32 | } 33 | ] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-nested-2/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "interpolate", 4 | [ 5 | "linear" 6 | ], 7 | [ 8 | "zoom" 9 | ], 10 | 0, 11 | 0, 12 | 1, 13 | [ 14 | "interpolate", 15 | [ 16 | "linear" 17 | ], 18 | [ 19 | "zoom" 20 | ], 21 | 0, 22 | 0, 23 | 1, 24 | 1 25 | ] 26 | ], 27 | "inputs": [ 28 | [ 29 | {}, 30 | {} 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "error", 36 | "errors": [ 37 | { 38 | "key": "", 39 | "error": "Only one zoom-based \"step\" or \"interpolate\" subexpression may be used in an expression." 40 | } 41 | ] 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-nested-3/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "x", 5 | [ 6 | "interpolate", 7 | [ 8 | "linear" 9 | ], 10 | [ 11 | "zoom" 12 | ], 13 | 0, 14 | 0, 15 | 1, 16 | 1 17 | ], 18 | [ 19 | "interpolate", 20 | [ 21 | "linear" 22 | ], 23 | [ 24 | "zoom" 25 | ], 26 | 0, 27 | 0, 28 | 1, 29 | 1 30 | ] 31 | ], 32 | "inputs": [ 33 | [ 34 | {}, 35 | {} 36 | ] 37 | ], 38 | "expected": { 39 | "compiled": { 40 | "result": "error", 41 | "errors": [ 42 | { 43 | "key": "", 44 | "error": "Only one zoom-based \"step\" or \"interpolate\" subexpression may be used in an expression." 45 | } 46 | ] 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-nested-4/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "coalesce", 4 | [ 5 | "interpolate", 6 | [ 7 | "linear" 8 | ], 9 | [ 10 | "zoom" 11 | ], 12 | 0, 13 | 0, 14 | 1, 15 | 1 16 | ], 17 | [ 18 | "interpolate", 19 | [ 20 | "linear" 21 | ], 22 | [ 23 | "zoom" 24 | ], 25 | 0, 26 | 0, 27 | 1, 28 | 1 29 | ] 30 | ], 31 | "inputs": [ 32 | [ 33 | {}, 34 | {} 35 | ] 36 | ], 37 | "expected": { 38 | "compiled": { 39 | "result": "error", 40 | "errors": [ 41 | { 42 | "key": "", 43 | "error": "Only one zoom-based \"step\" or \"interpolate\" subexpression may be used in an expression." 44 | } 45 | ] 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-nested-5/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "x", 5 | [ 6 | "interpolate", 7 | [ 8 | "linear" 9 | ], 10 | [ 11 | "zoom" 12 | ], 13 | 0, 14 | 0, 15 | 1, 16 | 1 17 | ], 18 | [ 19 | "+", 20 | 0.5, 21 | [ 22 | "get", 23 | "x" 24 | ] 25 | ] 26 | ], 27 | "inputs": [ 28 | [ 29 | {}, 30 | {} 31 | ] 32 | ], 33 | "expected": { 34 | "compiled": { 35 | "result": "error", 36 | "errors": [ 37 | { 38 | "key": "", 39 | "error": "\"zoom\" expression may only be used as input to a top-level \"step\" or \"interpolate\" expression." 40 | } 41 | ] 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/invalid-no-curve/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "+", 4 | [ 5 | "zoom" 6 | ], 7 | 0 8 | ], 9 | "inputs": [ 10 | [ 11 | { 12 | "zoom": 5 13 | }, 14 | {} 15 | ] 16 | ], 17 | "expected": { 18 | "compiled": { 19 | "result": "error", 20 | "errors": [ 21 | { 22 | "key": "", 23 | "error": "\"zoom\" expression may only be used as input to a top-level \"step\" or \"interpolate\" expression." 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/nested-coalesce/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "coalesce", 4 | [ 5 | "interpolate", 6 | [ 7 | "linear" 8 | ], 9 | [ 10 | "zoom" 11 | ], 12 | 0, 13 | 0, 14 | 30, 15 | 30 16 | ] 17 | ], 18 | "inputs": [ 19 | [ 20 | { 21 | "zoom": 5 22 | }, 23 | {} 24 | ] 25 | ], 26 | "expected": { 27 | "compiled": { 28 | "result": "success", 29 | "isFeatureConstant": true, 30 | "isZoomConstant": false, 31 | "type": "number" 32 | }, 33 | "outputs": [ 34 | 5 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /test/integration/expression/tests/zoom/nested-let/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "expression": [ 3 | "let", 4 | "x", 5 | [ 6 | "number", 7 | [ 8 | "get", 9 | "a" 10 | ] 11 | ], 12 | [ 13 | "interpolate", 14 | [ 15 | "linear" 16 | ], 17 | [ 18 | "zoom" 19 | ], 20 | 0, 21 | 0, 22 | 30, 23 | [ 24 | "var", 25 | "x" 26 | ] 27 | ] 28 | ], 29 | "inputs": [ 30 | [ 31 | { 32 | "zoom": 5 33 | }, 34 | { 35 | "a": 30 36 | } 37 | ] 38 | ], 39 | "expected": { 40 | "compiled": { 41 | "result": "success", 42 | "isFeatureConstant": false, 43 | "isZoomConstant": false, 44 | "type": "number" 45 | }, 46 | "outputs": [ 47 | { 48 | "error": "Expected value to be of type number, but found null instead." 49 | } 50 | ] 51 | } 52 | } -------------------------------------------------------------------------------- /test/integration/style-spec/tests/bad-color.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[0].paint.fill-color: color expected, array found", 4 | "line": 16 5 | }, 6 | { 7 | "message": "layers[0].paint.fill-outline-color: color expected, \"not a color\" found", 8 | "line": 17 9 | }, 10 | { 11 | "message": "layers[1].paint.fill-outline-color: color expected, array found", 12 | "line": 26 13 | } 14 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/bad-color.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[0].paint.fill-color: color expected, array found", 4 | "line": 16 5 | }, 6 | { 7 | "message": "layers[0].paint.fill-outline-color: color expected, \"not a color\" found", 8 | "line": 17 9 | }, 10 | { 11 | "message": "layers[1].paint.fill-outline-color: color expected, array found", 12 | "line": 26 13 | }, 14 | { 15 | "message": "layers[2].paint.fill-color: color expected, \"__proto__\" found", 16 | "line": 35 17 | }, 18 | { 19 | "message": "layers[2].paint.fill-outline-color.stops[0][1]: color expected, \"valueOf\" found", 20 | "line": 39 21 | }, 22 | { 23 | "message": "layers[2].paint.fill-outline-color.stops[1][1]: color expected, \"__proto__\" found", 24 | "line": 40 25 | } 26 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/center-altitude.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "centerAltitude": "123.4", 4 | "sources": {}, 5 | "layers": [] 6 | } 7 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/center-altitude.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "centerAltitude: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/center-altitude.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "centerAltitude: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/constants.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "vector": { 5 | "type": "vector", 6 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 7 | } 8 | }, 9 | "constants": { 10 | "@mapbox": "#fff" 11 | }, 12 | "layers": [ 13 | { 14 | "id": "constant", 15 | "type": "fill", 16 | "source": "vector", 17 | "source-layer": "layer", 18 | "paint": { 19 | "fill-color": "#fff" 20 | } 21 | }, 22 | { 23 | "id": "color-op", 24 | "type": "fill", 25 | "source": "vector", 26 | "source-layer": "layer", 27 | "paint": { 28 | "fill-color": ["lighten", -20, "#000"] 29 | } 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/constants.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "constants: constants have been deprecated as of v8", 4 | "line": 9 5 | }, 6 | { 7 | "message": "layers[1].paint.fill-color: color expected, array found", 8 | "line": 28 9 | }, 10 | { 11 | "message": "Unsupported property \"constants\"", 12 | "line": 9 13 | } 14 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/constants.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "constants: constants have been deprecated as of v8", 4 | "line": 9 5 | }, 6 | { 7 | "message": "layers[1].paint.fill-color: color expected, array found", 8 | "line": 28 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/extrakeys.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": {}, 4 | "layers": [ 5 | { 6 | "id": "bad-constant", 7 | "type": "background", 8 | "paint": { 9 | "background-color": "#000" 10 | } 11 | } 12 | ], 13 | "extrakey": { 14 | "foo": "bar" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/extrakeys.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "Unsupported property \"extrakey\"", 4 | "line": 13 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/extrakeys.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light-arbitrary.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "vector": { 5 | "type": "vector", 6 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 7 | } 8 | }, 9 | "light": { 10 | "anchor": "map", 11 | "position": [1, 90, 90], 12 | "color": "white", 13 | "intensity": 0.75, 14 | "foo": "bar" 15 | }, 16 | "layers": [] 17 | } 18 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light-arbitrary.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "foo: unknown property \"foo\"", 4 | "line": 14 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light-arbitrary.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "foo: unknown property \"foo\"", 4 | "line": 14 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light-malformed-color.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "vector": { 5 | "type": "vector", 6 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 7 | } 8 | }, 9 | "light": { 10 | "anchor": "map", 11 | "position": [1, 90, 90], 12 | "color": "__proto__", 13 | "intensity": 0.75 14 | }, 15 | "layers": [] 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light-malformed-color.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "color: color expected, \"__proto__\" found", 4 | "line": 12 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "vector": { 5 | "type": "vector", 6 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 7 | } 8 | }, 9 | "light": { 10 | "anchor": true, 11 | "position": [1, 2], 12 | "color": [255, 255, 255, 1], 13 | "intensity": 1.5 14 | }, 15 | "layers": [] 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "anchor: expected one of [map, viewport], true found", 4 | "line": 10 5 | }, 6 | { 7 | "message": "position: array length 3 expected, length 2 found", 8 | "line": 11 9 | }, 10 | { 11 | "message": "color: color expected, array found", 12 | "line": 12 13 | }, 14 | { 15 | "message": "intensity: 1.5 is greater than the maximum value 1", 16 | "line": 13 17 | } 18 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/light.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "anchor: expected one of [map, viewport], true found", 4 | "line": 10 5 | }, 6 | { 7 | "message": "position: array length 3 expected, length 2 found", 8 | "line": 11 9 | }, 10 | { 11 | "message": "color: color expected, array found", 12 | "line": 12 13 | }, 14 | { 15 | "message": "intensity: 1.5 is greater than the maximum value 1", 16 | "line": 13 17 | } 18 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs-type.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "glyphs": true, 4 | "sources": { 5 | "vector": { 6 | "type": "vector", 7 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 8 | } 9 | }, 10 | "layers": [ 11 | { 12 | "id": "minimum", 13 | "type": "symbol", 14 | "source": "vector", 15 | "source-layer": "layer", 16 | "layout": { 17 | "text-font": ["Helvetica"], 18 | "text-field": "{foo}" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs-type.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: string expected, boolean found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs-type.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: string expected, boolean found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "glyphs": "https://example.com", 4 | "sources": { 5 | "vector": { 6 | "type": "vector", 7 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 8 | } 9 | }, 10 | "layers": [ 11 | { 12 | "id": "minimum", 13 | "type": "symbol", 14 | "source": "vector", 15 | "source-layer": "layer", 16 | "layout": { 17 | "text-font": ["Helvetica"], 18 | "text-field": "{foo}" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: \"glyphs\" url must include a \"{fontstack}\" token", 4 | "line": 3 5 | }, 6 | { 7 | "message": "glyphs: \"glyphs\" url must include a \"{range}\" token", 8 | "line": 3 9 | }, 10 | { 11 | "message": "glyphs: Styles must reference glyphs hosted by Mapbox", 12 | "line": 3 13 | } 14 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/malformed-glyphs.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: \"glyphs\" url must include a \"{fontstack}\" token", 4 | "line": 3 5 | }, 6 | { 7 | "message": "glyphs: \"glyphs\" url must include a \"{range}\" token", 8 | "line": 3 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/map-properties.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "zoom": 5, 4 | "center": [10, 10], 5 | "bearing": 20, 6 | "glyphs": "https://example.com/{fontstack}/{range}", 7 | "sources": { 8 | "vector": { 9 | "type": "vector", 10 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 11 | } 12 | }, 13 | "layers": [ 14 | { 15 | "id": "minimum", 16 | "type": "symbol", 17 | "source": "vector", 18 | "source-layer": "layer", 19 | "layout": { 20 | "text-font": ["Helvetica"], 21 | "text-field": "{foo}" 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/map-properties.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: Styles must reference glyphs hosted by Mapbox", 4 | "line": 6 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/map-properties.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/metadata.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "metadata": { 4 | "mapbox:groups": { 5 | "group-0": { 6 | "name": "Group Name" 7 | } 8 | } 9 | }, 10 | "constants": {}, 11 | "sources": {}, 12 | "layers": [ 13 | { 14 | "id": "background", 15 | "type": "background", 16 | "metadata": { 17 | "mapbox:group": "group-0" 18 | }, 19 | "paint": { 20 | "background-color": "#000" 21 | } 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/metadata.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "constants: constants have been deprecated as of v8", 4 | "line": 10 5 | }, 6 | { 7 | "message": "Unsupported property \"constants\"", 8 | "line": 10 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/metadata.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "constants: constants have been deprecated as of v8", 4 | "line": 10 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/missing-glyphs.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "vector": { 5 | "type": "vector", 6 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 7 | } 8 | }, 9 | "layers": [ 10 | { 11 | "id": "minimum", 12 | "type": "symbol", 13 | "source": "vector", 14 | "source-layer": "layer", 15 | "layout": { 16 | "text-font": ["Helvetica"], 17 | "text-field": "{foo}" 18 | } 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/missing-glyphs.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[0].layout.text-field: use of \"text-field\" requires a style \"glyphs\" property", 4 | "line": 17 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/missing-glyphs.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[0].layout.text-field: use of \"text-field\" requires a style \"glyphs\" property", 4 | "line": 17 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/no-sources.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "layers": [ 4 | { 5 | "id": "vector-raster-mismatch", 6 | "type": "line", 7 | "source": "raster" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/no-sources.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "missing required property \"sources\"", 4 | "line": 1 5 | }, 6 | { 7 | "message": "layers[0]: source \"raster\" not found", 8 | "line": 7 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/no-sources.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "missing required property \"sources\"", 4 | "line": 1 5 | }, 6 | { 7 | "message": "layers[0]: source \"raster\" not found", 8 | "line": 7 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/non-mapbox-references.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "glyphs": "https://example.com/{fontstack}/{range}", 4 | "sprite": "https://example.com/", 5 | "sources": { 6 | "vector1": { 7 | "type": "vector", 8 | "url": "example://abcd.1234" 9 | }, 10 | "vector2": { 11 | "type": "vector", 12 | "url": "https://example.com/tilejson.json" 13 | } 14 | }, 15 | "layers": [] 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/non-mapbox-references.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "glyphs: Styles must reference glyphs hosted by Mapbox", 4 | "line": 3 5 | }, 6 | { 7 | "message": "sprite: Styles must reference sprites hosted by Mapbox", 8 | "line": 4 9 | }, 10 | { 11 | "message": "sources[0]: Source url must be a valid Mapbox tileset url", 12 | "line": 8 13 | }, 14 | { 15 | "message": "sources[1]: Source url must be a valid Mapbox tileset url", 16 | "line": 12 17 | } 18 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/non-mapbox-references.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/numbers.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "line": 42, 4 | "message": "layers[2].paint.circle-radius: -1 is less than the minimum value 0" 5 | }, 6 | { 7 | "message": "layers[3].paint.circle-radius: number expected, null found" 8 | }, 9 | { 10 | "line": 58, 11 | "message": "layers[4].paint.circle-radius: missing required property \"stops\"" 12 | }, 13 | { 14 | "line": 66, 15 | "message": "layers[5].paint.circle-radius: number expected, array found" 16 | }, 17 | { 18 | "line": 74, 19 | "message": "layers[6].paint.circle-radius: number expected, boolean found" 20 | }, 21 | { 22 | "line": 6, 23 | "message": "source.data: Unsupported property \"data\"" 24 | } 25 | ] 26 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/numbers.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[2].paint.circle-radius: -1 is less than the minimum value 0", 4 | "line": 42 5 | }, 6 | { 7 | "message": "layers[3].paint.circle-radius: number expected, null found" 8 | }, 9 | { 10 | "message": "layers[4].paint.circle-radius: missing required property \"stops\"", 11 | "line": 58 12 | }, 13 | { 14 | "message": "layers[5].paint.circle-radius: number expected, array found", 15 | "line": 66 16 | }, 17 | { 18 | "message": "layers[6].paint.circle-radius: number expected, boolean found", 19 | "line": 74 20 | } 21 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/pitch.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "pitch": "45", 4 | "sources": {}, 5 | "layers": [] 6 | } 7 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/pitch.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "pitch: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/pitch.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "pitch: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/projection.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "projection": {"type":"mercator"}, 4 | "sources": {}, 5 | "layers": [] 6 | } 7 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/projection.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/required.input.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/required.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "missing required property \"version\"", 4 | "line": 1 5 | }, 6 | { 7 | "message": "missing required property \"sources\"", 8 | "line": 1 9 | }, 10 | { 11 | "message": "missing required property \"layers\"", 12 | "line": 1 13 | } 14 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/required.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "missing required property \"version\"", 4 | "line": 1 5 | }, 6 | { 7 | "message": "missing required property \"sources\"", 8 | "line": 1 9 | }, 10 | { 11 | "message": "missing required property \"layers\"", 12 | "line": 1 13 | } 14 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/roll.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "roll": "45", 4 | "sources": {}, 5 | "layers": [] 6 | } 7 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/roll.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "roll: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/roll.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "roll: number expected, string found", 4 | "line": 3 5 | } 6 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/root-properties.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "constants": [], 4 | "sources": [], 5 | "layers": {}, 6 | "created": "", 7 | "modified": "", 8 | "name": "Test", 9 | "owner": "peterqliu", 10 | "id": "peterqliu.test", 11 | "light": true 12 | } 13 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/root-properties.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "version: expected one of [8], 1 found", 4 | "line": 2 5 | }, 6 | { 7 | "message": "constants: constants have been deprecated as of v8", 8 | "line": 3 9 | }, 10 | { 11 | "message": "sources: object expected, array found", 12 | "line": 4 13 | }, 14 | { 15 | "message": "layers: array expected, object found", 16 | "line": 5 17 | }, 18 | { 19 | "message": "light: object expected, boolean found", 20 | "line": 11 21 | }, 22 | { 23 | "message": "Unsupported property \"constants\"", 24 | "line": 3 25 | }, 26 | { 27 | "message": "version: Style version must be 8", 28 | "line": 2 29 | } 30 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/root-properties.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "version: expected one of [8], 1 found", 4 | "line": 2 5 | }, 6 | { 7 | "message": "constants: constants have been deprecated as of v8", 8 | "line": 3 9 | }, 10 | { 11 | "message": "sources: object expected, array found", 12 | "line": 4 13 | }, 14 | { 15 | "message": "layers: array expected, object found", 16 | "line": 5 17 | }, 18 | { 19 | "message": "light: object expected, boolean found", 20 | "line": 11 21 | } 22 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/state.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "state": { 4 | "string": { 5 | "default": "type1" 6 | }, 7 | "boolean": { 8 | "default": true 9 | }, 10 | "number": { 11 | "default": 1 12 | }, 13 | "arrayOfStrings": { 14 | "default": ["type1", "type2", "type3"] 15 | }, 16 | "arrayOfBooleans": { 17 | "default": [true, false, true] 18 | }, 19 | "arrayOfNumbers": { 20 | "default": [1, 2, 3] 21 | }, 22 | "arrayOfArrays": { 23 | "default": [["type1", "type2"], ["type3", "type4"]] 24 | } 25 | }, 26 | "sources": { 27 | "vector": { 28 | "type": "vector", 29 | "url": "https://demotiles.maplibre.org/tiles/tiles.json" 30 | } 31 | }, 32 | "layers": [] 33 | } 34 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/state.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/terrain.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": { 4 | "terrain": { 5 | "type": "raster-dem", 6 | "tiles": ["local://tiles/{z}-{x}-{y}.terrain.png"], 7 | "maxzoom": 15, 8 | "tileSize": 256 9 | } 10 | }, 11 | "layers": [], 12 | "terrain": { 13 | "source": 123, 14 | "exaggeration": "2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/terrain.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "source: string expected, number found", 4 | "line": 13 5 | }, 6 | { 7 | "message": "exaggeration: number expected, string found", 8 | "line": 14 9 | } 10 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/text-field-format.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[1].layout.text-field: First argument must be an image or text section.", 4 | "line": 42 5 | }, 6 | { 7 | "message": "layers[2].layout.text-field: Expected at least one argument.", 8 | "line": 53 9 | }, 10 | { 11 | "message": "layers[6].layout.text-field[1]: Expected number but found string instead.", 12 | "line": 99 13 | }, 14 | { 15 | "message": "layers[7].layout.text-field[1][0]: Unknown expression \"Helvetica\". If you wanted a literal array, use [\"literal\", [...]].", 16 | "line": 111 17 | }, 18 | { 19 | "message": "layers[10].layout.text-field[1]: Expected array but found number instead.", 20 | "line": 147 21 | }, 22 | { 23 | "message": "glyphs: Styles must reference glyphs hosted by Mapbox", 24 | "line": 24 25 | }, 26 | { 27 | "message": "source.data: Unsupported property \"data\"", 28 | "line": 6 29 | } 30 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/text-field-format.output.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "message": "layers[1].layout.text-field: First argument must be an image or text section.", 4 | "line": 42 5 | }, 6 | { 7 | "message": "layers[2].layout.text-field: Expected at least one argument.", 8 | "line": 53 9 | }, 10 | { 11 | "message": "layers[6].layout.text-field[1]: Expected number but found string instead.", 12 | "line": 99 13 | }, 14 | { 15 | "message": "layers[7].layout.text-field[1][0]: Unknown expression \"Helvetica\". If you wanted a literal array, use [\"literal\", [...]].", 16 | "line": 111 17 | }, 18 | { 19 | "message": "layers[10].layout.text-field[1]: Expected array but found number instead.", 20 | "line": 147 21 | } 22 | ] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/unknown-keys-nested.input.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 8, 3 | "sources": {}, 4 | "layers": [ 5 | { 6 | "id": "bad-constant", 7 | "type": "background", 8 | "foo": "bar", 9 | "paint": { } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test/integration/style-spec/tests/unknown-keys-nested.output-api-supported.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /test/integration/style-spec/tests/unknown-keys-nested.output.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "checkJs": true, 6 | "isolatedModules": false, 7 | "noEmit": false, 8 | "declaration": false, 9 | "esModuleInterop": true, 10 | "importHelpers": false, 11 | "jsx": "react", 12 | "module": "ESNext", 13 | "moduleResolution": "bundler", 14 | "resolveJsonModule": true, 15 | "skipLibCheck": false, 16 | "strict": false, 17 | "target": "ES2019", 18 | "lib": ["ESNext", "DOM", "DOM.Iterable"], 19 | "types": ["node", "geojson"] 20 | }, 21 | "ts-node": { 22 | "experimentalSpecifierResolution": "node", 23 | "esm": true 24 | }, 25 | "include": ["rollup.config.*", "src/**/*", "build/**/*"], 26 | "exclude": ["node_modules", "dist"] 27 | } 28 | -------------------------------------------------------------------------------- /vitest.config.build.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | name: 'build', 6 | environment: 'node', 7 | include: [ 8 | 'test/build/**/*.test.{ts,js}', 9 | ], 10 | coverage: { 11 | provider: 'v8', 12 | reporter: ['json', 'html'], 13 | exclude: ['node_modules/', 'dist/', '**/*.test.ts'], 14 | all: true, 15 | include: ['src'], 16 | reportsDirectory: './coverage/vitest/build', 17 | }, 18 | } 19 | }); -------------------------------------------------------------------------------- /vitest.config.integration.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | name: 'integration', 6 | environment: 'node', 7 | include: [ 8 | 'test/integration/**/*.test.{ts,js}', 9 | ], 10 | coverage: { 11 | provider: 'v8', 12 | reporter: ['json', 'html'], 13 | exclude: ['node_modules/', 'dist/', '**/*.test.ts'], 14 | all: true, 15 | include: ['src'], 16 | reportsDirectory: './coverage/vitest/integration', 17 | }, 18 | }, 19 | }); -------------------------------------------------------------------------------- /vitest.config.unit.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | name: 'unit', 6 | environment: 'node', 7 | typecheck: { 8 | enabled: true, 9 | include: [ 10 | 'src/**/*.test.ts', 11 | ], 12 | }, 13 | include: [ 14 | 'src/**/*.test.{ts,js}' 15 | ], 16 | coverage: { 17 | provider: 'v8', 18 | reporter: ['json', 'html'], 19 | exclude: ['node_modules/', 'dist/', '**/*.test.ts'], 20 | all: true, 21 | include: ['src'], 22 | reportsDirectory: './coverage/vitest/unit', 23 | }, 24 | }, 25 | }); --------------------------------------------------------------------------------