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
40 changes: 35 additions & 5 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import wordpressPlugin from '@wordpress/eslint-plugin';
import comments from '@eslint-community/eslint-plugin-eslint-comments/configs';
import jestPlugin from 'eslint-plugin-jest';
import globals from 'globals';
import tseslint from 'typescript-eslint';

const TEST_FILES = [
'**/__tests__/**/*.js',
'**/test/*.js',
'**/?(*.)test.js',
'tests/js/**/*.js',
'**/__tests__/**/*.{js,ts,tsx}',
'**/test/*.{js,ts,tsx}',
'**/?(*.)test.{js,ts,tsx}',
'tests/js/**/*.{js,ts,tsx}',
];

export default [
Expand All @@ -28,6 +29,30 @@ export default [

...wordpressPlugin.configs[ 'recommended-with-formatting' ],

// `recommended-with-formatting` (unlike `recommended`) doesn't register a
// TypeScript config, so `.ts`/`.tsx` would be unmatched and skipped. Add the
// TypeScript parser + the unused-vars handoff, mirroring the TS block in
// @wordpress/eslint-plugin's `recommended` preset.
{
files: [ '**/*.ts', '**/*.tsx' ],
languageOptions: {
parser: tseslint.parser,
},
plugins: {
'@typescript-eslint': tseslint.plugin,
},
rules: {
'no-duplicate-imports': 'off',
'jsdoc/require-param-type': 'off',
'jsdoc/require-returns-type': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{ ignoreRestSiblings: true },
],
},
},

// import plugin is already registered by the WordPress config above;
// add the remaining rules from plugin:import/recommended without re-registering.
{
Expand Down Expand Up @@ -65,7 +90,12 @@ export default [

{
settings: {
'import/resolver': { node: true },
'import/resolver': {
typescript: {
extensions: [ '.js', '.jsx', '.ts', '.tsx' ],
},
node: true,
},
},
},
];
58 changes: 10 additions & 48 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 10 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"devDependencies": {
"@babel/core": "7.29.7",
"@eslint-community/eslint-plugin-eslint-comments": "4.7.2",
"@types/jest": "29.5.14",
"@types/react": "19.2.17",
"@types/react-dom": "19.2.3",
"@types/wordpress__block-editor": "15.0.6",
Comment thread
pratik-londhe4 marked this conversation as resolved.
"@wordpress/babel-preset-default": "8.47.0",
"@wordpress/browserslist-config": "6.47.0",
"@wordpress/env": "11.7.0",
Expand All @@ -34,6 +38,7 @@
"npm-run-all": "4.1.5",
"rtlcss": "4.3.0",
"svgo": "4.0.1",
"typescript": "6.0.3",
"webpack": "5.107.2",
"webpack-remove-empty-scripts": "1.1.1"
},
Expand All @@ -47,7 +52,9 @@
"overrides": {
"webpack-dev-server": "5.2.1",
"serialize-javascript": "7.0.3",
"minimatch": "3.1.3"
"minimatch": "3.1.3",
"@types/react": "$@types/react",
"@types/react-dom": "$@types/react-dom"
},
"private": true,
"repository": {
Expand All @@ -64,11 +71,12 @@
"init": "./bin/init.js && npm run sync-ai",
"sync-ai": "node bin/sync-ai.js",
"lint:all": "npm-run-all --parallel lint:*",
"lint:css": "wp-scripts lint-style ./src",
"lint:css": "wp-scripts lint-style './src/**/*.{css,scss}'",
"lint:css:fix": "npm run lint:css -- --fix",
"lint:js": "wp-scripts lint-js ./src",
"lint:js:fix": "npm run lint:js -- --fix",
"lint:js:report": "npm run lint:js -- --output-file lint-js-report.json --format json .",
"lint:js:types": "tsc --noEmit",
"lint:package-json": "wp-scripts lint-pkg-json --ignorePath .gitignore",
"lint:php": "php vendor/bin/phpcs",
"lint:php:fix": "node ./bin/phpcbf.js",
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
declare module '*.scss';
declare module '*.css';
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,32 @@
*/
import { store, getContext, getElement } from '@wordpress/interactivity';

/**
* Shape of the per-element context (set via `data-wp-context` in the markup).
*/
interface MediaTextContext {
isPlaying: boolean;
}

store( 'elementary/media-text', {
actions: {
/**
* Update the video play state.
*
* @return {void}
*/
play() {
const context = getContext();
play(): void {
const context = getContext< MediaTextContext >();
context.isPlaying = true;
},
},
callbacks: {
/**
* Play the video.
*
* @return {void}
*/
playVideo() {
const context = getContext();
playVideo(): void {
const context = getContext< MediaTextContext >();
const { ref } = getElement();
if ( context.isPlaying ) {
ref.querySelector( 'video' )?.play();
ref?.querySelector( 'video' )?.play();
context.isPlaying = false;
}
},
Expand Down
29 changes: 29 additions & 0 deletions tests/js/webpack-config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,33 @@ describe( 'webpack component entries', () => {
'components/button': path.join( buttonDir, 'button.js' ),
} );
} );

it( 'picks up .ts and .tsx component entries with the build pattern', () => {
tmpDir = fs.mkdtempSync(
path.join( os.tmpdir(), 'elementary-webpack-components-ts-' )
);

const cardDir = path.join( tmpDir, 'card' );
const modalDir = path.join( tmpDir, 'modal' );
const legacyDir = path.join( tmpDir, 'legacy' );

[ cardDir, modalDir, legacyDir ].forEach( ( dir ) => fs.mkdirSync( dir ) );

// One entry per supported extension.
fs.writeFileSync( path.join( cardDir, 'card.ts' ), '' );
fs.writeFileSync( path.join( modalDir, 'modal.tsx' ), '' );
fs.writeFileSync( path.join( legacyDir, 'legacy.js' ), '' );

// Same-folder files that must NOT become entries (basename mismatch),
// even though their extensions match the widened pattern.
fs.writeFileSync( path.join( cardDir, 'card.types.ts' ), '' );
fs.writeFileSync( path.join( cardDir, 'card.test.tsx' ), '' );

// Mirrors the pattern used by componentScripts in webpack.config.js.
expect( getComponentEntries( tmpDir, /\.(jsx?|tsx?)$/ ) ).toEqual( {
'components/card': path.join( cardDir, 'card.ts' ),
'components/modal': path.join( modalDir, 'modal.tsx' ),
'components/legacy': path.join( legacyDir, 'legacy.js' ),
} );
} );
} );
66 changes: 66 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"$schema": "https://json.schemastore.org/tsconfig.json",

"compilerOptions": {
"allowJs": true,
// Migration override — flip to true once src/ is fully .ts/.tsx.
"checkJs": false,

// Type checking — full strict.
"strict": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"noErrorTruncation": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,

// Modules
"module": "preserve",
"moduleResolution": "bundler",
"resolveJsonModule": true,

// Interop Constraints
"esModuleInterop": true,
"isolatedModules": true,
// @todo flip to true once package.json declares `"type": "module"`.
"verbatimModuleSyntax": false,

// Language and Environment
"jsx": "react-jsx",
"lib": [ "ES2022", "DOM.Iterable", "DOM" ],
"moduleDetection": "force",
"target": "ES2022",

// Completeness
"skipLibCheck": true,

// Project-specific
"noEmit": true,
"paths": {
"@/*": [ "./src/*" ]
},
// Jest globals stay out of src/; tests get their own tsconfig once they migrate.
"types": [ "node" ]
},
"include": [
"src/**/*",
"tests/**/*",
"webpack.config.js",
"webpack.blocks.config.js",
"babel.config.js"
],
"exclude": [
"node_modules",
"vendor",
"assets/build",
"build",
"bin"
]
}
4 changes: 2 additions & 2 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,10 +530,10 @@ const scripts = {
],
};

// Component JS entry points from src/components/{component}/{component}.js.
// Component script entry points from src/components/{component}/{component}.{js,jsx,ts,tsx}.
const componentScripts = {
...sharedNonHotConfig,
entry: () => getComponentEntries( COMPONENTS_DIR, /\.js$/ ),
entry: () => getComponentEntries( COMPONENTS_DIR, /\.(jsx?|tsx?)$/ ),
Comment thread
pratik-londhe4 marked this conversation as resolved.
plugins: [
...sharedNonHotConfig.plugins.filter( isNotPlugin( 'RtlCssPlugin' ) ),
],
Expand Down