2
\$\begingroup\$

I am working on a program that checks for the browser support of a CSS file. Below you can find my working code, so far it supports CSS At-Rules & Properties. In the next few weeks, I will need to expand this code so that I can slowly support the entire language.

I am trying to come up with a readable and efficient system, keep in mind that some CSS files can get huge (10.000 + Lines), so I want to keep the iteration count as low as possible.

There are a couple of things bothering me at the moment, for once, I don't like that I have different functions to check the browser support ('getAtruleSupportData' & 'getPropertySupportData'). I am quite sure I can write this in a single function but I have had no success so far. The other thing that really bothers me is the 'checkBrowserSupport' function itself. I am not sure, what to think about it, but the more I expand it, the more 'reduces' and 'filters' I will need to use. I am not sure this is going to scale at all.

In general, I want to improve the scalability of my code, it's readability and general performance. Any help is more than welcome.

Example Input:

{ atrules:
   [ { type: 'Atrule',
       loc: [Object],
       name: 'media',
       prelude: [Object],
       block: [Object] } ],
  declarations:
   [ { type: 'Declaration',
       loc: [Object],
       important: false,
       property: 'margin',
       value: [Object] },
     { type: 'Declaration',
       loc: [Object],
       important: false,
       property: 'margin',
       value: [Object] } ],
  mediaFeatures:
   [ { type: 'MediaFeature',
       loc: [Object],
       name: 'min-width',
       value: [Object] } ] }

Example Browserscope:

const browserscope = {
  chrome: 60,
  edge: 15,
  firefox: 60,
  ie: 10,
  safari: 10,
};

Working Code:

const bcd = require('mdn-browser-compat-data');

const checkBrowserSupport = ({atrules, declarations}, browserscope) => {
  return {
    atrules: atrules
        .reduce((acc, {name, loc}) => {
          const supportData = getAtruleSupportData(name);

          supportData &&
          acc.push(formatData(browserscope, name, loc, supportData));

          return acc;
        }, [])
        .filter((atrule) => atrule.notSupported.length),
    declarations: declarations
        .reduce((acc, {property, loc}) => {
          const supportData = getPropertySupportData(property);

          supportData &&
          acc.push(formatData(browserscope, property, loc, supportData));

          return acc;
        }, [])
        .filter((property) => property.notSupported.length),
  };
};

const formatData = (browserscope, name, loc, supportData) => {
  const {line, column} = loc.start;

  return Object.entries(browserscope).reduce((acc, [browser, version]) => {
    acc.name = name;
    acc.location = {line, column};
    acc.supported = acc.supported || [];
    acc.notSupported = acc.notSupported || [];

    const browserSupportData = Array.isArray(supportData[browser])
      ? supportData[browser][0].version_added
      : supportData[browser].version_added;

    browserSupportData && browserSupportData <= version
      ? acc.supported.push(browser)
      : acc.notSupported.push(browser);

    return acc;
  }, {});
};

const getAtruleSupportData = (atrule) => {
  try {
    return bcd.css['at-rules'][atrule].__compat.support;
  } catch (error) {
    return false;
  }
};

const getPropertySupportData = (property) => {
  try {
    return bcd.css.properties[property].__compat.support;
  } catch (error) {
    return false;
  }
};

module.exports = {
  checkBrowserSupport,
};
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.