Use ESM in Node.js code generation scripts (#2739)

This commit is contained in:
Bart Louwers
2024-08-23 14:31:36 +02:00
committed by GitHub
parent 8e2c84243a
commit 8ad4a51f2f
22 changed files with 241 additions and 579 deletions

View File

@@ -1,13 +1,9 @@
#!/usr/bin/env node
'use strict';
import { ArgumentParser } from "argparse";
import * as path from "node:path";
import spec from "./style-spec.mjs";
import colorParser from "csscolorparser";
const { ArgumentParser } = require("argparse");
const path = require('path');
const fs = require('fs');
const spec = require('./style-spec');
const colorParser = require('csscolorparser');
require('./style-code');
import { camelize, camelizeWithLeadingLowercase, readAndCompile, writeIfModified } from "./style-code.mjs";
// Parse command line
const args = (() => {
@@ -21,22 +17,33 @@ const args = (() => {
return parser.parse_args();
})();
function parseCSSColor(str) {
function parseCSSColor(/** @type {string} **/ str) {
const color = colorParser.parseCSSColor(str);
if (!color) throw new Error("Could not parse CSS color");
return [
color[0] / 255 * color[3], color[1] / 255 * color[3], color[2] / 255 * color[3], color[3]
];
}
global.isLightProperty = function (property) {
/**
* @param {any} property
*/
function isLightProperty(property) {
return property['light-property'] === true;
};
global.isOverridable = function (property) {
/**
* @param {any} property
*/
function isOverridable(property) {
return ['text-color'].includes(property.name);
};
global.expressionType = function (property) {
/**
* @param {any} property
* @returns {string}
*/
function expressionType(property) {
switch (property.type) {
case 'boolean':
return 'BooleanType';
@@ -57,7 +64,12 @@ global.expressionType = function (property) {
}
};
global.evaluatedType = function (property) {
/**
*
* @param {any} property
* @returns {string}
*/
function evaluatedType(property) {
if (/-translate-anchor$/.test(property.name)) {
return 'TranslateAnchorType';
}
@@ -102,7 +114,12 @@ global.evaluatedType = function (property) {
}
};
/**
* @param {any} property
* @param {any} type
*/
function attributeUniformType(property, type) {
/** @type {Record<string, string[]>} **/
const attributeNameExceptions = {
'text-opacity': ['opacity'],
'icon-opacity': ['opacity'],
@@ -120,6 +137,7 @@ function attributeUniformType(property, type) {
'fill-pattern': ['pattern_to', 'pattern_from'],
'fill-extrusion-pattern': ['pattern_to', 'pattern_from']
}
/** @type {string[]} **/
const names = attributeNameExceptions[property.name] ||
[ property.name.replace(type + '-', '').replace(/-/g, '_') ];
@@ -128,7 +146,10 @@ function attributeUniformType(property, type) {
}).join(', ');
}
global.layoutPropertyType = function (property) {
/**
* @param {any} property
*/
function layoutPropertyType(property) {
switch (property['property-type']) {
case 'data-driven':
case 'cross-faded-data-driven':
@@ -138,7 +159,13 @@ global.layoutPropertyType = function (property) {
}
};
global.paintPropertyType = function (property, type) {
/**
*
* @param {any} property
* @param {any} type
* @returns
*/
function paintPropertyType(property, type) {
switch (property['property-type']) {
case 'data-driven':
if (isOverridable(property))
@@ -153,7 +180,10 @@ global.paintPropertyType = function (property, type) {
}
};
global.propertyValueType = function (property) {
/**
* @param {any} property
*/
function propertyValueType(property) {
switch (property['property-type']) {
case 'color-ramp':
return `ColorRampPropertyValue`;
@@ -162,6 +192,11 @@ global.propertyValueType = function (property) {
}
};
/**
* @param {any} property
* @param {number} num
* @returns {string}
*/
function formatNumber(property, num = 0) {
if (evaluatedType(property) === "float") {
const str = num.toString();
@@ -170,7 +205,10 @@ function formatNumber(property, num = 0) {
return num.toString();
}
global.defaultValue = function (property) {
/**
* @param {any} property
*/
function defaultValue(property) {
// https://github.com/mapbox/mapbox-gl-native/issues/5258
if (property.name === 'line-round-limit') {
return 1;
@@ -210,7 +248,7 @@ global.defaultValue = function (property) {
return `{ ${color} }`;
}
case 'array':
const defaults = (property.default || []).map((e) => defaultValue({ type: property.value, default: e }));
const defaults = (property.default || []).map((/** @type {any} **/ e) => defaultValue({ type: property.value, default: e }));
if (property.length) {
return `{{${defaults.join(', ')}}}`;
} else {
@@ -222,7 +260,7 @@ global.defaultValue = function (property) {
};
console.log("Generating style code...");
const root = path.dirname(__dirname);
const root = path.join(import.meta.dirname, "..")
const outLocation = args.out ? args.out : root;
const layerHpp = readAndCompile(`include/mbgl/style/layers/layer.hpp.ejs`, root);
@@ -241,7 +279,9 @@ spec.paint_line['line-floor-width'] = {
};
const layers = Object.keys(spec.layer.type.values).map((type) => {
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((memo, name) => {
/** @type {any[]} */
const layoutProperties = Object.keys(spec[`layout_${type}`]).reduce((/** @type {any} **/ memo, name) => {
if (name !== 'visibility') {
spec[`layout_${type}`][name].name = name;
memo.push(spec[`layout_${type}`][name]);
@@ -253,7 +293,8 @@ const layers = Object.keys(spec.layer.type.values).map((type) => {
// to get a deterministic order.
layoutProperties.sort((a, b) => collator.compare(a.name, b.name));
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((memo, name) => {
/** @type {any[]} */
const paintProperties = Object.keys(spec[`paint_${type}`]).reduce((/** @type {any} **/ memo, name) => {
spec[`paint_${type}`][name].name = name;
memo.push(spec[`paint_${type}`][name]);
return memo;
@@ -273,7 +314,27 @@ const layers = Object.keys(spec.layer.type.values).map((type) => {
};
});
for (const layer of layers) {
function setupGlobalEjsHelpers() {
const funcs = {
layoutPropertyType,
evaluatedType,
isOverridable,
expressionType,
defaultValue,
paintPropertyType,
propertyValueType,
camelize,
camelizeWithLeadingLowercase
};
for (const [funcName, func] of Object.entries(funcs)) {
// @ts-ignore
global[funcName] = func;
}
}
setupGlobalEjsHelpers();
for (let layer of layers) {
const layerFileName = layer.type.replace('-', '_');
writeIfModified(`src/mbgl/style/layers/${layerFileName}_layer_properties.hpp`, propertiesHpp(layer), outLocation);
@@ -289,7 +350,8 @@ for (const layer of layers) {
}
// Light
const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => {
/** @type {any[]} **/
const lightProperties = Object.keys(spec[`light`]).reduce((/** @type {any} **/ memo, name) => {
var property = spec[`light`][name];
property.name = name;
property['light-property'] = true;

1
scripts/global.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
declare module "csscolorparser"

View File

@@ -3,9 +3,16 @@
"strict": true,
"allowJs": true,
"checkJs": true,
"module": "NodeNext"
"module": "NodeNext",
"skipLibCheck": true,
"resolveJsonModule": true,
"maxNodeModuleJsDepth": 0
},
"include": [
"**/*.mjs"
"./**/*.mjs",
"**/*.d.ts"
],
"exclude": [
"node_modules"
]
}

View File

@@ -1,42 +1,63 @@
// Global functions //
// EJS Helpers
const ejs = require('ejs');
const fs = require('fs');
const path = require('path');
import ejs from "ejs";
import fs from "node:fs";
global.iff = function (condition, val) {
import path from "node:path";
/**
* @param {() => boolean} condition
* @param {string} val
* @returns {string}
*/
export function iff(condition, val) {
return condition() ? val : "";
};
global.camelize = function (str) {
/**
* @param {string} str
* @returns {string}
*/
export function camelize(str) {
return str.replace(/(?:^|-)(.)/g, function (_, x) {
return x.toUpperCase();
});
};
global.camelizeWithLeadingLowercase = function (str) {
/**
* @param {string} str
* @returns {string}
*/
export function camelizeWithLeadingLowercase(str) {
return str.replace(/-(.)/g, function (_, x) {
return x.toUpperCase();
});
};
global.snakeCaseUpper = function snakeCaseUpper(str) {
export function snakeCaseUpper(/** @type {string} **/ str) {
return str.replace(/-/g, "_").toUpperCase();
};
global.unhyphenate = function (str) {
export function unhyphenate (/** @type {string} **/ str) {
return str.replace(/-/g, " ");
};
// Write out a list of files that this script is modifying so that we can check
var files = [];
/** @type {string[]} **/
let files = [];
process.on('exit', function() {
const list = path.join(path.dirname(process.argv[1]), path.basename(process.argv[1], '.js') + '.list');
console.log(`Writing files that this script modifies to: ${list}`);
fs.writeFileSync(list, files.join("\n"));
});
global.writeIfModified = function(filename, newContent, output) {
/**
*
* @param {string} filename
* @param {string} newContent
* @param {string} output
*/
export function writeIfModified(filename, newContent, output) {
if (output) {
filename = path.resolve(path.join(output, filename));
}
@@ -61,7 +82,13 @@ global.writeIfModified = function(filename, newContent, output) {
console.warn(`* Updating outdated file '${filename}'`);
};
global.readAndCompile = function(filename, root) {
/**
*
* @param {string} filename
* @param {string} root
* @returns
*/
export function readAndCompile(filename, root) {
if (root) {
filename = path.resolve(path.join(root, filename));
}

View File

@@ -1,7 +1,10 @@
const referenceSpec = require('../scripts/style-spec-reference/v8');
import referenceSpec from "../scripts/style-spec-reference/v8.json" with { type: "json" };
referenceSpec.layer.type.values["location-indicator"] = {};
referenceSpec["layout_location-indicator"] = {
/** @type {any} */
let modifiedReferenceSpec = referenceSpec;
modifiedReferenceSpec.layer.type.values["location-indicator"] = {};
modifiedReferenceSpec["layout_location-indicator"] = {
"top-image": {
"type": "resolvedImage",
"property-type": "data-constant",
@@ -37,7 +40,7 @@ referenceSpec["layout_location-indicator"] = {
}
};
referenceSpec["paint_location-indicator"] = {
modifiedReferenceSpec["paint_location-indicator"] = {
"perspective-compensation": {
"type": "number",
"default": "0.85",
@@ -65,7 +68,6 @@ referenceSpec["paint_location-indicator"] = {
},
"bearing": {
"type": "number",
"default": "0",
"default": 0,
"period": 360,
"units": "degrees",
@@ -176,21 +178,7 @@ referenceSpec["paint_location-indicator"] = {
},
"transition": true,
"doc": "The color for drawing the accuracy radius border. To adjust transparency, set the alpha component of the color accordingly."
},
"bearing": {
"type": "number",
"default": "0",
"default": 0,
"period": 360,
"units": "degrees",
"property-type": "data-constant",
"expression": {
"interpolated": false,
"parameters": [ ]
},
"transition": false,
"doc": "The bearing of the location indicator."
}
};
var spec = module.exports = referenceSpec
export default modifiedReferenceSpec;