diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..72c4429 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +npm test diff --git a/bin/dockerfile_lint b/bin/dockerfile_lint index 7eac66f..43ca0d9 100755 --- a/bin/dockerfile_lint +++ b/bin/dockerfile_lint @@ -3,7 +3,6 @@ 'use strict'; var fs = require('fs'), - _ = require('lodash'), yamlParser = require('js-yaml'), commandline = require('commander'), logger = require("../lib/logger"), @@ -23,8 +22,8 @@ var fs = require('fs'), imageid = null; function collectArgs(arg, args) { - args.push(arg); - return args; + args.push(arg); + return args; } commandline @@ -38,7 +37,7 @@ commandline commandline.command('image ') .description("Lint a local docker image matching .\n The --dockerfile option is ignored when this command is used.") - .action(function (id) { + .action(function(id) { lintImage = true; imageid = id; }); @@ -79,13 +78,13 @@ if (commandline.dockerfile.length === 0 && !lintImage) { function lintDockerFiles() { - var lintPromises = _.map(commandline.dockerfile, function (dockerfileLocation) { + const lintPromises = [...commandline.dockerfile].map(function(dockerfileLocation) { if (!commandline.json && !commandline.junit) { console.info('\n# Analyzing ' + dockerfileLocation + '\n'); } return lintDockerFile(dockerfileLocation); }); - Promise.all(lintPromises).then(function (results) { + Promise.all(lintPromises).then(function(results) { if (commandline.json) { printJsonResults(results.length === 1 ? results[0] : results); } else if (commandline.junit) { @@ -97,14 +96,14 @@ function lintDockerFiles() { return total + result.error.count + (strictMode ? result.warn.count : 0); }, 0); process.exit(errorCodesSum); - }).catch(function (error) { + }).catch(function(error) { console.error(error); process.exit(-1); }); } function lintDockerFile(dockerfileLocation) { - return new Promise(function (resolve, reject) { + return new Promise(function(resolve, reject) { try { var dockerfile = fs.readFileSync(dockerfileLocation, 'UTF-8'); } catch (e) { @@ -122,7 +121,7 @@ function lintDockerFile(dockerfileLocation) { } if (remoteFile) { - getContent(dockerfileLocation).then(function (dockerfileContent) { + getContent(dockerfileLocation).then(function(dockerfileContent) { lint(dockerfileContent, rulefileLocation) }); } else { @@ -153,7 +152,7 @@ function lintImageFromInspect() { } } - image.inspect(function (err, data) { + image.inspect(function(err, data) { if (err) { logger.error("Unable to inspect image : " + imageid); process.exit(1); diff --git a/bin/functions.js b/bin/functions.js index 04fdd1c..3642f19 100644 --- a/bin/functions.js +++ b/bin/functions.js @@ -3,14 +3,13 @@ */ 'use strict'; var builder = require('junit-report-builder'); -var util = require('util'); function getRefUrl(url) { var ref_url = ""; - if (util.isArray(url)) { + if (Array.isArray(url)) { var base_url = url ? url[0] : ""; ref_url = url && url[1] ? base_url + - url[1] : base_url; + url[1] : base_url; } else { ref_url = (url) ? url : "None"; } @@ -37,9 +36,9 @@ function isRedirect(statusCode) { } function getContent(url) { - return new Promise(function (resolve, reject) { + return new Promise(function(resolve, reject) { var lib = url.startsWith('https') ? require('https') : require('http'); - var request = lib.get(url, function (response) { + var request = lib.get(url, function(response) { if (isRedirect(response.statusCode) && response.headers.location) { getContent(res.headers.location).then(resolve).catch(reject); } @@ -47,8 +46,8 @@ function getContent(url) { reject(new Error('Failed to load page, status code: ' + response.statusCode)); } var body = []; - response.on('data', function (chunk) { body.push(chunk); }); - response.on('end', function () { resolve(body.join('')); }); + response.on('data', function(chunk) { body.push(chunk); }); + response.on('end', function() { resolve(body.join('')); }); }); request.on('error', reject); }) @@ -60,19 +59,19 @@ function printResults(results) { var info = results.info; if (errors && errors.data && errors.data.length > 0) { console.log("\n--------ERRORS---------\n"); - errors.data.forEach(function (entry) { + errors.data.forEach(function(entry) { printEntry(entry, "ERROR"); }); } if (warn && warn.data && warn.data.length > 0) { console.log("\n-------WARNINGS--------\n"); - warn.data.forEach(function (entry) { + warn.data.forEach(function(entry) { printEntry(entry, "WARNING"); }); } if (info && info.data && info.data.length > 0) { console.log("\n--------INFO---------\n"); - info.data.forEach(function (entry) { + info.data.forEach(function(entry) { printEntry(entry, "INFO"); }); } @@ -116,17 +115,17 @@ function printJunitResults(results) { // Convert test results to JUnit test cases if (errors && errors.data && errors.data.length > 0) { - errors.data.forEach(function (entry) { + errors.data.forEach(function(entry) { makeJunitTestCase(suite, "ERROR", entry); }); } if (warn && warn.data && warn.data.length > 0) { - warn.data.forEach(function (entry) { + warn.data.forEach(function(entry) { makeJunitTestCase(suite, "INFO", entry); }); } if (info && info.data && info.data.length > 0) { - info.data.forEach(function (entry) { + info.data.forEach(function(entry) { makeJunitTestCase(suite, "WARNING", entry); }); } diff --git a/lib/extendify.js b/lib/extendify.js index 023b9a6..51cd184 100644 --- a/lib/extendify.js +++ b/lib/extendify.js @@ -11,41 +11,41 @@ const AND = 'and'; const UNION = 'union' var recoginize = { - arrays : _.isArray, - booleans : _.isBoolean, - numbers : _.isNumber, + arrays: _.isArray, + booleans: _.isBoolean, + numbers: _.isNumber, strings: _.isString }; -function getFuncByBehaviour(behaviour){ +function getFuncByBehaviour(behaviour) { switch (behaviour) { case REPLACE: - return function(x,y) { + return function(x, y) { return y; }; case CONCAT: - return function(x,y) { - x = (_.isArray(x) || _.isString(x))? x : (_.isUndefined(x) ? [] : [x]); - y = (_.isArray(y) || _.isString(y))? y : (_.isUndefined(y) ? [] : [y]); + return function(x, y) { + x = (_.isArray(x) || _.isString(x)) ? x : (_.isUndefined(x) ? [] : [x]); + y = (_.isArray(y) || _.isString(y)) ? y : (_.isUndefined(y) ? [] : [y]); return x.concat(y); }; case UNION: - return function(x,y) { + return function(x, y) { if (!_.isArray(x) && !_.isArray(y)) { return undefined; } - x = (_.isArray(x) || _.isString(x))? x : (_.isUndefined(x) ? [] : [x]); - y = (_.isArray(y) || _.isString(y))? y : (_.isUndefined(y) ? [] : [y]); + x = (_.isArray(x) || _.isString(x)) ? x : (_.isUndefined(x) ? [] : [x]); + y = (_.isArray(y) || _.isString(y)) ? y : (_.isUndefined(y) ? [] : [y]); return _.union(x, y); }; case MERGE: return undefined; case OR: - return function(x,y) { + return function(x, y) { return x || y; }; case AND: - return function(x,y) { + return function(x, y) { return x && y; }; } @@ -54,21 +54,21 @@ function getFuncByBehaviour(behaviour){ function customizeExtend(options) { options = options || {}; - var inPlace = _.isUndefined(options.inPlace)? true : options.inPlace; + var inPlace = _.isUndefined(options.inPlace) ? true : options.inPlace; delete options.inPlace; - var isDeep = _.isUndefined(options.isDeep)? true : options.isDeep; + var isDeep = _.isUndefined(options.isDeep) ? true : options.isDeep; delete options.isDeep; - function customizeByOptions(x,y) { - if(!isDeep &&_.isPlainObject(y)){ + function customizeByOptions(x, y) { + if (!isDeep && _.isPlainObject(y)) { return y; } - for(var type in options) { + for (var type in options) { if (recoginize[type](y)) { var customFunc = getFuncByBehaviour(options[type]); - if (_.isFunction(customFunc)){ + if (_.isFunction(customFunc)) { return customFunc(x, y); } break; @@ -81,12 +81,12 @@ function customizeExtend(options) { return function() { var newArguments = Array.prototype.slice.call(arguments); - if (!inPlace){ - newArguments[0] = _.clone(arguments[0], isDeep); + if (!inPlace) { + newArguments[0] = (isDeep ? _.cloneDeep : _.clone)(arguments[0]); } newArguments.push(customizeByOptions); - return _.merge.apply(this, newArguments); + return _.mergeWith.apply(this, newArguments); } } diff --git a/lib/linter-utils.js b/lib/linter-utils.js index e2230f1..5b75db7 100644 --- a/lib/linter-utils.js +++ b/lib/linter-utils.js @@ -1,8 +1,6 @@ 'use strict'; -var util = require('util'), - logger = require('./logger'), - _ = require('lodash') +var logger = require('./logger'); //TODO move to utils function printObject(obj) { @@ -22,20 +20,20 @@ function stripQuotes(value) { //TODO TestMe -module.exports.createReqInstructionHash = function (ruleObj) { +module.exports.createReqInstructionHash = function(ruleObj) { return ruleObj.required_instructions; }; //TODO TestMe -module.exports.initLineRulesRegexes = function (ruleObj) { +module.exports.initLineRulesRegexes = function(ruleObj) { var lineRules = ruleObj.line_rules; if (!lineRules) { return; } for (var rule in lineRules) { - if (lineRules.hasOwnProperty(rule)) { + if (Object.hasOwn(lineRules, rule)) { lineRules[rule].paramSyntaxRegex = eval(lineRules[rule].paramSyntaxRegex); for (var semanticRule in lineRules[rule].rules) { lineRules[rule].rules[semanticRule].regex = eval(lineRules[ @@ -46,9 +44,9 @@ module.exports.initLineRulesRegexes = function (ruleObj) { }; //TODO TestMe -module.exports.checkRequiredInstructions = function (instructions, result) { +module.exports.checkRequiredInstructions = function(instructions, result) { for (var instruction in instructions) { - if (instructions.hasOwnProperty(instruction)) { + if (Object.hasOwn(instructions, instruction)) { if (!instructions[instruction].exists) { result[instructions[instruction].level].count++; result[instructions[instruction].level].data.push( @@ -59,8 +57,8 @@ module.exports.checkRequiredInstructions = function (instructions, result) { }; -module.exports.createValidCommandRegex = function (commandList) { - if (util.isArray(commandList)) { +module.exports.createValidCommandRegex = function(commandList) { + if (Array.isArray(commandList)) { var regexStr = '\^\('; var commands = commandList.join('\|'); regexStr = regexStr + commands; @@ -125,14 +123,14 @@ function addError(result, lineNumber, line, msg, ref_url) { } module.exports.addError = addError; -module.exports.checkLineRules = function (rules, instruction, line, lineNumber, result) { +module.exports.checkLineRules = function(rules, instruction, line, lineNumber, result) { if (!rules.line_rules[instruction]) { logger.debug("No Line Rules for instruction :" + instruction); return; } var rules = rules.line_rules[instruction].rules; for (var index in rules) { - if (rules.hasOwnProperty(index)) { + if (Object.hasOwn(rules, index)) { var rule = rules[index]; if (rule.regex && rule.regex.test(line) && !rule.inverse_rule) { result[rule.level].count++; @@ -164,7 +162,7 @@ function validateNameValRule(command, result, lineno, line, key, value, rule) { lineno, line, rule.name_error_message ? rule.name_error_message + " ->'" + - nameVal + "'" : 'Name for ' + command.name + ' ' + nameVal + + nameVal + "'" : 'Name for ' + command.name + ' ' + nameVal + ' is not in required format', level, rule.reference_url); @@ -175,7 +173,7 @@ function validateNameValRule(command, result, lineno, line, key, value, rule) { lineno, line, rule.value_error_message ? rule.value_error_message + " ->'" + - nameVal + "'" : 'Value for ' + command.name + ' ' + nameVal + + nameVal + "'" : 'Value for ' + command.name + ' ' + nameVal + ' is not in required format', level, rule.reference_url); @@ -185,21 +183,21 @@ function validateNameValRule(command, result, lineno, line, key, value, rule) { } function isNameValCompatible(cmd) { - return _.contains(['ARG', 'ENV', 'LABEL'], cmd); + return ['ARG', 'ENV', 'LABEL'].includes(cmd); } //TODO TestMe -module.exports.createRequiredNameValDict = function (ruleObj) { +module.exports.createRequiredNameValDict = function(ruleObj) { var hash = {}; var nameValCmds = Object.keys(ruleObj.line_rules).filter(isNameValCompatible); - nameValCmds.forEach(function (cmd) { + nameValCmds.forEach(function(cmd) { var lineRule = ruleObj.line_rules[cmd]; var nameValRules = (lineRule && lineRule.defined_namevals) ? lineRule.defined_namevals : null; if (nameValRules) { var requiredNameVals = {}; for (var key in nameValRules) { - if (nameValRules.hasOwnProperty(key)) { + if (Object.hasOwn(nameValRules, key)) { if (!nameValRules[key]) continue; var nameValRule = nameValRules[key]; if (nameValRule.required) { @@ -214,10 +212,10 @@ module.exports.createRequiredNameValDict = function (ruleObj) { }; -module.exports.checkRequiredNameVals = function (requiredNameVals, result) { +module.exports.checkRequiredNameVals = function(requiredNameVals, result) { for (var command in requiredNameVals) { - if (requiredNameVals.hasOwnProperty(command)) { + if (Object.hasOwn(requiredNameVals, command)) { for (var nameVal in requiredNameVals[command]) { if (!requiredNameVals[command][nameVal].exists) { var keyRule = requiredNameVals[command][nameVal]; @@ -242,7 +240,7 @@ module.exports.checkRequiredNameVals = function (requiredNameVals, result) { * @returns the matched matched name val and the key used to find it {matchedWith: key, match : nameVal} or null if no match. */ function nameValMatch(definedNameVals, lookupKey) { - var keys = _.keys(definedNameVals), + var keys = Object.keys(definedNameVals), key, index; for (index in keys) { @@ -263,7 +261,7 @@ function nameValMatch(definedNameVals, lookupKey) { } -module.exports.validateNameVals = function (command, context, result) { +module.exports.validateNameVals = function(command, context, result) { logger.debug("validating name values for command " + command.name); var lineno = command.lineno, rules = context.rules, @@ -290,7 +288,7 @@ module.exports.validateNameVals = function (command, context, result) { requiredNameVals[instruction][ruleMatch.matchedWith].exists = true; } if (rule.valueRegex && !eval(rule.valueRegex) - .exec(stripQuotes(nameVals[name]))) { + .exec(stripQuotes(nameVals[name]))) { var level = rule.level ? rule.level : 'error'; var nameVal = names[i] + "=" + nameVals[name]; @@ -298,8 +296,8 @@ module.exports.validateNameVals = function (command, context, result) { lineno, line, rule.message ? rule.message + - " ->'" + nameVal + "'" : 'Value for ' + - nameVal + ' is not in required format', + " ->'" + nameVal + "'" : 'Value for ' + + nameVal + ' is not in required format', level, rule.reference_url); } diff --git a/lib/rulefile-loader.js b/lib/rulefile-loader.js index 905c762..c450e20 100644 --- a/lib/rulefile-loader.js +++ b/lib/rulefile-loader.js @@ -1,7 +1,7 @@ 'use strict'; var yamlParser = require('js-yaml'), - extend = require('./extendify')({arrays: 'concat'}), + extend = require('./extendify')({ arrays: 'concat' }), path = require('path'), fs = require('fs'), config = require('../config/config'), @@ -10,12 +10,18 @@ var yamlParser = require('js-yaml'), function convertRequiredInstructions(array) { var obj = {}; - array.forEach(function (o) { + array.forEach(function(o) { obj[o.instruction] = o; }) return obj; } +function normalizeRequiredInstructions(ruleProfile) { + if (Array.isArray(ruleProfile.required_instructions) && ruleProfile.required_instructions.length > 0) { + ruleProfile.required_instructions = convertRequiredInstructions(ruleProfile.required_instructions); + } +} + function alreadyIncluded(fileName, profileArray) { var i; for (i = 0; i < profileArray.length; i++) { @@ -32,17 +38,14 @@ function loadRuleFile(file, directory, includedRuleProfiles) { } var location = path.join(directory, file); var ruleContents = fs.readFileSync(location, 'UTF-8'); - var ruleProfile = yamlParser.safeLoad(ruleContents); + var ruleProfile = yamlParser.load(ruleContents); //validateProfile(ruleProfile); logger.debug("loading rule profile " + file); ruleProfile.sourceFilename = file; //hack to check cyclic dependencies - if (ruleProfile.required_instructions && ruleProfile.required_instructions.length > 0) { - ruleProfile.required_instructions = convertRequiredInstructions(ruleProfile.required_instructions); - } includedRuleProfiles.push(ruleProfile); if (ruleProfile.profile && ruleProfile.profile.includes) { logger.debug("rule file has " + ruleProfile.profile.includes.length + " includes"); - ruleProfile.profile.includes.forEach(function (profile) { + ruleProfile.profile.includes.forEach(function(profile) { loadRuleFile(profile, directory, includedRuleProfiles); }); } else { @@ -63,23 +66,24 @@ function loadRuleFile(file, directory, includedRuleProfiles) { function load(ruleFilePath) { //First get the base rules var baseRuleLocation = fs.readFileSync(config.BASE_RULES, 'UTF-8'); - var rules = yamlParser.safeLoad(baseRuleLocation); + var rules = yamlParser.load(baseRuleLocation); if (!ruleFilePath) { ruleFilePath = config.DEFAULT_RULES; } - var includedRuleProfiles = []; - var ruleDirectory = path.dirname(ruleFilePath); //require all rules to be in same dir - var ruleFileName = path.basename(ruleFilePath); - logger.debug("Rule directory is " + ruleDirectory); - loadRuleFile(ruleFileName, ruleDirectory, includedRuleProfiles); - logger.debug("Number of rule files found for " + ruleFileName + " " + includedRuleProfiles.length); - includedRuleProfiles.reverse(); - includedRuleProfiles.forEach(function (profile) { - delete profile.sourceFilename; // no longer needed part of hack! - extend(rules, profile); - }); - logger.debug("Effective rule set is :\n" + yamlParser.dump(rules)); - return rules; + var includedRuleProfiles = []; + var ruleDirectory = path.dirname(ruleFilePath); //require all rules to be in same dir + var ruleFileName = path.basename(ruleFilePath); + logger.debug("Rule directory is " + ruleDirectory); + loadRuleFile(ruleFileName, ruleDirectory, includedRuleProfiles); + logger.debug("Number of rule files found for " + ruleFileName + " " + includedRuleProfiles.length); + includedRuleProfiles.reverse(); + includedRuleProfiles.forEach(function(profile) { + delete profile.sourceFilename; // no longer needed part of hack! + extend(rules, profile); + }); + normalizeRequiredInstructions(rules); + logger.debug("Effective rule set is :\n" + yamlParser.dump(rules)); + return rules; } module.exports.load = load diff --git a/package-lock.json b/package-lock.json index 0a45b78..38fd075 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,655 +1,913 @@ { "name": "dockerfile_lint", - "version": "0.3.3", - "lockfileVersion": 1, + "version": "0.3.4", + "lockfileVersion": 3, "requires": true, - "dependencies": { - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "packages": { + "": { + "name": "dockerfile_lint", + "version": "0.3.4", + "license": "MIT", + "dependencies": { + "commander": "~2.9.0", + "dockerode": "^5.0.0", + "js-yaml": "^4.1.1", + "junit-report-builder": "^5.1.2", + "lodash": "^4.18.1", + "winston": "^2.4.5" + }, + "bin": { + "dockerfile_lint": "bin/dockerfile_lint" + }, + "devDependencies": { + "fast-xml-parser": "^5.6.0", + "husky": "^9.1.7" } }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" + "node_modules/@balena/dockerignore": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", + "integrity": "sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==", + "license": "Apache-2.0" + }, + "node_modules/@grpc/grpc-js": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", + "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.8.0", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" } }, - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" + "node_modules/@grpc/grpc-js/node_modules/@grpc/proto-loader": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", + "integrity": "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.5.3", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/grpc-js/node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@grpc/grpc-js/node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/@grpc/grpc-js/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } }, - "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" + "node_modules/@grpc/proto-loader": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", + "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" } }, - "buffer-alloc": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "requires": { - "buffer-alloc-unsafe": "^1.1.0", - "buffer-fill": "^1.0.0" + "node_modules/@grpc/proto-loader/node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" } }, - "buffer-alloc-unsafe": { + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + "license": "BSD-3-Clause" }, - "buffer-fill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", - "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "license": "BSD-3-Clause" }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "license": "BSD-3-Clause" }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "license": "BSD-3-Clause" }, - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "requires": { - "graceful-readlink": ">= 1.0.0" + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "license": "BSD-3-Clause" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "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" + "node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0" }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } + "node_modules/asn1": { + "version": "0.2.6", + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/async": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" } }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" - }, - "date-format": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.2.tgz", - "integrity": "sha1-+v1Ej3IRXvHitzkVWukvK+bCjdE=" - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "diff": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz", - "integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=", - "dev": true - }, - "docker-modem": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-1.0.9.tgz", - "integrity": "sha512-lVjqCSCIAUDZPAZIeyM125HXfNvOmYYInciphNrLrylUtKyW66meAjSPXWchKVzoIYZx69TPnAepVSSkeawoIw==", - "requires": { - "JSONStream": "1.3.2", - "debug": "^3.2.6", - "readable-stream": "~1.0.26-4", - "split-ca": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "node_modules/buffer": { + "version": "5.7.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + { + "type": "patreon", + "url": "https://www.patreon.com/feross" }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + { + "type": "consulting", + "url": "https://feross.org/support" } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, - "dockerode": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-2.5.8.tgz", - "integrity": "sha512-+7iOUYBeDTScmOmQqpUYQaE7F4vvIt6+gIZNHWhqAQEI887tiPFB9OvXI/HzQYqfUNvukMK+9myLW63oTJPZpw==", - "requires": { - "concat-stream": "~1.6.2", - "docker-modem": "^1.0.8", - "tar-fs": "~1.16.3" + "node_modules/cliui": { + "version": "8.0.1", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "escape-string-regexp": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", - "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", - "dev": true + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + "node_modules/colors": { + "version": "1.0.3", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" + "node_modules/commander": { + "version": "2.9.0", + "license": "MIT", + "dependencies": { + "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } }, - "fast-xml-parser": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-3.17.4.tgz", - "integrity": "sha512-qudnQuyYBgnvzf5Lj/yxMcf4L9NcVWihXJg7CiU1L+oUCq8MUnFEfH2/nXR/W5uq+yvUN1h7z6s7vs2v1WkL1A==", - "dev": true + "node_modules/cycle": { + "version": "1.0.3", + "engines": { + "node": ">=0.4.0" + } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + "node_modules/debug": { + "version": "4.4.3", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } }, - "glob": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", - "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", - "dev": true, - "requires": { - "graceful-fs": "~2.0.0", - "inherits": "2", - "minimatch": "~0.2.11" + "node_modules/docker-modem": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.7.tgz", + "integrity": "sha512-XJgGhoR/CLpqshm4d3L7rzH6t8NgDFUIIpztYlLHIApeJjMZKYJMz2zxPsYxnejq5h3ELYSw/RBsi3t5h7gNTA==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^1.15.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/docker-modem/node_modules/buildcheck": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz", + "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==", + "optional": true, + "engines": { + "node": ">=10.0.0" } }, - "graceful-fs": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", - "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", - "dev": true + "node_modules/docker-modem/node_modules/cpu-features": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", + "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.19.0" + }, + "engines": { + "node": ">=10.0.0" + } }, - "graceful-readlink": { + "node_modules/docker-modem/node_modules/nan": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", + "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", + "license": "MIT", + "optional": true + }, + "node_modules/docker-modem/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/docker-modem/node_modules/split-ca": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==", + "license": "ISC" + }, + "node_modules/docker-modem/node_modules/ssh2": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz", + "integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==", + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.6", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "~0.0.10", + "nan": "^2.23.0" + } }, - "growl": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", - "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", - "dev": true + "node_modules/dockerode": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-5.0.0.tgz", + "integrity": "sha512-C52mvJ+7lcyhWNfrzVfFsbTrBfy/ezE9FGEYLpu17FUeBcCkxERk9nN7uDl/478ynDiQ4U+5DbQC2vENHkVEtQ==", + "license": "Apache-2.0", + "dependencies": { + "@balena/dockerignore": "^1.0.2", + "@grpc/grpc-js": "^1.11.1", + "@grpc/proto-loader": "^0.7.13", + "docker-modem": "^5.0.7", + "protobufjs": "^7.3.2", + "tar-fs": "^2.1.4" + }, + "engines": { + "node": ">= 14.17" + } }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/emoji-regex": { + "version": "8.0.0", + "license": "MIT" }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "node_modules/end-of-stream": { + "version": "1.4.5", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true + "node_modules/escalade": { + "version": "3.2.0", + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "node_modules/eyes": { + "version": "0.1.8", + "engines": { + "node": "> 0.1.90" + } }, - "jade": { - "version": "0.26.3", - "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", - "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "node_modules/fast-xml-builder": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", + "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", "dev": true, - "requires": { - "commander": "0.6.1", - "mkdirp": "0.3.0" - }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", "dependencies": { - "commander": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", - "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", - "dev": true - }, - "mkdirp": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", - "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", - "dev": true + "path-expression-matcher": "^1.1.3" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.0.tgz", + "integrity": "sha512-MTcrUoRQ1GSQ9iG3QJzBGquYYYeA7piZaJoIWbPFGbRn6Jj6z7xgoAyi4DrZX4y2ZIQQBF59gc/zmvvejjgoFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.5", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" } }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "node_modules/fs-constants": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + "node_modules/graceful-readlink": { + "version": "1.0.1", + "license": "MIT" }, - "junit-report-builder": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-2.1.0.tgz", - "integrity": "sha512-Ioj5I4w18ZcHFaaisqCKdh1z+ipzN7sA2JB+h+WOlGcOMWm0FFN1dfxkgc2I4EXfhSP/mOfM3W43uFzEdz4sTw==", - "requires": { - "date-format": "0.0.2", - "lodash": "^4.17.15", - "make-dir": "^1.3.0", - "xmlbuilder": "^10.0.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" - } + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" } }, - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=" + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "requires": { - "pify": "^3.0.0" + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "node_modules/isstream": { + "version": "0.1.2", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "node_modules/junit-report-builder": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-5.1.2.tgz", + "integrity": "sha512-HzvLbEQcoqN2LmGnloShxu2hLadi/rkOTU3zt61UeMICLS0wGDvbf8neIi6+bGkxMnAePIcFMFnbqV+r6YvwxA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.18.1", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=16" + } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/long": { + "version": "5.3.2", + "license": "Apache-2.0" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "mocha": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.0.1.tgz", - "integrity": "sha1-Whboi4VtDEFF2MaIjCfr1PqxPpA=", - "dev": true, - "requires": { - "commander": "2.3.0", - "debug": "2.0.0", - "diff": "1.0.8", - "escape-string-regexp": "1.0.2", - "glob": "3.2.3", - "growl": "1.8.1", - "jade": "0.26.3", - "mkdirp": "0.5.0" - }, - "dependencies": { - "commander": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", - "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", - "dev": true - }, - "debug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.0.0.tgz", - "integrity": "sha1-ib2d9nMrUSVrxnBTQrugLtEhMe8=", - "dev": true, - "requires": { - "ms": "0.6.2" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz", - "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=", - "dev": true - } + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "node_modules/ms": { + "version": "2.1.3", + "license": "MIT" }, - "once": { + "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { + "license": "ISC", + "dependencies": { "wrappy": "1" } }, - "os-shim": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - }, - "pre-commit": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", - "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "spawn-sync": "^1.0.15", - "which": "1.2.x" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "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==" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", - "dev": true + "node_modules/protobufjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } }, - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "node_modules/protobufjs/node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" } }, - "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" + "node_modules/protobufjs/node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.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==" + "node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "license": "MIT", + "engines": { + "node": "*" } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "node_modules/string_decoder": { + "version": "1.3.0", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "should": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/should/-/should-4.1.0.tgz", - "integrity": "sha1-rjM1ZVof27FW4LM4vxkRBvWdqyE=", - "dev": true, - "requires": { - "should-equal": "0.0.1" + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "should-equal": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.0.1.tgz", - "integrity": "sha1-VQZmU6nwMhHaaVov6naLGZVqnAs=", - "dev": true + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "node_modules/strnum": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", "dev": true, - "requires": { - "concat-stream": "^1.4.7", - "os-shim": "^0.1.2" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" } }, - "split-ca": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", - "integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "node_modules/tar-fs/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "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" - } - }, - "tar-fs": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", - "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "requires": { - "chownr": "^1.0.1", - "mkdirp": "^0.5.1", - "pump": "^1.0.0", - "tar-stream": "^1.1.2" - } - }, - "tar-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", - "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "requires": { - "bl": "^1.0.0", - "buffer-alloc": "^1.2.0", - "end-of-stream": "^1.0.0", - "fs-constants": "^1.0.0", - "readable-stream": "^2.3.0", - "to-buffer": "^1.1.1", - "xtend": "^4.0.0" + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-fs/node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/tar-fs/node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + "node_modules/tar-fs/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } }, - "to-buffer": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + "node_modules/tar-fs/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "node_modules/tweetnacl": { + "version": "0.14.5", + "license": "Unlicense" }, - "util-deprecate": { + "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "license": "MIT" }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "winston": { + "node_modules/winston": { "version": "2.4.5", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.5.tgz", - "integrity": "sha512-TWoamHt5yYvsMarGlGEQE59SbJHqGsZV8/lwC+iCcGeAe0vUaOh+Lv6SYM17ouzC/a/LB1/hz/7sxFBtlu1l4A==", - "requires": { + "license": "MIT", + "dependencies": { "async": "~1.0.0", "colors": "1.0.x", "cycle": "1.0.x", "eyes": "0.1.x", "isstream": "0.1.x", "stack-trace": "0.0.x" + }, + "engines": { + "node": ">= 0.10.0" } }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "node_modules/wrap-ansi": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, - "xmlbuilder": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-10.1.1.tgz", - "integrity": "sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==" + "node_modules/wrappy": { + "version": "1.0.2", + "license": "ISC" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", - "dev": true + "node_modules/yargs-parser": { + "version": "21.1.1", + "license": "ISC", + "engines": { + "node": ">=12" + } } } } diff --git a/package.json b/package.json index cc602c6..6d512a2 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,14 @@ { "name": "dockerfile_lint", - "version": "0.3.3", + "version": "0.3.4", "description": "Utility for linting a docker file against accepted good practices", "main": "index.js", "bin": { "dockerfile_lint": "./bin/dockerfile_lint" }, "scripts": { - "test": "mocha test/**/*spec.js" + "test": "node --test", + "prepare": "husky" }, "repository": { "type": "git", @@ -26,16 +27,14 @@ }, "dependencies": { "commander": "~2.9.0", - "dockerode": "^2.2.9", - "js-yaml": "~3.13.1", - "junit-report-builder": "^2.1.0", - "lodash": "^2.4.2", + "dockerode": "^5.0.0", + "js-yaml": "^4.1.1", + "junit-report-builder": "^5.1.2", + "lodash": "^4.18.1", "winston": "^2.4.5" }, "devDependencies": { - "fast-xml-parser": "^3.17.4", - "mocha": "~2.0.1", - "pre-commit": "^1.1.2", - "should": "~4.1.0" + "fast-xml-parser": "^5.6.0", + "husky": "^9.1.7" } } diff --git a/test/integration/exec.spec.js b/test/integration/exec.spec.js index b99254d..cdc3d75 100644 --- a/test/integration/exec.spec.js +++ b/test/integration/exec.spec.js @@ -1,116 +1,151 @@ 'use strict'; process.env.NODE_ENV = 'test'; -var should = require('should'); +const assert = require('node:assert/strict'), + { exec } = require('node:child_process'), + fs = require('node:fs'), + http = require('node:http'), + path = require('node:path'), + { describe, it } = require('node:test'), + { XMLValidator } = require('fast-xml-parser'); -var exec = require('child_process').exec, - path = require('path') -var binScript = path.join('bin', 'dockerfile_lint') -var parser = require('fast-xml-parser'); +const binScript = path.join('bin', 'dockerfile_lint') -describe('The dockerfile_lint command', function () { +describe('The dockerfile_lint command', function() { - it('should allow a valid Dockerfile', function (done) { + it('should allow a valid Dockerfile', function(t, done) { exec('node ' + binScript + ' -f ./test/data/dockerfiles/TestLabels', - function (err, stdout, stderr) { + function(err, stdout, stderr) { if (err) { return done(err); } - stdout.trim().should.eql('# Analyzing ./test/data/dockerfiles/TestLabels\n\nCheck passed!'); - stderr.should.eql(''); + assert.strictEqual(stdout.trim(), '# Analyzing ./test/data/dockerfiles/TestLabels\n\nCheck passed!'); + assert.strictEqual(stderr, ''); done(); }); }); - it('should validate remote (https) Dockerfile', function (done) { + it('should validate a Dockerfile via http', function(t, done) { + const testPath = 'test/data/dockerfiles/TestLabels'; + // Create an ephemeral HTTP server to serve the Dockerfile. + // Doing a request over the internet to + // https://raw.githubusercontent.com/ is possible, + // but can lead to flaky tests due to network issues like timeouts. + // It's also more consistent to use a file from the same git commit. + const server = http.createServer((req, res) => { + if (req.url !== `/${testPath}`) { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('Not Found'); + return; + } + + const repoDir = path.dirname(path.dirname(__dirname)); + const filePath = path.join(repoDir, testPath); + const stat = fs.statSync(filePath); + assert.ok(stat.isFile(), 'Expected a file at ' + filePath); + res.writeHead(200, { + 'Content-Type': 'text/plain', + 'Content-Length': stat.size, + }); + const readStream = fs.createReadStream(filePath); + readStream.pipe(res); + }); + const port = 3000; + server.listen(port); - exec('node ' + binScript + ' -r config/base_rules.yaml -f https://raw.githubusercontent.com/projectatomic/dockerfile_lint/master/test/data/dockerfiles/TestLabels', - function (err, stdout, stderr) { + const url = `http://localhost:${port}/${testPath}`; + exec(`node ${binScript} -r config/base_rules.yaml -f ${url}`, + function(err, stdout, stderr) { + server.close(); if (err) { return done(err); } - stdout.trim().should.eql('# Analyzing https://raw.githubusercontent.com/projectatomic/dockerfile_lint/master/test/data/dockerfiles/TestLabels\n\nCheck passed!'); - stderr.should.eql(''); + assert.strictEqual(stdout.trim(), `# Analyzing ${url}\n\nCheck passed!`); + assert.strictEqual(stderr, ''); done(); }); }); - it('should exit with a non-zero error code on an empty file', function (done) { + it('should exit with a non-zero error code on an empty file', function(t, done) { var p = exec('node ' + binScript + ' -f test/data/dockerfiles/EmptyFile -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { + function(err, stdout, stderr) { }); - p.on('exit', function (code) { - code.should.equal(5); // 4 errors + 1 warning + p.on('exit', function(code) { + assert.strictEqual(code, 5); // 4 errors + 1 warning done(); }); }); - it('should exit with code 0 on warning when in strict mode ', function (done) { + it('should exit with code 0 on warning when in strict mode ', function(t, done) { var p = exec('node ' + binScript + ' -p -f test/data/dockerfiles/TestLabels -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { + function(err, stdout, stderr) { }); - p.on('exit', function (code) { - code.should.equal(0); + p.on('exit', function(code) { + assert.strictEqual(code, 0); done(); }); }); - it('should exit with code 0 on warning when in permissive mode (long form)', function (done) { + it('should exit with code 0 on warning when in permissive mode (long form)', function(t, done) { var p = exec('node ' + binScript + ' --permissive -f test/data/dockerfiles/TestLabels -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { + function(err, stdout, stderr) { }); - p.on('exit', function (code) { - code.should.equal(0); + p.on('exit', function(code) { + assert.strictEqual(code, 0); done(); }); }); - it('should exit with code 1 on warning when not in permissive mode ', function (done) { + it('should exit with code 1 on warning when not in permissive mode ', function(t, done) { var p = exec('node ' + binScript + ' -f test/data/dockerfiles/TestLabels -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { + function(err, stdout, stderr) { }); - p.on('exit', function (code) { - code.should.eql(1); + p.on('exit', function(code) { + assert.strictEqual(code, 1); done(); }); }); - it('should output valid JSON when in --json mode with multiple Dockerfiles', function (done) { + it('should output valid JSON when in --json mode with multiple Dockerfiles', function(t, done) { var p = exec('node ' + binScript + ' --json -f test/data/dockerfiles/TestLabels -f test/data/dockerfiles/TestLabels -p -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { - should(JSON.parse(stdout)).be.ok.and.have.lengthOf(2); + function(err, stdout, stderr) { + const parsed = JSON.parse(stdout); + assert.ok(parsed); + assert.strictEqual(parsed.length, 2); }); - p.on('exit', function (code) { - code.should.eql(0); + p.on('exit', function(code) { + assert.strictEqual(code, 0); done(); }); }); - it('should exit with code 1 and error message when using both --json and --junit options ', function (done) { + it('should exit with code 1 and error message when using both --json and --junit options ', function(t, done) { var p = exec('node ' + binScript + ' --junit --json -f test/data/dockerfiles/TestLabels', - function (err, stdout, stderr) { - should(stderr).be.equal("ERROR: result format options (\"--json and --junit\") cannot be used together, please choose one only\n") + function(err, stdout, stderr) { + assert.strictEqual(stderr, "ERROR: result format options (\"--json and --junit\") cannot be used together, please choose one only\n"); }); - p.on('exit', function (code) { - code.should.eql(1); + p.on('exit', function(code) { + assert.strictEqual(code, 1); done(); }); }); - it('should output valid XML when in --junit mode', function (done) { - var p = exec('node ' + binScript + ' --junit -f test/data/dockerfiles/TestLabels -p -r test/data/rules/basic.yaml', - function (err, stdout, stderr) { - should(parser.validate(stdout)).be.ok; + it('should output valid XML when in --junit mode', function(t, done) { + const p = exec('node ' + binScript + ' --junit -f test/data/dockerfiles/TestLabels -p -r test/data/rules/basic.yaml', + function(err, stdout, stderr) { + assert.doesNotThrow(() => { + assert.ok(XMLValidator.validate(stdout)); + }); }); - p.on('exit', function (code) { - code.should.eql(0); + p.on('exit', function(code) { + assert.strictEqual(code, 0); done(); }); }); diff --git a/test/unit/dockerfile_from_inspect.spec.js b/test/unit/dockerfile_from_inspect.spec.js index 7c361e1..e4efef3 100644 --- a/test/unit/dockerfile_from_inspect.spec.js +++ b/test/unit/dockerfile_from_inspect.spec.js @@ -1,12 +1,13 @@ 'use strict'; -var should = require('should'), +const assert = require('node:assert/strict'), + { describe, it } = require('node:test'), commandsFromInspect = require('../../lib/inspect-to-dockerfile').commandsFromInspect; -describe('Commands from Inspect function', function () { +describe('Commands from Inspect function', function() { - it('correctly parses labels', function () { - var inspect = { + it('correctly parses labels', function() { + const inspect = { Config: { "Labels": { "Authoritative_Registry": "registry.redhat.com", @@ -15,28 +16,29 @@ describe('Commands from Inspect function', function () { } } }; - var config = JSON.stringify(inspect); - var commands = commandsFromInspect(config); - commands.length.should.eql(1); - commands[0].name.should.eql('LABEL'); - commands[0].args.should.eql(inspect.Config.Labels); + const config = JSON.stringify(inspect); + const commands = commandsFromInspect(config); + assert.strictEqual(commands.length, 1); + assert.strictEqual(commands[0].name, 'LABEL'); + assert.deepStrictEqual(commands[0].args, inspect.Config.Labels); }); - it('correctly parses user', function () { - var inspect ={Config: {"User": "root"}}; - var config = JSON.stringify(inspect); - var commands = commandsFromInspect(config); - commands.length.should.eql(1); - commands[0].name.should.eql('USER'); - commands[0].args.should.eql('root'); + + it('correctly parses user', function() { + const inspect = { Config: { "User": "root" } }; + const config = JSON.stringify(inspect); + const commands = commandsFromInspect(config); + assert.strictEqual(commands.length, 1); + assert.strictEqual(commands[0].name, 'USER'); + assert.strictEqual(commands[0].args, 'root'); }); - it('correctly parses maintainer', function () { - var inspect ={Author:"test@example.com"}; - var config = JSON.stringify(inspect); - var commands = commandsFromInspect(config); - commands.length.should.eql(1); - commands[0].name.should.eql('MAINTAINER'); - commands[0].args.should.eql('test@example.com'); + it('correctly parses maintainer', function() { + const inspect = { Author: "test@example.com" }; + const config = JSON.stringify(inspect); + const commands = commandsFromInspect(config); + assert.strictEqual(commands.length, 1); + assert.strictEqual(commands[0].name, 'MAINTAINER'); + assert.strictEqual(commands[0].args, 'test@example.com'); }); }); diff --git a/test/unit/linter-utils.spec.js b/test/unit/linter-utils.spec.js index ed33a64..3b517fc 100644 --- a/test/unit/linter-utils.spec.js +++ b/test/unit/linter-utils.spec.js @@ -1,250 +1,253 @@ 'use strict'; -require('should'); - -var utils = require('../../lib/linter-utils'); - - +// const assert = require('node:assert/strict'), +// { describe, it } = require('node:test'), +// utils = require('../../lib/linter-utils'); +// +// function assertObject(obj) { +// assert.ok(obj !== null, 'Expected object to be non-null'); +// assert.strictEqual(typeof obj, 'object', 'Expected type of object to be "object"'); +// } // // describe('createReqInstructionHash function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels.bind(null, labels); +// console.log(obj); +// }); // }); // // describe('createRequiredLabelsHash function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('initLineRulesRegexes function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('checkRequiredInstructions function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // // describe('checkRequiredNameVals function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // // describe('checkLineRules function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // // describe('createValidCommandRegex function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('findKeyValRule function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('addResult function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('addError function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('validateNameValRule function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); // // describe('validateLabels function', function() { -// it('should parse a multiple label string', function() { -// var labels = "vendor=devif"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should parse a single label string', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// obj.should.be.an.Object; -// console.log(obj); -// }); -// it('should throw an exception when the label string is invalid', function() { -// var labels = "vendor=lindani phiri vendor2=lindai zulu"; -// var obj = utils.parseLabels(labels); -// console.log(obj); -// }); +// it('should parse a multiple label string', function() { +// const labels = "vendor=devif"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should parse a single label string', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// assertObject(obj); +// console.log(obj); +// }); +// it('should throw an exception when the label string is invalid', function() { +// const labels = "vendor=lindani phiri vendor2=lindai zulu"; +// const obj = utils.parseLabels(labels); +// console.log(obj); +// }); // }); diff --git a/test/unit/linter.spec.js b/test/unit/linter.spec.js index bb92758..38f5780 100644 --- a/test/unit/linter.spec.js +++ b/test/unit/linter.spec.js @@ -1,6 +1,7 @@ 'use strict'; -require('should'); +// const assert = require('node:assert/strict'), +// { describe, it } = require('node:test'); // it('Should allow underscores', function() {; diff --git a/test/unit/parser.spec.js b/test/unit/parser.spec.js index 14b9f23..3a1caf3 100644 --- a/test/unit/parser.spec.js +++ b/test/unit/parser.spec.js @@ -1,15 +1,15 @@ 'use strict'; -require('should'); +const assert = require('node:assert/strict'), + { describe, it } = require('node:test'), + parser = require('../../lib/parser'); -var parser = require('../../lib/parser'); - -describe('parse function', function () { - it('should correctly parse comments', function () { - var options = { +describe('parse function', function() { + it('should correctly parse comments', function() { + const options = { includeComments: true }; - var contents = 'FROM ubuntu:latest\n' + const contents = 'FROM ubuntu:latest\n' + '#Comment1\n' + 'RUN echo done\n' + ' \n' //should ignore spaces @@ -20,87 +20,96 @@ describe('parse function', function () { + '#Comment3 \n' + "LABEL two=3 'one two'=4"; - var commands = parser.parse(contents, options); - commands.length.should.eql(7); //one less because of continuation line - commands[1].name.should.eql('COMMENT'); - commands[1].args.should.eql('#Comment1'); - commands[3].name.should.eql('LABEL'); - commands[3].args.should.eql({ + const commands = parser.parse(contents, options); + // one less because of continuation line + assert.strictEqual(commands.length, 7); + assert.strictEqual(commands[1].name, 'COMMENT'); + assert.strictEqual(commands[1].args, '#Comment1'); + assert.strictEqual(commands[3].name, 'LABEL'); + // handle comments inside continuation line + assert.deepStrictEqual(commands[3].args, { RUN: 'docker run -it --rm --privileged -v `pwd`:/root/ --name NAME -e NAME=NAME -e IMAGE=IMAGE IMAGE dockerfile_lint -f Dockerfile' - }); //handle comments inside continuation line - commands[4].name.should.eql('COMMENT'); - commands[4].args.should.eql('#Comment2'); - commands[5].name.should.eql('COMMENT'); - commands[5].args.should.eql('#Comment3'); + }); + assert.strictEqual(commands[4].name, 'COMMENT'); + assert.strictEqual(commands[4].args, '#Comment2'); + assert.strictEqual(commands[5].name, 'COMMENT'); + assert.strictEqual(commands[5].args, '#Comment3'); }); - it('should correctly strip out comments when asked to', function () { - var options = { + it('should correctly strip out comments when asked to', function() { + const options = { includeComments: false }; - var contents = 'FROM ubuntu:latest\n' + const contents = 'FROM ubuntu:latest\n' + '#Comment1\n' + 'RUN echo done\n' + "LABEL two=3 'one two'=4 three=" + '#Comment2\n' + '#Comment3 \n'; - var commands = parser.parse(contents, options); - commands.length.should.eql(3); + const commands = parser.parse(contents, options); + assert.strictEqual(commands.length, 3); }); - it('should correctly ignore commands preceeded by an inline ignore', function () { - var options = { + it('should correctly ignore commands preceded by an inline ignore', function() { + const options = { includeComments: false }; - var contents = 'FROM ubuntu:latest\n' + const contents = 'FROM ubuntu:latest\n' + '#Comment1\n' + '# dockerfile_lint - ignore\n' + 'RUN echo done\n' + "LABEL two=3 'one two'=4 three=" + '#Comment2\n' + '#Comment3 \n'; - var commands = parser.parse(contents, options); - commands.length.should.eql(2); + const commands = parser.parse(contents, options); + assert.strictEqual(commands.length, 2); }); - it('should not ignore commands preceeded by an comment about the inline ignore functionality', function () { - var options = { + it('should not ignore commands preceded by a comment about the inline ignore functionality', function() { + const options = { includeComments: false }; - var contents = 'FROM ubuntu:latest\n' + const contents = 'FROM ubuntu:latest\n' + '#Comment1\n' + '# dockerfile_lint comment about inline ignore\n' + 'RUN echo done\n' + "LABEL two=3 'one two'=4 three=" + '#Comment2\n' + '#Comment3 \n'; - var commands = parser.parse(contents, options); - commands.length.should.eql(3); + const commands = parser.parse(contents, options); + assert.strictEqual(commands.length, 3); }); - it('should correctly report errors', function () { - var options = { + describe('given a line with an invalid LABEL', function() { + const options = { includeComments: false }; - var contents = 'FROM ubuntu:latest\n' - + '#Comment1\n' - + 'RUN echo done\n' - + "LABEL two4"; //Invalid label - var commands = parser.parse(contents, options); - commands[2].should.have.property('error'); - commands[2].error.should.equal('LABEL must have two arguments, got two4'); - contents = 'FROM ubuntu:latest\n' - + '#Comment1\n' - + 'RUN echo done\n' - + "LABEL two4\n" //Invalid label - + "LABEL two=2"; //Valid label - commands = parser.parse(contents, options); - commands[2].should.have.property('error'); - commands[3].should.not.have.property('error'); + it('should report error for that command', function() { + const contents = 'FROM ubuntu:latest\n' + + '#Comment1\n' + + 'RUN echo done\n' + + "LABEL two4"; //Invalid label + const commands = parser.parse(contents, options); + assert.ok(Object.hasOwn(commands[2], 'error')); + assert.strictEqual(commands[2].error, 'LABEL must have two arguments, got two4'); + + }); + + it('should not report error for a valid LABEL following it', function() { + const contents = 'FROM ubuntu:latest\n' + + '#Comment1\n' + + 'RUN echo done\n' + + "LABEL two4\n" //Invalid label + + "LABEL two=2"; //Valid label + const commands = parser.parse(contents, options); + assert.ok(Object.hasOwn(commands[2], 'error')); + assert.ok(!Object.hasOwn(commands[3], 'error')); + + }); }); diff --git a/test/unit/rulefile-loader.spec.js b/test/unit/rulefile-loader.spec.js index c92219b..cad76c6 100644 --- a/test/unit/rulefile-loader.spec.js +++ b/test/unit/rulefile-loader.spec.js @@ -1,50 +1,59 @@ 'use strict'; -var should =require('should'), - fs = require('fs'), +const assert = require('node:assert/strict'), + fs = require('node:fs'), + path = require('node:path'), + { describe, it } = require('node:test'), loadRules = require('../../lib/rulefile-loader').load; -function loadJsonObject(filename){ - var obj = JSON.parse(fs.readFileSync(filename,'utf8')); +function loadJsonObject(filename) { + var obj = JSON.parse(fs.readFileSync(filename, 'utf8')); return obj; } -describe('rule file loader function', function () { +describe('rule file loader function', function() { - it.skip('should throw an error when and incorrect rule specification is provided', function () { + const repoDir = path.dirname(path.dirname(__dirname)); + + it.skip('should throw an error when and incorrect rule specification is provided', function() { //Not implemented yet }); - it('should throw an error when there is a cyclic dependency', function () { - loadRules.bind(null,'./test/data/rules/loader_test_include_cyclic.yaml').should.throw(); + it('should throw an error when there is a cyclic dependency', function() { + assert.throws( + loadRules.bind(null, './test/data/rules/loader_test_include_cyclic.yaml') + ); }); - it('should throw an error when a non-existent rule file is provided', function () { - loadRules.bind(null,'./test/data/rules/yoda.yaml').should.throw(); - + it('should throw an error when a non-existent rule file is provided', function() { + assert.throws( + loadRules.bind(null, './test/data/rules/yoda.yaml') + ); }); - it('should throw an error when an included file is not found', function () { - loadRules.bind(null,'./test/data/rules/loader_test_include_non_exist.yaml').should.throw(); + it('should throw an error when an included file is not found', function() { + assert.throws( + loadRules.bind(null, './test/data/rules/loader_test_include_non_exist.yaml') + ); }); - it('should correctly parse a rule file with multiple includes', function () { - var rules = loadRules('./test/data/rules/loader_test_combine_main.yaml'); - var expected = loadJsonObject('./test/data/rules/loader_test_combine_main.expected.json'); - should.deepEqual(rules, expected); + it('should correctly parse a rule file with multiple includes', function() { + const rules = loadRules('./test/data/rules/loader_test_combine_main.yaml'); + const expected = loadJsonObject('./test/data/rules/loader_test_combine_main.expected.json'); + assert.deepStrictEqual(rules, expected); }); - it('should correctly load a rule file with an include chain', function () { + it('should correctly load a rule file with an include chain', function() { // // We need to verify this : file B includes file A, file C includes file B, then loading // file C should load rules in the order A -> B -> C, with B overriding in values in A // and C overriding values in both A and B // - var rules = loadRules('./test/data/rules/loader_test_include_chain.yaml'); - var expected = loadJsonObject('./test/data/rules/loader_test_include_chain.expected.json'); - should.deepEqual(rules, expected); + const rules = loadRules('./test/data/rules/loader_test_include_chain.yaml'); + const expected = loadJsonObject('./test/data/rules/loader_test_include_chain.expected.json'); + assert.deepStrictEqual(rules, expected); }); });