Pipeline and packaging updates (#538)

* Added release ADO pipeline with software manifest generation
* Added static analysis pipeline
* Package vulernability updates
* Simulator updates - always send content encoding and type
* Moved webview external dependencies to webpack bundles
This commit is contained in:
Ryan K 2022-03-30 10:36:05 -07:00 коммит произвёл GitHub
Родитель 6763ff2658
Коммит 1749746501
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
31 изменённых файлов: 3419 добавлений и 5514 удалений

Просмотреть файл

@ -0,0 +1,37 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Required for schedule only trigger
trigger: none
pr: none
# Run weekly at midnight Sunday (Pacific).
schedules:
- cron: "0 8 * * 0"
displayName: 'Weekly Static Analysis'
branches:
include:
- main
variables:
LGTM.UploadSnapshot: true
Semmle.SkipAnalysis: true
stages:
- stage: 'staticAnalysis'
displayName: 'Static Analysis'
jobs:
- job: 'codeQL'
displayName: 'Execute CodeQL Analysis'
pool:
vmImage: 'windows-2019'
steps:
- task: Semmle@1
inputs:
sourceCodeDirectory: '$(Build.SourcesDirectory)'
language: 'tsandjs'
querySuite: 'Recommended'
timeout: '1800'
ram: '16384'
addProjectDirToScanningExclusionList: true
env:
System_AccessToken: $(System.AccessToken)

Просмотреть файл

@ -0,0 +1,5 @@
steps:
# Typescript Compile
- script: |
npm run compile
displayName: 'Typescript compile'

Просмотреть файл

@ -0,0 +1,39 @@
parameters:
- name: productionRelease
displayName: 'Build package for a production release (non-preview)'
type: boolean
default: false
steps:
- script: |
npm install -g vsce
displayName: 'Install VSCE tool'
- ${{ if eq(parameters.productionRelease, false) }}:
- script: |
vsce package --pre-release
displayName: 'Build pre-release VSIX Package'
- ${{ if eq(parameters.productionRelease, true) }}:
- script: |
vsce package
displayName: 'Build VSIX Package'
- task: CopyFiles@2
displayName: 'Copy VSIX to artifact staging'
inputs:
SourceFolder: '$(System.DefaultWorkingDirectory)'
Contents: '**/*.vsix'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
displayName: 'Generate software manifest'
inputs:
BuildDropPath: '$(Build.ArtifactStagingDirectory)'
- task: PublishPipelineArtifact@1
displayName: 'Publish build artifacts'
inputs:
targetPath: '$(Build.ArtifactStagingDirectory)'
artifactType: 'pipeline'
artifactName: vscode-azure-iot-toolkit

Просмотреть файл

@ -0,0 +1,30 @@
steps:
# cred scan
- task: CredScan@3
displayName: 'Run CredScan'
inputs:
outputFormat: 'pre'
scanFolder: '$(Build.SourcesDirectory)'
# poli check
- task: securedevelopmentteam.vss-secure-development-tools.build-task-policheck.PoliCheck@1
displayName: 'Run PoliCheck'
inputs:
targetType: F
- task: PostAnalysis@1
inputs:
AllTools: false
APIScan: false
BinSkim: false
CodesignValidation: false
CredScan: true
FortifySCA: false
FxCop: false
ModernCop: false
PoliCheck: true
RoslynAnalyzers: false
SDLNativeRules: false
Semmle: false
TSLint: false
ToolLogsNotFoundAction: 'Standard'

Просмотреть файл

@ -0,0 +1,10 @@
steps:
# install nodejs
- task: NodeTool@0
inputs:
versionSpec: '14.x'
displayName: 'Install Node.js'
# Install dependencies and run tslint and test
- script: |
npm ci
displayName: 'Install dependencies'

Просмотреть файл

@ -0,0 +1,13 @@
steps:
- script: |
npm run tslint
displayName: 'TSLint'
# Inits a virtualized x-server instance for running extension tests on headless linux
- bash: |
xvfb-run -a npm test
displayName: 'Run Tests (Linux)'
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
- script: |
npm test
displayName: 'Run Tests'
condition: and(succeeded(), ne(variables['Agent.OS'], 'Linux'))

136
.azure-devops/release.yml Normal file
Просмотреть файл

@ -0,0 +1,136 @@
# Manual trigger only
trigger: none
pr: none
parameters:
- name: buildAgentPoolVar
displayName: 'Build agent pool'
type: string
default: 'BuildAgentPool'
- name: buildAgentVmImageVar
displayName: 'Build agent image'
type: string
default: 'BuildAgentImage'
- name: aiKeyVar
displayName: 'AI Key Variable'
type: string
default: 'TestAIKey'
- name: publishExt
displayName: 'Publish to Marketplace'
type: boolean
default: false
- name: productionRelease
displayName: 'Publish to marketplace as public (non-preview)'
type: boolean
default: false
variables:
- name: vmImage
value: $[variables.${{ parameters.buildAgentVmImageVar }}]
- name: buildPool
value: $[variables.${{ parameters.buildAgentPoolVar }}]
- name: aiKey
value: $[variables.${{ parameters.aiKeyVar }}]
stages:
- stage: test
jobs:
- job: test
strategy:
matrix:
linux:
imageName: 'ubuntu-latest'
mac:
imageName: 'macos-latest'
windows:
imageName: 'windows-latest'
pool:
vmImage: $(imageName)
steps:
- template: common/setup_steps.yml
- template: common/test_steps.yml
- stage: build
dependsOn: [test]
jobs:
- job: SDLTools
displayName: 'SDL checks'
pool:
vmImage: windows-latest
steps:
- template: common/sdl_steps.yml
- job: build_and_package
displayName: 'Build and Publish Artifacts'
pool:
name: $(buildPool)
vmImage: $(vmImage)
demands:
- ImageOverride -equals $(vmImage)
dependsOn: SDLTools
steps:
- template: common/setup_steps.yml
- template: common/compile_steps.yml
# modify application insights key for releases only
- script: |
node scripts/modifyPackageJson.js aiKey $(aiKey)
displayName: 'Inject App Insights key'
condition: and(succeeded(), ${{ parameters.publishExt }})
- template: common/package_steps.yml
parameters:
productionRelease: ${{ eq(parameters.productionRelease, true) }}
- stage: release
displayName: 'Release to VS Marketplace'
dependsOn: [test, build]
condition: and(succeeded(), ${{ parameters.publishExt }})
pool:
name: $(buildPool)
vmImage: $(vmImage)
demands:
- ImageOverride -equals $(vmImage)
jobs:
- deployment: 'StageRelease'
displayName: 'Stage Release for deployment'
environment: 'production'
- job: 'release'
displayName: 'Release package'
steps:
- task: DownloadPipelineArtifact@2
displayName : 'Download VSIX Build Artifacts'
inputs:
source: 'current'
artifact: 'vscode-azure-iot-toolkit'
path: '$(System.ArtifactsDirectory)/vsix'
# install Node
- task: NodeTool@0
inputs:
versionSpec: '14.x'
displayName: 'Install Node.js'
- script: |
npm install -g vsce
displayName: 'Install VSCE tool'
# publish pre-release vsix to marketplace
- bash: |
vsce publish -p $MARKETPLACE_TOKEN --packagePath *.vsix --pre-release
workingDirectory: '$(System.ArtifactsDirectory)/vsix'
displayName: 'Deploy pre-release VSIX to marketplace'
condition: and(succeeded(), not(${{ parameters.productionRelease }}))
env:
MARKETPLACE_TOKEN: $(vsciot_marketplace_token)
# publish vsix to marketplace
- bash: |
vsce publish -p $MARKETPLACE_TOKEN --packagePath *.vsix
workingDirectory: '$(System.ArtifactsDirectory)/vsix'
displayName: 'Deploy release VSIX to marketplace'
condition: and(succeeded(), ${{ parameters.productionRelease }})
env:
MARKETPLACE_TOKEN: $(vsciot_marketplace_token)

12
.github/workflows/build-test.yml поставляемый
Просмотреть файл

@ -20,7 +20,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
node-version: [12.x] node-version: [14.x]
# Steps represent a sequence of tasks that will be executed as part of the job # Steps represent a sequence of tasks that will be executed as part of the job
steps: steps:
@ -40,7 +40,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
node-version: [12.x] node-version: [14.x]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-node@v2.1.4 - uses: actions/setup-node@v2.1.4
@ -53,11 +53,3 @@ jobs:
if: runner.os == 'Linux' if: runner.os == 'Linux'
- run: npm test - run: npm test
if: runner.os != 'Linux' if: runner.os != 'Linux'
- name: Set up Ruby 2.6
uses: actions/setup-ruby@v1
with:
ruby-version: 2.6.x
- name: Check links with awesome_bot
run: |
gem install awesome_bot
awesome_bot --allow-dupe --allow-redirect --skip-save-results `ls *.md` --white-list gitter.im

5
.gitignore поставляемый
Просмотреть файл

@ -2,4 +2,7 @@ out
node_modules node_modules
npm-debug.log npm-debug.log
dist dist
.vscode-test .vscode-test
# output of simulator bundling
resources/simulator/scripts/**/*
resources/welcome/scripts/**/*

Просмотреть файл

@ -1,3 +1,8 @@
## 2.16.7 (2022-03-23)
### Changed
* Changed D2C messages to always declare message content-type as `application/json` and encoding as `utf-8`
* Updated package vulnerabilities
## 2.16.6 (2021-01-26) ## 2.16.6 (2021-01-26)
### Changed ### Changed
* Updated package vulnerabilities * Updated package vulnerabilities

Просмотреть файл

@ -1,19 +0,0 @@
Copyright (c) 2017 Matt Sweetman
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.

Просмотреть файл

@ -1,62 +0,0 @@
// Copyright (c) 2017 Matt Sweetman
// 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.
var Handlebars = require('handlebars');
var fecha = require('fecha');
var numbro = require('numbro');
var mockdata = require('./lib/mockdata');
var helpers = require('./lib/helpers');
var utils = require('./lib/utils');
var dummyjson = {
// Global seed for the random number generator
seed: null,
parse: function (string, options) {
options = options || {};
// Merge custom mockdata/helpers into the defaults, items with the same name will override
options.mockdata = Handlebars.Utils.extend({}, mockdata, options.mockdata);
options.helpers = Handlebars.Utils.extend({}, helpers, options.helpers);
// If a seed is passed in the options it will override the default one
utils.setRandomSeed(options.seed || dummyjson.seed);
// Certain helpers, such as name and email, attempt to synchronise and use the same values when
// called after one-another. This object acts as a cache so the helpers can share their values.
options.mockdata.__cache = {};
return Handlebars.compile(string)(options.mockdata, {
helpers: options.helpers,
partials: options.partials
});
},
// Expose the built-in modules so people can use them in their own helpers
mockdata: mockdata,
helpers: helpers,
utils: utils,
// Also expose the number and date formatters so people can modify their settings
fecha: fecha,
numbro: numbro
};
module.exports = dummyjson;

Просмотреть файл

@ -1,472 +0,0 @@
// Copyright (c) 2017 Matt Sweetman
// 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.
var os = require('os');
var Handlebars = require('handlebars');
var numbro = require('numbro');
var fecha = require('fecha');
var utils = require('./utils');
// Generating int and floats is very similar so we route both to this single function
function getNumber (type, min, max, format, options) {
var ret;
// Juggle the arguments if the user didn't supply a format string
if (!options) {
options = format;
format = null;
}
if (type === 'int') {
ret = utils.randomInt(min, max);
} else if (type === 'float') {
ret = utils.randomFloat(min, max);
}
if (typeof options.hash.round === 'number') {
ret = Math.round(ret / options.hash.round) * options.hash.round;
}
if (format) {
ret = numbro(ret).format(format);
}
return ret;
}
// Generating time and dates is very similar so we route both to this single function
function getDate (type, min, max, format, options) {
var ret;
// Juggle the arguments if the user didn't supply a format string
if (!options) {
options = format;
format = null;
}
if (type === 'date') {
min = Date.parse(min);
max = Date.parse(max);
} else if (type === 'time') {
min = Date.parse('1970-01-01T' + min);
max = Date.parse('1970-01-01T' + max);
}
ret = utils.randomDate(min, max);
if (format === 'unix') {
// We need to undo the timezone offset fix from utils.randomDate()
ret = Math.floor((ret.getTime() - ret.getTimezoneOffset() * 60000) / 1000);
} else if (format) {
ret = fecha.format(ret, format);
} else if (type === 'time') {
// Time has a default format if one is not specified
ret = fecha.format(ret, 'HH:mm');
}
return ret;
}
function getFirstName (options) {
// The value is cached so that other helpers can use it.
// Each helper is allowed to use the cached value just once.
var cache = options.data.root.__cache;
var ret = utils.randomArrayItem(options.data.root.firstNames);
cache.firstName = ret;
cache.username_firstName = ret;
cache.email_firstName = ret;
return ret;
}
function getLastName (options) {
// The value is cached so that other helpers can use it.
// Each helper is allowed to use the cached value just once.
var cache = options.data.root.__cache;
var ret = utils.randomArrayItem(options.data.root.lastNames);
cache.lastName = ret;
cache.username_lastName = ret;
cache.email_lastName = ret;
return ret;
}
function getCompany (options) {
// The value is cached so that other helpers can use it.
// Each helper is allowed to use the cached value just once.
var cache = options.data.root.__cache;
var ret = utils.randomArrayItem(options.data.root.companies);
cache.company = ret;
cache.domain_company = ret;
cache.email_company = ret;
return ret;
}
function getTld (options) {
// The value is cached so that other helpers can use it.
// Each helper is allowed to use the cached value just once.
var cache = options.data.root.__cache;
var tld = utils.randomArrayItem(options.data.root.tlds);
cache.tld = tld;
cache.domain_tld = tld;
cache.email_tld = tld;
return tld;
}
var helpers = {
repeat: function (min, max, options) {
var ret = '';
var total = 0;
var data;
var i;
if (arguments.length === 3) {
// If given two numbers then pick a random one between the two
total = utils.randomInt(min, max);
} else if (arguments.length === 2) {
// If given one number then just use it as a fixed repeat total
options = max;
total = min;
} else {
throw new Error('The repeat helper requires a numeric param');
}
// Create a shallow copy of data so we can add variables without modifying the original
data = Handlebars.Utils.extend({}, options.data);
for (i = 0; i < total; i++) {
// Clear the linked values on each iteration so a new set of names/companies is generated
options.data.root.__cache = {};
// You can access these in your template using @index, @total, @first, @last
data.index = i;
data.total = total;
data.first = i === 0;
data.last = i === total - 1;
// By using 'this' as the context the repeat block will inherit the current scope
ret = ret + options.fn(this, {data: data});
if (options.hash.comma !== false) {
// Trim any whitespace left by handlebars and add a comma if it doesn't already exist,
// also trim any trailing commas that might be at the end of the loop
ret = ret.trimRight();
if (i < total - 1 && ret.charAt(ret.length - 1) !== ',') {
ret += ',';
} else if (i === total - 1 && ret.charAt(ret.length - 1) === ',') {
ret = ret.slice(0, -1);
}
ret += os.EOL;
}
}
return ret;
},
int: function (min, max, format, options) {
if (arguments.length !== 3 && arguments.length !== 4) {
throw new Error('The int helper requires two numeric params');
}
return getNumber('int', min, max, format, options);
},
float: function (min, max, format, options) {
if (arguments.length !== 3 && arguments.length !== 4) {
throw new Error('The float helper requires two numeric params');
}
return getNumber('float', min, max, format, options);
},
boolean: function () {
return utils.randomBoolean().toString();
},
date: function (min, max, format, options) {
if (arguments.length !== 3 && arguments.length !== 4) {
throw new Error('The date helper requires two string params');
}
return getDate('date', min, max, format, options);
},
time: function (min, max, format, options) {
if (arguments.length !== 3 && arguments.length !== 4) {
throw new Error('The time helper requires two string params');
}
return getDate('time', min, max, format, options);
},
title: function (options) {
return utils.randomArrayItem(options.data.root.titles);
},
firstName: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var ret = cache.firstName || getFirstName(options);
// The cached values are cleared so they can't be used again
cache.firstName = null;
return ret;
},
lastName: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var ret = cache.lastName || getLastName(options);
// The cached values are cleared so they can't be used again
cache.lastName = null;
return ret;
},
username: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var first = cache.username_firstName || getFirstName(options);
var last = cache.username_lastName || getLastName(options);
// The cached values are cleared so they can't be used again
cache.username_firstName = null;
cache.username_lastName = null;
return first.substr(0, 1).toLowerCase() + last.toLowerCase();
},
company: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var company = cache.company || getCompany(options);
// The cached values are cleared so they can't be used again
cache.company = null;
return company;
},
tld: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var tld = cache.tld || getTld(options);
// The cached values are cleared so they can't be used again
cache.tld = null;
return tld;
},
domain: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var company = cache.domain_company || getCompany(options);
var tld = cache.domain_tld || getTld(options);
// The cached values are cleared so they can't be used again
cache.domain_company = null;
cache.domain_tld = null;
return company.toLowerCase() + '.' + tld;
},
email: function (options) {
// Try to use the cached values first, otherwise generate a new value
var cache = options.data.root.__cache;
var first = cache.email_firstName || getFirstName(options);
var last = cache.email_lastName || getLastName(options);
var company = cache.email_company || getCompany(options);
var tld = cache.email_tld || getTld(options);
// The cached values are cleared so they can't be used again
cache.email_firstName = null;
cache.email_lastName = null;
cache.email_company = null;
cache.email_tld = null;
return first.toLowerCase() + '.' + last.toLowerCase() +
'@' + company.toLowerCase() + '.' + tld;
},
street: function (options) {
return utils.randomArrayItem(options.data.root.streets);
},
city: function (options) {
return utils.randomArrayItem(options.data.root.cities);
},
country: function (options) {
var ret;
var rootData = options.data.root;
var cache = rootData.__cache;
// Try to use the cached values first, otherwise generate a new value
if (cache.country) {
ret = cache.country;
} else {
var pos = utils.randomInt(0, rootData.countries.length - 1);
ret = rootData.countries[pos];
cache.countryCode = rootData.countryCodes[pos];
}
// The cached values are cleared so they can't be used again
cache.country = null;
return ret;
},
countryCode: function (options) {
var ret;
var rootData = options.data.root;
var cache = rootData.__cache;
// Try to use the cached values first, otherwise generate a new value
if (cache.countryCode) {
ret = cache.countryCode;
} else {
var pos = utils.randomInt(0, rootData.countries.length - 1);
ret = rootData.countryCodes[pos];
cache.country = rootData.countries[pos];
}
// The cached values are cleared so they can't be used again
cache.countryCode = null;
return ret;
},
zipcode: function () {
return ('0' + utils.randomInt(1000, 99999).toString()).slice(-5);
},
postcode: function () {
return utils.randomChar() + utils.randomChar() + utils.randomInt(0, 9) + ' ' +
utils.randomInt(0, 9) + utils.randomChar() + utils.randomChar();
},
lat: function (options) {
return getNumber('float', -90, 90, '0.000000', options);
},
long: function (options) {
return getNumber('float', -180, 180, '0.000000', options);
},
phone: function (format) {
// Provide a default format if one is not given
format = (typeof format === 'string') ? format : 'xxx-xxx-xxxx';
return format.replace(/x/g, function () {
return utils.randomInt(0, 9);
});
},
guid: function () {
var ret = '';
var i = 0;
var mask = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
var c, r, v;
while (i++ < 36) {
c = mask[i - 1];
r = utils.random() * 16 | 0;
v = (c === 'x') ? r : (r & 0x3 | 0x8);
ret += (c === '-' || c === '4') ? c : v.toString(16);
}
return ret;
},
ipv4: function () {
return utils.randomInt(1, 255) + '.' + utils.randomInt(0, 255) + '.' +
utils.randomInt(0, 255) + '.' + utils.randomInt(0, 255);
},
ipv6: function () {
return utils.randomInt(1, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16) + ':' +
utils.randomInt(0, 0xffff).toString(16);
},
color: function (options) {
return utils.randomArrayItem(options.data.root.colors);
},
hexColor: function (options) {
var r = utils.randomInt(0, 0xff);
var g = utils.randomInt(0, 0xff);
var b = utils.randomInt(0, 0xff);
if (options.hash.websafe === true) {
r = Math.round(r / 0x33) * 0x33;
g = Math.round(g / 0x33) * 0x33;
b = Math.round(b / 0x33) * 0x33;
}
// Ensure that single digit values are padded with leading zeros
return '#' +
('0' + r.toString(16)).slice(-2) +
('0' + g.toString(16)).slice(-2) +
('0' + b.toString(16)).slice(-2);
},
lorem: function (totalWords, options) {
var ret = '';
var i, word;
var isNewSentence = true;
var lastPunctuationIndex = 0;
// Juggle the arguments if totalWords wasn't provided
if (!options) {
options = totalWords;
totalWords = 25;
}
for (i = 0; i < totalWords; i++) {
word = utils.randomArrayItem(options.data.root.lorem);
// If the last iteration triggered a new sentence then capitalize the first letter
if (isNewSentence) {
word = word.charAt(0).toUpperCase() + word.slice(1);
isNewSentence = false;
}
// Only introduce new punctuation if we're more then 3 words away from the end,
// and more than 3 words since the last punctuation, and a 1 in 3 chance.
if (i < totalWords - 3 && i - lastPunctuationIndex > 3 && utils.random() < 0.3) {
isNewSentence = utils.random() < 0.6;
word = word + (isNewSentence ? '.' : ',');
lastPunctuationIndex = i;
}
ret = ret + word + ' ';
}
// Add a period/full-stop at the very end
ret = ret.trimRight() + '.';
return ret;
},
lowercase: function (value) {
return value.toLowerCase();
},
uppercase: function (value) {
return value.toUpperCase();
}
};
module.exports = helpers;

