diff --git a/README.md b/README.md
index 6a30a78..9fafb1d 100644
--- a/README.md
+++ b/README.md
@@ -91,6 +91,10 @@ If you want to use tokens in XML based configuration files to be replaced during
- replace tokens in your updated configuration file
## Release notes
+**New in 4.3.0**
+- Add task **5.0.0**
+ - **Breaking change**: Migrate task to Node10 execution handler needing agent `2.144.0` minimum ([#228](https://github.com/qetza/vsts-replacetokens-task/issues/228), [#230](https://github.com/qetza/vsts-replacetokens-task/issues/230)).
+
**New in 4.2.1**
- Task **4.1.1**
- Revert migrate tasks to Node10 execution handler ([#233](https://github.com/qetza/vsts-replacetokens-task/issues/233)).
diff --git a/ReplaceTokens/ReplaceTokensV5/README.md b/ReplaceTokens/ReplaceTokensV5/README.md
new file mode 100644
index 0000000..f4d01a7
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/README.md
@@ -0,0 +1,93 @@
+[![Donate](images/donate.png)](https://www.paypal.me/grouchon/5)
+
+# Replace Tokens task
+Azure Pipelines extension that replace tokens in **text** files with variable values.
+
+## Usage
+If you are using the UI, add a new task, select **Replace Tokens** from the **Utility** category and configure it as needed.
+
+If your are using a YAML file, add a task with the following syntax:
+```yaml
+- task: qetza.replacetokens.replacetokens-task.replacetokens@3
+ displayName: 'Replace tokens'
+ inputs:
+ targetFiles: |
+ **/*.config
+ **/*.json => outputs/*.json
+```
+
+**Note:** the task will only work on text files, if you need to replace token in archive file you will need to first extract the files and after archive them back.
+
+## Parameters
+The parameters of the task are described bellow, in parenthesis is the YAML name:
+
+- **Root directory** (rootDirectory): the base directory for searching files. If not specified the default working directory will be used.
+- **Target files** (targetFiles): the absolute or relative newline-separated paths to the files to replace tokens. Wildcards can be used (eg: `**\*.config` for all _.config_ files in all sub folders).
+> **Syntax**: {file path}[ => {output path}]
+>
+> - `web.config` will replace tokens in _web.config_ and update the file.
+> - `web.tokenized.config => web.config` will replace tokens in _web.tokenized.config_ and save the result in _web.config_.
+> - `config\web.tokenized.config => c:\config\web.config` will replace tokens in _config\web.tokenized.config_ and save the result in _c:\\config\web.config_.
+>
+> **Wildcard support**
+> - `*.tokenized.config => *.config` will replace tokens in all _{filename}.tokenized.config_ target files and save the result in _{filename}.config_.
+> - `**\*.tokenized.config => c:\tmp\*.config` will replace tokens in all _{filename}.tokenized.config_ target files and save the result in _c:\tmp\\{filename}.config_.
+>
+> Only the wildcard _*_ in the target file name will be used for replacement in the output.\
+> Relative paths in the output pattern are relative to the target file path.\
+>
+> **Negative pattern**\
+> If you want to use negative pattern in target file, use a semi-colon `;` to separate the including pattern and the negative patterns. When using output syntax, only the wildcard in the first pattern will be used for generating the output path.
+> - `**\*.tokenized.config;!**\dev\*.config => c:\tmp\*.config` will replace tokens in all _{filename}.tokenized.config_ target files except those under a _dev_ directory and save the result in _c:\tmp\\{filename}.config_.
+
+- **Files encoding** (encoding): the files encoding used for reading and writing. The 'auto' value will determine the encoding based on the Byte Order Mark (BOM) if present; otherwise it will use ascii. (allowed values: auto, ascii, utf-7, utf-8, utf-16le, utf-16be, win1252 and iso88591)
+- **Write unicode BOM** (writeBOM): if checked writes an unicode Byte Order Mark (BOM).
+- **Escape type** (escapeType): specify how to escape variable values. Value `auto` uses the file extension (`.json` and `.xml`) to determine the escaping and `none` as fallback. (allowed values: auto, none, json, xml and custom)
+- **Escape character** (escapeChar): when using `custom` escape type, the escape character to use when escaping characters in the variable values.
+- **Characters to escape** (charsToEscape): when using `custom` escape type, characters in variable values to escape before replacing tokens.
+- **Verbosity** (verbosity): specify the level of log verbosity. (note: error and system debug are always on) (allowed values: normal, detailed and off)
+- **Action on missing variable** (actionOnMissing): specify the action to take on a missing variable.
+ - _silently continue_ (continue): the task will continue without displaying any message.
+ - _log warning_ (warn): the task will continue but log a warning with the missing variable name.
+ - _fail_ (fail): the task will fail and log the missing variable name.
+- **Keep token for missing variable** (keepToken): if checked tokens with missing variables will not be replaced by empty string.
+- **Action on no file processed** (actionOnNoFiles): specify the action when no file was processed. (allowed values: continue, warn, fail)
+- **Token pattern** (tokenPattern): specify the pattern of the tokens to search in the target files. (allowed values: default, rm, octopus, azpipelines, doublebraces and custom)
+- **Token prefix** (tokenPrefix): when using `custom` token pattern, the prefix of the tokens to search in the target files.
+- **Token suffix** (tokenSuffix): when using `custom` token pattern, the suffix of the tokens to search in the target files.
+- **Use legacy pattern** (useLegacyPattern): if checked whitespaces between the token prefix/suffix and the variable name are not ignored.
+- **Empty value** (emptyValue): the variable value that will be replaced with an empty string.
+- **Default value** (defaultValue): the value to be used if a variable is not found. Do not set to disable default value feature. (to replace with an empty string set the default value to the _Empty value_)
+- **Enable transformations** (enableTransforms): if checked transformations can be applied on variable values. The following transformations are available:
+ - _lower_: make variable value lower case. Example: `#{lower(MyVar)}#`
+ - _upper_: make variable value upper case. Example: `#{upper(MyVar)}#`
+ - _noescape_: disable variable value escaping. (this can be used if you want to inject raw JSON or XML for example). Example: `#{noescape(MyVar)}#`
+ - _base64_: encode variable value in BASE64. Example `#{base64(MyVar)}#`
+- **Transform prefix** (transformPrefix): The prefix between transform name and token name. Default: `(`.
+- **Transform suffix** (transformSuffix): The suffix after the token name. Default: `)`.
+- **Variable files (JSON or YAML)** (variableFiles): the absolute or relative comma or newline-separated paths to the files containing additional variables. Wildcards can be used (eg: `vars\**\*.json` for all _.json_ files in all sub folders of _vars_). YAML files **must have** the `.yml`or `.yaml` extension otherwise the file is treated as JSON. Variables declared in files overrides variables defined in the pipeline.
+- **Variable separator** (variableSeparator): the separtor to use in variable names for nested objects and arrays in variable files. Example: `{ 'My': { 'Value': ['Hello World!'] } }` will create a variable _My.Value.0_ with the value _Hello World!_.
+- **Send anonymous usage telemetry** (enableTelemetry): if checked anonymous usage data (hashed collection and pipeline id, no file parameter values, no variable values) will be sent to the task author only to analyze task usage.
+
+### Output variables
+The task creates the following as output variables:
+- **tokenReplacedCount**: the total number of tokens which were replaced by a variable.
+- **tokenFoundCount**: the total number of of tokens which were found.
+- **fileProcessedCount**: the total number of files which were processed.
+- **transformExecutedCount**: the total number of transformations which were executed.
+- **defaultValueCount**: the total number of default value used.
+
+## Data/Telemetry
+The Replace Tokens task for Azure Pipelines collects anonymous usage data and sends them to its author to help improve the product by default. If you don’t wish to send usage data, you can change your telemetry settings through _Send anonymous usage telemetry_ parameter or by setting a variable or environment variable `REPLACETOKENS_DISABLE_TELEMETRY` to `true`.
+
+## Tips
+If you want to use tokens in XML based configuration files to be replaced during deployment and also have those files usable for local development you can combine the [Replace Tokens task](https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens) with the [XDT tranform task](https://marketplace.visualstudio.com/items?itemName=qetza.xdttransform):
+- create an XDT transformation file containing your tokens
+- setup your configuration file with local developement values
+- at deployment time
+ - inject your tokens in the configuration file by using your transformation file
+ - replace tokens in your updated configuration file
+
+## Release notes
+**New in 5.0.0**
+- **Breaking change**: Migrate task to Node10 execution handler needing agent `2.144.0` minimum ([#228](https://github.com/qetza/vsts-replacetokens-task/issues/228), [#230](https://github.com/qetza/vsts-replacetokens-task/issues/230)).
\ No newline at end of file
diff --git a/ReplaceTokens/ReplaceTokensV5/icon.png b/ReplaceTokens/ReplaceTokensV5/icon.png
new file mode 100644
index 0000000..cf7b807
Binary files /dev/null and b/ReplaceTokens/ReplaceTokensV5/icon.png differ
diff --git a/ReplaceTokens/ReplaceTokensV5/index.ts b/ReplaceTokens/ReplaceTokensV5/index.ts
new file mode 100644
index 0000000..4fd9617
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/index.ts
@@ -0,0 +1,747 @@
+import tl = require('azure-pipelines-task-lib/task');
+import fs = require('fs');
+import iconv = require('iconv-lite');
+import jschardet = require('jschardet');
+import path = require('path');
+import os = require('os');
+import crypto = require('crypto');
+import trackEvent, { TelemetryEvent } from './telemetry';
+import yaml = require('js-yaml');
+
+const ENCODING_AUTO: string = 'auto';
+const ENCODING_ASCII: string = 'ascii';
+const ENCODING_UTF_7: string = 'utf-7';
+const ENCODING_UTF_8: string = 'utf-8';
+const ENCODING_UTF_16LE: string = 'utf-16le';
+const ENCODING_UTF_16BE: string = 'utf-16be';
+const ENCODING_WIN1252: string = 'windows1252';
+const ENCODING_ISO_8859_1: string = 'iso88591';
+
+const ACTION_WARN: string = 'warn';
+const ACTION_FAIL: string = 'fail';
+
+const XML_ESCAPE: RegExp = /[<>&'"]/g;
+const JSON_ESCAPE: RegExp = /["\\\b\f\n\r\t]/g;
+const WIN32_DIRECTORY_SEPARATOR: RegExp = /\\/g;
+const POSIX_DIRECTORY_SEPARATOR: RegExp = /\//g;
+const OUTPUT_WILDCARD: RegExp = /\*/g;
+
+interface Options {
+ readonly encoding: string,
+ readonly keepToken: boolean,
+ readonly actionOnMissing: string,
+ readonly writeBOM: boolean,
+ readonly emptyValue: string,
+ readonly escapeType: string,
+ readonly escapeChar: string,
+ readonly charsToEscape: string,
+ readonly verbosity: string,
+ readonly defaultValue: string,
+ readonly enableTransforms: boolean
+}
+
+interface Rule {
+ isInputWildcard: boolean,
+ inputPatterns: string[],
+ isOutputRelative: boolean,
+ outputPattern: string
+}
+
+interface ILogger {
+ debug(message: string): void,
+ info(message: string): void,
+ warn(message: string): void,
+ error(message: string): void
+}
+
+class NullLogger implements ILogger {
+ public debug(message: string): void {}
+ public info(message: string): void {}
+ public warn(message: string): void {}
+ public error(message: string): void {}
+}
+
+enum LogLevel {
+ Debug,
+ Info,
+ Warn,
+ Error,
+ Off = 255
+}
+
+class Logger implements ILogger {
+ private _level: LogLevel;
+
+ constructor(level: LogLevel) {
+ this._level = level;
+ }
+
+ public debug(message: string): void {
+ this.log(LogLevel.Debug, message);
+ }
+
+ public info(message: string): void {
+ this.log(LogLevel.Info, message);
+ }
+
+ public warn(message: string): void {
+ this.log(LogLevel.Warn, message);
+ }
+
+ public error(message: string): void {
+ this.log(LogLevel.Error, message);
+ }
+
+ private log(level: LogLevel, message: string): void {
+ // always log debug to system debug
+ if (level === LogLevel.Debug)
+ tl.debug(message);
+
+ // always set task result on error
+ if (level === LogLevel.Error)
+ tl.setResult(tl.TaskResult.Failed, message);
+
+ if (level < this._level)
+ return;
+
+ switch (level)
+ {
+ case LogLevel.Debug:
+ case LogLevel.Info:
+ console.log(message);
+ break;
+
+ case LogLevel.Warn:
+ tl.warning(message);
+ break;
+ }
+
+ }
+}
+
+class Counter {
+ public Tokens: number = 0;
+ public Replaced: number = 0;
+ public Files: number = 0;
+ public DefaultValues: number = 0;
+ public Transforms: number = 0;
+}
+
+var logger: ILogger = new NullLogger();
+var globalCounters: Counter = new Counter();
+var fileVariables: {[name: string]: string} = {};
+
+var mapEncoding = function (encoding: string): string {
+ switch (encoding)
+ {
+ case 'auto':
+ return ENCODING_AUTO;
+
+ case 'Ascii':
+ case 'ascii':
+ return ENCODING_ASCII;
+
+ case 'UTF7':
+ case 'utf-7':
+ return ENCODING_UTF_7;
+
+ case 'UTF8':
+ case 'utf-8':
+ return ENCODING_UTF_8;
+
+ case 'Unicode':
+ case 'utf-16le':
+ return ENCODING_UTF_16LE;
+
+ case 'BigEndianUnicode':
+ case 'utf-16be':
+ return ENCODING_UTF_16BE;
+
+ case 'win1252':
+ return ENCODING_WIN1252;
+
+ case 'iso88591':
+ return ENCODING_ISO_8859_1;
+
+ case 'UTF32':
+ throw new Error('utf-32 encoding is no more supported.');
+
+ case 'BigEndianUTF32':
+ throw new Error('utf-32be encoding is no more supported.');
+
+ default:
+ throw new Error('invalid encoding: ' + encoding);
+ }
+}
+
+var getEncoding = function (filePath: string): string {
+ let buffer: Buffer = fs.readFileSync(filePath, { flag: 'r' });
+ let charset: any = jschardet.detect(buffer);
+
+ switch (charset.encoding)
+ {
+ case 'ascii':
+ return ENCODING_ASCII;
+
+ case 'UTF-8':
+ return ENCODING_UTF_8;
+
+ case 'UTF-16LE':
+ return ENCODING_UTF_16LE;
+
+ case 'UTF-16BE':
+ return ENCODING_UTF_16BE;
+
+ case 'windows-1252':
+ return ENCODING_WIN1252;
+
+ default:
+ return ENCODING_ASCII;
+ }
+}
+
+var loadVariablesFromJson = function(
+ value: any,
+ name: string,
+ separator: string,
+ variables: { [name: string] : string; }): number
+{
+ let count: number = 0;
+ let type: string = typeof(value);
+
+ let prefix: string = name;
+ if (name.length != 0)
+ prefix += separator;
+
+ if (value === null || type == "boolean" || type == "number" || type == "string")
+ {
+ variables[name] = (value === null ? "" : value) + "";
+
+ ++count;
+ logger.debug(' loaded variable: ' + name);
+ }
+ else if (Array.isArray(value))
+ {
+ value.forEach((v: any, i: number) => {
+ count += loadVariablesFromJson(v, prefix + i, separator, variables);
+ });
+ }
+ else if (type == "object")
+ {
+ Object.keys(value).forEach(key => {
+ count += loadVariablesFromJson(value[key], prefix + key, separator, variables);
+ });
+ }
+
+ return count;
+}
+
+var replaceTokensInFile = function (
+ filePath: string,
+ outputPath: string,
+ regex: RegExp,
+ transformRegex: RegExp,
+ options: Options): void {
+ logger.info('##[group]replacing tokens in: ' + filePath);
+
+ if (filePath !== outputPath)
+ logger.info(' output in: ' + outputPath);
+
+ // ensure encoding
+ let encoding: string = options.encoding;
+ if (options.encoding === ENCODING_AUTO)
+ encoding = getEncoding(filePath);
+
+ logger.debug(' using encoding: ' + encoding);
+
+ // read file and replace tokens
+ let localCounter: Counter = new Counter();
+
+ let content: string = iconv.decode(fs.readFileSync(filePath), encoding);
+ content = content.replace(regex, (match, name) => {
+ ++localCounter.Tokens;
+
+ // extract transformation
+ let transformName: string = null;
+ if (options.enableTransforms)
+ {
+ let m = name.match(transformRegex);
+ if (m)
+ {
+ ++localCounter.Transforms;
+
+ transformName = m[1];
+ name = m[2];
+ }
+ }
+
+ // replace value
+ let value: string = tl.getVariable(name);
+ if (name in fileVariables)
+ value = fileVariables[name];
+
+ let usedDefaultValue: boolean = false;
+ if (!value && options.defaultValue)
+ {
+ ++localCounter.DefaultValues;
+
+ value = options.defaultValue;
+ usedDefaultValue = true;
+ }
+
+ if (!value)
+ {
+ if (options.keepToken)
+ value = match;
+ else
+ value = '';
+
+ let message: string = ' variable not found: ' + name;
+ switch (options.actionOnMissing)
+ {
+ case ACTION_WARN:
+ logger.warn(message);
+ break;
+
+ case ACTION_FAIL:
+ logger.error(message);
+ break;
+
+ default:
+ logger.debug(message);
+ }
+ }
+ else
+ {
+ ++localCounter.Replaced;
+
+ if (options.emptyValue && value === options.emptyValue)
+ value = '';
+
+ // apply transformation
+ if (transformName)
+ {
+ switch (transformName) {
+ case 'lower':
+ value = value.toLowerCase();
+ break;
+
+ case 'upper':
+ value = value.toUpperCase();
+ break;
+
+ case 'noescape':
+ // nothing done here, disable escaping later
+ break;
+
+ case 'base64':
+ value = Buffer.from(value).toString('base64');
+ break;
+
+ default:
+ --localCounter.Transforms;
+ logger.warn(' unknown transform: ' + transformName);
+ break;
+ }
+ }
+ }
+
+ let escapeType: string = options.escapeType;
+ if (escapeType === 'auto')
+ {
+ switch (path.extname(filePath)) {
+ case '.json':
+ escapeType = 'json';
+ break;
+
+ case '.xml':
+ escapeType = 'xml';
+ break;
+
+ default:
+ escapeType = 'none';
+ break;
+ }
+ }
+
+ if (transformName === 'noescape')
+ {
+ escapeType = 'none';
+ }
+
+ // log value before escaping to show raw value and avoid secret leaks (escaped secrets are not replaced by ***)
+ logger.debug(' ' + name + ': ' + value + (usedDefaultValue ? ' (default value)' : ''));
+
+ switch (escapeType) {
+ case 'json':
+ value = value.replace(JSON_ESCAPE, match => {
+ switch (match) {
+ case '"':
+ case '\\':
+ return '\\' + match;
+
+ case '\b': return "\\b";
+ case '\f': return "\\f";
+ case '\n': return "\\n";
+ case '\r': return "\\r";
+ case '\t': return "\\t";
+ }
+ });
+ break;
+
+ case 'xml':
+ value = value.replace(XML_ESCAPE, match => {
+ switch (match) {
+ case '<': return '<';
+ case '>': return '>';
+ case '&': return '&';
+ case '\'': return ''';
+ case '"': return '"';
+ }
+ });
+ break;
+
+ case 'custom':
+ if (options.escapeChar && options.charsToEscape)
+ for (var c of options.charsToEscape)
+ // split and join to avoid regex and escaping escape char
+ value = value.split(c).join(options.escapeChar + c);
+ break;
+ }
+
+ return value;
+ });
+
+ // ensure outputPath directory exists
+ let mkdirSyncRecursive = function (p: string) {
+ if (fs.existsSync(p))
+ return;
+
+ mkdirSyncRecursive(path.dirname(p));
+
+ fs.mkdirSync(p);
+ logger.debug(' created folder: ' + p);
+ };
+ mkdirSyncRecursive(path.dirname(path.resolve(outputPath)));
+
+ // write file & log
+ if (localCounter.Tokens)
+ {
+ // always write if tokens found
+ fs.writeFileSync(outputPath, iconv.encode(content, encoding, { addBOM: options.writeBOM, stripBOM: null, defaultEncoding: null }));
+ }
+ else if (filePath !== outputPath)
+ {
+ // copy original file if output is different (not using copyFileSync to support node 6.x)
+ fs.writeFileSync(outputPath, fs.readFileSync(filePath));
+ }
+
+ logger.info(' ' + localCounter.Replaced + ' token(s) replaced out of ' + localCounter.Tokens + (localCounter.DefaultValues ? ' (using ' + localCounter.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + localCounter.Transforms + ' transformation(s)' : ''));
+ logger.info('##[endgroup]');
+
+ globalCounters.Tokens += localCounter.Tokens;
+ globalCounters.Replaced += localCounter.Replaced;
+ globalCounters.DefaultValues += localCounter.DefaultValues;
+ globalCounters.Transforms += localCounter.Transforms;
+}
+
+var mapLogLevel = function (level: string): LogLevel {
+ switch (level)
+ {
+ case "normal":
+ return LogLevel.Info;
+
+ case "detailed":
+ return LogLevel.Debug;
+
+ case "off":
+ return LogLevel.Off;
+ }
+
+ return LogLevel.Info;
+}
+
+var normalize = function (p: string): string {
+ return os.platform() === 'win32'
+ ? p.replace(POSIX_DIRECTORY_SEPARATOR, '\\')
+ : p.replace(WIN32_DIRECTORY_SEPARATOR, '/');
+}
+
+async function run() {
+ let startTime: Date = new Date();
+ let serverType = tl.getVariable('System.ServerType');
+ let telemetryEnabled = tl.getBoolInput('enableTelemetry', true) && tl.getVariable('REPLACETOKENS_DISABLE_TELEMETRY') !== 'true';
+
+ let proxyUrl: string = undefined;
+ let config = tl.getHttpProxyConfiguration();
+ if (config)
+ proxyUrl = config.proxyUrl;
+
+ let telemetryEvent = {
+ account: crypto.createHash('sha256').update(tl.getVariable('system.collectionid')).digest('hex'),
+ pipeline: crypto.createHash('sha256').update(tl.getVariable('system.teamprojectid') + tl.getVariable('system.definitionid')).digest('hex'),
+ pipelineType: tl.getVariable('release.releaseid') ? 'release' : 'build',
+ serverType: !serverType || serverType.toLowerCase() !== 'hosted' ? 'server' : 'services',
+ } as TelemetryEvent;
+
+ try {
+ // load inputs
+ let root: string = tl.getPathInput('rootDirectory', false, true);
+ let tokenPattern: string = tl.getInput('tokenPattern', true);
+ let tokenPrefix: string = tl.getInput('tokenPrefix', true);
+ let tokenSuffix: string = tl.getInput('tokenSuffix', true);
+ let useLegacyPattern: boolean = tl.getBoolInput('useLegacyPattern', true);
+ let options: Options = {
+ encoding: mapEncoding(tl.getInput('encoding', true)),
+ keepToken: tl.getBoolInput('keepToken', true),
+ actionOnMissing: tl.getInput('actionOnMissing', true),
+ writeBOM: tl.getBoolInput('writeBOM', true),
+ emptyValue: tl.getInput('emptyValue', false),
+ escapeType: tl.getInput('escapeType', false),
+ escapeChar: tl.getInput('escapeChar', false),
+ defaultValue: tl.getInput('defaultValue', false),
+ charsToEscape: tl.getInput('charsToEscape', false),
+ verbosity: tl.getInput('verbosity', true),
+ enableTransforms: tl.getBoolInput('enableTransforms', false),
+ };
+ let transformPrefix: string = tl.getInput('transformPrefix', true);
+ let transformSuffix: string = tl.getInput('transformSuffix', true);
+ let actionOnNoFiles: string = tl.getInput('actionOnNoFiles', true);
+
+ logger = new Logger(mapLogLevel(options.verbosity));
+
+ let rules: Rule[] = [];
+ let ruleUsingInputWildcardCount: number = 0;
+ let ruleUsingNegativeInputPattern: number = 0;
+ let ruleUsingOutputPatternCount: number = 0;
+
+ tl.getDelimitedInput('targetFiles', '\n', true).forEach((l: string) => {
+ if (l)
+ l.split(',').forEach((line: string) => {
+ if (line)
+ {
+ let ruleParts: string[] = line.split('=>');
+ let rule: Rule = {
+ isInputWildcard: false,
+ inputPatterns: normalize(ruleParts[0].trim()).split(';'),
+ isOutputRelative: false,
+ outputPattern: null
+ };
+
+ rule.isInputWildcard = path.basename(rule.inputPatterns[0]).indexOf('*') != -1;
+
+ if (ruleParts.length > 1)
+ {
+ rule.outputPattern = normalize(ruleParts[1].trim());
+ rule.isOutputRelative = !path.isAbsolute(rule.outputPattern)
+ }
+
+ rules.push(rule);
+
+ if (ruleParts[0].indexOf('!') != -1)
+ ++ruleUsingNegativeInputPattern;
+
+ if (rule.isInputWildcard)
+ ++ruleUsingInputWildcardCount;
+
+ if (rule.outputPattern)
+ ++ruleUsingOutputPatternCount;
+ }
+ })
+ });
+
+ let variableSeparator: string = tl.getInput('variableSeparator', false);
+ let variableFilesCount: number = 0;
+
+ tl.getDelimitedInput('variableFiles', '\n', false).forEach((l: string) => {
+ if (l)
+ l.split(',').forEach((p: string) => {
+ if (p)
+ {
+ tl.findMatch(root, normalize(p)).forEach(filePath => {
+ if (tl.stats(filePath).isDirectory())
+ return;
+
+ if (!tl.exist(filePath))
+ {
+ logger.error('file not found: ' + filePath);
+
+ return;
+ }
+
+ logger.info('##[group]loading variables from: ' + filePath);
+
+ let encoding: string = getEncoding(filePath);
+ let extension: string = path.extname(filePath).toLowerCase();
+ let content: string = iconv.decode(fs.readFileSync(filePath), encoding);
+ let variables: any = extension === '.yaml' || extension === '.yml'
+ ? yaml.load(content)
+ : JSON.parse(content);
+
+ let count: number = loadVariablesFromJson(variables, '', variableSeparator, fileVariables);
+
+ logger.info(' ' + count + ' variable(s) loaded.');
+ logger.info('##[endgroup]');
+
+ ++variableFilesCount;
+ });
+ }
+ });
+ });
+
+ // initialize task
+ switch (tokenPattern)
+ {
+ case 'default':
+ tokenPrefix = '#{';
+ tokenSuffix = '}#';
+ break;
+
+ case 'rm':
+ tokenPrefix = '__';
+ tokenSuffix = '__';
+ break;
+
+ case 'octopus':
+ tokenPrefix = '#{';
+ tokenSuffix = '}';
+ break;
+
+ case 'azpipelines':
+ tokenPrefix = '$(';
+ tokenSuffix = ')';
+ break;
+
+ case 'doublebraces':
+ tokenPrefix = '{{';
+ tokenSuffix = '}}';
+ break;
+ }
+
+ let escapedTokenPrefix: string = tokenPrefix.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ let escapedTokenSuffix: string = tokenSuffix.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ let pattern = useLegacyPattern
+ ? escapedTokenPrefix + '((?:(?!' + escapedTokenSuffix + ').)*)' + escapedTokenSuffix
+ : escapedTokenPrefix + '\\s*((?:(?!' + escapedTokenPrefix + ')(?!\\s*' + escapedTokenSuffix + ').)*)\\s*' + escapedTokenSuffix;
+ let regex: RegExp = new RegExp(pattern, 'gm');
+ logger.debug('pattern: ' + regex.source);
+
+ let escapedTransformPrefix: string = transformPrefix.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ let escapedTransformSuffix: string = transformSuffix.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ let transformPattern = '\\s*(.*)' + escapedTransformPrefix + '\\s*((?:(?!' + escapedTransformPrefix + ')(?!\\s*' + escapedTransformSuffix + ').)*)\\s*' + escapedTransformSuffix + '\\s*';
+ let transformRegex: RegExp = new RegExp(transformPattern);
+ logger.debug('transform pattern: ' + transformRegex.source);
+
+ // set telemetry data
+ telemetryEvent.actionOnMissing = options.actionOnMissing;
+ telemetryEvent.charsToEscape = options.charsToEscape;
+ telemetryEvent.emptyValue = options.emptyValue;
+ telemetryEvent.encoding = options.encoding;
+ telemetryEvent.escapeChar = options.escapeChar;
+ telemetryEvent.escapeType = options.escapeType;
+ telemetryEvent.keepToken = options.keepToken;
+ telemetryEvent.pattern = regex.source;
+ telemetryEvent.result = 'succeeded';
+ telemetryEvent.rules = rules.length;
+ telemetryEvent.rulesWithInputWildcard = ruleUsingInputWildcardCount;
+ telemetryEvent.rulesWithNegativePattern = ruleUsingNegativeInputPattern;
+ telemetryEvent.rulesWithOutputPattern = ruleUsingOutputPatternCount;
+ telemetryEvent.tokenPrefix = tokenPrefix;
+ telemetryEvent.tokenSuffix = tokenSuffix;
+ telemetryEvent.variableFiles = variableFilesCount;
+ telemetryEvent.variableSeparator = variableSeparator;
+ telemetryEvent.verbosity = options.verbosity;
+ telemetryEvent.writeBOM = options.writeBOM;
+ telemetryEvent.useLegacyPattern = useLegacyPattern;
+ telemetryEvent.enableTransforms = options.enableTransforms;
+ telemetryEvent.transformPrefix = transformPrefix;
+ telemetryEvent.transformSuffix = transformSuffix;
+ telemetryEvent.transformPattern = transformPattern;
+ telemetryEvent.defaultValue = options.defaultValue;
+ telemetryEvent.tokenPattern = tokenPattern;
+ telemetryEvent.actionOnNoFiles = actionOnNoFiles;
+
+ // process files
+ rules.forEach(rule => {
+ tl.findMatch(root, rule.inputPatterns).forEach(filePath => {
+ if (tl.stats(filePath).isDirectory())
+ return;
+
+ if (!tl.exist(filePath))
+ {
+ logger.error('file not found: ' + filePath);
+
+ return;
+ }
+
+ let outputPath: string = filePath;
+ if (rule.outputPattern)
+ {
+ outputPath = rule.outputPattern;
+
+ if (rule.isInputWildcard)
+ {
+ let inputBasename: string = path.basename(rule.inputPatterns[0]);
+ let inputWildcardIndex = inputBasename.indexOf('*');
+ let fileBasename: string = path.basename(filePath);
+ let token: string = fileBasename.substring(inputWildcardIndex, fileBasename.length - (inputBasename.length - inputWildcardIndex -1));
+
+ outputPath = outputPath.replace(OUTPUT_WILDCARD, token);
+ }
+
+ if (rule.isOutputRelative)
+ outputPath = path.join(path.dirname(filePath), outputPath);
+ }
+
+ replaceTokensInFile(filePath, outputPath, regex, transformRegex, options);
+ ++globalCounters.Files;
+ });
+ });
+
+ // set output variables
+ tl.setVariable('tokenReplacedCount', globalCounters.Replaced.toString());
+ tl.setVariable('tokenFoundCount', globalCounters.Tokens.toString());
+ tl.setVariable('fileProcessedCount', globalCounters.Files.toString());
+ tl.setVariable('transformExecutedCount', globalCounters.Transforms.toString());
+ tl.setVariable('defaultValueCount', globalCounters.DefaultValues.toString());
+
+ // display summary
+ let duration = (+new Date() - (+startTime)) / 1000;
+
+ if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_WARN)
+ {
+ logger.warn('found no files to process in ' + duration + ' seconds.');
+ }
+ else if (globalCounters.Files === 0 && actionOnNoFiles === ACTION_FAIL)
+ {
+ logger.error('found no files to process in ' + duration + ' seconds.');
+ }
+ else
+ {
+ logger.info('replaced ' + globalCounters.Replaced + ' tokens out of ' + globalCounters.Tokens + (globalCounters.DefaultValues ? ' (using ' + globalCounters.DefaultValues + ' default value(s))' : '') + (options.enableTransforms ? ' and running ' + globalCounters.Transforms + ' functions' : '') + ' in ' + globalCounters.Files + ' file(s) in ' + duration + ' seconds.');
+ }
+
+ telemetryEvent.duration = duration;
+ telemetryEvent.tokenReplaced = globalCounters.Replaced;
+ telemetryEvent.tokenFound = globalCounters.Tokens;
+ telemetryEvent.defaultValueReplaced = globalCounters.DefaultValues;
+ telemetryEvent.fileProcessed = globalCounters.Files;
+ telemetryEvent.transformExecuted = globalCounters.Transforms;
+ }
+ catch (err)
+ {
+ telemetryEvent.result = 'failed';
+
+ logger.error(err.message);
+ }
+ finally
+ {
+ if (telemetryEnabled)
+ {
+ var trackedData = trackEvent(telemetryEvent, proxyUrl);
+ tl.debug('sent usage telemetry: ' + JSON.stringify(trackedData));
+ }
+ }
+}
+
+run();
\ No newline at end of file
diff --git a/ReplaceTokens/ReplaceTokensV5/package-lock.json b/ReplaceTokens/ReplaceTokensV5/package-lock.json
new file mode 100644
index 0000000..3bb18e4
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/package-lock.json
@@ -0,0 +1,1091 @@
+{
+ "name": "qetza.vsts-replacetokens-task",
+ "version": "0.1.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "qetza.vsts-replacetokens-task",
+ "version": "0.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "azure-pipelines-task-lib": "^3.1.10",
+ "iconv-lite": "^0.4.15",
+ "js-yaml": "^4.0.0",
+ "jschardet": "^2.2.1"
+ }
+ },
+ "node_modules/@types/concat-stream": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz",
+ "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/form-data": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
+ "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "10.17.60",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
+ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="
+ },
+ "node_modules/@types/qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
+ },
+ "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=="
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "node_modules/azure-pipelines-task-lib": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-3.1.10.tgz",
+ "integrity": "sha512-S5iH1mD9G7boOV0kjVsFkqlz/6FOZjQAajshj3ajzQK9Wr3XRq9JK9+grJP4ityG6of28X2XWpieFdJLhnWLoA==",
+ "dependencies": {
+ "minimatch": "3.0.4",
+ "mockery": "^1.7.0",
+ "q": "^1.5.1",
+ "semver": "^5.1.0",
+ "shelljs": "^0.8.4",
+ "sync-request": "6.1.0",
+ "uuid": "^3.0.1"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "node_modules/concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "engines": [
+ "node >= 0.8"
+ ],
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+ "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-port": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
+ "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/http-basic": {
+ "version": "8.1.3",
+ "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
+ "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
+ "dependencies": {
+ "caseless": "^0.12.0",
+ "concat-stream": "^1.6.2",
+ "http-response-object": "^3.0.1",
+ "parse-cache-control": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/http-response-object": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
+ "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
+ "dependencies": {
+ "@types/node": "^10.0.3"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/interpret": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
+ "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
+ "dependencies": {
+ "has": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "node_modules/js-yaml": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
+ "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jschardet": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-2.2.1.tgz",
+ "integrity": "sha512-Ks2JNuUJoc7PGaZ7bVFtSEvOcr0rBq6Q1J5/7+zKWLT+g+4zziL63O0jg7y2jxhzIa1LVsHUbPXrbaWmz9iwDw==",
+ "engines": {
+ "node": ">=0.1.90"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+ "dependencies": {
+ "mime-db": "1.51.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/mockery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
+ "integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
+ },
+ "node_modules/object-inspect": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+ "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/parse-cache-control": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
+ "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104="
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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=="
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
+ "node_modules/promise": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
+ "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
+ "dependencies": {
+ "asap": "~2.0.6"
+ }
+ },
+ "node_modules/q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
+ "engines": {
+ "node": ">=0.6.0",
+ "teleport": ">=0.2.0"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+ "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "dependencies": {
+ "resolve": "^1.1.6"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
+ "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+ "dependencies": {
+ "is-core-module": "^2.8.1",
+ "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/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
+ "node_modules/shelljs": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
+ "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+ "dependencies": {
+ "glob": "^7.0.0",
+ "interpret": "^1.0.0",
+ "rechoir": "^0.6.2"
+ },
+ "bin": {
+ "shjs": "bin/shjs"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "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==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sync-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
+ "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
+ "dependencies": {
+ "http-response-object": "^3.0.1",
+ "sync-rpc": "^1.2.1",
+ "then-request": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/sync-rpc": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
+ "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
+ "dependencies": {
+ "get-port": "^3.1.0"
+ }
+ },
+ "node_modules/then-request": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
+ "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
+ "dependencies": {
+ "@types/concat-stream": "^1.6.0",
+ "@types/form-data": "0.0.33",
+ "@types/node": "^8.0.0",
+ "@types/qs": "^6.2.31",
+ "caseless": "~0.12.0",
+ "concat-stream": "^1.6.0",
+ "form-data": "^2.2.0",
+ "http-basic": "^8.1.1",
+ "http-response-object": "^3.0.1",
+ "promise": "^8.0.0",
+ "qs": "^6.4.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/then-request/node_modules/@types/node": {
+ "version": "8.10.66",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
+ "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw=="
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ }
+ },
+ "dependencies": {
+ "@types/concat-stream": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz",
+ "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/form-data": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz",
+ "integrity": "sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/node": {
+ "version": "10.17.60",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz",
+ "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="
+ },
+ "@types/qs": {
+ "version": "6.9.7",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
+ },
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ },
+ "azure-pipelines-task-lib": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-3.1.10.tgz",
+ "integrity": "sha512-S5iH1mD9G7boOV0kjVsFkqlz/6FOZjQAajshj3ajzQK9Wr3XRq9JK9+grJP4ityG6of28X2XWpieFdJLhnWLoA==",
+ "requires": {
+ "minimatch": "3.0.4",
+ "mockery": "^1.7.0",
+ "q": "^1.5.1",
+ "semver": "^5.1.0",
+ "shelljs": "^0.8.4",
+ "sync-request": "6.1.0",
+ "uuid": "^3.0.1"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ },
+ "form-data": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+ "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
+ "get-intrinsic": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+ "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "get-port": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
+ "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw="
+ },
+ "glob": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
+ "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-symbols": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+ },
+ "http-basic": {
+ "version": "8.1.3",
+ "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz",
+ "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==",
+ "requires": {
+ "caseless": "^0.12.0",
+ "concat-stream": "^1.6.2",
+ "http-response-object": "^3.0.1",
+ "parse-cache-control": "^1.0.1"
+ }
+ },
+ "http-response-object": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz",
+ "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==",
+ "requires": {
+ "@types/node": "^10.0.3"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "interpret": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
+ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
+ },
+ "is-core-module": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
+ "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
+ "requires": {
+ "has": "^1.0.3"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "js-yaml": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
+ "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
+ "requires": {
+ "argparse": "^2.0.1"
+ }
+ },
+ "jschardet": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-2.2.1.tgz",
+ "integrity": "sha512-Ks2JNuUJoc7PGaZ7bVFtSEvOcr0rBq6Q1J5/7+zKWLT+g+4zziL63O0jg7y2jxhzIa1LVsHUbPXrbaWmz9iwDw=="
+ },
+ "mime-db": {
+ "version": "1.51.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz",
+ "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
+ },
+ "mime-types": {
+ "version": "2.1.34",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz",
+ "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==",
+ "requires": {
+ "mime-db": "1.51.0"
+ }
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "mockery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
+ "integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
+ },
+ "object-inspect": {
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
+ "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "parse-cache-control": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz",
+ "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104="
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "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=="
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ },
+ "promise": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
+ "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
+ "requires": {
+ "asap": "~2.0.6"
+ }
+ },
+ "q": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
+ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
+ },
+ "qs": {
+ "version": "6.10.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
+ "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rechoir": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
+ "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+ "requires": {
+ "resolve": "^1.1.6"
+ }
+ },
+ "resolve": {
+ "version": "1.22.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
+ "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
+ "requires": {
+ "is-core-module": "^2.8.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ },
+ "shelljs": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
+ "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+ "requires": {
+ "glob": "^7.0.0",
+ "interpret": "^1.0.0",
+ "rechoir": "^0.6.2"
+ }
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "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=="
+ },
+ "sync-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz",
+ "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==",
+ "requires": {
+ "http-response-object": "^3.0.1",
+ "sync-rpc": "^1.2.1",
+ "then-request": "^6.0.0"
+ }
+ },
+ "sync-rpc": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz",
+ "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==",
+ "requires": {
+ "get-port": "^3.1.0"
+ }
+ },
+ "then-request": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz",
+ "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==",
+ "requires": {
+ "@types/concat-stream": "^1.6.0",
+ "@types/form-data": "0.0.33",
+ "@types/node": "^8.0.0",
+ "@types/qs": "^6.2.31",
+ "caseless": "~0.12.0",
+ "concat-stream": "^1.6.0",
+ "form-data": "^2.2.0",
+ "http-basic": "^8.1.1",
+ "http-response-object": "^3.0.1",
+ "promise": "^8.0.0",
+ "qs": "^6.4.0"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "8.10.66",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz",
+ "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw=="
+ }
+ }
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ }
+ }
+}
diff --git a/ReplaceTokens/ReplaceTokensV5/package.json b/ReplaceTokens/ReplaceTokensV5/package.json
new file mode 100644
index 0000000..c020a43
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "qetza.vsts-replacetokens-task",
+ "version": "0.1.0",
+ "description": "Build task for VS Team Services that can run replace tokens in files.",
+ "author": "Guillaume Rouchon",
+ "license": "MIT",
+ "homepage": "https://github.com/qetza/vsts-replacetokens-task#readme",
+ "bugs": {
+ "url": "https://github.com/qetza/vsts-replacetokens-task/issues"
+ },
+ "keywords": [
+ "VSTS",
+ "release",
+ "build",
+ "token",
+ "replace",
+ "variable",
+ "substitution"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/qetza/vsts-replacetokens-task.git"
+ },
+ "dependencies": {
+ "azure-pipelines-task-lib": "^3.1.10",
+ "iconv-lite": "^0.4.15",
+ "js-yaml": "^4.0.0",
+ "jschardet": "^2.2.1"
+ }
+}
diff --git a/ReplaceTokens/ReplaceTokensV5/task.json b/ReplaceTokens/ReplaceTokensV5/task.json
new file mode 100644
index 0000000..e424ee3
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/task.json
@@ -0,0 +1,309 @@
+{
+ "id": "A8515EC8-7254-4FFD-912C-86772E2B5962",
+ "name": "replacetokens",
+ "friendlyName": "Replace Tokens",
+ "description": "Replace tokens in files",
+ "helpMarkDown": "[Learn more about this task](https://github.com/qetza/vsts-replacetokens-task/blob/master/ReplaceTokens/ReplaceTokensV4/README.md)",
+ "category": "Utility",
+ "visibility": [
+ "Build",
+ "Release"
+ ],
+ "author": "Guillaume Rouchon",
+ "version": {
+ "Major": 5,
+ "Minor": 0,
+ "Patch": 0
+ },
+ "releaseNotes": "Migrate to Node10 handler (breaking change).",
+ "instanceNameFormat": "Replace tokens in $(targetFiles)",
+ "minimumAgentVersion": "2.144.0",
+ "groups": [
+ {
+ "name": "validations",
+ "displayName": "Validations",
+ "isExpanded": true
+ },
+ {
+ "name": "transforms",
+ "displayName": "Transformations",
+ "isExpanded": false
+ },
+ {
+ "name": "variables",
+ "displayName": "Variables",
+ "isExpanded": false
+ },
+ {
+ "name": "advanced",
+ "displayName": "Advanced",
+ "isExpanded": false
+ }
+ ],
+ "inputs": [
+ {
+ "name": "rootDirectory",
+ "type": "filePath",
+ "label": "Root directory",
+ "defaultValue": "",
+ "required": false,
+ "helpMarkDown": "Base directory for searching files. If not specified the default working directory will be used."
+ },
+ {
+ "name": "targetFiles",
+ "type": "multiLine",
+ "label": "Target files",
+ "defaultValue": "**/*.config",
+ "required": true,
+ "helpMarkDown": "Absolute or relative comma or newline-separated paths to the files to replace tokens (wildcards can be used).
Syntax: {file path}[ => {output path}]
Example: 'web.config' will replace tokens in web.config and update the file.
Example: 'config\\*.tokenized.config => *.config' will replace tokens in config\\{filename}.tokenized.config and save the result in config\\{filename}.config."
+ },
+ {
+ "name": "encoding",
+ "type": "pickList",
+ "label": "Files encoding",
+ "defaultValue": "auto",
+ "required": true,
+ "options": {
+ "auto": "auto",
+ "ascii": "ascii",
+ "utf-7": "utf-7",
+ "utf-8": "utf-8",
+ "utf-16le": "utf-16",
+ "utf-16be": "utf-16 (big endian)",
+ "win1252": "windows 1252",
+ "iso88591": "iso 8859-1"
+ },
+ "helpMarkDown": "Specify the files encoding.
The 'auto' value will determine the encoding based on the Byte Order Mark (BOM) if present; otherwise it will use ascii."
+ },
+ {
+ "name": "tokenPattern",
+ "type": "pickList",
+ "label": "Token pattern",
+ "defaultValue": "default",
+ "required": true,
+ "options": {
+ "default": "#{ ... }#",
+ "rm": "__ ... __",
+ "octopus": "#{ ... }",
+ "azpipelines": "$( ... )",
+ "doublebraces": "{{ ... }}",
+ "custom": "custom"
+ },
+ "helpMarkDown": "Specify the token pattern. Use custom to specify your own prefix and suffix"
+ },
+ {
+ "name": "tokenPrefix",
+ "type": "string",
+ "label": "Token prefix",
+ "defaultValue": "#{",
+ "required": true,
+ "visibleRule": "tokenPattern == custom",
+ "helpMarkDown": "The prefix of the tokens to search in the target files."
+ },
+ {
+ "name": "tokenSuffix",
+ "type": "string",
+ "label": "Token suffix",
+ "defaultValue": "}#",
+ "required": true,
+ "visibleRule": "tokenPattern == custom",
+ "helpMarkDown": "The suffix of the tokens to search in the target files."
+ },
+ {
+ "name": "writeBOM",
+ "type": "boolean",
+ "label": "Write unicode BOM",
+ "defaultValue": "true",
+ "required": true,
+ "helpMarkDown": "If checked writes an unicode Byte Order Mark (BOM).",
+ "visibleRule": "encoding != ascii && encoding != win1252 && encoding != iso88591"
+ },
+ {
+ "name": "escapeType",
+ "type": "pickList",
+ "defaultValue": "auto",
+ "label": "Escape values type",
+ "helpMarkDown": "Specify how to escape variable values.",
+ "options": {
+ "auto": "auto",
+ "none": "no escaping",
+ "json": "json",
+ "xml": "xml",
+ "custom": "custom"
+ }
+ },
+ {
+ "name": "escapeChar",
+ "type": "string",
+ "label": "Escape character",
+ "visibleRule": "escapeType == custom",
+ "helpMarkDown": "The escape character to use when escaping characters in the variable values."
+ },
+ {
+ "name": "charsToEscape",
+ "type": "string",
+ "label": "Characters to escape",
+ "visibleRule": "escapeType == custom",
+ "helpMarkDown": "Characters in variable values to escape before replacing tokens."
+ },
+ {
+ "name": "verbosity",
+ "type": "pickList",
+ "label": "Verbosity",
+ "defaultValue": "normal",
+ "options": {
+ "normal": "normal",
+ "detailed": "detailed",
+ "off": "off"
+ },
+ "helpMarkDown": "Specify the logs verbosity level. (error and system debug are always on)"
+ },
+ {
+ "name": "actionOnMissing",
+ "type": "pickList",
+ "label": "Action on missing variable",
+ "defaultValue": "warn",
+ "groupName": "validations",
+ "required": true,
+ "options": {
+ "continue": "silently continue",
+ "warn": "log warning",
+ "fail": "fail"
+ },
+ "helpMarkDown": "Specify the action on a missing variable."
+ },
+ {
+ "name": "keepToken",
+ "type": "boolean",
+ "label": "Keep token for missing variable",
+ "defaultValue": "false",
+ "groupName": "validations",
+ "required": true,
+ "helpMarkDown": "If checked tokens with missing variables will not be replaced by empty string."
+ },
+ {
+ "name": "actionOnNoFiles",
+ "type": "pickList",
+ "label": "Action on no file processed",
+ "defaultValue": "continue",
+ "groupName": "validations",
+ "required": true,
+ "options": {
+ "continue": "silently continue",
+ "warn": "log warning",
+ "fail": "fail"
+ },
+ "helpMarkDown": "Specify the action when no file was processed."
+ },
+ {
+ "name": "enableTransforms",
+ "type": "boolean",
+ "label": "Enable transformations",
+ "defaultValue": "false",
+ "groupName": "transforms",
+ "required": true,
+ "helpMarkDown": "If checked transformations can be applied on variable values.
Syntax: {token prefix}{transformation name}{transform prefix}{token}{transform suffix}{token suffix}
Example: #{lower(MyVar)}#"
+ },
+ {
+ "name": "transformPrefix",
+ "type": "string",
+ "label": "Transform prefix",
+ "defaultValue": "(",
+ "groupName": "transforms",
+ "required": true,
+ "helpMarkDown": "The prefix between transform name and token name.",
+ "visibleRule": "enableTransforms == true"
+ },
+ {
+ "name": "transformSuffix",
+ "type": "string",
+ "label": "Transform suffix",
+ "defaultValue": ")",
+ "groupName": "transforms",
+ "required": true,
+ "helpMarkDown": "The suffix after the token name.",
+ "visibleRule": "enableTransforms == true"
+ },
+ {
+ "name": "variableFiles",
+ "type": "multiLine",
+ "label": "Files (JSON or YAML)",
+ "defaultValue": "",
+ "groupName": "variables",
+ "required": false,
+ "helpMarkDown": "Absolute or relative comma or newline-separated paths to the files containing additional variables (wildcards can be used). YAML files must have the .yml or .yaml extension otherwise the file is treated as JSON."
+ },
+ {
+ "name": "variableSeparator",
+ "type": "string",
+ "label": "Separator",
+ "defaultValue": ".",
+ "groupName": "variables",
+ "required": false,
+ "helpMarkDown": "The separtor to use in variable names for nested objects in variable files.
Example: {'My':{'Value':'Hello World!'}} will create a variable 'My.Value' with the value 'Hello World!'"
+ },
+ {
+ "name": "useLegacyPattern",
+ "type": "boolean",
+ "label": "Use legacy pattern",
+ "defaultValue": "false",
+ "groupName": "advanced",
+ "required": true,
+ "helpMarkDown": "If checked whitespaces between the token prefix/suffix and the variable name are not ignored."
+ },
+ {
+ "name": "emptyValue",
+ "type": "string",
+ "label": "Empty value",
+ "defaultValue": "(empty)",
+ "groupName": "advanced",
+ "required": false,
+ "helpMarkDown": "The variable value which will be replaced by an empty string."
+ },
+ {
+ "name": "defaultValue",
+ "type": "string",
+ "label": "Default value",
+ "defaultValue": "",
+ "groupName": "advanced",
+ "required": false,
+ "helpMarkDown": "The value to be used if a variable is not found. Do not set to disable default value feature."
+ },
+ {
+ "name": "enableTelemetry",
+ "type": "boolean",
+ "label": "Send anonymous usage telemetry",
+ "defaultValue": "true",
+ "groupName": "advanced",
+ "required": true,
+ "helpMarkDown": "If checked anonymous usage data will be sent to the task author for task usage analysis."
+ }
+ ],
+ "outputVariables": [
+ {
+ "name": "tokenReplacedCount",
+ "description": "Total number of tokens replaced."
+ },
+ {
+ "name": "tokenFoundCount",
+ "description": "Total number of tokens found."
+ },
+ {
+ "name": "fileProcessedCount",
+ "description": "Total number of files processed."
+ },
+ {
+ "name": "transformExecutedCount",
+ "description": "Total number of transformations executed."
+ },
+ {
+ "name": "defaultValueCount",
+ "description": "Total number of default value used."
+ }
+ ],
+ "execution": {
+ "Node10": {
+ "target": "index.js"
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReplaceTokens/ReplaceTokensV5/telemetry.ts b/ReplaceTokens/ReplaceTokensV5/telemetry.ts
new file mode 100644
index 0000000..16a6b20
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/telemetry.ts
@@ -0,0 +1,179 @@
+import crypto = require('crypto');
+import url = require('url');
+import http = require('http');
+import https = require('https');
+
+const instrumentationKey = '99bddd1b-7049-4f4a-b45c-5c6ffbb48a2e';
+const preview = false;
+const version = '5.0.0';
+const sdkVersion = 'replacetokens:1.0.0';
+const operationName = 'replacetokens';
+const eventName = 'token.replaced';
+const telemetryUrl = 'https://dc.services.visualstudio.com/v2/track';
+const timeout = 3000;
+
+export default function trackEvent(event: TelemetryEvent, proxyUrl?: string): string {
+ try
+ {
+ // create event payload
+ let operationId: string = crypto.randomBytes(16).toString('hex');
+ let body = {
+ name: 'Microsoft.ApplicationInsights.Dev.' + instrumentationKey + '.Event',
+ time: new Date().toISOString(),
+ iKey: instrumentationKey,
+ tags: {
+ 'ai.application.ver': version,
+ 'ai.cloud.role': event.serverType,
+ 'ai.internal.sdkVersion': sdkVersion,
+ 'ai.operation.id': operationId,
+ 'ai.operation.name': operationName,
+ 'ai.operation.parentId': '|' + operationId,
+ 'ai.user.accountId': event.account,
+ 'ai.user.authUserId': event.pipeline
+ },
+ data: {
+ baseType: 'EventData',
+ baseData: {
+ ver: '2',
+ name: eventName,
+ properties: {
+ preview: preview,
+ pipelineType: event.pipelineType,
+ result: event.result,
+ tokenPrefix: event.tokenPrefix,
+ tokenSuffix: event.tokenSuffix,
+ pattern: event.pattern,
+ encoding: event.encoding,
+ keepToken: event.keepToken,
+ actionOnMissing: event.actionOnMissing,
+ writeBOM: event.writeBOM,
+ emptyValue: event.emptyValue,
+ escapeType: event.escapeType,
+ escapeChar: event.escapeChar,
+ charsToEscape: event.charsToEscape,
+ verbosity: event.verbosity,
+ variableFiles: event.variableFiles,
+ variableSeparator: event.variableSeparator,
+ rules: event.rules,
+ rulesWithInputWildcard: event.rulesWithInputWildcard,
+ rulesWithOutputPattern: event.rulesWithOutputPattern,
+ rulesWithNegativePattern: event.rulesWithNegativePattern,
+ duration: event.duration,
+ tokenReplaced: event.tokenReplaced,
+ tokenFound: event.tokenFound,
+ fileProcessed: event.fileProcessed,
+ useLegacyPattern: event.useLegacyPattern,
+ enableTransforms: event.enableTransforms,
+ transformPrefix: event.transformPrefix,
+ transformSuffix: event.transformSuffix,
+ transformPattern: event.transformPattern,
+ transformExecuted: event.transformExecuted,
+ defaultValue: event.defaultValue,
+ defaultValueReplaced: event.defaultValueReplaced,
+ tokenPattern: event.tokenPattern,
+ actionOnNoFiles: event.actionOnNoFiles
+ }
+ }
+ }
+ };
+
+ // send event
+ let telemetryUrlParsed = url.parse(telemetryUrl);
+ let options = {
+ method: 'POST',
+ host: telemetryUrlParsed.hostname,
+ port: telemetryUrlParsed.port,
+ path: telemetryUrlParsed.pathname,
+ withCredentials: false,
+ timeout: timeout,
+ headers: <{ [key: string]: string}>{
+ 'Content-Type': 'application/json'
+ }
+ };
+
+ proxyUrl = proxyUrl || process.env['https_proxy'] || undefined;
+ if (proxyUrl)
+ {
+ if (proxyUrl.indexOf('//') === 0)
+ proxyUrl = 'http:' + proxyUrl
+
+ let proxyUrlParsed = url.parse(proxyUrl);
+ if (proxyUrlParsed.protocol === 'https:')
+ {
+ proxyUrl = undefined;
+ }
+ else
+ {
+ options = {...options,
+ host: proxyUrlParsed.hostname,
+ port: proxyUrlParsed.port || '80',
+ path: telemetryUrl,
+ headers: {...options.headers,
+ Host: telemetryUrlParsed.hostname
+ }
+ }
+ }
+ }
+
+ let request = proxyUrl
+ ? http.request(options)
+ : https.request(options);
+
+ request.setTimeout(timeout, () => {
+ request.abort()
+ });
+ request.on('error', (e) => {});
+
+ request.write(JSON.stringify(body));
+ request.end();
+
+ // return payload
+ body.name = 'Microsoft.ApplicationInsights.Dev.*****.Event'
+ body.iKey = '*****';
+
+ return JSON.stringify(body);
+ }
+ catch
+ {
+ }
+}
+
+export interface TelemetryEvent {
+ account: string,
+ pipeline: string,
+ pipelineType: string,
+ serverType: string,
+ result: string,
+ tokenPrefix: string,
+ tokenSuffix: string,
+ pattern: string,
+ encoding: string,
+ keepToken: boolean,
+ actionOnMissing: string,
+ writeBOM: boolean,
+ emptyValue: string,
+ escapeType: string,
+ escapeChar: string,
+ charsToEscape: string,
+ verbosity: string,
+ variableFiles: number,
+ variableSeparator: string,
+ rules: number,
+ rulesWithInputWildcard: number,
+ rulesWithOutputPattern: number,
+ rulesWithNegativePattern: number,
+ duration: number;
+ tokenReplaced: number;
+ tokenFound: number;
+ fileProcessed: number;
+ useLegacyPattern: boolean;
+ enableTransforms: boolean;
+ transformPrefix: string;
+ transformSuffix: string;
+ transformPattern: string;
+ transformExecuted: number;
+ defaultValue: string;
+ defaultValueReplaced: number;
+ tokenPattern: string;
+ actionOnNoFiles: string;
+}
\ No newline at end of file
diff --git a/ReplaceTokens/ReplaceTokensV5/tsconfig.json b/ReplaceTokens/ReplaceTokensV5/tsconfig.json
new file mode 100644
index 0000000..0438b79
--- /dev/null
+++ b/ReplaceTokens/ReplaceTokensV5/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "compilerOptions": {
+ "target": "ES6",
+ "module": "commonjs"
+ }
+}
\ No newline at end of file
diff --git a/make.js b/make.js
index 622f12b..27ce320 100644
--- a/make.js
+++ b/make.js
@@ -64,6 +64,7 @@ target.build = function() {
// build tasks
buildTask(3);
buildTask(4);
+ buildTask(5);
// copy extension resources
console.log('build: copying extension resources');
diff --git a/package.json b/package.json
index fbfc35c..12027ff 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
},
"devDependencies": {
"@types/js-yaml": "^4.0.0",
- "@types/node": "^6.14.13",
+ "@types/node": "^10.17.0",
"@types/q": "0.0.32",
"@types/uuid": "^8.3.0",
"minimist": "~1.2.5",
diff --git a/vss-extension.json b/vss-extension.json
index 50ee7bf..8fb8bfd 100644
--- a/vss-extension.json
+++ b/vss-extension.json
@@ -2,7 +2,7 @@
"manifestVersion": 1,
"id": "replacetokens",
"name": "Replace Tokens",
- "version": "4.2.1",
+ "version": "4.3.0",
"public": true,
"publisher": "qetza",
"targets": [