Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

obsohtml

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

obsohtml - npm Package Compare versions

Comparing version
1.9.6
to
1.9.7
+1
-1
.github/dependabot.yml

@@ -1,2 +0,2 @@

# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference
# https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference

@@ -3,0 +3,0 @@ version: 2

@@ -1,3 +0,3 @@

buy_me_a_coffee: meiert
# buy_me_a_coffee: meiert
github: j9t
liberapay: j9t
# liberapay: j9t

@@ -21,31 +21,50 @@ #!/usr/bin/env node

// Pre-compile regexes once at startup
const elementRegexes = obsoleteElements.map(element => ({
element,
regex: new RegExp(`<\\s*${element}\\b`, 'i'),
}));
const attributeRegexes = obsoleteAttributes.map(attribute => ({
attribute,
// Matches the attribute preceded by whitespace anywhere in a tag, without
// requiring it to be the last attribute before the closing bracket.
regex: new RegExp(`<[^>]*\\s${attribute}\\b(\\s*=\\s*(?:"[^"]*"|'[^']*'|[^"'\\s>]+))?`, 'i'),
}));
// Directories to skip during traversal
const EXCLUDED_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'vendor']);
// Default project directory (user’s home directory)
const defaultProjectDirectory = os.homedir();
// Track whether any obsolete HTML was found
let foundObsolete = false;
// Function to find obsolete elements and attributes in a file
async function findObsolete(filePath) {
function findObsolete(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
// Check for obsolete elements
obsoleteElements.forEach(element => {
const elementRegex = new RegExp(`<\\s*${element}\\b`, 'i');
if (elementRegex.test(content)) {
for (const { element, regex } of elementRegexes) {
if (regex.test(content)) {
foundObsolete = true;
const message = styleText('blue', `Found obsolete element ${styleText('bold', `'${element}'`)} in ${filePath}`);
console.log(message);
}
});
}
// Check for obsolete attributes
obsoleteAttributes.forEach(attribute => {
const attributeRegex = new RegExp(`<[^>]*\\s${attribute}\\b(\\s*=\\s*(?:"[^"]*"|'[^']*'|[^"'\\s>]+))?\\s*(?=/?>)`, 'i');
if (attributeRegex.test(content)) {
for (const { attribute, regex } of attributeRegexes) {
if (regex.test(content)) {
foundObsolete = true;
const message = styleText('green', `Found obsolete attribute ${styleText('bold', `'${attribute}'`)} in ${filePath}`);
console.log(message);
}
});
}
}
// Function to walk through the project directory, excluding node_modules directories
// Function to walk through the project directory, excluding common build/VCS directories
function walkDirectory(directory, verbose) {
const MAX_PATH_LENGTH = 255; // Adjust this value based on your OS limits
const MAX_PATH_LENGTH = 255;
let files;

@@ -67,3 +86,3 @@

files.forEach(file => {
for (const file of files) {
const fullPath = path.join(directory, file);

@@ -73,3 +92,3 @@

if (verbose) console.warn(`Skipping file or directory with path too long: ${fullPath}`);
return;
continue;
}

@@ -81,9 +100,15 @@

if (verbose) console.warn(`Skipping symbolic link: ${fullPath}`);
return;
continue;
}
if (stats.isDirectory()) {
if (file !== 'node_modules') {
if (!EXCLUDED_DIRS.has(file)) {
walkDirectory(fullPath, verbose);
}
} else if (fullPath.endsWith('.html') || fullPath.endsWith('.htm') || fullPath.endsWith('.php') || fullPath.endsWith('.njk') || fullPath.endsWith('.twig') || fullPath.endsWith('.js') || fullPath.endsWith('.ts')) {
} else if (
fullPath.endsWith('.html') || fullPath.endsWith('.htm') ||
fullPath.endsWith('.php') ||
fullPath.endsWith('.njk') || fullPath.endsWith('.twig') ||
fullPath.endsWith('.js') || fullPath.endsWith('.jsx') ||
fullPath.endsWith('.ts') || fullPath.endsWith('.tsx')
) {
findObsolete(fullPath);

@@ -98,8 +123,21 @@ }

}
});
}
}
// Main function to execute the script
async function main(projectDirectory = defaultProjectDirectory, verbose = false) {
await walkDirectory(projectDirectory, verbose);
function main(projectDirectory = defaultProjectDirectory, verbose = false) {
let stats;
try {
stats = fs.lstatSync(projectDirectory);
} catch (err) {
if (err.code !== 'ENOENT') throw err;
}
if (stats?.isFile()) {
findObsolete(projectDirectory);
} else {
walkDirectory(projectDirectory, verbose);
}
if (foundObsolete) process.exit(1);
}

@@ -106,0 +144,0 @@

@@ -12,2 +12,11 @@ import fs from 'node:fs';

function run(args) {
const result = spawnSync('node', [scriptPath, ...args], { encoding: 'utf-8' });
return {
stdout: stripVTControlCharacters(result.stdout),
stderr: stripVTControlCharacters(result.stderr),
status: result.status,
};
}
describe('ObsoHTML', () => {

@@ -17,7 +26,9 @@ const tempDir = path.join(__dirname, 'temp_test_dir');

const tempFileWithAttributes = path.join(tempDir, 'test_with_attributes.html');
const tempFileWithMidTagAttribute = path.join(tempDir, 'test_mid_tag_attribute.html');
const tempFileWithMinimizedAttributes = path.join(tempDir, 'test_with_minimized_attributes.html');
const tempTwigFile = path.join(tempDir, 'test.twig');
const tempJsxFile = path.join(tempDir, 'test.jsx');
const tempTsxFile = path.join(tempDir, 'test.tsx');
before(() => {
// Create a temporary directory and files
if (!fs.existsSync(tempDir)) {

@@ -28,12 +39,17 @@ fs.mkdirSync(tempDir);

fs.writeFileSync(tempFileWithAttributes, '<!DOCTYPE html><html><title>Test</title><body><img src=test.jpg alt=Test align=left></body></html>');
fs.writeFileSync(tempFileWithMidTagAttribute, '<!DOCTYPE html><html><title>Test</title><body><img align=left src=test.jpg></body></html>');
fs.writeFileSync(tempFileWithMinimizedAttributes, '<!DOCTYPE html><html><title>Test</title><hr noshade><table><tr><th class=nowrap></table>');
fs.writeFileSync(tempTwigFile, '<!DOCTYPE html><html><title>Test</title><isindex>');
fs.writeFileSync(tempJsxFile, 'export default () => <center>Hello</center>;');
fs.writeFileSync(tempTsxFile, 'export default (): JSX.Element => <marquee>Hello</marquee>;');
});
after(() => {
// Clean up the temporary directory and files
fs.unlinkSync(tempFile);
fs.unlinkSync(tempFileWithAttributes);
fs.unlinkSync(tempFileWithMidTagAttribute);
fs.unlinkSync(tempFileWithMinimizedAttributes);
fs.unlinkSync(tempTwigFile);
fs.unlinkSync(tempJsxFile);
fs.unlinkSync(tempTsxFile);
fs.rmdirSync(tempDir);

@@ -43,41 +59,69 @@ });

test('Detect obsolete elements', () => {
const result = spawnSync('node', [scriptPath, '-f', tempDir], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete element 'center'"));
const { stdout } = run(['-f', tempDir]);
assert.ok(stdout.includes("Found obsolete element 'center'"));
});
test('Detect obsolete attributes', () => {
const result = spawnSync('node', [scriptPath, '-f', tempDir], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete attribute 'align'"));
const { stdout } = run(['-f', tempDir]);
assert.ok(stdout.includes("Found obsolete attribute 'align'"));
});
test('Detect obsolete elements and attributes using absolute path', () => {
const absolutePath = path.resolve(tempDir);
const result = spawnSync('node', [scriptPath, '-f', absolutePath], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete element 'center'"));
assert.ok(output.includes("Found obsolete attribute 'align'"));
const { stdout } = run(['-f', path.resolve(tempDir)]);
assert.ok(stdout.includes("Found obsolete element 'center'"));
assert.ok(stdout.includes("Found obsolete attribute 'align'"));
});
test('Detect obsolete elements and attributes using relative path', () => {
const relativePath = path.relative(process.cwd(), tempDir);
const result = spawnSync('node', [scriptPath, '--folder', relativePath], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete element 'center'"));
assert.ok(output.includes("Found obsolete attribute 'align'"));
const { stdout } = run(['--folder', path.relative(process.cwd(), tempDir)]);
assert.ok(stdout.includes("Found obsolete element 'center'"));
assert.ok(stdout.includes("Found obsolete attribute 'align'"));
});
test('Detect obsolete minimized attributes', () => {
const result = spawnSync('node', [scriptPath, '-f', tempDir], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete attribute 'noshade'"));
assert.ok(!output.includes("Found obsolete attribute 'nowrap'"));
const { stdout } = run(['-f', tempDir]);
assert.ok(stdout.includes("Found obsolete attribute 'noshade'"));
assert.ok(!stdout.includes("Found obsolete attribute 'nowrap'"));
});
test('Detect obsolete elements in Twig file', () => {
const result = spawnSync('node', [scriptPath, '-f', tempDir], { encoding: 'utf-8' });
const output = stripVTControlCharacters(result.stdout);
assert.ok(output.includes("Found obsolete element 'isindex'"));
const { stdout } = run(['-f', tempDir]);
assert.ok(stdout.includes("Found obsolete element 'isindex'"));
});
});
test('Detect obsolete attribute when it is not the last attribute in a tag', () => {
const { stdout } = run(['-f', tempFileWithMidTagAttribute]);
assert.ok(stdout.includes("Found obsolete attribute 'align'"));
});
test('Detect obsolete elements in JSX file', () => {
const { stdout } = run(['-f', tempJsxFile]);
assert.ok(stdout.includes("Found obsolete element 'center'"));
});
test('Detect obsolete elements in TSX file', () => {
const { stdout } = run(['-f', tempTsxFile]);
assert.ok(stdout.includes("Found obsolete element 'marquee'"));
});
test('Exit with code 1 when obsolete HTML is found', () => {
const { status } = run(['-f', tempDir]);
assert.strictEqual(status, 1);
});
test('Exit with code 0 when no obsolete HTML is found', () => {
const cleanFile = path.join(tempDir, 'clean.html');
fs.writeFileSync(cleanFile, '<!DOCTYPE html><html><title>Clean</title><body><p>No issues here.</p></body></html>');
try {
const { status } = run(['-f', cleanFile]);
assert.strictEqual(status, 0);
} finally {
fs.unlinkSync(cleanFile);
}
});
test('Verbose mode reports skipped non-existent directory', () => {
const { stderr } = run(['-f', path.join(tempDir, 'nonexistent'), '-v']);
assert.ok(stderr.includes('Skipping non-existent directory'));
});
});

@@ -18,3 +18,3 @@ {

],
"license": "CC-BY-SA-4.0",
"license": "MIT",
"name": "obsohtml",

@@ -30,3 +30,3 @@ "repository": {

"type": "module",
"version": "1.9.6"
"version": "1.9.7"
}

@@ -5,3 +5,3 @@ # ObsoHTML, the Obsolete HTML Checker

ObsoHTML is a Node.js script designed to scan HTML, PHP, Nunjucks, Twig, JavaScript, and TypeScript files for obsolete or proprietary HTML attributes and elements (in scripts, it would catch JSX syntax). It helps you identify and update deprecated HTML code to be more sure to use web standards.
ObsoHTML is a Node.js script designed to scan HTML, PHP, Nunjucks, Twig, JavaScript, and TypeScript files for obsolete or proprietary HTML attributes and elements. It helps you identify and update deprecated HTML code to be more sure to use web standards.

@@ -24,3 +24,3 @@ ObsoHTML has inherent limitations and may not find all obsolete attributes and elements. If you run into a problem, please [file an issue](https://github.com/j9t/obsohtml/issues).

The script accepts a folder path as a command line option, which can be specified in both short form (`-f`) and long form (`--folder`). The folder path can be either absolute or relative.
The script accepts a folder or file path as a command line option, which can be specified in both short form (`-f`) and long form (`--folder`). The path can be either absolute or relative.

@@ -85,2 +85,4 @@ The script can be run in “verbose” mode by appending `-v` or `--verbose` to the command. This will show information about files and directories that were skipped.

The script exits with code `1` if any obsolete HTML is found, and `0` if none is found, making it suitable for use in CI pipelines.
## Background

@@ -87,0 +89,0 @@