@linaria/utils
Version:
Blazing fast zero-runtime CSS in JS library
135 lines (134 loc) • 4.21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.removeDangerousCode = void 0;
var _findIdentifiers = require("./findIdentifiers");
var _isUnnecessaryReactCall = require("./isUnnecessaryReactCall");
var _scopeHelpers = require("./scopeHelpers");
var _JSXElementsRemover = _interopRequireDefault(require("./visitors/JSXElementsRemover"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const isGlobal = id => {
if (!(0, _findIdentifiers.nonType)(id)) {
return false;
}
const {
scope
} = id;
const {
name
} = id.node;
return !scope.hasBinding(name) && scope.hasGlobal(name);
};
const ssrCheckFields = new Set(['document', 'location', 'navigator', 'sessionStorage', 'localStorage', 'window']);
const forbiddenGlobals = new Set([...ssrCheckFields, '$RefreshReg$', 'XMLHttpRequest', 'clearImmediate', 'clearInterval', 'clearTimeout', 'fetch', 'navigator', 'setImmediate', 'setInterval', 'setTimeout']);
const isBrowserGlobal = id => {
return forbiddenGlobals.has(id.node.name) && isGlobal(id);
};
const isSSRCheckField = id => {
return ssrCheckFields.has(id.node.name) && isGlobal(id);
};
const getPropertyName = path => {
if (path.isIdentifier()) {
return path.node.name;
}
if (path.isStringLiteral()) {
return path.node.value;
}
return null;
};
const removeDangerousCode = programPath => {
programPath.traverse({
// JSX can be replaced with a dummy value,
// but we have to do it after we processed template tags.
CallExpression: {
enter(p) {
if ((0, _isUnnecessaryReactCall.isUnnecessaryReactCall)(p)) {
(0, _JSXElementsRemover.default)(p);
}
}
},
JSXElement: {
enter: _JSXElementsRemover.default
},
JSXFragment: {
enter: _JSXElementsRemover.default
},
MemberExpression(p, state) {
const obj = p.get('object');
const prop = p.get('property');
if (!obj.isIdentifier({
name: 'window'
})) {
return;
}
const name = getPropertyName(prop);
if (!name) {
return;
}
state.windowScoped.add(name);
// eslint-disable-next-line no-param-reassign
state.globals = state.globals.filter(id => {
if (id.node.name === name) {
(0, _scopeHelpers.removeWithRelated)([id]);
return false;
}
return true;
});
},
MetaProperty(p) {
// Remove all references to `import.meta`
(0, _scopeHelpers.removeWithRelated)([p]);
},
Identifier(p, state) {
if (p.find(parent => parent.isTSTypeReference())) {
// don't mess with TS type references
return;
}
if (isBrowserGlobal(p)) {
if (p.find(parentPath => parentPath.isUnaryExpression({
operator: 'typeof'
}) || parentPath.isTSTypeQuery())) {
// Ignore `typeof window` expressions
return;
}
if (p.parentPath.isClassProperty()) {
// ignore class property decls
return;
}
if (p.parentPath.isMemberExpression() && p.key === 'property') {
// ignore e.g this.fetch()
// window.fetch will be handled by the windowScoped block below
return;
}
(0, _scopeHelpers.removeWithRelated)([p]);
return;
}
if (state.windowScoped.has(p.node.name)) {
(0, _scopeHelpers.removeWithRelated)([p]);
} else if (isGlobal(p)) {
state.globals.push(p);
}
},
// Since we can use happy-dom, typical SSR checks may not work as expected.
// We need to detect them and replace with an "undefined" literal.
UnaryExpression(p) {
if (p.node.operator !== 'typeof') {
return;
}
const arg = p.get('argument');
if (!arg.isIdentifier() || !isSSRCheckField(arg)) {
return;
}
(0, _scopeHelpers.applyAction)(['replace', p, {
type: 'StringLiteral',
value: 'undefined'
}]);
}
}, {
globals: [],
windowScoped: new Set()
});
};
exports.removeDangerousCode = removeDangerousCode;
//# sourceMappingURL=removeDangerousCode.js.map