Replies: 1 comment
-
|
I think this is well written! I would say that if you get it to work so that it can replace the current setup we are in a better state than before. Some stuff to consider: doc generation and types generation is also proprietary, so I would make sure it doesn't degrade when migrating. Consider posting a link to this discussion on slack and maybe present that in the monthly meeting to get more feedback. I think it's a good approach in general. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
JSON Schema had been brought up in the past (namely in maplibre/maplibre-gl-js#1851) as a more standard, better-documented way of defining the style JSON compared to the current v8.json design.
While that thread seems to conclude that it makes sense for v8.json to be converted to JSON Schema, my understanding is that this idea ended up not being pursued due to difficulties in specifying the expression syntax using JSON Schema. (This is not mentioned in the aforementioned thread but is the explanation given in #393 (comment), #89 (comment), #1128 (comment)).
However, I am curious whether the inability to define expression syntax is actually a deal-breaker for taking advantage of JSON Schema.
The issues surrounding v8.json which motivated maplibre/maplibre-gl-js#1851 are still very relevant, and even if standard JSON Schema vocabulary (i.e. non-custom properties) is incapable of fully defining expression syntax, I feel that adopting JSON Schema may still bring significant improvements over the status quo with regard to these issues.
Issues with v8.json
Below are two underlying issues which I believe motivated the original proposal and which I would like to focus on for this discussion:
The v8.json syntax lacks expressiveness/flexibility.
It seems we want v8.json to function as the single source of truth for the style spec, yet the existing language used in v8.json is not compatible with some desired API designs, e.g. AFAIK it is impossible to define custom types which are not objects (see Add support for multiple sprites in one style maplibre-gl-js#1805 (comment)).
The current workaround for this sort of limitation seems to be to create a custom name for the type, say
"type": "sprite", but not define that type in v8.json. Any code which relies on v8.json for property types instead obtains knowledge about this custom type from elsewhere, e.g. via handwritten implementation logic baked into the code itself rather than from v8.json.This inconsistency in where types are defined lessens the ability for v8.json to function as the single source of truth, and this can cause confusion for devs working with v8.json (as evidenced here).
v8.json uses a custom, undocumented syntax.
While most of v8.json is fairly self-explanatory, some parts are obscure and require searching through usages to understand their purpose (and some parts remain confusing even so). For instance:
minimum/maximumfield?property-typeroot property?Especially since this file is directly consumed by other MapLibre libraries, I believe it is important for it to be well-defined what parts of the file hold what meaning and serve what purpose. The developer experience is not great having to navigate through questions like these and make assumptions regarding how to interpret the style spec language.
Ideas
I have two independent JSON Schema-related ideas which I feel could bring significant improvements over the current setup.
Note that expressions remain described by a custom language under all solutions, as it is impossible to describe them to the desired level of detail with standard JSON Schema — my argument is that this fact should not impede improvements that could be made to v8.json overall to address the aforementioned issues.
1. Convert v8.json to JSON Schema
This is the solution suggested in maplibre/maplibre-gl-js#1851.
The conversion of v8.json into a valid JSON Schema (which I will hereafter refer to as style.schema.json) would make the style spec be written in a well-defined language (resolving issue 2) which is proven to be flexible enough to describe most JSON structures (resolving issue 1, with the exception of expressions).
This would of course require any code currently relying on v8.json to be modified to extract the necessary data from the new JSON Schema structure.
Benefits
Drawbacks/Concerns
typefield indicates syntactical type, which is not the same as v8.json'stypewhich indicates 'semantic type'. For instance, IIUC a paint property withtype: 'number'syntactically accepts an expression in addition to a number literal.This significantly complicates things. The JSON Schema would have to be considerably more complex (relative to v8.json) to describe this fact, which also means the logic in consumers to obtain this spec information would need significant changes.
Below is the initial idea I had in mind:
"position": { + "mlgl-type": "array", + "anyOf": [ + { + "type": "array", + "items": { + "type": "number" + }, + "minItems": 3, + "maxItems": 3, + }, + { "$ref": "#/$defs/expression" } + ] - "type": "array", "default": [ 1.15, 210, 30 ], - "length": 3, - "value": "number", "property-type": "data-constant", "transition": true, "expression": { "interpolated": true, "parameters": [ "zoom" ] }, - "doc": "Position of the light source...", + "description": "Position of the light source...", - "example": [ + "examples": [[ 1.5, 90, 80 - ], + ]], "sdk-support": { "basic functionality": { "js": "0.27.0", "android": "5.1.0", "ios": "3.6.0" } } }minItems/maxItemsmust be specified inanyOf[0]rather than the root object because an expression is also syntactically an array, whereas other annotations such asdefaultare at the root since these describe thepositionproperty itself and not just theanyOf[0]option. This distinction however can be unclear from the implementer/consumer's perspective, making it confusing which properties are defined at the root and which within theanyOf(where by 'consumer' I mean the code in MapLibre repos which currently depend on the specs in v8.json). Furthermore, ideally we want the schema to capture the fact that theminItems/maxItemsconstraint also applies to the result of the expression, which this design fails to do.A solution could be to treat expressions as an exception and not explicitly include it in the schema which is used as the source of truth. This would of course make this an inaccurate schema, but would better capture the properties' constraints and would make parsing more convenient for consumers. Should there be a desire for a 'complete' schema which includes expressions, IIUC it should be possible to then generate it from this 'incomplete' schema:
2. Describe the style spec with a meta-schema
This could either be done together with or independently from the above idea.
If v8.json is converted to JSON Schema, this meta-schema would define the syntax and interpretation of custom properties which are not a part of standard JSON Schema. This would fully resolve issue 2 since style.schema.json overall could be interpreted as a JSON Schema document following the official JSON Schema specs, and any custom properties could be interpreted following what we document in this custom meta-schema.
If converting v8.json turns out to be too disruptive or not actually feasible, then this meta-schema could be used to define the syntax and interpretation of v8.json, somewhat alleviating issue 2. Issue 1 would still be unaddressed in this case, but I believe having a meta-schema could also make it smoother if/when introducing changes to the v8.json syntax in the future.
Regardless, this meta-schema could be useful as a point of reference for, without having to search through all consumers to understand how v8.json/style.schema.json is used, answering questions like those posed above regarding properties with unclear interpretations.
Benefits
Drawbacks/Concerns
With all the above said, I am no expert in the MapLibre libraries, and these are just some thoughts I had and wished to jot down somewhere after experiencing confusion around v8.json and its role in TS type generation and validation. At the current moment, I feel both ideas offer improvements from the status quo, and would be interested in implementing any solution along these lines.
I would highly appreciate any feedback on the above ideas or insights (aside from what is already public in GitHub issues/PRs/discussions) regarding past efforts to accomplish something similar.
Beta Was this translation helpful? Give feedback.
All reactions