<commit_before>import valueParser from "postcss-value-parser"
import {
  declarationValueIndexOffset,
  report,
  ruleMessages,
  styleSearch,
  validateOptions,
  whitespaceChecker,
} from "../../utils"

export const ruleName = "function-comma-space-after"

export const messages = ruleMessages(ruleName, {
  expectedAfter: () => `Expected single space after ","`,
  rejectedAfter: () => `Unexpected whitespace after ","`,
  expectedAfterSingleLine: () => `Expected single space after "," in a single-line function`,
  rejectedAfterSingleLine: () => `Unexpected whitespace after "," in a single-line function`,
})

export default function (expectation) {
  const checker = whitespaceChecker("space", expectation, messages)
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, {
      actual: expectation,
      possible: [
        "always",
        "never",
        "always-single-line",
        "never-single-line",
      ],
    })
    if (!validOptions) { return }

    functionCommaSpaceChecker({
      root,
      result,
      locationChecker: checker.after,
      checkedRuleName: ruleName,
    })
  }
}

export function functionCommaSpaceChecker({ locationChecker, root, result, checkedRuleName }) {
  root.walkDecls(decl => {
    const functionOffset = declarationValueIndexOffset(decl)

    const cssFunctions = valueParser(decl.value)
      .nodes
      .filter(node => node.type === "function")

    cssFunctions.forEach(cssFunction => {
      const cssFunctionString = valueParser.stringify(cssFunction)
      styleSearch({ source: cssFunctionString, target: "," }, match => {
        locationChecker({
          source: cssFunctionString,
          index: match.startIndex,
          err: message => {
            report({
              message,
              node: decl,
              index: functionOffset + cssFunction.sourceIndex + match.startIndex,
              result,
              ruleName: checkedRuleName,
            })
          },
        })
      })
    })
  })
}
<commit_msg>Fix nested function comma bug; closes #494<commit_after>import valueParser from "postcss-value-parser"
import {
  declarationValueIndexOffset,
  report,
  ruleMessages,
  styleSearch,
  validateOptions,
  whitespaceChecker,
} from "../../utils"

export const ruleName = "function-comma-space-after"

export const messages = ruleMessages(ruleName, {
  expectedAfter: () => `Expected single space after ","`,
  rejectedAfter: () => `Unexpected whitespace after ","`,
  expectedAfterSingleLine: () => `Expected single space after "," in a single-line function`,
  rejectedAfterSingleLine: () => `Unexpected whitespace after "," in a single-line function`,
})

export default function (expectation) {
  const checker = whitespaceChecker("space", expectation, messages)
  return (root, result) => {
    const validOptions = validateOptions(result, ruleName, {
      actual: expectation,
      possible: [
        "always",
        "never",
        "always-single-line",
        "never-single-line",
      ],
    })
    if (!validOptions) { return }

    functionCommaSpaceChecker({
      root,
      result,
      locationChecker: checker.after,
      checkedRuleName: ruleName,
    })
  }
}

export function functionCommaSpaceChecker({ locationChecker, root, result, checkedRuleName }) {
  root.walkDecls(decl => {
    valueParser(decl.value).walk(valueNode => {
      if (valueNode.type !== "function") { return }

      let functionArguments = (() => {
        let result = valueParser.stringify(valueNode)
        // Remove function name and opening paren
        result = result.slice(valueNode.value.length + 1)
        // Remove closing paren
        result = result.slice(0, result.length - 1)
        return result
      })()

      styleSearch({
        source: functionArguments,
        target: ",",
        outsideFunctionalNotation: true,
      }, (match) => {
        locationChecker({
          source: functionArguments,
          index: match.startIndex,
          err: (message) => {
            const index = declarationValueIndexOffset(decl) +
              valueNode.value.length + 1 +
              valueNode.sourceIndex +
              match.startIndex
            report({
              index,
              message,
              node: decl,
              result,
              ruleName: checkedRuleName,
            })
          },
        })
      })
    })
  })
}

{'fraction_non_alphanumeric': 0.11517615176151762, 'fraction_numerical': 0.0015808491418247517, 'mean_word_length': 2.5432, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3622474', 'n_tokens_mistral': 1166, 'n_tokens_neox': 1176, 'n_words': 276}