drop unused files (#5453)

This commit is contained in:
Robin Malfait 2021-09-09 08:39:14 +02:00 committed by GitHub
parent ec0562b887
commit 249f6ff596
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 0 additions and 873 deletions

View File

@ -1,93 +0,0 @@
import postcss from 'postcss'
import cloneNodes from '../util/cloneNodes'
import buildMediaQuery from '../util/buildMediaQuery'
import buildSelectorVariant from '../util/buildSelectorVariant'
import { tap } from '../util/tap'
function isLayer(node) {
if (Array.isArray(node)) {
return node.length === 1 && isLayer(node[0])
}
return node.type === 'atrule' && node.name === 'layer'
}
function layerNodes(nodes) {
return isLayer(nodes) ? nodes[0].nodes : nodes
}
export default function (config) {
return function (css) {
// Wrap any `responsive` rules with a copy of their parent `layer` to
// ensure the layer isn't lost when copying to the `screens` location.
css.walkAtRules('layer', (layerAtRule) => {
let layer = layerAtRule.params
layerAtRule.walkAtRules('responsive', (responsiveAtRule) => {
let nestedlayerAtRule = postcss.atRule({
name: 'layer',
params: layer,
})
nestedlayerAtRule.prepend(responsiveAtRule.nodes)
responsiveAtRule.removeAll()
responsiveAtRule.prepend(nestedlayerAtRule)
})
})
let {
theme: { screens },
separator,
} = config
let responsiveRules = postcss.root()
let finalRules = []
css.walkAtRules('responsive', (atRule) => {
let nodes = atRule.nodes
responsiveRules.append(...cloneNodes(nodes))
// If the parent is already a `layer` (this is true for anything coming from
// a plugin, including core plugins) we don't want to create a double nested
// layer, so only insert the layer children. If there is no parent layer,
// preserve the layer information when inserting the nodes.
if (isLayer(atRule.parent)) {
atRule.before(layerNodes(nodes))
} else {
atRule.before(nodes)
}
atRule.remove()
})
for (let [screen, value] of Object.entries(screens ?? {})) {
let mediaQuery = postcss.atRule({
name: 'media',
params: buildMediaQuery(value),
})
mediaQuery.append(
tap(responsiveRules.clone(), (clonedRoot) => {
clonedRoot.walkRules((rule) => {
rule.selectors = rule.selectors.map((selector) =>
buildSelectorVariant(selector, screen, separator, (message) => {
throw rule.error(message)
})
)
})
})
)
finalRules.push(mediaQuery)
}
let hasScreenRules = finalRules.some((i) => i.nodes.length !== 0)
css.walkAtRules('tailwind', (atRule) => {
if (atRule.params !== 'screens') {
return
}
if (hasScreenRules) {
atRule.before(finalRules)
}
atRule.remove()
})
}
}

View File

@ -1,21 +0,0 @@
import parser from 'postcss-selector-parser'
import { tap } from './tap'
import { useMemo } from './useMemo'
const buildSelectorVariant = useMemo(
(selector, variantName, separator, onError = () => {}) => {
return parser((selectors) => {
tap(selectors.first.filter(({ type }) => type === 'class').pop(), (classSelector) => {
if (classSelector === undefined) {
onError('Variant cannot be generated because selector contains no classes.')
return
}
classSelector.value = `${variantName}${separator}${classSelector.value}`
})
}).processSync(selector)
},
(selector, variantName, separator) => [selector, variantName, separator].join('||')
)
export default buildSelectorVariant

View File

@ -1,22 +0,0 @@
export function disposables() {
let disposables = []
let api = {
add(cb) {
disposables.push(cb)
return () => {
let idx = disposables.indexOf(cb)
if (idx !== -1) disposables.splice(idx, 1)
}
},
dispose() {
disposables.splice(0).forEach((dispose) => dispose())
},
}
return api
}
// A shared disposables collection
export let shared = disposables()

View File

@ -1,47 +0,0 @@
import postcss from 'postcss'
import selectorParser from 'postcss-selector-parser'
import { useMemo } from './useMemo'
let classNameParser = selectorParser((selectors) => {
return selectors.first.filter(({ type }) => type === 'class').pop().value
})
let getClassNameFromSelector = useMemo(
(selector) => classNameParser.transformSync(selector),
(selector) => selector
)
export default function generateVariantFunction(generator, options = {}) {
return {
options,
handler: (container, config) => {
let cloned = postcss.root({ nodes: container.clone().nodes })
container.before(
(
generator({
container: cloned,
separator: config.separator,
modifySelectors: (modifierFunction) => {
cloned.each((rule) => {
if (rule.type !== 'rule') {
return
}
rule.selectors = rule.selectors.map((selector) => {
return modifierFunction({
get className() {
return getClassNameFromSelector(selector)
},
selector,
})
})
})
return cloned
},
}) ?? cloned
).nodes
)
},
}
}

View File

@ -1,3 +0,0 @@
export default function (importantVal, selector) {
return `${importantVal} ${selector}`
}

View File

@ -1,9 +0,0 @@
export default function prefixNegativeModifiers(base, modifier) {
if (modifier === '-') {
return `-${base}`
} else if (modifier.startsWith('-')) {
return `-${base}-${modifier.slice(1)}`
} else {
return `${base}-${modifier}`
}
}

View File

@ -1,165 +0,0 @@
import dlv from 'dlv'
import postcss from 'postcss'
import Node from 'postcss/lib/node'
import escapeClassName from './escapeClassName'
import generateVariantFunction from './generateVariantFunction'
import parseObjectStyles from './parseObjectStyles'
import prefixSelector from './prefixSelector'
import wrapWithVariants from './wrapWithVariants'
import cloneNodes from './cloneNodes'
import transformThemeValue from './transformThemeValue'
import nameClass from './nameClass'
import isKeyframeRule from './isKeyframeRule'
import { toPath } from './toPath'
import { defaults } from './defaults'
function parseStyles(styles) {
if (!Array.isArray(styles)) {
return parseStyles([styles])
}
return styles.flatMap((style) => (style instanceof Node ? style : parseObjectStyles(style)))
}
function wrapWithLayer(rules, layer) {
return postcss
.atRule({ name: 'layer', params: layer })
.append(cloneNodes(Array.isArray(rules) ? rules : [rules]))
}
export default function (plugins, config) {
const pluginBaseStyles = []
const pluginComponents = []
const pluginUtilities = []
const pluginVariantGenerators = {}
const applyConfiguredPrefix = (selector) => {
return prefixSelector(config.prefix, selector)
}
function addUtilities(utilities, options) {
const defaultOptions = {
variants: [],
respectPrefix: true,
respectImportant: true,
}
options = Array.isArray(options)
? Object.assign({}, defaultOptions, { variants: options })
: defaults(options, defaultOptions)
const styles = postcss.root({ nodes: parseStyles(utilities) })
styles.walkRules((rule) => {
if (options.respectPrefix && !isKeyframeRule(rule)) {
rule.selector = applyConfiguredPrefix(rule.selector)
}
if (options.respectImportant && config.important) {
rule.__tailwind = {
...rule.__tailwind,
important: config.important,
}
}
})
pluginUtilities.push(
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'utilities')
)
}
const getConfigValue = (path, defaultValue) => (path ? dlv(config, path, defaultValue) : config)
plugins.forEach((plugin) => {
if (plugin.__isOptionsFunction) {
plugin = plugin()
}
const handler = typeof plugin === 'function' ? plugin : plugin?.handler ?? (() => {})
handler({
postcss,
config: getConfigValue,
theme: (path, defaultValue) => {
let [pathRoot, ...subPaths] = toPath(path)
let value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
return transformThemeValue(pathRoot)(value)
},
corePlugins: (path) => {
if (Array.isArray(config.corePlugins)) {
return config.corePlugins.includes(path)
}
return getConfigValue(`corePlugins.${path}`, true)
},
variants: (path, defaultValue) => {
if (Array.isArray(config.variants)) {
return config.variants
}
return getConfigValue(`variants.${path}`, defaultValue)
},
e: escapeClassName,
prefix: applyConfiguredPrefix,
addUtilities,
matchUtilities: (matches, { values, variants, respectPrefix, respectImportant }) => {
let modifierValues = Object.entries(values || {})
let result = Object.entries(matches).flatMap(([name, utilityFunction]) => {
return modifierValues
.map(([modifier, value]) => {
let declarations = utilityFunction(value, {
includeRules(rules, options) {
addUtilities(rules, options)
},
})
if (!declarations) {
return null
}
return {
[nameClass(name, modifier)]: declarations,
}
})
.filter(Boolean)
})
addUtilities(result, { variants, respectPrefix, respectImportant })
},
addComponents: (components, options) => {
const defaultOptions = { variants: [], respectPrefix: true }
options = Array.isArray(options)
? Object.assign({}, defaultOptions, { variants: options })
: defaults(options, defaultOptions)
const styles = postcss.root({ nodes: parseStyles(components) })
styles.walkRules((rule) => {
if (options.respectPrefix && !isKeyframeRule(rule)) {
rule.selector = applyConfiguredPrefix(rule.selector)
}
})
pluginComponents.push(
wrapWithLayer(wrapWithVariants(styles.nodes, options.variants), 'components')
)
},
addBase: (baseStyles) => {
pluginBaseStyles.push(wrapWithLayer(parseStyles(baseStyles), 'base'))
},
addVariant: (name, generator, options = {}) => {
pluginVariantGenerators[name] = generateVariantFunction(generator, options)
},
})
})
return {
base: pluginBaseStyles,
components: pluginComponents,
utilities: pluginUtilities,
variantGenerators: pluginVariantGenerators,
}
}

