Reorganize prototype code

This commit is contained in:
Adam Wathan 2020-08-14 12:23:28 -04:00
parent 577f536eeb
commit cef0b84abf
7 changed files with 89 additions and 69 deletions

View File

@ -655,7 +655,7 @@ describe('using apply with the prefix option', () => {
},
])
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
@ -679,7 +679,7 @@ describe('using apply with the prefix option', () => {
},
])
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
@ -697,7 +697,7 @@ describe('using apply with the prefix option', () => {
},
])
return run(input, config, () => processPlugins(corePlugins(config), config)).catch(e => {
return run(input, config).catch(e => {
expect(e).toMatchObject({ name: 'CssSyntaxError' })
})
})
@ -720,7 +720,7 @@ describe('using apply with the prefix option', () => {
},
])
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
@ -744,7 +744,7 @@ describe('using apply with the prefix option', () => {
},
])
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
@ -764,16 +764,62 @@ describe('using apply with the prefix option', () => {
expect.assertions(1)
return run(input, config, () => processPlugins(corePlugins(config), config)).catch(e => {
return run(input, config).catch(e => {
expect(e).toMatchObject({
name: 'CssSyntaxError',
reason: 'The `mt-4` class does not exist, but `tw-mt-4` does. Did you forget the prefix?',
})
})
})
test('you can apply classes with important and a prefix enabled', () => {
const input = `
.foo { @apply tw-mt-4; }
`
const expected = `
.foo { margin-top: 1rem; }
`
const config = resolveConfig([
{
...defaultConfig,
prefix: 'tw-',
important: true,
},
])
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
})
test('you can apply classes with an important selector and a prefix enabled', () => {
const input = `
.foo { @apply tw-mt-4; }
`
const expected = `
.foo { margin-top: 1rem; }
`
const config = resolveConfig([
{
...defaultConfig,
prefix: 'tw-',
important: '#app',
},
])
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
})
})
test.skip('you can apply utility classes when a selector is used for the important option', () => {
test('you can apply utility classes when a selector is used for the important option', () => {
const input = `
.foo {
@apply mt-8 mb-8;
@ -794,30 +840,7 @@ test.skip('you can apply utility classes when a selector is used for the importa
},
])
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})
})
test.skip('you can apply utility classes without using the given prefix even if important (selector) is used', () => {
const input = `
.foo { @apply .tw-mt-4 .mb-4; }
`
const expected = `
.foo { margin-top: 1rem; margin-bottom: 1rem; }
`
const config = resolveConfig([
{
...defaultConfig,
prefix: 'tw-',
important: '#app',
},
])
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
return run(input, config).then(result => {
expect(result.css).toMatchCss(expected)
expect(result.warnings().length).toBe(0)
})

View File

@ -70,8 +70,7 @@ export function issueFlagNotices(config) {
.map(s => chalk.cyan(s))
.join(', ')
console.log()
log.info(`You have opted-in to future-facing breaking changes: ${changes}`)
log.info(`\nYou have opted-in to future-facing breaking changes: ${changes}`)
log.info(
'These changes are stable and will be the default behavior in the next major version of Tailwind.'
)
@ -82,8 +81,7 @@ export function issueFlagNotices(config) {
.map(s => chalk.yellow(s))
.join(', ')
console.log()
log.warn(`You have enabled experimental features: ${changes}`)
log.warn(`\nYou have enabled experimental features: ${changes}`)
log.warn(
'Experimental features are not covered by semver, may introduce breaking changes, and can change at any time.'
)
@ -94,8 +92,7 @@ export function issueFlagNotices(config) {
.map(s => chalk.magenta(s))
.join(', ')
console.log()
log.risk(`There are upcoming breaking changes: ${changes}`)
log.risk(`\nThere are upcoming breaking changes: ${changes}`)
log.risk(
'We highly recommend opting-in to these changes now to simplify upgrading Tailwind in the future.'
)

View File

@ -210,11 +210,11 @@ function processApplyAtRules(css, lookupTree, config) {
afterRule,
]
const root = _.tap(postcss.root({ nodes: rulesToInsert }), root =>
const { nodes } = _.tap(postcss.root({ nodes: rulesToInsert }), root =>
root.walkDecls(d => (d.important = important))
)
const mergedRules = mergeAdjacentRules(rule, root.nodes)
const mergedRules = mergeAdjacentRules(rule, nodes)
inject.remove()
rule.after(mergedRules)

View File

@ -0,0 +1,19 @@
export default function applyImportantConfiguration(_config) {
return function(css) {
css.walkRules(rule => {
const important = rule.__tailwind ? rule.__tailwind.important : false
if (!important) {
return
}
if (typeof important === 'string') {
rule.selectors = rule.selectors.map(selector => {
return `${rule.__tailwind.important} ${selector}`
})
} else {
rule.walkDecls(decl => (decl.important = true))
}
})
}
}

View File

@ -5,7 +5,8 @@ import chalk from 'chalk'
import { log } from '../cli/utils'
import * as emoji from '../cli/emoji'
function removeTailwindComments(css) {
function removeTailwindMarkers(css) {
css.walkAtRules('tailwind', rule => rule.remove())
css.walkComments(comment => {
switch (comment.text.trim()) {
case 'tailwind start components':
@ -28,7 +29,7 @@ export default function purgeUnusedUtilities(config) {
)
if (!purgeEnabled) {
return removeTailwindComments
return removeTailwindMarkers
}
// Skip if `purge: []` since that's part of the default config
@ -48,7 +49,7 @@ export default function purgeUnusedUtilities(config) {
log(
chalk.white('\n https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css')
)
return removeTailwindComments
return removeTailwindMarkers
}
return postcss([
@ -73,7 +74,7 @@ export default function purgeUnusedUtilities(config) {
})
}
},
removeTailwindComments,
removeTailwindMarkers,
purgecss({
content: Array.isArray(config.purge) ? config.purge : config.purge.content,
defaultExtractor: content => {

View File

@ -8,6 +8,7 @@ import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import convertLayerAtRulesToControlComments from './lib/convertLayerAtRulesToControlComments'
import substituteScreenAtRules from './lib/substituteScreenAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'
import applyImportantConfiguration from './lib/applyImportantConfiguration'
import purgeUnusedStyles from './lib/purgeUnusedStyles'
import corePlugins from './corePlugins'
@ -40,9 +41,7 @@ export default function(getConfig) {
convertLayerAtRulesToControlComments(config),
substituteScreenAtRules(config),
substituteClassApplyAtRules(config, getProcessedPlugins),
function(css) {
css.walkAtRules('tailwind', rule => rule.remove())
},
applyImportantConfiguration(config),
purgeUnusedStyles(config),
]).process(css, { from: _.get(css, 'source.input.file') })
}

View File

@ -9,8 +9,6 @@ import parseObjectStyles from '../util/parseObjectStyles'
import prefixSelector from '../util/prefixSelector'
import wrapWithVariants from '../util/wrapWithVariants'
import cloneNodes from '../util/cloneNodes'
import increaseSpecificity from '../util/increaseSpecificity'
import selectorParser from 'postcss-selector-parser'
function parseStyles(styles) {
if (!Array.isArray(styles)) {
@ -20,14 +18,6 @@ function parseStyles(styles) {
return _.flatMap(styles, style => (style instanceof Node ? style : parseObjectStyles(style)))
}
function containsClass(value) {
return selectorParser(selectors => {
let classFound = false
selectors.walkClasses(() => (classFound = true))
return classFound
}).transformSync(value)
}
function wrapWithLayer(rules, layer) {
return postcss
.atRule({
@ -102,19 +92,10 @@ export default function(plugins, config) {
rule.selector = applyConfiguredPrefix(rule.selector)
}
if (options.respectImportant && _.get(config, 'important')) {
if (config.important === true) {
rule.walkDecls(decl => (decl.important = true))
} else if (typeof config.important === 'string') {
if (containsClass(config.important)) {
throw rule.error(
`Classes are not allowed when using the \`important\` option with a string argument. Please use an ID instead.`
)
}
rule.selectors = rule.selectors.map(selector => {
return increaseSpecificity(config.important, selector)
})
if (options.respectImportant && config.important) {
rule.__tailwind = {
...rule.__tailwind,
important: config.important,
}
}
})