cfpathcheck
Advanced tools
Comparing version 3.0.6 to 3.1.0
@@ -5,2 +5,18 @@ # Change Log | ||
## [3.1.0] - 2019-12-14 | ||
### Added | ||
- xo linter | ||
- prettierrc.yaml config | ||
- nodejs v13 support | ||
- unit tests (using mocha and chai) | ||
### Updated | ||
- chalk@3.0.0 | ||
- glob@7.1.6 | ||
- prettier@1.19.1 | ||
- snyk@1.260.0 | ||
### Removed | ||
- eslint | ||
## [3.0.6] - 2019-10-13 | ||
@@ -215,2 +231,3 @@ ### Updated | ||
[3.1.0]: https://github.com/timbeadle/cfpathcheck/compare/3.0.6...3.1.0 | ||
[3.0.6]: https://github.com/timbeadle/cfpathcheck/compare/3.0.5...3.0.6 | ||
@@ -217,0 +234,0 @@ [3.0.5]: https://github.com/timbeadle/cfpathcheck/compare/3.0.4...3.0.5 |
@@ -1,3 +0,1 @@ | ||
/*global module, require */ | ||
'use strict'; | ||
@@ -8,37 +6,8 @@ | ||
const glob = require('glob'); | ||
const _ = require('lodash'); | ||
const checkstyleFormatter = require('checkstyle-formatter'); | ||
const chalk = require('chalk'); | ||
const logSymbols = require('log-symbols'); | ||
const utils = require('./utils'); | ||
/** | ||
* Uses lodash isEqual to perform non-strict object comparison. | ||
* | ||
* @see http://stackoverflow.com/a/4587130/167987 | ||
* @param {object} obj - The object to search for. | ||
* @param {Array} list - The array of objects to search. | ||
*/ | ||
const containsObject = (obj, list) => { | ||
for (let i = 0; i < list.length; i += 1) { | ||
if (_.isEqual(list[i], obj)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
/** | ||
* @param {string} line - The file line to check for an XML file prolog. | ||
*/ | ||
const checkIsXMLFile = (line) => { | ||
const XMLSearch = line.match(/(<\?xml|type="text\/xml)/); | ||
let isXMLFile = false; | ||
if (XMLSearch !== null) { | ||
isXMLFile = true; | ||
} | ||
return isXMLFile; | ||
}; | ||
/** | ||
* Compares two arrays of cfml taglib prefixes to see if there are any mismatches. | ||
@@ -57,3 +26,5 @@ * | ||
prefixArray1.forEach((value) => { | ||
if (!prefixedViolations.hasOwnProperty(value.prefix)) { | ||
if ( | ||
!Object.prototype.hasOwnProperty.call(prefixedViolations, value.prefix) | ||
) { | ||
prefixedViolations[value.prefix] = []; | ||
@@ -67,11 +38,10 @@ } | ||
if (value.prefix !== value2.prefix) { | ||
if (value.prefix === value2.prefix) { | ||
prefixManifest[value.prefix] = true; | ||
} else if ( | ||
!Object.prototype.hasOwnProperty.call(prefixManifest, value.prefix) || | ||
!prefixManifest[value.prefix] | ||
) { | ||
// Don't override a true value with false - true is sticky | ||
if (!prefixManifest.hasOwnProperty(value.prefix) || | ||
!prefixManifest[value.prefix] | ||
) { | ||
prefixManifest[value.prefix] = false; | ||
} | ||
} else { | ||
prefixManifest[value.prefix] = true; | ||
prefixManifest[value.prefix] = false; | ||
} | ||
@@ -83,8 +53,6 @@ | ||
message: formattedMessage, | ||
severity: severity | ||
severity, | ||
}; | ||
// console.log(prefixedViolations[value.prefix]); | ||
if (!containsObject(messageObj, prefixedViolations[value.prefix])) { | ||
if (!utils.containsObject(messageObj, prefixedViolations[value.prefix])) { | ||
prefixedViolations[value.prefix].push(messageObj); | ||
@@ -100,5 +68,5 @@ } | ||
message: formattedMessage, | ||
severity: severity | ||
severity, | ||
}; | ||
if (!containsObject(messageObj, prefixedViolations[value.prefix])) { | ||
if (!utils.containsObject(messageObj, prefixedViolations[value.prefix])) { | ||
prefixedViolations[value.prefix].push(messageObj); | ||
@@ -111,3 +79,3 @@ } | ||
for (const prefix in prefixManifest) { | ||
if (prefixManifest.hasOwnProperty(prefix)) { | ||
if (Object.prototype.hasOwnProperty.call(prefixManifest, prefix)) { | ||
if (prefixManifest[prefix]) { | ||
@@ -124,29 +92,11 @@ delete prefixedViolations[prefix]; | ||
return violations; | ||
} | ||
}; | ||
/** | ||
* @param {string} str - The string to match. | ||
* @param {RegExp} regex - The RegExp to use. | ||
* @param {string} filePath | ||
*/ | ||
const matchAll = (str, regex) => { | ||
const res = []; | ||
let m; | ||
if (regex.global) { | ||
while ((m = regex.exec(str))) { | ||
res.push(m); | ||
} | ||
} else { | ||
if ((m = regex.exec(str))) { | ||
res.push(m); | ||
} | ||
} | ||
return res; | ||
const readFile = (filePath) => { | ||
return fs.readFileSync(filePath, 'utf8').replace(/\r\n/, '\n'); | ||
}; | ||
const readFile = (filePath) => { | ||
return fs | ||
.readFileSync(filePath, 'utf8') | ||
.replace(/\r\n/, '\n'); | ||
} | ||
/** | ||
@@ -170,9 +120,6 @@ * @param {string} filePath - The path of the file to check. | ||
lines.forEach((line) => { | ||
// console.log('Line from file:', line); | ||
isXMLFile = utils.checkIsXMLFile(line); | ||
isXMLFile = checkIsXMLFile(line); | ||
// Exclude @usage doc lines including code snippets | ||
const isUsageLine = line.match(/^@usage/) !== null; | ||
const isUsageLine = line.startsWith('@usage'); | ||
@@ -182,12 +129,10 @@ const importSearch = line.match(/prefix=["']([A-Za-z0-9]+)["']/); | ||
if (importSearch !== null) { | ||
// console.log(importSearch); | ||
prefixes.push({ | ||
prefix: importSearch[1], | ||
line: lineNumber, | ||
column: importSearch.index + 1 | ||
column: importSearch.index + 1, | ||
}); | ||
} | ||
const namespaceSearch = matchAll(line, /<([A-Za-z0-9]+):/g); | ||
// console.log(namespaceSearch); | ||
const namespaceSearch = utils.matchAll(line, /<([A-Za-z0-9]+):/g); | ||
@@ -200,3 +145,3 @@ // We're outputting an XML file - don't attempt to collate namespace prefix usages | ||
line: lineNumber, | ||
column: value.index + 1 | ||
column: value.index + 1, | ||
}); | ||
@@ -206,3 +151,3 @@ }); | ||
const taglibMatches = matchAll(line, /taglib=["']([^"']+)["']/g); | ||
const taglibMatches = utils.matchAll(line, /taglib=["']([^"']+)["']/g); | ||
@@ -214,2 +159,3 @@ taglibMatches.forEach((taglibMatch) => { | ||
} | ||
if (!fs.existsSync(taglibPath)) { | ||
@@ -220,3 +166,3 @@ taglibPathViolations.push({ | ||
message: `cfimport taglib path ${taglibPath} not found`, | ||
severity: 'error' | ||
severity: 'error', | ||
}); | ||
@@ -226,11 +172,9 @@ } | ||
// <cfinclude template="$path" /> | ||
const cfIncludeMatches = matchAll(line, /template=["']([^"']+)["']/g); | ||
// Checks <cfinclude template="$path" /> | ||
const cfIncludeMatches = utils.matchAll(line, /template=["']([^"']+)["']/g); | ||
// include '$path'; (inside <cfscript>) | ||
const includeMatches = matchAll(line, /\binclude\s['"](.*\.cfm)['"]/g); | ||
// Checks include '$path'; (inside <cfscript>) | ||
const includeMatches = utils.matchAll(line, /\binclude\s['"](.*\.cfm)['"]/g); | ||
cfIncludeMatches.concat(includeMatches).forEach((includeMatch) => { | ||
// console.log(includeMatch); | ||
// Dynamic path (contains # or &): all we can check is the non-dynamic part, | ||
@@ -242,9 +186,9 @@ // wound back to the last slash | ||
if (hashPos !== -1 || ampersandPos !== -1) { | ||
const searchPos = hashPos !== -1 ? hashPos : ampersandPos; | ||
const searchPos = hashPos === -1 ? ampersandPos : hashPos; | ||
const lastSlashPos = templatePath.lastIndexOf('/', searchPos); | ||
templatePath = path.dirname(templatePath.substr(0, lastSlashPos)); | ||
templatePath = path.dirname(templatePath.slice(0, lastSlashPos)); | ||
} | ||
// Can't work with webroot-virtual paths, e.g. /missing.cfm | ||
if (templatePath.substr(0, 1) !== '/') { | ||
if (templatePath.slice(0, 1) !== '/') { | ||
if (!path.isAbsolute(templatePath)) { | ||
@@ -260,3 +204,3 @@ // Resolve the templatePath relative to the dirname of the including file | ||
message: `cfinclude/include template path ${templatePath} not found`, | ||
severity: 'error' | ||
severity: 'error', | ||
}); | ||
@@ -308,9 +252,10 @@ } | ||
// (Add a trailing slash if not present) | ||
if (filePath.substr(-1) !== '/') { | ||
if (filePath.slice(-1) !== '/') { | ||
filePath += '/'; | ||
} | ||
fileNames = glob.sync(`${filePath}**/*.cfm`, { | ||
ignore: ['**/WEB-INF/**', '**/node_modules/**'] | ||
ignore: ['**/WEB-INF/**', '**/node_modules/**'], | ||
}); | ||
} catch (e) { | ||
} catch (_) { | ||
// ...if that fails, it's a file, not a directory | ||
@@ -320,89 +265,95 @@ fileNames = [filePath]; | ||
} | ||
return fileNames; | ||
}; | ||
/** | ||
* @param {string} filePath - The full path of the file to check. | ||
*/ | ||
const check = (filePath) => { | ||
const violations = []; | ||
const fileNames = getFiles(filePath); | ||
module.exports = { | ||
/** | ||
* @param {string} filePath - The full path of the file to check. | ||
*/ | ||
check: (filePath) => { | ||
const violations = []; | ||
const fileNames = getFiles(filePath); | ||
// console.log(fileNames); | ||
// Loop over our file list, checking each file | ||
fileNames.forEach((fileName) => { | ||
const fileViolations = checkFile(fileName); | ||
// Loop over our file list, checking each file | ||
fileNames.forEach((fileName) => { | ||
const fileViolations = checkFile(fileName); | ||
// console.log(fileViolations); | ||
if (fileViolations.length > 0) { | ||
violations.push({ | ||
filename: fileName, | ||
messages: fileViolations | ||
}); | ||
} | ||
}); | ||
if (fileViolations.length > 0) { | ||
violations.push({ | ||
filename: fileName, | ||
messages: fileViolations, | ||
}); | ||
} | ||
}); | ||
// console.log(violations); | ||
return violations; | ||
}; | ||
return violations; | ||
}, | ||
/** | ||
* @param {Array} violations - The violations array. | ||
* @param {string} format - The output format to use. | ||
*/ | ||
const formatter = (violations, format) => { | ||
let output; | ||
if (format === 'checkstyle') { | ||
output = checkstyleFormatter(violations); | ||
} else { | ||
output = violations; | ||
} | ||
/** | ||
* @param {Array} violations - The violations array. | ||
* @param {string} format - The output format to use. | ||
*/ | ||
formatter: (violations, format) => { | ||
let output; | ||
if (format === 'checkstyle') { | ||
output = checkstyleFormatter(violations); | ||
} else { | ||
output = violations; | ||
} | ||
return output; | ||
}, | ||
return output; | ||
}; | ||
/** | ||
* @param {string} output - The file contents to write. | ||
* @param {string} outFile - The file to write to. | ||
*/ | ||
writeFile: (output, outFile) => { | ||
// Resolve the path if it's not absolute | ||
if (!path.isAbsolute(outFile)) { | ||
outFile = path.resolve(outFile); | ||
} | ||
/** | ||
* @param {string} output - The file contents to write. | ||
* @param {string} outFile - The file to write to. | ||
*/ | ||
const writeFile = (output, outFile) => { | ||
// Resolve the path if it's not absolute | ||
if (!path.isAbsolute(outFile)) { | ||
outFile = path.resolve(outFile); | ||
} | ||
// Warn that the target directory doesn't exist | ||
if (!fs.existsSync(path.dirname(outFile))) { | ||
// fs.mkdirSync(path.dirname(outFile)); | ||
console.warn( | ||
`Cannot write ${outFile}. Destination directory doesn't exist` | ||
); | ||
} else { | ||
fs.writeFileSync(outFile, output, 'utf8'); | ||
} | ||
}, | ||
// Warn that the target directory doesn't exist | ||
if (fs.existsSync(path.dirname(outFile))) { | ||
fs.writeFileSync(outFile, output, 'utf8'); | ||
} else { | ||
console.warn( | ||
`Cannot write ${outFile}. Destination directory doesn't exist` | ||
); | ||
} | ||
}; | ||
/** | ||
* @param {string|Array} output - The output to write. | ||
*/ | ||
writeOutput: (output) => { | ||
if (output instanceof Array) { | ||
output.forEach((violation) => { | ||
console.log(`File: ${chalk.green(violation.filename)}`); | ||
violation.messages.forEach((message) => { | ||
let messageText = `L${message.line}:${message.column} - ${message.message}`; | ||
if (message.severity === 'error') { | ||
messageText = chalk.red(messageText); | ||
} else if (message.severity === 'warning') { | ||
messageText = chalk.yellow(messageText); | ||
} | ||
/** | ||
* @param {string|Array} output - The output to write. | ||
*/ | ||
const writeOutput = (output) => { | ||
if (Array.isArray(output)) { | ||
output.forEach((violation) => { | ||
console.log(`File: ${chalk.green(violation.filename)}`); | ||
violation.messages.forEach((message) => { | ||
let messageText = `L${message.line}:${message.column} - ${message.message}`; | ||
if (message.severity === 'error') { | ||
messageText = chalk.red(messageText); | ||
} else if (message.severity === 'warning') { | ||
messageText = chalk.yellow(messageText); | ||
} | ||
console.log(' ', logSymbols[message.severity], messageText); | ||
}); | ||
console.log(' ', logSymbols[message.severity], messageText); | ||
}); | ||
} else { | ||
console.log(output); | ||
} | ||
}); | ||
} else { | ||
console.log(output); | ||
} | ||
}; | ||
module.exports = { | ||
comparePrefixArrays, | ||
check, | ||
checkFile, | ||
formatter, | ||
getFiles, | ||
readFile, | ||
writeFile, | ||
writeOutput, | ||
}; |
{ | ||
"name": "cfpathcheck", | ||
"xo": { | ||
"env": [ | ||
"node" | ||
], | ||
"prettier": true | ||
}, | ||
"description": "Check CFML files for correct paths in cfinclude/cfimport tags", | ||
"version": "3.0.6", | ||
"version": "3.1.0", | ||
"homepage": "https://github.com/timbeadle/cfpathcheck", | ||
@@ -39,4 +45,7 @@ "author": { | ||
"scripts": { | ||
"test": "snyk test --dev && npm run lint", | ||
"lint": "eslint --config .eslintrc.yml lib/cfpathcheck.js bin/cfpathcheck", | ||
"test": "snyk test && npm run test:snyk && npm run test:lint && npm run test:unit", | ||
"test:coverage": "nyc --reporter=lcov npm run test:unit", | ||
"test:lint": "xo lib/cfpathcheck.js bin/cfpathcheck", | ||
"test:snyk": "snyk test --dev", | ||
"test:unit": "mocha test/*.spec.js", | ||
"snyk-protect": "snyk protect", | ||
@@ -46,20 +55,19 @@ "prepare": "npm run snyk-protect" | ||
"dependencies": { | ||
"chalk": "^2.4.2", | ||
"chalk": "^3.0.0", | ||
"checkstyle-formatter": "^1.1.0", | ||
"crlf": "^1.1.0", | ||
"glob": "^7.1.4", | ||
"glob": "^7.1.6", | ||
"lodash": "^4.17.15", | ||
"log-symbols": "^3.0.0", | ||
"minimist": "^1.2.0", | ||
"snyk": "^1.234.2" | ||
"snyk": "^1.260.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^6.5.1", | ||
"eslint-config-prettier": "^6.4.0", | ||
"eslint-plugin-jsdoc": "^15.11.0", | ||
"eslint-plugin-node": "^10.0.0", | ||
"eslint-plugin-prettier": "^3.1.1", | ||
"prettier": "^1.18.2" | ||
"chai": "^4.2.0", | ||
"mocha": "^6.2.2", | ||
"nyc": "^14.1.1", | ||
"prettier": "^1.19.1", | ||
"xo": "^0.25.3" | ||
}, | ||
"snyk": true | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
142790
5
24
846
1
+ Addedansi-styles@4.3.0(transitive)
+ Addedchalk@3.0.0(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedsupports-color@7.2.0(transitive)
Updatedchalk@^3.0.0
Updatedglob@^7.1.6
Updatedsnyk@^1.260.0