115 lines
3.6 KiB
JavaScript
115 lines
3.6 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* require-userprofile-with-home
|
|
*
|
|
* Flag test files that assign `process.env.HOME` without also referencing
|
|
* `USERPROFILE` anywhere in the file.
|
|
*
|
|
* ## What this enforces (G6)
|
|
*
|
|
* Program-level: collect assignments to `process.env.HOME`
|
|
* (`process.env.HOME = …` / `process.env['HOME'] = …`); track whether
|
|
* `USERPROFILE` appears anywhere in the file (any reference). At
|
|
* `Program:exit`, if HOME is assigned and `USERPROFILE` never appears, report
|
|
* each HOME assignment.
|
|
*
|
|
* Message: Windows uses `USERPROFILE`, not `HOME` — set
|
|
* `process.env.USERPROFILE` alongside.
|
|
*
|
|
* DEFECT category: DEFECT.WINDOWS-TEST-PORTABILITY
|
|
*/
|
|
|
|
/** @type {import('eslint').Rule.RuleModule} */
|
|
const rule = {
|
|
meta: {
|
|
type: 'problem',
|
|
docs: {
|
|
description:
|
|
'Require process.env.USERPROFILE to be set alongside process.env.HOME (Windows portability)',
|
|
category: 'Portability',
|
|
},
|
|
schema: [],
|
|
messages: {
|
|
missingUserProfile:
|
|
'Assigning process.env.HOME without process.env.USERPROFILE is not portable ' +
|
|
'(DEFECT.WINDOWS-TEST-PORTABILITY): Windows uses USERPROFILE as the home ' +
|
|
'directory environment variable, not HOME. Set process.env.USERPROFILE ' +
|
|
'alongside process.env.HOME.',
|
|
},
|
|
},
|
|
|
|
create(context) {
|
|
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
|
|
/** Collected HOME assignment nodes */
|
|
const homeAssignments = [];
|
|
|
|
/** Whether a real process.env.USERPROFILE = … assignment exists in the file */
|
|
let userProfileAssigned = false;
|
|
|
|
/**
|
|
* Returns true if node is an assignment to process.env[key] or
|
|
* process.env.key for the given key name.
|
|
*
|
|
* Recognized shapes (as the left-hand side of AssignmentExpression):
|
|
* process.env.KEY — MemberExpression(MemberExpression, Identifier)
|
|
* process.env['KEY'] — MemberExpression(MemberExpression, Literal, computed=true)
|
|
*
|
|
* @param {import('eslint').Rule.Node} lhs — left side of AssignmentExpression
|
|
* @param {string} key — the env var name to check
|
|
* @returns {boolean}
|
|
*/
|
|
function isProcessEnvAssignment(lhs, key) {
|
|
if (!lhs || lhs.type !== 'MemberExpression') return false;
|
|
const obj = lhs.object;
|
|
if (!obj || obj.type !== 'MemberExpression') return false;
|
|
|
|
// obj must be process.env
|
|
if (
|
|
obj.computed ||
|
|
obj.object.type !== 'Identifier' ||
|
|
obj.object.name !== 'process' ||
|
|
obj.property.type !== 'Identifier' ||
|
|
obj.property.name !== 'env'
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// Property must be key (identifier or string literal)
|
|
if (!lhs.computed) {
|
|
return lhs.property.type === 'Identifier' && lhs.property.name === key;
|
|
} else {
|
|
return (
|
|
lhs.property.type === 'Literal' && lhs.property.value === key
|
|
);
|
|
}
|
|
}
|
|
|
|
return {
|
|
AssignmentExpression(node) {
|
|
if (isProcessEnvAssignment(node.left, 'HOME')) {
|
|
homeAssignments.push(node);
|
|
}
|
|
// Track actual USERPROFILE assignments (not mere text/comment mentions)
|
|
if (isProcessEnvAssignment(node.left, 'USERPROFILE')) {
|
|
userProfileAssigned = true;
|
|
}
|
|
},
|
|
|
|
'Program:exit'() {
|
|
if (homeAssignments.length === 0) return;
|
|
|
|
// Only suppress if USERPROFILE is actually ASSIGNED (not just mentioned in a comment)
|
|
if (userProfileAssigned) return;
|
|
|
|
for (const node of homeAssignments) {
|
|
context.report({ node, messageId: 'missingUserProfile' });
|
|
}
|
|
},
|
|
};
|
|
},
|
|
};
|
|
|
|
module.exports = rule;
|