Skip to content
Draft
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
13 changes: 9 additions & 4 deletions packages/eslint-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ const eslintSettings = merge(require('@yardinternet/eslint-config'), [
module.exports = eslintSettings;
```

## brave-root vs theme-root
## Import aliases

The `@sage/scripts` import alias auto-detects where ESLint runs:
Every theme gets an `@<theme>/scripts` alias pointing at its own
`resources/scripts`, in both layouts:

- **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`.
- **brave-root** — cwd is the project root; aliases resolve per theme, e.g. `@sage/scripts` → `web/app/themes/sage/resources/scripts`.
- **theme-root** — cwd is a single theme (has `style.css`, no themes directory); `@<theme>/scripts` → `./resources/scripts`.

`@sage/scripts` is always available: in projects without a theme named `sage` it
falls back to the default theme, so shared starter code keeps resolving. See
[project layout detection](../shared-utils/README.md#project-layout-detection).
1 change: 1 addition & 0 deletions packages/eslint-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"license": "ISC",
"dependencies": {
"@wordpress/eslint-plugin": "^25.8.0",
"@yardinternet/shared-utils": "workspace:*",
"eslint-import-resolver-alias": "^1.1.2",
"globals": "^17.7.0",
"typescript-eslint": "^8.62.1"
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const sharedRules = {
module.exports = [
...wordpress.configs.recommended,
{
files: [ '**/*.js', '**/*.jsx' ],
files: [ '**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs' ],
languageOptions: {
globals: sharedGlobals,
},
Expand Down
51 changes: 35 additions & 16 deletions packages/eslint-config/src/utils/resolve-import-aliases.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,51 @@
const fs = require( 'fs' );
const path = require( 'path' );
const { tryResolveThemeContext } = require( '@yardinternet/shared-utils' );

/**
* 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.
* - brave-root: `@<theme>/scripts` for every theme in the themes directory.
* - theme-root (cwd is a theme): `@<theme>/scripts` points at the local
* `./resources/scripts`.
*
* `@sage/scripts` is kept in both layouts, aliased to the default theme, so
* starter code importing it keeps resolving in projects that do not name their
* parent theme `sage`.
*/
const resolveImportAliases = () => {
const cwd = process.cwd();
const isBraveRoot = fs.existsSync( path.resolve( cwd, 'web/app/themes' ) );
const context = tryResolveThemeContext();

if ( ! context ) {
// Not a WordPress project layout — assume the cwd is the theme.
const themeName = path.basename( process.cwd() );

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

const themeName = path.basename( cwd );
const scriptsPath = ( theme ) =>
context.mode === 'theme-root'
? './resources/scripts'
: `./${ theme.relDirPosix }/resources/scripts`;

const aliases = context.themes.map( ( theme ) => [
`@${ theme.name }/scripts`,
scriptsPath( theme ),
] );

if ( ! aliases.some( ( [ alias ] ) => alias === '@sage/scripts' ) ) {
const defaultTheme = context.themes.find(
( theme ) => theme.name === context.defaultTheme
);

if ( defaultTheme ) {
aliases.push( [ '@sage/scripts', scriptsPath( defaultTheme ) ] );
}
}

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' ],
];
return aliases;
};

module.exports = resolveImportAliases;
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,8 @@ exports[`eslint config files patterns match snapshot 1`] = `
[
"**/*.js",
"**/*.jsx",
"**/*.cjs",
"**/*.mjs",
],
[
"**/*.ts",
Expand Down
59 changes: 59 additions & 0 deletions packages/eslint-config/tests/import-aliases.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
'use strict';

const path = require( 'path' );
const resolveImportAliases = require( '../src/utils/resolve-import-aliases' );
const { clearThemeContextCache } = require( '@yardinternet/shared-utils' );

const FIXTURES = path.resolve( __dirname, '../../shared-utils/tests/fixtures' );

const originalCwd = process.cwd();

const useProject = ( ...segments ) => {
process.chdir( path.join( FIXTURES, ...segments ) );
clearThemeContextCache();
};

afterEach( () => {
process.chdir( originalCwd );
clearThemeContextCache();
} );

test( 'brave-root aliases every theme and keeps @sage/scripts', () => {
useProject( 'bedrock' );

expect( resolveImportAliases() ).toEqual( [
[ '@sage/scripts', './web/app/themes/sage/resources/scripts' ],
[
'@sage-child/scripts',
'./web/app/themes/sage-child/resources/scripts',
],
] );
} );

test( '@sage/scripts falls back to the default theme when no sage exists', () => {
useProject( 'configured' );

expect( resolveImportAliases() ).toEqual( [
[ '@alpha/scripts', './src/themes/alpha/resources/scripts' ],
[ '@zulu/scripts', './src/themes/zulu/resources/scripts' ],
[ '@sage/scripts', './src/themes/zulu/resources/scripts' ],
] );
} );

test( 'theme-root points every alias at the local resources', () => {
useProject( 'theme-root', 'basis' );

expect( resolveImportAliases() ).toEqual( [
[ '@basis/scripts', './resources/scripts' ],
[ '@sage/scripts', './resources/scripts' ],
] );
} );

test( 'unresolvable layouts keep the historical theme-root guess', () => {
useProject( 'empty' );

expect( resolveImportAliases() ).toEqual( [
[ '@empty/scripts', './resources/scripts' ],
[ '@sage/scripts', './resources/scripts' ],
] );
} );
7 changes: 5 additions & 2 deletions packages/postcss-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ const postcssSettings = require('@yardinternet/postcss-config');
module.exports = postcssSettings(getPathToTheme(), __dirname);
```

The default path to the styles is `web/app/themes/sage/resources/styles`.
You can change this values by passing the paths as an parameter.
The `@sage` import alias points at the default theme's
`resources/styles`, resolved from the [project
layout](../shared-utils/README.md#project-layout-detection). It falls back to
`web/app/themes/sage/resources/styles` when the layout cannot be resolved.
You can change this value by passing the path as a parameter.

```js
const postcssSettings = require('@yardinternet/postcss-config');
Expand Down
55 changes: 28 additions & 27 deletions packages/postcss-config/package.json
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
{
"name": "@yardinternet/postcss-config",
"version": "2.1.6",
"description": "PostCSS settings",
"main": "src/index.js",
"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/postcss-config"
},
"type": "commonjs",
"author": "",
"license": "ISC",
"dependencies": {
"autoprefixer": "^10.5.0",
"cssnano": "^7.1.9",
"path": "^0.12.7",
"postcss": "^8.5.15",
"postcss-import": "^16.1.1",
"postcss-mixins": "^12.1.2",
"postcss-nested": "^7.0.2"
}
"name": "@yardinternet/postcss-config",
"version": "2.1.6",
"description": "PostCSS settings",
"main": "src/index.js",
"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/postcss-config"
},
"type": "commonjs",
"author": "",
"license": "ISC",
"dependencies": {
"@yardinternet/shared-utils": "workspace:*",
"autoprefixer": "^10.5.0",
"cssnano": "^7.1.9",
"path": "^0.12.7",
"postcss": "^8.5.15",
"postcss-import": "^16.1.1",
"postcss-mixins": "^12.1.2",
"postcss-nested": "^7.0.2"
}
}
29 changes: 23 additions & 6 deletions packages/postcss-config/src/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
const path = require( 'path' );
const { tryResolveThemeContext } = require( '@yardinternet/shared-utils' );

/**
* Styles of the parent theme the `@sage` import alias points at. Falls back to
* the historical sage path when the project layout cannot be resolved.
*/
const defaultStylesPath = ( basePath ) => {
const context = tryResolveThemeContext( { cwd: basePath } );

if ( ! context ) {
return 'web/app/themes/sage/resources/styles';
}

return path.join(
context.themeRelDir( context.defaultTheme ),
'resources',
'styles'
);
};

module.exports = ( pathToTheme, basePath, pathToStyles = null ) => {
const parentStylesPath = pathToStyles ?? defaultStylesPath( basePath );

module.exports = (
pathToTheme,
basePath,
pathToStyles = 'web/app/themes/sage/resources/styles'
) => {
// Add alias paths for PostCSS imports
const resolveAliasPaths = ( id ) => {
if ( id.startsWith( '@sage' ) ) {
const relativePath = id.replace( '@sage', '' ).trimStart( '/' );

const sageParentThemeStylesPath = path.join(
basePath,
pathToStyles
parentStylesPath
);
return path.join( sageParentThemeStylesPath, relativePath );
}
Expand Down
23 changes: 20 additions & 3 deletions packages/prettier-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,26 @@ const prettierSettings = merge(require('@yardinternet/prettier-config'), {
module.exports = prettierSettings;
```

## brave-root vs theme-root
## Tailwind config stylesheet

The Tailwind config stylesheet is located automatically, trying both layouts:
Located automatically at `<theme>/resources/styles/base/config.css`, in both
layouts:

- **brave-root** — `web/app/themes/sage/resources/styles/base/config.css`.
- **brave-root** — the default theme's stylesheet is used as the project-wide
default, and each theme additionally gets a Prettier `override` pointing at
its own, so a file is sorted against its own theme's Tailwind config.
- **theme-root** — the theme's own `resources/styles/base/config.css`.

See [project layout detection](../shared-utils/README.md#project-layout-detection)
for how the themes directory and default theme are resolved.

### VSCode

The project root is anchored on this package's own location inside the project's
`node_modules`, which is the only signal that holds up in the VSCode Prettier
extension — the extension host's `process.cwd()` is `/` when the editor is
launched from the Dock, and `VSCODE_CWD` points at whichever directory launched
the editor.

The config is read once per process, so a multi-root workspace resolves a single
project. Reload the window after adding a theme.
1 change: 1 addition & 0 deletions packages/prettier-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@shufo/prettier-plugin-blade": "^1.16.2",
"@shufo/tailwindcss-class-sorter": "^3.0.1",
"@wordpress/prettier-config": "^4.48.0",
"@yardinternet/shared-utils": "workspace:*",
"prettier": "npm:wp-prettier@^3.0.3",
"prettier-plugin-tailwindcss": "^0.7.4"
},
Expand Down
18 changes: 17 additions & 1 deletion packages/prettier-config/src/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
const findTailwindStylesheet = require( './utils/find-tailwind-stylesheet' );
const path = require( 'path' );
const {
findTailwindStylesheet,
findThemeStylesheets,
} = require( './utils/find-tailwind-stylesheet' );

const tailwindStylesheet = findTailwindStylesheet();

/**
* Prettier merges every matching override in order, so these only narrow the
* Tailwind stylesheet per theme — a file is sorted against its own theme's
* config instead of a single project-wide one. Globs are absolute and posix,
* since override patterns resolve against the config file's directory.
*/
const themeOverrides = findThemeStylesheets().map( ( theme ) => ( {
files: `${ theme.dir.split( path.sep ).join( '/' ) }/**`,
options: { tailwindStylesheet: theme.stylesheet },
} ) );

module.exports = {
...require( '@wordpress/prettier-config' ),
plugins: [
Expand All @@ -10,6 +25,7 @@ module.exports = {
],
...( tailwindStylesheet && { tailwindStylesheet } ),
overrides: [
...themeOverrides,
{
files: [ '*.css', '*.js', '*.jsx', '*.ts', '*.tsx' ],
options: {
Expand Down
Loading