Socket
Socket
Sign inDemoInstall

cfpathcheck

Package Overview
Dependencies
Maintainers
0
Versions
76
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cfpathcheck - npm Package Compare versions

Comparing version 10.0.2 to 10.1.0

dist/core.d.ts

2

bin/cli.js

@@ -28,3 +28,3 @@ #!/usr/bin/env node

*/
const violations = check(file, 'json');
const violations = check(file);
const output = formatter(violations, reporter);

@@ -31,0 +31,0 @@

@@ -5,2 +5,32 @@ # Change Log

## [10.1.0] - 2024-07-30
### Added
- NodeJS v22 test run.
- fixtures/test-script.cfm, for testing cfscript syntax imports.
- rimraf package, to clean up the `dist` folder before building ts type files.
- tsconfig.json: `"moduleResolution": "Node"`
### Updated
- Internal rewrite, splitting the monolithic cfpathcheck.js module into more focused, smaller modules.
- The external API hasn't changed, however, so this is only a minor version increment.
- package.json: engines.node: 18 -> 18.20.3
- @snyk/protect@1.1292.1
- @types/chai@4.3.16
- @types/mocha@10.0.7
- @types/node@22.0.0
- chai@5.1.1
- eslint-config-xo@0.45.0
- glob@10.4.5
- ls-engines@0.9.2
- mocha@10.7.0
- npm-run-all2@6.2.2
- nyc@17.0.0
- prettier@3.3.3
- typescript@5.5.4
- (volta) node@18.20.3
- (volta) npm@10.8.2
### Removed
- Unnecessary `format` argument in the call to the `check(file)` function.
## [10.0.2] - 2024-03-16

@@ -644,3 +674,4 @@ ### Updated

[10.0.1]: https://github.com/timbeadle/cfpathcheck/compare/10.0.1...10.0.2
[10.1.0]: https://github.com/timbeadle/cfpathcheck/compare/10.0.2...10.1.0
[10.0.2]: https://github.com/timbeadle/cfpathcheck/compare/10.0.1...10.0.2
[10.0.1]: https://github.com/timbeadle/cfpathcheck/compare/10.0.0...10.0.1

@@ -647,0 +678,0 @@ [10.0.0]: https://github.com/timbeadle/cfpathcheck/compare/9.0.0...10.0.0

@@ -1,9 +0,11 @@

export function comparePrefixArrays(prefixArray1: Array<string>, prefixArray2: Array<string>, message: string, severity: string): Array<object>;
export function readFile(filePath: string): string;
export function checkFile(filePath: string): Array<object>;
export function getFiles(filePath: string): Array<string>;
export function check(filePath: string): Array<object>;
export function formatter(violations: Array<object>, format: string): string | Array<object>;
export function writeFile(output: string, outFile: string): void;
export function writeOutput(output: string | Array<object>): void;
import { check } from './core.js';
import { checkFile } from './core.js';
import { comparePrefixArrays } from './core.js';
import { formatMessageText } from './format.js';
import { formatter } from './format.js';
import { getFiles } from './file.js';
import { readFile } from './file.js';
import { writeFile } from './file.js';
import { writeOutput } from './format.js';
export { check, checkFile, comparePrefixArrays, formatMessageText, formatter, getFiles, readFile, writeFile, writeOutput };
//# sourceMappingURL=cfpathcheck.d.ts.map
export function containsObject(targetObject: object, list: Array<object>): boolean;
export function checkIsXMLFile(line: string): boolean;
export function matchAll(matchString: string, regex: RegExp): RegExpExecArray | any[];
export function normalisePath(filePath: string): string;
//# sourceMappingURL=utils.d.ts.map

@@ -1,342 +0,7 @@

