From 9eafc51203d0739a37fce60e710367e1feba9dca Mon Sep 17 00:00:00 2001 From: Aleksandr Savelev <94454577+AleksSavelev@users.noreply.github.com> Date: Thu, 20 Jul 2023 09:41:46 +0200 Subject: [PATCH] Migrate to TypeScript (#467) * Updated webpack-plugin * Updated changelog * Migrated TS * Added lib to gitignore * Removed redundant changes * Removed redundant packages * Renamed utils file in tests. small review fixes * Fixed import in test file * Moved all subCommands into one pbiviz.js file * Updated Changelog * Returned deps related to fallback for webpack 5 * Fixed sub commands functions * fixed paths in webpack config * Fixed port option in start command * Updated packages * Migrated from uuid to crypto --------- Co-authored-by: AleksSavelev --- .eslintignore | 8 + .eslintrc.json | 309 +---- .gitignore | 1 + Changelog.md | 7 + README.md | 2 +- bin/pbiviz-info.js | 54 - bin/pbiviz-new.js | 82 -- bin/pbiviz-package.js | 122 -- bin/pbiviz-start.js | 142 --- bin/pbiviz.js | 91 +- config.json | 61 +- lib/CommandHelpManager.js | 51 - lib/VisualPackage.js | 118 -- lib/utils.js | 26 - lib/webpack.config.js | 149 --- package-lock.json | 1039 ++++++++++++++--- package.json | 32 +- spec/clean-tests.js | 2 +- spec/e2e/pbivizCertSpec.js | 27 +- spec/e2e/pbivizInfoSpec.js | 17 +- spec/e2e/pbivizNewSpec.js | 118 +- spec/e2e/pbivizPackageSpec.js | 176 ++- spec/e2e/pbivizStartSpec.js | 13 +- spec/e2e/pbivizWebpackVerSpec.js | 30 +- spec/e2e/{utils.js => testUtils.js} | 21 +- spec/helpers/FileSystem.js | 36 +- spec/jasmine-runner.js | 10 +- .../CertificateTools.ts | 178 +-- src/CommandManager.ts | 78 ++ lib/ConsoleWriter.js => src/ConsoleWriter.ts | 112 +- .../TemplateFetcher.ts | 44 +- .../VisualGenerator.ts | 41 +- src/VisualManager.ts | 220 ++++ lib/WebPackWrap.js => src/WebPackWrap.ts | 176 +-- src/utils.ts | 41 + src/webpack.config.ts | 144 +++ templates/pbiviz-json-template.js | 4 +- templates/pbiviz.json.template | 2 +- templates/plugin-ts-template.js | 2 +- templates/visuals/default/.eslintignore | 5 + templates/visuals/default/.eslintrc.js | 20 + templates/visuals/default/package.json | 17 +- templates/visuals/default/pbiviz.json | 5 +- templates/visuals/default/tsconfig.json | 4 +- templates/visuals/default/tslint.json | 9 - templates/visuals/rhtml/.eslintignore | 5 + templates/visuals/rhtml/.eslintrc.js | 20 + templates/visuals/rhtml/package.json | 13 +- templates/visuals/rhtml/pbiviz.json | 3 +- templates/visuals/rhtml/tslint.json | 9 - templates/visuals/rvisual/.eslintignore | 5 + templates/visuals/rvisual/.eslintrc.js | 20 + templates/visuals/rvisual/package.json | 9 +- templates/visuals/rvisual/tslint.json | 9 - templates/visuals/slicer/.eslintignore | 5 + templates/visuals/slicer/.eslintrc.js | 20 + templates/visuals/slicer/package.json | 15 +- templates/visuals/slicer/tslint.json | 9 - templates/visuals/table/.eslintignore | 5 + templates/visuals/table/.eslintrc.js | 20 + templates/visuals/table/package.json | 15 +- templates/visuals/table/tsconfig.json | 4 + templates/visuals/table/tslint.json | 9 - tsconfig.json | 22 + 64 files changed, 2171 insertions(+), 1892 deletions(-) create mode 100644 .eslintignore delete mode 100644 bin/pbiviz-info.js delete mode 100755 bin/pbiviz-new.js delete mode 100644 bin/pbiviz-package.js delete mode 100644 bin/pbiviz-start.js delete mode 100644 lib/CommandHelpManager.js delete mode 100644 lib/VisualPackage.js delete mode 100644 lib/utils.js delete mode 100644 lib/webpack.config.js rename spec/e2e/{utils.js => testUtils.js} (80%) rename lib/CertificateTools.js => src/CertificateTools.ts (71%) create mode 100644 src/CommandManager.ts rename lib/ConsoleWriter.js => src/ConsoleWriter.ts (58%) rename lib/TemplateFetcher.js => src/TemplateFetcher.ts (79%) rename lib/VisualGenerator.js => src/VisualGenerator.ts (87%) create mode 100644 src/VisualManager.ts rename lib/WebPackWrap.js => src/WebPackWrap.ts (59%) create mode 100644 src/utils.ts create mode 100644 src/webpack.config.ts create mode 100644 templates/visuals/default/.eslintignore create mode 100644 templates/visuals/default/.eslintrc.js delete mode 100644 templates/visuals/default/tslint.json create mode 100644 templates/visuals/rhtml/.eslintignore create mode 100644 templates/visuals/rhtml/.eslintrc.js delete mode 100644 templates/visuals/rhtml/tslint.json create mode 100644 templates/visuals/rvisual/.eslintignore create mode 100644 templates/visuals/rvisual/.eslintrc.js delete mode 100644 templates/visuals/rvisual/tslint.json create mode 100644 templates/visuals/slicer/.eslintignore create mode 100644 templates/visuals/slicer/.eslintrc.js delete mode 100644 templates/visuals/slicer/tslint.json create mode 100644 templates/visuals/table/.eslintignore create mode 100644 templates/visuals/table/.eslintrc.js delete mode 100644 templates/visuals/table/tslint.json create mode 100644 tsconfig.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..9e453d5b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,8 @@ +node_modules +dist +templates +webroot +spec +.eslintrc.json +lib +bin \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index e342b08c..ba1d684b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -3,310 +3,19 @@ "es6": true, "node": true }, + "parser": "@typescript-eslint/parser", "extends": "eslint:recommended", + "plugins": [ + "@typescript-eslint" + ], "parserOptions": { "ecmaVersion": 2023, - "sourceType": "module" + "sourceType": "module", + "project": "tsconfig.json", + "tsconfigRootDir": "." }, "rules": { - "accessor-pairs": "error", - "array-bracket-newline": "error", - "array-bracket-spacing": [ - "error", - "never" - ], - "array-callback-return": "off", - "array-element-newline": "off", - "arrow-body-style": "off", - "arrow-parens": "off", - "no-console": "off", - "arrow-spacing": [ - "error", - { - "after": true, - "before": true - } - ], - "block-scoped-var": "error", - "block-spacing": "error", - "brace-style": "off", - "callback-return": "off", - "camelcase": "error", - "capitalized-comments": "off", - "class-methods-use-this": "off", - "comma-dangle": "error", - "comma-spacing": [ - "error", - { - "after": true, - "before": false - } - ], - "comma-style": [ - "error", - "last" - ], - "complexity": "off", - "computed-property-spacing": [ - "error", - "never" - ], - "consistent-return": "off", - "consistent-this": "error", - "curly": "error", - "default-case": "error", - "dot-location": [ - "error", - "property" - ], - "dot-notation": [ - "error", - { - "allowKeywords": true - } - ], - "eol-last": "error", - "eqeqeq": "off", - "func-call-spacing": "error", - "func-name-matching": "error", - "func-names": [ - "error", - "never" - ], - "func-style": [ - "error", - "declaration", - { - "allowArrowFunctions": true - } - ], - "function-paren-newline": "off", - "generator-star-spacing": "error", - "global-require": "off", - "guard-for-in": "off", - "handle-callback-err": "error", - "id-blacklist": "error", - "id-length": "off", - "id-match": "error", - "implicit-arrow-linebreak": [ - "off", - "beside" - ], - "indent": "off", - "indent-legacy": "off", - "init-declarations": "off", - "jsx-quotes": "error", - "key-spacing": "error", - "keyword-spacing": [ - "error", - { - "after": true, - "before": true - } - ], - "line-comment-position": "off", - "linebreak-style": [ - "error", - "unix" - ], - "lines-around-comment": "off", - "lines-around-directive": "error", - "lines-between-class-members": "error", - "max-classes-per-file": "error", - "max-depth": "off", - "max-len": "off", - "max-lines": "off", - "max-lines-per-function": "off", - "max-nested-callbacks": "error", - "max-params": "off", - "max-statements": "off", - "max-statements-per-line": "off", - "multiline-comment-style": [ - "off", - "starred-block" - ], - "new-cap": "error", - "new-parens": "error", - "newline-after-var": "off", - "newline-before-return": "off", - "newline-per-chained-call": "off", - "no-alert": "error", - "no-array-constructor": "error", - "no-await-in-loop": "off", - "no-bitwise": "error", - "no-buffer-constructor": "error", - "no-caller": "error", - "no-catch-shadow": "error", - "no-confusing-arrow": "off", - "no-continue": "error", - "no-div-regex": "error", - "no-duplicate-imports": "error", - "no-else-return": "error", - "no-empty-function": "error", - "no-eq-null": "error", - "no-eval": "error", - "no-extend-native": "error", - "no-extra-bind": "error", - "no-extra-label": "error", - "no-extra-parens": "off", - "no-floating-decimal": "error", - "no-implicit-coercion": "error", - "no-implicit-globals": "error", - "no-implied-eval": "error", - "no-inline-comments": "off", - "no-invalid-this": "off", - "no-iterator": "error", - "no-label-var": "error", - "no-labels": "error", - "no-lone-blocks": "error", - "no-lonely-if": "error", - "no-loop-func": "error", - "no-magic-numbers": "off", - "no-mixed-operators": "error", - "no-mixed-requires": "error", - "no-multi-assign": "error", - "no-multi-spaces": "off", - "no-multi-str": "error", - "no-multiple-empty-lines": "error", - "no-native-reassign": "error", - "no-negated-condition": "off", - "no-negated-in-lhs": "error", - "no-nested-ternary": "off", - "no-new": "error", - "no-new-func": "error", - "no-new-object": "error", - "no-new-require": "error", - "no-new-wrappers": "error", - "no-octal-escape": "error", - "no-param-reassign": "off", - "no-case-declarations": "off", - "no-path-concat": "error", - "no-plusplus": [ - "off", - { - "allowForLoopAfterthoughts": true - } - ], - "no-process-env": "error", - "no-process-exit": "off", - "no-proto": "error", - "no-prototype-builtins": "off", - "no-restricted-globals": "error", - "no-restricted-imports": "error", - "no-restricted-modules": "error", - "no-restricted-properties": "error", - "no-restricted-syntax": "error", - "no-return-assign": "error", - "no-return-await": "error", - "no-script-url": "error", - "no-self-compare": "error", - "no-sequences": "error", - "no-shadow": "off", - "no-shadow-restricted-names": "error", - "no-spaced-func": "error", - "no-sync": "off", - "no-template-curly-in-string": "error", - "no-ternary": "off", - "no-throw-literal": "error", - "no-trailing-spaces": "off", - "no-undef-init": "error", - "no-undefined": "error", - "no-undef": "off", - "no-underscore-dangle": "off", - "no-unmodified-loop-condition": "error", - "no-unneeded-ternary": [ - "error", - { - "defaultAssignment": true - } - ], - "no-unused-expressions": "off", - "no-use-before-define": "off", - "no-useless-call": "error", - "no-useless-computed-key": "error", - "no-useless-concat": "error", - "no-useless-constructor": "error", - "no-useless-rename": "error", - "no-useless-return": "error", - "no-var": "error", - "no-void": "error", - "no-warning-comments": "off", - "no-whitespace-before-property": "error", - "no-with": "error", - "nonblock-statement-body-position": "error", - "object-curly-newline": "error", - "object-curly-spacing": [ - "error", - "always" - ], - "object-property-newline": "error", - "object-shorthand": "off", - "one-var": "off", - "one-var-declaration-per-line": [ - "error", - "initializations" - ], - "operator-assignment": "error", - "operator-linebreak": "error", - "padded-blocks": "off", - "padding-line-between-statements": "error", - "prefer-arrow-callback": "off", - "prefer-const": "off", - "prefer-destructuring": "off", - "prefer-numeric-literals": "error", - "prefer-object-spread": "error", - "prefer-promise-reject-errors": "off", - "prefer-reflect": "off", - "prefer-rest-params": "off", - "prefer-spread": "error", - "prefer-template": "off", - "quote-props": "off", - "quotes": "off", - "radix": "error", - "require-await": "warn", - "require-jsdoc": "off", - "rest-spread-spacing": "error", - "semi": "error", - "semi-spacing": [ - "error", - { - "after": true, - "before": false - } - ], - "semi-style": "off", - "sort-imports": "error", - "sort-keys": "off", - "sort-vars": "off", - "space-before-blocks": "error", - "space-before-function-paren": "off", - "space-in-parens": [ - "error", - "never" - ], - "space-infix-ops": "error", - "space-unary-ops": "error", - "spaced-comment": "off", - "strict": "off", - "switch-colon-spacing": "error", - "symbol-description": "error", - "template-curly-spacing": [ - "error", - "never" - ], - "template-tag-spacing": "error", - "unicode-bom": [ - "error", - "never" - ], - "valid-jsdoc": "off", - "vars-on-top": "error", - "wrap-iife": "error", - "wrap-regex": "off", - "yield-star-spacing": "error", - "yoda": [ - "error", - "never" - ] + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error" } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5a7bdce9..8267c195 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store node_modules +lib *.log spec/.tmp /certs diff --git a/Changelog.md b/Changelog.md index df3a3f1c..6ffd2182 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,13 @@ This page contains information about changes to the PowerBI Visual Tools (pbiviz). +## 5.0.0 +* Migrated to TypeScript +* Migrated to eslint +* Fixed vulnerabilities +* Migrated to newest CommanderJS +* Migrated to NodeJS 18.0 **⚠** + ## 4.3.2 * LocalizationLoader has been moved to `powerbi-visuals-webpack-plugin` diff --git a/README.md b/README.md index f99e777e..f8420899 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Before you can get started you'll need to install the tools. This should only ta Before you can run (or install) the command line tools you must install NodeJS. -* NodeJS 10.0+ Required - [Download NodeJS](https://nodejs.org) +* NodeJS 18.0+ Required - [Download NodeJS](https://nodejs.org) #### Installation diff --git a/bin/pbiviz-info.js b/bin/pbiviz-info.js deleted file mode 100644 index af0a2390..00000000 --- a/bin/pbiviz-info.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -let program = require('commander'); -let VisualPackage = require('../lib/VisualPackage'); -let ConsoleWriter = require('../lib/ConsoleWriter'); -let CommandHelpManager = require('../lib/CommandHelpManager'); -let options = process.argv; - -if (options.some(option => option === '--help' || option === '-h')) { - program.help(CommandHelpManager.createSubCommandHelpCallback(options)); - process.exit(0); -} - -program.parse(options); - -let cwd = process.cwd(); - -VisualPackage.loadVisualPackage(cwd).then((visualPackage) => { - let info = visualPackage.config; - if (info) { - ConsoleWriter.infoTable(info); - } else { - ConsoleWriter.error('Unable to load visual info. Please ensure the package is valid.'); - } -}).catch((e) => { - ConsoleWriter.error('LOAD ERROR', e); - process.exit(1); -}); diff --git a/bin/pbiviz-new.js b/bin/pbiviz-new.js deleted file mode 100755 index ccf221eb..00000000 --- a/bin/pbiviz-new.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -const program = require('commander'); -const VisualPackage = require('../lib/VisualPackage'); -const ConsoleWriter = require('../lib/ConsoleWriter'); -const CommandHelpManager = require('../lib/CommandHelpManager'); -const TemplateFetcher = require('../lib/TemplateFetcher'); -const config = require('../config.json'); -const options = process.argv; - -program - .option('-f, --force', 'force creation (overwrites folder if exists)') - .option('-t, --template [template]', 'use a specific template (default, table, slicer, rvisual, rhtml)'); - -if (options.some(option => option === '--help' || option === '-h')) { - program.help(CommandHelpManager.createSubCommandHelpCallback(options)); - process.exit(0); -} - -program.parse(options); - -let args = program.args; - -if (!args || args.length < 1) { - ConsoleWriter.error("You must enter a visual name"); - process.exit(1); -} - -let visualName = args.join(' '); -let cwd = process.cwd(); - -ConsoleWriter.info('Creating new visual'); - -if (program.force) { - ConsoleWriter.warn('Running with force flag. Existing files will be overwritten'); -} - -let generateOptions = { - force: program.force, - template: program.template -}; - -if (config.visualTemplates[generateOptions.template]) { - new TemplateFetcher({ - force: program.force, - templateName: generateOptions.template, - visualName: visualName - }).fetch(); -} else { - VisualPackage.createVisualPackage(cwd, visualName, generateOptions).then(() => { - ConsoleWriter.done('Visual creation complete'); - }).catch((e) => { - ConsoleWriter.error('Unable to create visual.\n', e); - process.exit(1); - }); -} diff --git a/bin/pbiviz-package.js b/bin/pbiviz-package.js deleted file mode 100644 index 0f4d5e68..00000000 --- a/bin/pbiviz-package.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -const program = require('commander'); -const compareVersions = require("compare-versions"); -const webpack = require("webpack"); - -const config = require('../config.json'); -const VisualPackage = require('../lib/VisualPackage'); -const ConsoleWriter = require('../lib/ConsoleWriter'); -const WebPackWrap = require('../lib/WebPackWrap'); -const CommandHelpManager = require('../lib/CommandHelpManager'); - -let options = process.argv; -const minAPIversion = config.constants.minAPIversion; - -program - .option('--resources', "Produces a folder containing the pbiviz resource files (js, css, json)") - .option('--no-pbiviz', "Doesn't produce a pbiviz file (must be used in conjunction with resources flag)") - .option('--no-minify', "Doesn't minify the js in the package (useful for debugging)") - .option('--no-plugin', "Doesn't include a plugin declaration to the package (must be used in conjunction with --no-pbiviz and --resources flags)") - .option('--no-stats', "Doesn't generate statistics files") - .option('-c, --compression ', "Enables compression of visual package", /^(0|1|2|3|4|5|6|7|8|9)$/i, "6"); - -if (options.some(option => option === '--help' || option === '-h')) { - program.help(CommandHelpManager.createSubCommandHelpCallback(options)); - process.exit(0); -} - -program.parse(options); - -let cwd = process.cwd(); - -if (!program.pbiviz && !program.resources) { - ConsoleWriter.error('Nothing to build. Cannot use --no-pbiviz without --resources'); - process.exit(1); -} - -VisualPackage.loadVisualPackage(cwd).then((visualPackage) => { - if (visualPackage.config.apiVersion && compareVersions.compare(visualPackage.config.apiVersion, minAPIversion, "<")) { - ConsoleWriter.error(`Package wasn't created, your current API is '${visualPackage.config.apiVersion}'. - Please use 'powerbi-visuals-api' ${minAPIversion} or above to build a visual.`); - process.exit(9); - } - ConsoleWriter.info('Building visual...'); - - new WebPackWrap().applyWebpackConfig(visualPackage, { - devMode: false, - generateResources: program.resources, - generatePbiviz: program.pbiviz, - minifyJS: program.minify, - minify: program.minify, - compression: program.compression, - disableStats: !program.stats - }).then(({ webpackConfig }) => { - let compiler = webpack(webpackConfig); - compiler.run(function (err, stats) { - if (err) { - ConsoleWriter.error(`Package wasn't created. ${JSON.stringify(err)}`); - } - if (stats.compilation.errors.length) { - ConsoleWriter.error(`Package wasn't created. ${stats.compilation.errors.length} errors found`); - } - displayCertificationRules(); - process.exit(0); - }); - }).catch(e => { - ConsoleWriter.error(e.message); - process.exit(1); - }); -}).catch(e => { - ConsoleWriter.error('LOAD ERROR', e); - process.exit(1); -}); - -function displayCertificationRules() { - ConsoleWriter.blank(); - ConsoleWriter.warn("Please, make sure that the visual source code matches to requirements of certification:"); - ConsoleWriter.blank(); - ConsoleWriter.info(`Visual must use API v${minAPIversion} and above`); - ConsoleWriter.info("The project repository must:"); - ConsoleWriter.info("Include package.json and package-lock.json;"); - ConsoleWriter.info("Not include node_modules folder"); - ConsoleWriter.info("Run npm install expect no errors"); - ConsoleWriter.info("Run pbiviz package expect no errors"); - ConsoleWriter.info("The compiled package of the Custom Visual should match submitted package."); - ConsoleWriter.info("npm audit command must not return any alerts with high or moderate level."); - ConsoleWriter.info("The project must include Tslint from Microsoft with no overridden configuration, and this command shouldn’t return any tslint errors."); - ConsoleWriter.info("https://www.npmjs.com/package/tslint-microsoft-contrib"); - ConsoleWriter.info("Ensure no arbitrary/dynamic code is run (bad: eval(), unsafe use of settimeout(), requestAnimationFrame(), setinterval(some function with user input).. running user input/data etc.)"); - ConsoleWriter.info("Ensure DOM is manipulated safely (bad: innerHTML, D3.html(), unsanitized user input/data directly added to DOM, etc.)"); - ConsoleWriter.info("Ensure no js errors/exceptions in browser console for any input data. As test dataset please use this sample report"); - ConsoleWriter.blank(); - ConsoleWriter.info("Full description of certification requirements you can find in documentation:"); - ConsoleWriter.info("https://docs.microsoft.com/en-us/power-bi/power-bi-custom-visuals-certified#certification-requirements"); -} - diff --git a/bin/pbiviz-start.js b/bin/pbiviz-start.js deleted file mode 100644 index 9b07f31d..00000000 --- a/bin/pbiviz-start.js +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -const program = require('commander'); -const compareVersions = require("compare-versions"); -const fs = require('fs-extra'); -const path = require('path'); -const webpack = require("webpack"); - -const config = require('../config.json'); -const VisualPackage = require('../lib/VisualPackage'); -const WebpackDevServer = require("webpack-dev-server"); -const ConsoleWriter = require('../lib/ConsoleWriter'); -const WebPackWrap = require('../lib/WebPackWrap'); -const CommandHelpManager = require('../lib/CommandHelpManager'); - -const options = process.argv; -const minAPIversion = config.constants.minAPIversion; - -program - .option('-p, --port [port]', 'set the port listening on') - .option('-m, --mute', 'mute error outputs') - .option('-d, --drop', 'drop outputs into output folder') - .option('--no-stats', "Doesn't generate statistics files"); - -if (options.some(option => option === '--help' || option === '-h')) { - program.help(CommandHelpManager.createSubCommandHelpCallback(options)); - process.exit(0); -} - -program.parse(options); - -let cwd = process.cwd(); -let server; -VisualPackage.loadVisualPackage(cwd).then((visualPackage) => { - if (visualPackage.config.apiVersion && compareVersions.compare(visualPackage.config.apiVersion, minAPIversion, "<")) { - ConsoleWriter.error(`Can't start the visual because of the current API is '${visualPackage.config.apiVersion}'. - Please use 'powerbi-visuals-api' ${minAPIversion} or above to build a visual.`); - throw new Error(`Invalid API version.`); - } - new WebPackWrap().applyWebpackConfig(visualPackage, { - devMode: true, - devtool: "source-map", - generateResources: true, - generatePbiviz: false, - minifyJS: false, - minify: false, - devServerPort: program.port, - disableStats: !program.stats - }) - .then(({ webpackConfig }) => { - let compiler = webpack(webpackConfig); - ConsoleWriter.blank(); - ConsoleWriter.info('Starting server...'); - // webpack dev server serves bundle from disk instead memory - if (program.drop) { - webpackConfig.devServer.onBeforeSetupMiddleware = (devServer) => { - let setHeaders = (res) => { - Object.getOwnPropertyNames(webpackConfig.devServer.headers) - .forEach(property => res.header(property, webpackConfig.devServer.headers[property])); - }; - let readFile = (file, res) => { - fs.readFile(file).then(function (content) { - res.write(content); - res.end(); - }); - }; - [ - 'visual.js`', - 'visual.css', - 'pbiviz.json' - ].forEach(asset => { - devServer.app.get(`${webpackConfig.devServer.publicPath}/${asset}`, function (req, res) { - setHeaders(res); - readFile(path.join(webpackConfig.devServer.static.directory, asset), res); - }); - }); - }; - } - - server = new WebpackDevServer({ - ...webpackConfig.devServer, - client: false, - hot: false, - devMiddleware: { - writeToDisk: true - } - }, compiler); - - (async () => { - await server.start(); - ConsoleWriter.info(`Server listening on port ${webpackConfig.devServer.port}`); - })(); - - }) - .catch(e => { - ConsoleWriter.error(e.message); - process.exit(1); - }); -}).catch(e => { - ConsoleWriter.error('LOAD ERROR', e); - process.exit(1); -}); - -//clean up -function stopServer() { - ConsoleWriter.blank(); - ConsoleWriter.info("Stopping server..."); - if (server) { - server.close(); - server = null; - } -} - -process.on('SIGINT', stopServer); -process.on('SIGTERM', stopServer); - diff --git a/bin/pbiviz.js b/bin/pbiviz.js index 1ec9ea6d..82d78b91 100755 --- a/bin/pbiviz.js +++ b/bin/pbiviz.js @@ -27,46 +27,65 @@ "use strict"; -let confPath = '../config.json'; -let program = require('commander'); -let npmPackage = require('../package.json'); -let ConsoleWriter = require('../lib/ConsoleWriter'); -let config = require(confPath); -let args = process.argv; -let CertificateTools = require("../lib/CertificateTools"); +import { createCertificate } from "../lib/CertificateTools.js"; +import ConsoleWriter from '../lib/ConsoleWriter.js'; +import CommandManager from '../lib/CommandManager.js'; +import { readJsonFromRoot } from '../lib/utils.js'; +import { Command, Option } from 'commander'; -ConsoleWriter.info(`${npmPackage.name} version - ${npmPackage.version}`); +const npmPackage = readJsonFromRoot('package.json'); +const rootPath = process.cwd(); +const program = new Command(); -program +const pbiviz = program .version(npmPackage.version) - .command('new [name]', 'Create a new visual') - .command('info', 'Display info about the current visual') - .command('start', 'Start the current visual') - .command('package', 'Package the current visual into a pbiviz file') - .option('--install-cert', 'Creates and installs localhost certificate', onOpenCertFile); + .option('--install-cert', 'Creates and installs localhost certificate', createCertificate) + .showHelpAfterError('Run "pbiviz help" for usage instructions.') + .addHelpText('beforeAll', ConsoleWriter.info(`${npmPackage.name} version - ${npmPackage.version}`)) + .addHelpText('before', ConsoleWriter.getLogoVisualization()); -//prepend logo to help screen -if (args.length === 2 || (args.length > 2 && args[2] === 'help')) { - ConsoleWriter.logo(); -} +pbiviz + .command('new') + .usage(" [options]") + .argument('', 'name of new visual') + .option('-f, --force', 'force creation (overwrites folder if exists)') + .addOption(new Option('-t, --template [template]', 'use a specific template') + .choices(['default', 'table', 'slicer', 'rvisual', 'rhtml', 'circlecard']) + .default('default') + ) + .action((name, options) => { + CommandManager.new(options, name, rootPath); + }); -program.parse(args); +pbiviz + .command('info') + .action(() => { + CommandManager.info(rootPath); + }); -if (program.args.length > 0) { - let validCommands = program.commands.map(c => c.name()); - if (validCommands.indexOf(program.args[0]) === -1) { - ConsoleWriter.error("Invalid command. Run 'pbiviz help' for usage instructions."); - process.exit(1); - } -} +pbiviz + .command('start') + .usage('[options]') + .option('-p, --port [port]', 'set the port listening on') + .option('-d, --drop', 'drop outputs into output folder') + .option('--no-stats', "Doesn't generate statistics files") + .action(async (options) => { + CommandManager.start(options, rootPath); + }); -async function onOpenCertFile() { - let certPath = await CertificateTools.getCertFile(config, true); - - if (!certPath) { - ConsoleWriter.error("Certificate not found. The new certificate will be generated"); - await CertificateTools.createCertFile(config, true); - } else { - await CertificateTools.openCertFile(config); - } -} +pbiviz + .command('package') + .usage('[options]') + .option('--resources', "Produces a folder containing the pbiviz resource files (js, css, json)") + .option('--no-pbiviz', "Doesn't produce a pbiviz file (must be used in conjunction with resources flag)") + .option('--no-minify', "Doesn't minify the js in the package (useful for debugging)") + .option('--no-stats', "Doesn't generate statistics files") + .addOption(new Option('-c, --compression ', "Enables compression of visual package") + .choices(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']) + .default('6') + ) + .action((options) => { + CommandManager.package(options, rootPath); + }); + +program.parse(process.argv); \ No newline at end of file diff --git a/config.json b/config.json index d7754e08..8677bd40 100644 --- a/config.json +++ b/config.json @@ -1,35 +1,28 @@ { - "templates": { - "visuals": "templates/visuals", - "pbiviz": "templates/pbiviz.json.template", - "plugin": "templates/plugin.ts.template", - "package": "templates/package.json.template" - }, - "generate": { - "apiVersion": "3.8.0" - }, - "constants": { - "minAPIversion": "3.2.0" - }, - "build": { - "precompileFolder": ".tmp/precompile", - "dropFolder": ".tmp/drop", - "js": "tmp.visual.js", - "css": "visual.css", - "stats": "../../webpack.statistics.html" - }, - "package": { - "dropFolder": "dist" - }, - "server": { - "root": "webRoot", - "assetsRoute": "/assets", - "privateKey": "certs/PowerBICustomVisualTest_private.key", - "certificate": "certs/PowerBICustomVisualTest_public.crt", - "pfx": "certs/PowerBICustomVisualTest_public.pfx", - "port": "8080" - }, - "visualTemplates": { - "circlecard": "https://codeload.github.com/microsoft/powerbi-visuals-circlecard-react/zip/master" - } -} \ No newline at end of file + "templates": { + "visuals": "templates/visuals", + "pbiviz": "templates/pbiviz.json.template", + "plugin": "templates/plugin.ts.template", + "package": "templates/package.json.template" + }, + "generate": { "apiVersion": "5.3.0" }, + "constants": { "minAPIversion": "4.7.0" }, + "build": { + "precompileFolder": ".tmp/precompile", + "dropFolder": ".tmp/drop", + "js": "tmp.visual.js", + "css": "visual.css", + "stats": "../../webpack.statistics.html" + }, + "package": { "dropFolder": "dist" }, + "server": { + "root": "webRoot", + "assetsRoute": "/assets", + "privateKey": "certs/PowerBICustomVisualTest_private.key", + "certificate": "certs/PowerBICustomVisualTest_public.crt", + "pfx": "certs/PowerBICustomVisualTest_public.pfx" + }, + "visualTemplates": { + "circlecard": "https://codeload.github.com/microsoft/powerbi-visuals-circlecard-react/zip/master" + } +} diff --git a/lib/CommandHelpManager.js b/lib/CommandHelpManager.js deleted file mode 100644 index cec93f86..00000000 --- a/lib/CommandHelpManager.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -let path = require('path'); -let basename = path.basename; -let targetString = "Usage:"; - -class CommandHelpmanager { - static createSubCommandHelpCallback(options) { - return (txt) => { - let targetPosition = txt.indexOf(targetString); - let preparedHelp = ""; - let subCommandName = basename(options[1], ".js").replace("-", " "); - - if (targetPosition !== -1) { - targetPosition += targetString.length + 1; - preparedHelp = [txt.slice(0, targetPosition), subCommandName, txt.slice(targetPosition)].join(''); - return preparedHelp; - } - - return txt; - }; - } -} - -module.exports = CommandHelpmanager; diff --git a/lib/VisualPackage.js b/lib/VisualPackage.js deleted file mode 100644 index 5f9be520..00000000 --- a/lib/VisualPackage.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Power BI Visual CLI - * - * Copyright (c) Microsoft Corporation - * All rights reserved. - * MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the ""Software""), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -"use strict"; - -let fs = require('fs-extra'); -let path = require('path'); -let VisualGenerator = require('../lib/VisualGenerator'); -let childProcess = require('child_process'); -let ConsoleWriter = require('../lib/ConsoleWriter'); - -const CONFIG_FILE = 'pbiviz.json'; - -/** - * Represents an instance of a visual package based on file path - */ -class VisualPackage { - /** - * Creates a new visual package - * - * @param {string} rootPath - file path to root of visual package - * @param {string} visualName - name of the visual to create in the rootPath - * @param {object} generateOptions - options for the visual generator - * } - instance of newly created visual package - */ - static createVisualPackage(rootPath, visualName, generateOptions) { - return VisualGenerator.generate(rootPath, visualName, generateOptions) - .then((visualPath) => VisualPackage.installPackages(visualPath) - .then(() => visualPath) - ) - .then((visualPath) => VisualPackage.loadVisualPackage(visualPath)); - } - - /** - * Loads an instance of a visual package from a file path - * - * @param {string} rootPath - file path to root of visual package - * @returns {Promise} - instance of newly created visual package - */ - static loadVisualPackage(rootPath) { - return new Promise((resolve, reject) => { - try { - resolve(new VisualPackage(rootPath)); - } catch (e) { - if (e && e.code && e.code === 'ENOENT') { - return reject(new Error(CONFIG_FILE + ' not found. You must be in the root of a visual project to run this command.')); - } - reject(e); - } - }); - } - - /** - * Install npm dependencies for visual - * @param {string} rootPath - file path to root of visual package - * @static - * @returns {Promise} - * @memberof VisualPackage - */ - static installPackages(visualPath) { - return new Promise(function (resolve, reject) { - ConsoleWriter.info('Installing packages...'); - childProcess.exec(`npm install`, { cwd: visualPath }, - (err) => { - if (err) { - reject(new Error('Package install failed.')); - } else { - ConsoleWriter.info('Installed packages.'); - resolve(); - } - }); - }); - } - - /** - * Creates a VisualPackage instance - * - * @param {string} rootPath - file path to root of visual package - */ - constructor(rootPath) { - this.basePath = rootPath; - this.config = fs.readJsonSync(this.buildPath(CONFIG_FILE)); - } - - /** - * Builds a path starting from the package base path - * - * @param {...*} arguments - arguments passed through to path.join - */ - buildPath() { - return path.join.apply(this, [this.basePath].concat(Array.from(arguments))); - } -} - -module.exports = VisualPackage; diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index ebbd13d6..00000000 --- a/lib/utils.js +++ /dev/null @@ -1,26 +0,0 @@ -const fs = require('fs-extra'); -let https = require("https"); -let path = require("path"); - -function download(url, pathToFile) { - return new Promise((resolve, reject) => { - const fileStream = fs.createWriteStream(pathToFile); - https.get(url, (res) => { - res.pipe(fileStream); - fileStream.on('close', () => resolve(fileStream)); - res.on('error', (error) => reject(error)); - }) - .on('error', (error) => reject(error)); - }); -} - -function createFolder(folderName) { - let folder = path.join("./", folderName); - fs.ensureDirSync(folder); - return folder; -} - -module.exports = { - download, - createFolder - }; diff --git a/lib/webpack.config.js b/lib/webpack.config.js deleted file mode 100644 index a29fa0ff..00000000 --- a/lib/webpack.config.js +++ /dev/null @@ -1,149 +0,0 @@ -const path = require("path"); -const webpack = require("webpack"); -const MiniCssExtractPlugin = require("mini-css-extract-plugin"); -const { LocalizationLoader } = require("powerbi-visuals-webpack-plugin"); -const TerserPlugin = require("terser-webpack-plugin"); -const config = require("../config.json"); - -module.exports = { - entry: { - 'visual.js': ['./src/visual.ts'] - }, - target: 'web', - devtool: false, - mode: "production", - optimization: { - minimizer: [ - new TerserPlugin({ - parallel: true, - terserOptions: {} - }) - ], - minimize: false, - concatenateModules: false - }, - performance: { - maxEntrypointSize: 1024000, - maxAssetSize: 1024000, - hints: false - }, - module: { - rules: [ - { - parser: { - amd: false - } - }, - { - test: /\.json$/, - loader: require.resolve('json-loader'), - type: "javascript/auto" - }, - { - test: /(\.less)|(\.css)$/, - use: [ - { - loader: MiniCssExtractPlugin.loader - }, - { - loader: require.resolve('css-loader') - }, - { - loader: require.resolve('less-loader'), - options: { - lessOptions: { - paths: [path.resolve(__dirname, "..", 'node_modules')] - } - } - } - ] - }, - { - test: /\.(woff|ttf|ico|woff2|jpg|jpeg|png|webp|gif|svg|eot)$/i, - type: 'asset/inline' - }, - { - test: /powerbiGlobalizeLocales\.js$/, - use: [ - { - loader: LocalizationLoader - } - ] - } - ] - }, - externals: { - "powerbi-visuals-api": 'null', - "fakeDefine": 'false', - "corePowerbiObject": "Function('return this.powerbi')()", - "realWindow": "Function('return this')()" - }, - resolve: { - extensions: ['.tsx', '.ts', '.jsx', '.js', '.css'], - fallback: { - assert: require.resolve("assert/"), - buffer: require.resolve("buffer/"), - console: require.resolve("console-browserify/"), - constants: require.resolve("constants-browserify/"), - crypto: require.resolve("crypto-browserify/"), - domain: require.resolve("domain-browser/"), - events: require.resolve("events/"), - http: require.resolve("stream-http/"), - https: require.resolve("https-browserify/"), - os: require.resolve("os-browserify/"), - path: require.resolve("path-browserify/"), - punycode: require.resolve("punycode/"), - process: require.resolve("process/"), - querystring: require.resolve("querystring-es3/"), - stream: require.resolve("stream-browserify/"), - /* eslint-disable camelcase */ - _stream_duplex: require.resolve("readable-stream/"), - _stream_passthrough: require.resolve("readable-stream/"), - _stream_readable: require.resolve("readable-stream/"), - _stream_transform: require.resolve("readable-stream/"), - _stream_writable: require.resolve("readable-stream/"), - string_decoder: require.resolve("string_decoder/"), - /* eslint-enable camelcase */ - sys: require.resolve("util/"), - timers: require.resolve("timers-browserify/"), - tty: require.resolve("tty-browserify/"), - url: require.resolve("url/"), - util: require.resolve("util/"), - vm: require.resolve("vm-browserify/"), - zlib: require.resolve("browserify-zlib/") - } - }, - output: { - path: null, - publicPath: 'assets', - filename: "[name]" - }, - devServer: { - allowedHosts: "all", - static: { - directory: null - }, - compress: true, - port: 8080, - hot: false, - server: 'https', - headers: { - "access-control-allow-origin": "*", - "cache-control": "public, max-age=0" - } - }, - plugins: [ - new webpack.ProvidePlugin({ - $: 'jquery', - jQuery: 'jquery', - d3: 'd3', - Buffer: ["buffer", "Buffer"], - process: "process/browser" - }), - new MiniCssExtractPlugin({ - filename: config.build.css, - chunkFilename: "[id].css" - }) - ] -}; - diff --git a/package-lock.json b/package-lock.json index 9484af52..f06f47be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,21 +1,22 @@ { "name": "powerbi-visuals-tools", - "version": "4.3.3", + "version": "5.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "powerbi-visuals-tools", - "version": "4.3.3", + "version": "5.0.0", "license": "MIT", "dependencies": { + "@typescript-eslint/parser": "^5.62.0", "assert": "^2.0.0", "async": "^3.2.4", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", - "chalk": "3.0.0", - "commander": "4.1.1", - "compare-versions": "^3.6.0", + "chalk": "^5.3.0", + "commander": "^11.0.0", + "compare-versions": "^6.0.0", "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", @@ -25,6 +26,7 @@ "extra-watch-webpack-plugin": "^1.0.3", "fs-extra": "^11.1.1", "https-browserify": "^1.0.0", + "inline-source-map": "^0.6.2", "json-loader": "0.5.7", "jszip": "^3.10.1", "less": "^4.1.3", @@ -43,15 +45,15 @@ "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "string_decoder": "^1.3.0", + "terser-webpack-plugin": "^5.3.9", "timers-browserify": "^2.0.12", "ts-loader": "^9.4.4", "tty-browserify": "0.0.1", "typescript": "^4.9.5", "url": "^0.11.1", "util": "^0.12.5", - "uuid": "9.0.0", "vm-browserify": "^1.1.2", - "webpack": "^5.88.1", + "webpack": "^5.88.2", "webpack-bundle-analyzer": "4.9.0", "webpack-dev-server": "^4.15.1" }, @@ -59,14 +61,17 @@ "pbiviz": "bin/pbiviz.js" }, "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.62.0", "eslint": "^8.45.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", "jasmine": "5.0.2", "jasmine-spec-reporter": "7.0.0", "semver": "7.5.4", - "tree-kill": "1.2.2" + "tree-kill": "1.2.2", + "webpack-cli": "^5.1.4" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" }, "optionalDependencies": { "fsevents": "*" @@ -76,7 +81,6 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -93,7 +97,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -108,7 +111,6 @@ "version": "4.5.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", - "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -117,7 +119,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", - "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -140,7 +141,6 @@ "version": "8.44.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -149,7 +149,6 @@ "version": "0.11.10", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", - "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -163,7 +162,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "engines": { "node": ">=12.22" }, @@ -175,8 +173,7 @@ "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -283,7 +280,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -296,7 +292,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -305,7 +300,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -451,6 +445,12 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, + "node_modules/@types/semver": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "dev": true + }, "node_modules/@types/send": { "version": "0.17.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", @@ -494,6 +494,189 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -625,6 +808,50 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -681,7 +908,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -768,7 +994,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -802,14 +1027,21 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-flatten": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, "node_modules/asn1.js": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", @@ -1181,15 +1413,14 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001516", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001516.tgz", - "integrity": "sha512-Wmec9pCBY8CWbmI4HsjBeQLqDTqV91nFVR83DnZpYyRnPI1wePDsTg0bGLPC5VU/3OIZV1fmxEea1b+tFKe86g==", + "version": "1.0.30001517", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001517.tgz", + "integrity": "sha512-Vdhm5S11DaFVLlyiKu4hiUTkpZu+y1KA/rZZqVQfOD5YdDT/eQKlkt7NaE0WGOFgX32diqt9MiP9CAiFeRklaA==", "funding": [ { "type": "opencollective", @@ -1206,15 +1437,14 @@ ] }, "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { - "node": ">=8" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/chokidar": { @@ -1271,6 +1501,20 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1302,17 +1546,17 @@ } }, "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz", + "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==", "engines": { - "node": ">= 6" + "node": ">=16" } }, "node_modules/compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.0.0.tgz", + "integrity": "sha512-s2MzYxfRsE9f/ow8hjn7ysa7pod1xhHdQMsgiJtKx6XSNf4x2N1KG4fjrkUmXcP/e9Y2ZX4zB6sHIso0Lm6evQ==" }, "node_modules/compressible": { "version": "2.0.18", @@ -1559,8 +1803,7 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/default-gateway": { "version": "6.0.3", @@ -1642,6 +1885,17 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -1662,7 +1916,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -1698,9 +1951,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.461", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.461.tgz", - "integrity": "sha512-1JkvV2sgEGTDXjdsaQCeSwYYuhLRphRpc+g6EHTFELJXEiznLt3/0pZ9JuAOQ5p2rI3YxKTbivtvajirIfhrEQ==" + "version": "1.4.464", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.464.tgz", + "integrity": "sha512-guZ84yoou4+ILNdj0XEbmGs6DEWj6zpVOWYpY09GU66yEb0DSYvP/biBPzHn0GuW/3RC/pnaYNUWlQE1fJYtgA==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -1747,6 +2000,18 @@ "node": ">=10.13.0" } }, + "node_modules/envinfo": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", + "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/errno": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", @@ -1786,7 +2051,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -1798,7 +2062,6 @@ "version": "8.45.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz", "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==", - "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", @@ -1848,27 +2111,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-powerbi-visuals": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-powerbi-visuals/-/eslint-plugin-powerbi-visuals-0.8.1.tgz", + "integrity": "sha512-GAdD5kIO2+X+WsTGW9DvfQ5sd2UFw+0FaPGYPsq2Dpt0RuVdfpHG58PJF7YWzjQmtr2EUGGJUbCALq4v3hK+JQ==", + "dev": true + }, "node_modules/eslint-scope": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", - "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", - "dev": true, + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dependencies": { "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "estraverse": "^4.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=8.0.0" } }, "node_modules/eslint-visitor-keys": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -1880,7 +2144,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -1892,11 +2155,44 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz", + "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -1913,7 +2209,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -1921,6 +2216,14 @@ "node": ">=0.10" } }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1932,7 +2235,7 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { + "node_modules/esrecurse/node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -1940,11 +2243,18 @@ "node": ">=4.0" } }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2098,6 +2408,32 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-glob": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz", + "integrity": "sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2106,14 +2442,21 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -2133,7 +2476,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -2186,7 +2528,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -2202,7 +2543,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -2214,8 +2554,7 @@ "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" }, "node_modules/follow-redirects": { "version": "1.15.2", @@ -2377,7 +2716,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -2394,7 +2732,6 @@ "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -2405,6 +2742,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -2424,8 +2780,7 @@ "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "node_modules/gzip-size": { "version": "6.0.0", @@ -2730,7 +3085,6 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, "engines": { "node": ">= 4" } @@ -2756,7 +3110,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2768,11 +3121,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "engines": { "node": ">=0.8.19" } @@ -2791,6 +3162,23 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA==", + "dependencies": { + "source-map": "~0.5.3" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -2836,6 +3224,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-core-module": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", + "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -2919,7 +3319,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2935,6 +3334,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -2947,15 +3358,11 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -2990,6 +3397,15 @@ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jackspeak": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", @@ -3095,25 +3511,10 @@ "node": ">= 10.13.0" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -3139,8 +3540,7 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/jsonfile": { "version": "6.1.0", @@ -3191,6 +3591,15 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/launch-editor": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", @@ -3241,11 +3650,19 @@ "webpack": "^5.0.0" } }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -3274,7 +3691,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -3308,8 +3724,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.uniq": { "version": "4.5.0", @@ -3388,6 +3803,14 @@ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -3605,7 +4028,12 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, "node_modules/needle": { @@ -3784,7 +4212,6 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -3806,7 +4233,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -3821,7 +4247,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -3844,6 +4269,15 @@ "node": ">=8" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -3853,7 +4287,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -3898,7 +4331,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -3919,6 +4351,12 @@ "node": ">=8" } }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, "node_modules/path-scurry": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", @@ -3949,6 +4387,14 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -3989,6 +4435,70 @@ "node": ">=6" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/postcss": { "version": "8.4.26", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.26.tgz", @@ -4135,6 +4645,11 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/powerbi-visuals-webpack-plugin/node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + }, "node_modules/powerbi-visuals-webpack-plugin/node_modules/fs-extra": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", @@ -4149,6 +4664,17 @@ "node": ">=10" } }, + "node_modules/powerbi-visuals-webpack-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/powerbi-visuals-webpack-plugin/node_modules/universalify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", @@ -4161,7 +4687,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "engines": { "node": ">= 0.8.0" } @@ -4257,7 +4782,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -4357,6 +4881,18 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -4370,11 +4906,48 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -4391,7 +4964,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4424,7 +4996,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -4670,6 +5241,18 @@ "sha.js": "bin.js" } }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4728,6 +5311,14 @@ "node": ">= 10" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -4747,9 +5338,9 @@ } }, "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "engines": { "node": ">=0.10.0" } @@ -4771,6 +5362,14 @@ "source-map": "^0.6.0" } }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -4943,7 +5542,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4976,7 +5574,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, @@ -4985,14 +5582,29 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dependencies": { "has-flag": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/tapable": { @@ -5078,8 +5690,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/thunky": { "version": "1.1.0", @@ -5166,11 +5777,41 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tslib": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz", "integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA==" }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", @@ -5180,7 +5821,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -5192,7 +5832,6 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -5316,14 +5955,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -5358,9 +5989,9 @@ } }, "node_modules/webpack": { - "version": "5.88.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.1.tgz", - "integrity": "sha512-FROX3TxQnC/ox4N+3xQoWZzvGXSuscxR32rbzjpXgEzWudJFEJBpdlkkob2ylrv5yzzufD1zph1OoFsLtm6stQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.0", @@ -5449,6 +6080,71 @@ "node": ">= 10" } }, + "node_modules/webpack-bundle-analyzer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/webpack-dev-middleware": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", @@ -5647,32 +6343,25 @@ } } }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/webpack-merge": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz", + "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==", + "dev": true, "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=10.0.0" } }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "engines": { - "node": ">=4.0" + "node": ">=10.13.0" } }, "node_modules/webpack/node_modules/schema-utils": { @@ -5728,16 +6417,15 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.10.tgz", - "integrity": "sha512-uxoA5vLUfRPdjCuJ1h5LlYdmTLbYfums398v3WLkM+i/Wltl2/XyZpQWKbN++ck5L64SR/grOHqtXCUKmlZPNA==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -5746,6 +6434,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, "node_modules/wrap-ansi": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", @@ -5882,7 +6576,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 54667faf..367c7368 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,17 @@ { "name": "powerbi-visuals-tools", - "version": "4.3.3", + "version": "5.0.0", "description": "Command line tool for creating and publishing visuals for Power BI", - "main": "./lib/VisualPackage.js", + "main": "./bin/pbiviz.js", + "type": "module", "scripts": { - "start": "node ./bin/pbiviz.js", - "test": "npm run clean-tests && npm run lint && npm run jasmine", + "build": "tsc", + "pbiviz": "node ./bin/pbiviz.js", + "start": "npm run pbiviz start", + "test": "npm run build && npm run clean-tests && npm run lint && npm run jasmine", "jasmine": "node spec/jasmine-runner.js", "jasmine-inspect": "node --inspect spec/jasmine-runner.js", - "lint": "eslint bin lib spec", + "lint": "npx eslint . --ext .ts,.tsx", "clean-tests": "node spec/clean-tests.js", "debug-tests": "npm run clean-tests && npm run lint && npm run jasmine-inspect" }, @@ -26,22 +29,25 @@ }, "homepage": "https://github.com/Microsoft/PowerBI-visuals-tools#readme", "dependencies": { + "@typescript-eslint/parser": "^5.62.0", "assert": "^2.0.0", "async": "^3.2.4", "browserify-zlib": "^0.2.0", "buffer": "^6.0.3", - "chalk": "3.0.0", - "commander": "4.1.1", - "compare-versions": "^3.6.0", + "chalk": "^5.3.0", + "commander": "^11.0.0", + "compare-versions": "^6.0.0", "console-browserify": "^1.2.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.12.0", "css-loader": "^6.8.1", "domain-browser": "^4.22.0", "events": "^3.3.0", + "terser-webpack-plugin": "^5.3.9", "extra-watch-webpack-plugin": "^1.0.3", "fs-extra": "^11.1.1", "https-browserify": "^1.0.0", + "inline-source-map": "^0.6.2", "json-loader": "0.5.7", "jszip": "^3.10.1", "less": "^4.1.3", @@ -66,9 +72,8 @@ "typescript": "^4.9.5", "url": "^0.11.1", "util": "^0.12.5", - "uuid": "9.0.0", "vm-browserify": "^1.1.2", - "webpack": "^5.88.1", + "webpack": "^5.88.2", "webpack-bundle-analyzer": "4.9.0", "webpack-dev-server": "^4.15.1" }, @@ -77,12 +82,15 @@ "jasmine": "5.0.2", "jasmine-spec-reporter": "7.0.0", "semver": "7.5.4", - "tree-kill": "1.2.2" + "tree-kill": "1.2.2", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "webpack-cli": "^5.1.4" }, "optionalDependencies": { "fsevents": "*" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } } diff --git a/spec/clean-tests.js b/spec/clean-tests.js index 73ad8b0a..7a411d51 100644 --- a/spec/clean-tests.js +++ b/spec/clean-tests.js @@ -26,6 +26,6 @@ "use strict"; -let FileSystem = require('./helpers/FileSystem.js'); +import FileSystem from './helpers/FileSystem.js'; FileSystem.deleteTempDirectory(); diff --git a/spec/e2e/pbivizCertSpec.js b/spec/e2e/pbivizCertSpec.js index 034b76c4..43e56904 100644 --- a/spec/e2e/pbivizCertSpec.js +++ b/spec/e2e/pbivizCertSpec.js @@ -26,28 +26,29 @@ "use strict"; -let fs = require('fs-extra'); -let path = require('path'); -console.log(__dirname); -let config = require('./../../config.json'); +import fs from 'fs-extra'; +import path from 'path'; +import { getRootPath, readJsonFromRoot } from '../../lib/utils.js'; +import { createCertFile } from '../../lib/CertificateTools.js'; -let CertificateTools = require('./../../lib/CertificateTools'); +const config = readJsonFromRoot('config.json'); describe("E2E - pbiviz --install-cert", () => { beforeEach((done) => { - CertificateTools.createCertFile(config, false).then(done); + createCertFile(config, false).then(done); }); describe("pbiviz", () => { it("pbiviz --install-cert command should generate certificate", (done) => { - let certPath = path.join(__dirname, "../../", config.server.certificate); - let keyPath = path.join(__dirname, "../../", config.server.privateKey); - let pfxPath = path.join(__dirname, "../../", config.server.pfx); - let certExists = fs.existsSync(certPath); - let keyExists = fs.existsSync(keyPath); - let pfxExists = fs.existsSync(pfxPath); + const rootPath = getRootPath(); + const certPath = path.join(rootPath, config.server.certificate); + const keyPath = path.join(rootPath, config.server.privateKey); + const pfxPath = path.join(rootPath, config.server.pfx); + const certExists = fs.existsSync(certPath); + const keyExists = fs.existsSync(keyPath); + const pfxExists = fs.existsSync(pfxPath); - let result = (certExists && keyExists) || pfxExists; + const result = (certExists && keyExists) || pfxExists; expect(result).toBeTruthy(); done(); diff --git a/spec/e2e/pbivizInfoSpec.js b/spec/e2e/pbivizInfoSpec.js index ee671dbd..6bbf833b 100644 --- a/spec/e2e/pbivizInfoSpec.js +++ b/spec/e2e/pbivizInfoSpec.js @@ -26,21 +26,21 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); - -const FileSystem = require('../helpers/FileSystem.js'); +import fs from 'fs-extra'; +import path from 'path'; +import FileSystem from '../helpers/FileSystem.js'; +import { writeMetadata } from "./testUtils.js"; const tempPath = FileSystem.getTempPath(); const startPath = process.cwd(); -const writeMetadata = require("./utils").writeMetadata; describe("E2E - pbiviz info", () => { - const visualName = 'myuniquevisualnamegoeshere'; + const visualName = 'myvisualname'; const visualPath = path.join(tempPath, visualName); beforeEach(() => { + process.chdir(startPath); FileSystem.resetTempDirectory(); process.chdir(tempPath); FileSystem.runPbiviz('new', visualName); @@ -49,10 +49,6 @@ describe("E2E - pbiviz info", () => { writeMetadata(visualPath); }); - afterEach(() => { - process.chdir(startPath); - }); - afterAll(() => { process.chdir(startPath); FileSystem.deleteTempDirectory(); @@ -71,6 +67,7 @@ describe("E2E - pbiviz info", () => { expect(error).toBeDefined(); expect(error.status).toBe(1); expect(error.message).toContain("Error: pbiviz.json not found. You must be in the root of a visual project to run this command"); + }); it("Should output visual info", () => { diff --git a/spec/e2e/pbivizNewSpec.js b/spec/e2e/pbivizNewSpec.js index 4099bcae..f0ccbfb2 100644 --- a/spec/e2e/pbivizNewSpec.js +++ b/spec/e2e/pbivizNewSpec.js @@ -26,20 +26,19 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); -const fsPromises = require("fs").promises; -const utils = require('./utils'); - -const FileSystem = require('../helpers/FileSystem.js'); -const writeMetadata = require("./utils").writeMetadata; -const download = require("../../lib/utils").download; -const createFolder = require("../../lib/utils").createFolder; -const config = require("../../config.json"); - +import fs from 'fs-extra'; +import path from 'path'; +import { promises as fsPromises } from "fs"; +import FileSystem from '../helpers/FileSystem.js'; +import { writeMetadata, readdirSyncRecursive } from "./testUtils.js"; +import { download, createFolder, readJsonFromRoot } from "../../lib/utils.js"; + +const config = readJsonFromRoot('config.json'); const tempPath = FileSystem.getTempPath(); const templatePath = FileSystem.getTemplatePath(); const startPath = process.cwd(); +const visualName = 'visualName'; +const visualPath = path.join(tempPath, visualName); describe("E2E - pbiviz new", () => { @@ -53,37 +52,34 @@ describe("E2E - pbiviz new", () => { }); afterAll(() => { - process.chdir(startPath); FileSystem.deleteTempDirectory(); }); it("Should generate new visual with default template", () => { - let visualName = 'visualname'; - let template = 'default'; - let visualPath = path.join(tempPath, visualName); + const template = 'default'; FileSystem.runPbiviz('new', visualName, ' -t default'); writeMetadata(visualPath); //check base dir - let stat = fs.statSync(visualPath); + const stat = fs.statSync(visualPath); expect(stat.isDirectory()).toBe(true); //check contents - let expectedFiles = utils.readdirSyncRecursive(path.join(templatePath, 'visuals', template)); - expectedFiles.concat(utils.readdirSyncRecursive(path.join(templatePath, 'visuals', '_global'))); + const expectedFiles = readdirSyncRecursive(path.join(templatePath, 'visuals', template)); + expectedFiles.concat(readdirSyncRecursive(path.join(templatePath, 'visuals', '_global'))); expectedFiles.push('/pbiviz.json'); - let visualFiles = utils.readdirSyncRecursive(visualPath); - let fileDiff = [expectedFiles, visualFiles].reduce((a, b) => a.filter(c => !b.includes(c))); + const visualFiles = readdirSyncRecursive(visualPath); + const fileDiff = [expectedFiles, visualFiles].reduce((a, b) => a.filter(c => !b.includes(c))); expect(fileDiff.length).toBe(0); // check exists node_modules directory - let nodeModulesDirStat = fs.statSync(path.join(visualPath, "node_modules")); + const nodeModulesDirStat = fs.statSync(path.join(visualPath, "node_modules")); expect(nodeModulesDirStat.isDirectory()).toBe(true); //check pbiviz.json config file - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; expect(visualConfig.name).toBe(visualName); expect(visualConfig.displayName).toBe(visualName); expect(visualConfig.guid).toBeDefined(); @@ -92,7 +88,7 @@ describe("E2E - pbiviz new", () => { }); describe(`Should download 'Circlecard' visual archive from the repo`, () => { - let template = 'circlecard'; + const template = 'circlecard'; it(`Verifiy size`, async () => { const folder = createFolder(template); @@ -108,6 +104,33 @@ describe("E2E - pbiviz new", () => { describe('Should generate new visual using specified template', () => { + function testGeneratedVisualByTemplateName(template) { + FileSystem.runPbiviz('new', visualName, `--template ${template}`); + if (template !== 'circlecard') { + FileSystem.runCMDCommand('npm i', visualPath, startPath); + } + + //check base dir exists + const stat = fs.statSync(visualPath); + expect(stat.isDirectory()).toBe(true); + + //read pbiviz json generated in visual + const pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); + + //check pbiviz.json config file + const visualConfig = pbivizJson.visual; + if (template === 'circlecard') { + expect(visualConfig.name).toBe('reactCircleCard'); + expect(visualConfig.displayName).toBe('ReactCircleCard'); + } else { + expect(visualConfig.name).toBe(visualName); + expect(visualConfig.displayName).toBe(visualName); + } + expect(visualConfig.guid).toBeDefined(); + expect(visualConfig.guid).toMatch(/^[a-zA-Z0-9]+$/g); + expect(visualConfig.guid.substr(0, visualName.length)).toBe(visualName); + } + it('table', () => { const template = 'table'; @@ -137,55 +160,23 @@ describe("E2E - pbiviz new", () => { testGeneratedVisualByTemplateName(template); }); - - function testGeneratedVisualByTemplateName(template) { - let visualName = 'visualname', - visualPath = path.join(tempPath, visualName); - - FileSystem.runPbiviz('new', visualName, `--template ${template}`); - if (template !== 'circlecard') { - FileSystem.runCMDCommand('npm i', visualPath, startPath); - } - - //check base dir exists - let stat = fs.statSync(visualPath); - expect(stat.isDirectory()).toBe(true); - - //read pbiviz json generated in visual - let pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); - - //check pbiviz.json config file - let visualConfig = pbivizJson.visual; - if (template === 'circlecard') { - expect(visualConfig.name).toBe('reactCircleCard'); - expect(visualConfig.displayName).toBe('ReactCircleCard'); - } else { - expect(visualConfig.name).toBe(visualName); - expect(visualConfig.displayName).toBe(visualName); - } - expect(visualConfig.guid).toBeDefined(); - expect(visualConfig.guid).toMatch(/^[a-zA-Z0-9]+$/g); - expect(visualConfig.guid.substr(0, visualName.length)).toBe(visualName); - } }); it("Should convert multi-word visual name to camelCase", () => { - let visualDisplayName = 'My Visual Name here'; - let visualName = 'myVisualNameHere'; - FileSystem.runPbiviz('new', visualDisplayName); + const visualDisplayName = 'Visual Name'; + FileSystem.runPbiviz('new', `"${visualDisplayName}"`); - let visualPath = path.join(tempPath, visualName); - let stat = fs.statSync(visualPath); + const stat = fs.statSync(visualPath); expect(stat.isDirectory()).toBe(true); - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; expect(visualConfig.name).toBe(visualName); expect(visualConfig.displayName).toBe(visualDisplayName); }); it("Should throw error if the visual name invalid", () => { - let invalidVisualName = '12test'; let error; + let invalidVisualName = '12test'; try { FileSystem.runPbiviz('new', invalidVisualName); } @@ -215,9 +206,7 @@ describe("E2E - pbiviz new", () => { }); it("Should throw error if the visual already exists", () => { - let visualName = 'visualname'; let error; - FileSystem.runPbiviz('new', visualName); try { @@ -228,12 +217,11 @@ describe("E2E - pbiviz new", () => { expect(error).toBeDefined(); expect(error.status).toBe(1); + }); it("Should overwrite existing visual with force flag", () => { - let visualName = 'visualname'; - let visualPath = path.join(tempPath, visualName); - let visualTestFilePath = path.join(visualPath, 'testFile.txt'); + const visualTestFilePath = path.join(visualPath, 'testFile.txt'); let visualNewError, testFileError1, testFileError2; FileSystem.runPbiviz('new', visualName); diff --git a/spec/e2e/pbivizPackageSpec.js b/spec/e2e/pbivizPackageSpec.js index 7f142cf9..4db61ac9 100644 --- a/spec/e2e/pbivizPackageSpec.js +++ b/spec/e2e/pbivizPackageSpec.js @@ -1,3 +1,4 @@ +/* eslint-disable no-useless-escape */ /* * Power BI Visual CLI * @@ -26,25 +27,25 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); -const async = require('async'); -const JSZip = require('jszip'); -const lodashIsEqual = require('lodash.isequal'); - -const FileSystem = require('../helpers/FileSystem.js'); -const writeMetadata = require("./utils").writeMetadata; +import fs from 'fs-extra'; +import path from 'path'; +import async from 'async'; +import JSZip from 'jszip'; +import lodashIsEqual from 'lodash.isequal'; +import FileSystem from '../helpers/FileSystem.js'; +import { writeMetadata } from "./testUtils.js"; const tempPath = FileSystem.getTempPath(); const startPath = process.cwd(); describe("E2E - pbiviz package", () => { - let visualName = 'visualname'; - let visualPath = path.join(tempPath, visualName); + const visualName = 'visualname'; + const visualPath = path.join(tempPath, visualName); let visualPbiviz = {}; beforeEach(() => { + process.chdir(startPath); FileSystem.resetTempDirectory(); process.chdir(tempPath); FileSystem.runPbiviz('new', visualName); @@ -56,10 +57,6 @@ describe("E2E - pbiviz package", () => { visualPbiviz = JSON.parse(fs.readFileSync(path.join(visualPath, 'pbiviz.json'), { encoding: "utf8" })); }); - afterEach(() => { - process.chdir(startPath); - }); - afterAll(() => { process.chdir(startPath); FileSystem.deleteTempDirectory(); @@ -94,61 +91,61 @@ describe("E2E - pbiviz package", () => { }); it("Should create a pbiviz file and no resources folder with no flags", () => { + let error; FileSystem.runPbiviz('package'); - let pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); - let resourcesPath = path.join(visualPath, 'dist', 'resources'); + const pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); + const resourcesPath = path.join(visualPath, 'dist', 'resources'); - let resourcesError; try { fs.accessSync(resourcesPath); } catch (e) { - resourcesError = e; + error = e } + expect(error).toBeDefined(); + expect(error.code).toBe('ENOENT'); - expect(resourcesError).toBeDefined(); - expect(resourcesError.code).toBe('ENOENT'); expect(fs.statSync(pbivizPath).isFile()).toBe(true); }); it("Should create a pbiviz file and resource folder with --resources flag", () => { - FileSystem.runPbiviz('package', false, '--resources'); + FileSystem.runPbiviz('package', undefined, '--resources'); - let pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); - let resourcesPath = path.join(visualPath, 'dist', 'resources'); + const pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); + const resourcesPath = path.join(visualPath, 'dist', 'resources'); expect(fs.statSync(pbivizPath).isFile()).toBe(true); expect(fs.statSync(resourcesPath).isDirectory()).toBe(true); }); it("Should not create pbiviz file with --no-pbiviz flag", () => { - FileSystem.runPbiviz('package', false, '--no-pbiviz --resources'); + let error + FileSystem.runPbiviz('package', undefined, '--no-pbiviz --resources'); - let pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); - let resourcesPath = path.join(visualPath, 'dist', 'resources'); + const pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); + const resourcesPath = path.join(visualPath, 'dist', 'resources'); - let pbivizError; try { fs.accessSync(pbivizPath); } catch (e) { - pbivizError = e; + error = e } + expect(error).toBeDefined(); + expect(error.code).toBe('ENOENT'); - expect(pbivizError).toBeDefined(); - expect(pbivizError.code).toBe('ENOENT'); expect(fs.statSync(resourcesPath).isDirectory()).toBe(true); }); it("Should correctly generate pbiviz file", (done) => { FileSystem.runPbiviz('package'); - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; - let visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); - let pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); - let pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); + const pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + visualPbiviz.visual.version + '.pbiviz'); + const pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; - let zipContents = fs.readFileSync(pbivizPath); - let jszip = new JSZip(); + const zipContents = fs.readFileSync(pbivizPath); + const jszip = new JSZip(); jszip.loadAsync(zipContents) .then((zip) => { async.parallel([ @@ -156,7 +153,7 @@ describe("E2E - pbiviz package", () => { (next) => { zip.file('package.json').async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.resources.length).toBe(1); expect(data.resources[0].file).toBe(pbivizResourcePath); expect(data.visual).toEqual(visualConfig); @@ -168,7 +165,7 @@ describe("E2E - pbiviz package", () => { (next) => { zip.file(pbivizResourcePath).async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.visual).toEqual(visualConfig); expect(data.capabilities).toEqual(visualCapabilities); expect(data.content.js).toBeDefined(); @@ -189,19 +186,19 @@ describe("E2E - pbiviz package", () => { }); it("Should correctly generate resources folder", () => { - FileSystem.runPbiviz('package', false, '--no-pbiviz --resources'); + FileSystem.runPbiviz('package', undefined, '--no-pbiviz --resources'); - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; - let visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); - let resourcesPath = path.join(visualPath, 'dist', 'resources'); - let pbivizPath = path.join(resourcesPath, visualPbiviz.visual.guid + '.pbiviz.json'); + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); + const resourcesPath = path.join(visualPath, 'dist', 'resources'); + const pbivizPath = path.join(resourcesPath, visualPbiviz.visual.guid + '.pbiviz.json'); expect(fs.statSync(resourcesPath).isDirectory()).toBe(true); expect(fs.statSync(path.join(resourcesPath, 'visual.prod.js')).isFile()).toBe(true); expect(fs.statSync(path.join(resourcesPath, 'visual.prod.css')).isFile()).toBe(true); expect(fs.statSync(pbivizPath).isFile()).toBe(true); - let pbiviz = fs.readJsonSync(pbivizPath); + const pbiviz = fs.readJsonSync(pbivizPath); expect(pbiviz.visual).toEqual(visualConfig); expect(pbiviz.capabilities).toEqual(visualCapabilities); expect(pbiviz.content.js).toBeDefined(); @@ -212,41 +209,41 @@ describe("E2E - pbiviz package", () => { // tets can't check the minification, because in input the plugin gets minified version, // plugin can't create two version js file for compare xit("Should minify assets by default", () => { - FileSystem.runPbiviz('package', false, '--resources --no-pbiviz'); + FileSystem.runPbiviz('package', undefined, '--resources --no-pbiviz'); - let js = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.js')); + const js = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.js')); - let prodJs = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.prod.js')); + const prodJs = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.prod.js')); expect(js.size).toBeGreaterThan(prodJs.size); }); it("Should skip minification with --no-minify flag", () => { - FileSystem.runPbiviz('package', false, '--resources --no-pbiviz --no-minify'); + FileSystem.runPbiviz('package', undefined, '--resources --no-pbiviz --no-minify'); - let js = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.js')); + const js = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.js')); - let prodJs = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.prod.js')); + const prodJs = fs.statSync(path.join(visualPath, 'dist', 'resources', 'visual.prod.js')); expect(js.size).toBe(prodJs.size); }); it("Should set all versions in metadata equal", (done) => { - let visualVersion = "1.2.3"; + const visualVersion = "1.2.3.4"; - let pbivizJsonPath = path.join(visualPath, 'pbiviz.json'); - let pbiviz = fs.readJsonSync(pbivizJsonPath); + const pbivizJsonPath = path.join(visualPath, 'pbiviz.json'); + const pbiviz = fs.readJsonSync(pbivizJsonPath); pbiviz.visual.version = visualVersion; fs.writeFileSync(pbivizJsonPath, JSON.stringify(pbiviz)); FileSystem.runCMDCommand('npm i', visualPath); FileSystem.runPbiviz('package'); - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; - let pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + pbiviz.visual.version + '.pbiviz'); - let pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const pbivizPath = path.join(visualPath, 'dist', visualPbiviz.visual.guid + "." + pbiviz.visual.version + '.pbiviz'); + const pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; - let zipContents = fs.readFileSync(pbivizPath); - let jszip = new JSZip(); + const zipContents = fs.readFileSync(pbivizPath); + const jszip = new JSZip(); jszip.loadAsync(zipContents) .then((zip) => { async.parallel([ @@ -254,7 +251,7 @@ describe("E2E - pbiviz package", () => { next => { zip.file('package.json').async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.visual.version).toEqual(visualVersion); expect(data.version).toEqual(visualVersion); next(); @@ -265,7 +262,7 @@ describe("E2E - pbiviz package", () => { next => { zip.file(pbivizResourcePath).async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.visual.version).toEqual(visualVersion); next(); }) @@ -308,7 +305,7 @@ describe("E2E - pbiviz package", () => { return writeJsonPromise('pbiviz.json', pbivizJson); }) .then(() => - FileSystem.runPbiviz('package', false, '--no-pbiviz --no-minify --resources') + FileSystem.runPbiviz('package', undefined, '--no-pbiviz --no-minify --resources') ) .then(() => readJsonPromise(path.join(visualPath, 'dist', 'resources', visualPbiviz.visual.guid + '.pbiviz.json')) @@ -359,7 +356,7 @@ describe("E2E - pbiviz package", () => { .then(() => writeJsonPromise('stringResources/ru-RU/resources.resjson', ResJsonRuLocalization)) ])) .then(() => - FileSystem.runPbiviz('package', false, '--no-pbiviz --no-minify --resources') + FileSystem.runPbiviz('package', undefined, '--no-pbiviz --no-minify --resources') ) .then(() => readJsonPromise(path.join(visualPath, 'dist', 'resources', visualPbiviz.visual.guid + '.pbiviz.json')) @@ -430,7 +427,7 @@ describe("E2E - pbiviz package", () => { return writeJsonPromise('pbiviz.json', pbivizJson); }) .then(() => - FileSystem.runPbiviz('package', false, '--no-pbiviz --no-minify --resources') + FileSystem.runPbiviz('package', undefined, '--no-pbiviz --no-minify --resources') ) .then(() => readJsonPromise(path.join(visualPath, 'dist', 'resources', visualPbiviz.visual.guid + '.pbiviz.json'))) .then((pbivizJson) => { @@ -457,12 +454,11 @@ describe("E2E - pbiviz package", () => { FileSystem.runPbiviz('package', '--no-stats'); const statisticFilePath = path.join(visualPath, 'webpack.statistics.prod.html'); try { - fs.statSync(statisticFilePath).isFile(); + expect(fs.statSync(statisticFilePath).isFile()).toBe(false); } catch (error) { expect(error).not.toBeNull(); } }); - }); function mkDirPromise(path) { @@ -502,7 +498,7 @@ function testMissingScript(fname) { try { FileSystem.runPbiviz('package'); } catch (e) { - error = e; + error = e } expect(error).toBeDefined(); expect(error.status).toBe(1); @@ -511,7 +507,7 @@ function testMissingScript(fname) { function testErrorInDependencies() { let error; - let invalidDependencies = [ + const invalidDependencies = [ { invalidPropertyName: "ddd" } @@ -536,10 +532,10 @@ function testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, re FileSystem.runPbiviz('package'); - let visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; - let visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); - let pbivizPath = path.join(visualPath, 'dist', visualName + '.pbiviz'); - let pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; + const visualConfig = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')).visual; + const visualCapabilities = fs.readJsonSync(path.join(visualPath, 'capabilities.json')); + const pbivizPath = path.join(visualPath, 'dist', visualName + '.pbiviz'); + const pbivizResourcePath = `resources/${visualConfig.guid}.pbiviz.json`; visualCapabilities.dataViewMappings[0].scriptResult.script.scriptSourceDefault = scriptSourceDefault; @@ -548,8 +544,8 @@ function testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, re dependencies = fs.readJsonSync(path.join(visualPath, 'dependencies.json')); } - let zipContents = fs.readFileSync(pbivizPath); - let jszip = new JSZip(); + const zipContents = fs.readFileSync(pbivizPath); + const jszip = new JSZip(); jszip.loadAsync(zipContents) .then((zip) => { async.parallel([ @@ -557,7 +553,7 @@ function testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, re (next) => { zip.file('package.json').async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.resources.length).toBe(1); expect(data.resources[0].file).toBe(pbivizResourcePath); expect(data.visual).toEqual(visualConfig); @@ -569,7 +565,7 @@ function testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, re (next) => { zip.file(pbivizResourcePath).async('string') .then((content) => { - let data = JSON.parse(content); + const data = JSON.parse(content); expect(data.visual).toEqual(visualConfig); expect(data.capabilities).toEqual(visualCapabilities); expect(data.content.js).toBeDefined(); @@ -593,8 +589,8 @@ function testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, re // new tools doesn't support R visuals build. coming soon xdescribe("E2E - pbiviz package for R Visual template", () => { - let visualName = 'visualname'; - let visualPath = path.join(tempPath, visualName); + const visualName = 'visualname'; + const visualPath = path.join(tempPath, visualName); beforeEach(() => { FileSystem.resetTempDirectory(); @@ -622,14 +618,14 @@ xdescribe("E2E - pbiviz package for R Visual template", () => { }); it("Should correctly generate pbiviz file for R Visual template - no dependencies file", (done) => { - let scriptSourceDefault = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); - let removeDependencies = true; + const scriptSourceDefault = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); + const removeDependencies = true; testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, removeDependencies); }); it("Should correctly generate pbiviz file for R Visual template", (done) => { - let scriptSourceDefault = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); - let removeDependencies = false; + const scriptSourceDefault = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); + const removeDependencies = false; testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, removeDependencies); }); }); @@ -637,13 +633,13 @@ xdescribe("E2E - pbiviz package for R Visual template", () => { // new tools doesn't support R visuals build. coming soon xdescribe("E2E - pbiviz package for R HTML template", () => { - let visualName = 'visualname'; - let visualPath = path.join(tempPath, visualName); + const visualName = 'visualname'; + const visualPath = path.join(tempPath, visualName); function getScriptSourceDefault() { - let FlattenScriptContent = fs.readFileSync(path.join(visualPath, 'r_files/flatten_HTML.r')).toString(); - let scriptContent = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); - let pattern = "source('./r_files/flatten_HTML.r')"; + const FlattenScriptContent = fs.readFileSync(path.join(visualPath, 'r_files/flatten_HTML.r')).toString(); + const scriptContent = fs.readFileSync(path.join(visualPath, 'script.r')).toString(); + const pattern = "source('./r_files/flatten_HTML.r')"; return scriptContent.replace(pattern, FlattenScriptContent); } @@ -677,14 +673,14 @@ xdescribe("E2E - pbiviz package for R HTML template", () => { }); it("Should correctly generate pbiviz file for R HTML template - no dependencies file", (done) => { - let scriptSourceDefault = getScriptSourceDefault(); - let removeDependencies = true; + const scriptSourceDefault = getScriptSourceDefault(); + const removeDependencies = true; testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, removeDependencies); }); it("Should correctly generate pbiviz file for R HTML template", (done) => { - let scriptSourceDefault = getScriptSourceDefault(); - let removeDependencies = false; + const scriptSourceDefault = getScriptSourceDefault(); + const removeDependencies = false; testPbivizPackage(done, visualPath, visualName, scriptSourceDefault, removeDependencies); }); }); diff --git a/spec/e2e/pbivizStartSpec.js b/spec/e2e/pbivizStartSpec.js index a704dbbf..3d32441d 100644 --- a/spec/e2e/pbivizStartSpec.js +++ b/spec/e2e/pbivizStartSpec.js @@ -26,13 +26,12 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); -const async = require('async'); -const FileSystem = require('../helpers/FileSystem.js'); -const writeMetadata = require("./utils").writeMetadata; -const download = require("../../lib/utils").download; -const createFolder = require("../../lib/utils").createFolder; +import fs from 'fs-extra'; +import path from 'path'; +import async from 'async'; +import FileSystem from '../helpers/FileSystem.js'; +import { writeMetadata } from "./testUtils.js"; +import { download, createFolder } from "../../lib/utils.js"; const tempPath = FileSystem.getTempPath(); const startPath = process.cwd(); diff --git a/spec/e2e/pbivizWebpackVerSpec.js b/spec/e2e/pbivizWebpackVerSpec.js index bd9ddf5c..e5d514f8 100644 --- a/spec/e2e/pbivizWebpackVerSpec.js +++ b/spec/e2e/pbivizWebpackVerSpec.js @@ -26,12 +26,11 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); - -const FileSystem = require('../helpers/FileSystem.js'); -const writeMetadata = require("./utils").writeMetadata; -const semver = require('semver'); +import fs from 'fs-extra'; +import path from 'path'; +import semver from 'semver'; +import FileSystem from '../helpers/FileSystem.js'; +import { writeMetadata } from "./testUtils.js"; const tempPath = FileSystem.getTempPath(); const startPath = process.cwd(); @@ -57,11 +56,10 @@ describe("E2E - webpack tools", () => { FileSystem.deleteTempDirectory(); }); - let removeApi = () => { - let packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); - packageJson.dependencies = { - "powerbi-visuals-utils-dataviewutils": "2.0.1" - }; + const removeApi = () => { + const packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); + delete packageJson.dependencies["powerbi-visuals-api"]; + fs.writeJsonSync(path.join(visualPath, 'package.json'), packageJson); fs.removeSync(path.join(visualPath, "node_modules", "powerbi-visuals-api")); @@ -70,28 +68,28 @@ describe("E2E - webpack tools", () => { it("Should not add empty dependencies option into visual config", () => { FileSystem.runPbiviz('package'); - let packageJson = fs.readJsonSync(path.join(visualPath, '.tmp/drop/pbiviz.json')); + const packageJson = fs.readJsonSync(path.join(visualPath, '.tmp/drop/pbiviz.json')); expect(packageJson.dependencies).not.toBeDefined(); }); it("Should install the latest powerbi-visual-api if apiVersion is undefined", () => { - let pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); + const pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); pbivizJson.apiVersion = null; fs.writeJsonSync(path.join(visualPath, 'pbiviz.json'), pbivizJson); removeApi(); FileSystem.runPbiviz('package'); - let packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); + const packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); expect(packageJson.dependencies["powerbi-visuals-api"]).toBeDefined(); }); it("Should install powerbi-visual-api with version from pbiviz.json on 'pbiviz start/package'", () => { - let pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); + const pbivizJson = fs.readJsonSync(path.join(visualPath, 'pbiviz.json')); removeApi(); FileSystem.runPbiviz('package'); - let packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); + const packageJson = fs.readJsonSync(path.join(visualPath, 'package.json')); expect(packageJson.dependencies["powerbi-visuals-api"]).toBeDefined(); expect(semver.major(pbivizJson.apiVersion)) .toBe(semver.major(packageJson.dependencies["powerbi-visuals-api"].replace(/\^|\~/, ""))); // eslint-disable-line no-useless-escape diff --git a/spec/e2e/utils.js b/spec/e2e/testUtils.js similarity index 80% rename from spec/e2e/utils.js rename to spec/e2e/testUtils.js index b6a11c83..8141974c 100644 --- a/spec/e2e/utils.js +++ b/spec/e2e/testUtils.js @@ -26,16 +26,16 @@ "use strict"; -const path = require("path"); -const fs = require('fs-extra'); +import path from "path"; +import fs from 'fs-extra'; -let readdirSyncRecursive = (baseDir) => { - let read = (dir) => { +export const readdirSyncRecursive = (baseDir) => { + const read = (dir) => { let results = []; - let list = fs.readdirSync(dir); + const list = fs.readdirSync(dir); list.forEach((file) => { file = dir + '/' + file; - let stat = fs.statSync(file); + const stat = fs.statSync(file); if (stat && stat.isDirectory()) { /* Recurse into a subdirectory */ results = results.concat(read(file)); @@ -49,15 +49,12 @@ let readdirSyncRecursive = (baseDir) => { return read(baseDir); }; -let writeMetadata = (visualPath) => { - let pbivizJSONFile = path.join(visualPath, '/pbiviz.json'); - let pbiviz = fs.readJSONSync(pbivizJSONFile); +export const writeMetadata = (visualPath) => { + const pbivizJSONFile = path.join(visualPath, '/pbiviz.json'); + const pbiviz = fs.readJSONSync(pbivizJSONFile); pbiviz.visual.description = "description"; pbiviz.visual.supportUrl = "supportUrl"; pbiviz.author.name = "Microsoft"; pbiviz.author.email = "pbicvsupport"; fs.writeJSONSync(pbivizJSONFile, pbiviz); }; - -module.exports.readdirSyncRecursive = readdirSyncRecursive; -module.exports.writeMetadata = writeMetadata; diff --git a/spec/helpers/FileSystem.js b/spec/helpers/FileSystem.js index c1aaa14d..12e7d099 100644 --- a/spec/helpers/FileSystem.js +++ b/spec/helpers/FileSystem.js @@ -26,21 +26,23 @@ "use strict"; -let fs = require('fs-extra'); -let path = require('path'); -let childProcess = require('child_process'); -let treeKill = require('tree-kill'); - -const TEMP_DIR = path.join(__dirname, '..', '.tmp'); -const BIN_PATH = path.join(__dirname, '..', '..', 'bin', 'pbiviz.js'); -const TEMPLATE_PATH = path.join(__dirname, '..', '..', 'templates'); - -class FileSystem { +import fs from 'fs-extra'; +import path from 'path'; +import childProcess from 'child_process'; +import treeKill from 'tree-kill'; +import { getRootPath } from '../../lib/utils.js'; + +const rootPath = getRootPath(); +const TEMP_DIR = path.join(rootPath, 'spec/.tmp'); +const BIN_PATH = path.join(rootPath, 'bin/pbiviz.js'); +const TEMPLATE_PATH = path.join(rootPath, 'templates'); + +export default class FileSystem { static expectFileToExist(fileName) { return new Promise((resolve, reject) => { - fs.exists(fileName, (exist) => { + fs.existsSync(fileName, (exist) => { if (exist) { - resolve(); + resolve(true); } else { reject(new Error(`File ${fileName} was expected to exist but not found...`)); } @@ -62,12 +64,12 @@ class FileSystem { static expectFileToMatch(fileName, regEx) { return FileSystem.readFile(fileName) - .then(content => { + .then((content) => { if (typeof regEx == 'string') { - if (content.indexOf(regEx) == -1) { + if ((content).indexOf(regEx) == -1) { throw new Error(`File "${fileName}" did not contain "${regEx}"...`); } - } else if (!content.match(regEx)) { + } else if (!(content).match(regEx)) { throw new Error(`File "${fileName}" did not contain "${regEx}"...`); } }); @@ -168,6 +170,4 @@ class FileSystem { }); } -} - -module.exports = FileSystem; +} \ No newline at end of file diff --git a/spec/jasmine-runner.js b/spec/jasmine-runner.js index 13802d09..7484da97 100644 --- a/spec/jasmine-runner.js +++ b/spec/jasmine-runner.js @@ -26,11 +26,11 @@ "use strict"; -let Jasmine = require('jasmine'); -let SpecReporter = require('jasmine-spec-reporter').SpecReporter; +import jasmine from 'jasmine'; +import { SpecReporter } from 'jasmine-spec-reporter'; -let jrunner = new Jasmine(); -jrunner.configureDefaultReporter({ print: () => {} }); // eslint-disable-line no-empty-function -jasmine.getEnv().addReporter(new SpecReporter()); +let jrunner = new jasmine(); +jrunner.configureDefaultReporter({ print: () => {} }); +jrunner.addReporter(new SpecReporter()); jrunner.loadConfigFile(); jrunner.execute(); diff --git a/lib/CertificateTools.js b/src/CertificateTools.ts similarity index 71% rename from lib/CertificateTools.js rename to src/CertificateTools.ts index 6d7be421..01575217 100644 --- a/lib/CertificateTools.js +++ b/src/CertificateTools.ts @@ -26,22 +26,30 @@ "use strict"; -let confPath = '../config.json'; -let nodeExec = require('child_process').exec; -let path = require('path'); -let os = require('os'); -let ConsoleWriter = require('../lib/ConsoleWriter'); -let fs = require('fs-extra'); -let config = require(confPath); -const certSafePeriod = 1000 * 60 * 60 * 24; - -function exec(command, callback) { - if (callback) { - return nodeExec(command, callback); - } +import { exec as nodeExec } from 'child_process'; +import fs from 'fs-extra'; +import os from 'os'; +import path from 'path'; +import crypto from "crypto" +import { getRootPath, readJsonFromRoot } from './utils.js'; +import ConsoleWriter from './ConsoleWriter.js'; + +const certSafePeriod = 1000 * 60 * 60 * 24; // 24 hours +const rootPath = getRootPath(); +const confPath = '/config.json'; + +interface CertificateOptions { + passphrase?: string; + cert?: string; + key?: string; + pfx?: string; + certificate?: string; + privateKey?: string; +} +function exec(command, callback?): Promise { return new Promise((resolve, reject) => { - nodeExec(command, (err, stdout, stderr) => { + nodeExec(command, callback ? callback : (err, stdout: string, stderr) => { if (err) { reject(stderr); } @@ -51,7 +59,19 @@ function exec(command, callback) { } -async function createCertFile(config, open) { +export async function createCertificate() { + const config = readJsonFromRoot('config.json'); + const certPath = await getCertFile(config, true); + + if (!certPath) { + ConsoleWriter.error("Certificate not found. The new certificate will be generated"); + await createCertFile(config, true); + } else { + await openCertFile(config); + } +} + +export async function createCertFile(config, open) { ConsoleWriter.info(`Generating a new certificate...`); const subject = "localhost"; const keyLength = 2048; @@ -62,11 +82,11 @@ async function createCertFile(config, open) { open = false; } - let certPath = path.join(__dirname, '..', config.server.certificate); - let keyPath = path.join(__dirname, '..', config.server.privateKey); - let pfxPath = path.join(__dirname, '..', config.server.pfx); + const certPath = path.join(rootPath, config.server.certificate); + const keyPath = path.join(rootPath, config.server.privateKey); + const pfxPath = path.join(rootPath, config.server.pfx); - let openCmds = { + const openCmds = { linux: 'openssl', darwin: 'openssl', win32: 'powershell' @@ -114,10 +134,12 @@ async function createCertFile(config, open) { } break; case "win32": + // eslint-disable-next-line no-case-declarations let passphrase = ""; // for windows 7 and others // 6.1 - Windows 7 - let osVersion = os.release().split("."); + // eslint-disable-next-line no-case-declarations + const osVersion = os.release().split("."); if ((Number(osVersion[0]) === 6 && Number(osVersion[1]) === 1) || Number(osVersion[0]) < 6) { await removeCertFiles(certPath, keyPath, pfxPath); startCmd = "openssl"; @@ -138,13 +160,12 @@ async function createCertFile(config, open) { } break; } + passphrase = crypto.getRandomValues(new Uint32Array(1))[0].toString().substring(2); + config.server.passphrase = passphrase; + fs.writeFileSync(path.join(rootPath, confPath), JSON.stringify(config)); // for windows 8 / 8.1 / server 2012 R2 / if (Number(osVersion[0]) === 6 && (Number(osVersion[1]) === 2 || Number(osVersion[1]) === 3)) { // for 10 - passphrase = Math.random().toString().substring(2); - config.server.passphrase = passphrase; - fs.writeFileSync(path.join(__dirname, confPath), JSON.stringify(config)); - createCertCommand = `$cert = ('Cert:\\CurrentUser\\My\\' + (` + ` New-SelfSignedCertificate ` + ` -DnsName localhost ` + @@ -156,15 +177,8 @@ async function createCertFile(config, open) { ` -Password (ConvertTo-SecureString -String '${passphrase}' -Force -AsPlainText)`; await exec(`${startCmd} "${createCertCommand}"`); - if (await fs.exists(pfxPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${pfxPath}. Passphrase is '${passphrase}'`); - } } else { // for window 10 / server 2016 - passphrase = Math.random().toString().substring(2); - config.server.passphrase = passphrase; - fs.writeFileSync(path.join(__dirname, confPath), JSON.stringify(config)); - createCertCommand = `$cert = ('Cert:\\CurrentUser\\My\\' + (` + ` New-SelfSignedCertificate ` + ` -DnsName localhost ` + @@ -183,9 +197,9 @@ async function createCertFile(config, open) { ` -Password (ConvertTo-SecureString -String '${passphrase}' -Force -AsPlainText)`; await exec(`${startCmd} "${createCertCommand}"`); - if (await fs.exists(pfxPath)) { - ConsoleWriter.info(`Certificate generated. Location is ${pfxPath}. Passphrase is '${passphrase}'`); - } + } + if (await fs.exists(pfxPath)) { + ConsoleWriter.info(`Certificate generated. Location is ${pfxPath}. Passphrase is '${passphrase}'`); } break; default: @@ -193,28 +207,28 @@ async function createCertFile(config, open) { } } catch (e) { if (e && e.message && e.message.indexOf("'openssl' is not recognized as an internal or external command") > 0) { - ConsoleWriter.warn('Create certificate error:'); - ConsoleWriter.warn('OpenSSL is not installed or not available from command line'); + ConsoleWriter.warning('Create certificate error:'); + ConsoleWriter.warning('OpenSSL is not installed or not available from command line'); ConsoleWriter.info('Install OpenSSL from https://www.openssl.org or https://wiki.openssl.org/index.php/Binaries'); ConsoleWriter.info('and try again'); ConsoleWriter.info('Read more at'); ConsoleWriter.info('https://github.com/Microsoft/PowerBI-visuals/blob/master/tools/CreateCertificate.md#manual'); } else { - ConsoleWriter.error('Create certificate error:', e); + ConsoleWriter.error(['Create certificate error:', e]); } } } else { - ConsoleWriter.error('Unknown platform. Please place a custom-generated certificate in:', certPath); + ConsoleWriter.error(['Unknown platform. Please place a custom-generated certificate in:', certPath]); } } -async function getCertFile(config, silent) { +async function getCertFile(config, silent?) { if (typeof silent === "undefined") { silent = false; } - let cert = path.join(__dirname, '..', config.server.certificate); - let pfx = path.join(__dirname, '..', config.server.pfx); + const cert = path.join(rootPath, config.server.certificate); + const pfx = path.join(rootPath, config.server.pfx); if (await fs.exists(cert)) { return cert; @@ -235,30 +249,30 @@ async function getCertFile(config, silent) { } async function openCertFile(config) { - let certPath = await getCertFile(config); + const certPath = await getCertFile(config); if (!certPath) { return null; } - let openCmds = { + const openCmds = { linux: 'xdg-open', darwin: 'open', win32: 'powershell start' }; - let startCmd = openCmds[os.platform()]; + const startCmd = openCmds[os.platform()]; if (startCmd) { try { await exec(`${startCmd} "${certPath}"`); } catch (e) { - ConsoleWriter.info('Certificate path:', certPath); + ConsoleWriter.info(['Certificate path:', certPath]); } } else { - ConsoleWriter.info('Certificate path:', certPath); + ConsoleWriter.info(['Certificate path:', certPath]); } } -async function removeCertFiles(certPath, keyPath, pfxPath) { +export async function removeCertFiles(certPath, keyPath, pfxPath?) { try { await fs.unlink(certPath); } catch (e) { @@ -282,36 +296,37 @@ async function removeCertFiles(certPath, keyPath, pfxPath) { } } -async function getGlobalPbivizCerts() { - let options = {}; +async function getGlobalPbivizCerts(config) { + const options: CertificateOptions = {}; try { - let location = (await exec('npm ls -g powerbi-visuals-tools')).split("\n")[0]; - let certPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.certificate); - let keyPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.privateKey); - let pfxPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.pfx); - let globalPbiviConfig = path.join(location, "node_modules", "powerbi-visuals-tools", "config.json"); - options.passphrase = fs.existsSync(globalPbiviConfig) && fs.readJSONSync(globalPbiviConfig).server.passphrase; + const location = (await exec('npm ls -g powerbi-visuals-tools')).split("\n")[0]; + const certPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.certificate); + const keyPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.privateKey); + const pfxPath = path.join(location, "node_modules", "powerbi-visuals-tools", config.server.pfx); + const globalPbivizConfig = path.join(location, "node_modules", "powerbi-visuals-tools", "config.json"); + options.passphrase = fs.existsSync(globalPbivizConfig) && fs.readJSONSync(globalPbivizConfig).server.passphrase; - let CertFileVerified = await veryfyCertFile(keyPath, certPath, pfxPath, options.passphrase); + const CertFileVerified = await verifyCertFile(keyPath, certPath, pfxPath, options.passphrase); options.cert = fs.existsSync(certPath) && certPath; options.key = fs.existsSync(keyPath) && keyPath; options.pfx = fs.existsSync(pfxPath) && CertFileVerified && pfxPath; } catch (err) { - ConsoleWriter.warn(`Global certificate error: ${err}`); + ConsoleWriter.warning(`Global certificate error: ${err}`); } if (!options.cert && !options.pfx) { - ConsoleWriter.warn(`Global instance of valid pbiviz certificate not found.`); + ConsoleWriter.warning(`Global instance of valid pbiviz certificate not found.`); } return options; } -async function resolveCertificate() { - let options = {}; - let keyPath = path.join(__dirname, '..', config.server.privateKey); - let certPath = path.join(__dirname, '..', config.server.certificate); - let pfxPath = path.join(__dirname, '..', config.server.pfx); +export async function resolveCertificate() { + const config = readJsonFromRoot('config.json'); + const options: CertificateOptions = {}; + const keyPath = path.join(rootPath, config.server.privateKey); + const certPath = path.join(rootPath, config.server.certificate); + const pfxPath = path.join(rootPath, config.server.pfx); if (config.server.passphrase) { options.passphrase = config.server.passphrase; @@ -326,12 +341,12 @@ async function resolveCertificate() { options.pfx = await fs.readFile(pfxPath); } - let CertFileVerified = await veryfyCertFile(keyPath, certPath, pfxPath, options.passphrase); + const CertFileVerified = await verifyCertFile(keyPath, certPath, pfxPath, options.passphrase); if ((!options.cert && !options.pfx) || !CertFileVerified) { - ConsoleWriter.warn("Local valid certificate not found."); + ConsoleWriter.warning("Local valid certificate not found."); ConsoleWriter.info("Checking global instance of pbiviz certificate..."); - let globalPbivizOptions = await getGlobalPbivizCerts(); + const globalPbivizOptions = await getGlobalPbivizCerts(config); if (!globalPbivizOptions.cert && !globalPbivizOptions.pfx) { await createCertFile(config, true); @@ -358,28 +373,28 @@ async function resolveCertificate() { // copy certs to local instance ConsoleWriter.info("Copy server certificate from global instance of pbiviz..."); if (globalPbivizOptions.cert) { - await fs.copyFile(globalPbivizOptions.cert, path.join(__dirname, '..', config.server.certificate)); + await fs.copyFile(globalPbivizOptions.cert, path.join(rootPath, config.server.certificate)); options.certificate = config.server.certificate; } if (globalPbivizOptions.key) { - await fs.copyFile(globalPbivizOptions.key, path.join(__dirname, '..', config.server.privateKey)); + await fs.copyFile(globalPbivizOptions.key, path.join(rootPath, config.server.privateKey)); options.privateKey = config.server.privateKey; } if (globalPbivizOptions.pfx) { - await fs.copyFile(globalPbivizOptions.pfx, path.join(__dirname, '..', config.server.pfx)); - // need to pass whole file instead patho to file - options.pfx = await fs.readFile(path.join(__dirname, '..', config.server.pfx)); + await fs.copyFile(globalPbivizOptions.pfx, path.join(rootPath, config.server.pfx)); + // need to pass whole file instead path to file + options.pfx = await fs.readFile(path.join(rootPath, config.server.pfx)); options.passphrase = globalPbivizOptions.passphrase; // eslint-disable-next-line require-atomic-updates config.server.passphrase = globalPbivizOptions.passphrase; } - await fs.writeFile(path.join(__dirname, confPath), JSON.stringify(config)); + await fs.writeFile(path.join(rootPath, confPath), JSON.stringify(config)); } } return options; } -async function veryfyCertFile(keyPath, certPath, pfxPath, passphrase) { +export async function verifyCertFile(keyPath, certPath, pfxPath, passphrase) { let verifyCertDate; try { let endDateStr; @@ -389,7 +404,7 @@ async function veryfyCertFile(keyPath, certPath, pfxPath, passphrase) { if (!fs.existsSync(pfxPath) || !passphrase) { return false; } - let certStr = await exec(`powershell.exe (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('${pfxPath}','${passphrase}')).NotAfter.ToString('yyyy-MM-dd HH:mm:ss')`); + const certStr = await exec(`powershell.exe (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('${pfxPath}','${passphrase}')).NotAfter.ToString('yyyy-MM-dd HH:mm:ss')`); endDateStr = certStr.trim(); } // For Linux and Mac/darwin OS: @@ -400,26 +415,17 @@ async function veryfyCertFile(keyPath, certPath, pfxPath, passphrase) { endDateStr = await exec(`openssl x509 -enddate -noout -in ${certPath} | cut -d = -f 2`); } - let endDate = Date.parse(endDateStr); + const endDate = Date.parse(endDateStr); verifyCertDate = (endDate - Date.now()) > certSafePeriod; if (verifyCertDate) { ConsoleWriter.info(`Certificate is valid.`); } else { - ConsoleWriter.warn(`Certificate is invalid!`); + ConsoleWriter.warning(`Certificate is invalid!`); removeCertFiles(certPath, keyPath, pfxPath); } } catch (err) { - ConsoleWriter.warn(`Certificate verification error: ${err}`); + ConsoleWriter.warning(`Certificate verification error: ${err}`); removeCertFiles(certPath, keyPath, pfxPath); } return verifyCertDate; } - -module.exports = { - getCertFile, - createCertFile, - openCertFile, - removeCertFiles, - getGlobalPbivizCerts, - resolveCertificate -}; diff --git a/src/CommandManager.ts b/src/CommandManager.ts new file mode 100644 index 00000000..eb79ed02 --- /dev/null +++ b/src/CommandManager.ts @@ -0,0 +1,78 @@ + +import ConsoleWriter from './ConsoleWriter.js'; +import VisualManager from './VisualManager.js'; +import { WebpackOptions } from './WebPackWrap.js'; + +interface StartOptions { + port: number, + stats: boolean, + drop: boolean +} + +interface PackageOptions { + pbiviz: boolean, + resources: boolean, + minify: boolean, + compression: number, + stats: boolean, +} + +interface NewOptions { + force: boolean, + template: string +} + +export default class CommandManager { + public static async start(options: StartOptions, rootPath: string) { + const webpackOptions: WebpackOptions = { + devMode: true, + devtool: "source-map", + generateResources: true, + generatePbiviz: false, + minifyJS: false, + minify: false, + devServerPort: options.port, + stats: options.stats + } + const visualManager = new VisualManager(rootPath) + await visualManager + .prepareVisual() + .initializeWebpack(webpackOptions) + visualManager.startWebpackServer(options.drop) + } + + public static async package(options: PackageOptions, rootPath: string) { + if (!options.pbiviz && !options.resources) { + ConsoleWriter.error('Nothing to build. Cannot use --no-pbiviz without --resources'); + process.exit(1); + } + + const webpackOptions = { + devMode: false, + generateResources: options.resources, + generatePbiviz: options.pbiviz, + minifyJS: options.minify, + minify: options.minify, + compression: options.compression, + stats: options.stats + } + new VisualManager(rootPath) + .prepareVisual() + .initializeWebpack(webpackOptions) + .then(visualManager => visualManager.generatePackage()) + } + + public static new({ force, template }: NewOptions, name: string, rootPath: string) { + const generateOptions = { + force: force, + template: template + }; + VisualManager.createVisual(rootPath, name, generateOptions) + } + + public static info(rootPath: string) { + new VisualManager(rootPath) + .prepareVisual() + .displayInfo(); + } +} \ No newline at end of file diff --git a/lib/ConsoleWriter.js b/src/ConsoleWriter.ts similarity index 58% rename from lib/ConsoleWriter.js rename to src/ConsoleWriter.ts index 41c184c6..d1eb286a 100644 --- a/lib/ConsoleWriter.js +++ b/src/ConsoleWriter.ts @@ -26,20 +26,19 @@ "use strict"; -let chalk = require('chalk'); -let fs = require('fs'); -let path = require('path'); -let os = require('os'); +import chalk from 'chalk'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import { getRootPath } from './utils.js'; -if (os.platform() === 'darwin') { - chalk = chalk.bold; -} +const preferredChalk = os.platform() === 'darwin' ? chalk.bold : chalk; function prependLogTag(tag, args) { - return [tag].concat(Array.from(args)); + return [tag].concat(args); } -class ConsoleWriter { +export default class ConsoleWriter { /** Causes the terminal to beep */ static beep() { process.stdout.write("\x07"); @@ -47,47 +46,47 @@ class ConsoleWriter { /** Outputs a blank line */ static blank() { - console.info(chalk.reset(' ')); + console.info(preferredChalk.reset(' ')); } /** * Outputs arguments with the "done" tag / colors * - * @param {...*} arguments - arguments passed through to console.info + * @param {array} arguments - arguments passed through to console.info */ - static done(/* arguments */) { - let tag = chalk.bgGreen(' done '); - console.info.apply(this, prependLogTag(tag, arguments)); + static done(args) { + const tag = preferredChalk.bgGreen(' done '); + console.info.apply(this, prependLogTag(tag, args)); } /** * Outputs arguments with the "info" tag / colors * - * @param {...*} arguments - arguments passed through to console.info + * @param {array} args - arguments passed through to console.info */ - static info(/* arguments */) { - let tag = chalk.bgCyan(' info '); - console.info.apply(this, prependLogTag(tag, arguments)); + static info(args) { + const tag = preferredChalk.bgCyan(' info '); + console.info.apply(this, prependLogTag(tag, args)); } /** * Outputs arguments with the "warn" tag / colors * - * @param {...*} arguments - arguments passed through to console.warn + * @param {array} args - arguments passed through to console.warn */ - static warn(/* arguments */) { - let tag = chalk.bgYellow.black(' warn '); - console.warn.apply(this, prependLogTag(tag, arguments)); + static warning(args) { + const tag = preferredChalk.bgYellow.black(' warn '); + console.warn.apply(this, prependLogTag(tag, args)); } /** * Outputs arguments with the "error" tag / colors * - * @param {...*} arguments - arguments passed through to console.error + * @param {array} args - arguments passed through to console.error */ - static error(/* arguments */) { - let tag = chalk.bgRed(' error '); - console.error.apply(this, prependLogTag(tag, arguments)); + static error(args) { + const tag = preferredChalk.bgRed(' error '); + console.error.apply(this, prependLogTag(tag, args)); } /** @@ -97,14 +96,14 @@ class ConsoleWriter { * @param {number} [depthLimit=Infinity] - limit the number of levels to recurse * @param {string} [keyPrefix=''] - text to prepend to each key */ - static infoTable(data, depthLimit, keyPrefix) { + static infoTable(data, depthLimit?, keyPrefix?) { if (!data) { return; } - let limit = typeof depthLimit === 'undefined' ? Infinity : depthLimit; - for (let key in data) { - let item = data[key]; - let itemKey = (keyPrefix || '') + key; + const limit = typeof depthLimit === 'undefined' ? Infinity : depthLimit; + for (const key in data) { + const item = data[key]; + const itemKey = (keyPrefix || '') + key; if (limit > 1 && typeof item === 'object' && !Array.isArray(item)) { ConsoleWriter.infoTable(item, limit - 1, itemKey + '.'); } else { @@ -120,11 +119,11 @@ class ConsoleWriter { * @param {string} value - value for this row * @param {number} [keyWidth=30] - width used for padding of the key column */ - static infoTableRow(key, value, keyWidth) { - let width = keyWidth || 30; - let padding = Math.max(0, width - key.length); - let paddedKey = chalk.bold(key) + (new Array(padding)).join('.'); - ConsoleWriter.info(paddedKey, value); + static infoTableRow(key, value, keyWidth?) { + const width = keyWidth || 30; + const padding = Math.max(0, width - key.length); + const paddedKey = preferredChalk.bold(key) + (new Array(padding)).join('.'); + ConsoleWriter.info([paddedKey, value]); } /** @@ -138,23 +137,22 @@ class ConsoleWriter { if (!error) { return; } - let tag = error.type ? chalk.bold(error.type.toUpperCase()) : 'UNKNOWN'; - let file = error.filename ? chalk.bgWhite.black(` ${error.filename} `) + ':' : ''; - let position = (error.line && error.column) ? chalk.cyan(`(${error.line},${error.column})`) : ''; - let message = error.message || ''; - ConsoleWriter.error(tag, `${file} ${position} ${message}`); + const tag = error.type ? preferredChalk.bold(error.type.toUpperCase()) : 'UNKNOWN'; + const file = error.filename ? preferredChalk.bgWhite.black(` ${error.filename} `) + ':' : ''; + const position = (error.line && error.column) ? preferredChalk.cyan(`(${error.line},${error.column})`) : ''; + const message = error.message || ''; + ConsoleWriter.error([tag, `${file} ${position} ${message}`]); }); } else { - ConsoleWriter.error('UNKNOWN', errors); + ConsoleWriter.error(['UNKNOWN', errors]); } } /** * Outputs ascii art of the PowerBI logo */ - static logo() { - let logoText = fs.readFileSync(path.join(__dirname, '..', 'assets', 'logo.txt')).toString(); - console.info(chalk.bold.yellow(logoText)); + static getLogoVisualization() { + return fs.readFileSync(path.join(getRootPath(), 'assets', 'logo.txt')).toString(); } /** @@ -163,10 +161,10 @@ class ConsoleWriter { static validationLog(log) { // api/js/css/pkg - let filterChecks = (attrCB, propCB) => { - for (let checkname in log) { + const filterChecks = (attrCB, propCB) => { + for (const checkname in log) { if (checkname !== 'valid') { - let checkpoint = log[checkname]; + const checkpoint = log[checkname]; ConsoleWriter[checkpoint.error.length ? 'info' : 'done'](checkpoint.check); attrCB(checkpoint, propCB); } @@ -174,10 +172,10 @@ class ConsoleWriter { }; // error/message/ok - let filterCheckAttrs = (checkpoint, propCB) => { - for (let propName in checkpoint) { + const filterCheckAttrs = (checkpoint, propCB) => { + for (const propName in checkpoint) { if (propName !== 'message') { - let prop = checkpoint[propName]; + const prop = checkpoint[propName]; if (typeof (prop) === 'object' && prop.length) { propCB(prop, propName); } @@ -186,10 +184,10 @@ class ConsoleWriter { }; // col/line/text - let filterAttrProps = (props, propName) => { + const filterAttrProps = (props, propName) => { props.forEach((opt) => { - let result = []; - for (let key in opt) { + const result = []; + for (const key in opt) { result.push(opt[key]); } if (result.length) { @@ -200,11 +198,9 @@ class ConsoleWriter { filterChecks(filterCheckAttrs, filterAttrProps); - let type = log.valid ? 'done' : 'error'; - let text = log.valid ? 'Valid package' : 'Invalid package'; + const type = log.valid ? 'done' : 'error'; + const text = log.valid ? 'Valid package' : 'Invalid package'; ConsoleWriter.blank(); ConsoleWriter[type](text); } } - -module.exports = ConsoleWriter; diff --git a/lib/TemplateFetcher.js b/src/TemplateFetcher.ts similarity index 79% rename from lib/TemplateFetcher.js rename to src/TemplateFetcher.ts index 1e74e274..c953223d 100644 --- a/lib/TemplateFetcher.js +++ b/src/TemplateFetcher.ts @@ -1,15 +1,21 @@ -const fs = require('fs-extra'); -const path = require('path'); -const config = require('../config.json'); -const JSZip = require('jszip'); -const VisualGenerator = require("./VisualGenerator"); -const { exec } = require('child_process'); -const ConsoleWriter = require('../lib/ConsoleWriter'); -const download = require('./utils').download; -const createFolder = require('./utils').createFolder; -class TemplateFetcher { - constructor({ templateName, visualName, apiVersion }) { +import { createFolder, download, readJsonFromRoot } from './utils.js'; +import ConsoleWriter from './ConsoleWriter.js'; +import JSZip from 'jszip'; +import VisualGenerator from "./VisualGenerator.js"; +import { exec } from 'child_process'; +import fs from 'fs-extra'; +import path from 'path'; + +const config = readJsonFromRoot('config.json'); + +export default class TemplateFetcher { + private templateName: string; + private visualName: string; + private folderName: string; + private apiVersion: string; + + constructor(templateName: string, visualName: string, apiVersion: string) { this.templateName = templateName; this.visualName = visualName; this.folderName = `${this.visualName}`; @@ -17,7 +23,7 @@ class TemplateFetcher { } fetch() { - let folder = createFolder.call(this, this.folderName); + const folder = createFolder.call(this, this.folderName); download.call(this, config.visualTemplates[this.templateName], path.join(folder, "template.zip")) .then(this.extractFiles.bind(this)) .then(this.removeZipFile.bind(this)) @@ -32,7 +38,7 @@ class TemplateFetcher { const fileName = path.join(folder, "template.zip"); await fs.unlink(`.${path.sep}${fileName}`, (err) => { if (err) { - ConsoleWriter.warn(`.${path.sep}${fileName} was not deleted`); + ConsoleWriter.warning(`.${path.sep}${fileName} was not deleted`); } }); } @@ -50,8 +56,8 @@ class TemplateFetcher { await fs.ensureDir(dest); } else { // write files into dirs for exclude parent folder - const dest = path.join(path.dirname(filePath), path.join(path.dirname(filename), "..", filename.split("/").pop(0))); - const content = await zip.file(filename).async('nodebuffer'); + const dest = path.join(path.dirname(filePath), path.join(path.dirname(filename), "..", filename.split("/").pop() ?? "")); + const content = await zip.file(filename)?.async('nodebuffer'); await fs.writeFile(dest, content); } } @@ -91,12 +97,12 @@ class TemplateFetcher { ConsoleWriter.error(`Error code: ${error.code}`); ConsoleWriter.error(`Signal received: ${error.signal}`); } - ConsoleWriter.warn(stderr); + ConsoleWriter.warning(stderr); ConsoleWriter.info(stdout); - resolve(); + resolve(true); }); child.on("error", (er) => { - ConsoleWriter.log(er); + ConsoleWriter.error(er); reject(); }); child.on("exit", (code) => { @@ -114,5 +120,3 @@ class TemplateFetcher { ConsoleWriter.info("Run `npm run package` to create visual package"); } } - -module.exports = TemplateFetcher; diff --git a/lib/VisualGenerator.js b/src/VisualGenerator.ts similarity index 87% rename from lib/VisualGenerator.js rename to src/VisualGenerator.ts index c0a32edc..d3347af8 100644 --- a/lib/VisualGenerator.js +++ b/src/VisualGenerator.ts @@ -26,15 +26,17 @@ "use strict"; -const fs = require('fs-extra'); -const path = require('path'); -const uuid = require('uuid'); -const compareVersions = require("compare-versions"); -const config = require('../config.json'); -const lodashDefaults = require('lodash.defaults'); -const template = require('../templates/pbiviz-json-template'); - -const VISUAL_TEMPLATES_PATH = path.join(__dirname, '..', config.templates.visuals); +import crypto from 'crypto'; +import { getRootPath, readJsonFromRoot } from './utils.js'; +import { compareVersions } from "compare-versions"; +import fs from 'fs-extra'; +import lodashDefaults from 'lodash.defaults'; +import path from 'path'; +import template from '../templates/pbiviz-json-template.js'; + +const config = readJsonFromRoot('config.json'); + +const VISUAL_TEMPLATES_PATH = path.join(getRootPath(), config.templates.visuals); const API_VERSION = config.generate.apiVersion; const minAPIversion = config.constants.minAPIversion; @@ -78,7 +80,7 @@ function createPbiVizJson(visualPath, options, templateName) { let data = template(options); // write out the target file content - let targetPath = path.join(visualPath, 'pbiviz.json'); + const targetPath = path.join(visualPath, 'pbiviz.json'); fs.writeFileSync(targetPath, data); let templatePath = path.join(VISUAL_TEMPLATES_PATH, templateName); @@ -88,7 +90,7 @@ function createPbiVizJson(visualPath, options, templateName) { data = fs.readJsonSync(targetPath); //override externalJS settings with those of the local template file - let templateData = fs.readJsonSync(templatePath); + const templateData = fs.readJsonSync(templatePath); for (const objKey of Object.keys(templateData)) { data[objKey] = templateData[objKey]; } @@ -144,7 +146,7 @@ const defaultOptions = { externalJS: [] }; -class VisualGenerator { +export default class VisualGenerator { /** * Generates a new visual * @@ -153,23 +155,23 @@ class VisualGenerator { * @param {object} options - specify options for the visual generator * @returns {Promise} - promise resolves with the path to the newly created package */ - static generate(targetPath, visualName, options) { + static generateVisual(targetPath, visualName, options): Promise { return new Promise((resolve, reject) => { - let buildOptions = lodashDefaults(options, defaultOptions); - if (!buildOptions.apiVersion || compareVersions.compare(buildOptions.apiVersion, minAPIversion, "<")) { + const buildOptions = lodashDefaults(options, defaultOptions); + if (!buildOptions.apiVersion || compareVersions(buildOptions.apiVersion, minAPIversion) === -1) { return reject(new Error(`Can not generate a visual with an API below than ${minAPIversion}, current API is '${buildOptions.apiVersion}'.`)); } - let visualOptions = generateVisualOptions(visualName, buildOptions.apiVersion); + const visualOptions = generateVisualOptions(visualName, buildOptions.apiVersion); const validationResult = VisualGenerator.checkVisualName(visualOptions.name); if (!visualOptions || !visualOptions.name || validationResult) { return reject(new Error(validationResult || "Invalid visual name")); } if (!validTemplate(buildOptions.template)) { - return reject(new Error('Invalid template')); + return reject(new Error(`Invalid template "${buildOptions.template}"`)); } - let visualPath = path.join(targetPath, visualOptions.name); + const visualPath = path.join(targetPath, visualOptions.name); fs.access(visualPath, err => { if (!err && !buildOptions.force) { return reject(new Error('This visual already exists. Use force to overwrite.')); @@ -192,7 +194,7 @@ class VisualGenerator { * Generates a random GUID for your visual */ static generateVisualGuid() { - return uuid.v4().replace(/-/g, '').toUpperCase(); + return crypto.randomUUID().replace(/-/g, '').toUpperCase(); } /** @@ -232,4 +234,3 @@ class VisualGenerator { } } } -module.exports = VisualGenerator; diff --git a/src/VisualManager.ts b/src/VisualManager.ts new file mode 100644 index 00000000..d65d185b --- /dev/null +++ b/src/VisualManager.ts @@ -0,0 +1,220 @@ +/* + * Power BI Visual CLI + * + * Copyright (c) Microsoft Corporation + * All rights reserved. + * MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the ""Software""), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +"use strict"; + +import webpack, { Compiler, Stats } from "webpack"; +import WebpackDevServer from "webpack-dev-server"; +import childProcess from 'child_process'; +import fs from 'fs-extra'; +import path from 'path'; + +import ConsoleWriter from './ConsoleWriter.js'; +import VisualGenerator from './VisualGenerator.js'; +import { readJsonFromRoot, readJsonFromVisual } from './utils.js'; +import WebpackWrap, { WebpackOptions } from './WebPackWrap.js'; +import TemplateFetcher from "./TemplateFetcher.js"; + +interface GenerateOptions { + force: boolean; + template: string; +} + +const PBIVIZ_FILE = 'pbiviz.json'; + +/** + * Represents an instance of a visual package based on file path + */ +export default class VisualManager { + public basePath: string; + public pbivizConfig; + private webpackConfig; + private compiler: Compiler; + private webpackDevServer: WebpackDevServer; + + constructor(rootPath: string) { + this.basePath = rootPath; + } + + public prepareVisual() { + if (this.doesPBIVIZExists()) { + this.pbivizConfig = readJsonFromVisual(PBIVIZ_FILE, this.basePath); + } else { + throw new Error(PBIVIZ_FILE + ' not found. You must be in the root of a visual project to run this command.') + } + return this; + } + + public async initializeWebpack(webpackOptions: WebpackOptions) { + const webpackWrap = new WebpackWrap(); + this.webpackConfig = await webpackWrap.generateWebpackConfig(this, webpackOptions) + + this.compiler = webpack(this.webpackConfig); + + return this; + } + + public generatePackage() { + const callback = (err: Error, stats: Stats) => { + this.parseCompilationResults(err, stats) + } + this.compiler.run(callback); + } + + public startWebpackServer(generateDropFiles: boolean = false) { + ConsoleWriter.blank(); + ConsoleWriter.info('Starting server...'); + try { + if (generateDropFiles) { + this.prepareDropFiles(); + } + + this.webpackDevServer = new WebpackDevServer({ + ...this.webpackConfig.devServer, + client: false, + hot: false, + devMiddleware: { + writeToDisk: true + } + }, this.compiler); + + (async () => { + await this.webpackDevServer.start(); + ConsoleWriter.info(`Server listening on port ${this.webpackConfig.devServer.port}`); + })(); + + process.on('SIGINT', this.stopServer); + process.on('SIGTERM', this.stopServer); + } catch (e) { + ConsoleWriter.error(e.message); + process.exit(1); + } + } + + public displayInfo() { + if (this.pbivizConfig) { + ConsoleWriter.infoTable(this.pbivizConfig); + } else { + ConsoleWriter.error('Unable to load visual info. Please ensure the package is valid.'); + } + } + + /** + * Creates a new visual package + */ + static async createVisual(rootPath: string, visualName: string, generateOptions: GenerateOptions): Promise { + ConsoleWriter.info('Creating new visual'); + if (generateOptions.force) { + ConsoleWriter.warning('Running with force flag. Existing files will be overwritten'); + } + + try { + const config = readJsonFromRoot('config.json'); + if(config.visualTemplates[generateOptions.template]){ + new TemplateFetcher( generateOptions.template, visualName, undefined ) + .fetch(); + return; + } + const newVisualPath = await VisualGenerator.generateVisual(rootPath, visualName, generateOptions) + await VisualManager.installPackages(newVisualPath).then(() => ConsoleWriter.done('Visual creation complete')) + + return new VisualManager(newVisualPath); + } catch (error) { + ConsoleWriter.error(['Unable to create visual.\n', error]); + process.exit(1); + } + } + + /** + * Install npm dependencies for visual + */ + static installPackages(visualPath: string): Promise { + return new Promise(function (resolve, reject) { + ConsoleWriter.info('Installing packages...'); + childProcess.exec(`npm install`, { cwd: visualPath }, + (err) => { + if (err) { + reject(new Error('Package install failed.')); + } else { + ConsoleWriter.info('Installed packages.'); + resolve(); + } + }); + }); + } + + private doesPBIVIZExists() { + return fs.existsSync(PBIVIZ_FILE); + } + + private prepareDropFiles() { + this.webpackConfig.devServer.onBeforeSetupMiddleware = (devServer) => { + const { headers, publicPath, static: { directory } } = this.webpackConfig.devServer; + const assets = [ 'visual.js`', 'visual.css', 'pbiviz.json' ] + + const setHeaders = (res) => { + Object.getOwnPropertyNames(headers) + .forEach(property => res.header(property, headers[property])); + }; + const readFile = (file, res) => { + fs.readFile(file).then(function (content) { + res.write(content); + res.end(); + }); + }; + + assets.forEach(asset => { + devServer.app.get(`${publicPath}/${asset}`, function (req, res) { + setHeaders(res); + readFile(path.join(directory, asset), res); + }); + }); + }; + } + + private stopServer() { + ConsoleWriter.blank(); + ConsoleWriter.info("Stopping server..."); + if (this.webpackDevServer) { + this.webpackDevServer.close(); + this.webpackDevServer = null; + } + } + + private parseCompilationResults(err: Error, stats: Stats) { + ConsoleWriter.blank(); + if (err) { + ConsoleWriter.error(`Package wasn't created. ${JSON.stringify(err)}`); + } + if (stats?.compilation.errors.length) { + stats.compilation.errors.forEach(error => ConsoleWriter.error(error.message)); + ConsoleWriter.error(`Package wasn't created. ${stats.compilation.errors.length} errors found.`); + } + if (!err && !stats?.compilation.errors.length) { + ConsoleWriter.done('Build completed successfully'); + } + } +} diff --git a/lib/WebPackWrap.js b/src/WebPackWrap.ts similarity index 59% rename from lib/WebPackWrap.js rename to src/WebPackWrap.ts index d8d12fee..9a9b65ec 100644 --- a/lib/WebPackWrap.js +++ b/src/WebPackWrap.ts @@ -1,58 +1,74 @@ "use strict"; -const fs = require('fs-extra'); -const os = require('os'); -const path = require('path'); -const webpack = require('webpack'); -const config = require('../config.json'); -const { PowerBICustomVisualsWebpackPlugin } = require('powerbi-visuals-webpack-plugin'); -const encoding = "utf8"; -const ConsoleWriter = require('../lib/ConsoleWriter'); -const ExtraWatchWebpackPlugin = require('extra-watch-webpack-plugin'); -const Visualizer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; -const util = require('util'); -const exec = util.promisify(require('child_process').exec); -const CertificateTools = require("../lib/CertificateTools"); +import fs from 'fs-extra'; +import os from 'os'; +import path from 'path'; +import webpack from 'webpack'; +import util from 'util'; +const exec = util.promisify(processExec); +import { exec as processExec } from 'child_process'; +import ExtraWatchWebpackPlugin from 'extra-watch-webpack-plugin'; +import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; +import { PowerBICustomVisualsWebpackPlugin } from 'powerbi-visuals-webpack-plugin'; +import ConsoleWriter from './ConsoleWriter.js'; +import { resolveCertificate } from "./CertificateTools.js"; +import lodashCloneDeep from 'lodash.clonedeep'; +import { readJsonFromRoot, readJsonFromVisual } from './utils.js' + +const config = readJsonFromRoot('config.json'); +const npmPackage = readJsonFromRoot('package.json'); + const visualPlugin = "visualPlugin.ts"; -const lodashCloneDeep = require('lodash.clonedeep'); -const npmPackage = require('../package.json'); +const encoding = "utf8"; + +export interface WebpackOptions { + devMode: boolean; + generateResources: boolean; + generatePbiviz: boolean; + minifyJS: boolean; + minify: boolean; + stats: boolean; + compression?: number; + devtool?: string; + devServerPort?: number; + fast?: boolean; +} -class WebPackGenerator { +export default class WebPackWrap { + private pbiviz; + private webpackConfig; static async prepareFoldersAndFiles(visualPackage) { - let tmpFolder = path.join(visualPackage.basePath, ".tmp"); - let precompileFolder = path.join(visualPackage.basePath, config.build.precompileFolder); - let dropFolder = path.join(visualPackage.basePath, config.build.dropFolder); - let packgeDropFolder = path.join(visualPackage.basePath, config.package.dropFolder); - let visualPluginFile = path.join(visualPackage.basePath, config.build.precompileFolder, visualPlugin); + const tmpFolder = path.join(visualPackage.basePath, ".tmp"); + const precompileFolder = path.join(visualPackage.basePath, config.build.precompileFolder); + const dropFolder = path.join(visualPackage.basePath, config.build.dropFolder); + const packageDropFolder = path.join(visualPackage.basePath, config.package.dropFolder); + const visualPluginFile = path.join(visualPackage.basePath, config.build.precompileFolder, visualPlugin); await fs.ensureDir(tmpFolder); await fs.ensureDir(precompileFolder); await fs.ensureDir(dropFolder); - await fs.ensureDir(packgeDropFolder); + await fs.ensureDir(packageDropFolder); await fs.createFile(visualPluginFile); } static loadAPIPackage() { try { - let basePath = require.resolve("powerbi-visuals-api", { - paths: [process.cwd()] - }); - return require(basePath); + return import("file://" + path.join(process.cwd(), "node_modules", "powerbi-visuals-api", "index.js")); } catch (ex) { return null; } } async installAPIpackage() { - let apiVersion = this.pbiviz.apiVersion ? `~${this.pbiviz.apiVersion}` : "latest"; + const apiVersion = this.pbiviz.apiVersion ? `~${this.pbiviz.apiVersion}` : "latest"; try { ConsoleWriter.info(`Installing API: ${apiVersion}...`); - let { + const { stdout, stderr } = await exec(`npm install --save powerbi-visuals-api@${apiVersion}`); - ConsoleWriter.info(stdout); - ConsoleWriter.warn(stderr); + if (stdout) ConsoleWriter.info(stdout); + if (stderr) ConsoleWriter.warning(stderr); return true; } catch (ex) { if (ex.message.indexOf("No matching version found for powerbi-visuals-api") !== -1) { @@ -72,12 +88,12 @@ class WebPackGenerator { } async configureDevServer(visualPackage, port = 8080) { - let options = await CertificateTools.resolveCertificate(); + const options = await resolveCertificate(); this.webpackConfig.devServer = { ...this.webpackConfig.devServer, hot: false, - port: port || config.server.port, + port, static: { directory: path.join(visualPackage.basePath, config.build.dropFolder), publicPath: config.server.assetsRoute @@ -95,13 +111,11 @@ class WebPackGenerator { } configureVisualPlugin(options, tsconfig, visualPackage) { - const visualJSFilePath = visualPackage.buildPath(tsconfig.compilerOptions.out || tsconfig.compilerOptions.outDir); + const visualJSFilePath = tsconfig.compilerOptions.out || tsconfig.compilerOptions.outDir; this.webpackConfig.output.path = path.join(visualPackage.basePath, config.build.dropFolder); this.webpackConfig.output.filename = "[name]"; - let visualPluginPath = path.join(process.cwd(), config.build.precompileFolder, visualPlugin); - this.webpackConfig.plugins.push( - new webpack.WatchIgnorePlugin({ paths: [visualPluginPath] }) - ); + const visualPluginPath = path.join(process.cwd(), config.build.precompileFolder, visualPlugin); + this.webpackConfig.watchOptions.ignored.push(visualPluginPath) if (tsconfig.compilerOptions.out) { this.webpackConfig.entry = { "visual.js": visualJSFilePath @@ -114,37 +128,39 @@ class WebPackGenerator { } async getEnvironmentDetails() { - let env = {}; - env.nodeVersion = process.versions.node; - env.osPlatform = await os.platform(); - env.osVersion = await os.version ? os.version() : "undefined"; - env.osReleaseVersion = await os.release(); - env.toolsVersion = npmPackage.version; + const env = { + nodeVersion: process.versions.node, + osPlatform: await os.platform(), + osVersion: await os.version ?? "undefined", + osReleaseVersion: await os.release(), + toolsVersion: npmPackage.version + }; return env; } async configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig) { - let pluginConfiguration = lodashCloneDeep(visualPackage.config); + const pluginConfiguration = lodashCloneDeep(visualPackage.pbivizConfig); //(?=\D*$) - positive look-ahead to find last version symbols and exclude any non-digit symbols after the version. - let regexFullVersion = /(?:\d+\.?){1,3}(?=\D*$)/; - let regexMinorVersion = /\d+(?:\.\d+)?/; + const regexFullVersion = /(?:\d+\.?){1,3}(?=\D*$)/; + const regexMinorVersion = /\d+(?:\.\d+)?/; let apiVersionInstalled; try { - apiVersionInstalled = (await exec('npm list powerbi-visuals-api version')).stdout.match(regexFullVersion)[0]; + const subprocess = await exec('npm list powerbi-visuals-api version') + apiVersionInstalled = subprocess.stdout.match(regexFullVersion)[0]; } catch (err) { - ConsoleWriter.warn(`"powerbi-visuals-api" is not installed`); + ConsoleWriter.warning(`"powerbi-visuals-api" is not installed`); } // if the powerbi-visual-api package wasn't installed // install the powerbi-visual-api, with version from apiVersion in pbiviz.json // or the latest API, if apiVersion is absent in pbiviz.json - if (!apiVersionInstalled || (typeof this.pbiviz.apiVersion !== "undefined" && this.pbiviz.apiVersion.match(regexMinorVersion)[0] != apiVersionInstalled.match(regexMinorVersion)[0])) { - ConsoleWriter.warn(`installed "powerbi-visuals-api" version - "${apiVersionInstalled}", is not match with the version specified in pbviz.json - "${this.pbiviz.apiVersion}".`); + if (!apiVersionInstalled || !this.pbiviz.apiVersion || this.pbiviz.apiVersion.match(regexMinorVersion)[0] != apiVersionInstalled.match(regexMinorVersion)[0]) { + ConsoleWriter.warning(`installed "powerbi-visuals-api" version - "${apiVersionInstalled}", is not match with the version specified in pbviz.json - "${this.pbiviz.apiVersion}".`); await this.installAPIpackage(); } // pluginConfiguration.env = await this.getEnvironmentDetails(); - let api = WebPackGenerator.loadAPIPackage(visualPackage); + const api = await WebPackWrap.loadAPIPackage(); pluginConfiguration.apiVersion = api.version; pluginConfiguration.capabilitiesSchema = api.schemas.capabilities; pluginConfiguration.pbivizSchema = api.schemas.pbiviz; @@ -167,16 +183,16 @@ class WebPackGenerator { } async appendPlugins(options, visualPackage, tsconfig) { - let pluginConfiguration = await this.configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig); + const pluginConfiguration = await this.configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig); let statsFilename = config.build.stats.split("/").pop(); - let statsLocation = config.build.stats.split("/").slice(0, -1).join(path.sep); - statsFilename = statsFilename.split(".").slice(0, -1).join("."); + const statsLocation = config.build.stats.split("/").slice(0, -1).join(path.sep); + statsFilename = statsFilename?.split(".").slice(0, -1).join("."); statsFilename = `${statsFilename}.${options.devMode ? "dev" : "prod"}.html`; - if (!options.disableStats) { + if (options.stats) { this.webpackConfig.plugins.push( - new Visualizer({ + new BundleAnalyzerPlugin({ reportFilename: path.join(statsLocation, statsFilename), openAnalyzer: false, analyzerMode: `static` @@ -186,12 +202,7 @@ class WebPackGenerator { this.webpackConfig.plugins.push( new PowerBICustomVisualsWebpackPlugin(pluginConfiguration), new ExtraWatchWebpackPlugin({ - files: [visualPackage.buildPath(this.pbiviz.capabilities)] - }), - new webpack.ProvidePlugin({ - window: 'realWindow', - define: 'fakeDefine', - powerbi: 'globalPowerbi' + files: this.pbiviz.capabilities }) ); @@ -205,7 +216,7 @@ class WebPackGenerator { } } - useLoader({ + async useLoader({ fast = false }) { let tsOptions = {}; @@ -219,15 +230,15 @@ class WebPackGenerator { test: /(\.ts)x?$/, use: [ { - loader: require.resolve('ts-loader'), + loader: 'ts-loader', options: tsOptions } ] }); } - async prepareWebPackConfig(visualPackage, options, tsconfig) { - this.webpackConfig = require('./webpack.config'); + async prepareWebPackConfig(visualPackage, options: WebpackOptions, tsconfig) { + this.webpackConfig = Object.assign({}, await import('./webpack.config.js')).default; if (options.minifyJS) { this.enableOptimization(); } @@ -239,7 +250,7 @@ class WebPackGenerator { await this.appendPlugins(options, visualPackage, tsconfig); await this.configureDevServer(visualPackage, options.devServerPort); await this.configureVisualPlugin(options, tsconfig, visualPackage); - this.useLoader({ + await this.useLoader({ fast: options.fast }); @@ -247,8 +258,8 @@ class WebPackGenerator { } async assemblyExternalJSFiles(visualPackage) { - let externalJSFilesContent = ""; - let externalJSFilesPath = path.join(visualPackage.basePath, config.build.precompileFolder, "externalJS.js"); + const externalJSFilesContent = ""; + const externalJSFilesPath = path.join(visualPackage.basePath, config.build.precompileFolder, "externalJS.js"); await fs.writeFile( externalJSFilesPath, externalJSFilesContent, { @@ -258,7 +269,7 @@ class WebPackGenerator { return externalJSFilesPath; } - async applyWebpackConfig(visualPackage, options = { + async generateWebpackConfig(visualPackage, options: WebpackOptions = { devMode: false, generateResources: false, generatePbiviz: false, @@ -267,27 +278,22 @@ class WebPackGenerator { devServerPort: 8080, fast: false, compression: 0, - disableStats: false + stats: true }) { - const tsconfigPath = visualPackage.buildPath('tsconfig.json'); - const tsconfig = require(tsconfigPath); + const tsconfig = readJsonFromVisual('tsconfig.json'); + this.pbiviz = readJsonFromVisual('pbiviz.json'); - this.pbivizJsonPath = visualPackage.buildPath('pbiviz.json'); - this.pbiviz = require(this.pbivizJsonPath); - - const capabliliesPath = this.pbiviz.capabilities; - visualPackage.config.capabilities = capabliliesPath; + const capabilitiesPath = this.pbiviz.capabilities; + visualPackage.pbivizConfig.capabilities = capabilitiesPath; const dependenciesPath = this.pbiviz.dependencies && path.join(process.cwd(), this.pbiviz.dependencies); - const dependenciesFile = fs.existsSync(dependenciesPath) && require(dependenciesPath); - visualPackage.config.dependencies = typeof dependenciesFile === 'object' ? dependenciesFile : {}; + const dependenciesFile = fs.existsSync(dependenciesPath) && JSON.parse(fs.readFileSync(dependenciesPath)); + visualPackage.pbivizConfig.dependencies = typeof dependenciesFile === 'object' ? dependenciesFile : {}; - await WebPackGenerator.prepareFoldersAndFiles(visualPackage); + await WebPackWrap.prepareFoldersAndFiles(visualPackage); - let webpackConfig = await this.prepareWebPackConfig(visualPackage, options, tsconfig); + const webpackConfig = await this.prepareWebPackConfig(visualPackage, options, tsconfig); - return { webpackConfig }; + return webpackConfig; } } - -module.exports = WebPackGenerator; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 00000000..34b48195 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,41 @@ +import fs from 'fs-extra'; +import https from "https"; +import path from "path"; +import os from "os"; + +export function download(url, pathToFile) { + return new Promise((resolve, reject) => { + const fileStream = fs.createWriteStream(pathToFile); + https.get(url, (res) => { + res.pipe(fileStream); + fileStream.on('close', () => resolve(fileStream)); + res.on('error', (error) => reject(error)); + }) + .on('error', (error) => reject(error)); + }); +} + +export function createFolder(folderName): string { + const folder = path.join("./", folderName); + fs.ensureDirSync(folder); + return folder; +} + +export function getRootPath(): string { + const isLinux = os.platform() === "linux" + const pathToDirectory = import.meta.url.split(isLinux ? "file://" : "file:///")[1]; + return path.join(pathToDirectory, "../.."); +} + +export function readFileFromRoot(filePath: string) { + return fs.readFileSync(path.join(getRootPath(), filePath), "utf8") +} + +export function readJsonFromRoot(filePath: string) { + return JSON.parse(readFileFromRoot(filePath)); +} + +export function readJsonFromVisual(filePath: string, visualPath?: string) { + return JSON.parse(fs.readFileSync(path.join(visualPath ?? process.cwd(), filePath), "utf8")); +} + diff --git a/src/webpack.config.ts b/src/webpack.config.ts new file mode 100644 index 00000000..99d24543 --- /dev/null +++ b/src/webpack.config.ts @@ -0,0 +1,144 @@ + +import { getRootPath, readJsonFromRoot } from './utils.js'; +import { LocalizationLoader } from "powerbi-visuals-webpack-plugin"; +import MiniCssExtractPlugin from "mini-css-extract-plugin"; +import TerserPlugin from "terser-webpack-plugin"; +import path from "path"; +import webpack from "webpack"; + +const config = readJsonFromRoot("/config.json"); + +const webpackConfig = { + entry: { + 'visual.js': ['./src/visual.ts'] + }, + target: 'web', + devtool: false, + mode: "production", + optimization: { + minimizer: [ + new TerserPlugin({ + parallel: true, + terserOptions: {} + }) + ], + minimize: false, + concatenateModules: false + }, + performance: { + maxEntrypointSize: 1024000, + maxAssetSize: 1024000, + hints: false + }, + module: { + rules: [ + { + parser: { + amd: false + } + }, + { + test: /\.json$/, + loader: 'json-loader', + type: "javascript/auto" + }, + { + test: /(\.less)|(\.css)$/, + use: [ + { + loader: MiniCssExtractPlugin.loader + }, + { + loader: 'css-loader' + }, + { + loader: 'less-loader', + options: { + lessOptions: { + paths: [path.resolve(getRootPath(), 'node_modules')] + } + } + } + ] + }, + { + test: /\.(woff|ttf|ico|woff2|jpg|jpeg|png|webp|gif|svg|eot)$/i, + type: 'asset/inline' + }, + { + test: /powerbiGlobalizeLocales\.js$/, + loader: LocalizationLoader + } + ] + }, + externals: { + "powerbi-visuals-api": 'null' + }, + resolve: { + extensions: ['.tsx', '.ts', '.jsx', '.js', '.css'], + fallback: { + assert: path.resolve("../node-modules/assert/"), + buffer: path.resolve("../node-modules/buffer/"), + console: path.resolve("../node-modules/console-browserify/"), + constants: path.resolve("../node-modules/constants-browserify/"), + crypto: path.resolve("../node-modules/crypto-browserify/"), + domain: path.resolve("../node-modules/domain-browser/"), + events: path.resolve("../node-modules/events/"), + http: path.resolve("../node-modules/stream-http/"), + https: path.resolve("../node-modules/https-browserify/"), + os: path.resolve("../node-modules/os-browserify/"), + path: path.resolve("../node-modules/path-browserify/"), + punycode: path.resolve("../node-modules/punycode/"), + process: path.resolve("../node-modules/process/"), + querystring: path.resolve("../node-modules/querystring-es3/"), + stream: path.resolve("../node-modules/stream-browserify/"), + _stream_duplex: path.resolve("../node-modules/readable-stream/"), + _stream_passthrough: path.resolve("../node-modules/readable-stream/"), + _stream_readable: path.resolve("../node-modules/readable-stream/"), + _stream_transform: path.resolve("../node-modules/readable-stream/"), + _stream_writable: path.resolve("../node-modules/readable-stream/"), + string_decoder: path.resolve("../node-modules/string_decoder/"), + sys: path.resolve("../node-modules/util/"), + timers: path.resolve("../node-modules/timers-browserify/"), + tty: path.resolve("../node-modules/tty-browserify/"), + url: path.resolve("../node-modules/url/"), + util: path.resolve("../node-modules/util/"), + vm: path.resolve("../node-modules/vm-browserify/"), + zlib: path.resolve("../node-modules/browserify-zlib/") + } + }, + output: { + path: null, + publicPath: 'assets', + filename: "[name]" + }, + devServer: { + allowedHosts: "all", + static: { + directory: null + }, + compress: true, + port: 8080, + hot: false, + server: 'https', + headers: { + "access-control-allow-origin": "*", + "cache-control": "public, max-age=0" + } + }, + watchOptions: { + ignored: ['node_modules/**'] + }, + plugins: [ + new webpack.ProvidePlugin({ + Buffer: ["buffer", "Buffer"], + process: "process/browser" + }), + new MiniCssExtractPlugin({ + filename: config.build.css, + chunkFilename: "[id].css" + }) + ] +}; + +export default webpackConfig; diff --git a/templates/pbiviz-json-template.js b/templates/pbiviz-json-template.js index 3c62952e..f7e88169 100644 --- a/templates/pbiviz-json-template.js +++ b/templates/pbiviz-json-template.js @@ -1,11 +1,11 @@ -module.exports = function (options) { +export default function (options) { return `{ "visual": { "name": "${options.name}", "displayName": "${options.displayName}", "guid": "${options.guid}", "visualClassName": "${options.visualClassName}", - "version": "1.0.0", + "version": "1.0.0.0", "description": "", "supportUrl": "", "gitHubUrl": "" diff --git a/templates/pbiviz.json.template b/templates/pbiviz.json.template index 13cc0b2e..f0684e01 100644 --- a/templates/pbiviz.json.template +++ b/templates/pbiviz.json.template @@ -4,7 +4,7 @@ "displayName": "<%= displayName %>", "guid": "<%= guid %>", "visualClassName": "<%= visualClassName %>", - "version": "1.0.0", + "version": "1.0.0.0", "description": "", "supportUrl": "", "gitHubUrl": "" diff --git a/templates/plugin-ts-template.js b/templates/plugin-ts-template.js index 1be320f3..2bfb4ec3 100644 --- a/templates/plugin-ts-template.js +++ b/templates/plugin-ts-template.js @@ -1,4 +1,4 @@ -module.exports = function (options) { +export default function (options) { return `declare var powerbi; powerbi.visuals = powerbi.visuals || {}; powerbi.visuals.plugins = powerbi.visuals.plugins || {}; diff --git a/templates/visuals/default/.eslintignore b/templates/visuals/default/.eslintignore new file mode 100644 index 00000000..fc6204f9 --- /dev/null +++ b/templates/visuals/default/.eslintignore @@ -0,0 +1,5 @@ +assets +style +dist +node_modules +.eslintrc.js \ No newline at end of file diff --git a/templates/visuals/default/.eslintrc.js b/templates/visuals/default/.eslintrc.js new file mode 100644 index 00000000..42f26710 --- /dev/null +++ b/templates/visuals/default/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + "browser": true, + "es6": true, + "es2017": true + }, + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + tsconfigRootDir: ".", + }, + plugins: [ + "powerbi-visuals" + ], + extends: [ + "plugin:powerbi-visuals/recommended" + ], + rules: {} +}; \ No newline at end of file diff --git a/templates/visuals/default/package.json b/templates/visuals/default/package.json index 1599fb41..ad2a4aa9 100644 --- a/templates/visuals/default/package.json +++ b/templates/visuals/default/package.json @@ -1,6 +1,7 @@ { "name": "visual", "description": "default_template_value", + "version": "1.0.0.0", "repository": { "type": "default_template_value", "url": "default_template_value" @@ -10,18 +11,18 @@ "pbiviz": "pbiviz", "start": "pbiviz start", "package": "pbiviz package", - "lint": "tslint -c tslint.json -p tsconfig.json" + "lint": "npx eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { - "@types/d3": "5.7.2", - "d3": "5.12.0", - "powerbi-visuals-api": "5.1.0", + "@types/d3": "7.4.0", + "d3": "7.8.5", + "powerbi-visuals-api": "5.4.0", "powerbi-visuals-utils-formattingmodel": "5.0.0" }, "devDependencies": { - "ts-loader": "6.1.0", - "tslint": "^5.18.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.3" + "@typescript-eslint/eslint-plugin": "^5.59.11", + "eslint": "^8.42.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "typescript": "4.9.3" } } \ No newline at end of file diff --git a/templates/visuals/default/pbiviz.json b/templates/visuals/default/pbiviz.json index 2a473931..fdd458a5 100644 --- a/templates/visuals/default/pbiviz.json +++ b/templates/visuals/default/pbiviz.json @@ -1,5 +1,6 @@ { - "apiVersion": "5.1.0", + "apiVersion": "5.3.0", "externalJS": null, - "dependencies": null + "dependencies": null, + "version": "1.0.0.0" } \ No newline at end of file diff --git a/templates/visuals/default/tsconfig.json b/templates/visuals/default/tsconfig.json index 1b13ad53..fb77f004 100644 --- a/templates/visuals/default/tsconfig.json +++ b/templates/visuals/default/tsconfig.json @@ -3,13 +3,13 @@ "allowJs": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "target": "es6", + "target": "es2022", "sourceMap": true, "outDir": "./.tmp/build/", "moduleResolution": "node", "declaration": true, "lib": [ - "es2015", + "es2022", "dom" ] }, diff --git a/templates/visuals/default/tslint.json b/templates/visuals/default/tslint.json deleted file mode 100644 index 9076745d..00000000 --- a/templates/visuals/default/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tslint-microsoft-contrib/recommended", - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" - ], - "rules": { - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/templates/visuals/rhtml/.eslintignore b/templates/visuals/rhtml/.eslintignore new file mode 100644 index 00000000..fc6204f9 --- /dev/null +++ b/templates/visuals/rhtml/.eslintignore @@ -0,0 +1,5 @@ +assets +style +dist +node_modules +.eslintrc.js \ No newline at end of file diff --git a/templates/visuals/rhtml/.eslintrc.js b/templates/visuals/rhtml/.eslintrc.js new file mode 100644 index 00000000..42f26710 --- /dev/null +++ b/templates/visuals/rhtml/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + "browser": true, + "es6": true, + "es2017": true + }, + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + tsconfigRootDir: ".", + }, + plugins: [ + "powerbi-visuals" + ], + extends: [ + "plugin:powerbi-visuals/recommended" + ], + rules: {} +}; \ No newline at end of file diff --git a/templates/visuals/rhtml/package.json b/templates/visuals/rhtml/package.json index a7781c32..e5895e06 100644 --- a/templates/visuals/rhtml/package.json +++ b/templates/visuals/rhtml/package.json @@ -4,16 +4,17 @@ "powerbi-visuals-utils-formattingmodel": "5.0.0" }, "devDependencies": { - "powerbi-visuals-api": "5.1.0", - "ts-loader": "6.1.0", - "tslint": "^5.18.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.3" + "powerbi-visuals-api": "5.4.0", + "ts-loader": "9.4.3", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "eslint": "^8.42.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "typescript": "5.1.3" }, "scripts": { "pbiviz": "pbiviz", "start": "pbiviz start", "package": "pbiviz package", - "lint": "tslint -c tslint.json -p tsconfig.json" + "lint": "npx eslint . --ext .js,.jsx,.ts,.tsx" } } diff --git a/templates/visuals/rhtml/pbiviz.json b/templates/visuals/rhtml/pbiviz.json index f39bf49a..46d44540 100644 --- a/templates/visuals/rhtml/pbiviz.json +++ b/templates/visuals/rhtml/pbiviz.json @@ -1,4 +1,5 @@ { "apiVersion": "5.1.0", - "externalJS": null + "externalJS": null, + "version": "1.0.0.0" } \ No newline at end of file diff --git a/templates/visuals/rhtml/tslint.json b/templates/visuals/rhtml/tslint.json deleted file mode 100644 index 9076745d..00000000 --- a/templates/visuals/rhtml/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tslint-microsoft-contrib/recommended", - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" - ], - "rules": { - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/templates/visuals/rvisual/.eslintignore b/templates/visuals/rvisual/.eslintignore new file mode 100644 index 00000000..fc6204f9 --- /dev/null +++ b/templates/visuals/rvisual/.eslintignore @@ -0,0 +1,5 @@ +assets +style +dist +node_modules +.eslintrc.js \ No newline at end of file diff --git a/templates/visuals/rvisual/.eslintrc.js b/templates/visuals/rvisual/.eslintrc.js new file mode 100644 index 00000000..42f26710 --- /dev/null +++ b/templates/visuals/rvisual/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + "browser": true, + "es6": true, + "es2017": true + }, + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + tsconfigRootDir: ".", + }, + plugins: [ + "powerbi-visuals" + ], + extends: [ + "plugin:powerbi-visuals/recommended" + ], + rules: {} +}; \ No newline at end of file diff --git a/templates/visuals/rvisual/package.json b/templates/visuals/rvisual/package.json index fe54cedf..124c47d2 100644 --- a/templates/visuals/rvisual/package.json +++ b/templates/visuals/rvisual/package.json @@ -4,10 +4,11 @@ "powerbi-visuals-utils-formattingmodel": "5.0.0" }, "devDependencies": { - "powerbi-visuals-api": "5.1.0", - "tslint": "^5.18.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.3" + "powerbi-visuals-api": "5.4.0", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "eslint": "^8.42.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "typescript": "4.9.3" }, "scripts": { "pbiviz": "pbiviz", diff --git a/templates/visuals/rvisual/tslint.json b/templates/visuals/rvisual/tslint.json deleted file mode 100644 index 9076745d..00000000 --- a/templates/visuals/rvisual/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tslint-microsoft-contrib/recommended", - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" - ], - "rules": { - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/templates/visuals/slicer/.eslintignore b/templates/visuals/slicer/.eslintignore new file mode 100644 index 00000000..fc6204f9 --- /dev/null +++ b/templates/visuals/slicer/.eslintignore @@ -0,0 +1,5 @@ +assets +style +dist +node_modules +.eslintrc.js \ No newline at end of file diff --git a/templates/visuals/slicer/.eslintrc.js b/templates/visuals/slicer/.eslintrc.js new file mode 100644 index 00000000..42f26710 --- /dev/null +++ b/templates/visuals/slicer/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + "browser": true, + "es6": true, + "es2017": true + }, + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + tsconfigRootDir: ".", + }, + plugins: [ + "powerbi-visuals" + ], + extends: [ + "plugin:powerbi-visuals/recommended" + ], + rules: {} +}; \ No newline at end of file diff --git a/templates/visuals/slicer/package.json b/templates/visuals/slicer/package.json index cb69bf01..24aaff94 100644 --- a/templates/visuals/slicer/package.json +++ b/templates/visuals/slicer/package.json @@ -4,17 +4,18 @@ "pbiviz": "pbiviz", "start": "pbiviz start", "package": "pbiviz package", - "lint": "tslint -c tslint.json -p tsconfig.json" + "lint": "npx eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { - "d3": "5.10.0", + "d3": "7.8.5", "powerbi-visuals-utils-formattingmodel": "5.0.0" }, "devDependencies": { - "@types/d3": "5.7.2", - "powerbi-visuals-api": "5.1.0", - "tslint": "^5.18.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.3" + "@types/d3": "7.4.0", + "powerbi-visuals-api": "5.4.0", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "eslint": "^8.42.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "typescript": "4.9.3" } } \ No newline at end of file diff --git a/templates/visuals/slicer/tslint.json b/templates/visuals/slicer/tslint.json deleted file mode 100644 index 9076745d..00000000 --- a/templates/visuals/slicer/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tslint-microsoft-contrib/recommended", - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" - ], - "rules": { - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/templates/visuals/table/.eslintignore b/templates/visuals/table/.eslintignore new file mode 100644 index 00000000..fc6204f9 --- /dev/null +++ b/templates/visuals/table/.eslintignore @@ -0,0 +1,5 @@ +assets +style +dist +node_modules +.eslintrc.js \ No newline at end of file diff --git a/templates/visuals/table/.eslintrc.js b/templates/visuals/table/.eslintrc.js new file mode 100644 index 00000000..42f26710 --- /dev/null +++ b/templates/visuals/table/.eslintrc.js @@ -0,0 +1,20 @@ +module.exports = { + env: { + "browser": true, + "es6": true, + "es2017": true + }, + root: true, + parser: "@typescript-eslint/parser", + parserOptions: { + project: "tsconfig.json", + tsconfigRootDir: ".", + }, + plugins: [ + "powerbi-visuals" + ], + extends: [ + "plugin:powerbi-visuals/recommended" + ], + rules: {} +}; \ No newline at end of file diff --git a/templates/visuals/table/package.json b/templates/visuals/table/package.json index 8f1116f9..cc963bb2 100644 --- a/templates/visuals/table/package.json +++ b/templates/visuals/table/package.json @@ -4,17 +4,18 @@ "pbiviz": "pbiviz", "start": "pbiviz start", "package": "pbiviz package", - "lint": "tslint -c tslint.json -p tsconfig.json" + "lint": "npx eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { - "d3": "5.10.0", + "d3": "7.8.5", "powerbi-visuals-utils-formattingmodel": "5.0.0" }, "devDependencies": { - "powerbi-visuals-api": "5.1.0", - "@types/d3": "5.7.2", - "tslint": "^5.18.0", - "tslint-microsoft-contrib": "^6.2.0", - "typescript": "3.6.3" + "powerbi-visuals-api": "5.4.0", + "@types/d3": "7.4.0", + "@typescript-eslint/eslint-plugin": "^5.59.11", + "eslint": "^8.42.0", + "eslint-plugin-powerbi-visuals": "^0.8.1", + "typescript": "4.9.3" } } \ No newline at end of file diff --git a/templates/visuals/table/tsconfig.json b/templates/visuals/table/tsconfig.json index a54e4d7a..cd199e36 100644 --- a/templates/visuals/table/tsconfig.json +++ b/templates/visuals/table/tsconfig.json @@ -15,5 +15,9 @@ }, "files": [ "./src/visual.ts" + ], + "exclude": [ + "node_modules", + "templates", ] } \ No newline at end of file diff --git a/templates/visuals/table/tslint.json b/templates/visuals/table/tslint.json deleted file mode 100644 index 9076745d..00000000 --- a/templates/visuals/table/tslint.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "tslint-microsoft-contrib/recommended", - "rulesDirectory": [ - "node_modules/tslint-microsoft-contrib" - ], - "rules": { - "no-relative-imports": false - } -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..2f7577a6 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "allowJs": false, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "declaration": false, + "sourceMap": false, + "module": "ES2022", + "moduleResolution": "node", + "target": "ES2022", + "lib": [ + "ES2022", + "dom" + ], + "outDir": "lib" + }, + "include": [ + "src/**/*.ts" + ] + } \ No newline at end of file