Add no-inline-script eslint rule

This commit is contained in:
Alex Gleason 2025-06-07 10:56:52 -05:00
parent 2d325f7343
commit 7a7d91dbed
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
4 changed files with 141 additions and 1 deletions

View File

@ -2,6 +2,50 @@
This directory contains custom ESLint rules for the project.
## no-inline-script
This rule prevents the use of inline script tags in HTML files. Inline scripts can pose security risks and violate Content Security Policy (CSP) directives.
### Examples
**Bad** - These will trigger the rule:
```html
<!-- Inline JavaScript code -->
<script>
console.log("This is inline JavaScript");
</script>
<!-- Inline JSON-LD structured data -->
<script type="application/ld+json">
{"@context": "https://schema.org", "@type": "Organization"}
</script>
```
**Good** - These are fine:
```html
<!-- External script files -->
<script src="/js/app.js"></script>
<script type="module" src="/src/main.tsx"></script>
<!-- Empty script tags (no content) -->
<script id="data-container"></script>
```
### Configuration
The rule is configured in `eslint.config.js` as:
```javascript
"custom/no-inline-script": "error"
```
### Purpose
This rule helps maintain security best practices by:
- Preventing XSS vulnerabilities from inline scripts
- Enforcing Content Security Policy compliance
- Encouraging separation of concerns (HTML structure vs JavaScript logic)
- Making code easier to maintain and debug
## no-placeholder-comments
This rule detects and flags comments that start with "// In a real" (case-insensitive). These comments typically indicate placeholder implementations that should be replaced with real code.
@ -47,3 +91,56 @@ You can change the severity level to:
### Purpose
This rule helps ensure that placeholder comments used during development are replaced with actual implementations before code is committed or deployed to production.
## require-webmanifest
This rule ensures that HTML files include a proper web manifest link tag and that the referenced manifest file exists. Web manifests are essential for Progressive Web Apps (PWAs) and provide metadata about the application.
### Examples
**Bad** - These will trigger the rule:
```html
<!-- Missing manifest link entirely -->
<head>
<title>My App</title>
</head>
<!-- Manifest file doesn't exist -->
<head>
<link rel="manifest" href="/nonexistent-manifest.json">
</head>
<!-- Invalid manifest link (missing rel or href) -->
<head>
<link href="/manifest.json">
</head>
```
**Good** - These are fine:
```html
<!-- Proper manifest link with existing file -->
<head>
<link rel="manifest" href="/manifest.json">
</head>
<!-- Alternative valid manifest link -->
<head>
<link rel="manifest" href="/public/site.webmanifest">
</head>
```
### Configuration
The rule is configured in `eslint.config.js` as:
```javascript
"custom/require-webmanifest": "error"
```
### Purpose
This rule helps ensure:
- PWA compliance by requiring a web manifest
- Proper manifest file structure and accessibility
- Better user experience on mobile devices
- App installation capabilities
- Consistent branding and metadata across platforms

View File

@ -1,8 +1,10 @@
import noInlineScript from './no-inline-script.js';
import noPlaceholderComments from './no-placeholder-comments.js';
import requireWebmanifest from './require-webmanifest.js';
export default {
rules: {
'no-inline-script': noInlineScript,
'no-placeholder-comments': noPlaceholderComments,
'require-webmanifest': requireWebmanifest,
},

View File

@ -0,0 +1,40 @@
/**
* Rule to prevent inline script tags in HTML files
*/
export default {
meta: {
type: 'problem',
docs: {
description: 'Prevent inline script tags in HTML files',
category: 'Security',
recommended: true,
},
fixable: null,
schema: [],
messages: {
noInlineScript: 'Inline script tags are not allowed. Move script content to external files.',
},
},
create(context) {
return {
// For HTML files, we need to check script tags
'ScriptTag'(node) {
// Check if this is an inline script (has content but no src attribute)
const hasContent = node.value && node.value.value && node.value.value.trim().length > 0;
const hasSrc = node.attributes && node.attributes.some(attr =>
attr.key && attr.key.value === 'src'
);
// If the script has content but no src attribute, it's an inline script
if (hasContent && !hasSrc) {
context.report({
node,
messageId: 'noInlineScript',
});
}
},
};
},
};

View File

@ -68,6 +68,7 @@ export default tseslint.config(
"og:description",
],
],
"custom/no-inline-script": "error",
"custom/require-webmanifest": "error",
},
}