From 249f6ff5964fce2febd962fd369e1f4ff7121a1b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 9 Sep 2021 08:39:14 +0200 Subject: [PATCH] drop unused files (#5453) --- src/lib/substituteResponsiveAtRules.js | 93 ------ src/util/buildSelectorVariant.js | 21 -- src/util/disposables.js | 22 -- src/util/generateVariantFunction.js | 47 --- src/util/increaseSpecificity.js | 3 - src/util/prefixNegativeModifiers.js | 9 - src/util/processPlugins.js | 165 ---------- src/util/useMemo.js | 25 -- src/util/usesCustomProperties.js | 14 - src/util/wrapWithVariants.js | 21 -- tests/prefixNegativeModifiers.test.js | 13 - tests/responsiveAtRule.test.js | 440 ------------------------- 12 files changed, 873 deletions(-) delete mode 100644 src/lib/substituteResponsiveAtRules.js delete mode 100644 src/util/buildSelectorVariant.js delete mode 100644 src/util/disposables.js delete mode 100644 src/util/generateVariantFunction.js delete mode 100644 src/util/increaseSpecificity.js delete mode 100644 src/util/prefixNegativeModifiers.js delete mode 100644 src/util/processPlugins.js delete mode 100644 src/util/useMemo.js delete mode 100644 src/util/usesCustomProperties.js delete mode 100644 src/util/wrapWithVariants.js delete mode 100644 tests/prefixNegativeModifiers.test.js delete mode 100644 tests/responsiveAtRule.test.js diff --git a/src/lib/substituteResponsiveAtRules.js b/src/lib/substituteResponsiveAtRules.js deleted file mode 100644 index d15f2cea2..000000000 --- a/src/lib/substituteResponsiveAtRules.js +++ /dev/null @@ -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() - }) - } -} diff --git a/src/util/buildSelectorVariant.js b/src/util/buildSelectorVariant.js deleted file mode 100644 index 542c5ebdc..000000000 --- a/src/util/buildSelectorVariant.js +++ /dev/null @@ -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 diff --git a/src/util/disposables.js b/src/util/disposables.js deleted file mode 100644 index 46b617586..000000000 --- a/src/util/disposables.js +++ /dev/null @@ -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() diff --git a/src/util/generateVariantFunction.js b/src/util/generateVariantFunction.js deleted file mode 100644 index c3b426d1a..000000000 --- a/src/util/generateVariantFunction.js +++ /dev/null @@ -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 - ) - }, - } -} diff --git a/src/util/increaseSpecificity.js b/src/util/increaseSpecificity.js deleted file mode 100644 index 02acb4546..000000000 --- a/src/util/increaseSpecificity.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function (importantVal, selector) { - return `${importantVal} ${selector}` -} diff --git a/src/util/prefixNegativeModifiers.js b/src/util/prefixNegativeModifiers.js deleted file mode 100644 index 70cefa4c5..000000000 --- a/src/util/prefixNegativeModifiers.js +++ /dev/null @@ -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}` - } -} diff --git a/src/util/processPlugins.js b/src/util/processPlugins.js deleted file mode 100644 index 5f544159b..000000000 --- a/src/util/processPlugins.js +++ /dev/null @@ -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, - } -} diff --git a/src/util/useMemo.js b/src/util/useMemo.js deleted file mode 100644 index e050c9e48..000000000 --- a/src/util/useMemo.js +++ /dev/null @@ -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 - } -} diff --git a/src/util/usesCustomProperties.js b/src/util/usesCustomProperties.js deleted file mode 100644 index d5d744a9d..000000000 --- a/src/util/usesCustomProperties.js +++ /dev/null @@ -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 -} diff --git a/src/util/wrapWithVariants.js b/src/util/wrapWithVariants.js deleted file mode 100644 index 6820a3476..000000000 --- a/src/util/wrapWithVariants.js +++ /dev/null @@ -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])) -} diff --git a/tests/prefixNegativeModifiers.test.js b/tests/prefixNegativeModifiers.test.js deleted file mode 100644 index 7f4db0283..000000000 --- a/tests/prefixNegativeModifiers.test.js +++ /dev/null @@ -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') -}) diff --git a/tests/responsiveAtRule.test.js b/tests/responsiveAtRule.test.js deleted file mode 100644 index bee79e7de..000000000 --- a/tests/responsiveAtRule.test.js +++ /dev/null @@ -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' }) - }) -})