.eslintrc.js 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. const acorn = require('acorn');
  2. const unsafeEnvironment = [
  3. 'src/injected/**/*.js',
  4. ];
  5. // some functions are used by `injected`
  6. const unsafeSharedEnvironment = [
  7. 'src/common/browser.js',
  8. 'src/common/consts.js',
  9. 'src/common/index.js',
  10. 'src/common/object.js',
  11. 'src/common/util.js',
  12. ];
  13. const commonGlobals = getGlobals('src/common/safe-globals.js');
  14. const injectedGlobals = {
  15. ...commonGlobals,
  16. ...getGlobals('src/injected/safe-injected-globals.js'),
  17. };
  18. module.exports = {
  19. root: true,
  20. extends: [
  21. require.resolve('@gera2ld/plaid/eslint'),
  22. require.resolve('@gera2ld/plaid-vue/eslint/vue'),
  23. ],
  24. parserOptions: {
  25. ecmaFeatures: {
  26. legacyDecorators: true,
  27. },
  28. },
  29. overrides: [{
  30. // `browser` is a local variable since we remove the global `chrome` and `browser` in injected*
  31. // to prevent exposing them to userscripts with `@inject-into content`
  32. files: ['*'],
  33. excludedFiles: [...unsafeEnvironment, ...unsafeSharedEnvironment],
  34. globals: {
  35. browser: false,
  36. ...commonGlobals,
  37. },
  38. }, {
  39. files: unsafeEnvironment,
  40. globals: injectedGlobals,
  41. rules: {
  42. // Whitelisting our safe globals
  43. 'no-restricted-globals': ['error',
  44. ...require('confusing-browser-globals').filter(x => injectedGlobals[x] == null),
  45. ],
  46. /* Our .browserslistrc targets old browsers so the compiled code for {...objSpread} uses
  47. babel's polyfill that calls methods like `Object.assign` instead of our safe `assign`.
  48. Ideally, `eslint-plugin-compat` should be used but I couldn't make it work. */
  49. 'no-restricted-syntax': ['error', {
  50. selector: 'ObjectExpression > ExperimentalSpreadProperty',
  51. message: 'Object spread in an unsafe environment',
  52. }, {
  53. selector: 'OptionalCallExpression',
  54. message: 'Optional call in an unsafe environment',
  55. }],
  56. },
  57. }],
  58. rules: {
  59. 'import/extensions': ['error', 'ignorePackages', {
  60. js: 'never',
  61. vue: 'never',
  62. }],
  63. // copied from airbnb-base, replaced 4 with 8
  64. 'object-curly-newline': ['error', {
  65. ObjectExpression: { minProperties: 8, multiline: true, consistent: true },
  66. ObjectPattern: { minProperties: 8, multiline: true, consistent: true },
  67. ImportDeclaration: { minProperties: 8, multiline: true, consistent: true },
  68. ExportDeclaration: { minProperties: 8, multiline: true, consistent: true },
  69. }],
  70. },
  71. };
  72. function getGlobals(fileName) {
  73. const text = require('fs').readFileSync(fileName, { encoding: 'utf8' });
  74. const res = {};
  75. acorn.parse(text, { ecmaVersion: 2018, sourceType: 'module' }).body.forEach(body => {
  76. (body.declaration || body).declarations.forEach(function processId({ id: { name, properties } }) {
  77. if (name) {
  78. // const NAME = whatever
  79. res[name] = false;
  80. } else if (properties) {
  81. // const { NAME1, prototype: { NAME2: ALIAS2 } } = whatever
  82. properties.forEach(({ value }) => processId({ id: value }));
  83. }
  84. });
  85. });
  86. return res;
  87. }