Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/eslint-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ const eslintSettings = merge(require('@yardinternet/eslint-config'), [

module.exports = eslintSettings;
```

## brave-root vs theme-root

The `@sage/scripts` import alias auto-detects where ESLint runs:

- **brave-root** — cwd has `web/app/themes/`. `@sage/scripts` → `web/app/themes/sage/resources/scripts`.
- **theme-root** — cwd is a single theme (has `style.css`, no `web/app/themes/`). `@sage/scripts` and `@<theme>/scripts` → `./resources/scripts`.
8 changes: 2 additions & 6 deletions packages/eslint-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const tsPlugin = require( '@typescript-eslint/eslint-plugin' );
const { fixupConfigRules } = require( '@eslint/compat' );
const js = require( '@eslint/js' );
const { FlatCompat } = require( '@eslint/eslintrc' );
const resolveImportAliases = require( './utils/resolve-import-aliases' );

const compat = new FlatCompat( {
baseDirectory: __dirname,
Expand Down Expand Up @@ -73,12 +74,7 @@ module.exports = [
settings: {
...sharedSettings,
'import/resolver': {
alias: [
[
'@sage/scripts',
'./web/app/themes/sage/resources/scripts',
],
],
alias: resolveImportAliases(),
},
},
},
Expand Down
32 changes: 32 additions & 0 deletions packages/eslint-config/src/utils/resolve-import-aliases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const fs = require( 'fs' );
const path = require( 'path' );

/**
* Resolves the `import/resolver` aliases for the current project layout.
*
* - brave-root (default): the `@sage/scripts` alias, unchanged.
* - theme-root (cwd is a theme — no `web/app/themes`, has `style.css`): point
* both `@<theme>/scripts` and the `@sage/scripts` at the local
* `./resources/scripts` so theme imports resolve.
*/
const resolveImportAliases = () => {
const cwd = process.cwd();
const isBraveRoot = fs.existsSync( path.resolve( cwd, 'web/app/themes' ) );

if ( isBraveRoot ) {
return [
[ '@sage/scripts', './web/app/themes/sage/resources/scripts' ],
];
}

const themeName = path.basename( cwd );

Comment on lines +13 to +23
return [
[ `@${ themeName }/scripts`, './resources/scripts' ],
// Brave-root alias kept so shared/starter code importing `@sage/scripts`
// keeps resolving in a theme-root build.
[ '@sage/scripts', './resources/scripts' ],
];
};

module.exports = resolveImportAliases;
7 changes: 7 additions & 0 deletions packages/prettier-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ const prettierSettings = merge(require('@yardinternet/prettier-config'), {
})
module.exports = prettierSettings;
```

## brave-root vs theme-root

The Tailwind config stylesheet is located automatically, trying both layouts:

- **brave-root** — `web/app/themes/sage/resources/styles/base/config.css`.
- **theme-root** — the theme's own `resources/styles/base/config.css`.
14 changes: 11 additions & 3 deletions packages/prettier-config/src/utils/find-tailwind-stylesheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ const fs = require( 'fs' );
const path = require( 'path' );

function findTailwindStylesheet() {
const relative = 'web/app/themes/sage/resources/styles/base/config.css';
// Candidate locations of the Tailwind config stylesheet, tried in order:
// - brave-root: the sage theme inside `web/app/themes`.
// - theme-root: the theme's own resources (cwd is the theme).
const relatives = [
'web/app/themes/sage/resources/styles/base/config.css',
'resources/styles/base/config.css',
];

const roots = [];

Expand All @@ -21,8 +27,10 @@ function findTailwindStylesheet() {
roots.push( process.cwd() );

for ( const root of roots ) {
const candidate = path.resolve( root, relative );
if ( fs.existsSync( candidate ) ) return candidate;
for ( const relative of relatives ) {
const candidate = path.resolve( root, relative );
if ( fs.existsSync( candidate ) ) return candidate;
}
}

return null;
Expand Down
9 changes: 9 additions & 0 deletions packages/toolkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ Options
--version Shows version
```

### brave-root vs theme-root

`brave` mode auto-detects where the command runs:

- **brave-root** — cwd has `web/app/themes/`. Operates on all themes (lint/format globs, build/watch).
- **theme-root** — cwd is a single theme (has `style.css`, no `web/app/themes/`). Operates on that one theme.

Same commands either way.

### Format

For default for brave sites:
Expand Down
53 changes: 36 additions & 17 deletions packages/toolkit/src/config/modes.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
import { filetypes } from './filetypes.js';
import { resolveThemeContext } from '../utils/resolve-theme-context.js';

/**
* Builds the lint/format globs for the `brave` mode.
*
* - brave-root: matches `resources/**` across every theme.
* - theme-root: matches the current theme's own `resources/**`.
*
* Computed lazily (via the getter below) so the project context is only
* resolved when brave-mode globs are actually requested.
*/
const buildBravePaths = () => {
const { mode } = resolveThemeContext();
const prefix = mode === 'theme-root' ? '.' : './web/app/themes/**';

return [
{
filetype: filetypes.js.name,
path: [
`${ prefix }/resources/scripts/**/*.js`,
`${ prefix }/resources/scripts/**/*.jsx`,
],
},
{
filetype: filetypes.blade.name,
path: `${ prefix }/resources/views/**/*.blade.php`,
},
{
filetype: filetypes.css.name,
path: `${ prefix }/resources/styles/{*,**/*}.css`,
},
];
};

export const modes = {
brave: {
name: 'brave',
paths: [
{
filetype: filetypes.js.name,
path: [
'./web/app/themes/**/resources/scripts/**/*.js',
'./web/app/themes/**/resources/scripts/**/*.jsx',
],
},
{
filetype: filetypes.blade.name,
path: './web/app/themes/**/resources/views/**/*.blade.php',
},
{
filetype: filetypes.css.name,
path: './web/app/themes/**/resources/styles/{*,**/*}.css',
},
],
get paths() {
return buildBravePaths();
},
},
custom: {
name: 'custom',
Expand Down
3 changes: 2 additions & 1 deletion packages/toolkit/src/scripts/build-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import path from 'path';
* Internal dependencies
*/
import { getBlockPaths } from '../utils/get-block-paths.js';
import { getBlockThemeName } from '../utils/get-block-theme-name.js';
import {
ensureFileExists,
execWithEnv,
Expand All @@ -29,7 +30,7 @@ export const buildBlocks = async ( configFile = 'vite-blocks.config.js' ) => {
Promise.allSettled(
blocks.map( async ( blockPath ) => {
const blockName = path.basename( blockPath );
const themeName = blockPath.split( path.sep ).at( 3 ); // web/app/themes/<themeName>...
const themeName = getBlockThemeName( blockPath );

log.info( `Building block: ${ blockName } (${ themeName })` );

Expand Down
3 changes: 2 additions & 1 deletion packages/toolkit/src/scripts/watch-blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import path from 'path';
* Internal dependencies
*/
import { getBlockPaths } from '../utils/get-block-paths.js';
import { getBlockThemeName } from '../utils/get-block-theme-name.js';
import { ensureFileExists, setupGracefulShutdown } from '../utils/helpers.js';
import log from '../utils/logger.js';

Expand All @@ -27,7 +28,7 @@ export const watchBlocks = async ( configFile = 'vite-blocks.config.js' ) => {

blocks.forEach( ( blockPath ) => {
const blockName = path.basename( blockPath );
const themeName = blockPath.split( path.sep ).at( 3 ); // web/app/themes/<themeName>...
const themeName = getBlockThemeName( blockPath );

log.info( `Watching block: ${ blockName } (${ themeName })` );

Expand Down
39 changes: 6 additions & 33 deletions packages/toolkit/src/utils/get-all-theme-names.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,14 @@
/**
* Internal dependencies
*/
import log from './logger.js';
import { resolveThemeContext } from './resolve-theme-context.js';

/**
* External dependencies
*/
import fs from 'fs';
import path from 'path';

/**
* Returns an array of all theme names in the `web/app/themes` directory.
* 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 = () => {
const themesDir = path.resolve( 'web/app/themes' );

if ( ! fs.existsSync( themesDir ) ) {
log.error( 'Themes directory does not exist' );
return [];
}

return fs.readdirSync( themesDir ).filter( ( dirName ) => {
const fullPath = path.join( themesDir, dirName );

try {
const isDirectory = fs.statSync( fullPath ).isDirectory();

if ( ! isDirectory ) return false;

// Check if the directory contains a style.css file
const hasStyleCss = fs.existsSync(
path.join( fullPath, 'style.css' )
);
return hasStyleCss;
} catch {
log.error( `Error checking directory: ${ fullPath }` );
return false;
}
} );
return resolveThemeContext().themes.map( ( theme ) => theme.name );
};
9 changes: 4 additions & 5 deletions packages/toolkit/src/utils/get-block-paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import path from 'path';
/**
* Internal dependencies
*/
import { getAllThemeNames } from './get-all-theme-names.js';
import { resolveThemeContext } from './resolve-theme-context.js';

export const getBlockPaths = async () => {
const themeNames = getAllThemeNames();
const context = resolveThemeContext();

const blockPathsPerTheme = await Promise.all(
themeNames.map( async ( themeName ) => {
context.themes.map( async ( theme ) => {
const blocksDir = path.join(
'web/app/themes',
themeName,
theme.relDir,
'resources/scripts/blocks'
);

Expand Down
25 changes: 25 additions & 0 deletions packages/toolkit/src/utils/get-block-theme-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* External dependencies
*/
import path from 'path';

/**
* Internal dependencies
*/
import { resolveThemeContext } from './resolve-theme-context.js';

/**
* Returns the owning theme name for a discovered block path, for logging.
*
* - theme-root: the single theme's name.
* - brave-root: parsed from the `web/app/themes/<theme>/...` block path.
*/
export const getBlockThemeName = ( blockPath ) => {
const context = resolveThemeContext();

if ( context.mode === 'theme-root' ) {
return context.defaultTheme;
}

return blockPath.split( path.sep ).at( 3 );
};
Loading
Loading