diff options
Diffstat (limited to 'platform/darwin/scripts/generate-style-code.js')
-rwxr-xr-x[-rw-r--r--] | platform/darwin/scripts/generate-style-code.js | 197 |
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', })); |