From e372011197fa050e8bc7938f86cb2a4c87b9dee0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 14 Dec 2021 17:23:03 -0500 Subject: [PATCH 1/2] Support square bracket notation in paths --- src/lib/evaluateTailwindFunctions.js | 2 +- src/util/toPath.js | 24 +++++- tests/evaluateTailwindFunctions.test.js | 105 ++++++++++++++++++++++++ tests/to-path.test.js | 11 +-- 4 files changed, 135 insertions(+), 7 deletions(-) diff --git a/src/lib/evaluateTailwindFunctions.js b/src/lib/evaluateTailwindFunctions.js index 778230e59817..fbe366a93197 100644 --- a/src/lib/evaluateTailwindFunctions.js +++ b/src/lib/evaluateTailwindFunctions.js @@ -42,7 +42,7 @@ function validatePath(config, path, defaultValue) { ? pathToString(path) : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '') const pathSegments = Array.isArray(path) ? path : toPath(pathString) - const value = dlv(config.theme, pathString, defaultValue) + const value = dlv(config.theme, pathSegments, defaultValue) if (value === undefined) { let error = `'${pathString}' does not exist in your theme config.` diff --git a/src/util/toPath.js b/src/util/toPath.js index acf55d8d03e8..bf9d1333c371 100644 --- a/src/util/toPath.js +++ b/src/util/toPath.js @@ -1,4 +1,26 @@ +/** + * Parse a path string into an array of path segments. + * + * Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators. + * + * Example: + * a -> ['a] + * a.b.c -> ['a', 'b', 'c'] + * a[b].c -> ['a', 'b', 'c'] + * a[b.c].e.f -> ['a', 'b.c', 'e', 'f'] + * a[b][c][d] -> ['a', 'b', 'c', 'd'] + * + * @param {string|string[]} path + **/ export function toPath(path) { if (Array.isArray(path)) return path - return path.split(/[\.\]\[]+/g) + + let openBrackets = path.split('[').length - 1 + let closedBrackets = path.split(']').length - 1 + + if (openBrackets !== closedBrackets) { + throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`) + } + + return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean) } diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index 01d7393ba5bc..1cd07607b885 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -31,6 +31,111 @@ test('it looks up values in the theme using dot notation', () => { }) }) +test('it looks up values in the theme using bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow]'); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using consecutive bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow][100]'); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: { + 100: '#f7cc50', + }, + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using bracket notation that have dots in them', () => { + let input = css` + .banana { + padding-top: theme('spacing[1.5]'); + } + ` + + let output = css` + .banana { + padding-top: 0.375rem; + } + ` + + return run(input, { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('theme with mismatched brackets throws an error ', async () => { + let config = { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + } + + let input = (path) => css` + .banana { + padding-top: theme('${path}'); + } + ` + + await expect(run(input('spacing[1.5]]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[1.5]]` + ) + + await expect(run(input('spacing[[1.5]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[[1.5]` + ) + + await expect(run(input('spacing[a['), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[a[` + ) +}) + test('color can be a function', () => { let input = css` .backgroundColor { diff --git a/tests/to-path.test.js b/tests/to-path.test.js index dbd39c54a517..8737194ed40e 100644 --- a/tests/to-path.test.js +++ b/tests/to-path.test.js @@ -7,11 +7,12 @@ it('should keep an array as an array', () => { }) it.each` - input | output - ${'a.b.c'} | ${['a', 'b', 'c']} - ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} - ${'.a'} | ${['', 'a']} - ${'[].a'} | ${['', 'a']} + input | output + ${'a.b.c'} | ${['a', 'b', 'c']} + ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} + ${'.a'} | ${['a']} + ${'[].a'} | ${['a']} + ${'a[1.5][b][c]'} | ${['a', '1.5', 'b', 'c']} `('should convert "$input" to "$output"', ({ input, output }) => { expect(toPath(input)).toEqual(output) }) From 58747de2b2ddf25a9d5579a0723cec647ebe2eba Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 14 Dec 2021 17:27:22 -0500 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb356468d1ef..f062366f3629 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Don't output unparsable values ([#6469](https://github.com/tailwindlabs/tailwindcss/pull/6469)) - Fix text decoration utilities from overriding the new text decoration color/style/thickness utilities when used with a modifier ([#6378](https://github.com/tailwindlabs/tailwindcss/pull/6378)) - Move defaults to their own always-on layer ([#6500](https://github.com/tailwindlabs/tailwindcss/pull/6500)) -- Support negative values in safelist patterns ([6480](https://github.com/tailwindlabs/tailwindcss/pull/6480)) +- Support negative values in safelist patterns ([#6480](https://github.com/tailwindlabs/tailwindcss/pull/6480)) +- Support square bracket notation in paths ([#6519](https://github.com/tailwindlabs/tailwindcss/pull/6519)) ## [3.0.2] - 2021-12-13