Просмотреть файл

@ -1,229 +0,0 @@
// Copyright (c) 2017 Matt Sweetman
// 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.
var titles = [
'Mr', 'Mrs', 'Dr', 'Prof', 'Lord', 'Lady', 'Sir', 'Madam'
];
var firstNames = [
'Leanne', 'Edward', 'Haydee', 'Lyle', 'Shea', 'Curtis', 'Roselyn', 'Marcus', 'Lyn', 'Lloyd',
'Isabelle', 'Francis', 'Olivia', 'Roman', 'Myong', 'Jamie', 'Alexis', 'Vernon', 'Chloe', 'Max',
'Kirstie', 'Tyler', 'Katelin', 'Alejandro', 'Hannah', 'Gavin', 'Lynetta', 'Russell', 'Neida',
'Kurt', 'Dannielle', 'Aiden', 'Janett', 'Vaughn', 'Michelle', 'Brian', 'Maisha', 'Theo', 'Emma',
'Cedric', 'Jocelyn', 'Darrell', 'Grace', 'Ivan', 'Rikki', 'Erik', 'Madeleine', 'Rufus',
'Florance', 'Raymond', 'Jenette', 'Danny', 'Kathy', 'Michael', 'Layla', 'Rolf', 'Selma', 'Anton',
'Rosie', 'Craig', 'Victoria', 'Andy', 'Lorelei', 'Drew', 'Yuri', 'Miles', 'Raisa', 'Rico',
'Rosanne', 'Cory', 'Dori', 'Travis', 'Joslyn', 'Austin', 'Haley', 'Ian', 'Liza', 'Rickey',
'Susana', 'Stephen', 'Richelle', 'Lance', 'Jetta', 'Heath', 'Juliana', 'Rene', 'Madelyn', 'Stan',
'Eleanore', 'Jason', 'Alexa', 'Adam', 'Jenna', 'Warren', 'Cecilia', 'Benito', 'Elaine', 'Mitch',
'Raylene', 'Cyrus'
];
var lastNames = [
'Flinn', 'Bryd', 'Milligan', 'Keesee', 'Mercer', 'Chapman', 'Zobel', 'Carter', 'Pettey',
'Starck', 'Raymond', 'Pullman', 'Drolet', 'Higgins', 'Matzen', 'Tindel', 'Winter', 'Charley',
'Schaefer', 'Hancock', 'Dampier', 'Garling', 'Verde', 'Lenihan', 'Rhymer', 'Pleiman', 'Dunham',
'Seabury', 'Goudy', 'Latshaw', 'Whitson', 'Cumbie', 'Webster', 'Bourquin', 'Young', 'Rikard',
'Brier', 'Luck', 'Porras', 'Gilmore', 'Turner', 'Sprowl', 'Rohloff', 'Magby', 'Wallis', 'Mullens',
'Correa', 'Murphy', 'Connor', 'Gamble', 'Castleman', 'Pace', 'Durrett', 'Bourne', 'Hottle',
'Oldman', 'Paquette', 'Stine', 'Muldoon', 'Smit', 'Finn', 'Kilmer', 'Sager', 'White', 'Friedrich',
'Fennell', 'Miers', 'Carroll', 'Freeman', 'Hollis', 'Neal', 'Remus', 'Pickering', 'Woodrum',
'Bradbury', 'Caffey', 'Tuck', 'Jensen', 'Shelly', 'Hyder', 'Krumm', 'Hundt', 'Seal', 'Pendergast',
'Kelsey', 'Milling', 'Karst', 'Helland', 'Risley', 'Grieve', 'Paschall', 'Coolidge', 'Furlough',
'Brandt', 'Cadena', 'Rebelo', 'Leath', 'Backer', 'Bickers', 'Cappel'
];
var companies = [
'Unilogic', 'Solexis', 'Dalserve', 'Terrasys', 'Pancast', 'Tomiatech', 'Kancom', 'Iridimax',
'Proline', 'Qualcore', 'Thermatek', 'VTGrafix', 'Sunopia', 'WestGate', 'Chromaton', 'Tecomix',
'Galcom', 'Zatheon', 'OmniTouch', 'Hivemind', 'MultiServ', 'Citisys', 'Polygan', 'Dynaroc',
'Storex', 'Britech', 'Thermolock', 'Cryptonica', 'LoopSys', 'ForeTrust', 'TrueXT', 'LexiconLabs',
'Bellgate', 'Dynalab', 'Logico', 'Terralabs', 'CoreMax', 'Polycore', 'Infracom', 'Coolinga',
'MultiLingua', 'Conixco', 'QuadNet', 'FortyFour', 'TurboSystems', 'Optiplex', 'Nitrocam',
'CoreXTS', 'PeerSys', 'FastMart', 'Westercom', 'Templatek', 'Cirpria', 'FastFreight', 'Baramax',
'Superwire', 'Celmax', 'Connic', 'Forecore', 'SmartSystems', 'Ulogica', 'Seelogic', 'DynaAir',
'OpenServ', 'Maxcast', 'SixtySix', 'Protheon', 'SkyCenta', 'Eluxa', 'GrafixMedia', 'VenStrategy',
'Keycast', 'Opticast', 'Cameratek', 'CorpTek', 'Sealine', 'Playtech', 'Anaplex', 'Hypervision',
'Xenosys', 'Hassifix', 'Infratouch', 'Airconix', 'StrategyLine', 'Helixicon', 'MediaDime',
'NitroSystems', 'Viewtopia', 'Cryosoft', 'DuoServe', 'Acousticom', 'Freecast', 'CoreRobotics',
'Quadtek', 'Haltheon', 'TrioSys', 'Amsquare', 'Sophis', 'Keysoft', 'Creatonix'
];
var tlds = [
'com', 'org', 'net', 'info', 'edu', 'gov', 'co', 'biz', 'name', 'me', 'mobi', 'club', 'xyz', 'eu'
];
var streets = [
'Warner Street', 'Ceder Avenue', 'Glendale Road', 'Chester Square', 'Beechmont Parkway',
'Carter Street', 'Hinton Road', 'Pitman Street', 'Winston Road', 'Cottontail Road',
'Buckley Street', 'Concord Avenue', 'Clemont Street', 'Sleepy Lane', 'Bushey Crescent',
'Randolph Street', 'Radcliffe Road', 'Canal Street', 'Ridgewood Drive', 'Highland Drive',
'Orchard Road', 'Foster Walk', 'Walford Way', 'Harrington Crescent', 'Emmet Road',
'Berkeley Street', 'Clarendon Street', 'Sherman Road', 'Mount Street', 'Hunter Street',
'Pearl Street', 'Barret Street', 'Taylor Street', 'Shaftsbury Avenue', 'Paxton Street',
'Park Avenue', 'Seaside Drive', 'Tavistock Place', 'Prospect Place', 'Harvard Avenue',
'Elton Way', 'Green Street', 'Appleton Street', 'Banner Street', 'Piermont Drive', 'Brook Street',
'Main Street', 'Fairmont Avenue', 'Arlington Road', 'Rutherford Street', 'Windsor Avenue',
'Maple Street', 'Wandle Street', 'Grosvenor Square', 'Hunt Street', 'Haredale Road',
'Glenn Drive', 'Mulholland Drive', 'Baker Street', 'Fuller Road', 'Coleman Avenue', 'Wall Street',
'Robinson Street', 'Blakeley Street', 'Alexander Avenue', 'Gartland Street', 'Wooster Road',
'Brentwood Drive', 'Colwood Place', 'Rivington Street', 'Bramble Lane', 'Hartswood Road',
'Albion Place', 'Waverton Street', 'Sawmill Lane', 'Templeton Parkway', 'Hill Street',
'Marsham Street', 'Stockton Lane', 'Lake Drive', 'Elm Street', 'Winchester Drive',
'Crockett Street', 'High Street', 'Longford Crescent', 'Moreland Street', 'Sterling Street',
'Golden Lane', 'Mercer Street', 'Dunstable Street', 'Chestnut Walk', 'Rutland Drive',
'Buckfield Lane', 'Pembrooke Street', 'Tower Lane', 'Willow Avenue', 'Faraday Street',
'Springfield Street', 'Crawford Street', 'Hudson Street'
];
var cities = [
'Beaverton', 'Stanford', 'Baltimore', 'Newcastle', 'Halifax', 'Rockhampton', 'Coventry',
'Medford', 'Boulder', 'Dover', 'Waterbury', 'Christchurch', 'Manchester', 'Perth', 'Norwich',
'Redmond', 'Plymouth', 'Tacoma', 'Newport', 'Bradford', 'Aspen', 'Wellington', 'Oakland',
'Norfolk', 'Durham', 'Portsmouth', 'Detroit', 'Portland', 'Northampton', 'Dayton', 'Charleston',
'Irvine', 'Dallas', 'Albany', 'Petersburg', 'Melbourne', 'Southampton', 'Stafford', 'Bridgeport',
'Fairfield', 'Dundee', 'Spokane', 'Oakleigh', 'Bristol', 'Sacramento', 'Sheffield', 'Lewisburg',
'Miami', 'Brisbane', 'Denver', 'Kingston', 'Burwood', 'Rochester', 'Fresno', 'Cardiff',
'Auckland', 'Sudbury', 'Hastings', 'Reno', 'Hillboro', 'Palmerston', 'Oxford', 'Hobart',
'Atlanta', 'Wilmington', 'Vancouver', 'Youngstown', 'Hartford', 'London', 'Danbury', 'Birmingham',
'Columbia', 'Dublin', 'Chicago', 'Toronto', 'Orlando', 'Toledo', 'Pheonix', 'Bakersfield',
'Nottingham', 'Newark', 'Fargo', 'Walkerville', 'Exeter', 'Woodville', 'Greenville', 'Frankston',
'Bangor', 'Seattle', 'Canterbury', 'Colchester', 'Boston', 'York', 'Cambridge', 'Brighton',
'Lancaster', 'Adelaide', 'Cleveland', 'Telford', 'Richmond'
];
var countries = [
'Andorra', 'United Arab Emirates', 'Afghanistan', 'Antigua and Barbuda', 'Anguilla', 'Albania',
'Armenia', 'Angola', 'Antarctica', 'Argentina', 'American Samoa', 'Austria', 'Australia', 'Aruba',
'Åland Islands', 'Azerbaijan', 'Bosnia and Herzegovina', 'Barbados', 'Bangladesh', 'Belgium',
'Burkina Faso', 'Bulgaria', 'Bahrain', 'Burundi', 'Benin', 'Saint Barthélemy', 'Bermuda',
'Brunei Darussalam', 'Bolivia, Plurinational State of', 'Bonaire, Sint Eustatius and Saba',
'Brazil', 'Bahamas', 'Bhutan', 'Bouvet Island', 'Botswana', 'Belarus', 'Belize', 'Canada',
'Cocos (Keeling) Islands', 'Congo, the Democratic Republic of the', 'Central African Republic',
'Congo', 'Switzerland', 'Côte d\'Ivoire', 'Cook Islands', 'Chile', 'Cameroon', 'China',
'Colombia', 'Costa Rica', 'Cuba', 'Cabo Verde', 'Curaçao', 'Christmas Island', 'Cyprus',
'Czech Republic', 'Germany', 'Djibouti', 'Denmark', 'Dominica', 'Dominican Republic', 'Algeria',
'Ecuador', 'Estonia', 'Egypt', 'Western Sahara', 'Eritrea', 'Spain', 'Ethiopia', 'Finland',
'Fiji', 'Falkland Islands (Malvinas)', 'Micronesia, Federated States of', 'Faroe Islands',
'France', 'Gabon', 'United Kingdom of Great Britain and Northern Ireland', 'Grenada', 'Georgia',
'French Guiana', 'Guernsey', 'Ghana', 'Gibraltar', 'Greenland', 'Gambia', 'Guinea', 'Guadeloupe',
'Equatorial Guinea', 'Greece', 'South Georgia and the South Sandwich Islands', 'Guatemala',
'Guam', 'Guinea-Bissau', 'Guyana', 'Hong Kong', 'Heard Island and McDonald Islands', 'Honduras',
'Croatia', 'Haiti', 'Hungary', 'Indonesia', 'Ireland', 'Israel', 'Isle of Man', 'India',
'British Indian Ocean Territory', 'Iraq', 'Iran, Islamic Republic of', 'Iceland', 'Italy',
'Jersey', 'Jamaica', 'Jordan', 'Japan', 'Kenya', 'Kyrgyzstan', 'Cambodia', 'Kiribati', 'Comoros',
'Saint Kitts and Nevis', 'Korea, Democratic People\'s Republic of', 'Korea, Republic of',
'Kuwait', 'Cayman Islands', 'Kazakhstan', 'Lao People\'s Democratic Republic', 'Lebanon',
'Saint Lucia', 'Liechtenstein', 'Sri Lanka', 'Liberia', 'Lesotho', 'Lithuania', 'Luxembourg',
'Latvia', 'Libya', 'Morocco', 'Monaco', 'Moldova, Republic of', 'Montenegro',
'Saint Martin (French part)', 'Madagascar', 'Marshall Islands',
'Macedonia, the former Yugoslav Republic of', 'Mali', 'Myanmar', 'Mongolia', 'Macao',
'Northern Mariana Islands', 'Martinique', 'Mauritania', 'Montserrat', 'Malta', 'Mauritius',
'Maldives', 'Malawi', 'Mexico', 'Malaysia', 'Mozambique', 'Namibia', 'New Caledonia', 'Niger',
'Norfolk Island', 'Nigeria', 'Nicaragua', 'Netherlands', 'Norway', 'Nepal', 'Nauru', 'Niue',
'New Zealand', 'Oman', 'Panama', 'Peru', 'French Polynesia', 'Papua New Guinea', 'Philippines',
'Pakistan', 'Poland', 'Saint Pierre and Miquelon', 'Pitcairn', 'Puerto Rico',
'Palestine, State of', 'Portugal', 'Palau', 'Paraguay', 'Qatar', 'Réunion', 'Romania', 'Serbia',
'Russian Federation', 'Rwanda', 'Saudi Arabia', 'Solomon Islands', 'Seychelles', 'Sudan',
'Sweden', 'Singapore', 'Saint Helena, Ascension and Tristan da Cunha', 'Slovenia',
'Svalbard and Jan Mayen', 'Slovakia', 'Sierra Leone', 'San Marino', 'Senegal', 'Somalia',
'Suriname', 'South Sudan', 'Sao Tome and Principe', 'El Salvador', 'Sint Maarten (Dutch part)',
'Syrian Arab Republic', 'Swaziland', 'Turks and Caicos Islands', 'Chad',
'French Southern Territories', 'Togo', 'Thailand', 'Tajikistan', 'Tokelau', 'Timor-Leste',
'Turkmenistan', 'Tunisia', 'Tonga', 'Turkey', 'Trinidad and Tobago', 'Tuvalu',
'Taiwan, Province of China', 'Tanzania, United Republic of', 'Ukraine', 'Uganda',
'United States Minor Outlying Islands', 'United States of America', 'Uruguay', 'Uzbekistan',
'Holy See', 'Saint Vincent and the Grenadines', 'Venezuela, Bolivarian Republic of',
'Virgin Islands, British', 'Virgin Islands, U.S.', 'Viet Nam', 'Vanuatu', 'Wallis and Futuna',
'Samoa', 'Yemen', 'Mayotte', 'South Africa', 'Zambia', 'Zimbabwe'
];
var countryCodes = [
'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ',
'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS',
'BT', 'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN',
'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE',
'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF',
'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM',
'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM',
'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC',
'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK',
'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA',
'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG',
'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW',
'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS',
'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO',
'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI',
'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW'
];
var colors = [
'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black',
'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan',
'darkgoldenrod', 'darkgray', 'darkgreen', 'darkkhaki', 'darkmagenta', 'darkolivegreen',
'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue',
'darkslategray', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray',
'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite',
'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue',
'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightpink',
'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray', 'lightsteelblue', 'lightyellow',
'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue',
'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin',
'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid',
'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru',
'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue',
'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue',
'slateblue', 'slategray', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato',
'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen'
];
var lorem = [
'lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipiscing', 'elit', 'morbi',
'vulputate', 'eros', 'ut', 'mi', 'laoreet', 'viverra', 'nunc', 'lacinia', 'non', 'condimentum',
'aenean', 'lacus', 'nisl', 'auctor', 'at', 'tortor', 'ac', 'fringilla', 'sodales', 'pretium',
'quis', 'iaculis', 'in', 'aliquam', 'ultrices', 'felis', 'accumsan', 'ornare', 'etiam',
'elementum', 'aliquet', 'finibus', 'maecenas', 'dignissim', 'vel', 'blandit', 'placerat', 'sed',
'tempor', 'ex', 'faucibus', 'velit', 'nam', 'erat', 'augue', 'quisque', 'nulla', 'maximus',
'vitae', 'e', 'lobortis', 'euismod', 'tristique', 'metus', 'vehicula', 'purus', 'diam', 'mollis',
'neque', 'eu', 'porttitor', 'mauris', 'a', 'risus', 'orci', 'tincidunt', 'scelerisque',
'vestibulum', 'dui', 'ante', 'posuere', 'turpis', 'enim', 'cras', 'massa', 'cursus', 'suscipit',
'tempus', 'facilisis', 'ultricies', 'i', 'eget', 'imperdiet', 'donec', 'arcu', 'ligula',
'sagittis', 'hendrerit', 'justo', 'pellentesque', 'mattis', 'lacinia', 'leo', 'est', 'magna',
'nibh', 'sem', 'natoque', 'consequat', 'proin', 'eti', 'commodo', 'rhoncus', 'dictum', 'id',
'pharetra', 'sapien', 'gravida', 'sollicitudin', 'curabitur', 'au', 'nisi', 'bibendum', 'lectus',
'et', 'pulvinar'
];
module.exports = {
titles: titles,
firstNames: firstNames,
lastNames: lastNames,
companies: companies,
tlds: tlds,
streets: streets,
cities: cities,
countries: countries,
countryCodes: countryCodes,
colors: colors,
lorem: lorem
};

