diff --git a/package-lock.json b/package-lock.json index a2ee11c8383960..024fc6f3a306d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43127,6 +43127,15 @@ "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==", "license": "Apache-2.0" }, + "node_modules/wasm-vips": { + "version": "0.0.18", + "resolved": "https://registry.npmjs.org/wasm-vips/-/wasm-vips-0.0.18.tgz", + "integrity": "sha512-AJyCvxZj/3qceKNnh+YyEobu/IaJFoPN7x7SxyyHmYBS3kASMqJqxQEuN0ZHKQDWsCJ8armfx4Tq3uKrNc+nMA==", + "license": "MIT", + "engines": { + "node": ">=17.0.0" + } + }, "node_modules/watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", @@ -45243,6 +45252,7 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@wordpress/integration-tests": "file:../../test/integration", "@wordpress/stylelint-tools": "file:../../tools/stylelint", "deep-freeze": "^0.0.1" }, @@ -46979,6 +46989,7 @@ "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@wordpress/block-library": "file:../block-library", "deep-freeze": "^0.0.1" }, "engines": { @@ -47586,6 +47597,7 @@ "version": "5.49.0", "license": "GPL-2.0-or-later", "devDependencies": { + "@wordpress/lazy-import": "file:../lazy-import", "benchmark": "^2.1.4" }, "engines": { @@ -49494,15 +49506,6 @@ "npm": ">=8.19.2" } }, - "packages/vips/node_modules/wasm-vips": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/wasm-vips/-/wasm-vips-0.0.18.tgz", - "integrity": "sha512-AJyCvxZj/3qceKNnh+YyEobu/IaJFoPN7x7SxyyHmYBS3kASMqJqxQEuN0ZHKQDWsCJ8armfx4Tq3uKrNc+nMA==", - "license": "MIT", - "engines": { - "node": ">=17.0.0" - } - }, "packages/warning": { "name": "@wordpress/warning", "version": "3.49.0", @@ -50200,6 +50203,7 @@ "@y/websocket-server": "^0.1.1", "esbuild": "^0.27.2", "filenamify": "^4.2.0", + "wasm-vips": "^0.0.18", "ws": "^8.18.3", "y-websocket": "^3.0.0" } @@ -50255,7 +50259,8 @@ "@playwright/test": "^1.61.1", "@types/node": "^20.19.39", "@wordpress/e2e-test-utils-playwright": "file:../../packages/e2e-test-utils-playwright", - "@wordpress/scripts": "file:../../packages/scripts" + "@wordpress/scripts": "file:../../packages/scripts", + "wasm-vips": "^0.0.18" } }, "test/storybook-playwright": { diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 76bdd71295ebb3..561ce97aca6f2c 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -39,7 +39,7 @@ "require": "./build/index.cjs" }, "./package.json": "./package.json", - "./build-style/": "./build-style/" + "./build-style/*": "./build-style/*" }, "wpScript": true, "wpScriptModuleExports": { diff --git a/packages/block-editor/src/components/block-patterns-list/stories/index.story.jsx b/packages/block-editor/src/components/block-patterns-list/stories/index.story.jsx index d30b99241966eb..39860ce17f2929 100644 --- a/packages/block-editor/src/components/block-patterns-list/stories/index.story.jsx +++ b/packages/block-editor/src/components/block-patterns-list/stories/index.story.jsx @@ -11,7 +11,7 @@ import { ExperimentalBlockEditorProvider } from '../../provider'; import patterns from './fixtures'; // Reason: Styles are contained in ExperimentalBlockEditorProvider iframe. // eslint-disable-next-line @wordpress/no-non-module-stylesheet-imports -import blockLibraryStyles from '../../../../../block-library/build-style/style.css?raw'; +import blockLibraryStyles from '@wordpress/block-library/build-style/style.css?raw'; const blockEditorSettings = { styles: [ { css: blockLibraryStyles } ], diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 9cbcbc1709ddaa..5100ca90fbfbee 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -145,6 +145,7 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@wordpress/integration-tests": "file:../../test/integration", "@wordpress/stylelint-tools": "file:../../tools/stylelint", "deep-freeze": "^0.0.1" }, diff --git a/packages/block-library/src/cover/test/edit.js b/packages/block-library/src/cover/test/edit.js index 3b1dde597adf6f..fbd7769b726835 100644 --- a/packages/block-library/src/cover/test/edit.js +++ b/packages/block-library/src/cover/test/edit.js @@ -10,7 +10,7 @@ import userEvent from '@testing-library/user-event'; import { initializeEditor, selectBlock, -} from 'test/integration/helpers/integration-test-editor'; +} from '@wordpress/integration-tests/helpers/integration-test-editor'; const defaultSettings = { __experimentalFeatures: { diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index a98564691fe5af..140baf94859a57 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -40,6 +40,7 @@ "access": "public" }, "scripts": { + "prelint:js": "npm run build:js", "build": "concurrently \"npm run build:js\" \"npm run build:php\"", "build:js": "pegjs --format commonjs -o ./parser.js ./grammar.pegjs", "build:php": "node bin/create-php-parser.js" diff --git a/packages/components/src/context/stories/ComponentsProvider.stories.jsx b/packages/components/src/context/stories/ComponentsProvider.stories.jsx index 84c2aa30868603..91ac61cdd8e0dd 100644 --- a/packages/components/src/context/stories/ComponentsProvider.stories.jsx +++ b/packages/components/src/context/stories/ComponentsProvider.stories.jsx @@ -6,9 +6,9 @@ import { createContext, useContext, memo, useState } from '@wordpress/element'; /** * Internal dependencies */ -import { Card, CardBody } from '../../../card'; -import { View } from '../../../view'; -import { Text } from '../../../text'; +import { Card, CardBody } from '../../card'; +import { View } from '../../view'; +import { Text } from '../../text'; import { ContextSystemProvider } from '../index'; const SomeContext = createContext(); diff --git a/packages/editor/package.json b/packages/editor/package.json index 2882230a163366..aff3f31836152d 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -121,6 +121,7 @@ "@testing-library/dom": "^10.4.1", "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", + "@wordpress/block-library": "file:../block-library", "deep-freeze": "^0.0.1" }, "peerDependencies": { diff --git a/packages/editor/src/components/post-revisions-preview/test/block-diff.js b/packages/editor/src/components/post-revisions-preview/test/block-diff.js index 71f9a4683b02b0..f3c0677b955d5b 100644 --- a/packages/editor/src/components/post-revisions-preview/test/block-diff.js +++ b/packages/editor/src/components/post-revisions-preview/test/block-diff.js @@ -9,8 +9,8 @@ import { serialize, } from '@wordpress/blocks'; import { RichTextData } from '@wordpress/rich-text'; -import * as paragraphBlock from '@wordpress/block-library/src/paragraph'; -import * as groupBlock from '@wordpress/block-library/src/group'; +import * as paragraphBlock from '@wordpress/block-library/build-module/paragraph/index.mjs'; +import * as groupBlock from '@wordpress/block-library/build-module/group/index.mjs'; /** * Internal dependencies diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index 76912c37b9f598..6ca7bb0d4043b2 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -45,6 +45,7 @@ "types": "build-types", "sideEffects": false, "devDependencies": { + "@wordpress/lazy-import": "file:../lazy-import", "benchmark": "^2.1.4" }, "publishConfig": { diff --git a/storybook/stories/playground/zoom-out/index.jsx b/storybook/stories/playground/zoom-out/index.jsx index 389f7965150243..5a48617246bfcb 100644 --- a/storybook/stories/playground/zoom-out/index.jsx +++ b/storybook/stories/playground/zoom-out/index.jsx @@ -13,7 +13,7 @@ import { pattern } from './pattern'; import { editorStyles } from '../editor-styles'; // Reason: Styles are contained in BlockCanvas iframe. // eslint-disable-next-line @wordpress/no-non-module-stylesheet-imports -import contentCss from '../../../../packages/block-editor/build-style/content.css?raw'; +import contentCss from '@wordpress/block-editor/build-style/content.css?raw'; // Temporary hack to access private APIs before stabilizing zoom level. const { unlock } = __dangerousOptInToUnstableAPIsOnlyForCoreModules( diff --git a/test/e2e/package.json b/test/e2e/package.json index e0d368e9dd9f60..ab46a180f99cdb 100644 --- a/test/e2e/package.json +++ b/test/e2e/package.json @@ -30,6 +30,7 @@ "@y/websocket-server": "^0.1.1", "esbuild": "^0.27.2", "filenamify": "^4.2.0", + "wasm-vips": "^0.0.18", "ws": "^8.18.3", "y-websocket": "^3.0.0" }, diff --git a/test/integration/package.json b/test/integration/package.json index 649feb38b6c096..059a3ccfa0a60f 100644 --- a/test/integration/package.json +++ b/test/integration/package.json @@ -19,6 +19,9 @@ "bugs": { "url": "https://github.com/WordPress/gutenberg/issues" }, + "exports": { + "./helpers/integration-test-editor": "./helpers/integration-test-editor.js" + }, "devDependencies": { "@testing-library/react": "^16.3.2", "@testing-library/user-event": "^14.6.1", diff --git a/test/performance/package.json b/test/performance/package.json index e2f37597c7c785..eba2451e5ec33d 100644 --- a/test/performance/package.json +++ b/test/performance/package.json @@ -24,7 +24,8 @@ "@playwright/test": "^1.61.1", "@types/node": "^20.19.39", "@wordpress/e2e-test-utils-playwright": "file:../../packages/e2e-test-utils-playwright", - "@wordpress/scripts": "file:../../packages/scripts" + "@wordpress/scripts": "file:../../packages/scripts", + "wasm-vips": "^0.0.18" }, "publishConfig": { "access": "public" diff --git a/test/unit/jest.config.js b/test/unit/jest.config.js index 19bdca4c8bd0b3..6bb44b3b09f6e1 100644 --- a/test/unit/jest.config.js +++ b/test/unit/jest.config.js @@ -48,6 +48,8 @@ module.exports = { 'packages/$1/src', '@wordpress/theme/design-tokens.js': '/packages/theme/src/prebuilt/js/design-tokens.mjs', + '@wordpress/block-library/build-module/(.*).mjs': + '/packages/block-library/src/$1.js', '.+\\.wasm$': '/test/unit/config/wasm-stub.js', }, preset: jestPresetDefaultDir, diff --git a/tools/eslint/config.mjs b/tools/eslint/config.mjs index f12a0494a49e93..782711ccdb34e7 100644 --- a/tools/eslint/config.mjs +++ b/tools/eslint/config.mjs @@ -376,9 +376,6 @@ export default dedupePlugins( [ { files: developmentFiles, rules: { - 'import/default': 'off', - 'import/no-unresolved': 'off', - 'import/named': 'off', '@wordpress/data-no-store-string-literals': 'off', }, }, @@ -389,6 +386,7 @@ export default dedupePlugins( [ files: [ '**/fixtures/**' ], rules: { 'import/no-extraneous-dependencies': 'off', + 'import/no-unresolved': 'off', }, }, diff --git a/tools/eslint/import-resolver.cjs b/tools/eslint/import-resolver.cjs index 3d08282515733d..7d7d3f6eb12be0 100644 --- a/tools/eslint/import-resolver.cjs +++ b/tools/eslint/import-resolver.cjs @@ -8,11 +8,81 @@ const PACKAGES_DIR = path.resolve( __dirname, '../../packages' ); exports.interfaceVersion = 2; +/** + * @typedef ExportEntryObject + * + * @property {string} import ESM import entrypoint. + * @property {string} default Default export entrypoint. + */ + +/** + * @typedef {string|ExportEntryObject} ExportEntry + */ + +/** + * Given an export entry and a subpath, returns the resolved export path for + * the matching entry. Defaults to the ESM entrypoint if available, falling back + * to the default export or the root entry if it is a string. + * + * @param {ExportEntry} exportEntry Export entry from package manifest. + * + * @return {string|undefined} The resolved export path, or undefined if no + * matching entry is found. + */ +function getResolvedExportPath( exportEntry ) { + return typeof exportEntry === 'string' + ? exportEntry + : exportEntry?.import ?? exportEntry?.default; +} + +/** + * Given a package entrypoint identifier, returns the resolved export path for + * the matching entry. Supports matching wildcard entries, and defaults to the + * ESM entrypoint if available. + * + * @param {string} subpath Package entrypoint identifier. + * @param {Record} exportMap Export map from package manifest. + * + * @return {string|void|undefined} The resolved export path, or undefined if no + * matching entry is found. + */ +function getResolvedExport( subpath, exportMap ) { + if ( Object.hasOwn( exportMap, subpath ) ) { + return getResolvedExportPath( exportMap[ subpath ] ); + } + + for ( const key in exportMap ) { + if ( ! Object.hasOwn( exportMap, key ) ) { + continue; + } + + const wildcardIndex = key.indexOf( '*' ); + if ( wildcardIndex === -1 ) { + continue; + } + + if ( subpath.startsWith( key.substring( 0, wildcardIndex ) ) ) { + const wildcardPath = subpath.substring( wildcardIndex ); + const resolvedPath = getResolvedExportPath( exportMap[ key ] ); + return resolvedPath?.replace( '*', wildcardPath ); + } + } +} + exports.resolve = function ( source, file, config ) { const resolve = ( sourcePath ) => resolverNode.resolve( sourcePath, file, { ...config, - extensions: [ '.tsx', '.ts', '.mjs', '.js', '.json', '.node' ], + extensions: [ + '.tsx', + '.ts', + '.mjs', + '.js', + '.jsx', + '.cjs', + '.json', + '.node', + ], } ); if ( source.startsWith( '@wordpress/' ) ) { @@ -30,11 +100,28 @@ exports.resolve = function ( source, file, config ) { try { const manifestPath = path.join( packagePath, 'package.json' ); const manifest = JSON.parse( readFileSync( manifestPath, 'utf8' ) ); - const subpath = path.join( '.', pathParts.join( '/' ) ); - const exportPath = manifest.exports?.[ subpath ]?.import; + let subpath = '.'; + if ( pathParts.length > 0 ) { + subpath += '/' + pathParts.join( '/' ); + } + + // Storybook uses the React Vite builder, and Vite supports + // importing assets as strings by appending `?raw`. Ignore this + // and other querystrings in the path when resolving the export. + // + // See: https://vite.dev/guide/assets#importing-asset-as-string + subpath = subpath.split( '?' )[ 0 ]; + + const exportPath = getResolvedExport( subpath, manifest.exports ); + const sourcePath = exportPath - .replace( 'build-module', 'src' ) - .replace( /\.mjs$/, '.js' ); + // Remap build-style CSS files to src SCSS files. By default, + // wp-build emits a CSS file for each SCSS file in src. This is + // controlled by wpStyleEntryPoints which we don't fully + // recreate here (yet), but generally we don't override this. + .replace( /build-style\/(.+?)\.css/, 'src/$1.scss' ) + .replace( /build(-module)?/, 'src' ) + .replace( /\.[cm]?js$/, '.js' ); return resolve( path.join( packagePath, sourcePath ) ); } catch {