diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 702dfd2..6c39689 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: - node-version: [18.x, 20.x, 22.x, latest] + node-version: [20.x, 22.x, latest] steps: - name: Checkout code diff --git a/package.json b/package.json index ce1c83f..078a2ca 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,8 @@ "esbuild": "0.25.6", "eslint": "^9.0.0", "globals": "^16.3.0", + "@tailwindcss/oxide": "^4.1.11", + "@tailwindcss/vite": "^4.1.11", "tailwindcss": "^4.1.11", "typescript": "^5.0.0", "vite": "^7.0.0", diff --git a/src/index.ts b/src/index.ts index 77c088a..0a6dd1d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1164,13 +1164,13 @@ export function wordpressThemeJson(config: ThemeJsonConfig = {}): VitePlugin { }; const patterns = { - COLOR: /(?:^|[;{}])\s*--color-([^:]+):\s*([^;}]+)[;}]?/gm, + COLOR: /(?:^|[;{}])\s*--color-([^:]+):\s*([^;}]+)/gm, FONT_FAMILY: - /(?:^|[;{}])\s*--font-([^:]+):\s*([^;}]+)[;}]?/gm, + /(?:^|[;{}])\s*--font-([^:]+):\s*([^;}]+)/gm, FONT_SIZE: - /(?:^|[;{}])\s*--text-([^:]+):\s*([^;}]+)[;}]?/gm, + /(?:^|[;{}])\s*--text-([^:]+):\s*([^;}]+)/gm, BORDER_RADIUS: - /(?:^|[;{}])\s*--radius-([^:]+):\s*([^;}]+)[;}]?/gm, + /(?:^|[;{}])\s*--radius-([^:]+):\s*([^;}]+)/gm, } as const; // Process colors from either @theme block or Tailwind config diff --git a/tests/build.test.ts b/tests/build.test.ts new file mode 100644 index 0000000..90ceb9c --- /dev/null +++ b/tests/build.test.ts @@ -0,0 +1,120 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, expect, it, afterAll } from 'vitest'; +import { build } from 'vite'; +import tailwindcss from '@tailwindcss/vite'; +import { wordpressThemeJson } from '../src/index.js'; +import fs from 'fs'; +import path from 'path'; + +const fixtureDir = path.resolve(__dirname, 'fixture'); +const outDir = path.join(fixtureDir, 'dist'); + +async function runBuild(pluginOptions = {}) { + await build({ + plugins: [ + tailwindcss(), + wordpressThemeJson({ + baseThemeJsonPath: path.join(fixtureDir, 'theme.json'), + outputPath: 'theme.json', + ...pluginOptions, + }), + ], + build: { + rollupOptions: { + input: path.join(fixtureDir, 'app.css'), + }, + outDir, + emptyOutDir: true, + write: true, + }, + logLevel: 'silent', + }); + + return JSON.parse(fs.readFileSync(path.join(outDir, 'theme.json'), 'utf8')); +} + +describe('vite build integration', () => { + afterAll(() => { + fs.rmSync(outDir, { recursive: true, force: true }); + }); + + describe('colors', () => { + it('should extract all 11 shades for each color', async () => { + const themeJson = await runBuild(); + const palette = themeJson.settings.color.palette; + + const redColors = palette.filter((c: any) => c.slug.startsWith('red-')); + expect(redColors).toHaveLength(11); + + const expectedShades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]; + for (const shade of expectedShades) { + expect(palette).toContainEqual( + expect.objectContaining({ + name: `Red (${shade})`, + slug: `red-${shade}`, + }) + ); + } + }); + + it('should include all Tailwind color families', async () => { + const themeJson = await runBuild(); + const palette = themeJson.settings.color.palette; + const slugs = palette.map((c: any) => c.slug); + + const expectedFamilies = [ + 'red', 'orange', 'amber', 'yellow', 'lime', 'green', + 'emerald', 'teal', 'cyan', 'sky', 'blue', 'indigo', + 'violet', 'purple', 'fuchsia', 'pink', 'rose', + 'slate', 'gray', 'zinc', 'neutral', 'stone', + ]; + + for (const family of expectedFamilies) { + expect(slugs.some((s: string) => s.startsWith(`${family}-`))).toBe(true); + } + }); + + it('should not include colors when disabled', async () => { + const themeJson = await runBuild({ disableTailwindColors: true }); + expect(themeJson.settings.color.palette).toBeUndefined(); + }); + }); + + describe('fonts', () => { + it('should extract font families', async () => { + const themeJson = await runBuild(); + const fonts = themeJson.settings.typography.fontFamilies; + + expect(fonts).toContainEqual( + expect.objectContaining({ slug: 'sans' }) + ); + expect(fonts).toContainEqual( + expect.objectContaining({ slug: 'mono' }) + ); + }); + }); + + describe('font sizes', () => { + it('should extract all font sizes', async () => { + const themeJson = await runBuild(); + const sizes = themeJson.settings.typography.fontSizes; + + const expectedSizes = ['xs', 'sm', 'base', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl', '7xl', '8xl', '9xl']; + for (const size of expectedSizes) { + expect(sizes).toContainEqual( + expect.objectContaining({ slug: size }) + ); + } + }); + }); + + describe('border radius', () => { + it('should extract border radius sizes', async () => { + const themeJson = await runBuild({ disableTailwindBorderRadius: false }); + const radiusSizes = themeJson.settings.border?.radiusSizes; + + expect(radiusSizes).toBeDefined(); + expect(radiusSizes!.length).toBeGreaterThan(0); + }); + }); +}); diff --git a/tests/fixture/app.css b/tests/fixture/app.css new file mode 100644 index 0000000..d9182b9 --- /dev/null +++ b/tests/fixture/app.css @@ -0,0 +1 @@ +@import "tailwindcss" theme(static); diff --git a/tests/fixture/theme.json b/tests/fixture/theme.json new file mode 100644 index 0000000..ba768d9 --- /dev/null +++ b/tests/fixture/theme.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://schemas.wp.org/trunk/theme.json", + "version": 3, + "settings": { + "color": { + "custom": false, + "defaultPalette": false + }, + "typography": { + "defaultFontSizes": false, + "customFontSize": false + } + } +}