Initial commit

This commit is contained in:
Patrick Marsceill
2017-03-09 13:16:08 -05:00
commit b7b0d0d7bf
4147 changed files with 401224 additions and 0 deletions

10
node_modules/stylelint/lib/utils/atRuleParamIndex.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
/* @flow */
"use strict"
module.exports = function (atRule/*: postcss$atRule*/)/*: number*/ {
// Initial 1 is for the `@`
let index = 1 + atRule.name.length
if (atRule.raws.afterName) {
index += atRule.raws.afterName.length
}
return index
}

43
node_modules/stylelint/lib/utils/beforeBlockString.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
/* @flow */
"use strict"
module.exports = function (
statement/*: Object*/,
options/*:: ?: Object*/
)/*: string*/ {
options = options || {}
let result = ""
let rule/*: postcss$rule*/
let atRule/*: postcss$atRule*/
if (statement.type === "rule") {
rule = statement
}
if (statement.type === "atrule") {
atRule = statement
}
if (!rule && !atRule) {
return result
}
const before = (statement.raws.before || "")
if (!options.noRawBefore) {
result += before
}
if (rule) {
result += rule.selector
}
if (atRule) {
result += "@" + atRule.name + (atRule.raws.afterName || "") + atRule.params
}
const between = statement.raws.between
if (between !== undefined) {
result += between
}
return result
}

21
node_modules/stylelint/lib/utils/blockString.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/* @flow */
"use strict"
const beforeBlockString = require("./beforeBlockString")
const hasBlock = require("./hasBlock")
const rawNodeString = require("./rawNodeString")
/**
* Return a CSS statement's block -- the string that starts and `{` and ends with `}`.
*
* If the statement has no block (e.g. `@import url(foo.css);`),
* return undefined.
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {string|undefined}
*/
module.exports = function (statement/*: postcss$rule | postcss$atRule*/)/*: string | boolean*/ {
if (!hasBlock(statement)) {
return false
}
return rawNodeString(statement).slice(beforeBlockString(statement).length)
}

7
node_modules/stylelint/lib/utils/blurComments.js generated vendored Normal file
View File

