Skip to content

Commit 7fcea88

Browse files
chore: reworked how the underlying expressions-type system works (#1391)
* reworked how the underlying expressions-type system works * fix typo
1 parent 6bba04c commit 7fcea88

File tree

2 files changed

+179
-36
lines changed

2 files changed

+179
-36
lines changed

build/generate-docs.ts

Lines changed: 84 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,28 @@ import {formatJSON} from './util';
44

55
/**
66
* This script generates markdown documentation from the JSON schema.
7-
* It leverages exitsing md files in the docs folder and adds generated files from the v8.json file.
7+
* It leverages existing md files in the docs folder and adds generated files from the v8.json file.
88
*/
99

1010
const BASE_PATH = 'docs';
1111

1212
type JsonExpressionSyntax = {
1313
overloads: {
1414
parameters: string[];
15-
'output-type': string;
16-
}[];
17-
parameters?: {
18-
name: string;
19-
type: string;
20-
doc?: string;
15+
'output-type': string | string[];
2116
}[];
17+
parameters?: Parameter[];
2218
}
2319

20+
type Parameter ={
21+
name: string;
22+
type: ParameterType;
23+
doc?: string;
24+
};
25+
26+
// either a basic type, a union of a few basic types or an object
27+
type ParameterType = string | string[] | { [key: string]: JsonObject };
28+
2429
type JsonSdkSupport = {
2530
[info: string]: {
2631
js?: string;
@@ -36,10 +41,13 @@ type JsonObject = {
3641
type: string;
3742
doc: string;
3843
requires?: any[];
39-
example: string | object | number;
44+
example: string | object | number | boolean;
4045
expression?: { interpolated?: boolean; parameters?: string[]};
4146
transition?: boolean;
47+
// for enum type: what is the type of the emum elements
4248
values?: {[key: string]: { doc: string; 'sdk-support'?: JsonSdkSupport }} | number[];
49+
// for array type: what is the type of the array elements?
50+
value?: string;
4351
minimum?: number;
4452
maximum?: number;
4553
}
@@ -121,6 +129,52 @@ function sdkSupportToMarkdown(support: JsonSdkSupport): string {
121129
return markdown;
122130
}
123131

132+
/**
133+
* Joins the array of type strings into a single string with `" | "` between them.
134+
* @param input the array or string to be joined
135+
* @returns the joined string
136+
*/
137+
function parameterTypeToType(input: ParameterType):string{
138+
if ( typeof input === 'string' )
139+
return input
140+
if (Array.isArray(input)) {
141+
return input.join(' | ')
142+
}
143+
const parameters = Object.entries(input)
144+
.map(([key, val])=> {
145+
const requiredSuffix = val.required ? '' : '?';
146+
return `${key}${requiredSuffix}: ${jsonObjectToType(val)}`
147+
})
148+
.join(', ')
149+
150+
return `{${parameters}}`;
151+
}
152+
153+
/**
154+
* Converts the JSON object to a type string.
155+
* @param val - the JSON object
156+
* @returns the type string
157+
*/
158+
function jsonObjectToType(val: JsonObject):string{
159+
switch (val.type) {
160+
case 'boolean':
161+
case 'string':
162+
case 'number':
163+
case 'color':
164+
// basic types -> no conversion needed
165+
return val.type
166+
case 'array':
167+
return `${val.type}<${parameterTypeToType(val.value)}>`;
168+
case 'enum':
169+
const values = val.values;
170+
if (!values || Array.isArray(values))
171+
throw new Error(`Enum ${JSON.stringify(val)} has no "values" describing the contained Options in the form of an Object`)
172+
return Object.keys(values).map(s=>`"${s}"`).join(' | ');
173+
default:
174+
throw new Error(`Unknown "type" ${val.type} for ${JSON.stringify(val)}`)
175+
}
176+
}
177+
124178
/**
125179
* Converts the expression syntax object to markdown format.
126180
* @param key - the expression name
@@ -130,17 +184,32 @@ function sdkSupportToMarkdown(support: JsonSdkSupport): string {
130184
function expressionSyntaxToMarkdown(key: string, syntax: JsonExpressionSyntax) {
131185
let markdown = '\nSyntax:\n';
132186
const codeBlockLines = syntax.overloads.map((overload) => {
133-
return `[${[`"${key}"`, ...overload.parameters].join(', ')}]: ${overload['output-type']}`;
187+
const key_and_parameters = [`"${key}"`, ...overload.parameters].join(', ');
188+
189+
return `[${key_and_parameters}]: ${parameterTypeToType(overload['output-type'])}`;
134190
});
135191
markdown += `${codeBlockMarkdown(codeBlockLines.join('\n'), 'js')}\n`;
136192
for (const parameter of syntax.parameters ?? []) {
137-
markdown += `- \`${parameter.name}\``;
138-
if (parameter.type) {
139-
const type = parameter.type.replaceAll('<', '&lt;').replaceAll('>', '&gt;');
140-
markdown += `: *${type}*`;
141-
}
193+
const type = parameterTypeToType(parameter.type).replaceAll('<', '&lt;').replaceAll('>', '&gt;');
194+
markdown += `- \`${parameter.name}\`: \`${type}\``;
142195
if (parameter.doc) {
143-
markdown += ` — ${parameter.doc}`;
196+
markdown += `- ${parameter.doc}`;
197+
}
198+
if (typeof parameter.type !== 'string' && !Array.isArray(parameter.type)){
199+
// the type is an object type => we can attach more documentation about the contained variables
200+
markdown += ' \nParameters:'
201+
Object.entries(parameter.type).forEach(([key, val])=>{
202+
const type = jsonObjectToType(val).replaceAll('<', '&lt;').replaceAll('>', '&gt;');
203+
markdown += `\n - \`${key}\`: \`${type}\` - ${val.doc}`
204+
if (val.type==='enum' && val.values){
205+
markdown += ' \n Possible values are:'
206+
for (const [enumKey, enumValue] of Object.entries(val.values)) {
207+
const defaultIndicator = val.default === enumKey ? ' *default*' : '';
208+
markdown += `\n - \`"${enumKey}"\`${defaultIndicator} - ${enumValue.doc}`
209+
}
210+
}
211+
212+
})
144213
}
145214
markdown += '\n';
146215
}

src/reference/v8.json

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3053,7 +3053,7 @@
30533053
},
30543054
{
30553055
"name": "type",
3056-
"type": "\"string\" | \"number\" | \"boolean\"",
3056+
"type": ["string", "number", "boolean"],
30573057
"doc": "The asserted type of the input array."
30583058
},
30593059
{
@@ -3295,12 +3295,12 @@
32953295
"parameters": [
32963296
{
32973297
"name": "input",
3298-
"type": "string | number",
3298+
"type": ["string", "number"],
32993299
"doc": "Any expression."
33003300
},
33013301
{
33023302
"name": "label_i",
3303-
"type": "string literal | number literal | array<string literal> | array<number literal>",
3303+
"type": ["string literal", "number literal", "array<string literal>", "array<number literal>"],
33043304
"doc": "The i-th literal value or array of literal values to match the input against."
33053305
},
33063306
{
@@ -3399,13 +3399,13 @@
33993399
"overloads": [
34003400
{
34013401
"parameters": ["interpolation_type", "input", "stop_1_input", "stop_1_output", "...", "stop_n_input", "stop_n_output"],
3402-
"output-type": "number | array<number> | color | array<color> | projection"
3402+
"output-type": ["number", "array<number>", "color", "array<color>", "projection"]
34033403
}
34043404
],
34053405
"parameters": [
34063406
{
34073407
"name": "interpolation_type",
3408-
"type": "[\"linear\"] | [\"exponential\", base] | [\"cubic-bezier\", x1, y1, x2, y2]",
3408+
"type": ["[\"linear\"]", "[\"exponential\", base]", "[\"cubic-bezier\", x1, y1, x2, y2]"],
34093409
"doc": "The interpolation type."
34103410
},
34113411
{
@@ -3420,7 +3420,7 @@
34203420
},
34213421
{
34223422
"name": "stop_i_output",
3423-
"type": "number | array<number> | color | array<color> | projection",
3423+
"type": ["number", "array<number>", "color", "array<color>", "projection"],
34243424
"doc": "The output value corresponding to the i-th stop."
34253425
}
34263426
]
@@ -3441,13 +3441,13 @@
34413441
"overloads": [
34423442
{
34433443
"parameters": ["interpolation_type", "input", "stop_1_input", "stop_1_output", "...", "stop_n_input", "stop_n_output"],
3444-
"output-type": "color | array<color>"
3444+
"output-type": ["color", "array<color>"]
34453445
}
34463446
],
34473447
"parameters": [
34483448
{
34493449
"name": "interpolation_type",
3450-
"type": "[\"linear\"] | [\"exponential\", base] | [\"cubic-bezier\", x1, y1, x2, y2]"
3450+
"type": ["[\"linear\"]", "[\"exponential\", base]", "[\"cubic-bezier\", x1, y1, x2, y2]"]
34513451
},
34523452
{
34533453
"name": "input",
@@ -3459,7 +3459,7 @@
34593459
},
34603460
{
34613461
"name": "stop_i_output",
3462-
"type": "color | array<color>"
3462+
"type": ["color", "array<color>"]
34633463
}
34643464
]
34653465
},
@@ -3479,13 +3479,13 @@
34793479
"overloads": [
34803480
{
34813481
"parameters": ["interpolation_type", "input", "stop_1_input", "stop_1_output", "...", "stop_n_input", "stop_n_output"],
3482-
"output-type": "color | array<color>"
3482+
"output-type": ["color", "array<color>"]
34833483
}
34843484
],
34853485
"parameters": [
34863486
{
34873487
"name": "interpolation_type",
3488-
"type": "[\"linear\"] | [\"exponential\", base] | [\"cubic-bezier\", x1, y1, x2, y2]"
3488+
"type": ["[\"linear\"]", "[\"exponential\", base]", "[\"cubic-bezier\", x1, y1, x2, y2]"]
34893489
},
34903490
{
34913491
"name": "input",
@@ -3497,7 +3497,7 @@
34973497
},
34983498
{
34993499
"name": "stop_i_output",
3500-
"type": "color | array<color>"
3500+
"type": ["color", "array<color>"]
35013501
}
35023502
]
35033503
},
@@ -3702,7 +3702,7 @@
37023702
}
37033703
},
37043704
"collator": {
3705-
"doc": "Returns a `collator` for use in locale-dependent comparison operations. The `case-sensitive` and `diacritic-sensitive` options default to `false`. The `locale` argument specifies the IETF language tag of the locale to use. If none is provided, the default locale is used. If the requested locale is not available, the `collator` will use a system-defined fallback locale. Use `resolved-locale` to test the results of locale fallback behavior.",
3705+
"doc": "Returns a `collator` for use in locale-dependent comparison operations. Use `resolved-locale` to test the results of locale fallback behavior.",
37063706
"syntax": {
37073707
"overloads": [
37083708
{
@@ -3713,7 +3713,25 @@
37133713
"parameters": [
37143714
{
37153715
"name": "options",
3716-
"type": "{ \"case-sensitive\"?: boolean, \"diacritic-sensitive\"?: boolean, \"locale\"?: string }"
3716+
"type": {
3717+
"case-sensitive": {
3718+
"type": "boolean",
3719+
"default": false,
3720+
"example": true,
3721+
"doc": "If characters of different case-ness are considered different"
3722+
},
3723+
"diacritic-sensitive": {
3724+
"type": "boolean",
3725+
"default": false,
3726+
"example": true,
3727+
"doc": "If characters with different diacritics are considered different"
3728+
},
3729+
"locale": {
3730+
"type": "string",
3731+
"example": "en",
3732+
"doc": "IETF language tag of the locale to use. If none is provided, the default locale is used. If the requested locale is not available, the `collator` will use a system-defined fallback locale."
3733+
}
3734+
}
37173735
}
37183736
]
37193737
},
@@ -3728,7 +3746,7 @@
37283746
}
37293747
},
37303748
"format": {
3731-
"doc": "Returns a `formatted` string for displaying mixed-format text in the `text-field` property. The input may contain a string literal or expression, including an [`'image'`](#image) expression. Strings may be followed by a style override object that supports the following properties:\n\n- `\"text-font\"`: Overrides the font stack specified by the root layout property.\n\n- `\"text-color\"`: Overrides the color specified by the root paint property.\n\n- `\"font-scale\"`: Applies a scaling factor on `text-size` as specified by the root layout property.\n\n- `\"vertical-align\"`: Aligns vertically text section or image in relation to the row it belongs to. Possible values are: \n\t- `\"bottom\"` *default*: align the bottom of this section with the bottom of other sections.\n<img alt=\"Visual representation of bottom alignment\" src=\"https://github.com/user-attachments/assets/0474a2fd-a4b2-417c-9187-7a13a28695bc\"/>\n\t- `\"center\"`: align the center of this section with the center of other sections.\n<img alt=\"Visual representation of center alignment\" src=\"https://github.com/user-attachments/assets/92237455-be6d-4c5d-b8f6-8127effc1950\"/>\n\t- `\"top\"`: align the top of this section with the top of other sections.\n<img alt=\"Visual representation of top alignment\" src=\"https://github.com/user-attachments/assets/45dccb28-d977-4abb-a006-4ea9792b7c53\"/>\n\t- Refer to [the design proposal](https://github.com/maplibre/maplibre-style-spec/issues/832) for more details.\n\n - [Change the case of labels](https://maplibre.org/maplibre-gl-js/docs/examples/change-case-of-labels/)\n\n - [Display and style rich text labels](https://maplibre.org/maplibre-gl-js/docs/examples/display-and-style-rich-text-labels/)",
3749+
"doc": "Returns a `formatted` string for displaying mixed-format text in the `text-field` property. The input may contain a string literal or expression, including an [`'image'`](#image) expression. Strings may be followed by a style override object.\n\n - [Change the case of labels](https://maplibre.org/maplibre-gl-js/docs/examples/change-case-of-labels/)\n\n - [Display and style rich text labels](https://maplibre.org/maplibre-gl-js/docs/examples/display-and-style-rich-text-labels/)",
37323750
"syntax": {
37333751
"overloads": [
37343752
{
@@ -3739,11 +3757,44 @@
37393757
"parameters": [
37403758
{
37413759
"name": "input_i",
3742-
"type": "string | image"
3760+
"type": ["string", "image"]
37433761
},
37443762
{
37453763
"name": "style_overrides_i",
3746-
"type": "{ \"text-font\"?: string, \"text-color\"?: color, \"font-scale\"?: number, \"vertical-align\"?: \"bottom\" | \"center\" | \"top\" }"
3764+
"type": {
3765+
"text-font": {
3766+
"type": "string",
3767+
"doc": "Overrides the font stack specified by the root layout property.",
3768+
"example": "Arial Unicode MS Regular"
3769+
},
3770+
"text-color": {
3771+
"type": "color",
3772+
"doc": "Overrides the color specified by the root paint property.",
3773+
"example": "#333"
3774+
},
3775+
"font-scale": {
3776+
"type": "number",
3777+
"doc":"Applies a scaling factor on `text-size` as specified by the root layout property.",
3778+
"example": 1.2
3779+
},
3780+
"vertical-align": {
3781+
"type": "enum",
3782+
"doc": "Aligns a vertical text section or image in relation to the row it belongs to. Refer to [the design proposal](https://github.com/maplibre/maplibre-style-spec/issues/832) for more details.",
3783+
"default": "bottom",
3784+
"example": "bottom",
3785+
"values": {
3786+
"bottom": {
3787+
"doc": "align the bottom of this section with the bottom of other sections.\n![Visual representation of bottom alignment](https://github.com/user-attachments/assets/0474a2fd-a4b2-417c-9187-7a13a28695bc)"
3788+
},
3789+
"center": {
3790+
"doc": "align the center of this section with the center of other sections.\n![Visual representation of center alignment](https://github.com/user-attachments/assets/92237455-be6d-4c5d-b8f6-8127effc1950)"
3791+
},
3792+
"top": {
3793+
"doc": "align the top of this section with the top of other sections.\n![Visual representation of top alignment](https://github.com/user-attachments/assets/45dccb28-d977-4abb-a006-4ea9792b7c53)"
3794+
}
3795+
}
3796+
}
3797+
}
37473798
}
37483799
]
37493800
},
@@ -3836,7 +3887,7 @@
38363887
}
38373888
},
38383889
"number-format": {
3839-
"doc": "Converts the input number into a string representation using the providing formatting rules. If set, the `locale` argument specifies the locale to use, as a BCP 47 language tag. If set, the `currency` argument specifies an ISO 4217 code to use for currency-style formatting. If set, the `min-fraction-digits` and `max-fraction-digits` arguments specify the minimum and maximum number of fractional digits to include.\n\n - [Display HTML clusters with custom properties](https://maplibre.org/maplibre-gl-js/docs/examples/display-html-clusters-with-custom-properties/)",
3890+
"doc": "Converts the input number into a string representation using the provided format_options.\n\n - [Display HTML clusters with custom properties](https://maplibre.org/maplibre-gl-js/docs/examples/display-html-clusters-with-custom-properties/)",
38403891
"syntax": {
38413892
"overloads": [
38423893
{
@@ -3847,11 +3898,34 @@
38473898
"parameters": [
38483899
{
38493900
"name": "input",
3850-
"type": "number"
3901+
"type": "number",
3902+
"doc": "number to format"
38513903
},
38523904
{
38533905
"name": "format_options",
3854-
"type": "{ \"locale\"?: string, \"currency\"?: string, \"min-fraction-digits\"?: number, \"max-fraction-digits\"?: number }"
3906+
"type": {
3907+
"locale": {
3908+
"type": "string",
3909+
"example": "en",
3910+
"doc": "Specifies the locale to use, as a BCP 47 language tag"
3911+
},
3912+
"currency": {
3913+
"type": "string",
3914+
"example": "USD",
3915+
"doc": "An ISO 4217 code to use for currency-style formatting"
3916+
},
3917+
"min-fraction-digits": {
3918+
"type": "number",
3919+
"example": 1,
3920+
"doc": "Minimum number of fractional digits to include"
3921+
},
3922+
"max-fraction-digits": {
3923+
"type": "number",
3924+
"example": 2,
3925+
"doc": "Maximum number of fractional digits to include"
3926+
}
3927+
},
3928+
"doc": "Format options for the number"
38553929
}
38563930
]
38573931
},
@@ -4143,7 +4217,7 @@
41434217
"parameters": [
41444218
{
41454219
"name": "array_or_string",
4146-
"type": "array | string"
4220+
"type": ["array", "string"]
41474221
}
41484222
]
41494223
},

0 commit comments

Comments
 (0)