Просмотреть файл

@ -1,64 +0,0 @@
// Copyright (c) 2017 Matt Sweetman
// 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.
var seedrandom = require('seedrandom');
// Create an instance of the prng without a seed (so it'll be a random sequence every time)
var prng = seedrandom();
var utils = {
setRandomSeed: function (seed) {
prng = seedrandom(seed);
},
random: function () {
return prng();
},
randomInt: function (min, max) {
return Math.floor(utils.random() * (max - min + 1)) + min;
},
randomFloat: function (min, max) {
return utils.random() * (max - min) + min;
},
randomBoolean: function () {
return utils.random() < 0.5;
},
randomDate: function (min, max) {
// We add the timezone offset to avoid the date falling outside the supplied range
var d = new Date(Math.floor(utils.random() * (max - min)) + min);
d.setTime(d.getTime() + d.getTimezoneOffset() * 60000);
return d;
},
randomArrayItem: function (array) {
return array[utils.randomInt(0, array.length - 1)];
},
randomChar: function (charset) {
charset = charset || 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return charset.charAt(utils.randomInt(0, charset.length - 1));
}
};
module.exports = utils;

7579
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,12 +2,12 @@
"name": "azure-iot-toolkit", "name": "azure-iot-toolkit",
"displayName": "Azure IoT Hub", "displayName": "Azure IoT Hub",
"description": "This extension is now a part of Azure IoT Tools extension pack. We highly recommend installing Azure IoT Tools to get full capabilities for Azure IoT development. Interact with Azure IoT Hub, IoT Device Management, IoT Edge Management, IoT Hub Device Simulation, IoT Hub Code Generation and IoT Hub Device Provisioning Service (DPS).", "description": "This extension is now a part of Azure IoT Tools extension pack. We highly recommend installing Azure IoT Tools to get full capabilities for Azure IoT development. Interact with Azure IoT Hub, IoT Device Management, IoT Edge Management, IoT Hub Device Simulation, IoT Hub Code Generation and IoT Hub Device Provisioning Service (DPS).",
"version": "2.16.6", "version": "2.16.7",
"publisher": "vsciot-vscode", "publisher": "vsciot-vscode",
"aiKey": "0caaff90-cc1c-4def-b64c-3ef33615bc9b", "aiKey": "0caaff90-cc1c-4def-b64c-3ef33615bc9b",
"icon": "logo.png", "icon": "logo.png",
"engines": { "engines": {
"vscode": "^1.40.0" "vscode": "^1.65.1"
}, },
"license": "SEE LICENSE IN LICENSE.txt", "license": "SEE LICENSE IN LICENSE.txt",
"repository": { "repository": {
@ -780,13 +780,16 @@
] ]
}, },
"scripts": { "scripts": {
"vscode:prepublish": "rimraf dist && webpack --mode production", "vscode:prepublish": "rimraf dist && npm run resources:clean && webpack --mode production",
"compile": "tsc -p ./", "compile": "tsc -p ./",
"tslint": "tslint -t verbose src/**/*.ts test/**/*.ts --exclude src/**/*.d.ts", "tslint": "tslint -t verbose src/**/*.ts test/**/*.ts --exclude src/**/*.d.ts",
"version": "tsc -v", "version": "tsc -v",
"test": "npm run compile && node ./out/test/runTests.js", "test": "npm run compile && node ./out/test/runTests.js",
"webpack": "rimraf dist && webpack --mode development", "simulator:clean": "rimraf resources/simulator/scripts",
"webpack-dev": "rimraf dist && webpack --mode development --watch" "welcome:clean": "rimraf resources/welcome/scripts",
"resources:clean": "npm run simulator:clean && npm run welcome:clean",
"webpack": "rimraf dist && npm run resources:clean && webpack --mode development",
"webpack-dev": "rimraf dist && npm run resources:clean && webpack --mode development --watch"
}, },
"devDependencies": { "devDependencies": {
"@opentelemetry/tracing": "^0.18.2", "@opentelemetry/tracing": "^0.18.2",
@ -801,7 +804,7 @@
"@types/vscode": "^1.40.0", "@types/vscode": "^1.40.0",
"copy-webpack-plugin": "^6.0.3", "copy-webpack-plugin": "^6.0.3",
"fail-on-errors-webpack-plugin": "^3.0.0", "fail-on-errors-webpack-plugin": "^3.0.0",
"mocha": "^8.2.1", "mocha": "^9.2.2",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"shebang-loader": "0.0.1", "shebang-loader": "0.0.1",
"terser-webpack-plugin": "^5.1.1", "terser-webpack-plugin": "^5.1.1",
@ -809,7 +812,7 @@
"tslint": "^6.1.3", "tslint": "^6.1.3",
"typescript": "^3.9.7", "typescript": "^3.9.7",
"webpack": "^5.30.0", "webpack": "^5.30.0",
"webpack-cli": "^3.3.12" "webpack-cli": "^4.9.2"
}, },
"dependencies": { "dependencies": {
"@azure/arm-deviceprovisioningservices": "^2.1.0", "@azure/arm-deviceprovisioningservices": "^2.1.0",
@ -820,23 +823,24 @@
"@azure/ms-rest-azure-env": "^2.0.0", "@azure/ms-rest-azure-env": "^2.0.0",
"@azure/ms-rest-nodeauth": "^3.0.5", "@azure/ms-rest-nodeauth": "^3.0.5",
"ajv": "^6.12.4", "ajv": "^6.12.4",
"axios": "^0.21.1", "axios": "^0.21.4",
"azure-iot-device-mqtt": "^1.15.0", "azure-iot-device-mqtt": "^1.15.0",
"azure-iothub": "^1.12.4", "azure-iothub": "^1.12.4",
"body-parser": "^1.18.2", "body-parser": "^1.18.2",
"dummy-json": "^3.0.4",
"express": "^4.16.3", "express": "^4.16.3",
"fecha": "^4.2.0",
"fs-extra": "^9.0.1", "fs-extra": "^9.0.1",
"glob": "^7.1.6", "glob": "^7.1.6",
"handlebars": "^4.7.7", "iview": "^3.5.4",
"numbro": "^2.3.1", "jquery": "^3.3.1",
"keytar": "^7.9.0",
"replace-in-file": "^6.1.0", "replace-in-file": "^6.1.0",
"seedrandom": "^3.0.5",
"strip-json-comments": "^3.1.1", "strip-json-comments": "^3.1.1",
"uuid": "^8.3.0", "uuid": "^8.3.0",
"vscode-azureextensionui": "^0.35.0", "vscode-azureextensionui": "^0.35.0",
"vscode-extension-telemetry": "^0.1.6", "vscode-extension-telemetry": "^0.1.6",
"vscode-test": "^1.4.1" "vscode-test": "^1.4.1",
"vue": "^2.6.14"
}, },
"extensionDependencies": [ "extensionDependencies": [
"ms-vscode.azure-account" "ms-vscode.azure-account"

9
resources/simulator/axios.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -6,13 +6,8 @@
otherwise webview may show in blank because some variable cannot get the initial data otherwise webview may show in blank because some variable cannot get the initial data
(e.g. axios.js is missing so that we can't do POST in main.js ) --> (e.g. axios.js is missing so that we can't do POST in main.js ) -->
<link rel="stylesheet" href="{{root}}/resources/simulator/main.css"> <link rel="stylesheet" href="{{root}}/resources/simulator/main.css">
<link rel="stylesheet" href="./main.css">
<link rel="stylesheet" href="{{root}}/resources/simulator/iview.css"> <link rel="stylesheet" href="{{root}}/resources/simulator/iview.css">
<link rel="stylesheet" href="./iview.css"> <script type="text/javascript" src="{{root}}/resources/simulator/scripts/vendor.js"></script>
<script type="text/javascript" src="{{root}}/resources/simulator/axios.min.js"></script>
<script type="text/javascript" src="./axios.min.js"></script>
<script type="text/javascript" src="{{root}}/resources/simulator/vue.min.js"></script>
<script type="text/javascript" src="./vue.min.js"></script>
<!-- v-cloak will remain on the element until the associated Vue instance finishes compilation. <!-- v-cloak will remain on the element until the associated Vue instance finishes compilation.
Combined with CSS rules, this directive can be used to hide un-compiled mustache bindings until the Vue instance is ready. --> Combined with CSS rules, this directive can be used to hide un-compiled mustache bindings until the Vue instance is ready. -->
<style type="text/css"> <style type="text/css">
@ -155,12 +150,7 @@
</div> </div>
</Modal> </Modal>
</div> </div>
<!-- The loading sequence is critical, iview.js must be executed before main.js, <script type="text/javascript" src="{{root}}/resources/simulator/scripts/simulator.js"></script>
otherwise unexpected placeholder will show on the page before they get properly rendered -->
<script type="text/javascript" src="{{root}}/resources/simulator/iview.min.js"></script>
<script type="text/javascript" src="./iview.min.js"></script>
<script type="text/javascript" src="{{root}}/resources/simulator/main.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body> </body>
</html> </html>

40
resources/simulator/iview.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,3 +1,7 @@
import iView from 'iview';
import Vue from 'vue';
import axios from 'axios';
let vscode; let vscode;
try { try {
vscode = acquireVsCodeApi(); vscode = acquireVsCodeApi();
@ -55,6 +59,8 @@ const defaultValue = {
dummyJsonArea: dummyJsonTemplate dummyJsonArea: dummyJsonTemplate
}; };
Vue.use(iView);
const app = new Vue({ const app = new Vue({
el: "#app", el: "#app",
data() { data() {

6
resources/simulator/vue.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -231,8 +231,8 @@
</div> </div>
</div> </div>
<a href="#" id="back-to-top">&uarr;</a> <a href="#" id="back-to-top">&uarr;</a>
<script type="text/javascript" src="{{root}}/resources/welcome/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="{{root}}/resources/welcome/scripts/vendor.js"></script>
<script type="text/javascript" src="{{root}}/resources/welcome/main.js"></script> <script type="text/javascript" src="{{root}}/resources/welcome/scripts/welcome.js"></script>
</body> </body>
</html> </html>

2
resources/welcome/jquery-3.3.1.min.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,3 +1,5 @@
import $ from "jquery";
$(function () { $(function () {
main(); main();
}); });

Просмотреть файл

@ -0,0 +1,23 @@
const fs = require("fs");
const packageJson = JSON.parse(fs.readFileSync("package.json"));
const indexOfDash = packageJson.version.indexOf("-");
// remove trailing -rc if it presents.
if (indexOfDash !== -1) {
packageJson.version = packageJson.version.substring(0, indexOfDash);
}
// modify package.json by key/value pairs.
const cnt = process.argv.length;
if (cnt % 2 === 1) {
console.log("Format error, expect even argv length!");
process.exit(1);
}
for (let i = 3; i < cnt; i += 2) {
packageJson[process.argv[i - 1]] = process.argv[i];
}
fs.writeFileSync("package.json", JSON.stringify(packageJson, null, 2) + "\n");

Просмотреть файл

@ -28,7 +28,7 @@ export class DeviceTree implements vscode.TreeDataProvider<INode> {
const iotHubConnectionString = await Utility.setConnectionString(Constants.IotHubConnectionStringKey, Constants.IotHubConnectionStringTitle); const iotHubConnectionString = await Utility.setConnectionString(Constants.IotHubConnectionStringKey, Constants.IotHubConnectionStringTitle);
if (iotHubConnectionString) { if (iotHubConnectionString) {
vscode.window.showInformationMessage(`${Constants.IotHubConnectionStringTitle} is updated.`); vscode.window.showInformationMessage(`${Constants.IotHubConnectionStringTitle} is updated.`);
this._onDidChangeTreeData.fire(); this._onDidChangeTreeData.fire(undefined);
} }
} }
@ -64,7 +64,7 @@ export class DeviceTree implements vscode.TreeDataProvider<INode> {
if (treeViewAutoRefreshEnable) { if (treeViewAutoRefreshEnable) {
const treeViewAutoRefreshIntervalInSeconds = Utility.getConfig<number>(Constants.TreeViewAutoRefreshIntervalInSecondsKey); const treeViewAutoRefreshIntervalInSeconds = Utility.getConfig<number>(Constants.TreeViewAutoRefreshIntervalInSecondsKey);
return setInterval(() => { return setInterval(() => {
this._onDidChangeTreeData.fire(); this._onDidChangeTreeData.fire(undefined);
}, treeViewAutoRefreshIntervalInSeconds * 1000); }, treeViewAutoRefreshIntervalInSeconds * 1000);
} }
return undefined; return undefined;

4
src/dummy-json.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,4 @@
// dummy-json.d.ts
declare module "dummy-json" {
export function parse(content: string): string;
}

Просмотреть файл

@ -7,7 +7,7 @@ import { Message } from "azure-iot-device";
import { Client } from "azure-iot-device"; import { Client } from "azure-iot-device";
import { clientFromConnectionString } from "azure-iot-device-mqtt"; import { clientFromConnectionString } from "azure-iot-device-mqtt";
import * as vscode from "vscode"; import * as vscode from "vscode";
import * as dummyjson from "../external_lib/dummy-json"; import dummyjson from "dummy-json";
import { Constants } from "./constants"; import { Constants } from "./constants";
import { IoTHubResourceExplorer } from "./iotHubResourceExplorer"; import { IoTHubResourceExplorer } from "./iotHubResourceExplorer";
import { DeviceItem } from "./Model/DeviceItem"; import { DeviceItem } from "./Model/DeviceItem";
@ -295,11 +295,12 @@ export class Simulator {
const stringify = Utility.getConfig<boolean>( const stringify = Utility.getConfig<boolean>(
Constants.IoTHubD2CMessageStringifyKey, Constants.IoTHubD2CMessageStringifyKey,
); );
let msg = new Message(stringify ? JSON.stringify(message) : message); const msg = new Message(stringify ? JSON.stringify(message) : message);
if (stringify) { // default to utf-8 encoding
msg.contentType = "application/json"; msg.contentEncoding = "utf-8";
msg.contentEncoding = "utf-8"; // msg.contentType must either be `undefined` or `application/json`
} msg.contentType = "application/json";
await client.sendEvent( await client.sendEvent(
msg, msg,
this.sendEventDoneCallback( this.sendEventDoneCallback(

Просмотреть файл

@ -3,7 +3,7 @@ import express from "express";
import * as http from "http"; import * as http from "http";
import { AddressInfo } from "net"; import { AddressInfo } from "net";
import * as vscode from "vscode"; import * as vscode from "vscode";
import * as dummyjson from "../../external_lib/dummy-json"; import dummyjson from "dummy-json";
import { Constants } from "../constants"; import { Constants } from "../constants";
import { DeviceItem } from "../Model/DeviceItem"; import { DeviceItem } from "../Model/DeviceItem";
import { SendStatus } from "../sendStatus"; import { SendStatus } from "../sendStatus";

Просмотреть файл

@ -14,7 +14,7 @@ const path = require('path');
const webpack = require('webpack'); const webpack = require('webpack');
/**@type {import('webpack').Configuration}*/ /**@type {import('webpack').Configuration}*/
const config = { const extensionConfig = {
target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
node: { node: {
__dirname: false __dirname: false
@ -36,7 +36,8 @@ const config = {
extensions: ['.ts', '.js'], extensions: ['.ts', '.js'],
// suppress warning: webpack + require handlebars error // suppress warning: webpack + require handlebars error
alias: { alias: {
handlebars: 'handlebars/dist/handlebars.min.js' handlebars: 'handlebars/dist/handlebars.min.js',
fecha: 'fecha/dist/fecha.min.js'
} }
}, },
module: { module: {
@ -131,4 +132,54 @@ const config = {
} }
} }
module.exports = config; const simulatorConfig = {
entry: './resources/simulator/main.js',
output: {
path: path.resolve(__dirname, 'resources', 'simulator', 'scripts'),
filename: 'simulator.js',
},
devtool: 'source-map',
resolve: {
extensions: ['.js'],
alias: {
vue: 'vue/dist/vue.js'
},
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
filename: 'vendor.js'
},
},
},
},
}
const welcomeConfig = {
entry: './resources/welcome/main.js',
output: {
path: path.resolve(__dirname, 'resources', 'welcome', 'scripts'),
filename: 'welcome.js',
},
devtool: 'source-map',
resolve: {
extensions: ['.js'],
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
filename: 'vendor.js'
},
},
},
},
}
module.exports = [extensionConfig, simulatorConfig, welcomeConfig];