import {
readFileSync, existsSync, readdirSync, writeFileSync,
} from 'fs';
import path from 'path';
import { sync } from 'glob';
import checkstyleFormatter from 'checkstyle-formatter';
import chalk from 'chalk';
import logSymbols from 'log-symbols';
import { containsObject, checkIsXMLFile, matchAll } from './utils.js';
import { check, checkFile, comparePrefixArrays } from './core.js';
import { getFiles, readFile, writeFile } from './file.js';
import { formatMessageText, formatter, writeOutput } from './format.js';
/**
* Compares two arrays of cfml taglib prefixes to see if there are any mismatches.
*
* @param {Array<string>} prefixArray1 - The first array of taglib prefixes.
* @param {Array<string>} prefixArray2 - The second array of taglib prefixes.
* @param {string} message - The message to display in case of a violation.
* @param {string} severity - The violation severity.
*
* @returns {Array<object>}
*/
export const comparePrefixArrays = (prefixArray1, prefixArray2, message, severity) => {
const prefixedViolations = {};
const prefixManifest = {};
const violations = [];
for (const value of prefixArray1) {
if (
!Object.hasOwn(prefixedViolations, value.prefix)
) {
prefixedViolations[value.prefix] = [];
}
const formattedMessage = message.replace('{2}', value.prefix);
for (const value2 of prefixArray2) {
// Key not found
if (value.prefix === value2.prefix) {
prefixManifest[value.prefix] = true;
} else if (
!Object.hasOwn(prefixManifest, value.prefix)
|| !prefixManifest[value.prefix]
) {
// Don't override a true value with false - true is sticky
prefixManifest[value.prefix] = false;
}
const messageObject = {
line: value.line,
column: value.column || 1,
message: formattedMessage,
severity,
};
if (!containsObject(messageObject, prefixedViolations[value.prefix])) {
prefixedViolations[value.prefix].push(messageObject);
}
}
if (prefixArray2.length === 0) {
prefixManifest[value.prefix] = false;
const messageObject = {
line: value.line,
column: value.column || 1,
message: formattedMessage,
severity,
};
if (!containsObject(messageObject, prefixedViolations[value.prefix])) {
prefixedViolations[value.prefix].push(messageObject);
}
}
}
// Delete the array of messages for prefix keys that *were* found
for (const prefix in prefixManifest) {
if (Object.hasOwn(prefixManifest, prefix)) {
if (prefixManifest[prefix]) {
delete prefixedViolations[prefix];
} else {
for (const value of prefixedViolations[prefix]) {
violations.push(value);
}
}
}
}
return violations;
export {
check, checkFile, comparePrefixArrays, formatMessageText, formatter, getFiles, readFile, writeFile, writeOutput,
};
/**
* Reads a file from the filesystem and normalises its line endings.
*
* @param {string} filePath
*
* @returns {string}
*/
export const readFile = (filePath) => readFileSync(filePath, 'utf8').replace(/\r\n/, '\n');
/**
* Checks a file for missing paths.
*
* @param {string} filePath - The path of the file to check.
*
* @returns {Array<object>}
*/
export const checkFile = (filePath) => {
const templatePathViolations = [];
const taglibPathViolations = [];
const prefixes = [];
const prefixUsages = [];
let isXMLFile = false;
let lineNumber = 1;
const lines = readFile(filePath).split('\n');
// Cache the dirname of the file being analysed
const fileDirname = path.dirname(filePath);
for (const line of lines) {
isXMLFile = checkIsXMLFile(line);
// Exclude @usage doc lines including code snippets
const isUsageLine = line.startsWith('@usage');
const importSearch = line.match(/prefix=["'](?<import>[A-Za-z\d]+)["']/);
if (importSearch !== null) {
prefixes.push({
prefix: importSearch.groups.import,
line: lineNumber,
column: importSearch.index + 1,
});
}
const namespaceSearch = matchAll(line, /<(?<namespace>[A-Za-z\d]+):/g);
// We're outputting an XML file - don't attempt to collate namespace prefix usages
if (!isXMLFile && !isUsageLine) {
for (const value of namespaceSearch) {
prefixUsages.push({
prefix: value.groups.namespace,
line: lineNumber,
column: value.index + 1,
});
}
}
const taglibMatches = matchAll(line, /taglib=["'](?<taglib>[^"']+)["']/g);
for (const taglibMatch of taglibMatches) {
let taglibPath = taglibMatch.groups.taglib;
if (!path.isAbsolute(taglibPath)) {
taglibPath = path.resolve(fileDirname, taglibPath);
}
if (!existsSync(taglibPath)) {
taglibPathViolations.push({
line: lineNumber,
column: taglibMatch.index + 1,
message: `cfimport taglib path ${taglibPath} not found`,
severity: 'error',
});
}
}
// Checks <cfinclude template="$path" />
const cfIncludeMatches = matchAll(line, /template=["'](?<path>[^"']+)["']/g);
// Checks include '$path'; (inside <cfscript>)
// @TODO fix vulnerable RegExp
// eslint-disable-next-line redos/no-vulnerable
const includeMatches = matchAll(line, /\binclude\s['"](?<path>.*\.cfm)['"]/g);
for (const includeMatch of [...cfIncludeMatches, ...includeMatches]) {
// Dynamic path (contains # or &): all we can check is the non-dynamic part,
// wound back to the last slash
let templatePath = includeMatch.groups.path;
const hashPos = templatePath.indexOf('#');
const ampersandPos = templatePath.indexOf('&');
if (hashPos !== -1 || ampersandPos !== -1) {
const searchPos = hashPos === -1 ? ampersandPos : hashPos;
const lastSlashPos = templatePath.lastIndexOf('/', searchPos);
templatePath = path.dirname(templatePath.slice(0, lastSlashPos));
}
// Can't work with webroot-virtual paths, e.g. /missing.cfm
if (templatePath.slice(0, 1) !== '/') {
if (!path.isAbsolute(templatePath)) {
// Resolve the templatePath relative to the dirname of the including file
templatePath = path.resolve(fileDirname, templatePath);
}
if (!existsSync(templatePath)) {
templatePathViolations.push({
line: lineNumber,
column: includeMatch.index + 1,
message: `cfinclude/include template path ${templatePath} not found`,
severity: 'error',
});
}
}
}
lineNumber += 1;
}
const unusedPrefixViolations = comparePrefixArrays(
prefixes,
prefixUsages,
'cfimported namespace prefix "{2}" not used',
'warning',
);
const unimportedPrefixViolations = comparePrefixArrays(
prefixUsages,
prefixes,
'used namespace prefix "{2}" not cfimported',
'error',
);
return [
...unimportedPrefixViolations,
...unusedPrefixViolations,
...templatePathViolations,
...taglibPathViolations,
];
};
/**
* Gets a list of files from a given path.
*
* @param {string} filePath
*
* @returns {Array<string>}
*/
export const getFiles = (filePath) => {
let fileNames = [];
// Resolve the path, if a relative path was passed in
if (!path.isAbsolute(filePath)) {
filePath = path.resolve(filePath);
}
// The path exists...
if (existsSync(filePath)) {
try {
// ...try a readdirSync and...
readdirSync(filePath);
// (Add a trailing slash if not present)
if (filePath.slice(-1) !== '/') {
filePath += '/';
}
fileNames = sync(`${filePath}**/*.cfm`, {
ignore: ['**/WEB-INF/**', '**/node_modules/**'],
});
} catch {
// ...if that fails, it's a file, not a directory
fileNames = [filePath];
}
}
return fileNames;
};
/**
* Checks a file or files for path errors.
*
* @param {string} filePath - The full path of the file to check.
*
* @returns {Array<object>}
*/
export const check = (filePath) => {
const violations = [];
const fileNames = getFiles(filePath);
// Loop over our file list, checking each file
for (const fileName of fileNames) {
const fileViolations = checkFile(fileName);
if (fileViolations.length > 0) {
violations.push({
filename: fileName,
messages: fileViolations,
});
}
}
return violations;
};
/**
* @param {Array<object>} violations - The violations array.
* @param {string} format - The output format to use.
*
* @returns {string|Array<object>}
*/
export const formatter = (violations, format) => format === 'checkstyle'
? checkstyleFormatter(violations)
: violations;
/**
* @param {string} output - The file contents to write.
* @param {string} outFile - The file to write to.
*/
export 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 (existsSync(path.dirname(outFile))) {
writeFileSync(outFile, output, 'utf8');
} else {
console.warn(`Cannot write ${outFile}. Destination directory doesn’t exist`);
}
};
/**
* @param {string|Array<object>} output - The output to write.
*/
export const writeOutput = (output) => {
if (Array.isArray(output)) {
for (const violation of output) {
console.log(`File: ${chalk.green(violation.filename)}`);
for (const message of violation.messages) {
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);
}
}
} else {
console.log(output);
}
};
import deepEqual from 'deep-equal';
import path from 'path';

@@ -48,1 +49,15 @@ /**

};
/**
*
* @param {string} filePath - The path to normalise
* @returns {string}
*/
export const normalisePath = (filePath) => {
// Resolve the path, if a relative path was passed in
if (!path.isAbsolute(filePath)) {
filePath = path.resolve(filePath);
}
return filePath;
};

@@ -5,3 +5,3 @@ {

"description": "Check CFML files for correct paths in cfinclude/cfimport tags",
"version": "10.0.2",
"version": "10.1.0",
"homepage": "https://github.com/timbeadle/cfpathcheck",

@@ -37,6 +37,6 @@ "author": {

"engines": {
"node": ">= 18"
"node": ">= 18.20.3"
},
"scripts": {
"build:types": "tsc",
"build:types": "rimraf ./dist/* && tsc",
"test": "run-p test:snyk test:lint test:unit test:engines",

@@ -53,3 +53,3 @@ "test:ci": "run-p test:lint test:unit test:engines",

"dependencies": {
"@snyk/protect": "^1.1284.0",
"@snyk/protect": "^1.1292.1",
"chalk": "^5.3.0",

@@ -59,3 +59,3 @@ "checkstyle-formatter": "^1.1.0",

"deep-equal": "^2.2.3",
"glob": "^10.3.10",
"glob": "^10.4.5",
"log-symbols": "^6.0.0",

@@ -65,3 +65,3 @@ "minimist": "^1.2.8"

"devDependencies": {
"@types/chai": "4.3.12",
"@types/chai": "4.3.16",
"@types/checkstyle-formatter": "1.0.2",

@@ -71,21 +71,22 @@ "@types/deep-equal": "1.0.4",

"@types/minimist": "1.2.5",
"@types/mocha": "10.0.6",
"@types/node": "^20.11.28",
"chai": "5.1.0",
"@types/mocha": "10.0.7",
"@types/node": "^22.0.0",
"chai": "5.1.1",
"eslint": "8.57.0",
"eslint-config-xo": "0.44.0",
"eslint-config-xo": "0.45.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-redos": "4.4.5",
"ls-engines": "0.9.1",
"mocha": "10.3.0",
"npm-run-all2": "6.1.2",
"nyc": "15.1.0",
"prettier": "3.2.5",
"typescript": "^5.4.2"
"ls-engines": "0.9.2",
"mocha": "10.7.0",
"npm-run-all2": "6.2.2",
"nyc": "17.0.0",
"prettier": "3.3.3",
"rimraf": "^5.0.9",
"typescript": "^5.5.4"
},
"snyk": true,
"volta": {
"node": "18.18.2",
"npm": "10.5.0"
"node": "18.20.3",
"npm": "10.8.2"
}
}

@@ -21,4 +21,5 @@ {

"esModuleInterop": true,
"target": "ES2015"
"target": "ES2015",
"moduleResolution": "Node"
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc