powerbi-visuals-tools 3.4.2 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/launch.json +18 -0
- package/Changelog.md +20 -0
- package/bin/pbiviz-package.js +0 -2
- package/bin/pbiviz-start.js +0 -2
- package/bin/pbiviz.js +2 -0
- package/config.json +1 -1
- package/lib/CertificateTools.js +5 -7
- package/lib/WebPackWrap.js +33 -66
- package/lib/webpack.config.js +1 -1
- package/package.json +2 -11
- package/templates/visuals/default/package.json +1 -4
- package/templates/visuals/default/src/visual.ts +0 -1
- package/templates/visuals/slicer/package.json +1 -5
- package/templates/visuals/slicer/src/visual.ts +0 -1
- package/templates/visuals/table/package.json +1 -5
- package/templates/visuals/table/src/visual.ts +0 -1
package/.vscode/launch.json
CHANGED
|
@@ -22,8 +22,26 @@
|
|
|
22
22
|
"name": "pbiviz-start t1",
|
|
23
23
|
"cwd": "${workspaceFolder}\\testGround\\t1",
|
|
24
24
|
"program": "${workspaceFolder}\\bin\\pbiviz.js",
|
|
25
|
+
"args": [
|
|
26
|
+
"start"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "node",
|
|
31
|
+
"request": "launch",
|
|
32
|
+
"name": "pbiviz-start t1 Linux",
|
|
33
|
+
"cwd": "${workspaceFolder}/testGround/t1",
|
|
34
|
+
"program": "${workspaceFolder}/bin/pbiviz.js",
|
|
25
35
|
"args": ["start"]
|
|
26
36
|
},
|
|
37
|
+
{
|
|
38
|
+
"type": "node",
|
|
39
|
+
"request": "launch",
|
|
40
|
+
"name": "pbiviz-package t1",
|
|
41
|
+
"cwd": "${workspaceFolder}\\testGround\\t1",
|
|
42
|
+
"program": "${workspaceFolder}\\bin\\pbiviz.js",
|
|
43
|
+
"args": ["package"]
|
|
44
|
+
},
|
|
27
45
|
{
|
|
28
46
|
"type": "node",
|
|
29
47
|
"request": "launch",
|
package/Changelog.md
CHANGED
|
@@ -2,11 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
This page contains information about changes to the PowerBI Visual Tools (pbiviz).
|
|
4
4
|
|
|
5
|
+
## 4.0.3
|
|
6
|
+
### **⚠ BREAKING CHANGES**
|
|
7
|
+
* Removed polyfills and 'Internet Explorer` browser support
|
|
8
|
+
* Removed `--target` option for `pbiviz-start` and `pbiviz-package` commands
|
|
9
|
+
|
|
10
|
+
## 4.0.2
|
|
11
|
+
* Fix custom visual package upload to desktop version of PowerBI
|
|
12
|
+
* Removed environment logging in this version
|
|
13
|
+
* Downgraded "powerbi-visuals-webpack-plugin"
|
|
14
|
+
|
|
15
|
+
## 4.0.0
|
|
16
|
+
* This release version includes changes from previous betta versions: 3.4.0, 3.4.1, 3.4.2, 3.4.3.
|
|
17
|
+
|
|
18
|
+
## 3.4.3
|
|
19
|
+
|
|
20
|
+
* Updated webpack assets compilation
|
|
21
|
+
* Added environment logging for debugging purposes
|
|
22
|
+
* Fixed certificate date verification for different regional settings
|
|
23
|
+
|
|
5
24
|
## 3.4.2
|
|
6
25
|
|
|
7
26
|
* Migrated from `request` lib to node `https` standard method
|
|
8
27
|
* Removed `friendly-errors-webpack-plugin` usage
|
|
9
28
|
* Removed or updated deprecated dependencies
|
|
29
|
+
* Fixed vulnerabilities
|
|
10
30
|
|
|
11
31
|
## 3.4.1
|
|
12
32
|
|
package/bin/pbiviz-package.js
CHANGED
|
@@ -39,7 +39,6 @@ let options = process.argv;
|
|
|
39
39
|
const minAPIversion = config.constants.minAPIversion;
|
|
40
40
|
|
|
41
41
|
program
|
|
42
|
-
.option('-t, --target [target]', 'Enable babel loader to compile JS into ES5 standart', 'es5')
|
|
43
42
|
.option('--resources', "Produces a folder containing the pbiviz resource files (js, css, json)", false)
|
|
44
43
|
.option('--no-pbiviz', "Doesn't produce a pbiviz file (must be used in conjunction with resources flag)", false)
|
|
45
44
|
.option('--no-minify', "Doesn't minify the js in the package (useful for debugging)", true)
|
|
@@ -76,7 +75,6 @@ VisualPackage.loadVisualPackage(cwd).then((visualPackage) => {
|
|
|
76
75
|
generatePbiviz: program.pbiviz,
|
|
77
76
|
minifyJS: program.minify,
|
|
78
77
|
minify: program.minify,
|
|
79
|
-
target: program.target,
|
|
80
78
|
compression: program.compression
|
|
81
79
|
}).then(({ webpackConfig }) => {
|
|
82
80
|
let compiler = webpack(webpackConfig);
|
package/bin/pbiviz-start.js
CHANGED
|
@@ -42,7 +42,6 @@ const options = process.argv;
|
|
|
42
42
|
const minAPIversion = config.constants.minAPIversion;
|
|
43
43
|
|
|
44
44
|
program
|
|
45
|
-
.option('-t, --target [target]', 'Enable babel loader to compile JS into ES5 standart')
|
|
46
45
|
.option('-p, --port [port]', 'set the port listening on')
|
|
47
46
|
.option('-m, --mute', 'mute error outputs')
|
|
48
47
|
.option('-d, --drop', 'drop outputs into output folder');
|
|
@@ -71,7 +70,6 @@ VisualPackage.loadVisualPackage(cwd).then((visualPackage) => {
|
|
|
71
70
|
generatePbiviz: false,
|
|
72
71
|
minifyJS: false,
|
|
73
72
|
minify: false,
|
|
74
|
-
target: typeof program.target === 'undefined' ? "es5" : program.target,
|
|
75
73
|
devServerPort: program.port
|
|
76
74
|
})
|
|
77
75
|
.then(({ webpackConfig }) => {
|
package/bin/pbiviz.js
CHANGED
|
@@ -35,6 +35,8 @@ let config = require(confPath);
|
|
|
35
35
|
let args = process.argv;
|
|
36
36
|
let CertificateTools = require("../lib/CertificateTools");
|
|
37
37
|
|
|
38
|
+
ConsoleWriter.info(`${npmPackage.name} version - ${npmPackage.version}`);
|
|
39
|
+
|
|
38
40
|
program
|
|
39
41
|
.version(npmPackage.version)
|
|
40
42
|
.command('new [name]', 'Create a new visual')
|
package/config.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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","passphrase":"
|
|
1
|
+
{"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","passphrase":"9982422364989703"},"visualTemplates":{"circlecard":"https://codeload.github.com/microsoft/powerbi-visuals-circlecard-react/zip/master"}}
|
package/lib/CertificateTools.js
CHANGED
|
@@ -56,7 +56,7 @@ async function createCertFile(config, open) {
|
|
|
56
56
|
const subject = "localhost";
|
|
57
57
|
const keyLength = 2048;
|
|
58
58
|
const algorithm = "sha256";
|
|
59
|
-
const validPeriod =
|
|
59
|
+
const validPeriod = 365;
|
|
60
60
|
|
|
61
61
|
if (typeof open === 'undefined') {
|
|
62
62
|
open = false;
|
|
@@ -389,10 +389,8 @@ async function veryfyCertFile(keyPath, certPath, pfxPath, passphrase) {
|
|
|
389
389
|
if (!fs.existsSync(pfxPath) || !passphrase) {
|
|
390
390
|
return false;
|
|
391
391
|
}
|
|
392
|
-
let certStr = await exec(`
|
|
393
|
-
|
|
394
|
-
let regex = /(?<=: ).*/;
|
|
395
|
-
endDateStr = regex.exec(certStrSplitted[6]);
|
|
392
|
+
let certStr = await exec(`powershell.exe (New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('${pfxPath}','${passphrase}')).NotAfter.ToString('yyyy-MM-dd HH:mm:ss')`);
|
|
393
|
+
endDateStr = certStr.trim();
|
|
396
394
|
}
|
|
397
395
|
// For Linux and Mac/darwin OS:
|
|
398
396
|
else if (os.platform() === "linux" || os.platform() === "darwin") {
|
|
@@ -402,8 +400,8 @@ async function veryfyCertFile(keyPath, certPath, pfxPath, passphrase) {
|
|
|
402
400
|
endDateStr = await exec(`openssl x509 -enddate -noout -in ${certPath} | cut -d = -f 2`);
|
|
403
401
|
}
|
|
404
402
|
|
|
405
|
-
let endDate =
|
|
406
|
-
verifyCertDate = (endDate -
|
|
403
|
+
let endDate = Date.parse(endDateStr);
|
|
404
|
+
verifyCertDate = (endDate - Date.now()) > certSafePeriod;
|
|
407
405
|
if (verifyCertDate) {
|
|
408
406
|
ConsoleWriter.info(`Certificate is valid.`);
|
|
409
407
|
} else {
|
package/lib/WebPackWrap.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
const path = require('path');
|
|
5
6
|
const webpack = require('webpack');
|
|
6
7
|
const config = require('../config.json');
|
|
@@ -14,6 +15,7 @@ const exec = util.promisify(require('child_process').exec);
|
|
|
14
15
|
const CertificateTools = require("../lib/CertificateTools");
|
|
15
16
|
const visualPlugin = "visualPlugin.ts";
|
|
16
17
|
const lodashCloneDeep = require('lodash.clonedeep');
|
|
18
|
+
const npmPackage = require('../package.json');
|
|
17
19
|
|
|
18
20
|
class WebPackGenerator {
|
|
19
21
|
|
|
@@ -80,11 +82,14 @@ class WebPackGenerator {
|
|
|
80
82
|
directory: path.join(visualPackage.basePath, config.build.dropFolder),
|
|
81
83
|
publicPath: config.server.assetsRoute
|
|
82
84
|
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
server: {
|
|
86
|
+
type: 'https',
|
|
87
|
+
options: {
|
|
88
|
+
key: options.key,
|
|
89
|
+
cert: options.cert,
|
|
90
|
+
pfx: options.pfx,
|
|
91
|
+
passphrase: options.passphrase
|
|
92
|
+
}
|
|
88
93
|
}
|
|
89
94
|
};
|
|
90
95
|
}
|
|
@@ -108,6 +113,16 @@ class WebPackGenerator {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
|
|
116
|
+
async getEnvironmentDetails() {
|
|
117
|
+
let env = {};
|
|
118
|
+
env.nodeVersion = process.versions.node;
|
|
119
|
+
env.osPlatform = await os.platform();
|
|
120
|
+
env.osVersion = await os.version ? os.version() : "undefined";
|
|
121
|
+
env.osReleaseVersion = await os.release();
|
|
122
|
+
env.toolsVersion = npmPackage.version;
|
|
123
|
+
return env;
|
|
124
|
+
}
|
|
125
|
+
|
|
111
126
|
async configureCustomVisualsWebpackPlugin(visualPackage, options, tsconfig) {
|
|
112
127
|
let pluginConfiguration = lodashCloneDeep(visualPackage.config);
|
|
113
128
|
//(?=\D*$) - positive look-ahead to find last version symbols and exclude any non-digit symbols after the version.
|
|
@@ -127,6 +142,8 @@ class WebPackGenerator {
|
|
|
127
142
|
await this.installAPIpackage();
|
|
128
143
|
}
|
|
129
144
|
|
|
145
|
+
// pluginConfiguration.env = await this.getEnvironmentDetails();
|
|
146
|
+
|
|
130
147
|
let api = WebPackGenerator.loadAPIPackage(visualPackage);
|
|
131
148
|
pluginConfiguration.apiVersion = api.version;
|
|
132
149
|
pluginConfiguration.capabilitiesSchema = api.schemas.capabilities;
|
|
@@ -179,13 +196,12 @@ class WebPackGenerator {
|
|
|
179
196
|
new webpack.SourceMapDevToolPlugin({
|
|
180
197
|
filename: '[file].map',
|
|
181
198
|
publicPath: `https://localhost:${this.webpackConfig.devServer.port}/assets/`
|
|
182
|
-
|
|
199
|
+
})
|
|
183
200
|
);
|
|
184
201
|
}
|
|
185
202
|
}
|
|
186
203
|
|
|
187
|
-
|
|
188
|
-
target = "es5",
|
|
204
|
+
useLoader({
|
|
189
205
|
fast = false
|
|
190
206
|
}) {
|
|
191
207
|
let tsOptions = {};
|
|
@@ -195,62 +211,15 @@ class WebPackGenerator {
|
|
|
195
211
|
experimentalWatchApi: false
|
|
196
212
|
};
|
|
197
213
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
[
|
|
202
|
-
require.resolve('@babel/preset-env'),
|
|
203
|
-
{
|
|
204
|
-
"targets": {
|
|
205
|
-
"ie": "11"
|
|
206
|
-
},
|
|
207
|
-
useBuiltIns: "entry",
|
|
208
|
-
corejs: 3,
|
|
209
|
-
modules: false
|
|
210
|
-
}
|
|
211
|
-
]
|
|
212
|
-
],
|
|
213
|
-
plugins: [require.resolve("@babel/plugin-syntax-dynamic-import")],
|
|
214
|
-
sourceType: "unambiguous",
|
|
215
|
-
cacheDirectory: path.join(config.build.precompileFolder, "babelCache")
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
this.webpackConfig.module.rules.push({
|
|
219
|
-
test: /(\.ts)x|\.ts$/,
|
|
220
|
-
include: /powerbi-visuals-|src|precompile[/\\]visualPlugin.ts/,
|
|
221
|
-
exclude: [/core-js/],
|
|
222
|
-
use: [
|
|
223
|
-
{
|
|
224
|
-
loader: require.resolve('babel-loader'),
|
|
225
|
-
options: babelOptions
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
loader: require.resolve('ts-loader'),
|
|
229
|
-
options: tsOptions
|
|
230
|
-
}
|
|
231
|
-
]
|
|
232
|
-
},
|
|
214
|
+
this.webpackConfig.module.rules.push({
|
|
215
|
+
test: /(\.ts)x?$/,
|
|
216
|
+
use: [
|
|
233
217
|
{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
options: babelOptions
|
|
240
|
-
}
|
|
241
|
-
]
|
|
242
|
-
});
|
|
243
|
-
} else {
|
|
244
|
-
this.webpackConfig.module.rules.push({
|
|
245
|
-
test: /(\.ts)x?$/,
|
|
246
|
-
use: [
|
|
247
|
-
{
|
|
248
|
-
loader: require.resolve('ts-loader'),
|
|
249
|
-
options: tsOptions
|
|
250
|
-
}
|
|
251
|
-
]
|
|
252
|
-
});
|
|
253
|
-
}
|
|
218
|
+
loader: require.resolve('ts-loader'),
|
|
219
|
+
options: tsOptions
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
});
|
|
254
223
|
}
|
|
255
224
|
|
|
256
225
|
async prepareWebPackConfig(visualPackage, options, tsconfig) {
|
|
@@ -266,8 +235,7 @@ class WebPackGenerator {
|
|
|
266
235
|
await this.appendPlugins(options, visualPackage, tsconfig);
|
|
267
236
|
await this.configureDevServer(visualPackage, options.devServerPort);
|
|
268
237
|
await this.configureVisualPlugin(options, tsconfig, visualPackage);
|
|
269
|
-
this.
|
|
270
|
-
target: options.target,
|
|
238
|
+
this.useLoader({
|
|
271
239
|
fast: options.fast
|
|
272
240
|
});
|
|
273
241
|
|
|
@@ -292,7 +260,6 @@ class WebPackGenerator {
|
|
|
292
260
|
generatePbiviz: false,
|
|
293
261
|
minifyJS: true,
|
|
294
262
|
minify: true,
|
|
295
|
-
target: "es5",
|
|
296
263
|
devServerPort: 8080,
|
|
297
264
|
fast: false,
|
|
298
265
|
compression: 0
|
package/lib/webpack.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "powerbi-visuals-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "Command line tool for creating and publishing visuals for Power BI",
|
|
5
5
|
"main": "./lib/VisualPackage.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,24 +26,16 @@
|
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/Microsoft/PowerBI-visuals-tools#readme",
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@babel/core": "7.9.0",
|
|
30
|
-
"@babel/plugin-syntax-dynamic-import": "7.8.3",
|
|
31
|
-
"@babel/preset-env": "7.9.0",
|
|
32
|
-
"@babel/runtime": "7.9.2",
|
|
33
|
-
"@babel/runtime-corejs3": "7.9.2",
|
|
34
29
|
"assert": "^2.0.0",
|
|
35
30
|
"async": "3.2.0",
|
|
36
|
-
"babel-loader": "^8.1.0",
|
|
37
31
|
"base64-inline-loader": "^2.0.1",
|
|
38
32
|
"browserify-zlib": "^0.2.0",
|
|
39
33
|
"buffer": "^6.0.3",
|
|
40
34
|
"chalk": "3.0.0",
|
|
41
35
|
"commander": "4.1.1",
|
|
42
36
|
"compare-versions": "^3.6.0",
|
|
43
|
-
"connect": "3.7.0",
|
|
44
37
|
"console-browserify": "^1.2.0",
|
|
45
38
|
"constants-browserify": "^1.0.0",
|
|
46
|
-
"core-js": "^3.18.1",
|
|
47
39
|
"crypto-browserify": "^3.12.0",
|
|
48
40
|
"css-loader": "^5.2.7",
|
|
49
41
|
"domain-browser": "^4.22.0",
|
|
@@ -66,7 +58,6 @@
|
|
|
66
58
|
"punycode": "^2.1.1",
|
|
67
59
|
"querystring-es3": "^0.2.1",
|
|
68
60
|
"readable-stream": "^3.6.0",
|
|
69
|
-
"serve-static": "1.14.1",
|
|
70
61
|
"stream-browserify": "^3.0.0",
|
|
71
62
|
"stream-http": "^3.2.0",
|
|
72
63
|
"string_decoder": "^1.3.0",
|
|
@@ -83,7 +74,7 @@
|
|
|
83
74
|
"webpack-dev-server": "^4.1.0"
|
|
84
75
|
},
|
|
85
76
|
"devDependencies": {
|
|
86
|
-
"eslint": "
|
|
77
|
+
"eslint": "^7.31.0",
|
|
87
78
|
"jasmine": "3.5.0",
|
|
88
79
|
"jasmine-spec-reporter": "5.0.1",
|
|
89
80
|
"semver": "7.1.3",
|
|
@@ -13,13 +13,10 @@
|
|
|
13
13
|
"lint": "tslint -c tslint.json -p tsconfig.json"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@babel/runtime": "7.6.0",
|
|
17
|
-
"@babel/runtime-corejs2": "7.6.0",
|
|
18
16
|
"@types/d3": "5.7.2",
|
|
19
17
|
"d3": "5.12.0",
|
|
20
18
|
"powerbi-visuals-utils-dataviewutils": "2.2.1",
|
|
21
|
-
"powerbi-visuals-api": "~3.8.0"
|
|
22
|
-
"core-js": "^3.18.1"
|
|
19
|
+
"powerbi-visuals-api": "~3.8.0"
|
|
23
20
|
},
|
|
24
21
|
"devDependencies": {
|
|
25
22
|
"ts-loader": "6.1.0",
|
|
@@ -8,13 +8,9 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"d3": "5.10.0",
|
|
11
|
-
"powerbi-visuals-utils-dataviewutils": "^2.2.1"
|
|
12
|
-
"core-js": "3.18.1"
|
|
11
|
+
"powerbi-visuals-utils-dataviewutils": "^2.2.1"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
|
-
"@babel/polyfill": "^7.4.4",
|
|
16
|
-
"@babel/runtime": "^7.5.5",
|
|
17
|
-
"@babel/runtime-corejs2": "^7.5.5",
|
|
18
14
|
"@types/d3": "5.7.2",
|
|
19
15
|
"powerbi-visuals-api": "~3.8.0",
|
|
20
16
|
"tslint": "^5.18.0",
|
|
@@ -8,14 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"d3": "5.10.0",
|
|
11
|
-
"powerbi-visuals-utils-dataviewutils": "^2.2.1"
|
|
12
|
-
"core-js": "^3.18.1"
|
|
11
|
+
"powerbi-visuals-utils-dataviewutils": "^2.2.1"
|
|
13
12
|
},
|
|
14
13
|
"devDependencies": {
|
|
15
14
|
"powerbi-visuals-api": "~3.8.0",
|
|
16
|
-
"@babel/polyfill": "^7.4.4",
|
|
17
|
-
"@babel/runtime": "^7.5.5",
|
|
18
|
-
"@babel/runtime-corejs2": "^7.5.5",
|
|
19
15
|
"@types/d3": "5.7.2",
|
|
20
16
|
"tslint": "^5.18.0",
|
|
21
17
|
"tslint-microsoft-contrib": "^6.2.0",
|