View File

@ -1,25 +0,0 @@
import { shared } from './disposables'
export function useMemo(cb, keyResolver) {
let cache = new Map()
function clearCache() {
cache.clear()
shared.add(clearCache)
}
shared.add(clearCache)
return (...args) => {
let key = keyResolver(...args)
if (cache.has(key)) {
return cache.get(key)
}
let result = cb(...args)
cache.set(key, result)
return result
}
}

View File

@ -1,14 +0,0 @@
import valueParser from 'postcss-value-parser'
export default function usesCustomProperties(value) {
let foundCustomProperty = false
valueParser(value).walk((node) => {
if (node.type === 'function' && node.value === 'var') {
foundCustomProperty = true
}
return !foundCustomProperty
})
return foundCustomProperty
}

View File

@ -1,21 +0,0 @@
import postcss from 'postcss'
import cloneNodes from './cloneNodes'
export default function wrapWithVariants(rules, variants) {
let foundVariantAtRule = false
postcss.root({ nodes: rules }).walkAtRules('variants', () => {
foundVariantAtRule = true
})
if (foundVariantAtRule) {
return cloneNodes(rules)
}
return postcss
.atRule({
name: 'variants',
params: variants.join(', '),
})
.append(cloneNodes(Array.isArray(rules) ? rules : [rules]))
}

