summaryrefslogtreecommitdiff
path: root/platform/darwin/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/scripts')
-rwxr-xr-x[-rw-r--r--]platform/darwin/scripts/generate-style-code.js197
-rw-r--r--platform/darwin/scripts/style-spec-overrides-v8.json11
-rwxr-xr-x[-rw-r--r--]platform/darwin/scripts/update-examples.js12
3 files changed, 139 insertions, 81 deletions
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index 4ee86e65da..a7804ac948 100644..100755
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -1,3 +1,4 @@
+#!/usr/bin/env node
'use strict';
const fs = require('fs');
@@ -11,7 +12,7 @@ const cocoaConventions = require('./style-spec-cocoa-conventions-v8.json');
const prefix = 'MGL';
const suffix = 'StyleLayer';
-let spec = _.merge(require('../../../mapbox-gl-js/src/style-spec/reference/v8'), require('./style-spec-overrides-v8.json'));
+let spec = _.merge(require('../../../scripts/style-spec'), require('./style-spec-overrides-v8.json'));
// Rename properties and keep `original` for use with setters and getters
_.forOwn(cocoaConventions, function (properties, kind) {
@@ -27,8 +28,10 @@ _.forOwn(cocoaConventions, function (properties, kind) {
delete spec[kind][oldName];
spec[kind][newName] = property;
- // Update requirements in other properties.
- let updateRequirements = function (property, name) {
+ // Update cross-references to this property in other properties'
+ // documentation and requirements.
+ let renameCrossReferences = function (property, name) {
+ property.doc = property.doc.replace(new RegExp('`' + oldName + '`', 'g'), '`' + newName + '`');
let requires = property.requires || [];
for (let i = 0; i < requires.length; i++) {
if (requires[i] === oldName) {
@@ -45,8 +48,8 @@ _.forOwn(cocoaConventions, function (properties, kind) {
}
}
};
- _.forOwn(spec[kind.replace(/^layout_/, 'paint_')], updateRequirements);
- _.forOwn(spec[kind.replace(/^paint_/, 'layout_')], updateRequirements);
+ _.forOwn(spec[kind.replace(/^layout_/, 'paint_')], renameCrossReferences);
+ _.forOwn(spec[kind.replace(/^paint_/, 'layout_')], renameCrossReferences);
})
});
@@ -92,37 +95,42 @@ global.testImplementation = function (property, layerType, isFunction) {
return `layer.${objCName(property)} = [MGLRuntimeStylingHelper ${helperMsg}];`;
};
-global.objCTestValue = function (property, layerType, indent) {
+global.objCTestValue = function (property, layerType, arraysAsStructs, indent) {
let propertyName = originalPropertyName(property);
switch (property.type) {
case 'boolean':
- return property.default ? '@NO' : '@YES';
+ return property.default ? '@"false"' : '@"true"';
case 'number':
- return '@0xff';
+ return '@"0xff"';
case 'string':
- return `@"${_.startCase(propertyName)}"`;
+ return `@"'${_.startCase(propertyName)}'"`;
case 'enum':
- let type = objCType(layerType, property.name);
- let value = `${type}${camelize(_.last(_.keys(property.values)))}`;
- return `[NSValue valueWith${type}:${value}]`;
+ return `@"'${_.last(_.keys(property.values))}'"`;
case 'color':
- return '[MGLColor redColor]';
+ return '@"%@", [MGLColor redColor]';
case 'array':
switch (arrayType(property)) {
case 'dasharray':
- return '@[@1, @2]';
+ return '@"{1, 2}"';
case 'font':
- return `@[@"${_.startCase(propertyName)}", @"${_.startCase(_.reverse(propertyName.split('')).join(''))}"]`;
+ return `@"{'${_.startCase(propertyName)}', '${_.startCase(_.reverse(propertyName.split('')).join(''))}'}"`;
case 'padding': {
- let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
- let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
- return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ if (arraysAsStructs) {
+ let iosValue = '[NSValue valueWithUIEdgeInsets:UIEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithEdgeInsets:NSEdgeInsetsMake(1, 1, 1, 1)]'.indent(indent * 4);
+ return `@"%@",\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ }
+ return '@"{1, 1, 1, 1}"';
}
case 'offset':
- case 'translate':
- let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
- let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
- return `\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ case 'translate': {
+ if (arraysAsStructs) {
+ let iosValue = '[NSValue valueWithCGVector:CGVectorMake(1, 1)]'.indent(indent * 4);
+ let macosValue = '[NSValue valueWithMGLVector:CGVectorMake(1, -1)]'.indent(indent * 4);
+ return `@"%@",\n#if TARGET_OS_IPHONE\n${iosValue}\n#else\n${macosValue}\n#endif\n${''.indent((indent - 1) * 4)}`;
+ }
+ return '@"{1, 1}"';
+ }
default:
throw new Error(`unknown array type for ${property.name}`);
}
@@ -245,6 +253,13 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
// Format everything else: our property name & its possible values.
// Requires symbols to be surrounded by backticks.
doc = doc.replace(/`(.+?)`/g, function (m, symbol, offset, str) {
+ if (kind === 'enum') {
+ let layoutProperties = spec[`layout_${layerType}`] || [];
+ let paintProperties = spec[`paint_${layerType}`] || [];
+ if (symbol in layoutProperties || symbol in paintProperties) {
+ return '`MGL' + camelize(layerType) + 'StyleLayer.' + camelizeWithLeadingLowercase(symbol) + '`';
+ }
+ }
if ('values' in property && Object.keys(property.values).indexOf(symbol) !== -1) {
let objCType = global.objCType(layerType, property.name);
return '`' + `${objCType}${camelize(symbol)}` + '`';
@@ -284,29 +299,23 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
}
doc += `\n\nThis attribute corresponds to the <a href="https://www.mapbox.com/mapbox-gl-style-spec/#${anchor}"><code>${property.original}</code></a> layout property in the Mapbox Style Specification.`;
}
- doc += '\n\nYou can set this property to an instance of:\n\n' +
- '* `MGLConstantStyleValue`\n';
+ doc += '\n\nYou can set this property to an expression containing any of the following:\n\n';
+ doc += `* Constant ${describeType(property)} values\n`;
+ if (property.type === 'enum') {
+ doc += '* Any of the following constant string values:\n';
+ doc += Object.keys(property.values).map(value => ' * `' + value + '`: ' + property.values[value].doc).join('\n') + '\n';
+ }
+ doc += '* Predefined functions, including mathematical and string operators\n' +
+ '* Conditional expressions\n' +
+ '* Variable assignments and references to assigned variables\n';
if (property["property-function"]) {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- '* `MGLSourceStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- ' * `MGLInterpolationModeCategorical`\n' +
- ' * `MGLInterpolationModeIdentity`\n' +
- '* `MGLCompositeStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n' +
- ' * `MGLInterpolationModeCategorical`\n';
+ doc += '* Interpolation and step functions applied to the `$zoomLevel` variable and/or feature attributes\n';
+ } else if (property.function === "interpolated") {
+ doc += '* Interpolation and step functions applied to the `$zoomLevel` variable\n\n' +
+ 'This property does not support applying interpolation or step functions to feature attributes.';
} else {
- if (property.function === "interpolated") {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of:\n' +
- ' * `MGLInterpolationModeExponential`\n' +
- ' * `MGLInterpolationModeInterval`\n';
- } else {
- doc += '* `MGLCameraStyleFunction` with an interpolation mode of `MGLInterpolationModeInterval`\n';
- }
+ doc += '* Step functions applied to the `$zoomLevel` variable\n\n' +
+ 'This property does not support applying interpolation functions to the `$zoomLevel` variable or applying interpolation or step functions to feature attributes.';
}
}
return doc;
@@ -320,7 +329,7 @@ global.propertyReqs = function (property, propertiesByName, type) {
return '`' + camelizeWithLeadingLowercase(req['!']) + '` is set to `nil`';
} else {
let name = Object.keys(req)[0];
- return '`' + camelizeWithLeadingLowercase(name) + '` is set to an `MGLStyleValue` object containing ' + describeValue(req[name], propertiesByName[name], type);
+ return '`' + camelizeWithLeadingLowercase(name) + '` is set to an expression that evaluates to ' + describeValue(req[name], propertiesByName[name], type);
}
}).join(', and ') + '. Otherwise, it is ignored.';
};
@@ -335,12 +344,55 @@ global.parseColor = function (str) {
};
};
+global.describeType = function (property) {
+ switch (property.type) {
+ case 'boolean':
+ return 'Boolean';
+ case 'number':
+ return 'numeric';
+ case 'string':
+ return 'string';
+ case 'enum':
+ return '`MGL' + camelize(property.name) + '`';
+ case 'color':
+ return '`UIColor`';
+ case 'array':
+ switch (arrayType(property)) {
+ case 'padding':
+ return '`UIEdgeInsets`';
+ case 'offset':
+ case 'translate':
+ return '`CGVector`';
+ case 'position':
+ return '`MGLSphericalPosition`';
+ default:
+ return 'array';
+ }
+ break;
+ default:
+ throw new Error(`unknown type for ${property.name}`);
+ }
+}
+
global.describeValue = function (value, property, layerType) {
+ if (Array.isArray(value) && property.type !== 'array' && property.type !== 'enum') {
+ switch (value[0]) {
+ case 'interpolate': {
+ let curveType = value[1][0];
+ let minimum = describeValue(value[3 + value.length % 2], property, layerType);
+ let maximum = describeValue(_.last(value), property, layerType);
+ return `${curveType.match(/^[aeiou]/i) ? 'an' : 'a'} ${curveType} interpolation expression ranging from ${minimum} to ${maximum}`;
+ }
+ default:
+ throw new Error(`No description available for ${value[0]} expression in ${property.name} of ${layerType}.`);
+ }
+ }
+
switch (property.type) {
case 'boolean':
- return 'an `NSNumber` object containing ' + (value ? '`YES`' : '`NO`');
+ return value ? '`YES`' : '`NO`';
case 'number':
- return 'an `NSNumber` object containing the float `' + value + '`';
+ return 'the float `' + value + '`';
case 'string':
if (value === '') {
return 'the empty string';
@@ -349,21 +401,18 @@ global.describeValue = function (value, property, layerType) {
case 'enum':
let displayValue;
if (Array.isArray(value)) {
- let separator = (value.length === 2) ? ' ' : ', ';
- displayValue = value.map((possibleValue, i) => {
- let conjunction = '';
- if (value.length === 2 && i === 0) conjunction = 'either ';
- if (i === value.length - 1) conjunction = 'or ';
- let objCType = global.objCType(layerType, property.name);
- return `${conjunction}\`${objCType}${camelize(possibleValue)}\``;
- }).join(separator);
- } else if (property['light-property']) {
- displayValue = `\`${prefix}Light${camelize(property.name)}${camelize(value)}\``;
+ let separator = (value.length === 2) ? ' ' : ', ';
+ displayValue = value.map((possibleValue, i) => {
+ let conjunction = '';
+ if (value.length === 2 && i === 0) conjunction = 'either ';
+ if (i === value.length - 1) conjunction = 'or ';
+ let objCType = global.objCType(layerType, property.name);
+ return `${conjunction}\`${objCType}${camelize(possibleValue)}\``;
+ }).join(separator);
} else {
- let objCType = global.objCType(layerType, property.name);
- displayValue = `\`${objCType}${camelize(value)}\``;
+ displayValue = `\`${value}\``;
}
- return `an \`NSValue\` object containing ${displayValue}`;
+ return displayValue;
case 'color':
let color = parseColor(value);
if (!color) {
@@ -404,7 +453,11 @@ global.describeValue = function (value, property, layerType) {
};
global.propertyDefault = function (property, layerType) {
- return 'an `MGLStyleValue` object containing ' + describeValue(property.default, property, layerType);
+ if (property.name === 'heatmap-color') {
+ return 'an expression that evaluates to a rainbow color scale from blue to red';
+ } else {
+ return 'an expression that evaluates to ' + describeValue(property.default, property, layerType);
+ }
};
global.originalPropertyName = function (property) {
@@ -564,9 +617,9 @@ const templatesMD = ejs.compile(fs.readFileSync('platform/darwin/docs/guides/Til
const lightH = ejs.compile(fs.readFileSync('platform/darwin/src/MGLLight.h.ejs', 'utf8'), {strict: true});
const lightM = ejs.compile(fs.readFileSync('platform/darwin/src/MGLLight.mm.ejs', 'utf8'), {strict: true});
const testLight = ejs.compile(fs.readFileSync('platform/darwin/test/MGLLightTest.mm.ejs', 'utf8'), { strict: true});
-fs.writeFileSync(`platform/darwin/src/MGLLight.h`, duplicatePlatformDecls(lightH({ properties: lightProperties, doc: lightDoc, type: lightType })));
-fs.writeFileSync(`platform/darwin/src/MGLLight.mm`, lightM({ properties: lightProperties, doc: lightDoc, type: lightType }));
-fs.writeFileSync(`platform/darwin/test/MGLLightTest.mm`, testLight({ properties: lightProperties, doc: lightDoc, type: lightType }));
+writeIfModified(`platform/darwin/src/MGLLight.h`, duplicatePlatformDecls(lightH({ properties: lightProperties, doc: lightDoc, type: lightType })));
+writeIfModified(`platform/darwin/src/MGLLight.mm`, lightM({ properties: lightProperties, doc: lightDoc, type: lightType }));
+writeIfModified(`platform/darwin/test/MGLLightTest.mm`, testLight({ properties: lightProperties, doc: lightDoc, type: lightType }));
const layers = _(spec.layer.type.values).map((value, layerType) => {
@@ -639,9 +692,9 @@ for (var layer of layers) {
renamedPropertiesByLayerType[layer.type] = renamedProperties;
}
- fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
- fs.writeFileSync(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
- fs.writeFileSync(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
+ writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.h`, duplicatePlatformDecls(layerH(layer)));
+ writeIfModified(`platform/darwin/src/${prefix}${camelize(layer.type)}${suffix}.mm`, layerM(layer));
+ writeIfModified(`platform/darwin/test/${prefix}${camelize(layer.type)}${suffix}Tests.mm`, testLayers(layer));
}
// Extract examples for guides from unit tests.
@@ -679,25 +732,25 @@ global.guideExample = function (guide, exampleId, os) {
return '```swift\n' + example + '\n```';
};
-fs.writeFileSync(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
+writeIfModified(`platform/ios/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'iOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
+writeIfModified(`platform/macos/docs/guides/For Style Authors.md`, forStyleAuthorsMD({
os: 'macOS',
renamedProperties: renamedPropertiesByLayerType,
layers: layers,
}));
-fs.writeFileSync(`platform/ios/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
+writeIfModified(`platform/ios/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
os: 'iOS',
}));
-fs.writeFileSync(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
+writeIfModified(`platform/macos/docs/guides/Using Style Functions at Runtime.md`, ddsGuideMD({
os: 'macOS',
}));
-fs.writeFileSync(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
+writeIfModified(`platform/ios/docs/guides/Tile URL Templates.md`, templatesMD({
os: 'iOS',
}));
-fs.writeFileSync(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
+writeIfModified(`platform/macos/docs/guides/Tile URL Templates.md`, templatesMD({
os: 'macOS',
}));
diff --git a/platform/darwin/scripts/style-spec-overrides-v8.json b/platform/darwin/scripts/style-spec-overrides-v8.json
index 67a6641fe7..12cfa31575 100644
--- a/platform/darwin/scripts/style-spec-overrides-v8.json
+++ b/platform/darwin/scripts/style-spec-overrides-v8.json
@@ -24,7 +24,10 @@
"doc": "An `MGLCircleStyleLayer` is a style layer that renders one or more filled circles on the map.\n\nUse a circle style layer to configure the visual appearance of point or point collection features in vector tiles loaded by an `MGLVectorSource` object or `MGLPointAnnotation`, `MGLPointFeature`, `MGLPointCollection`, or `MGLPointCollectionFeature` instances in an `MGLShapeSource` object.\n\nA circle style layer renders circles whose radii are measured in screen units. To display circles on the map whose radii correspond to real-world distances, use many-sided regular polygons and configure their appearance using an `MGLFillStyleLayer` object."
},
"raster": {
- "doc": "An `MGLRasterStyleLayer` is a style layer that renders raster tiles on the map.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` object. For example, you could use a raster style layer to render <a href=\"https://www.mapbox.com/satellite/\">Mapbox Satellite</a> imagery, a <a href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic."
+ "doc": "An `MGLRasterStyleLayer` is a style layer that renders georeferenced raster imagery on the map, especially raster tiles.\n\nUse a raster style layer to configure the color parameters of raster tiles loaded by an `MGLRasterSource` object or raster images loaded by an `MGLImageSource` object. For example, you could use a raster style layer to render <a href=\"https://www.mapbox.com/satellite/\">Mapbox Satellite</a> imagery, a <a href=\"https://www.mapbox.com/help/define-tileset/#raster-tilesets\">raster tile set</a> uploaded to Mapbox Studio, or a raster map authored in <a href=\"https://tilemill-project.github.io/tilemill/\">TileMill</a>, the classic Mapbox Editor, or Mapbox Studio Classic.\n\nRaster images may also be used as icons or patterns in a style layer. To register an image for use as an icon or pattern, use the `-[MGLStyle setImage:forName:]` method. To configure a point annotation’s image, use the `MGLAnnotationImage` class."
+ },
+ "hillshade": {
+ "doc": "An `MGLHillshadeStyleLayer` is a style layer that renders raster <a href=\"https://en.wikipedia.org/wiki/Digital_elevation_model\">digital elevation model</a> (DEM) tiles on the map.\n\nUse a hillshade style layer to configure the color parameters of raster tiles loaded by an `MGLRasterDEMSource` object. For example, you could use a hillshade style layer to render <a href=\"https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb\">Mapbox Terrain-RGB</a> data.\n\nTo display posterized hillshading based on vector shapes, as with the <a href=\"https://www.mapbox.com/vector-tiles/mapbox-terrain/\">Mapbox Terrain</a> source, use an `MGLVectorSource` object in conjunction with several `MGLFillStyleLayer` objects."
},
"background": {
"doc": "An `MGLBackgroundStyleLayer` is a style layer that covers the entire map. Use a background style layer to configure a color or pattern to show below all other map content. If the style’s other layers use the Mapbox Streets source, the background style layer is responsible for drawing land, whereas the oceans and other bodies of water are drawn by `MGLFillStyleLayer` objects.\n\nA background style layer is typically the bottommost layer in a style, because it covers the entire map and can occlude any layers below it. You can therefore access it by getting the last item in the `MGLStyle.layers` array.\n\nIf the background style layer is transparent or omitted from the style, any portion of the map view that does not show another style layer is transparent."
@@ -39,6 +42,12 @@
"icon-offset": {
"doc": "Offset distance of icon from its anchor."
},
+ "icon-image": {
+ "doc": "Name of image in sprite to use for drawing an image background. Within literal values, attribute names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named attribute. Expressions do not support this syntax; for equivalent functionality in expressions, use `stringByAppendingString:` and key path expressions."
+ },
+ "text-field": {
+ "doc": "Value to use for a text label. Within literal values, attribute names enclosed in curly brackets (e.g. `{token}`) are replaced with the value of the named attribute. Expressions do not support this syntax; for equivalent functionality in expressions, use `stringByAppendingString:` and key path expressions."
+ },
"text-font": {
"doc": "An array of font face names used to display the text.\n\nEach font name must be included in the `{fontstack}` portion of the JSON stylesheet’s <a href=\"https://www.mapbox.com/mapbox-gl-style-spec/#glyphs\"><code>glyphs</code></a> property. You can register a custom font when designing the style in Mapbox Studio. Fonts installed on the system are not used.\n\nThe first font named in the array is applied to the text. For each character in the text, if the first font lacks a glyph for the character, the next font is applied as a fallback, and so on."
},
diff --git a/platform/darwin/scripts/update-examples.js b/platform/darwin/scripts/update-examples.js
index d453c0e4ba..f87ed07288 100644..100755
--- a/platform/darwin/scripts/update-examples.js
+++ b/platform/darwin/scripts/update-examples.js
@@ -1,9 +1,12 @@
+#!/usr/bin/env node
'use strict';
const fs = require('fs');
const execFileSync = require('child_process').execFileSync;
const _ = require('lodash');
+require('../../../scripts/style-code');
+
const examplesSrc = fs.readFileSync('platform/darwin/test/MGLDocumentationExampleTests.swift', 'utf8');
// Regex extracts the following block
@@ -124,14 +127,7 @@ function completeExamples(os) {
}
// Write out the modified file contents.
- if (src === newSrc) {
- console.log('Skipping', path);
- } else {
- console.log('Updating', path);
- if (['0', 'false'].indexOf(process.env.DRY_RUN || '0') !== -1) {
- fs.writeFileSync(path, newSrc);
- }
- }
+ writeIfModified(path, newSrc)
});
});
}