summaryrefslogtreecommitdiff
path: root/platform/darwin/scripts/generate-style-code.js
diff options
context:
space:
mode:
Diffstat (limited to 'platform/darwin/scripts/generate-style-code.js')
-rwxr-xr-x[-rw-r--r--]platform/darwin/scripts/generate-style-code.js197
1 files changed, 125 insertions, 72 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',
}));