button-is-loading-wrapper

Try in Playground
chakra-ui

oscar143

UnknownInformational

0

No tags

No CWE or CVE

Using the is loading prop without a wrapper will cause some errors when the users use the browser translation services

Ast Rule: html element


button-is-loading-wrapper

How to write a rule
const TYPES = {
  string: getPropStringValue,
  sequence: getPropSequenceValue,
  array: getPropArrayValue,
  object: getPropObjectValue,
  object_element: getPropObjectValue,
  functiondefinition: () => {},
};

function getTag(node) {
  if (node && node.tag) {
    return node.tag.value;
  }
}

function getProp(attributes = [], prop = "") {
  if (!prop) return;

  return attributes.find((attribute) => {
    if (attribute && attribute.name && attribute.name.value) {
      return attribute.name.value === prop;
    }
  });
}

function getPropStringValue(value) {
  if (value.value === "true") {
    return true;
  }

  if (value.value === "false") {
    return false;
  }

  return value.value.replace(/^\"/g, "").replace(/\"$/g, "");
}

function getPropArrayValue(value) {
  const array = [];
  const arrayElements = value.elements;

  if (arrayElements.length) {
    for (const element of arrayElements) {
      array.push(TYPES[element.astType](element));
    }
  }

  return array;
}

function getPropObjectValue(value) {
  const object = {};
  const objectElements = value.elements;

  if (objectElements.length) {
    for (const element of objectElements) {
      object[element.name.value] = TYPES[element.value.astType](element.value);
    }
  }

  return object;
}

function getPropSequenceValue(value) {
  if (value.elements.length) {
    const element = value.elements[0];

    if (element) {
      return TYPES[element.astType](element);
    }
  }
}

function extractValue(attribute, extractor) {
  if (attribute) {
    // Null valued attributes imply truthiness.
    // For example: <div aria-hidden />
    if (attribute.value === null) return true;

    return extractor(attribute.value);
  }
}

function getValue(value) {
  return TYPES[value.astType](value);
}

function getPropValue(attribute) {
  return extractValue(attribute, getValue);
}

function propHasValue(attribute) {
  const value = getPropValue(attribute);

  if (typeof value !== "boolean") {
    return !!value;
  }

  return false;
}

function visit(node, filename, code) {
  if (getTag(node) === "Button") {
    const isLoading = getProp(node.attributes, "isLoading");

    if (isLoading !== undefined) {
      if (!node.htmlChildren.length) {
        return;
      }

      if (node.htmlChildren.length > 1) {
        const error = buildError(
          node.start.line,
          node.start.col,
          node.end.line,
          node.end.col,
          "Chakra buttons with isLoading attribute must have only one wrapping children.",
          "INFO",
          "BEST_PRACTICES"
        );

        addError(error);

        return;
      }

      const child = node.htmlChildren[0];

      if (child.astType === "htmldata") {
        const error = buildError(
          node.start.line,
          node.start.col,
          node.end.line,
          node.end.col,
          "Chakra buttons with isLoading attribute must have a wrapping children.",
          "INFO",
          "BEST_PRACTICES"
        );

        addError(error);

        return;
      }

      if (getTag(child) === "span") {
        return;
      }

      const asProp = getProp(child.attributes, "as");

      if (getPropValue(asProp) === "span") {
        return;
      }

      const error = buildError(
        node.start.line,
        node.start.col,
        node.end.line,
        node.end.col,
        "Chakra buttons with isLoading attribute should have a wrapping span child.",
        "INFO",
        "BEST_PRACTICES"
      );

      addError(error);
    }
  }
}

my-test.jsx

Expected test result: no error

no isLoading

<Button>
	<Box as="span">correct</span>
</Button>

my-test.jsx

Expected test result: no error

as wrapper

<Button isLoading>
	<Box as="span">correct</Box>
</Button>

my-test.jsx

Expected test result: has error

button error multiple children

<Button isLoading>
	<span>one</span>
	<span>two</span>
</Button>

my-test.jsx

Expected test result: has error

as wrapper no span

my-test.jsx

Expected test result: no error

button without isLoading

my-test.jsx

Expected test result: no error

button with isLoading should have a span

my-test.jsx

Expected test result: has error

button with isLoading should have span

Add comment

Log in to add a comment


    Be the first one to leave a comment!

Codiga Logo
Codiga Hub
  • Rulesets
  • Playground
  • Snippets
  • Cookbooks
soc-2 icon

We are SOC-2 Compliance Certified

G2 high performer medal

Codiga – All rights reserved 2022.