From fd910a19cd04b469a4b1ea8b2eddb6c0eee96ed7 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Wed, 15 Oct 2025 13:14:06 -0600 Subject: [PATCH 1/8] Linting/formatting --- devtools/regl_codegen/server.mjs | 81 ++++++-------- devtools/test_dashboard/server.mjs | 81 +++++++------- tasks/util/bundle_wrapper.mjs | 17 +-- test/jasmine/karma.conf.js | 164 +++++++++++++++-------------- 4 files changed, 162 insertions(+), 181 deletions(-) diff --git a/devtools/regl_codegen/server.mjs b/devtools/regl_codegen/server.mjs index 265c6572e3c..5c009d7c8f9 100644 --- a/devtools/regl_codegen/server.mjs +++ b/devtools/regl_codegen/server.mjs @@ -13,14 +13,7 @@ var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; var strict = args.strict; -var reglTraceList = [ - 'parcoords', - 'scattergl', - 'scatterpolargl', - 'splom' -]; - - +var reglTraceList = ['parcoords', 'scattergl', 'scatterpolargl', 'splom']; // Create server var _static = ecstatic({ @@ -32,13 +25,13 @@ var _static = ecstatic({ var tracesReceived = []; -var server = http.createServer(function(req, res) { - if(req.method === 'POST' && req.url === '/api/submit-code') { +var server = http.createServer(function (req, res) { + if (req.method === 'POST' && req.url === '/api/submit-code') { var body = ''; - req.on('data', function(data) { + req.on('data', function (data) { body += data; }); - req.on('end', function() { + req.on('end', function () { var data = JSON.parse(body); tracesReceived.push(data.trace); @@ -46,7 +39,7 @@ var server = http.createServer(function(req, res) { res.statusCode = 200; res.end(); }); - } else if(req.method === 'GET' && req.url === '/api/codegen-done') { + } else if (req.method === 'GET' && req.url === '/api/codegen-done') { console.log('Codegen complete'); console.log('Traces received:', tracesReceived); @@ -79,9 +72,9 @@ config.minify = false; await build(config); function getMockFiles() { - return new Promise(function(resolve, reject) { - fs.readdir(constants.pathToTestImageMocks, function(err, files) { - if(err) { + return new Promise(function (resolve, reject) { + fs.readdir(constants.pathToTestImageMocks, function (err, files) { + if (err) { reject(err); } else { resolve(files); @@ -91,7 +84,7 @@ function getMockFiles() { } function readFiles(files) { - var promises = files.map(function(file) { + var promises = files.map(function (file) { var filePath = path.join(constants.pathToTestImageMocks, file); return readFilePromise(filePath); }); @@ -101,22 +94,24 @@ function readFiles(files) { function createMocksList(files) { // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function(file) { + var jsonFiles = files.filter(function (file) { return file.name.substr(-5) === '.json'; }); - var mocksList = jsonFiles.map(function(file) { + var mocksList = jsonFiles.map(function (file) { var contents = JSON.parse(file.contents); // get plot type keywords from mocks - var types = contents.data.map(function(trace) { - return trace.type || 'scatter'; - }).reduce(function(acc, type, i, arr) { - if(arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); + var types = contents.data + .map(function (trace) { + return trace.type || 'scatter'; + }) + .reduce(function (acc, type, i, arr) { + if (arr.lastIndexOf(type) === i) { + acc.push(type); + } + return acc; + }, []); var filename = file.name.split(path.sep).pop(); @@ -145,9 +140,9 @@ function saveReglTracesToFile(traces) { } function readFilePromise(file) { - return new Promise(function(resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function(err, contents) { - if(err) { + return new Promise(function (resolve, reject) { + fs.readFile(file, { encoding: 'utf-8' }, function (err, contents) { + if (err) { reject(err); } else { resolve({ @@ -160,9 +155,9 @@ function readFilePromise(file) { } function writeFilePromise(path, contents) { - return new Promise(function(resolve, reject) { - fs.writeFile(path, contents, function(err) { - if(err) { + return new Promise(function (resolve, reject) { + fs.writeFile(path, contents, function (err) { + if (err) { reject(err); } else { resolve(path); @@ -178,31 +173,23 @@ function handleCodegen(data) { var pathToReglCodegenSrc = constants.pathToReglCodegenSrc; var pathToReglPrecompiledSrc = path.join(constants.pathToSrc, 'traces', trace, 'regl_precompiled.js'); - var header = [ - '\'use strict\';', - '', - ].join('\n'); + var header = ["'use strict';", ''].join('\n'); var imports = ''; - var exports = [ - '', - '/* eslint-disable quote-props */', - 'module.exports = {', - '', - ].join('\n'); + var exports = ['', '/* eslint-disable quote-props */', 'module.exports = {', ''].join('\n'); var varId = 0; - Object.entries(generated).forEach(function(kv) { + Object.entries(generated).forEach(function (kv) { var key = kv[0]; var value = kv[1]; var filePath = path.join(pathToReglCodegenSrc, key); fs.writeFileSync(filePath, 'module.exports = ' + value); - imports += 'var v' + varId + ' = require(\'../../' + path.join(constants.reglCodegenSubdir, key) + '\');\n'; - exports += ' \'' + key + '\': v' + varId + ',\n'; + imports += 'var v' + varId + " = require('../../" + path.join(constants.reglCodegenSubdir, key) + "');\n"; + exports += " '" + key + "': v" + varId + ',\n'; varId++; }); - if(varId > 0) { + if (varId > 0) { exports = exports.slice(0, -2) + '\n};\n'; } else { exports = 'module.exports = {};\n'; diff --git a/devtools/test_dashboard/server.mjs b/devtools/test_dashboard/server.mjs index b0adbd7ece4..ca6864887e1 100644 --- a/devtools/test_dashboard/server.mjs +++ b/devtools/test_dashboard/server.mjs @@ -1,5 +1,5 @@ import fs from 'fs'; -import path from 'path'; +import path from 'path'; import http from 'http'; import ecstatic from 'ecstatic'; import open from 'open'; @@ -17,7 +17,7 @@ var strict = args.strict; var mathjax3 = args.mathjax3; var mathjax3chtml = args.mathjax3chtml; -if(strict) { +if (strict) { config.entryPoints = ['./lib/index-strict.js']; } @@ -26,16 +26,11 @@ config.outfile = './build/plotly.js'; var mockFolder = constants.pathToTestImageMocks; // mock list -await getMockFiles() - .then(readFiles) - .then(createMocksList) - .then(saveMockListToFile); +await getMockFiles().then(readFiles).then(createMocksList).then(saveMockListToFile); // Devtools config var devtoolsConfig = { - entryPoints: [ - path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js') - ], + entryPoints: [path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js')], outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), format: 'cjs', globalName: 'Tabs', @@ -44,14 +39,14 @@ var devtoolsConfig = { sourcemap: false, plugins: [ glsl({ - minify: true, - }), + minify: true + }) ], define: { - global: 'window', + global: 'window' }, target: 'es2016', - logLevel: 'info', + logLevel: 'info' }; build(devtoolsConfig); @@ -70,7 +65,7 @@ function devServer() { }); const server = http.createServer((req, res) => { - if(strict) { + if (strict) { res.setHeader( 'Content-Security-Policy', // Comment/uncomment for testing CSP. Changes require a server restart. @@ -83,30 +78,30 @@ function devServer() { // "connect-src 'self'", // "object-src 'none'", // "base-uri 'self';", - "worker-src blob:", - ].join("; ") - ) + 'worker-src blob:' + ].join('; ') + ); } - staticFilesHandler(req, res) - }) + staticFilesHandler(req, res); + }); // Start the server up! server.listen(PORT); let indexName = 'index'; - if(mathjax3) indexName += '-mathjax3' - else if(mathjax3chtml) indexName += '-mathjax3chtml' - indexName += '.html' + if (mathjax3) indexName += '-mathjax3'; + else if (mathjax3chtml) indexName += '-mathjax3chtml'; + indexName += '.html'; // open up browser window open(`http://localhost:${PORT}/devtools/test_dashboard/${indexName}${strict ? '?strict=true' : ''}`); } function getMockFiles() { - return new Promise(function(resolve, reject) { - fs.readdir(mockFolder, function(err, files) { - if(err) { + return new Promise(function (resolve, reject) { + fs.readdir(mockFolder, function (err, files) { + if (err) { reject(err); } else { resolve(files); @@ -116,7 +111,7 @@ function getMockFiles() { } function readFiles(files) { - var promises = files.map(function(file) { + var promises = files.map(function (file) { var filePath = path.join(mockFolder, file); return readFilePromise(filePath); }); @@ -126,22 +121,24 @@ function readFiles(files) { function createMocksList(files) { // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function(file) { + var jsonFiles = files.filter(function (file) { return file.name.substr(-5) === '.json'; }); - var mocksList = jsonFiles.map(function(file) { + var mocksList = jsonFiles.map(function (file) { var contents = JSON.parse(file.contents); // get plot type keywords from mocks - var types = contents.data.map(function(trace) { - return trace.type || 'scatter'; - }).reduce(function(acc, type, i, arr) { - if(arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); + var types = contents.data + .map(function (trace) { + return trace.type || 'scatter'; + }) + .reduce(function (acc, type, i, arr) { + if (arr.lastIndexOf(type) === i) { + acc.push(type); + } + return acc; + }, []); var filename = file.name.split(path.sep).pop(); @@ -163,9 +160,9 @@ function saveMockListToFile(mocksList) { } function readFilePromise(file) { - return new Promise(function(resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function(err, contents) { - if(err) { + return new Promise(function (resolve, reject) { + fs.readFile(file, { encoding: 'utf-8' }, function (err, contents) { + if (err) { reject(err); } else { resolve({ @@ -178,9 +175,9 @@ function readFilePromise(file) { } function writeFilePromise(path, contents) { - return new Promise(function(resolve, reject) { - fs.writeFile(path, contents, function(err) { - if(err) { + return new Promise(function (resolve, reject) { + fs.writeFile(path, contents, function (err) { + if (err) { reject(err); } else { resolve(path); diff --git a/tasks/util/bundle_wrapper.mjs b/tasks/util/bundle_wrapper.mjs index 561588a58f5..51ba37edd26 100644 --- a/tasks/util/bundle_wrapper.mjs +++ b/tasks/util/bundle_wrapper.mjs @@ -35,17 +35,17 @@ export default async function _bundle(pathToIndex, pathToBundle, opts, cb) { config.outfile = pathToBundle; config.minify = !!opts.minify; - if(!opts.noCompressAttributes) { + if (!opts.noCompressAttributes) { config.plugins = basePlugins.concat([esbuildPluginStripMeta]); } - if(opts.noPlugins) config.plugins = []; + if (opts.noPlugins) config.plugins = []; await build(config); addWrapper(pathToBundle); - if(cb) cb(); + if (cb) cb(); } // Until https://github.com/evanw/esbuild/pull/513 is merged @@ -67,14 +67,5 @@ function addWrapper(path) { common.throwOnError ); - fsExtra.appendFile( - path, - [ - '', - 'window.Plotly = Plotly;', - 'return Plotly;', - '}));', - ].join('\n'), - common.throwOnError - ); + fsExtra.appendFile(path, ['', 'window.Plotly = Plotly;', 'return Plotly;', '}));'].join('\n'), common.throwOnError); } diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index b1f52a8306d..72cadf492d0 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -12,17 +12,24 @@ var argv = minimist(process.argv.slice(4), { boolean: [ 'mathjax3', 'info', - 'nowatch', 'randomize', - 'failFast', 'doNotFailOnEmptyTestSuite', - 'Chrome', 'Firefox', - 'verbose', 'showSkipped', 'report-progress', 'report-spec', 'report-dots' + 'nowatch', + 'randomize', + 'failFast', + 'doNotFailOnEmptyTestSuite', + 'Chrome', + 'Firefox', + 'verbose', + 'showSkipped', + 'report-progress', + 'report-spec', + 'report-dots' ], alias: { Chrome: 'chrome', Firefox: ['firefox', 'FF'], bundleTest: ['bundletest', 'bundle_test'], nowatch: 'no-watch', - failFast: 'fail-fast', + failFast: 'fail-fast' }, default: { info: false, @@ -37,78 +44,80 @@ var argv = minimist(process.argv.slice(4), { } }); -if(argv.info) { - console.log([ - 'plotly.js karma runner for jasmine tests CLI info', - '', - 'Examples:', - '', - 'Run `axes_test.js`, `bar_test.js` and `scatter_test.js` suites w/o `autoWatch`:', - ' $ npm run test-jasmine -- axes bar_test.js scatter --nowatch', - '', - 'Run all tests with the `noCI` tag on Firefox in a 1500px wide window:', - ' $ npm run test-jasmine -- --tags=noCI --FF --width=1500', - '', - 'Arguments:', - ' - All non-flagged arguments corresponds to the test suites in `test/jasmine/tests/` to be run.', - ' No need to add the `_test.js` suffix, we expand them correctly here.', - ' - `--bundleTest` set the bundle test suite `test/jasmine/bundle_tests/ to be run.', - ' Note that only one bundle test can be run at a time.', - ' - Use `--tags` to specify which `@` tags to test (if any) e.g `npm run test-jasmine -- --tags=gl`', - ' will run only gl tests.', - ' - Use `--skip-tags` to specify which `@` tags to skip (if any) e.g `npm run test-jasmine -- --skip-tags=gl`', - ' will skip all gl tests.', - '', - 'Other options:', - ' - `--info`: show this info message', - ' - `--mathjax3`: to load mathjax v3 in relevant test', - ' - `--Chrome` (alias `--chrome`): run test in (our custom) Chrome browser', - ' - `--Firefox` (alias `--FF`, `--firefox`): run test in (our custom) Firefox browser', - ' - `--nowatch (dflt: `false`, `true` on CI)`: run karma w/o `autoWatch` / multiple run mode', - ' - `--randomize` (dflt: `false`): randomize test ordering (useful to detect bad test teardown)', - ' - `--failFast` (dflt: `false`): exit karma upon first test failure', - ' - `--doNotFailOnEmptyTestSuite` (dflt: `false`): do not fail run when no spec are ran (either from bundle error OR tag filtering)', - ' - `--tags`: run only test with given tags (using the `jasmine-spec-tags` framework)', - ' - `--width`(dflt: 1035): set width of the browser window', - ' - `--height` (dflt: 617): set height of the browser window', - ' - `--verbose` (dflt: `false`): show test result using verbose reporter', - ' - `--showSkipped` show tests that are skipped', - ' - `--report-progress`: use *progress* reporter', - ' - `--report-spec`: use *spec* reporter', - ' - `--report-dots`: use *dots* reporter', - '', - 'For info on the karma CLI options run `npm run test-jasmine -- --help`' - ].join('\n')); +if (argv.info) { + console.log( + [ + 'plotly.js karma runner for jasmine tests CLI info', + '', + 'Examples:', + '', + 'Run `axes_test.js`, `bar_test.js` and `scatter_test.js` suites w/o `autoWatch`:', + ' $ npm run test-jasmine -- axes bar_test.js scatter --nowatch', + '', + 'Run all tests with the `noCI` tag on Firefox in a 1500px wide window:', + ' $ npm run test-jasmine -- --tags=noCI --FF --width=1500', + '', + 'Arguments:', + ' - All non-flagged arguments corresponds to the test suites in `test/jasmine/tests/` to be run.', + ' No need to add the `_test.js` suffix, we expand them correctly here.', + ' - `--bundleTest` set the bundle test suite `test/jasmine/bundle_tests/ to be run.', + ' Note that only one bundle test can be run at a time.', + ' - Use `--tags` to specify which `@` tags to test (if any) e.g `npm run test-jasmine -- --tags=gl`', + ' will run only gl tests.', + ' - Use `--skip-tags` to specify which `@` tags to skip (if any) e.g `npm run test-jasmine -- --skip-tags=gl`', + ' will skip all gl tests.', + '', + 'Other options:', + ' - `--info`: show this info message', + ' - `--mathjax3`: to load mathjax v3 in relevant test', + ' - `--Chrome` (alias `--chrome`): run test in (our custom) Chrome browser', + ' - `--Firefox` (alias `--FF`, `--firefox`): run test in (our custom) Firefox browser', + ' - `--nowatch (dflt: `false`, `true` on CI)`: run karma w/o `autoWatch` / multiple run mode', + ' - `--randomize` (dflt: `false`): randomize test ordering (useful to detect bad test teardown)', + ' - `--failFast` (dflt: `false`): exit karma upon first test failure', + ' - `--doNotFailOnEmptyTestSuite` (dflt: `false`): do not fail run when no spec are ran (either from bundle error OR tag filtering)', + ' - `--tags`: run only test with given tags (using the `jasmine-spec-tags` framework)', + ' - `--width`(dflt: 1035): set width of the browser window', + ' - `--height` (dflt: 617): set height of the browser window', + ' - `--verbose` (dflt: `false`): show test result using verbose reporter', + ' - `--showSkipped` show tests that are skipped', + ' - `--report-progress`: use *progress* reporter', + ' - `--report-spec`: use *spec* reporter', + ' - `--report-dots`: use *dots* reporter', + '', + 'For info on the karma CLI options run `npm run test-jasmine -- --help`' + ].join('\n') + ); process.exit(0); } var SUFFIX = '_test.js'; -var basename = function(s) { return path.basename(s, SUFFIX); }; -var merge = function(_) { +var basename = function (s) { + return path.basename(s, SUFFIX); +}; +var merge = function (_) { var list = []; - (Array.isArray(_) ? _ : [_]).forEach(function(p) { + (Array.isArray(_) ? _ : [_]).forEach(function (p) { list = list.concat(p.split(',')); }); return list; }; -var glob = function(_) { - return _.length === 1 ? - _[0] + SUFFIX : - '{' + _.join(',') + '}' + SUFFIX; +var glob = function (_) { + return _.length === 1 ? _[0] + SUFFIX : '{' + _.join(',') + '}' + SUFFIX; }; var isBundleTest = !!argv.bundleTest; var isFullSuite = !isBundleTest && argv._.length === 0; var testFileGlob; -if(isFullSuite) { +if (isFullSuite) { testFileGlob = path.join(__dirname, 'tests', '*' + SUFFIX); -} else if(isBundleTest) { +} else if (isBundleTest) { var _ = merge(argv.bundleTest); - if(_.length > 1) { + if (_.length > 1) { console.warn('Can only run one bundle test suite at a time, ignoring ', _.slice(1)); } @@ -124,15 +133,15 @@ var pathToMathJax3 = path.join(__dirname, '..', '..', 'node_modules', '@plotly/m var pathToVirtualWebgl = path.join(__dirname, '..', '..', 'node_modules', 'virtual-webgl', 'src', 'virtual-webgl.js'); var reporters = []; -if(argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { - if(argv['report-progress']) reporters.push('progress'); - if(argv['report-spec']) reporters.push('spec'); - if(argv['report-dots']) reporters.push('dots'); +if (argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { + if (argv['report-progress']) reporters.push('progress'); + if (argv['report-spec']) reporters.push('spec'); + if (argv['report-dots']) reporters.push('dots'); } else { - if(isCI) { + if (isCI) { reporters.push('spec'); } else { - if(isFullSuite) { + if (isFullSuite) { reporters.push('dots'); } else { reporters.push('progress'); @@ -142,10 +151,10 @@ if(argv['report-progress'] || argv['report-spec'] || argv['report-dots']) { var hasSpecReporter = reporters.indexOf('spec') !== -1; -if(!hasSpecReporter && argv.showSkipped) reporters.push('spec'); -if(argv.verbose) reporters.push('verbose'); +if (!hasSpecReporter && argv.showSkipped) reporters.push('spec'); +if (argv.verbose) reporters.push('verbose'); -if(process.argv.indexOf('--tags=noCI,noCIdep') !== -1) { +if (process.argv.indexOf('--tags=noCI,noCIdep') !== -1) { reporters = ['dots']; } @@ -169,7 +178,6 @@ function func(config) { } func.defaultConfig = { - // base path that will be used to resolve all patterns (eg. files, exclude) basePath: constants.pathToRoot, @@ -184,7 +192,7 @@ func.defaultConfig = { require('karma-spec-reporter'), require('karma-chrome-launcher'), require('karma-firefox-launcher'), - require('karma-esbuild'), + require('karma-esbuild') ], // list of files / patterns to load in the browser @@ -194,9 +202,9 @@ func.defaultConfig = { pathToCustomMatchers, // available to fetch from /base/node_modules/@plotly/mathjax-v2/ // more info: http://karma-runner.github.io/3.0/config/files.html - {pattern: pathToMathJax2 + '/**', included: false, watched: false, served: true}, - {pattern: pathToMathJax3 + '/**', included: false, watched: false, served: true}, - {pattern: pathToTopojsonDist + '/**', included: false, watched: false, served: true} + { pattern: pathToMathJax2 + '/**', included: false, watched: false, served: true }, + { pattern: pathToMathJax3 + '/**', included: false, watched: false, served: true }, + { pattern: pathToTopojsonDist + '/**', included: false, watched: false, served: true } ], // list of files / pattern to exclude @@ -253,7 +261,7 @@ func.defaultConfig = { '--touch-events', '--window-size=' + argv.width + ',' + argv.height, isCI ? '--ignore-gpu-blacklist' : '', - (isBundleTest && basename(testFileGlob) === 'no_webgl') ? '--disable-webgl' : '' + isBundleTest && basename(testFileGlob) === 'no_webgl' ? '--disable-webgl' : '' ] }, _Firefox: { @@ -318,11 +326,9 @@ func.defaultConfig = { func.defaultConfig.preprocessors[pathToCustomMatchers] = ['esbuild']; func.defaultConfig.preprocessors[testFileGlob] = ['esbuild']; -if(argv.virtualWebgl) { +if (argv.virtualWebgl) { // add virtual-webgl to the top - func.defaultConfig.files = [ - pathToVirtualWebgl - ].concat(func.defaultConfig.files); + func.defaultConfig.files = [pathToVirtualWebgl].concat(func.defaultConfig.files); } // lastly, load test file glob @@ -330,8 +336,8 @@ func.defaultConfig.files.push(testFileGlob); // add browsers var browsers = func.defaultConfig.browsers; -if(argv.Chrome) browsers.push('_Chrome'); -if(argv.Firefox) browsers.push('_Firefox'); -if(browsers.length === 0) browsers.push('_Chrome'); +if (argv.Chrome) browsers.push('_Chrome'); +if (argv.Firefox) browsers.push('_Firefox'); +if (browsers.length === 0) browsers.push('_Chrome'); module.exports = func; From dbe27dffa2d27025cc597d16d72741de4d928710 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Wed, 15 Oct 2025 13:53:23 -0600 Subject: [PATCH 2/8] Move esbuild configs to one file, update references --- biome.json | 1 + devtools/regl_codegen/server.mjs | 7 +--- devtools/test_dashboard/server.mjs | 32 ++-------------- esbuild-config.js | 59 ++++++++++++++++++++++-------- tasks/util/bundle_wrapper.mjs | 2 +- test/jasmine/karma.conf.js | 2 +- 6 files changed, 51 insertions(+), 52 deletions(-) diff --git a/biome.json b/biome.json index dd8691beddd..9f6e2acb25c 100644 --- a/biome.json +++ b/biome.json @@ -4,6 +4,7 @@ "files": { "maxSize": 10000000, "includes": [ + "**/esbuild-config.js", "**/src/**", "**/lib/**", "**/test/**", diff --git a/devtools/regl_codegen/server.mjs b/devtools/regl_codegen/server.mjs index 5c009d7c8f9..7e9af41ca29 100644 --- a/devtools/regl_codegen/server.mjs +++ b/devtools/regl_codegen/server.mjs @@ -7,7 +7,7 @@ import minimist from 'minimist'; import constants from '../../tasks/util/constants.js'; import { build } from 'esbuild'; -import config from '../../esbuild-config.js'; +import { esbuildConfig as config } from '../../esbuild-config.js'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; @@ -64,11 +64,6 @@ server.listen(PORT); // open up browser window open('http://localhost:' + PORT + '/devtools/regl_codegen/index' + (strict ? '-strict' : '') + '.html'); -var devtoolsPath = path.join(constants.pathToRoot, 'devtools/regl_codegen'); -config.entryPoints = [path.join(devtoolsPath, 'devtools.js')]; -config.outfile = './build/regl_codegen-bundle.js'; -config.sourcemap = false; -config.minify = false; await build(config); function getMockFiles() { diff --git a/devtools/test_dashboard/server.mjs b/devtools/test_dashboard/server.mjs index ca6864887e1..8d30410e7c6 100644 --- a/devtools/test_dashboard/server.mjs +++ b/devtools/test_dashboard/server.mjs @@ -7,9 +7,8 @@ import minimist from 'minimist'; import constants from '../../tasks/util/constants.js'; import { context, build } from 'esbuild'; -import config from '../../esbuild-config.js'; -import { glsl } from 'esbuild-plugin-glsl'; +import { devtoolsConfig, localDevConfig } from '../../esbuild-config.js'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; @@ -17,41 +16,16 @@ var strict = args.strict; var mathjax3 = args.mathjax3; var mathjax3chtml = args.mathjax3chtml; -if (strict) { - config.entryPoints = ['./lib/index-strict.js']; -} - -config.outfile = './build/plotly.js'; +if (strict) localDevConfig.entryPoints = ['./lib/index-strict.js']; var mockFolder = constants.pathToTestImageMocks; // mock list await getMockFiles().then(readFiles).then(createMocksList).then(saveMockListToFile); -// Devtools config -var devtoolsConfig = { - entryPoints: [path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js')], - outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), - format: 'cjs', - globalName: 'Tabs', - bundle: true, - minify: false, - sourcemap: false, - plugins: [ - glsl({ - minify: true - }) - ], - define: { - global: 'window' - }, - target: 'es2016', - logLevel: 'info' -}; - build(devtoolsConfig); -var ctx = await context(config); +var ctx = await context(localDevConfig); devServer(); console.log('watching esbuild...'); await ctx.watch(); diff --git a/esbuild-config.js b/esbuild-config.js index 3f37992ec0a..fac038ee953 100644 --- a/esbuild-config.js +++ b/esbuild-config.js @@ -1,30 +1,59 @@ -var glsl = require('esbuild-plugin-glsl').glsl; -var environmentPlugin = require('esbuild-plugin-environment').environmentPlugin; +const { environmentPlugin } = require('esbuild-plugin-environment'); +const { glsl } = require('esbuild-plugin-glsl'); const InlineCSSPlugin = require('esbuild-plugin-inline-css'); +const path = require('path'); +const constants = require('./tasks/util/constants.js'); -module.exports = { +// Default config used when building library +const esbuildConfig = { entryPoints: ['./lib/index.js'], format: 'iife', globalName: 'Plotly', bundle: true, minify: false, sourcemap: false, - plugins: [ - InlineCSSPlugin(), - glsl({ - minify: true, - }), - environmentPlugin({ - NODE_DEBUG: false, - }), - ], + plugins: [InlineCSSPlugin(), glsl({ minify: true }), environmentPlugin({ NODE_DEBUG: false })], alias: { - stream: 'stream-browserify', + stream: 'stream-browserify' }, define: { global: 'window', - 'define.amd': 'false', + 'define.amd': 'false' }, target: 'es2016', - logLevel: 'info', + logLevel: 'info' +}; + +const devtoolsConfig = { + entryPoints: [path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js')], + outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), + format: 'cjs', + globalName: 'Tabs', + bundle: true, + minify: false, + sourcemap: false, + plugins: [glsl({ minify: true })], + define: { global: 'window' }, + target: 'es2016', + logLevel: 'info' +}; + +const localDevConfig = { + ...esbuildConfig, + outfile: './build/plotly.js' +}; + +const localDevReglCodegenConfig = { + ...esbuildConfig, + entryPoints: [path.join(constants.pathToRoot, 'devtools/regl_codegen', 'devtools.js')], + outfile: './build/regl_codegen-bundle.js', + sourcemap: false, + minify: false +}; + +module.exports = { + devtoolsConfig, + esbuildConfig, + localDevConfig, + localDevReglCodegenConfig, }; diff --git a/tasks/util/bundle_wrapper.mjs b/tasks/util/bundle_wrapper.mjs index 51ba37edd26..a4cb0d43e62 100644 --- a/tasks/util/bundle_wrapper.mjs +++ b/tasks/util/bundle_wrapper.mjs @@ -4,7 +4,7 @@ import prependFile from 'prepend-file'; import { build } from 'esbuild'; -import esbuildConfig from '../../esbuild-config.js'; +import { esbuildConfig } from '../../esbuild-config.js'; import esbuildPluginStripMeta from '../../tasks/compress_attributes.js'; import common from './common.js'; diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index 72cadf492d0..c82cc9bfba6 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -3,7 +3,7 @@ var path = require('path'); var minimist = require('minimist'); var constants = require('../../tasks/util/constants'); -var esbuildConfig = require('../../esbuild-config.js'); +const { esbuildConfig } = require('../../esbuild-config.js'); var isCI = Boolean(process.env.CI); From 8c441308edb5142602b12a4fd095441a5aa3fbda Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Wed, 15 Oct 2025 13:54:08 -0600 Subject: [PATCH 3/8] Add build step to schema npm script --- devtools/test_dashboard/build.mjs | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 devtools/test_dashboard/build.mjs diff --git a/devtools/test_dashboard/build.mjs b/devtools/test_dashboard/build.mjs new file mode 100644 index 00000000000..3f437313a2f --- /dev/null +++ b/devtools/test_dashboard/build.mjs @@ -0,0 +1,7 @@ +import { build } from 'esbuild'; +import { localDevConfig } from '../../esbuild-config.js'; + +// Build plotly.js to be used locally, such as when generating the schema. +// This is the same process used in the test dashboard server script, but +// run only once. +build(localDevConfig); diff --git a/package.json b/package.json index 32ca49508b7..b401a11e2d3 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "bundle": "node tasks/bundle.mjs", "extra-bundles": "node tasks/extra_bundles.mjs", "locales": "node tasks/locales.js", - "schema": "node tasks/schema.mjs", + "schema": "node devtools/test_dashboard/build.mjs && node tasks/schema.mjs", "stats": "node tasks/stats.js", "find-strings": "node tasks/find_locale_strings.js", "preprocess": "node tasks/preprocess.js", From c8818ec1b162d7323ab391aa27f28042403be89b Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Thu, 16 Oct 2025 15:52:18 -0600 Subject: [PATCH 4/8] Linting/formatting --- tasks/schema.mjs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/tasks/schema.mjs b/tasks/schema.mjs index 2c332afbe48..e46b8a6d3bc 100644 --- a/tasks/schema.mjs +++ b/tasks/schema.mjs @@ -13,7 +13,7 @@ function isArray(v) { } function isObject(v) { - return typeof v === 'object' && v !== null && !(isArray(v)); + return typeof v === 'object' && v !== null && !isArray(v); } function isArrayOfObjects(v) { @@ -21,16 +21,12 @@ function isArrayOfObjects(v) { } function typeHandle(v) { - return ( - isArrayOfObjects(v) ? sortArrayOfObjects(v) : - isObject(v) ? sortObject(v) : - v - ); + return isArrayOfObjects(v) ? sortArrayOfObjects(v) : isObject(v) ? sortObject(v) : v; } function sortArrayOfObjects(list) { var newList = []; - for(var i = 0; i < list.length; i++) { + for (var i = 0; i < list.length; i++) { newList[i] = typeHandle(list[i]); } @@ -42,7 +38,7 @@ function sortObject(obj) { allKeys.sort(caseInsensitive); var newObj = {}; - for(var i = 0; i < allKeys.length; i++) { + for (var i = 0; i < allKeys.length; i++) { var key = allKeys[i]; newObj[key] = typeHandle(obj[key]); } @@ -64,7 +60,7 @@ function makeSchema(plotlyPath, schemaPath) { var lenAfterSort = plotSchemaStr.length; var linesBeforeSort = plotSchemaRaw.split('\n').length; var linesAfterSort = plotSchemaStr.split('\n').length; - if(linesAfterSort !== linesBeforeSort || lenAfterSort !== lenBeforeSort) { + if (linesAfterSort !== linesBeforeSort || lenAfterSort !== lenBeforeSort) { throw 'plot schema should have the same length & number of lines before and after sort'; } else { console.log('ok ' + path.basename(schemaPath)); @@ -73,13 +69,9 @@ function makeSchema(plotlyPath, schemaPath) { var isDist = process.argv.indexOf('dist') !== -1; -var pathToSchema = isDist ? - constants.pathToSchemaDist : - constants.pathToSchemaDiff; +var pathToSchema = isDist ? constants.pathToSchemaDist : constants.pathToSchemaDiff; -var pathToPlotly = isDist ? - constants.pathToPlotlyDistWithMeta : - constants.pathToPlotlyBuild; +var pathToPlotly = isDist ? constants.pathToPlotlyDistWithMeta : constants.pathToPlotlyBuild; // output plot-schema JSON makeSchema(pathToPlotly, pathToSchema); From 0ff3ebb0897f72ca33bb46820ca0767bb6f267d4 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Thu, 16 Oct 2025 16:45:47 -0600 Subject: [PATCH 5/8] Move build step into schema script --- devtools/test_dashboard/build.mjs | 7 ---- package.json | 2 +- tasks/schema.mjs | 63 ++++++++++++++----------------- 3 files changed, 30 insertions(+), 42 deletions(-) delete mode 100644 devtools/test_dashboard/build.mjs diff --git a/devtools/test_dashboard/build.mjs b/devtools/test_dashboard/build.mjs deleted file mode 100644 index 3f437313a2f..00000000000 --- a/devtools/test_dashboard/build.mjs +++ /dev/null @@ -1,7 +0,0 @@ -import { build } from 'esbuild'; -import { localDevConfig } from '../../esbuild-config.js'; - -// Build plotly.js to be used locally, such as when generating the schema. -// This is the same process used in the test dashboard server script, but -// run only once. -build(localDevConfig); diff --git a/package.json b/package.json index b401a11e2d3..32ca49508b7 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "bundle": "node tasks/bundle.mjs", "extra-bundles": "node tasks/extra_bundles.mjs", "locales": "node tasks/locales.js", - "schema": "node devtools/test_dashboard/build.mjs && node tasks/schema.mjs", + "schema": "node tasks/schema.mjs", "stats": "node tasks/stats.js", "find-strings": "node tasks/find_locale_strings.js", "preprocess": "node tasks/preprocess.js", diff --git a/tasks/schema.mjs b/tasks/schema.mjs index e46b8a6d3bc..b4a335f99dc 100644 --- a/tasks/schema.mjs +++ b/tasks/schema.mjs @@ -1,32 +1,24 @@ +import { build } from 'esbuild'; import fs from 'fs'; import path from 'path'; +import { localDevConfig } from '../esbuild-config.js'; import constants from './util/constants.js'; import plotlyNode from './util/plotly_node.mjs'; -function caseInsensitive(a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()); -} +const caseInsensitive = (a, b) => a.toLowerCase().localeCompare(b.toLowerCase()); -function isArray(v) { - return Array.isArray(v); -} +const { isArray } = Array; -function isObject(v) { - return typeof v === 'object' && v !== null && !isArray(v); -} +const isObject = (v) => typeof v === 'object' && v !== null && !isArray(v); -function isArrayOfObjects(v) { - return isArray(v) && isObject(v[0]); -} +const isArrayOfObjects = (v) => isArray(v) && isObject(v[0]); -function typeHandle(v) { - return isArrayOfObjects(v) ? sortArrayOfObjects(v) : isObject(v) ? sortObject(v) : v; -} +const typeHandle = (v) => (isArrayOfObjects(v) ? sortArrayOfObjects(v) : isObject(v) ? sortObject(v) : v); function sortArrayOfObjects(list) { - var newList = []; - for (var i = 0; i < list.length; i++) { + const newList = []; + for (let i = 0; i < list.length; i++) { newList[i] = typeHandle(list[i]); } @@ -34,12 +26,12 @@ function sortArrayOfObjects(list) { } function sortObject(obj) { - var allKeys = Object.keys(obj); + const allKeys = Object.keys(obj); allKeys.sort(caseInsensitive); - var newObj = {}; - for (var i = 0; i < allKeys.length; i++) { - var key = allKeys[i]; + const newObj = {}; + for (let i = 0; i < allKeys.length; i++) { + const key = allKeys[i]; newObj[key] = typeHandle(obj[key]); } @@ -47,19 +39,18 @@ function sortObject(obj) { } function makeSchema(plotlyPath, schemaPath) { - var Plotly = plotlyNode(plotlyPath); - - var obj = Plotly.PlotSchema.get(); - var sortedObj = sortObject(obj); - var plotSchemaRaw = JSON.stringify(obj, null, 1); - var plotSchemaStr = JSON.stringify(sortedObj, null, 1); + const Plotly = plotlyNode(plotlyPath); + const obj = Plotly.PlotSchema.get(); + const sortedObj = sortObject(obj); + const plotSchemaRaw = JSON.stringify(obj, null, 1); + const plotSchemaStr = JSON.stringify(sortedObj, null, 1); fs.writeFileSync(schemaPath, plotSchemaStr); - var lenBeforeSort = plotSchemaRaw.length; - var lenAfterSort = plotSchemaStr.length; - var linesBeforeSort = plotSchemaRaw.split('\n').length; - var linesAfterSort = plotSchemaStr.split('\n').length; + const lenBeforeSort = plotSchemaRaw.length; + const lenAfterSort = plotSchemaStr.length; + const linesBeforeSort = plotSchemaRaw.split('\n').length; + const linesAfterSort = plotSchemaStr.split('\n').length; if (linesAfterSort !== linesBeforeSort || lenAfterSort !== lenBeforeSort) { throw 'plot schema should have the same length & number of lines before and after sort'; } else { @@ -67,11 +58,15 @@ function makeSchema(plotlyPath, schemaPath) { } } -var isDist = process.argv.indexOf('dist') !== -1; +const isDist = process.argv.indexOf('dist') !== -1; + +const pathToSchema = isDist ? constants.pathToSchemaDist : constants.pathToSchemaDiff; -var pathToSchema = isDist ? constants.pathToSchemaDist : constants.pathToSchemaDiff; +const pathToPlotly = isDist ? constants.pathToPlotlyDistWithMeta : constants.pathToPlotlyBuild; -var pathToPlotly = isDist ? constants.pathToPlotlyDistWithMeta : constants.pathToPlotlyBuild; +// Build plotly.js to ensure changes to attributes are picked up. This is the same +// process used in the test dashboard server script, but run only once. +await build(localDevConfig); // output plot-schema JSON makeSchema(pathToPlotly, pathToSchema); From 9b651a9aee794531a62533172da3d1cc68906b9e Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 20 Oct 2025 13:58:47 -0600 Subject: [PATCH 6/8] Add descriptions to esbuild configs --- esbuild-config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esbuild-config.js b/esbuild-config.js index fac038ee953..77c6931cd48 100644 --- a/esbuild-config.js +++ b/esbuild-config.js @@ -24,6 +24,7 @@ const esbuildConfig = { logLevel: 'info' }; +// Config used when building bundle to serve test dashboard const devtoolsConfig = { entryPoints: [path.join(constants.pathToRoot, 'devtools', 'test_dashboard', 'devtools.js')], outfile: path.join(constants.pathToRoot, 'build', 'test_dashboard-bundle.js'), @@ -38,11 +39,13 @@ const devtoolsConfig = { logLevel: 'info' }; +// Config used when building plotly.js for local development const localDevConfig = { ...esbuildConfig, outfile: './build/plotly.js' }; +// Config used when building bundle to serve regl const localDevReglCodegenConfig = { ...esbuildConfig, entryPoints: [path.join(constants.pathToRoot, 'devtools/regl_codegen', 'devtools.js')], @@ -55,5 +58,5 @@ module.exports = { devtoolsConfig, esbuildConfig, localDevConfig, - localDevReglCodegenConfig, + localDevReglCodegenConfig }; From b61a0b8bfe16c51a6e1e4dad0de90a11494d1e1f Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 20 Oct 2025 13:59:08 -0600 Subject: [PATCH 7/8] Fix repo URL --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 32ca49508b7..d41047ca1cb 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "webpack": "./dist/plotly.js", "repository": { "type": "git", - "url": "https://github.com/plotly/plotly.js.git" + "url": "git+https://github.com/plotly/plotly.js.git" }, "bugs": { "url": "https://github.com/plotly/plotly.js/issues" From 570640cad4e19b205554f8794acc36700eacb645 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 20 Oct 2025 14:04:23 -0600 Subject: [PATCH 8/8] Move reused code into new file --- devtools/dashboard_utilities.mjs | 67 +++++++++++++++++ devtools/regl_codegen/server.mjs | 113 +++-------------------------- devtools/test_dashboard/server.mjs | 103 ++------------------------ 3 files changed, 84 insertions(+), 199 deletions(-) create mode 100644 devtools/dashboard_utilities.mjs diff --git a/devtools/dashboard_utilities.mjs b/devtools/dashboard_utilities.mjs new file mode 100644 index 00000000000..8ff5c109e61 --- /dev/null +++ b/devtools/dashboard_utilities.mjs @@ -0,0 +1,67 @@ +import fs from 'fs'; +import path from 'path'; +import constants from '../tasks/util/constants.js'; + +function readFilePromise(file) { + return new Promise((resolve, reject) => { + fs.readFile(file, { encoding: 'utf-8' }, (err, contents) => { + if (err) reject(err); + else resolve({ name: file, contents: contents }); + }); + }); +} + +function writeFilePromise(path, contents) { + return new Promise((resolve, reject) => { + fs.writeFile(path, contents, (err) => { + if (err) reject(err); + else resolve(path); + }); + }); +} + +export function getMockFiles() { + return new Promise((resolve, reject) => { + fs.readdir(constants.pathToTestImageMocks, (err, files) => { + if (err) reject(err); + else resolve(files); + }); + }); +} + +export function readFiles(files) { + const promises = files.map((file) => readFilePromise(path.join(constants.pathToTestImageMocks, file))); + + return Promise.all(promises); +} + +export function createMocksList(files) { + // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory + const jsonFiles = files.filter((file) => file.name.substr(-5) === '.json'); + + const mocksList = jsonFiles.map((file) => { + const contents = JSON.parse(file.contents); + + // get plot type keywords from mocks + const types = contents.data + .map((trace) => trace.type || 'scatter') + .reduce((acc, type, i, arr) => (arr.lastIndexOf(type) === i ? [...acc, type] : acc), []); + + const filename = file.name.split(path.sep).pop(); + + return { + name: filename.slice(0, -5), + file: filename, + keywords: types.join(', ') + }; + }); + + return mocksList; +} + +function saveListToFile(filePath, fileName) { + return (list) => writeFilePromise(path.join(filePath, fileName), JSON.stringify(list, null, 2)); +} + +export const saveMockListToFile = saveListToFile(constants.pathToBuild, 'test_dashboard_mocks.json'); +export const saveReglTracesToFile = saveListToFile(constants.pathToBuild, 'regl_traces.json'); diff --git a/devtools/regl_codegen/server.mjs b/devtools/regl_codegen/server.mjs index 7e9af41ca29..7cd15d8486f 100644 --- a/devtools/regl_codegen/server.mjs +++ b/devtools/regl_codegen/server.mjs @@ -1,13 +1,19 @@ +import ecstatic from 'ecstatic'; +import { build } from 'esbuild'; import fs from 'fs'; -import path from 'path'; import http from 'http'; -import ecstatic from 'ecstatic'; -import open from 'open'; import minimist from 'minimist'; - +import open from 'open'; +import path from 'path'; +import { localDevReglCodegenConfig as config } from '../../esbuild-config.js'; import constants from '../../tasks/util/constants.js'; -import { build } from 'esbuild'; -import { esbuildConfig as config } from '../../esbuild-config.js'; +import { + createMocksList, + getMockFiles, + readFiles, + saveMockListToFile, + saveReglTracesToFile +} from '../dashboard_utilities.mjs'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; @@ -66,101 +72,6 @@ open('http://localhost:' + PORT + '/devtools/regl_codegen/index' + (strict ? '-s await build(config); -function getMockFiles() { - return new Promise(function (resolve, reject) { - fs.readdir(constants.pathToTestImageMocks, function (err, files) { - if (err) { - reject(err); - } else { - resolve(files); - } - }); - }); -} - -function readFiles(files) { - var promises = files.map(function (file) { - var filePath = path.join(constants.pathToTestImageMocks, file); - return readFilePromise(filePath); - }); - - return Promise.all(promises); -} - -function createMocksList(files) { - // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function (file) { - return file.name.substr(-5) === '.json'; - }); - - var mocksList = jsonFiles.map(function (file) { - var contents = JSON.parse(file.contents); - - // get plot type keywords from mocks - var types = contents.data - .map(function (trace) { - return trace.type || 'scatter'; - }) - .reduce(function (acc, type, i, arr) { - if (arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); - - var filename = file.name.split(path.sep).pop(); - - return { - name: filename.slice(0, -5), - file: filename, - keywords: types.join(', ') - }; - }); - - return mocksList; -} - -function saveMockListToFile(mocksList) { - var filePath = path.join(constants.pathToBuild, 'test_dashboard_mocks.json'); - var content = JSON.stringify(mocksList, null, 4); - - return writeFilePromise(filePath, content); -} - -function saveReglTracesToFile(traces) { - var filePath = path.join(constants.pathToBuild, 'regl_traces.json'); - var content = JSON.stringify(traces, null, 4); - - return writeFilePromise(filePath, content); -} - -function readFilePromise(file) { - return new Promise(function (resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function (err, contents) { - if (err) { - reject(err); - } else { - resolve({ - name: file, - contents: contents - }); - } - }); - }); -} - -function writeFilePromise(path, contents) { - return new Promise(function (resolve, reject) { - fs.writeFile(path, contents, function (err) { - if (err) { - reject(err); - } else { - resolve(path); - } - }); - }); -} - function handleCodegen(data) { var trace = data.trace; var generated = data.generated; diff --git a/devtools/test_dashboard/server.mjs b/devtools/test_dashboard/server.mjs index 8d30410e7c6..f1c7ca071ed 100644 --- a/devtools/test_dashboard/server.mjs +++ b/devtools/test_dashboard/server.mjs @@ -1,14 +1,11 @@ -import fs from 'fs'; -import path from 'path'; -import http from 'http'; import ecstatic from 'ecstatic'; -import open from 'open'; +import { build, context } from 'esbuild'; +import http from 'http'; import minimist from 'minimist'; - -import constants from '../../tasks/util/constants.js'; -import { context, build } from 'esbuild'; - +import open from 'open'; import { devtoolsConfig, localDevConfig } from '../../esbuild-config.js'; +import constants from '../../tasks/util/constants.js'; +import { createMocksList, getMockFiles, readFiles, saveMockListToFile } from '../dashboard_utilities.mjs'; var args = minimist(process.argv.slice(2), {}); var PORT = args.port || 3000; @@ -18,8 +15,6 @@ var mathjax3chtml = args.mathjax3chtml; if (strict) localDevConfig.entryPoints = ['./lib/index-strict.js']; -var mockFolder = constants.pathToTestImageMocks; - // mock list await getMockFiles().then(readFiles).then(createMocksList).then(saveMockListToFile); @@ -71,91 +66,3 @@ function devServer() { // open up browser window open(`http://localhost:${PORT}/devtools/test_dashboard/${indexName}${strict ? '?strict=true' : ''}`); } - -function getMockFiles() { - return new Promise(function (resolve, reject) { - fs.readdir(mockFolder, function (err, files) { - if (err) { - reject(err); - } else { - resolve(files); - } - }); - }); -} - -function readFiles(files) { - var promises = files.map(function (file) { - var filePath = path.join(mockFolder, file); - return readFilePromise(filePath); - }); - - return Promise.all(promises); -} - -function createMocksList(files) { - // eliminate pollutants (e.g .DS_Store) that can accumulate in the mock directory - var jsonFiles = files.filter(function (file) { - return file.name.substr(-5) === '.json'; - }); - - var mocksList = jsonFiles.map(function (file) { - var contents = JSON.parse(file.contents); - - // get plot type keywords from mocks - var types = contents.data - .map(function (trace) { - return trace.type || 'scatter'; - }) - .reduce(function (acc, type, i, arr) { - if (arr.lastIndexOf(type) === i) { - acc.push(type); - } - return acc; - }, []); - - var filename = file.name.split(path.sep).pop(); - - return { - name: filename.slice(0, -5), - file: filename, - keywords: types.join(', ') - }; - }); - - return mocksList; -} - -function saveMockListToFile(mocksList) { - var filePath = path.join(constants.pathToBuild, 'test_dashboard_mocks.json'); - var content = JSON.stringify(mocksList, null, 4); - - return writeFilePromise(filePath, content); -} - -function readFilePromise(file) { - return new Promise(function (resolve, reject) { - fs.readFile(file, { encoding: 'utf-8' }, function (err, contents) { - if (err) { - reject(err); - } else { - resolve({ - name: file, - contents: contents - }); - } - }); - }); -} - -function writeFilePromise(path, contents) { - return new Promise(function (resolve, reject) { - fs.writeFile(path, contents, function (err) { - if (err) { - reject(err); - } else { - resolve(path); - } - }); - }); -}