diff --git a/README.md b/README.md index a92187e..65738a2 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,10 @@ It is used by the WordPress team for sites and packages. - [@yardinternet/eslint-config](packages/eslint-config/README.md) - [@yardinternet/stylelint-config](packages/stylelint-config/README.md) - [@yardinternet/postcss-config](packages/postcss-config/README.md) +- [@yardinternet/shared-utils](packages/shared-utils/README.md) - [@yardinternet/toolkit](packages/toolkit/README.md) - [@yardinternet/ts-config](packages/ts-config/README.md) +- [@yardinternet/ts-config-wordpress](packages/ts-config-wordpress/README.md) - [@yardinternet/vite-config](packages/vite-config/README.md) ## 👷‍♀️ Package Development diff --git a/packages/shared-utils/README.md b/packages/shared-utils/README.md new file mode 100644 index 0000000..31187a2 --- /dev/null +++ b/packages/shared-utils/README.md @@ -0,0 +1,13 @@ +# @yardinternet/shared-utils + +Shared utilities used internally by `@yardinternet/toolkit` and `@yardinternet/vite-config`. + +## Usage + +```js +import { resolveThemeContext, getAllThemeNames } from '@yardinternet/shared-utils'; +``` + +## Contents + +- **Theme context** (`resolveThemeContext`, `getAllThemeNames`) — theme discovery for brave-root / theme-root project layouts. diff --git a/packages/shared-utils/package.json b/packages/shared-utils/package.json new file mode 100644 index 0000000..69e6538 --- /dev/null +++ b/packages/shared-utils/package.json @@ -0,0 +1,20 @@ +{ + "name": "@yardinternet/shared-utils", + "version": "1.0.0", + "description": "Shared utilities used by @yardinternet/toolkit and @yardinternet/vite-config", + "main": "src/index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "publishConfig": { + "registry": "https://npm.pkg.github.com/" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/yardinternet/toolkit.git", + "directory": "packages/shared-utils" + }, + "author": "", + "license": "ISC" +} diff --git a/packages/toolkit/src/utils/get-all-theme-names.js b/packages/shared-utils/src/get-all-theme-names.js similarity index 100% rename from packages/toolkit/src/utils/get-all-theme-names.js rename to packages/shared-utils/src/get-all-theme-names.js diff --git a/packages/shared-utils/src/index.js b/packages/shared-utils/src/index.js new file mode 100644 index 0000000..067ea9b --- /dev/null +++ b/packages/shared-utils/src/index.js @@ -0,0 +1,2 @@ +export { resolveThemeContext } from './resolve-theme-context.js'; +export { getAllThemeNames } from './get-all-theme-names.js'; diff --git a/packages/vite-config/src/utils/resolve-theme-context.js b/packages/shared-utils/src/resolve-theme-context.js similarity index 100% rename from packages/vite-config/src/utils/resolve-theme-context.js rename to packages/shared-utils/src/resolve-theme-context.js diff --git a/packages/toolkit/package.json b/packages/toolkit/package.json index 4cfeac5..3378cda 100644 --- a/packages/toolkit/package.json +++ b/packages/toolkit/package.json @@ -25,6 +25,7 @@ "@shufo/tailwindcss-class-sorter": "^3.0.1", "@wordpress/eslint-plugin": "^25.6.0", "@wordpress/prettier-config": "^4.48.0", + "@yardinternet/shared-utils": "workspace:*", "chalk": "^5.6.2", "eslint": "^10.6.0", "eslint-import-resolver-alias": "^1.1.2", diff --git a/packages/toolkit/src/config/modes.js b/packages/toolkit/src/config/modes.js index f89d5e5..32ee981 100644 --- a/packages/toolkit/src/config/modes.js +++ b/packages/toolkit/src/config/modes.js @@ -1,5 +1,5 @@ import { filetypes } from './filetypes.js'; -import { resolveThemeContext } from '../utils/resolve-theme-context.js'; +import { resolveThemeContext } from '@yardinternet/shared-utils'; /** * Builds the lint/format globs for the `brave` mode. diff --git a/packages/toolkit/src/scripts/build-themes.js b/packages/toolkit/src/scripts/build-themes.js index a123b6f..80ab2e1 100644 --- a/packages/toolkit/src/scripts/build-themes.js +++ b/packages/toolkit/src/scripts/build-themes.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { getAllThemeNames } from '../utils/get-all-theme-names.js'; +import { getAllThemeNames } from '@yardinternet/shared-utils'; import { ensureFileExists, execWithEnv, diff --git a/packages/toolkit/src/utils/get-block-paths.js b/packages/toolkit/src/utils/get-block-paths.js index 2ff0103..3b03714 100644 --- a/packages/toolkit/src/utils/get-block-paths.js +++ b/packages/toolkit/src/utils/get-block-paths.js @@ -7,7 +7,7 @@ import path from 'path'; /** * Internal dependencies */ -import { resolveThemeContext } from './resolve-theme-context.js'; +import { resolveThemeContext } from '@yardinternet/shared-utils'; export const getBlockPaths = async () => { const context = resolveThemeContext(); diff --git a/packages/toolkit/src/utils/get-block-theme-name.js b/packages/toolkit/src/utils/get-block-theme-name.js index 5c22be9..481b77c 100644 --- a/packages/toolkit/src/utils/get-block-theme-name.js +++ b/packages/toolkit/src/utils/get-block-theme-name.js @@ -6,7 +6,7 @@ import path from 'path'; /** * Internal dependencies */ -import { resolveThemeContext } from './resolve-theme-context.js'; +import { resolveThemeContext } from '@yardinternet/shared-utils'; /** * Returns the owning theme name for a discovered block path, for logging. diff --git a/packages/toolkit/src/utils/resolve-theme-context.js b/packages/toolkit/src/utils/resolve-theme-context.js deleted file mode 100644 index fd3e34d..0000000 --- a/packages/toolkit/src/utils/resolve-theme-context.js +++ /dev/null @@ -1,106 +0,0 @@ -/** - * External dependencies - */ -import fs from 'fs'; -import path from 'path'; - -/** - * Resolves the project context for build/watch/lint/format tooling. - * - * Two layouts are supported: - * - * - `brave-root` (default): invoked from the root of a Brave/Bedrock - * project where themes live at `web/app/themes/`. - * - `theme-root`: invoked from inside a single theme directory (cwd is the - * theme). Every theme path collapses to the cwd, so a theme can build, watch, - * lint and format on its own. - * - * Detection is automatic and cheap: - * 1. A `web/app/themes` directory in cwd → brave-root. - * 2. A `style.css` in cwd → theme-root (cwd is a WordPress theme). - * 3. Otherwise throw with guidance. - * - * NOTE: kept in sync with the identical util in `@yardinternet/vite-config`. - */ - -const THEMES_SUBDIR = path.join( 'web', 'app', 'themes' ); - -const isDirectory = ( dirPath ) => { - try { - return fs.statSync( dirPath ).isDirectory(); - } catch { - return false; - } -}; - -const detectMode = ( cwd ) => { - if ( isDirectory( path.resolve( cwd, THEMES_SUBDIR ) ) ) { - return 'brave-root'; - } - - if ( fs.existsSync( path.resolve( cwd, 'style.css' ) ) ) { - return 'theme-root'; - } - - return null; -}; - -/** - * Discovers theme directories (dirs containing a `style.css`) inside a - * brave-root themes directory. - */ -const discoverThemeNames = ( themesDir ) => { - if ( ! isDirectory( themesDir ) ) { - return []; - } - - return fs.readdirSync( themesDir ).filter( ( dirName ) => { - const fullPath = path.join( themesDir, dirName ); - - if ( ! isDirectory( fullPath ) ) { - return false; - } - - return fs.existsSync( path.join( fullPath, 'style.css' ) ); - } ); -}; - -export const resolveThemeContext = () => { - const cwd = process.cwd(); - const mode = detectMode( cwd ); - - if ( mode === 'theme-root' ) { - const name = path.basename( cwd ); - - return { - mode, - themes: [ { name, dir: cwd, relDir: '.' } ], - themeDir: () => cwd, - themeRelDir: () => '.', - defaultTheme: name, - }; - } - - if ( mode === 'brave-root' ) { - const themesDir = path.resolve( cwd, THEMES_SUBDIR ); - const themes = discoverThemeNames( themesDir ).map( ( name ) => ( { - name, - dir: path.join( themesDir, name ), - relDir: path.join( THEMES_SUBDIR, name ), - } ) ); - - return { - mode, - themes, - themeDir: ( name ) => path.join( themesDir, name ), - themeRelDir: ( name ) => path.join( THEMES_SUBDIR, name ), - defaultTheme: 'sage', - }; - } - - throw new Error( - 'Unable to determine project context: no "web/app/themes" directory ' + - 'and no "style.css" in the current directory. Run from a Brave ' + - 'project root or from a theme directory.' - ); -}; diff --git a/packages/vite-config/package.json b/packages/vite-config/package.json index faa6045..b8c03be 100644 --- a/packages/vite-config/package.json +++ b/packages/vite-config/package.json @@ -21,6 +21,7 @@ "@roots/vite-plugin": "^2.2.0", "@tailwindcss/vite": "^4.3.1", "@vitejs/plugin-react": "^5.2.0", + "@yardinternet/shared-utils": "workspace:*", "@yardinternet/vite-plugin-gutenberg-blocks": "^2.7.1", "chalk": "^5.6.2", "laravel-vite-plugin": "^3.1.0", diff --git a/packages/vite-config/src/configs/brave-theme-blocks.js b/packages/vite-config/src/configs/brave-theme-blocks.js index e2c0ce1..b16250e 100644 --- a/packages/vite-config/src/configs/brave-theme-blocks.js +++ b/packages/vite-config/src/configs/brave-theme-blocks.js @@ -18,8 +18,10 @@ import path from 'path'; * Internal dependencies */ import { generateAliases } from '../utils/generate-aliases.js'; -import { getAllThemeNames } from '../utils/get-all-theme-names.js'; -import { resolveThemeContext } from '../utils/resolve-theme-context.js'; +import { + getAllThemeNames, + resolveThemeContext, +} from '@yardinternet/shared-utils'; export const braveBlocksConfig = ( { blockPath } ) => { const context = resolveThemeContext(); diff --git a/packages/vite-config/src/utils/generate-aliases.js b/packages/vite-config/src/utils/generate-aliases.js index 0e621d3..1682fc4 100644 --- a/packages/vite-config/src/utils/generate-aliases.js +++ b/packages/vite-config/src/utils/generate-aliases.js @@ -6,7 +6,7 @@ import path from 'path'; /** * Internal dependencies */ -import { resolveThemeContext } from './resolve-theme-context.js'; +import { resolveThemeContext } from '@yardinternet/shared-utils'; /** * Generates the aliases for each theme to use like `@theme-name`. diff --git a/packages/vite-config/src/utils/generate-entry-points.js b/packages/vite-config/src/utils/generate-entry-points.js index 80e950e..ad9ebe3 100644 --- a/packages/vite-config/src/utils/generate-entry-points.js +++ b/packages/vite-config/src/utils/generate-entry-points.js @@ -7,7 +7,7 @@ import path from 'path'; /** * Internal dependencies */ -import { resolveThemeContext } from './resolve-theme-context.js'; +import { resolveThemeContext } from '@yardinternet/shared-utils'; /** * Returns an array of valid entry point paths for the specified themes. diff --git a/packages/vite-config/src/utils/get-all-theme-names.js b/packages/vite-config/src/utils/get-all-theme-names.js deleted file mode 100644 index 0ef715a..0000000 --- a/packages/vite-config/src/utils/get-all-theme-names.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Internal dependencies - */ -import { resolveThemeContext } from './resolve-theme-context.js'; - -/** - * Returns an array of all theme names for the current project context. - * - * - brave-root: every theme in `web/app/themes` that has a `style.css`. - * - theme-root: a single-element array with the current theme's name. - */ -export const getAllThemeNames = () => { - return resolveThemeContext().themes.map( ( theme ) => theme.name ); -}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0167661..b153a7e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,7 +46,7 @@ importers: dependencies: '@wordpress/eslint-plugin': specifier: ^25.6.0 - version: 25.6.0(@babel/core@7.29.7)(@types/react@18.3.31)(@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(esbuild@0.27.7)(eslint@10.6.0(jiti@2.7.0))(postcss@8.5.15)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vite@7.3.5(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0))(wp-prettier@3.0.3) + version: 25.6.0(@babel/core@7.29.7)(@types/react@18.3.31)(@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(esbuild@0.27.7)(eslint@10.6.0(jiti@2.7.0))(postcss@8.5.15)(prettier@3.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vite@7.3.5(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0)) eslint-import-resolver-alias: specifier: ^1.1.2 version: 1.1.2(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))) @@ -110,6 +110,8 @@ importers: specifier: ^3.2.6 version: 3.2.6(@types/node@26.0.0)(jiti@1.21.7)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0) + packages/shared-utils: {} + packages/stylelint-config: dependencies: stylelint: @@ -139,6 +141,9 @@ importers: '@wordpress/prettier-config': specifier: ^4.48.0 version: 4.48.0(wp-prettier@3.0.3) + '@yardinternet/shared-utils': + specifier: workspace:* + version: link:../shared-utils chalk: specifier: ^5.6.2 version: 5.6.2 @@ -235,6 +240,9 @@ importers: '@vitejs/plugin-react': specifier: ^5.2.0 version: 5.2.0(vite@8.1.0(@types/node@26.0.0)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0)) + '@yardinternet/shared-utils': + specifier: workspace:* + version: link:../shared-utils '@yardinternet/vite-plugin-gutenberg-blocks': specifier: ^2.7.1 version: 2.7.1(typescript@5.9.3)(vite@8.1.0(@types/node@26.0.0)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0)) @@ -13809,14 +13817,14 @@ snapshots: - supports-color - vite - '@wordpress/eslint-plugin@25.6.0(@babel/core@7.29.7)(@types/react@18.3.31)(@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(esbuild@0.27.7)(eslint@10.6.0(jiti@2.7.0))(postcss@8.5.15)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vite@7.3.5(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0))(wp-prettier@3.0.3)': + '@wordpress/eslint-plugin@25.6.0(@babel/core@7.29.7)(@types/react@18.3.31)(@typescript-eslint/eslint-plugin@8.62.1(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(@typescript-eslint/parser@8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3))(esbuild@0.27.7)(eslint@10.6.0(jiti@2.7.0))(postcss@8.5.15)(prettier@3.8.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.9.3)(vite@7.3.5(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/eslint-parser': 7.29.7(@babel/core@7.29.7)(eslint@10.6.0(jiti@2.7.0)) '@eslint-community/eslint-plugin-eslint-comments': 4.7.2(eslint@10.6.0(jiti@2.7.0)) '@eslint/compat': 2.1.0(eslint@10.6.0(jiti@2.7.0)) '@wordpress/babel-preset-default': 8.50.0 - '@wordpress/prettier-config': 4.50.0(wp-prettier@3.0.3) + '@wordpress/prettier-config': 4.50.0(prettier@3.8.1) '@wordpress/theme': 0.17.0(@types/react@18.3.31)(esbuild@0.27.7)(postcss@8.5.15)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(stylelint@17.13.0(typescript@5.9.3))(vite@7.3.5(@types/node@26.0.0)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.101.0)(sugarss@5.0.1(postcss@8.5.15))(terser@5.48.0)(yaml@2.9.0)) cosmiconfig: 7.1.0 eslint: 10.6.0(jiti@2.7.0) @@ -13827,14 +13835,14 @@ snapshots: eslint-plugin-jsdoc: 50.8.0(eslint@10.6.0(jiti@2.7.0)) eslint-plugin-jsx-a11y: 6.10.2(eslint@10.6.0(jiti@2.7.0)) eslint-plugin-playwright: 2.10.5(eslint@10.6.0(jiti@2.7.0)) - eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0(jiti@2.7.0)))(eslint@10.6.0(jiti@2.7.0))(wp-prettier@3.0.3) + eslint-plugin-prettier: 5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0(jiti@2.7.0)))(eslint@10.6.0(jiti@2.7.0))(prettier@3.8.1) eslint-plugin-react: 7.37.5(eslint@10.6.0(jiti@2.7.0)) eslint-plugin-react-hooks: 7.1.1(eslint@10.6.0(jiti@2.7.0)) globals: 16.5.0 requireindex: 1.2.0 typescript-eslint: 8.62.1(eslint@10.6.0(jiti@2.7.0))(typescript@5.9.3) optionalDependencies: - prettier: wp-prettier@3.0.3 + prettier: 3.8.1 typescript: 5.9.3 transitivePeerDependencies: - '@types/eslint' @@ -14256,6 +14264,10 @@ snapshots: dependencies: prettier: wp-prettier@3.0.3 + '@wordpress/prettier-config@4.50.0(prettier@3.8.1)': + dependencies: + prettier: 3.8.1 + '@wordpress/prettier-config@4.50.0(wp-prettier@3.0.3)': dependencies: prettier: wp-prettier@3.0.3 @@ -16353,6 +16365,15 @@ snapshots: eslint: 10.6.0(jiti@2.7.0) globals: 17.7.0 + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0(jiti@2.7.0)))(eslint@10.6.0(jiti@2.7.0))(prettier@3.8.1): + dependencies: + eslint: 10.6.0(jiti@2.7.0) + prettier: 3.8.1 + prettier-linter-helpers: 1.0.1 + synckit: 0.11.13 + optionalDependencies: + eslint-config-prettier: 10.1.8(eslint@10.6.0(jiti@2.7.0)) + eslint-plugin-prettier@5.5.6(eslint-config-prettier@10.1.8(eslint@10.6.0(jiti@2.7.0)))(eslint@10.6.0(jiti@2.7.0))(wp-prettier@3.0.3): dependencies: eslint: 10.6.0(jiti@2.7.0)