text: 'use strict';
  
  const fs = require('fs');
  const ejs = require('ejs');
  const spec = require('mapbox-gl-style-spec').latest;
  var colorParser = require('csscolorparser');
  
  function parseCSSColor(str) {
    var color = colorParser.parseCSSColor(str);
    return [
        color[0] / 255 * color[3], color[1] / 255 * color[3], color[2] / 255 * color[3], color[3]
    ];
  }
  
  global.camelize = function (str) {
    return str.replace(/(?:^|-)(.)/g, function (_, x) {
      return x.toUpperCase();
    });
  }
  
  global.camelizeWithLeadingLowercase = function (str) {
    return str.replace(/-(.)/g, function (_, x) {
      return x.toUpperCase();
    });
  }
  
  global.propertyType = function (property) {
    if (/-translate-anchor$/.test(property.name)) {
      return 'TranslateAnchorType';
    }
    if (/-(rotation|pitch)-alignment$/.test(property.name)) {
      return 'AlignmentType';
    }
    switch (property.type) {
    case 'boolean':
      return 'bool';
    case 'number':
      return 'float';
    case 'string':
      return 'std::string';
    case 'enum':
      return `${camelize(property.name)}Type`;
    case 'color':
      return `Color`;
    case 'array':
      if (property.length) {
        return `std::array<${propertyType({type: property.value})}, ${property.length}>`;
      } else {
        return `std::vector<${propertyType({type: property.value})}>`;
      }
    default: throw new Error(`unknown type for ${property.name}`)
    }
  }
  
  global.defaultValue = function (property) {
    // https://github.com/mapbox/mapbox-gl-native/issues/5258
    if (property.name === 'line-round-limit') {
      return 1;
    }
  
    switch (property.type) {
    case 'number':
      return property.default;
    case 'string':
      return JSON.stringify(property.default || "");
    case 'enum':
      if (property.default === undefined) {
        return `${propertyType(property)}::Undefined`;
      } else {
        return `${propertyType(property)}::${camelize(property.default)}`;
      }
    case 'color':
      return `{ ${parseCSSColor(property.default).join(', ')} }`
    case 'array':
      const defaults = (property.default || []).map((e) => defaultValue({ type: property.value, default: e }));
      if (property.length) {
        return `{{ ${defaults.join(', ')} }}`;
      } else {
        return `{ ${defaults.join(', ')} }`;
      }
    default:
      return property.default;
    }
  }
  
  const layerHpp = ejs.compile(fs.readFileSync('include/mbgl/style/layers/layer.hpp.ejs', 'utf8'), {strict: true});
  const layerCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer.cpp.ejs', 'utf8'), {strict: true});
  const propertiesHpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.hpp.ejs', 'utf8'), {strict: true});
  const propertiesCpp = ejs.compile(fs.readFileSync('src/mbgl/style/layers/layer_properties.cpp.ejs', 'utf8'), {strict: true});
  
  const layers = spec.layer.type.values.map((type) => {
    const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
      if (name !== 'visibility') {
        spec[`layout_${type}`][name].name = name;
        memo.push(spec[`layout_${type}`][name]);
      }
      return memo;
    }, []);
  
    const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
      spec[`paint_${type}`][name].name = name;
      memo.push(spec[`paint_${type}`][name]);
      return memo;
    }, []);
  
    return {
      type: type,
      layoutProperties: layoutProperties,
      paintProperties: paintProperties,
    };
  });
  
  for (const layer of layers) {
    fs.writeFileSync(`include/mbgl/style/layers/${layer.type}_layer.hpp`, layerHpp(layer));
    fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer.cpp`, layerCpp(layer));
  
    fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer_properties.hpp`, propertiesHpp(layer));
    fs.writeFileSync(`src/mbgl/style/layers/${layer.type}_layer_properties.cpp`, propertiesCpp(layer));
  }
  
  const propertySettersHpp = ejs.compile(fs.readFileSync('include/mbgl/style/conversion/make_property_setters.hpp.ejs', 'utf8'), {strict: true});
  fs.writeFileSync('include/mbgl/style/conversion/make_property_setters.hpp', propertySettersHpp({layers: layers}));
  