UNPKG

@linaria/utils

Version:

Blazing fast zero-runtime CSS in JS library

127 lines 3.75 kB
import { nonType } from './findIdentifiers'; import { isUnnecessaryReactCall } from './isUnnecessaryReactCall'; import { applyAction, removeWithRelated } from './scopeHelpers'; import JSXElementsRemover from './visitors/JSXElementsRemover'; const isGlobal = id => { if (!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; }; export 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 (isUnnecessaryReactCall(p)) { JSXElementsRemover(p); } } }, JSXElement: { enter: JSXElementsRemover }, JSXFragment: { enter: JSXElementsRemover }, 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) { removeWithRelated([id]); return false; } return true; }); }, MetaProperty(p) { // Remove all references to `import.meta` 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; } removeWithRelated([p]); return; } if (state.windowScoped.has(p.node.name)) { 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; } applyAction(['replace', p, { type: 'StringLiteral', value: 'undefined' }]); } }, { globals: [], windowScoped: new Set() }); }; //# sourceMappingURL=removeDangerousCode.js.map