View File

@ -1,13 +0,0 @@
import prefixNegativeModifiers from '../src/util/prefixNegativeModifiers'
test('it does not prefix classes using standard syntax', () => {
expect(prefixNegativeModifiers('base', 'modifier')).toEqual('base-modifier')
})
test('it prefixes classes using negative syntax', () => {
expect(prefixNegativeModifiers('base', '-modifier')).toEqual('-base-modifier')
})
test('it prefixes classes and omits suffix using default negative syntax', () => {
expect(prefixNegativeModifiers('base', '-')).toEqual('-base')
})

View File

@ -1,440 +0,0 @@
import postcss from 'postcss'
import plugin from '../src/lib/substituteResponsiveAtRules'
import config from '../stubs/defaultConfig.stub.js'
function run(input, opts = config) {
return postcss([plugin(opts)]).process(input, { from: undefined })
}
test('it can generate responsive variants', () => {
const input = `
@responsive {
.banana { color: yellow; }
.chocolate { color: brown; }
}
@tailwind screens;
`
const output = `
.banana { color: yellow; }
.chocolate { color: brown; }
@media (min-width: 500px) {
.sm\\:banana { color: yellow; }
.sm\\:chocolate { color: brown; }
}
@media (min-width: 750px) {
.md\\:banana { color: yellow; }
.md\\:chocolate { color: brown; }
}
@media (min-width: 1000px) {
.lg\\:banana { color: yellow; }
.lg\\:chocolate { color: brown; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('it can generate responsive variants with a custom separator', () => {
const input = `
@responsive {
.banana { color: yellow; }
.chocolate { color: brown; }
}
@tailwind screens;
`
const output = `
.banana { color: yellow; }
.chocolate { color: brown; }
@media (min-width: 500px) {
.sm__banana { color: yellow; }
.sm__chocolate { color: brown; }
}
@media (min-width: 750px) {
.md__banana { color: yellow; }
.md__chocolate { color: brown; }
}
@media (min-width: 1000px) {
.lg__banana { color: yellow; }
.lg__chocolate { color: brown; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: '__',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('it can generate responsive variants when classes have non-standard characters', () => {
const input = `
@responsive {
.hover\\:banana { color: yellow; }
.chocolate-2\\.5 { color: brown; }
.group:hover .group-hover\\:toast { color: black; }
}
@tailwind screens;
`
const output = `
.hover\\:banana { color: yellow; }
.chocolate-2\\.5 { color: brown; }
.group:hover .group-hover\\:toast { color: black; }
@media (min-width: 500px) {
.sm\\:hover\\:banana { color: yellow; }
.sm\\:chocolate-2\\.5 { color: brown; }
.group:hover .sm\\:group-hover\\:toast { color: black; }
}
@media (min-width: 750px) {
.md\\:hover\\:banana { color: yellow; }
.md\\:chocolate-2\\.5 { color: brown; }
.group:hover .md\\:group-hover\\:toast { color: black; }
}
@media (min-width: 1000px) {
.lg\\:hover\\:banana { color: yellow; }
.lg\\:chocolate-2\\.5 { color: brown; }
.group:hover .lg\\:group-hover\\:toast { color: black; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('responsive variants are grouped', () => {
const input = `
@responsive {
.banana { color: yellow; }
}
.apple { color: red; }
@responsive {
.chocolate { color: brown; }
}
@tailwind screens;
`
const output = `
.banana { color: yellow; }
.apple { color: red; }
.chocolate { color: brown; }
@media (min-width: 500px) {
.sm\\:banana { color: yellow; }
.sm\\:chocolate { color: brown; }
}
@media (min-width: 750px) {
.md\\:banana { color: yellow; }
.md\\:chocolate { color: brown; }
}
@media (min-width: 1000px) {
.lg\\:banana { color: yellow; }
.lg\\:chocolate { color: brown; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('it can generate responsive variants for nested at-rules', () => {
const input = `
@responsive {
.banana { color: yellow; }
@supports(display: grid) {
.grid\\:banana { color: blue; }
}
}
@tailwind screens;
`
const output = `
.banana {
color: yellow;
}
@supports(display: grid) {
.grid\\:banana {
color: blue;
}
}
@media (min-width: 500px) {
.sm\\:banana {
color: yellow;
}
@supports(display: grid) {
.sm\\:grid\\:banana {
color: blue;
}
}
}
@media (min-width: 1000px) {
.lg\\:banana {
color: yellow;
}
@supports(display: grid) {
.lg\\:grid\\:banana {
color: blue;
}
}
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('it can generate responsive variants for deeply nested at-rules', () => {
const input = `
@responsive {
.banana { color: yellow; }
@supports(display: grid) {
@supports(display: flex) {
.flex-grid\\:banana { color: blue; }
}
}
}
@tailwind screens;
`
const output = `
.banana {
color: yellow;
}
@supports(display: grid) {
@supports(display: flex) {
.flex-grid\\:banana {
color: blue;
}
}
}
@media (min-width: 500px) {
.sm\\:banana {
color: yellow;
}
@supports(display: grid) {
@supports(display: flex) {
.sm\\:flex-grid\\:banana {
color: blue;
}
}
}
}
@media (min-width: 1000px) {
.lg\\:banana {
color: yellow;
}
@supports(display: grid) {
@supports(display: flex) {
.lg\\:flex-grid\\:banana {
color: blue;
}
}
}
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('screen prefix is only applied to the last class in a selector', () => {
const input = `
@responsive {
.banana li * .sandwich #foo > div { color: yellow; }
}
@tailwind screens;
`
const output = `
.banana li * .sandwich #foo > div { color: yellow; }
@media (min-width: 500px) {
.banana li * .sm\\:sandwich #foo > div { color: yellow; }
}
@media (min-width: 750px) {
.banana li * .md\\:sandwich #foo > div { color: yellow; }
}
@media (min-width: 1000px) {
.banana li * .lg\\:sandwich #foo > div { color: yellow; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('responsive variants are generated for all selectors in a rule', () => {
const input = `
@responsive {
.foo, .bar { color: yellow; }
}
@tailwind screens;
`
const output = `
.foo, .bar { color: yellow; }
@media (min-width: 500px) {
.sm\\:foo, .sm\\:bar { color: yellow; }
}
@media (min-width: 750px) {
.md\\:foo, .md\\:bar { color: yellow; }
}
@media (min-width: 1000px) {
.lg\\:foo, .lg\\:bar { color: yellow; }
}
`
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).then((result) => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('selectors with no classes cannot be made responsive', () => {
const input = `
@responsive {
div { color: yellow; }
}
@tailwind screens;
`
expect.assertions(1)
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).catch((e) => {
expect(e).toMatchObject({ name: 'CssSyntaxError' })
})
})
test('all selectors in a rule must contain classes', () => {
const input = `
@responsive {
.foo, div { color: yellow; }
}
@tailwind screens;
`
expect.assertions(1)
return run(input, {
theme: {
screens: {
sm: '500px',
md: '750px',
lg: '1000px',
},
},
separator: ':',
}).catch((e) => {
expect(e).toMatchObject({ name: 'CssSyntaxError' })
})
})