Skip to content
Open
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
9 changes: 0 additions & 9 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,6 @@ const restrictedImports = [
];

const restrictedSyntax = [
// NOTE: We can't include the forward slash in our regex or
// we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern)
// here. That's why we use \\u002F in the regexes below.
{
selector:
'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]:not([source.value=/^@wordpress\\u002F.+\\u002Fbuild-types\\u002F/])',
message: 'Path access on WordPress dependencies is not allowed.',
},
{
selector:
'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]',
Expand Down Expand Up @@ -145,7 +137,6 @@ module.exports = {
jsdoc: {
mode: 'typescript',
},
'import/internal-regex': null,
'import/resolver': require.resolve( './tools/eslint/import-resolver' ),
},
rules: {
Expand Down
13 changes: 13 additions & 0 deletions bin/test-create-block.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ if [ "$expected" -ne "$actual" ]; then
exit 1
fi

# Create an ESLint config that extends wp-scripts' default config but uses the
# monorepo's custom import resolver. This is needed because local @wordpress/*
# packages export paths pointing to built files (build-module/), but we haven't
# run a build. The custom resolver maps these to source files (src/) instead.
cat > .eslintrc.js << 'EOF'
module.exports = {
extends: [ require.resolve( '@wordpress/scripts/config/.eslintrc' ) ],
settings: {
'import/resolver': require.resolve( '../tools/eslint/import-resolver' ),
},
};
EOF

status "Formatting files..."
../node_modules/.bin/wp-scripts format

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import path from 'path';
/**
* WordPress dependencies
*/
// eslint-disable-next-line no-restricted-syntax
import {
jsTester,
phpTester,
Expand Down
10 changes: 8 additions & 2 deletions packages/create-block/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@

## Unreleased

### Bug Fixes

- Fixed scaffolded `package.json` dependencies to include WordPress packages used in default templates.

## 4.78.0 (2025-11-12)

## 4.77.0 (2025-10-29)

## 4.76.0 (2025-10-17)

## Enhancement
- Enable `alias` package installation ([#72079](https://github.com/WordPress/gutenberg/pull/72079)).
## Enhancement

- Enable `alias` package installation ([#72079](https://github.com/WordPress/gutenberg/pull/72079)).

## 4.75.0 (2025-10-01)

Expand All @@ -18,6 +23,7 @@
## 4.73.0 (2025-09-03)

### Enhancement

- Add lifecycle script execution support during npm packages installation ([#71072](https://github.com/WordPress/gutenberg/pull/71072)).

## 4.72.0 (2025-08-20)
Expand Down
5 changes: 5 additions & 0 deletions packages/create-block/lib/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ const predefinedPluginTemplates = {
viewScript: 'file:./view.js',
example: {},
folderName: './src/$slug',
npmDependencies: [
'@wordpress/block-editor',
'@wordpress/blocks',
'@wordpress/i18n',
],
},
variants: {
static: {},
Expand Down
15 changes: 10 additions & 5 deletions packages/eslint-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@

## Unreleased

### Breaking CHanges

- Updated recommended ruleset to enforce [`import/no-unresolved`](https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md) for `@wordpress/` packages. These packages were previously exempted from the rule.
- Removed default configuration of [`import/internal-regex`](https://github.com/import-js/eslint-plugin-import/tree/main?tab=readme-ov-file#importinternal-regex) to classify `@wordpress/` packages as internal. From the perspective of an external consumer of this package, `@wordpress/` packages should be considered external.

## 22.21.0 (2025-11-12)

### Enhancements

- Disabled `import/no-unresolved`, `import/default`, and `import/named` checks for TypeScript files when TypeScript is installed, since these issues are [already checked by TypeScript](https://typescript-eslint.io/troubleshooting/typed-linting/performance/).
- Improved resolution behavior to support modern package export semantics by updating default import resolver to [`eslint-import-resolver-typescript`](https://www.npmjs.com/package/eslint-import-resolver-typescript), including for non-TypeScript files.
- Disabled `import/no-unresolved`, `import/default`, and `import/named` checks for TypeScript files when TypeScript is installed, since these issues are [already checked by TypeScript](https://typescript-eslint.io/troubleshooting/typed-linting/performance/).
- Improved resolution behavior to support modern package export semantics by updating default import resolver to [`eslint-import-resolver-typescript`](https://www.npmjs.com/package/eslint-import-resolver-typescript), including for non-TypeScript files.

## 22.20.0 (2025-10-29)

Expand All @@ -27,9 +32,9 @@

### Enhancements

- Added stricter ESLint checks for translator comments.
- Supports unnamed (%s, %d, %f), positional (%1$s, etc.) and named placeholders.
- Flags missing and extra/outdated placeholders.
- Added stricter ESLint checks for translator comments.
- Supports unnamed (%s, %d, %f), positional (%1$s, etc.) and named placeholders.
- Flags missing and extra/outdated placeholders.

## 22.12.0 (2025-06-25)

Expand Down
11 changes: 1 addition & 10 deletions packages/eslint-plugin/configs/recommended-with-formatting.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// Exclude bundled WordPress packages from the list.
const wpPackagesRegExp = '^@wordpress/(?!(icons|interface|style-engine))';

const config = {
extends: [
require.resolve( './jsx-a11y.js' ),
Expand All @@ -20,7 +17,6 @@ const config = {
wp: 'readonly',
},
settings: {
'import/internal-regex': wpPackagesRegExp,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting that this can have an impact on rules like import/order in considering packages as "internal", though (a) this base config exists in a reusable package for third-party consumption where @wordpress/ packages are not internal, and (b) even inside the context of this project, we distinguish @wordpress/ packages from "internal" dependencies.

It might still make sense to define this at the root /.eslintrc.js since, after all, the setting is described as "useful when you are utilizing a monorepo setup or developing a set of packages that depend on each other". But it doesn't seem like something which will actually have much of an impact in practical usage from what I can tell.

Related: #73396

Copy link
Member Author

@aduth aduth Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting that this can have an impact on rules like import/order in considering packages as "internal", though (a) this base config exists in a reusable package for third-party consumption where @wordpress/ packages are not internal, and (b) even inside the context of this project, we distinguish @wordpress/ packages from "internal" dependencies.

I added an extra CHANGELOG note clarifying this in 0748af8.

It might still make sense to define this at the root /.eslintrc.js since, after all, the setting is described as "useful when you are utilizing a monorepo setup or developing a set of packages that depend on each other". But it doesn't seem like something which will actually have much of an impact in practical usage from what I can tell.

Funny enough, while this might make sense to do, I recalled that one of the changes I'm making in this branch is to remove the code where we explicitly unset this value in our .eslintrc.js. So this should change should have no net effect in this project. Ironic that we were defining this default internal regular expression and not using it in the one place it might make sense to do so 😅

'import/extensions': [ '.js', '.jsx' ],
'import/resolver': {
typescript: true,
Expand All @@ -33,12 +29,7 @@ const config = {
peerDependencies: true,
},
],
'import/no-unresolved': [
'error',
{
ignore: [ wpPackagesRegExp ],
},
],
'import/no-unresolved': 'error',
'import/default': 'warn',
'import/named': 'warn',
},
Expand Down
9 changes: 0 additions & 9 deletions packages/react-native-editor/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ module.exports = {
rules: {
'no-restricted-syntax': [
'error',
// NOTE: We can't include the forward slash in our regex or
// we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern)
// here. That's why we use \\u002F in the regexes below.
{
selector:
'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]',
message:
'Path access on WordPress dependencies is not allowed.',
},
{
selector:
'CallExpression[callee.name=/^(__|_x|_n|_nx)$/] Literal[value=/\\.{3}/]',
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/box/stories/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { type Meta, type StoryObj } from '@storybook/react';
/**
* WordPress dependencies
*/
import '@wordpress/theme/design-tokens.css'; // eslint-disable-line no-restricted-syntax
import '@wordpress/theme/design-tokens.css';

/**
* Internal dependencies
Expand Down
2 changes: 0 additions & 2 deletions test/integration/full-content/full-content.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ import {
writeBlockFixtureSerializedHTML,
} from '../fixtures';

/* eslint-disable no-restricted-syntax */
import * as form from '@wordpress/block-library/src/form';
import * as formInput from '@wordpress/block-library/src/form-input';
import * as formSubmitButton from '@wordpress/block-library/src/form-submit-button';
import * as formSubmissionNotification from '@wordpress/block-library/src/form-submission-notification';
/* eslint-enable no-restricted-syntax */

const blockBasenames = getAvailableBlockFixturesBasenames();

Expand Down
29 changes: 21 additions & 8 deletions tools/eslint/import-resolver.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/**
* External dependencies
*/
const path = require( 'node:path' );
const { existsSync } = require( 'node:fs' );
const resolverNode = require( 'eslint-import-resolver-typescript' );
const path = require( 'path' );

const PACKAGES_DIR = path.resolve( __dirname, '../../packages' );

exports.interfaceVersion = 2;
Expand All @@ -16,15 +16,28 @@ exports.resolve = function ( source, file, config ) {
} );

if ( source.startsWith( '@wordpress/' ) ) {
const packageName = source.slice( '@wordpress/'.length );

const result = resolve( path.join( PACKAGES_DIR, packageName ) );
const [ , packageName, ...pathParts ] = source.split( '/' );

if ( result.found ) {
return result;
// Consider whether the package is local to the project. If it's not,
// use the default resolution behavior.
const packagePath = path.join( PACKAGES_DIR, packageName );
if ( ! existsSync( packagePath ) ) {
return resolve( source );
}

return resolve( path.join( PACKAGES_DIR, `${ packageName }/src/` ) );
// For all local packages, ensure that we can resolve the requested
// source file using its declared exports.
try {
const manifestPath = path.join( packagePath, 'package.json' );
const manifest = require( manifestPath );
const subpath = path.join( '.', pathParts.join( '/' ) );
const exportPath = manifest.exports?.[ subpath ]?.import;
const sourcePath = exportPath.replace( 'build-module', 'src' );

return resolve( path.join( packagePath, sourcePath ) );
} catch {
return { found: false };
}
}

return resolve( source );
Expand Down
Loading