@@ -0,0 +1,7 @@
/* @flow */
"use strict"
module.exports = function (source/*: string*/)/*: string*/ {
const blurChar/*: string*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "`"
return source.replace(/\/\*.*\*\//g, blurChar)
}

View File

@@ -0,0 +1,43 @@
/* @flow */
"use strict"
const _ = require("lodash")
const balancedMatch = require("balanced-match")
/**
* Replace all of the characters that are arguments to a certain
* CSS function with some innocuous character.
*
* This is useful if you need to use a RegExp to find a string
* but want to ignore matches in certain functions (e.g. `url()`,
* which might contain all kinds of false positives).
*
* For example:
* blurFunctionArguments("abc url(abc) abc", "url") === "abc url(```) abc"
*
* @param {string} source
* @param {string} functionName
* @param {[string]} blurChar="`"
* @return {string} - The result string, with the function arguments "blurred"
*/
module.exports = function (source/*: string*/, functionName/*: string*/)/*: string*/ {
const blurChar/*: string*/ = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "`"
const nameWithParen = `${functionName.toLowerCase()}(`
const lowerCaseSource = source.toLowerCase()
if (!_.includes(lowerCaseSource, nameWithParen)) {
return source
}
const functionNameLength/*: number*/ = functionName.length
let result = source
let searchStartIndex = 0
while (lowerCaseSource.indexOf(nameWithParen, searchStartIndex) !== -1) {
const openingParenIndex = lowerCaseSource.indexOf(nameWithParen, searchStartIndex) + functionNameLength
const closingParenIndex = balancedMatch("(", ")", lowerCaseSource.slice(openingParenIndex)).end + openingParenIndex
const argumentsLength = closingParenIndex - openingParenIndex - 1
result = result.slice(0, openingParenIndex + 1) + _.repeat(blurChar, argumentsLength) + result.slice(closingParenIndex)
searchStartIndex = closingParenIndex
}
return result
}

View File

@@ -0,0 +1,7 @@
/* @flow */
"use strict"
module.exports = function (source/*: string*/)/*: string*/ {
const blurChar/*: string*/ = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : " "
return source.replace(/[#@{}]+/g, blurChar)
}

31
node_modules/stylelint/lib/utils/checkAgainstRule.js generated vendored Normal file
View File

@@ -0,0 +1,31 @@
/* @flow */
"use strict"
const Result = require("postcss/lib/result")
const normalizeRuleSettings = require("../normalizeRuleSettings")
const rules = require("../rules")
// Useful for third-party code (e.g. plugins) to run a PostCSS Root
// against a specific rule and do something with the warnings
module.exports = function (
options/*: {
ruleName: string,
ruleSettings: stylelint$configRuleSettings,
root: Object,
}*/,
callback/*: Function*/
) {
if (!options) throw new Error("checkAgainstRule requires an options object with 'ruleName', 'ruleSettings', and 'root' properties")
if (!callback) throw new Error("checkAgainstRule requires a callback")
if (!options.ruleName) throw new Error("checkAgainstRule requires a 'ruleName' option")
if (!rules[options.ruleName]) throw new Error(`Rule '${options.ruleName}' does not exist`)
if (!options.ruleSettings) throw new Error("checkAgainstRule requires a 'ruleSettings' option")
if (!options.root) throw new Error("checkAgainstRule requires a 'root' option")
const settings = normalizeRuleSettings(options.ruleSettings, options.ruleName)
if (!settings) { return }
const tmpPostcssResult = new Result()
rules[options.ruleName](settings[0], settings[1])(options.root, tmpPostcssResult)
tmpPostcssResult.warnings().forEach(callback)
}

11
node_modules/stylelint/lib/utils/configurationError.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
/* @flow */
"use strict"
/**
* Create configurationError from text and set CLI exit code
*/
module.exports = function (text/*: string */)/* Object */ {
const err/*: Object*/ = new Error(text)
err.code = 78
return err
}

39
node_modules/stylelint/lib/utils/containsString.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
/* @flow */
"use strict"
/**
* Checks if a string contains a value. The comparison value can be a string or
* an array of strings.
*
* Any strings starting and ending with `/` are ignored. Use the
* matchesStringOrRegExp() util to match regexes.
*/
module.exports = function containsString(
input/*: string*/,
comparison/*: string | Array<string>*/
)/*: false | { match: string, pattern: string }*/ {
if (!Array.isArray(comparison)) {
return testAgainstString(input, comparison)
}
for (const comparisonItem of comparison) {
const testResult = testAgainstString(input, comparisonItem)
if (testResult) {
return testResult
}
}
return false
}
function testAgainstString(value, comparison) {
if (!comparison) return false
if (comparison[0] === "/" && comparison[comparison.length - 1] === "/") {
return false
}
if (value.indexOf(comparison) >= 0) {
return { match: value, pattern: comparison }
}
return false
}

View File

@@ -0,0 +1,11 @@
/* @flow */
"use strict"
/**
* Get the index of a declaration's value
*/
module.exports = function (decl/*: Object*/)/*: number*/ {
const beforeColon = decl.toString().indexOf(":")
const afterColon = decl.raw("between").length - decl.raw("between").indexOf(":")
return beforeColon + afterColon
}

55
node_modules/stylelint/lib/utils/findAnimationName.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
/* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const getUnitFromValueNode = require("./getUnitFromValueNode")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isVariable = require("./isVariable")
const postcssValueParser = require("postcss-value-parser")
/**
* Get the font-families within a `font` shorthand property value.
*/
module.exports = function findAnimationName(value/*: string*/)/*: Array<Object>*/ {
const animationNames = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.basicKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
valueNodes.walk(valueNode => {
if (valueNode.type === "function") {
return false
}
if (valueNode.type !== "word") {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.animationShorthandKeywords.has(valueLowerCase)) {
return
}
// Ignore numbers with units
const unit = getUnitFromValueNode(valueNode)
if (unit || unit === "") {
return
}
animationNames.push(valueNode)
})
return animationNames
}

21
node_modules/stylelint/lib/utils/findAtRuleContext.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/* @flow */
"use strict"
/**
* Find the at-rule in which a rule is nested.
*
* Returns `null` if the rule is not nested within an at-rule.
*/
module.exports = function findAtRuleContext(
rule/*: postcss$rule */
)/*: ?postcss$atRule*/ {
const parent = rule.parent
if (parent.type === "root") {
return null
}
if (parent.type === "atrule") {
return parent
}
return findAtRuleContext(parent)
}

99
node_modules/stylelint/lib/utils/findFontFamily.js generated vendored Normal file
View File

@@ -0,0 +1,99 @@
/* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const isNumbery = require("./isNumbery")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isValidFontSize = require("./isValidFontSize")
const isVariable = require("./isVariable")
const postcssValueParser = require("postcss-value-parser")
const nodeTypesToCheck = new Set([ "word", "string", "space", "div" ])
function joinValueNodes(firstNode, secondNode, charactersBetween) {
firstNode.value = firstNode.value + charactersBetween + secondNode.value
return firstNode
}
/**
* Get the font-families within a `font` shorthand property value.
*
* @param {string} value
* @return {object} Collection font-family nodes
*/
module.exports = function findFontFamily(value/*: string*/)/*: Array<Object>*/ {
const fontFamilies = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.basicKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
let needMergeNodesByValue = false
let mergeCharacters = null
valueNodes.walk((valueNode, index, nodes) => {
if (valueNode.type === "function") {
return false
}
if (!nodeTypesToCheck.has(valueNode.type)) {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.fontShorthandKeywords.has(valueLowerCase) && !keywordSets.fontFamilyKeywords.has(valueLowerCase)) {
return
}
// Ignore font-sizes
if (isValidFontSize(valueNode.value)) {
return
}
// Ignore anything come after a <font-size>/, because it's a line-height
if (nodes[index - 1] && nodes[index - 1].value === "/" && nodes[index - 2] && isValidFontSize(nodes[index - 2].value)) {
return
}
// Ignore number values
if (isNumbery(valueLowerCase)) {
return
}
// Detect when a space or comma is dividing a list of font-families, and save the joining character.
if ((valueNode.type === "space" || valueNode.type === "div" && valueNode.value !== ",") && fontFamilies.length !== 0) {
needMergeNodesByValue = true
mergeCharacters = valueNode.value
return
} else if (valueNode.type === "space" || valueNode.type === "div") {
return
}
const fontFamily = valueNode
if (needMergeNodesByValue) {
joinValueNodes(fontFamilies[fontFamilies.length - 1], valueNode, mergeCharacters)
needMergeNodesByValue = false
mergeCharacters = null
} else {
fontFamilies.push(fontFamily)
}
})
return fontFamilies
}

49
node_modules/stylelint/lib/utils/findListStyleType.js generated vendored Normal file
View File

@@ -0,0 +1,49 @@
/* @flow */
"use strict"
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const isVariable = require("./isVariable")
const keywordSets = require("../reference/keywordSets")
const postcssValueParser = require("postcss-value-parser")
/**
* Get the list-style-type within a `list-style` shorthand property value.
*/
module.exports = function findListStyleType(value/*: string*/)/*: Array<Object>*/ {
const listStyleTypes = []
const valueNodes = postcssValueParser(value)
// Handle `inherit`, `initial` and etc
if (valueNodes.nodes.length === 1 && keywordSets.listStyleTypeKeywords.has(valueNodes.nodes[0].value.toLowerCase())) {
return [valueNodes.nodes[0]]
}
valueNodes.walk(valueNode => {
if (valueNode.type === "function") {
return false
}
if (valueNode.type !== "word") {
return
}
const valueLowerCase = valueNode.value.toLowerCase()
// Ignore non standard syntax
if (!isStandardSyntaxValue(valueLowerCase)) {
return
}
// Ignore variables
if (isVariable(valueLowerCase)) {
return
}
// Ignore keywords for other font parts
if (keywordSets.listStylePositionKeywords.has(valueLowerCase) || keywordSets.listStyleImageKeywords.has(valueLowerCase)) {
return
}
listStyleTypes.push(valueNode)
})
return listStyleTypes
}

View File

@@ -0,0 +1,33 @@
/* @flow */
"use strict"
const balancedMatch = require("balanced-match")
const styleSearch = require("style-search")
/**
* Search a CSS string for functions by name.
* For every match, invoke the callback, passing the function's
* "argument(s) string" (whatever is inside the parentheses)
* as an argument.
*
* Callback will be called once for every matching function found,
* with the function's "argument(s) string" and its starting index
* as the arguments.
*/
module.exports = function (
source/*: string*/,
functionName/*: string*/,
callback/*: Function*/
) {
styleSearch({
source,
target: functionName,
functionNames: "check",
}, match => {
if (source[match.endIndex] !== "(") {
return
}
const parensMatch = balancedMatch("(", ")", source.substr(match.startIndex))
callback(parensMatch.body, match.endIndex + 1)
})
}

17
node_modules/stylelint/lib/utils/getIsFileIgnored.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
"use strict"
const ignore = require("ignore")
const micromatch = require("micromatch")
const path = require("path")
module.exports = function getIsFileIgnored(
ignorePatterns/*: Array<string>*/,
ignoreFiles/*: string | Array<string>*/
)/*: Function */ {
const ignorePatternsFilter = ignore().add(ignorePatterns).createFilter()
return file => {
const filepathRelativeToCwd = path.relative(process.cwd(), file)
return ignorePatternsFilter && !ignorePatternsFilter(filepathRelativeToCwd) || ignoreFiles && micromatch(file, ignoreFiles).length
}
}

18
node_modules/stylelint/lib/utils/getModulePath.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
/* @flow */
"use strict"
const configurationError = require("./configurationError")
const resolveFrom = require("resolve-from")
module.exports = function (basedir/*: string*/, lookup/*: string*/)/*: string*/ {
// First try to resolve from the provided directory,
// then try to resolve from process.cwd.
let path = resolveFrom(basedir, lookup)
if (!path) {
path = resolveFrom(process.cwd(), lookup)
}
if (!path) {
throw configurationError(`Could not find "${lookup}". Do you need a \`configBasedir\`?`)
}
return path
}

View File

@@ -0,0 +1,36 @@
/* @flow */
"use strict"
const blurInterpolation = require("./blurInterpolation")
const _ = require("lodash")
const isStandardSyntaxValue = require("./isStandardSyntaxValue")
const valueParser = require("postcss-value-parser")
/**
* Get unit from value node
*
* Returns `null` if the unit is not found.
*/
module.exports = function (node/*: Object*/)/*: ?string*/ {
if (!node || node && !node.value) {
return null
}
const value = blurInterpolation(node.value, "")
// ignore hack unit
.replace("\\0", "").replace("\\9", "")
// ignore decimal place
.replace(".", "")
if (node.type !== "word" || !isStandardSyntaxValue(value) || !_.isFinite(parseInt(value)) || node.value[0] === "#") {
return null
}
const parsedUnit = valueParser.unit(value)
if (!parsedUnit) {
return null
}
return parsedUnit.unit
}

14
node_modules/stylelint/lib/utils/hasBlock.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
/* @flow */
"use strict"
/**
* Check if a statement has an block (empty or otherwise).
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {boolean} True if `statement` has a block (empty or otherwise)
*/
module.exports = function (
statement/*: postcss$rule | postcss$atRule*/
)/*: boolean*/ {
return statement.nodes !== undefined
}

15
node_modules/stylelint/lib/utils/hasEmptyBlock.js generated vendored Normal file
View File

@@ -0,0 +1,15 @@
/* @flow */
"use strict"
/**
* Check if a statement has an empty block.
*
* @param {Rule|AtRule} statement - postcss rule or at-rule node
* @return {boolean} True if the statement has a block and it is empty
*/
module.exports = function (
statement/*: postcss$rule | postcss$atRule*/
)/*: boolean*/ {
return statement.nodes !== undefined // has block
&& statement.nodes.length === 0 // and is empty
}

10
node_modules/stylelint/lib/utils/hasEmptyLine.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
/* @flow */
"use strict"
/**
* Check if a string contains at least one empty line
*/
module.exports = function (string/*:: ?: string*/)/*: boolean*/ {
if (string === "" || string === undefined) return false
return string.indexOf("\n\n") !== -1 || string.indexOf("\n\r\n") !== -1
}

20
node_modules/stylelint/lib/utils/hasInterpolation.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/* @flow */
"use strict"
const hasLessInterpolation = require("../utils/hasLessInterpolation")
const hasPsvInterpolation = require("../utils/hasPsvInterpolation")
const hasScssInterpolation = require("../utils/hasScssInterpolation")
/**
* Check whether a string has interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
// SCSS or Less interpolation
if (hasLessInterpolation(string) || hasScssInterpolation(string) || hasPsvInterpolation(string)) {
return true
}
return false
}

View File

@@ -0,0 +1,16 @@
/* @flow */
"use strict"
/**
* Check whether a string has less interpolation
*
* @param {string} string
* @return {boolean} If `true`, a string has less interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
if (/@{.+?}/.test(string)) {
return true
}
return false
}

View File

@@ -0,0 +1,13 @@
/* @flow */
"use strict"
/**
* Check whether a string has postcss-simple-vars interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
if (/\$\(.+?\)/.test(string)) {
return true
}
return false
}

View File

@@ -0,0 +1,13 @@
/* @flow */
"use strict"
/**
* Check whether a string has scss interpolation
*/
module.exports = function (string/*: string*/)/*: boolean*/ {
if (/#{.+?}/.test(string)) {
return true
}
return false
}

50
node_modules/stylelint/lib/utils/isAutoprefixable.js generated vendored Normal file
View File

@@ -0,0 +1,50 @@
/* @flow */
"use strict"
const Browsers = require("autoprefixer/lib/browsers")
const Prefixes = require("autoprefixer/lib/prefixes")
const autoprefixer = require("autoprefixer")
/**
* Use Autoprefixer's secret powers to determine whether or
* not a certain CSS identifier contains a vendor prefix that
* Autoprefixer, given the standardized identifier, could add itself.
*
* Used by `*-no-vendor-prefix-*` rules to find superfluous
* vendor prefixes.
*/
const prefixes = new Prefixes(autoprefixer.data.prefixes, new Browsers(autoprefixer.data.browsers, []))
/**
* Most identifier types have to be looked up in a unique way,
* so we're exposing special functions for each.
*/
module.exports = {
atRuleName(identifier/*: string*/)/*: boolean*/ {
return prefixes.remove[`@${identifier.toLowerCase()}`]
},
selector(identifier/*: string*/)/*: boolean*/ {
return prefixes.remove.selectors.some(selectorObj => {
return identifier.toLowerCase() === selectorObj.prefixed
})
},
mediaFeatureName(identifier/*: string*/)/*: boolean*/ {
return identifier.toLowerCase().indexOf("device-pixel-ratio") !== -1
},
property(identifier/*: string*/)/*: boolean*/ {
return autoprefixer.data.prefixes[prefixes.unprefixed(identifier.toLowerCase())]
},
propertyValue(prop/*: string*/, value/*: string*/)/*: boolean*/ {
const possiblePrefixableValues = prefixes.remove[prop.toLowerCase()] && prefixes.remove[prop.toLowerCase()].values
return possiblePrefixableValues && possiblePrefixableValues.some(valueObj => {
return value.toLowerCase() === valueObj.prefixed
})
},
}

View File

@@ -0,0 +1,19 @@
/* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const _ = require("lodash")
/**
* Check value is a custom ident
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
const valueLowerCase = value.toLowerCase()
if (keywordSets.counterIncrementKeywords.has(valueLowerCase) || _.isFinite(parseInt(valueLowerCase))) {
return false
}
return true
}

View File

@@ -0,0 +1,9 @@
/* @flow */
"use strict"
/**
* Check whether a media query is a custom
*/
module.exports = function (mediaQuery/*: string*/)/*: boolean*/ {
return mediaQuery.slice(0, 2) === "--"
}

9
node_modules/stylelint/lib/utils/isCustomProperty.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/* @flow */
"use strict"
/**
* Check whether a property is a custom one
*/
module.exports = function (property/*: string*/)/*: boolean*/ {
return property.slice(0, 2) === "--"
}

View File

@@ -0,0 +1,14 @@
/* @flow */
"use strict"
const _ = require("lodash")
const hasBlock = require("../utils/hasBlock")
/**
* Check whether a Node is a custom property set
*/
module.exports = function (node/*: Object*/)/*: boolean*/ {
const selector = _.get(node, "raws.selector.raw", node.selector)
return node.type === "rule" && hasBlock(node) && selector.slice(0, 2) === "--" && selector.slice(-1) === ":"
}

9
node_modules/stylelint/lib/utils/isCustomSelector.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/* @flow */
"use strict"
/**
* Check whether a selector is a custom one
*/
module.exports = function (selector/*: string*/)/*: boolean*/ {
return (selector.slice(0, 3) === ":--")
}

11
node_modules/stylelint/lib/utils/isKeyframeRule.js generated vendored Normal file
View File

@@ -0,0 +1,11 @@
/* @flow */
"use strict"
/**
* Check if a rule is a keyframe one
*/
module.exports = function (rule/*: postcss$rule*/)/*: boolean*/ {
const parent = rule.parent
return parent.type === "atrule" && parent.name.toLowerCase() === "keyframes"
}

20
node_modules/stylelint/lib/utils/isKeyframeSelector.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
/**
* Check whether a string is a keyframe selector.
*/
module.exports = function (selector/*: string*/)/*: boolean*/ {
if (keywordSets.keyframeSelectorKeywords.has(selector)) {
return true
}
// Percentages
if (/^(?:\d+\.?\d*|\d*\.?\d+)%$/.test(selector)) {
return true
}
return false
}

10
node_modules/stylelint/lib/utils/isNumbery.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
// Too weird for Flow
"use strict"
/**
* Check whether it's a number or a number-like string:
* i.e. when coerced to a number it == itself.
*/
module.exports = function (value) {
return value.trim().length !== 0 && Number(value) == value
}

18
node_modules/stylelint/lib/utils/isOnlyWhitespace.js generated vendored Normal file
View File

@@ -0,0 +1,18 @@
/* @flow */
"use strict"
const isWhitespace = require("./isWhitespace")
/**
* Returns a Boolean indicating whether the the input string is only whitespace.
*/
module.exports = function (input/*: string*/)/*: boolean*/ {
let isOnlyWhitespace = true
for (let i = 0, l = input.length; i < l; i++) {
if (!isWhitespace(input[i])) {
isOnlyWhitespace = false
break
}
}
return isOnlyWhitespace
}

View File

@@ -0,0 +1,12 @@
/* @flow */
"use strict"
/**
* Check whether a media feature is a range context one
*
* @param {string} media feature
* @return {boolean} If `true`, media feature is a range context one
*/
module.exports = function (mediaFeature/*: string*/)/*: boolean*/ {
return mediaFeature.indexOf("=") !== -1 || mediaFeature.indexOf("<") !== -1 || mediaFeature.indexOf(">") !== -1
}

13
node_modules/stylelint/lib/utils/isSingleLineString.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
/* @flow */
"use strict"
/**
* Check if a string is a single line (i.e. does not contain
* any newline characters).
*
* @param {string} input
* @return {boolean}
*/
module.exports = function (input/*: string*/)/*: boolean*/ {
return !/[\n\r]/.test(input)
}

View File

@@ -0,0 +1,22 @@
/* @flow */
"use strict"
/**
* Check whether a at-rule is standard
*
* @param {atRule} postcss at-rule node
* @return {boolean} If `true`, the declaration is standard
*/
module.exports = function (atRule/*: postcss$atRule*/)/*: boolean*/ {
// Ignore scss `@content` inside mixins
if (!atRule.nodes && atRule.params === "") {
return false
}
// Ignore detached ruleset `@detached-ruleset: { background: red; }; .top { @detached-ruleset(); }`
if (!atRule.nodes && atRule.raws.afterName === "" && atRule.params[0] === "(") {
return false
}
return true
}

View File

@@ -0,0 +1,33 @@
/* @flow */
"use strict"
/**
* Check whether a declaration is standard
*/
module.exports = function (decl/*: Object*/)/*: boolean*/ {
const prop = decl.prop,
parent = decl.parent
// Declarations belong in a declaration block
if (parent.type === "root") {
return false
}
// SCSS var (e.g. $var: x), nested list (e.g. $list: (x)) or nested map (e.g. $map: (key:value))
if (prop[0] === "$") {
return false
}
// Less var (e.g. @var: x), but exclude variable interpolation (e.g. @{var})
if (prop[0] === "@" && prop[1] !== "{") {
return false
}
// SCSS nested properties (e.g. border: { style: solid; color: red; })
if (parent.selector && parent.selector[parent.selector.length - 1] === ":" && parent.selector.substring(0, 2) !== "--") {
return false
}
return true
}

View File

@@ -0,0 +1,14 @@
/* @flow */
"use strict"
/**
* Check whether a function is standard
*/
module.exports = function (node/*: Object*/)/*: boolean*/ {
// Function nodes without names are things in parentheses like Sass lists
if (!node.value) {
return false
}
return true
}

View File

@@ -0,0 +1,23 @@
/* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a media feature is standard
*/
module.exports = function (mediaFeature/*: string*/)/*: boolean*/ {
// Remove outside parens
mediaFeature = mediaFeature.slice(1, -1)
// Parentheticals used for non-standard operations e.g. ($var - 10)
if (mediaFeature.indexOf("(") !== -1) {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(mediaFeature)) {
return false
}
return true
}

View File

@@ -0,0 +1,14 @@
/* @flow */
"use strict"
/**
* Check whether a media feature name is standard
*/
module.exports = function (mediaFeatureName/*: string*/)/*: boolean*/ {
// SCSS interpolation
if (/#{.+?}|\$.+?/.test(mediaFeatureName)) {
return false
}
return true
}

View File

@@ -0,0 +1,25 @@
/* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a property is standard
*/
module.exports = function (property/*: string*/)/*: boolean*/ {
// SCSS var (e.g. $var: x), list (e.g. $list: (x)) or map (e.g. $map: (key:value))
if (property[0] === "$") {
return false
}
// Less var (e.g. @var: x)
if (property[0] === "@") {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(property)) {
return false
}
return true
}

View File

@@ -0,0 +1,46 @@
/* @flow */
"use strict"
const _ = require("lodash")
const isCustomPropertySet = require("../utils/isCustomPropertySet")
/**
* Check whether a Node is a standard rule
*/
module.exports = function (rule/*: Object*/)/*: boolean*/ {
// Get full selector
const selector = _.get(rule, "raws.selector.raw", rule.selector)
// Custom property set (e.g. --custom-property-set: {})
if (isCustomPropertySet(rule)) {
return false
}
// Called Less mixin (e.g. a { .mixin() })
if (rule.ruleWithoutBody) {
return false
}
// Less detached rulesets
if (selector.slice(0, 1) === "@" && selector.slice(-1) === ":") {
return false
}
// Ignore mixin or &:extend rule
// https://github.com/webschik/postcss-less/blob/master/lib/less-parser.js#L52
if (rule.params && rule.params[0]) {
return false
}
// Non-outputting Less mixin definition (e.g. .mixin() {})
if (_.endsWith(selector, ")") && !_.includes(selector, ":")) {
return false
}
// Ignore Scss nested properties
if (selector.slice(-1) === ":") {
return false
}
return true
}

View File

@@ -0,0 +1,20 @@
/* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a selector is standard
*/
module.exports = function (selector/*: string*/)/*: boolean*/ {
// SCSS or Less interpolation
if (hasInterpolation(selector)) {
return false
}
// SCSS placeholder selectors
if (selector.indexOf("%") === 0) {
return false
}
return true
}

View File

@@ -0,0 +1,39 @@
/* @flow */
"use strict"
/**
* Check whether a type selector is standard
*
* @param {Node} postcss-selector-parser node (of type tag)
* @return {boolean} If `true`, the type selector is standard
*/
const keywordSets = require("../reference/keywordSets")
module.exports = function (node/*: Object*/)/*: boolean*/ {
// postcss-selector-parser includes the arguments to nth-child() functions
// as "tags", so we need to ignore them ourselves.
// The fake-tag's "parent" is actually a selector node, whose parent
// should be the :nth-child pseudo node.
const _node$parent$parent = node.parent.parent
const parentType = _node$parent$parent.type,
parentValue = _node$parent$parent.value
if (parentValue) {
const normalisedParentName = parentValue.toLowerCase().replace(/:+/, "")
if (parentType === "pseudo" && (keywordSets.aNPlusBNotationPseudoClasses.has(normalisedParentName) || keywordSets.linguisticPseudoClasses.has(normalisedParentName))) {
return false
}
}
// &-bar is a nesting selector combined with a suffix
if (node.prev() && node.prev().type === "nesting") {
return false
}
if (node.value[0] === "%") {
return false
}
return true
}

View File

@@ -0,0 +1,45 @@
/* @flow */
"use strict"
const hasLessInterpolation = require("../utils/hasLessInterpolation")
const hasPsvInterpolation = require("../utils/hasPsvInterpolation")
const hasScssInterpolation = require("../utils/hasScssInterpolation")
/**
* Check whether a URL is standard
*/
module.exports = function (url/*: string*/)/*: boolean*/ {
if (url.length === 0) {
return true
}
// Sass interpolation works anywhere
if (hasScssInterpolation(url) || hasPsvInterpolation(url)) {
return false
}
// Inside `'` and `"` work only LESS interpolation
if (url[0] === "'" && url[url.length - 1] === "'" || url[0] === "\"" && url[url.length - 1] === "\"") {
if (hasLessInterpolation(url)) {
return false
}
return true
}
// Less variable works only at the beginning
// Check is less variable, allow use '@url/some/path'
// https://github.com/less/less.js/blob/3.x/lib/less/parser/parser.js#L547
if (url[0] === "@" && /^@@?[\w-]+$/.test(url)) {
return false
}
// In url without quotes scss variable can be everywhere
// But in this case it is allowed to use only specific characters
// Also forbidden "/" at the end of url
if (url.indexOf("$") !== -1 && /^[\$\sA-Za-z0-9+-/*_'"\/]+$/.test(url) && url[url.length - 1] !== "/") {
return false
}
return true
}

View File

@@ -0,0 +1,25 @@
/* @flow */
"use strict"
const hasInterpolation = require("../utils/hasInterpolation")
/**
* Check whether a value is standard
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
// SCSS variable
if (value[0] === "$") {
return false
}
// Less variable
if (value[0] === "@") {
return false
}
// SCSS or Less interpolation
if (hasInterpolation(value)) {
return false
}
return true
}

34
node_modules/stylelint/lib/utils/isValidFontSize.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
/* @flow */
"use strict"
const keywordSets = require("../reference/keywordSets")
const valueParser = require("postcss-value-parser")
/**
* Check if a word is a font-size value.
*/
module.exports = function (word/*: string*/)/*: boolean*/ {
if (!word) {
return false
}
if (keywordSets.fontSizeKeywords.has(word)) {
return true
}
const numberUnit = valueParser.unit(word)
if (!numberUnit) {
return false
}
const unit = numberUnit.unit
if (unit === "%") {
return true
}
if (keywordSets.lengthUnits.has(unit.toLowerCase())) {
return true
}
return false
}

10
node_modules/stylelint/lib/utils/isValidHex.js generated vendored Normal file
View File

@@ -0,0 +1,10 @@
/* @flow */
"use strict"
/**
* Check if a value is a valid 3, 4, 6 or 8 digit hex
*/
module.exports = function (value/*: string*/)/*: boolean*/ {
return (/^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value)
)
}

9
node_modules/stylelint/lib/utils/isVariable.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/* @flow */
"use strict"
/**
* Check whether a word is a variable i.e var(--custom-property).
*/
module.exports = function (word/*: string*/)/*: boolean*/ {
return word.toLowerCase().slice(0, 4) === "var("
}

9
node_modules/stylelint/lib/utils/isWhitespace.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
/* @flow */
"use strict"
/**
* Check if a character is whitespace.
*/
module.exports = function (char/*: string*/)/*: boolean*/ {
return [ " ", "\n", "\t", "\r", "\f" ].indexOf(char) !== -1
}

View File

@@ -0,0 +1,53 @@
/* @flow */
"use strict"
/**
* Compares a string to a second value that, if it fits a certain convention,
* is converted to a regular expression before the comparison.
* If it doesn't fit the convention, then two strings are compared.
*
* Any strings starting and ending with `/` are interpreted
* as regular expressions.
*/
module.exports = function matchesStringOrRegExp(
input/*: string | Array<string>*/,
comparison/*: string | Array<string>*/
)/*: false | { match: string, pattern: string}*/ {
if (!Array.isArray(input)) {
return testAgainstStringOrArray(input, comparison)
}
for (const inputItem of input) {
const testResult = testAgainstStringOrArray(inputItem, comparison)
if (testResult) {
return testResult
}
}
return false
}
function testAgainstStringOrArray(value, comparison) {
if (!Array.isArray(comparison)) {
return testAgainstString(value, comparison)
}
for (const comparisonItem of comparison) {
const testResult = testAgainstString(value, comparisonItem)
if (testResult) {
return testResult
}
}
return false
}
function testAgainstString(value, comparison) {
const comparisonIsRegex = comparison[0] === "/" && comparison[comparison.length - 1] === "/"
if (comparisonIsRegex) {
const valueMatches = new RegExp(comparison.slice(1, -1)).test(value)
return valueMatches ? { match: value, pattern: comparison } : false
}
return value === comparison ? { match: value, pattern: comparison } : false
}

16
node_modules/stylelint/lib/utils/nextNonCommentNode.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/* @flow */
"use strict"
/**
* Get the next non-comment node in a PostCSS AST
* at or after a given node.
*/
module.exports = function nextNonCommentNode(startNode/*: Object*/)/*: ?Object*/ {
if (!startNode || !startNode.next) return null
if (startNode.type === "comment") {
return nextNonCommentNode(startNode.next())
}
return startNode
}

35
node_modules/stylelint/lib/utils/nodeContextLookup.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
// Too weird for Flow
"use strict"
/**
* Create a collection of Maps that serve to contextualize a given node.
* This is useful to ensure that you only compare nodes that share a certain
* context.
*
* All nodes are initially contextualized by their input source.
* From there, you can contextualize them however you want.
*
* For a usage example, see `selector-no-descending-specificity`.
*/
module.exports = function () {
const contextMap = new Map()
return {
getContext(node) {
const nodeSource = node.source.input.from
const baseContext = creativeGetMap(contextMap, nodeSource)
const subContexts = Array.from(arguments).slice(1)
return subContexts.reduce((result, context) => {
return creativeGetMap(result, context)
}, baseContext)
},
}
}
function creativeGetMap(someMap, someThing) {
if (!someMap.has(someThing)) {
someMap.set(someThing, new Map())
}
return someMap.get(someThing)
}

16
node_modules/stylelint/lib/utils/optionsMatches.js generated vendored Normal file
View File

@@ -0,0 +1,16 @@
/* @flow */
"use strict"
const matchesStringOrRegExp = require("./matchesStringOrRegExp")
/**
* Check if an options object's propertyName contains a user-defined string or
* regex that matches the passed in input.
*/
module.exports = function optionsMatches(
options/*: Object*/,
propertyName/*: string*/,
input/*: string*/
)/*: boolean*/ {
return !!(options && options[propertyName] && typeof input === "string" && matchesStringOrRegExp(input.toLowerCase(), options[propertyName]))
}

17
node_modules/stylelint/lib/utils/parseSelector.js generated vendored Normal file
View File

@@ -0,0 +1,17 @@
/* @flow */
"use strict"
const selectorParser = require("postcss-selector-parser")
module.exports = function (
selector/*: string*/,
result/*: Object*/,
node/*: Object*/,
cb/*: Function*/
) {
try {
selectorParser(cb).process(selector)
} catch (e) {
result.warn("Cannot parse selector", { node })
}
}

14
node_modules/stylelint/lib/utils/rawNodeString.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
/* @flow */
"use strict"
/**
* Stringify PostCSS node including its raw "before" string.
*/
module.exports = function (node/*: Object*/)/*: string*/ {
let result = ""
if (node.raws.before) {
result += node.raws.before
}
result += node.toString()
return result
}

81
node_modules/stylelint/lib/utils/report.js generated vendored Normal file
View File

@@ -0,0 +1,81 @@
/* @flow */
"use strict"
const _ = require("lodash")
/**
* Report a violation.
*
* This function accounts for `disabledRanges` attached to the result.
* That is, if the reported violation is within a disabledRange,
* it is ignored. Otherwise, it is attached to the result as a
* postcss warning.
*
* It also accounts for the rule's severity.
*
* You *must* pass *either* a node or a line number.
*/
module.exports = function (violation/*: {
ruleName: string,
result: Object,
message: string,
node: Object,
index?: number,
word?: string,
line?: number
}*/) {
const ruleName = violation.ruleName
const result = violation.result
const message = violation.message
const line = violation.line
const node = violation.node
const index = violation.index
const word = violation.word
result.stylelint = result.stylelint || {}
// In quiet mode, mere warnings are ignored
if (result.stylelint.quiet && result.stylelint.ruleSeverities[ruleName] !== "error") {
return
}
// If a line is not passed, use the node.positionBy method to get the
// line number that the complaint pertains to
const startLine = line || node.positionBy({ index }).line
if (result.stylelint.disabledRanges && !result.stylelint.ignoreDisables) {
const ranges = result.stylelint.disabledRanges[ruleName] || result.stylelint.disabledRanges.all
for (const range of ranges) {
if (
// If the violation is within a disabledRange,
// and that disabledRange's rules include this one,
// do not register a warning
range.start <= startLine && (range.end >= startLine || range.end === undefined) && (!range.rules || range.rules.indexOf(ruleName) !== -1)) {
return
}
}
}
const severity = _.get(result.stylelint, [ "ruleSeverities", ruleName ], "ignore")
if (!result.stylelint.stylelintError && severity === "error") {
result.stylelint.stylelintError = true
}
const warningProperties/*: Object*/ = {
severity,
rule: ruleName,
}
if (node) {
warningProperties.node = node
}
if (index) {
warningProperties.index = index
}
if (word) {
warningProperties.word = word
}
const warningMessage = _.get(result.stylelint, [ "customMessages", ruleName ], message)
result.warn(warningMessage, warningProperties)
}

29
node_modules/stylelint/lib/utils/ruleMessages.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
/* @flow */
"use strict"
/**
* Given an object of violation messages, return another
* that provides the same messages postfixed with the rule
* that has been violated.
*
* @param {string} ruleName
* @param {object} messages - Object whose keys are message identifiers
* and values are either message strings or functions that return message strings
* @return {object} New message object, whose messages will be marked with the rule name
*/
module.exports = function (
ruleName/*: string*/,
messages/*: Object*/
)/*: Object*/ {
return Object.keys(messages).reduce((newMessages, messageId) => {
const messageText = messages[messageId]
if (typeof messageText === "string") {
newMessages[messageId] = `${messageText} (${ruleName})`
} else {
newMessages[messageId] = function () {
return `${messageText.apply(null, arguments)} (${ruleName})`
}
}
return newMessages
}, {})
}

View File

@@ -0,0 +1,29 @@
/* @flow */
"use strict"
const _ = require("lodash")
/**
* Check whether the variable is an object and all it's properties are arrays of string values:
*
* ignoreProperties = {
* value1: ["item11", "item12", "item13"],
* value2: ["item21", "item22", "item23"],
* value3: ["item31", "item32", "item33"],
* }
*/
module.exports = function (value/*: Object*/)/*: boolean*/ {
if (!_.isPlainObject(value)) {
return false
}
return Object.keys(value).every(key => {
if (!_.isArray(value[key])) {
return false
}
// Make sure the array items are strings
return value[key].every(item => _.isString(item))
})
}

132
node_modules/stylelint/lib/utils/validateOptions.js generated vendored Normal file
View File

@@ -0,0 +1,132 @@
/* @flow */
"use strict"
const _ = require("lodash")
const ignoredOptions = [ "severity", "message" ]
/**
* Validate a rule's options.
*
* See existing rules for examples.
*
* @param {Result} result - postcss result
* @param {string} ruleName
* @param {...object} ...optionDescriptions - Each optionDescription can
* have the following properties:
* - `actual` (required): the actual passed option value or object.
* - `possible` (required): a schema representation of what values are
* valid for those options. `possible` should be an object if the
* options are an object, with corresponding keys; if the options are not an
* object, `possible` isn't, either. All `possible` value representations
* should be **arrays of either values or functions**. Values are === checked
* against `actual`. Functions are fed `actual` as an argument and their
* return value is interpreted: truthy = valid, falsy = invalid.
* - `optional` (optional): If this is `true`, `actual` can be undefined.
* @return {boolean} Whether or not the options are valid (true = valid)
*/
module.exports = function (
result/*: Object*/,
ruleName/*: string*/
)/*: boolean*/ {
let noErrors = true
const optionDescriptions = Array.from(arguments).slice(2)
optionDescriptions.forEach(optionDescription => {
validate(optionDescription, ruleName, complain)
})
function complain(message) {
noErrors = false
result.warn(message, {
stylelintType: "invalidOption",
})
_.set(result, "stylelint.stylelintError", true)
}
return noErrors
}
function validate(opts, ruleName, complain) {
const possible = opts.possible
const actual = opts.actual
const optional = opts.optional
if (actual === null || _.isEqual(actual, [null])) {
return
}
const nothingPossible = possible === undefined || Array.isArray(possible) && possible.length === 0
if (nothingPossible && actual === true) {
return
}
if (actual === undefined) {
if (nothingPossible || optional) {
return
}
complain(`Expected option value for rule "${ruleName}"`)
return
} else if (nothingPossible) {
complain(`Unexpected option value "${actual}" for rule "${ruleName}"`)
return
}
// If `possible` is a function ...
if (_.isFunction(possible)) {
if (!possible(actual)) {
complain(`Invalid option "${JSON.stringify(actual)}" for rule ${ruleName}`)
}
return
}
// If `possible` is an array instead of an object ...
if (!_.isPlainObject(possible)) {
[].concat(actual).forEach(a => {
if (isValid(possible, a)) {
return
}
complain(`Invalid option value "${a}" for rule "${ruleName}"`)
})
return
}
// If possible is an object ...
if (!_.isPlainObject(actual)) {
complain(`Invalid option value ${JSON.stringify(actual)} for rule "${ruleName}": ` + "should be an object")
return
}
Object.keys(actual).forEach(optionName => {
if (ignoredOptions.indexOf(optionName) !== -1) {
return
}
if (!possible[optionName]) {
complain(`Invalid option name "${optionName}" for rule "${ruleName}"`)
return
}
const actualOptionValue = actual[optionName];[].concat(actualOptionValue).forEach(a => {
if (isValid(possible[optionName], a)) {
return
}
complain(`Invalid value "${a}" for option "${optionName}" of rule "${ruleName}"`)
})
})
}
function isValid(possible, actual) {
const possibleList = [].concat(possible)
for (let i = 0, l = possibleList.length; i < l; i++) {
const possibility = possibleList[i]
if (typeof possibility === "function" && possibility(actual)) {
return true
}
if (actual === possibility) {
return true
}
}
}

306
node_modules/stylelint/lib/utils/whitespaceChecker.js generated vendored Normal file
View File

@@ -0,0 +1,306 @@
"use strict"
const configurationError = require("./configurationError")
const isSingleLineString = require("./isSingleLineString")
const isWhitespace = require("./isWhitespace")
/**
* Create a whitespaceChecker, which exposes the following functions:
* - `before()`
* - `beforeAllowingIndentation()`
* - `after()`
* - `afterOneOnly()`
*
* @param {"space"|"newline"} targetWhitespace - This is a keyword instead
* of the actual character (e.g. " ") in order to accommodate
* different styles of newline ("\n" vs "\r\n")
* @param {
* "always"|"never"
* |"always-single-line"|"always-multi-line"
* | "never-single-line"|"never-multi-line"
* } expectation
* @param {object} messages - An object of message functions;
* calling `before*()` or `after*()` and the `expectation` that is passed
* determines which message functions are required
* @param {function} [messages.exectedBefore]
* @param {function} [messages.rejectedBefore]
* @param {function} [messages.expectedAfter]
* @param {function} [messages.rejectedAfter]
* @param {function} [messages.expectedBeforeSingleLine]
* @param {function} [messages.rejectedBeforeSingleLine]
* @param {function} [messages.expectedBeforeMultiLine]
* @param {function} [messages.rejectedBeforeMultiLine]
* @return {object} The checker, with its exposed checking functions
*/
module.exports = function (
targetWhitespace/*: "space" | "newline"*/,
expectation/*: "always" | "never" | "always-single-line"
| "always-multi-line" | "never-single-line"|"never-multi-line"*/,
messages/*: Object*/
)/*: {
before: Function,
beforeAllowingIndentation: Function,
after: Function,
afterOneOnly: Function
}*/ {
// Keep track of active arguments in order to avoid passing
// too much stuff around, making signatures long and confusing.
// This variable gets reset anytime a checking function is called.
let activeArgs
/**
* Check for whitespace *before* a character.
*
* @param {object} args - Named arguments object
* @param {string} args.source - The source string
* @param {number} args.index - The index of the character to check before
* @param {function} args.err - If a violation is found, this callback
* will be invoked with the relevant warning message.
* Typically this callback will report() the violation.
* @param {function} args.errTarget - If a violation is found, this string
* will be sent to the relevant warning message.
* @param {string} [args.lineCheckStr] - Single- and multi-line checkers
* will use this string to determine whether they should proceed,
* i.e. if this string is one line only, single-line checkers will check,
* multi-line checkers will ignore.
* If none is passed, they will use `source`.
* @param {boolean} [args.onlyOneChar=false] - Only check *one* character before.
* By default, "always-*" checks will look for the `targetWhitespace` one
* before and then ensure there is no whitespace two before. This option
* bypasses that second check.
* @param {boolean} [args.allowIndentation=false] - Allow arbitrary indentation
* between the `targetWhitespace` (almost definitely a newline) and the `index`.
* With this option, the checker will see if a newline *begins* the whitespace before
* the `index`.
*/
function before(args) {
const source = args.source
const index = args.index
const err = args.err
const errTarget = args.errTarget
const lineCheckStr = args.lineCheckStr
const onlyOneChar = args.onlyOneChar === undefined ? false : args.onlyOneChar
const allowIndentation = args.allowIndentation === undefined ? false : args.allowIndentation
activeArgs = { source, index, err, errTarget, onlyOneChar, allowIndentation }
switch (expectation) {
case "always":
expectBefore()
break
case "never":
rejectBefore()
break
case "always-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
expectBefore(messages.expectedBeforeSingleLine)
break
case "never-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
rejectBefore(messages.rejectedBeforeSingleLine)
break
case "always-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
expectBefore(messages.expectedBeforeMultiLine)
break
case "never-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
rejectBefore(messages.rejectedBeforeMultiLine)
break
default:
throw configurationError(`Unknown expectation "${expectation}"`)
}
}
/**
* Check for whitespace *after* a character.
*
* Parameters are pretty much the same as for `before()`, above, just substitute
* the word "after" for "before".
*/
function after(args) {
const source = args.source
const index = args.index
const err = args.err
const errTarget = args.errTarget
const lineCheckStr = args.lineCheckStr
const onlyOneChar = args.onlyOneChar === undefined ? false : args.onlyOneChar
activeArgs = { source, index, err, errTarget, onlyOneChar }
switch (expectation) {
case "always":
expectAfter()
break
case "never":
rejectAfter()
break
case "always-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
expectAfter(messages.expectedAfterSingleLine)
break
case "never-single-line":
if (!isSingleLineString(lineCheckStr || source)) {
return
}
rejectAfter(messages.rejectedAfterSingleLine)
break
case "always-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
expectAfter(messages.expectedAfterMultiLine)
break
case "never-multi-line":
if (isSingleLineString(lineCheckStr || source)) {
return
}
rejectAfter(messages.rejectedAfterMultiLine)
break
default:
throw configurationError(`Unknown expectation "${expectation}"`)
}
}
function beforeAllowingIndentation(obj) {
before(Object.assign({}, obj, { allowIndentation: true }))
}
function expectBefore() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore
if (activeArgs.allowIndentation) {
expectBeforeAllowingIndentation(messageFunc)
return
}
const _activeArgs = activeArgs
const source = _activeArgs.source,
index = _activeArgs.index
const oneCharBefore = source[index - 1]
const twoCharsBefore = source[index - 2]
if (!isValue(oneCharBefore)) {
return
}
if (targetWhitespace === "space" && oneCharBefore === " ") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsBefore)) {
return
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
function expectBeforeAllowingIndentation() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedBefore
const _activeArgs2 = activeArgs
const source = _activeArgs2.source,
index = _activeArgs2.index,
err = _activeArgs2.err
const expectedChar = function () {
if (targetWhitespace === "newline") {
return "\n"
}
}()
let i = index - 1
while (source[i] !== expectedChar) {
if (source[i] === "\t" || source[i] === " ") {
i--
continue
}
err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
return
}
}
function rejectBefore() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedBefore
const _activeArgs3 = activeArgs
const source = _activeArgs3.source,
index = _activeArgs3.index
const oneCharBefore = source[index - 1]
if (isValue(oneCharBefore) && isWhitespace(oneCharBefore)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
}
function afterOneOnly(obj) {
after(Object.assign({}, obj, { onlyOneChar: true }))
}
function expectAfter() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.expectedAfter
const _activeArgs4 = activeArgs
const source = _activeArgs4.source,
index = _activeArgs4.index
const oneCharAfter = source[index + 1]
const twoCharsAfter = source[index + 2]
if (!isValue(oneCharAfter)) {
return
}
if (targetWhitespace === "newline") {
// If index is followed by a Windows CR-LF ...
if (oneCharAfter === "\r" && twoCharsAfter === "\n") {
if (activeArgs.onlyOneChar || !isWhitespace(source[index + 3])) {
return
}
}
// If index is followed by a Unix LF ...
if (oneCharAfter === "\n") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsAfter)) {
return
}
}
}
if (targetWhitespace === "space" && oneCharAfter === " ") {
if (activeArgs.onlyOneChar || !isWhitespace(twoCharsAfter)) {
return
}
}
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
function rejectAfter() {
const messageFunc = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : messages.rejectedAfter
const _activeArgs5 = activeArgs
const source = _activeArgs5.source,
index = _activeArgs5.index
const oneCharAfter = source[index + 1]
if (isValue(oneCharAfter) && isWhitespace(oneCharAfter)) {
activeArgs.err(messageFunc(activeArgs.errTarget ? activeArgs.errTarget : source[index]))
}
}
return {
before,
beforeAllowingIndentation,
after,
afterOneOnly,
}
}
function isValue(x) {
return x !== undefined && x !== null
}