webmanifest eslint

This commit is contained in:
Alex Gleason 2025-05-30 23:02:12 +02:00
parent 95de9fde27
commit 1b8dab92b9
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
3 changed files with 88 additions and 0 deletions

View File

@ -1,7 +1,9 @@
import noPlaceholderComments from './no-placeholder-comments.js'; import noPlaceholderComments from './no-placeholder-comments.js';
import requireWebmanifest from './require-webmanifest.js';
export default { export default {
rules: { rules: {
'no-placeholder-comments': noPlaceholderComments, 'no-placeholder-comments': noPlaceholderComments,
'require-webmanifest': requireWebmanifest,
}, },
}; };

View File

@ -0,0 +1,84 @@
import fs from 'fs';
import path from 'path';
export default {
meta: {
type: 'problem',
docs: {
description: 'Require web manifest file and proper HTML link tag',
category: 'Best Practices',
},
fixable: null,
schema: [],
messages: {
missingManifestFile: 'Web manifest file not found. Expected {{expectedPath}}',
missingManifestLink: 'Missing web manifest link tag in HTML head',
invalidManifestLink: 'Web manifest link tag has incorrect rel or href attribute',
},
},
create(context) {
const filename = context.getFilename();
// Only run this rule on HTML files
if (!filename.endsWith('.html')) {
return {};
}
return {
Program(node) {
const sourceCode = context.getSourceCode();
const htmlContent = sourceCode.getText();
// Check for manifest link tag in HTML
const manifestLinkRegex = /<link[^>]*rel=["']manifest["'][^>]*>/i;
const manifestMatch = htmlContent.match(manifestLinkRegex);
if (!manifestMatch) {
context.report({
node,
messageId: 'missingManifestLink',
});
return;
}
// Extract href from the manifest link
const hrefMatch = manifestMatch[0].match(/href=["']([^"']+)["']/i);
if (!hrefMatch) {
context.report({
node,
messageId: 'invalidManifestLink',
});
return;
}
const manifestPath = hrefMatch[1];
// Resolve the manifest file path relative to the project root
const htmlDir = path.dirname(filename);
let resolvedManifestPath;
if (manifestPath.startsWith('/')) {
// Absolute path - check in public directory first, then project root
const publicPath = path.resolve(htmlDir, 'public' + manifestPath);
const rootPath = path.resolve(htmlDir, '.' + manifestPath);
resolvedManifestPath = fs.existsSync(publicPath) ? publicPath : rootPath;
} else {
// Relative path
resolvedManifestPath = path.resolve(htmlDir, manifestPath);
}
// Check if the manifest file exists
if (!fs.existsSync(resolvedManifestPath)) {
context.report({
node,
messageId: 'missingManifestFile',
data: {
expectedPath: manifestPath,
},
});
}
},
};
},
};

View File

@ -35,6 +35,7 @@ export default tseslint.config(
files: ["**/*.html"], files: ["**/*.html"],
plugins: { plugins: {
"@html-eslint": htmlEslint, "@html-eslint": htmlEslint,
"custom": customRules,
}, },
languageOptions: { languageOptions: {
parser: htmlParser, parser: htmlParser,
@ -43,6 +44,7 @@ export default tseslint.config(
"@html-eslint/require-title": "error", "@html-eslint/require-title": "error",
"@html-eslint/require-meta-charset": "error", "@html-eslint/require-meta-charset": "error",
"@html-eslint/require-meta-viewport": "error", "@html-eslint/require-meta-viewport": "error",
"custom/require-webmanifest": "error",
}, },
} }
); );