From d0e28c6674287caeeef341f1f355e53d152fcf37 Mon Sep 17 00:00:00 2001 From: Victor Genaev Date: Wed, 23 Oct 2024 17:37:56 +0200 Subject: [PATCH 1/5] chore: upgrade to typescript-eslint v8 (#32369) Co-authored-by: Martin Hochel --- ...-9708d729-ebb2-44cd-8fe1-30cf46fc403d.json | 7 + ...-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json | 7 + package.json | 12 +- packages/eslint-plugin/package.json | 14 +- .../src/rules/ban-context-export/index.js | 1 - .../rules/ban-context-export/index.test.js | 33 ++-- .../ban-instanceof-html-element/index.js | 2 - .../ban-instanceof-html-element/index.test.js | 4 +- .../rules/deprecated-keyboard-event-props.js | 9 +- .../no-context-default-value/index.test.js | 4 +- .../src/rules/no-global-react.js | 1 - .../rules/no-restricted-imports/index.test.js | 4 +- .../src/rules/no-tslint-comments.js | 1 - .../ComponentSourceManager.ts | 3 +- .../getExampleModule.ts | 2 +- .../context-selector/useContextSelector.ts | 2 +- .../context-selector/useContextSelectors.ts | 2 +- .../react-bindings/src/utils/getWindow.ts | 2 +- .../react-builder/src/utils/treeStore.ts | 2 +- .../src/utils/fontSizeUtility.ts | 2 +- .../test/specs/commonTests/isConformant.tsx | 10 +- .../test/utils/assertNodeContains.ts | 2 +- packages/web-components/.eslintrc.json | 2 + tools/eslint-rules/jest.config.ts | 1 + .../rules/consistent-callback-type.ts | 3 +- .../rules/no-missing-jsx-pragma.spec.ts | 3 +- .../rules/no-missing-jsx-pragma.ts | 3 +- .../rules/no-restricted-globals.spec.ts | 8 +- .../rules/no-restricted-globals.ts | 6 +- tools/workspace-plugin/jest.config.ts | 1 + yarn.lock | 177 ++++++++---------- 31 files changed, 162 insertions(+), 168 deletions(-) create mode 100644 change/@fluentui-eslint-plugin-9708d729-ebb2-44cd-8fe1-30cf46fc403d.json create mode 100644 change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json diff --git a/change/@fluentui-eslint-plugin-9708d729-ebb2-44cd-8fe1-30cf46fc403d.json b/change/@fluentui-eslint-plugin-9708d729-ebb2-44cd-8fe1-30cf46fc403d.json new file mode 100644 index 00000000000000..8fd0ec90c6f91d --- /dev/null +++ b/change/@fluentui-eslint-plugin-9708d729-ebb2-44cd-8fe1-30cf46fc403d.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: bump minimal typescript version to 4.8.4", + "packageName": "@fluentui/eslint-plugin", + "email": "vgenaev@gmail.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json b/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json new file mode 100644 index 00000000000000..c53be7ff1e9396 --- /dev/null +++ b/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "resolve eslint errors after upgrade to typescript-eslint v8", + "packageName": "@fluentui/web-components", + "email": "vgenaev@gmail.com", + "dependentChangeType": "none" +} diff --git a/package.json b/package.json index 529e8bb606a790..18cdbba8782a4a 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "@phenomnomnominal/tsquery": "6.1.3", "@playwright/test": "1.44.0", "@react-native/babel-preset": "0.73.21", - "@rnx-kit/eslint-plugin": "0.7.2", + "@rnx-kit/eslint-plugin": "0.8.2", "@rollup/plugin-node-resolve": "13.3.0", "@storybook/addon-a11y": "7.6.20", "@storybook/addon-actions": "7.6.20", @@ -173,10 +173,10 @@ "@types/webpack-hot-middleware": "2.25.9", "@types/yargs": "13.0.11", "@types/yargs-unparser": "2.0.1", - "@typescript-eslint/eslint-plugin": "7.18.0", - "@typescript-eslint/parser": "7.18.0", - "@typescript-eslint/rule-tester": "7.18.0", - "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/eslint-plugin": "8.8.1", + "@typescript-eslint/parser": "8.8.1", + "@typescript-eslint/rule-tester": "8.8.1", + "@typescript-eslint/utils": "8.8.1", "@wojtekmaj/enzyme-adapter-react-17": "0.6.7", "ajv": "8.4.0", "autoprefixer": "10.2.1", @@ -233,7 +233,7 @@ "eslint-plugin-deprecation": "3.0.0", "eslint-plugin-es": "4.1.0", "eslint-plugin-import": "2.29.1", - "eslint-plugin-jest": "28.6.0", + "eslint-plugin-jest": "28.8.0", "eslint-plugin-jsdoc": "48.7.0", "eslint-plugin-jsx-a11y": "6.9.0", "eslint-plugin-playwright": "0.15.3", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index cccec7da257868..ba621af46a4ca6 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -15,12 +15,12 @@ }, "dependencies": { "@griffel/eslint-plugin": "^1.6.4", - "@rnx-kit/eslint-plugin": "^0.7.2", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/utils": "^7.18.0", - "@typescript-eslint/rule-tester": "7.18.0", - "@typescript-eslint/parser": "^7.18.0", - "@typescript-eslint/type-utils": "^7.18.0", + "@rnx-kit/eslint-plugin": "^0.8.2", + "@typescript-eslint/eslint-plugin": "^8.8.1", + "@typescript-eslint/utils": "^8.8.1", + "@typescript-eslint/rule-tester": "8.8.1", + "@typescript-eslint/parser": "^8.8.1", + "@typescript-eslint/type-utils": "^8.8.1", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^8.3.0", "eslint-import-resolver-typescript": "^3.6.1", @@ -37,7 +37,7 @@ }, "peerDependencies": { "eslint": "^8.0.0", - "typescript": "^4.7.5" + "typescript": "^4.8.4" }, "files": [ "src" diff --git a/packages/eslint-plugin/src/rules/ban-context-export/index.js b/packages/eslint-plugin/src/rules/ban-context-export/index.js index 81cde74b5fa5a5..a81dda19c9b7d3 100644 --- a/packages/eslint-plugin/src/rules/ban-context-export/index.js +++ b/packages/eslint-plugin/src/rules/ban-context-export/index.js @@ -35,7 +35,6 @@ module.exports = createRule({ type: 'problem', docs: { description: 'Ban export of React context or context selector objects', - recommended: 'recommended', }, messages: { nativeContext: '{{exportName}} should not be exported directly', diff --git a/packages/eslint-plugin/src/rules/ban-context-export/index.test.js b/packages/eslint-plugin/src/rules/ban-context-export/index.test.js index 099eec01b1fa5f..9f0f3273acd58e 100644 --- a/packages/eslint-plugin/src/rules/ban-context-export/index.test.js +++ b/packages/eslint-plugin/src/rules/ban-context-export/index.test.js @@ -3,35 +3,32 @@ const { RuleTester } = require('@typescript-eslint/rule-tester'); const path = require('path'); const rule = require('./index'); -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', - parserOptions: { - project: path.resolve(__dirname, './fixtures/ban-context-export/tsconfig.json'), - tsconfigRootDir: path.resolve(__dirname, './fixtures/ban-context-export'), - }, -}); +const ruleTester = new RuleTester(); /** * @param {string} fixtureName */ -function getParserOptions(fixtureName) { +function getLanguageOptions(fixtureName) { return { - project: path.resolve(__dirname, `./fixtures/${fixtureName}/tsconfig.json`), - tsconfigRootDir: path.resolve(__dirname, `./fixtures/${fixtureName}`), + parserOptions: { + parser: '@typescript-eslint/parser', + project: path.resolve(__dirname, `./fixtures/${fixtureName}/tsconfig.json`), + tsconfigRootDir: path.resolve(__dirname, `./fixtures/${fixtureName}`), + }, }; } ruleTester.run('ban-context-export', rule, { valid: [ { - parserOptions: getParserOptions('internal-export'), + languageOptions: getLanguageOptions('internal-export'), code: ` export { MyContext } from './context' `, filename: 'src/internal/index.ts', }, { - parserOptions: getParserOptions('not-a-context'), + languageOptions: getLanguageOptions('not-a-context'), code: ` export { MyContext } from './context' `, @@ -39,7 +36,7 @@ ruleTester.run('ban-context-export', rule, { }, { options: [{ exclude: ['**/special-path/**/*'] }], - parserOptions: getParserOptions('exclude'), + languageOptions: getLanguageOptions('exclude'), code: ` import * as React from 'react'; export const MyContext = React.createContext({}); @@ -50,7 +47,7 @@ ruleTester.run('ban-context-export', rule, { invalid: [ { errors: [{ messageId: 'nativeContext' }], - parserOptions: getParserOptions('export-specifier'), + languageOptions: getLanguageOptions('export-specifier'), code: ` export { MyContext } from './context' `, @@ -58,7 +55,7 @@ ruleTester.run('ban-context-export', rule, { }, { errors: [{ messageId: 'contextSelector' }], - parserOptions: getParserOptions('context-selector'), + languageOptions: getLanguageOptions('context-selector'), code: ` export { MyContext } from './context' `, @@ -66,7 +63,7 @@ ruleTester.run('ban-context-export', rule, { }, { errors: [{ messageId: 'nativeContext' }], - parserOptions: getParserOptions('named-export'), + languageOptions: getLanguageOptions('named-export'), code: ` import * as React from 'react'; export const MyContext = React.createContext({}); @@ -75,7 +72,7 @@ ruleTester.run('ban-context-export', rule, { }, { errors: [{ messageId: 'contextSelector' }], - parserOptions: getParserOptions('named-export'), + languageOptions: getLanguageOptions('named-export'), code: ` import { createContext } from '@proj/react-context-selector'; export const MyContext = createContext({}); @@ -85,7 +82,7 @@ ruleTester.run('ban-context-export', rule, { { errors: [{ messageId: 'nativeContext' }], options: [{ exclude: ['**/wrong-path/**/*'] }], - parserOptions: getParserOptions('exclude'), + languageOptions: getLanguageOptions('exclude'), code: ` import * as React from 'react'; export const MyContext = React.createContext({}); diff --git a/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.js b/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.js index 49277fb01e1ef6..ca22c6f9cda71b 100644 --- a/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.js +++ b/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.js @@ -4,7 +4,6 @@ const createRule = require('../../utils/createRule'); /** * @typedef {import('./types').HTMLElementConstructorName} HTMLElementConstructorName - * */ module.exports = createRule({ @@ -13,7 +12,6 @@ module.exports = createRule({ type: 'problem', docs: { description: 'Ban usage of instanceof HTMLElement comparison', - recommended: 'recommended', }, messages: { invalidBinaryExpression: 'instanceof {{right}} should be avoided, use isHTMLElement instead.', diff --git a/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.test.js b/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.test.js index 64bd9f936ace70..aaf940a64751fd 100644 --- a/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.test.js +++ b/packages/eslint-plugin/src/rules/ban-instanceof-html-element/index.test.js @@ -1,9 +1,7 @@ const { RuleTester } = require('@typescript-eslint/rule-tester'); const rule = require('./index'); -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); +const ruleTester = new RuleTester(); ruleTester.run('ban-instanceof-htmlelement', rule, { valid: [ diff --git a/packages/eslint-plugin/src/rules/deprecated-keyboard-event-props.js b/packages/eslint-plugin/src/rules/deprecated-keyboard-event-props.js index 5cc050c109de4a..30fa88473a8735 100644 --- a/packages/eslint-plugin/src/rules/deprecated-keyboard-event-props.js +++ b/packages/eslint-plugin/src/rules/deprecated-keyboard-event-props.js @@ -2,15 +2,18 @@ const createRule = require('../utils/createRule'); const { ESLintUtils } = require('@typescript-eslint/utils'); +/** + * @typedef { import('@typescript-eslint/utils').TSESLint.RuleMetaDataDocs} RuleMetaDataDocs + */ + module.exports = createRule({ name: 'deprecated-keyboard-event-props', meta: { type: 'problem', - docs: { + docs: /** @type {RuleMetaDataDocs} */ ({ description: 'Forbid use of deprecated KeyboardEvent props "which" and "keyCode".', - recommended: 'recommended', requiresTypeChecking: true, - }, + }), messages: { deprecatedProp: 'KeyboardEvent prop "{{name}}" is deprecated (consider using @fluentui/keyboard-key instead)', }, diff --git a/packages/eslint-plugin/src/rules/no-context-default-value/index.test.js b/packages/eslint-plugin/src/rules/no-context-default-value/index.test.js index 3181028e03381b..47ee4b7103b933 100644 --- a/packages/eslint-plugin/src/rules/no-context-default-value/index.test.js +++ b/packages/eslint-plugin/src/rules/no-context-default-value/index.test.js @@ -1,9 +1,7 @@ const { RuleTester } = require('@typescript-eslint/rule-tester'); const rule = require('./index'); -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); +const ruleTester = new RuleTester(); ruleTester.run('no-context-default-value', rule, { valid: [ diff --git a/packages/eslint-plugin/src/rules/no-global-react.js b/packages/eslint-plugin/src/rules/no-global-react.js index c32c5645698763..9fcec153bed0a2 100644 --- a/packages/eslint-plugin/src/rules/no-global-react.js +++ b/packages/eslint-plugin/src/rules/no-global-react.js @@ -8,7 +8,6 @@ module.exports = createRule({ type: 'problem', docs: { description: 'Prevent accidental references to the global React namespace', - recommended: 'recommended', }, messages: { missingImport: 'You must explicitly import React to reference it', diff --git a/packages/eslint-plugin/src/rules/no-restricted-imports/index.test.js b/packages/eslint-plugin/src/rules/no-restricted-imports/index.test.js index 5d07ee450f1e64..ce4abf4a2c08d3 100644 --- a/packages/eslint-plugin/src/rules/no-restricted-imports/index.test.js +++ b/packages/eslint-plugin/src/rules/no-restricted-imports/index.test.js @@ -1,9 +1,7 @@ const { RuleTester } = require('@typescript-eslint/rule-tester'); const rule = require('./index'); -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); +const ruleTester = new RuleTester(); ruleTester.run('no-restricted-imports', rule, { valid: [ diff --git a/packages/eslint-plugin/src/rules/no-tslint-comments.js b/packages/eslint-plugin/src/rules/no-tslint-comments.js index 4e943f8bcf361e..d0afa2877e86de 100644 --- a/packages/eslint-plugin/src/rules/no-tslint-comments.js +++ b/packages/eslint-plugin/src/rules/no-tslint-comments.js @@ -7,7 +7,6 @@ module.exports = createRule({ type: 'problem', docs: { description: 'Forbid tslint:disable/tslint:enable comments after ESLint migration.', - recommended: 'recommended', }, messages: { tslint: 'tslint:{{verb}} comments are unnecessary with ESLint', diff --git a/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/ComponentSourceManager.ts b/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/ComponentSourceManager.ts index b25f857f499f1e..a45c9a584c5ef9 100644 --- a/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/ComponentSourceManager.ts +++ b/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/ComponentSourceManager.ts @@ -121,9 +121,8 @@ export default class ComponentSourceManager extends React.Component< try { const formattedCode = prettifyCode(currentCode, prettierParser); - this.setState({ currentCode: formattedCode, formattedCode }); - } catch (e) {} + } catch {} }; handleCodeReset = (): void => { diff --git a/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/getExampleModule.ts b/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/getExampleModule.ts index 018cf7ae0bdc70..a62e91fd47d83b 100644 --- a/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/getExampleModule.ts +++ b/packages/fluentui/docs/src/components/ComponentDoc/ComponentSourceManager/getExampleModule.ts @@ -26,7 +26,7 @@ const getExampleModule = ( namedExports: examplesContext(modulePath), source: exampleSourcesContext(sourcePath), }; - } catch (e) { + } catch { return null; } }; diff --git a/packages/fluentui/react-bindings/src/context-selector/useContextSelector.ts b/packages/fluentui/react-bindings/src/context-selector/useContextSelector.ts index d20bc546c182be..bb385c359d6ea9 100644 --- a/packages/fluentui/react-bindings/src/context-selector/useContextSelector.ts +++ b/packages/fluentui/react-bindings/src/context-selector/useContextSelector.ts @@ -53,7 +53,7 @@ export const useContextSelector = ( } return [payload[1], nextSelected] as const; - } catch (e) { + } catch { // ignored (stale props or some other reason) } return [...prevState] as const; // schedule update diff --git a/packages/fluentui/react-bindings/src/context-selector/useContextSelectors.ts b/packages/fluentui/react-bindings/src/context-selector/useContextSelectors.ts index 1dc7139df1c1f4..73ee8d428621d3 100644 --- a/packages/fluentui/react-bindings/src/context-selector/useContextSelectors.ts +++ b/packages/fluentui/react-bindings/src/context-selector/useContextSelectors.ts @@ -79,7 +79,7 @@ export const useContextSelectors = < } return [payload[1], nextSelected] as const; - } catch (e) { + } catch { // ignored (stale props or some other reason) } return [...prevState] as const; // schedule update diff --git a/packages/fluentui/react-bindings/src/utils/getWindow.ts b/packages/fluentui/react-bindings/src/utils/getWindow.ts index 62ce6b0438ee0b..209e62c241d77a 100644 --- a/packages/fluentui/react-bindings/src/utils/getWindow.ts +++ b/packages/fluentui/react-bindings/src/utils/getWindow.ts @@ -5,7 +5,7 @@ let _window: Window | undefined = undefined; // Caching the window value at the file scope lets us minimize the impact. try { _window = window; -} catch (e) { +} catch { /* no-op */ } diff --git a/packages/fluentui/react-builder/src/utils/treeStore.ts b/packages/fluentui/react-builder/src/utils/treeStore.ts index 44e05a8e335f53..3efd73fb0c86e3 100644 --- a/packages/fluentui/react-builder/src/utils/treeStore.ts +++ b/packages/fluentui/react-builder/src/utils/treeStore.ts @@ -37,7 +37,7 @@ export const readTreeFromURL = (url: string): JSONTreeElement | null => { } try { return treeParse(treeString); - } catch (e) { + } catch { // TODO: client should know it failed return null; } diff --git a/packages/fluentui/react-northstar/src/utils/fontSizeUtility.ts b/packages/fluentui/react-northstar/src/utils/fontSizeUtility.ts index 73b3de0f5b29f4..931181647884a7 100644 --- a/packages/fluentui/react-northstar/src/utils/fontSizeUtility.ts +++ b/packages/fluentui/react-northstar/src/utils/fontSizeUtility.ts @@ -9,7 +9,7 @@ export const getDocumentRemSize = (): number => { try { // eslint-disable-next-line no-undef return getFontSizeValue(getComputedStyle(document.documentElement).fontSize) || DEFAULT_REM_SIZE_IN_PX; - } catch (e) { + } catch { return DEFAULT_REM_SIZE_IN_PX; } } diff --git a/packages/fluentui/react-northstar/test/specs/commonTests/isConformant.tsx b/packages/fluentui/react-northstar/test/specs/commonTests/isConformant.tsx index 02166f50b9b9cd..b7849d6e416fe0 100644 --- a/packages/fluentui/react-northstar/test/specs/commonTests/isConformant.tsx +++ b/packages/fluentui/react-northstar/test/specs/commonTests/isConformant.tsx @@ -153,7 +153,7 @@ export function isConformant( const component = getComponent(wrapper); try { expect(component.is(tag)).toEqual(true); - } catch (err) { + } catch { expect(component.type()).not.toEqual(Component); expect(component.prop('as')).toEqual(tag); } @@ -169,7 +169,7 @@ export function isConformant( try { expect(component.type()).toEqual(MyComponent); - } catch (err) { + } catch { expect(component.type()).not.toEqual(Component); expect(component.find('[as]').last().prop('as')).toEqual(MyComponent); } @@ -187,7 +187,7 @@ export function isConformant( try { expect(component.type()).toEqual(MyComponent); - } catch (err) { + } catch { expect(component.type()).not.toEqual(Component); expect(component.prop('as')).toEqual(MyComponent); } @@ -390,7 +390,7 @@ export function isConformant( try { expect(handlerSpy).toHaveBeenCalled(); - } catch (err) { + } catch { throw new Error( [ `<${constructorName} ${listenerName}={${handlerName}} />\n`, @@ -422,7 +422,7 @@ export function isConformant( expectedArgs.forEach((expectedArg, argI) => { expect(lastHandlerCall[argI]).toEqual(expectedArg); }); - } catch (err) { + } catch { throw new Error( [ `<${constructorName} ${listenerName}={${handlerName}} />\n`, diff --git a/packages/fluentui/react-northstar/test/utils/assertNodeContains.ts b/packages/fluentui/react-northstar/test/utils/assertNodeContains.ts index a885ab133c3bc7..29613c5723e819 100644 --- a/packages/fluentui/react-northstar/test/utils/assertNodeContains.ts +++ b/packages/fluentui/react-northstar/test/utils/assertNodeContains.ts @@ -9,7 +9,7 @@ export const assertNodeContains = (parentNode: Element, childSelector: string, i const didFind = parentNode.querySelector(childSelector) !== null; try { expect(didFind).toEqual(isPresent); - } catch (err) { + } catch { throw new Error(`${didFind ? 'Found' : 'Did not find'} "${childSelector}" in the ${parentNode}.`); } }; diff --git a/packages/web-components/.eslintrc.json b/packages/web-components/.eslintrc.json index c96b794360cfd5..3d5876196e9baa 100644 --- a/packages/web-components/.eslintrc.json +++ b/packages/web-components/.eslintrc.json @@ -38,6 +38,7 @@ "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-empty-interface": "error", + "@typescript-eslint/no-empty-object-type": "off", "@typescript-eslint/no-unsafe-declaration-merging": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/explicit-function-return-type": "off", @@ -49,6 +50,7 @@ "args": "none" } ], + "@typescript-eslint/no-unused-expressions": "warn", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/naming-convention": [ "error", diff --git a/tools/eslint-rules/jest.config.ts b/tools/eslint-rules/jest.config.ts index 7b931b87d5b9a4..413d6be004292e 100644 --- a/tools/eslint-rules/jest.config.ts +++ b/tools/eslint-rules/jest.config.ts @@ -2,6 +2,7 @@ export default { displayName: 'eslint-rules', preset: '../../jest.preset.js', + testEnvironment: 'node', transform: { '^.+\\.[tj]s$': ['@swc/jest', {}], }, diff --git a/tools/eslint-rules/rules/consistent-callback-type.ts b/tools/eslint-rules/rules/consistent-callback-type.ts index 963924de5ffcd8..20f012ef6d3ea3 100644 --- a/tools/eslint-rules/rules/consistent-callback-type.ts +++ b/tools/eslint-rules/rules/consistent-callback-type.ts @@ -9,7 +9,6 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ type: 'problem', docs: { description: 'Enforce callback props to be typed with `EventHandler`', - recommended: 'recommended', }, messages: { invalidType: 'callback props should be typed with @fluentui/react-utilities#EventHandler', @@ -41,7 +40,7 @@ export const rule = ESLintUtils.RuleCreator(() => __filename)({ typeAnnotation.type === AST_NODE_TYPES.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier && typeAnnotation.typeName.name === 'EventHandler' && - typeAnnotation.typeParameters + typeAnnotation.typeArguments ) ) { context.report({ diff --git a/tools/eslint-rules/rules/no-missing-jsx-pragma.spec.ts b/tools/eslint-rules/rules/no-missing-jsx-pragma.spec.ts index 610325520ea177..5c2aa488910135 100644 --- a/tools/eslint-rules/rules/no-missing-jsx-pragma.spec.ts +++ b/tools/eslint-rules/rules/no-missing-jsx-pragma.spec.ts @@ -2,8 +2,7 @@ import { RuleTester } from '@typescript-eslint/rule-tester'; import { rule, RULE_NAME } from './no-missing-jsx-pragma'; const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', - parserOptions: { ecmaFeatures: { jsx: true } }, + languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }, }); ruleTester.run(RULE_NAME, rule, { diff --git a/tools/eslint-rules/rules/no-missing-jsx-pragma.ts b/tools/eslint-rules/rules/no-missing-jsx-pragma.ts index da0c14195c7a6c..64425000c74dc0 100644 --- a/tools/eslint-rules/rules/no-missing-jsx-pragma.ts +++ b/tools/eslint-rules/rules/no-missing-jsx-pragma.ts @@ -14,7 +14,7 @@ * https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin/src/rules */ -import { ESLintUtils, AST_NODE_TYPES, AST_TOKEN_TYPES, ASTUtils, TSESTree } from '@typescript-eslint/utils'; +import { ESLintUtils, AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree } from '@typescript-eslint/utils'; // NOTE: The rule will be available in ESLint configs as "@nx/workspace-no-missing-jsx-pragma" export const RULE_NAME = 'no-missing-jsx-pragma'; @@ -34,7 +34,6 @@ export const rule = ESLintUtils.RuleCreator(() => __filename) __filename) __filename)/jest-setup.js'], + testEnvironment: 'node', } as import('@jest/types').Config.InitialOptions; diff --git a/yarn.lock b/yarn.lock index f2493826270244..abf6381e4c79dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1867,7 +1867,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0", "@eslint/js@^8.56.0": +"@eslint/js@8.57.0": version "8.57.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== @@ -3583,23 +3583,22 @@ mkdirp "^0.5.1" nullthrows "^1.1.1" -"@react-native/eslint-plugin@^0.74.0": - version "0.74.85" - resolved "https://registry.yarnpkg.com/@react-native/eslint-plugin/-/eslint-plugin-0.74.85.tgz#9e028ccf97ad6d3d661d796eb614951343be5a1f" - integrity sha512-FtyfgL8EOTddxm+DyjfsInqMtjmU0PWQIRdyET/uob8i6sCxS+HmBzhbtEVZUKwld2kNG1JGgdNLndcEejC81Q== +"@react-native/eslint-plugin@^0.75.0": + version "0.75.4" + resolved "https://registry.yarnpkg.com/@react-native/eslint-plugin/-/eslint-plugin-0.75.4.tgz#41fa462206e2fd4aea6a27fb0d7660161c6af6b3" + integrity sha512-1kEZzC8UKi3baHnH7tBVCNpF4aoAmT7g7hEa5/rtZ+Z7vcpaxeY6wjNYt3j02Z9n310yX0NKDJox30CqvzEvsg== -"@rnx-kit/eslint-plugin@0.7.2", "@rnx-kit/eslint-plugin@^0.7.2": - version "0.7.2" - resolved "https://registry.yarnpkg.com/@rnx-kit/eslint-plugin/-/eslint-plugin-0.7.2.tgz#be6164db3ca5b8b1782700c8b1d085cb8008e0bc" - integrity sha512-vOwLddSi4lJuGHOQf88iGub44wRFlwmpScx/G6mWoJ/MdWcuN142x6PPyZNIsB2bHQxdbhTnWqXE5JZgfXiSvQ== +"@rnx-kit/eslint-plugin@0.8.2", "@rnx-kit/eslint-plugin@^0.8.2": + version "0.8.2" + resolved "https://registry.yarnpkg.com/@rnx-kit/eslint-plugin/-/eslint-plugin-0.8.2.tgz#693cb08b4b483f2992c31a9cd6fac86f9f32969c" + integrity sha512-WRBS3U9vkZfhJayglotH+4YKj5mBfMMwVDIJmDeGvOm12KtwN/Q9epriKQyY5P40m/OByChw2UriLYngn/u/MQ== dependencies: "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "^8.56.0" - "@react-native/eslint-plugin" "^0.74.0" + "@react-native/eslint-plugin" "^0.75.0" enhanced-resolve "^5.8.3" eslint-plugin-react "^7.33.0" eslint-plugin-react-hooks "^4.6.0" - typescript-eslint "^7.5.0" + typescript-eslint "^8.0.0" "@rollup/plugin-node-resolve@13.3.0": version "13.3.0" @@ -5961,39 +5960,39 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@7.18.0", "@typescript-eslint/eslint-plugin@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz#b16d3cf3ee76bf572fdf511e79c248bdec619ea3" - integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== +"@typescript-eslint/eslint-plugin@8.8.1", "@typescript-eslint/eslint-plugin@^8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371" + integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.18.0" - "@typescript-eslint/type-utils" "7.18.0" - "@typescript-eslint/utils" "7.18.0" - "@typescript-eslint/visitor-keys" "7.18.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/type-utils" "8.8.1" + "@typescript-eslint/utils" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@7.18.0", "@typescript-eslint/parser@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.18.0.tgz#83928d0f1b7f4afa974098c64b5ce6f9051f96a0" - integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== +"@typescript-eslint/parser@8.8.1", "@typescript-eslint/parser@^8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8" + integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow== dependencies: - "@typescript-eslint/scope-manager" "7.18.0" - "@typescript-eslint/types" "7.18.0" - "@typescript-eslint/typescript-estree" "7.18.0" - "@typescript-eslint/visitor-keys" "7.18.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" debug "^4.3.4" -"@typescript-eslint/rule-tester@7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/rule-tester/-/rule-tester-7.18.0.tgz#1326101d6169dece15d91c0e96dc52e350d8c714" - integrity sha512-ClrFQlwen9pJcYPIBLuarzBpONQAwjmJ0+YUjAo1TGzoZFJPyUK/A7bb4Mps0u+SMJJnFXbfMN8I9feQDf0O5A== +"@typescript-eslint/rule-tester@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/rule-tester/-/rule-tester-8.8.1.tgz#9be928091917294f260a80178e1141f3acc13a38" + integrity sha512-79TdrU55nz5zroDIumNOpMC5I3fJkmzxAEkstz3nZ8P/xhcvwD35PUuk50l/cfvkdkYS4d4xZwf8iIamfoOzlg== dependencies: - "@typescript-eslint/typescript-estree" "7.18.0" - "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" ajv "^6.12.6" json-stable-stringify-without-jsonify "^1.0.1" lodash.merge "4.6.2" @@ -6007,31 +6006,21 @@ "@typescript-eslint/types" "7.18.0" "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/scope-manager@8.7.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz#90ee7bf9bc982b9260b93347c01a8bc2b595e0b8" - integrity sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg== - dependencies: - "@typescript-eslint/types" "8.7.0" - "@typescript-eslint/visitor-keys" "8.7.0" - -"@typescript-eslint/type-utils@7.18.0", "@typescript-eslint/type-utils@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" - integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== +"@typescript-eslint/scope-manager@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff" + integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA== dependencies: - "@typescript-eslint/typescript-estree" "7.18.0" - "@typescript-eslint/utils" "7.18.0" - debug "^4.3.4" - ts-api-utils "^1.3.0" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" -"@typescript-eslint/type-utils@^8.0.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz#d56b104183bdcffcc434a23d1ce26cde5e42df93" - integrity sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ== +"@typescript-eslint/type-utils@8.8.1", "@typescript-eslint/type-utils@^8.0.0", "@typescript-eslint/type-utils@^8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e" + integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA== dependencies: - "@typescript-eslint/typescript-estree" "8.7.0" - "@typescript-eslint/utils" "8.7.0" + "@typescript-eslint/typescript-estree" "8.8.1" + "@typescript-eslint/utils" "8.8.1" debug "^4.3.4" ts-api-utils "^1.3.0" @@ -6040,10 +6029,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== -"@typescript-eslint/types@8.7.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.7.0.tgz#21d987201c07b69ce7ddc03451d7196e5445ad19" - integrity sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w== +"@typescript-eslint/types@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1" + integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q== "@typescript-eslint/typescript-estree@7.18.0": version "7.18.0" @@ -6059,13 +6048,13 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/typescript-estree@8.7.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz#6c7db6baa4380b937fa81466c546d052f362d0e8" - integrity sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg== +"@typescript-eslint/typescript-estree@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec" + integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg== dependencies: - "@typescript-eslint/types" "8.7.0" - "@typescript-eslint/visitor-keys" "8.7.0" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/visitor-keys" "8.8.1" debug "^4.3.4" fast-glob "^3.3.2" is-glob "^4.0.3" @@ -6073,7 +6062,17 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.18.0", "@typescript-eslint/utils@^6.0.0 || ^7.0.0", "@typescript-eslint/utils@^7.0.0", "@typescript-eslint/utils@^7.18.0", "@typescript-eslint/utils@^7.9.0": +"@typescript-eslint/utils@8.8.1", "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0", "@typescript-eslint/utils@^8.0.0", "@typescript-eslint/utils@^8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d" + integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.8.1" + "@typescript-eslint/types" "8.8.1" + "@typescript-eslint/typescript-estree" "8.8.1" + +"@typescript-eslint/utils@^7.0.0", "@typescript-eslint/utils@^7.9.0": version "7.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== @@ -6083,16 +6082,6 @@ "@typescript-eslint/types" "7.18.0" "@typescript-eslint/typescript-estree" "7.18.0" -"@typescript-eslint/utils@8.7.0", "@typescript-eslint/utils@^8.0.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.7.0.tgz#cef3f70708b5b5fd7ed8672fc14714472bd8a011" - integrity sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.7.0" - "@typescript-eslint/types" "8.7.0" - "@typescript-eslint/typescript-estree" "8.7.0" - "@typescript-eslint/visitor-keys@7.18.0": version "7.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" @@ -6101,12 +6090,12 @@ "@typescript-eslint/types" "7.18.0" eslint-visitor-keys "^3.4.3" -"@typescript-eslint/visitor-keys@8.7.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz#5e46f1777f9d69360a883c1a56ac3c511c9659a8" - integrity sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ== +"@typescript-eslint/visitor-keys@8.8.1": + version "8.8.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5" + integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag== dependencies: - "@typescript-eslint/types" "8.7.0" + "@typescript-eslint/types" "8.8.1" eslint-visitor-keys "^3.4.3" "@uifabric/set-version@^7.0.23": @@ -10824,12 +10813,12 @@ eslint-plugin-import@2.29.1, eslint-plugin-import@^2.29.1: semver "^6.3.1" tsconfig-paths "^3.15.0" -eslint-plugin-jest@28.6.0, eslint-plugin-jest@^28.6.0: - version "28.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.6.0.tgz#8410588d60bcafa68a91b6ec272e4a415502302a" - integrity sha512-YG28E1/MIKwnz+e2H7VwYPzHUYU4aMa19w0yGcwXnnmJH6EfgHahTJ2un3IyraUxNfnz/KUhJAFXNNwWPo12tg== +eslint-plugin-jest@28.8.0, eslint-plugin-jest@^28.6.0: + version "28.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz#54f597b5a3295ad04ec946baa245ad02b9b2bca0" + integrity sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw== dependencies: - "@typescript-eslint/utils" "^6.0.0 || ^7.0.0" + "@typescript-eslint/utils" "^6.0.0 || ^7.0.0 || ^8.0.0" eslint-plugin-jsdoc@48.7.0, eslint-plugin-jsdoc@^48.7.0: version "48.7.0" @@ -22744,14 +22733,14 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript-eslint@^7.5.0: - version "7.18.0" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-7.18.0.tgz#e90d57649b2ad37a7475875fa3e834a6d9f61eb2" - integrity sha512-PonBkP603E3tt05lDkbOMyaxJjvKqQrXsnow72sVeOFINDE/qNmnnd+f9b4N+U7W6MXnnYyrhtmF2t08QWwUbA== +typescript-eslint@^8.0.0: + version "8.8.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a" + integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ== dependencies: - "@typescript-eslint/eslint-plugin" "7.18.0" - "@typescript-eslint/parser" "7.18.0" - "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/eslint-plugin" "8.8.1" + "@typescript-eslint/parser" "8.8.1" + "@typescript-eslint/utils" "8.8.1" typescript@5.0.4, typescript@~5.0.4: version "5.0.4" From 6baf51f49c4aa3e62447b770fb963059d60e505b Mon Sep 17 00:00:00 2001 From: ling1726 Date: Wed, 23 Oct 2024 18:35:33 +0200 Subject: [PATCH 2/5] fix: subtle selection should apply correctly to header rows (#33104) --- .../Table/TableSubtleSelection.stories.tsx | 16 +++++++-- .../src/stories/Table/utils.tsx | 35 +++++++++++++++++++ ...-f769575c-0588-4c39-b82a-b20389b9638a.json | 7 ++++ .../TableRow/useTableRowStyles.styles.ts | 34 +++++++++++------- .../useTableSelectionCell.tsx | 5 +-- 5 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 change/@fluentui-react-table-f769575c-0588-4c39-b82a-b20389b9638a.json diff --git a/apps/vr-tests-react-components/src/stories/Table/TableSubtleSelection.stories.tsx b/apps/vr-tests-react-components/src/stories/Table/TableSubtleSelection.stories.tsx index 8c9c5d0d6da4cf..c15a696da11793 100644 --- a/apps/vr-tests-react-components/src/stories/Table/TableSubtleSelection.stories.tsx +++ b/apps/vr-tests-react-components/src/stories/Table/TableSubtleSelection.stories.tsx @@ -1,17 +1,27 @@ import * as React from 'react'; import type { Meta } from '@storybook/react'; -import { Table } from '@fluentui/react-table'; +import { Table, tableHeaderClassNames } from '@fluentui/react-table'; import { Steps } from 'storywright'; import { withStoryWrightSteps } from '../../utilities'; -import { SubtleSelection } from './utils'; +import { SubtleSelection, SubtleSelectionEmpty } from './utils'; export default { title: 'Table table - subtle selection', decorators: [ story => - withStoryWrightSteps({ story, steps: new Steps().hover('.not-selected').snapshot('hover unselected row').end() }), + withStoryWrightSteps({ + story, + steps: new Steps() + .hover('.not-selected') + .snapshot('hover unselected row') + .hover(`.${tableHeaderClassNames.root}`) + .snapshot('hover header row') + .end(), + }), ], } satisfies Meta; export const Rest = () => ; Rest.storyName = 'rest'; + +export const NoSelection = () => ; diff --git a/apps/vr-tests-react-components/src/stories/Table/utils.tsx b/apps/vr-tests-react-components/src/stories/Table/utils.tsx index 5f392907510f94..ea2ce154989936 100644 --- a/apps/vr-tests-react-components/src/stories/Table/utils.tsx +++ b/apps/vr-tests-react-components/src/stories/Table/utils.tsx @@ -639,6 +639,41 @@ export const SubtleSelection: React.FC = ({ noNativeElements } ); +export const SubtleSelectionEmpty: React.FC = ({ noNativeElements }) => ( + + + + + + + {items.map((item, i) => ( + + + + {item.file.label} + + + + } + > + {item.author.label} + + + {item.lastUpdated.label} + + {item.lastUpdate.label} + + + ))} + +
+); + export const Truncate: React.FC = ({ noNativeElements, truncate }) => ( diff --git a/change/@fluentui-react-table-f769575c-0588-4c39-b82a-b20389b9638a.json b/change/@fluentui-react-table-f769575c-0588-4c39-b82a-b20389b9638a.json new file mode 100644 index 00000000000000..1bd93b371d6aa5 --- /dev/null +++ b/change/@fluentui-react-table-f769575c-0588-4c39-b82a-b20389b9638a.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: subtle selection should apply correctly to header rows", + "packageName": "@fluentui/react-table", + "email": "lingfangao@hotmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-table/library/src/components/TableRow/useTableRowStyles.styles.ts b/packages/react-components/react-table/library/src/components/TableRow/useTableRowStyles.styles.ts index c53a612c57543d..6a0b771d46408d 100644 --- a/packages/react-components/react-table/library/src/components/TableRow/useTableRowStyles.styles.ts +++ b/packages/react-components/react-table/library/src/components/TableRow/useTableRowStyles.styles.ts @@ -31,33 +31,43 @@ const useStyles = makeStyles({ root: { color: tokens.colorNeutralForeground1, boxSizing: 'border-box', + ...createCustomFocusIndicatorStyle( + { outline: `2px solid ${tokens.colorStrokeFocus2}`, borderRadius: tokens.borderRadiusMedium }, + { selector: 'focus' }, + ), + }, + + rootSubtleSelection: { ...createCustomFocusIndicatorStyle( { [`& .${tableSelectionCellClassNames.root}`]: { opacity: 1, }, - [`& .${tableCellActionsClassNames.root}`]: { - opacity: 1, - }, }, { selector: 'focus-within' }, ), - ...createCustomFocusIndicatorStyle( - { outline: `2px solid ${tokens.colorStrokeFocus2}`, borderRadius: tokens.borderRadiusMedium }, - { selector: 'focus' }, - ), + ':hover': { + [`& .${tableSelectionCellClassNames.root}`]: { + opacity: 1, + }, + }, }, rootInteractive: { + ...createCustomFocusIndicatorStyle( + { + [`& .${tableCellActionsClassNames.root}`]: { + opacity: 1, + }, + }, + { selector: 'focus-within' }, + ), ':active': { backgroundColor: tokens.colorSubtleBackgroundPressed, color: tokens.colorNeutralForeground1Pressed, [`& .${tableCellActionsClassNames.root}`]: { opacity: 1, }, - [`& .${tableSelectionCellClassNames.root}`]: { - opacity: 1, - }, }, ':hover': { backgroundColor: tokens.colorSubtleBackgroundHover, @@ -65,9 +75,6 @@ const useStyles = makeStyles({ [`& .${tableCellActionsClassNames.root}`]: { opacity: 1, }, - [`& .${tableSelectionCellClassNames.root}`]: { - opacity: 1, - }, }, // High contrast styles '@media (forced-colors: active)': { @@ -142,6 +149,7 @@ export const useTableRowStyles_unstable = (state: TableRowState): TableRowState state.root.className = mergeClasses( tableRowClassNames.root, styles.root, + styles.rootSubtleSelection, !state.isHeaderRow && styles.rootInteractive, styles[state.size], state.noNativeElements ? layoutStyles.flex.root : layoutStyles.table.root, diff --git a/packages/react-components/react-table/library/src/components/TableSelectionCell/useTableSelectionCell.tsx b/packages/react-components/react-table/library/src/components/TableSelectionCell/useTableSelectionCell.tsx index 2ed177f1b8c450..d76634b1cb03d7 100644 --- a/packages/react-components/react-table/library/src/components/TableSelectionCell/useTableSelectionCell.tsx +++ b/packages/react-components/react-table/library/src/components/TableSelectionCell/useTableSelectionCell.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; -import { useId, slot } from '@fluentui/react-utilities'; +import { useId, slot, useMergedRefs } from '@fluentui/react-utilities'; import { Checkbox } from '@fluentui/react-checkbox'; import { Radio } from '@fluentui/react-radio'; import type { TableSelectionCellProps, TableSelectionCellState } from './TableSelectionCell.types'; import { useTableCell_unstable } from '../TableCell/useTableCell'; import { useTableContext } from '../../contexts/tableContext'; +import { useFocusWithin } from '@fluentui/react-tabster'; /** * Create the state required to render TableSelectionCell. @@ -19,7 +20,7 @@ export const useTableSelectionCell_unstable = ( props: TableSelectionCellProps, ref: React.Ref, ): TableSelectionCellState => { - const tableCellState = useTableCell_unstable(props, ref); + const tableCellState = useTableCell_unstable(props, useMergedRefs(ref, useFocusWithin())); const { noNativeElements } = useTableContext(); const { type = 'checkbox', From 02d0cc182656c56d770b1ad9058d89204c1476a3 Mon Sep 17 00:00:00 2001 From: Martin Hochel Date: Wed, 23 Oct 2024 19:21:46 +0200 Subject: [PATCH 3/5] feat(workspace-plugin): various executor fixes and inferred ws plugin configuration capabilities (#33098) Co-authored-by: Dmytro Kirpa --- .../src/executors/build/executor.spec.ts | 2 +- .../src/executors/build/lib/babel.ts | 1 + .../src/executors/build/lib/swc.ts | 25 +-- .../src/executors/build/schema.d.ts | 9 +- .../src/executors/build/schema.json | 9 +- .../executors/generate-api/executor.spec.ts | 4 +- .../src/executors/generate-api/executor.ts | 2 +- .../src/executors/type-check/executor.spec.ts | 6 +- .../src/executors/type-check/executor.ts | 2 +- .../executors/verify-packaging/executor.ts | 3 +- .../src/plugins/workspace-plugin.spec.ts | 50 ++--- .../src/plugins/workspace-plugin.ts | 194 +++++++++++++----- 12 files changed, 192 insertions(+), 115 deletions(-) diff --git a/tools/workspace-plugin/src/executors/build/executor.spec.ts b/tools/workspace-plugin/src/executors/build/executor.spec.ts index 1e256f152ed6a1..ea26f7c24e6527 100644 --- a/tools/workspace-plugin/src/executors/build/executor.spec.ts +++ b/tools/workspace-plugin/src/executors/build/executor.spec.ts @@ -203,7 +203,7 @@ describe('Build Executor', () => { " `); expect(readFileSync(join(workspaceRoot, 'libs/proj/lib/greeter.js.map'), 'utf-8')).toMatchInlineSnapshot( - `"{\\"version\\":3,\\"sources\\":[\\"greeter.ts\\"],\\"sourcesContent\\":[\\"import { useStyles } from './greeter.styles';\\\\nexport function greeter(greeting: string, user: User): string {\\\\n const styles = useStyles();\\\\n return \`

\${greeting} \${user.name} from \${user.hometown?.name}

\`;\\\\n}\\\\n\\\\ntype User = {\\\\n name: string;\\\\n hometown?: {\\\\n name: string;\\\\n };\\\\n};\\\\n\\"],\\"names\\":[\\"useStyles\\",\\"greeter\\",\\"greeting\\",\\"user\\",\\"styles\\",\\"name\\",\\"hometown\\"],\\"rangeMappings\\":\\";;;;;\\",\\"mappings\\":\\"AAAA,SAASA,SAAS,QAAQ,mBAAmB;AAC7C,OAAO,SAASC,QAAQC,QAAgB,EAAEC,IAAU;QAEYA;IAD9D,MAAMC,SAASJ;IACf,OAAO,CAAC,WAAW,EAAEI,OAAO,EAAE,EAAEF,SAAS,CAAC,EAAEC,KAAKE,IAAI,CAAC,MAAM,GAAEF,iBAAAA,KAAKG,QAAQ,cAAbH,qCAAAA,eAAeE,IAAI,CAAC,KAAK,CAAC;AAC1F\\"}"`, + `"{\\"version\\":3,\\"sources\\":[\\"../src/greeter.ts\\"],\\"sourcesContent\\":[\\"import { useStyles } from './greeter.styles';\\\\nexport function greeter(greeting: string, user: User): string {\\\\n const styles = useStyles();\\\\n return \`

\${greeting} \${user.name} from \${user.hometown?.name}

\`;\\\\n}\\\\n\\\\ntype User = {\\\\n name: string;\\\\n hometown?: {\\\\n name: string;\\\\n };\\\\n};\\\\n\\"],\\"names\\":[\\"useStyles\\",\\"greeter\\",\\"greeting\\",\\"user\\",\\"styles\\",\\"name\\",\\"hometown\\"],\\"rangeMappings\\":\\";;;;;\\",\\"mappings\\":\\"AAAA,SAASA,SAAS,QAAQ,mBAAmB;AAC7C,OAAO,SAASC,QAAQC,QAAgB,EAAEC,IAAU;QAEYA;IAD9D,MAAMC,SAASJ;IACf,OAAO,CAAC,WAAW,EAAEI,OAAO,EAAE,EAAEF,SAAS,CAAC,EAAEC,KAAKE,IAAI,CAAC,MAAM,GAAEF,iBAAAA,KAAKG,QAAQ,cAAbH,qCAAAA,eAAeE,IAAI,CAAC,KAAK,CAAC;AAC1F\\"}"`, ); expect(readFileSync(join(workspaceRoot, 'libs/proj/lib-commonjs/greeter.js'), 'utf-8')).toMatchInlineSnapshot(` diff --git a/tools/workspace-plugin/src/executors/build/lib/babel.ts b/tools/workspace-plugin/src/executors/build/lib/babel.ts index 04576101348abc..4939d90f209f97 100644 --- a/tools/workspace-plugin/src/executors/build/lib/babel.ts +++ b/tools/workspace-plugin/src/executors/build/lib/babel.ts @@ -85,6 +85,7 @@ async function babel(esmModuleOutput: NormalizedOptions['moduleOutput'][number], const sourceCode = codeBuffer.toString().replace(EOL_REGEX, '\n'); const result = (await transformAsync(sourceCode, { + cwd: normalizedOptions.absoluteProjectRoot, ast: false, sourceMaps: true, diff --git a/tools/workspace-plugin/src/executors/build/lib/swc.ts b/tools/workspace-plugin/src/executors/build/lib/swc.ts index afd89dcaa018c4..a3c2dd9f887b55 100644 --- a/tools/workspace-plugin/src/executors/build/lib/swc.ts +++ b/tools/workspace-plugin/src/executors/build/lib/swc.ts @@ -1,14 +1,20 @@ -import { readFileSync } from 'node:fs'; import { mkdir, writeFile } from 'node:fs/promises'; -import { basename, dirname, join } from 'node:path'; +import { dirname, join } from 'node:path'; import { globSync } from 'fast-glob'; import { isMatch } from 'micromatch'; -import { transform, type Config } from '@swc/core'; +import { transformFile, type Config } from '@swc/core'; import { logger, readJsonFile } from '@nx/devkit'; import { type NormalizedOptions } from './shared'; +// extend @swc/core types by missing apis +declare module '@swc/core' { + interface BaseModuleConfig { + resolveFully?: boolean; + } +} + interface Options { module: 'es6' | 'commonjs' | 'amd'; outputPath: string; @@ -35,15 +41,10 @@ export async function compileSwc(options: Options, normalizedOptions: Normalized continue; } - const sourceCode = readFileSync(srcFilePath, 'utf-8'); - - const result = await transform(sourceCode, { - filename: fileName, - sourceFileName: basename(fileName), - module: { type: module }, - outputPath, - // this is crucial in order to transpile with project config SWC - configFile: swcConfigPath, + const result = await transformFile(srcFilePath, { + module: { type: module, resolveFully: Boolean(swcConfig.jsc?.baseUrl) }, + // srcFilePath is absolute path so outputPath needs to be as well in order to properly emit relative path within .map (eg: `"sources":["../src/utils/createDarkTheme.ts"]`) + outputPath: join(normalizedOptions.absoluteProjectRoot, outputPath), }); // Strip @jsx comments, see https://github.com/microsoft/fluentui/issues/29126 diff --git a/tools/workspace-plugin/src/executors/build/schema.d.ts b/tools/workspace-plugin/src/executors/build/schema.d.ts index 1c099ab6cef019..26b5481c0e2cc6 100644 --- a/tools/workspace-plugin/src/executors/build/schema.d.ts +++ b/tools/workspace-plugin/src/executors/build/schema.d.ts @@ -55,14 +55,7 @@ export interface BuildExecutorSchema { * Key-value pairs to replace in the output path */ substitutions?: { - /** - * The key to replace. - */ - key: string; - /** - * The value to replace. - */ - value: string; + [k: string]: string; }; } | string diff --git a/tools/workspace-plugin/src/executors/build/schema.json b/tools/workspace-plugin/src/executors/build/schema.json index bf4373b83626b9..f8dabb4fd107eb 100644 --- a/tools/workspace-plugin/src/executors/build/schema.json +++ b/tools/workspace-plugin/src/executors/build/schema.json @@ -47,12 +47,9 @@ "substitutions": { "type": "object", "description": "Key-value pairs to replace in the output path", - "properties": { - "key": { "type": "string", "description": "The key to replace." }, - "value": { "type": "string", "description": "The value to replace." } - }, - "additionalProperties": false, - "required": ["key", "value"] + "additionalProperties": { + "type": "string" + } } }, "additionalProperties": false, diff --git a/tools/workspace-plugin/src/executors/generate-api/executor.spec.ts b/tools/workspace-plugin/src/executors/generate-api/executor.spec.ts index 0bdead569d8d66..b68417b56b479a 100644 --- a/tools/workspace-plugin/src/executors/generate-api/executor.spec.ts +++ b/tools/workspace-plugin/src/executors/generate-api/executor.spec.ts @@ -148,8 +148,10 @@ describe('GenerateApi Executor', () => { const output = await executor(options, context); + const projectRootAbsolutePath = `${__dirname}/__fixtures__/proj`; + expect(execSyncMock.mock.calls.flat()).toEqual([ - `tsc -p ${__dirname}/__fixtures__/proj/tsconfig.lib.json --pretty --emitDeclarationOnly --baseUrl .`, + `tsc -p ${projectRootAbsolutePath}/tsconfig.lib.json --pretty --emitDeclarationOnly --baseUrl ${projectRootAbsolutePath}`, { stdio: 'inherit' }, ]); diff --git a/tools/workspace-plugin/src/executors/generate-api/executor.ts b/tools/workspace-plugin/src/executors/generate-api/executor.ts index d878979c731ce0..17bb673b99aa49 100644 --- a/tools/workspace-plugin/src/executors/generate-api/executor.ts +++ b/tools/workspace-plugin/src/executors/generate-api/executor.ts @@ -84,7 +84,7 @@ function generateTypeDeclarations(options: NormalizedOptions) { '--pretty', '--emitDeclarationOnly', // turn off path aliases. - '--baseUrl .', + `--baseUrl ${options.projectAbsolutePath}`, ].join(' '); verboseLog(`Emitting '.d.ts' files via: "${cmd}"`); diff --git a/tools/workspace-plugin/src/executors/type-check/executor.spec.ts b/tools/workspace-plugin/src/executors/type-check/executor.spec.ts index 22fd3495e896db..280e08803b990a 100644 --- a/tools/workspace-plugin/src/executors/type-check/executor.spec.ts +++ b/tools/workspace-plugin/src/executors/type-check/executor.spec.ts @@ -75,8 +75,8 @@ describe('TypeCheck Executor', () => { const output = await executor(options, mockContext); expect(promisifyCallMock.mock.calls.flat()).toEqual([ - 'tsc -p /root/libs/my-lib/tsconfig.lib.json --pretty --noEmit --baseUrl .', - 'tsc -p /root/libs/my-lib/tsconfig.spec.json --pretty --noEmit --baseUrl .', + 'tsc -p /root/libs/my-lib/tsconfig.lib.json --pretty --noEmit --baseUrl /root/libs/my-lib', + 'tsc -p /root/libs/my-lib/tsconfig.spec.json --pretty --noEmit --baseUrl /root/libs/my-lib', ]); expect(output.success).toBe(true); @@ -93,7 +93,7 @@ describe('TypeCheck Executor', () => { const output = await executor({ ...options, excludeProject: { spec: true, e2e: false } }, mockContext); expect(promisifyCallMock.mock.calls.flat()).toEqual([ - 'tsc -p /root/libs/my-lib/tsconfig.lib.json --pretty --noEmit --baseUrl .', + 'tsc -p /root/libs/my-lib/tsconfig.lib.json --pretty --noEmit --baseUrl /root/libs/my-lib', ]); expect(output.success).toBe(true); diff --git a/tools/workspace-plugin/src/executors/type-check/executor.ts b/tools/workspace-plugin/src/executors/type-check/executor.ts index dfd0a6fdafc749..33673193983a01 100644 --- a/tools/workspace-plugin/src/executors/type-check/executor.ts +++ b/tools/workspace-plugin/src/executors/type-check/executor.ts @@ -43,7 +43,7 @@ async function runTypeCheck(options: NormalizedOptions, context: ExecutorContext const asyncQueue = []; for (const ref of tsConfigsRefs) { - const program = `tsc -p ${ref} --pretty --noEmit --baseUrl .`; + const program = `tsc -p ${ref} --pretty --noEmit --baseUrl ${projectRootAbsolutePath}`; verboseLog(`Running "${program}"`); diff --git a/tools/workspace-plugin/src/executors/verify-packaging/executor.ts b/tools/workspace-plugin/src/executors/verify-packaging/executor.ts index 4a48934f5da7b8..37033028b6faa3 100644 --- a/tools/workspace-plugin/src/executors/verify-packaging/executor.ts +++ b/tools/workspace-plugin/src/executors/verify-packaging/executor.ts @@ -122,7 +122,8 @@ function assertions( ); } - if (isV8package) { + // apply only for non cross domain v8 packages (eg: react-migration-* is v9/v8) + if (isV8package && !isV9package) { issues.push(assertEmpty(npmPackResult, '(lib|lib-commonjs)/**/*.d.ts', `ships dts`)); if (options.isProduction && shipsBundle) { diff --git a/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts b/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts index 4eef49a2c1c3b6..819c0972eb4d0a 100644 --- a/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts +++ b/tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts @@ -136,32 +136,40 @@ describe(`workspace-plugin`, () => { describe(`v9 project nodes`, () => { it('should create default nodes for v9 library project', async () => { await tempFs.createFiles({ - 'proj/project.json': serializeJson({ + 'proj/library/project.json': serializeJson({ root: 'proj', + name: 'proj', projectType: 'library', tags: ['vNext'], } satisfies ProjectConfiguration), - 'proj/package.json': serializeJson({ name: '@proj/proj', private: true } satisfies Partial), + 'proj/library/package.json': serializeJson({ + name: '@proj/proj', + private: true, + } satisfies Partial), + 'proj/stories/project.json': serializeJson({ + root: 'proj/stories', + name: 'proj-stories', + } satisfies ProjectConfiguration), }); - const results = await createNodesFunction(['proj/project.json'], {}, context); + const results = await createNodesFunction(['proj/library/project.json'], {}, context); - expect(getTargetsNames(results)).toEqual([ + expect(getTargetsNames(results, 'proj/library')).toEqual([ 'clean', 'format', 'type-check', 'generate-api', 'build', - 'start', 'storybook', + 'start', ]); expect(results).toMatchInlineSnapshot(` Array [ Array [ - "proj/project.json", + "proj/library/project.json", Object { "projects": Object { - "proj": Object { + "proj/library": Object { "targets": Object { "build": Object { "cache": true, @@ -189,7 +197,7 @@ describe(`workspace-plugin`, () => { ], "metadata": Object { "help": Object { - "command": "yarn nx run undefined:build --help", + "command": "yarn nx run proj:build --help", "example": Object {}, }, "technologies": Array [ @@ -217,7 +225,7 @@ describe(`workspace-plugin`, () => { "{projectRoot}/lib-commonjs", "{projectRoot}/dist", "{projectRoot}/dist/index.d.ts", - "{projectRoot}/etc/undefined.api.md", + "{projectRoot}/etc/proj.api.md", ], }, "clean": Object { @@ -266,7 +274,7 @@ describe(`workspace-plugin`, () => { ], "metadata": Object { "help": Object { - "command": "yarn nx run undefined:generate-api --help", + "command": "yarn nx run proj:generate-api --help", "example": Object {}, }, "technologies": Array [ @@ -276,26 +284,16 @@ describe(`workspace-plugin`, () => { }, "outputs": Array [ "{projectRoot}/dist/index.d.ts", - "{projectRoot}/etc/undefined.api.md", + "{projectRoot}/etc/proj.api.md", ], }, "start": Object { - "command": "yarn storybook", - "options": Object { - "cwd": "proj", - }, + "cache": true, + "command": "nx run proj-stories:storybook", }, "storybook": Object { "cache": true, - "command": "yarn --cwd ../stories storybook", - "metadata": Object { - "technologies": Array [ - "storybook", - ], - }, - "options": Object { - "cwd": "proj", - }, + "command": "nx run proj-stories:storybook", }, "type-check": Object { "cache": true, @@ -323,6 +321,7 @@ describe(`workspace-plugin`, () => { it('should create default nodes for v9 stories project', async () => { await tempFs.createFiles({ + 'proj/stories/.storybook/main.js': '', 'proj/stories/project.json': serializeJson({ root: 'proj/stories', projectType: 'library', @@ -339,15 +338,16 @@ describe(`workspace-plugin`, () => { 'clean', 'format', 'type-check', + 'storybook', 'test-ssr', 'start', - 'storybook', ]); const targets = getTargets(results, 'proj/stories'); expect(targets?.storybook).toMatchInlineSnapshot(` Object { + "cache": true, "command": "yarn storybook dev", "inputs": Array [ "production", diff --git a/tools/workspace-plugin/src/plugins/workspace-plugin.ts b/tools/workspace-plugin/src/plugins/workspace-plugin.ts index a7f191c4870a9a..27a2f365b69ca9 100644 --- a/tools/workspace-plugin/src/plugins/workspace-plugin.ts +++ b/tools/workspace-plugin/src/plugins/workspace-plugin.ts @@ -22,34 +22,73 @@ import { assertProjectExists, projectConfigGlob } from './shared'; import { buildCleanTarget } from './clean-plugin'; import { buildFormatTarget } from './format-plugin'; import { buildTypeCheckTarget } from './type-check-plugin'; +import { measureStart, measureEnd } from '../utils'; -interface WorkspacePluginOptions {} +interface WorkspacePluginOptions { + testSSR?: TargetPluginOption; + verifyPackaging?: TargetPluginOption; +} +interface TargetPluginOption { + targetName?: string; + /** + * project names to exclude from adding target + */ + exclude?: string[]; + /** + * project names to include for adding target + */ + include?: string[]; +} export const createNodesV2: CreateNodesV2 = [ projectConfigGlob, - (configFiles, options, context) => { - return createNodesFromFiles( + async (configFiles, options, context) => { + const globalConfig: Pick = { pmc: getPackageManagerCommand('yarn') }; + + measureStart('workspace-plugin'); + const nodes = await createNodesFromFiles( (configFile, options, context) => { - return createNodesInternal(configFile, options ?? {}, context); + return createNodesInternal(configFile, options ?? {}, context, globalConfig); }, configFiles, options, context, ); + + measureEnd('workspace-plugin'); + + return nodes; }, ]; // =================================================================================================================== -function normalizeOptions(options: WorkspacePluginOptions | undefined): Required { +type NormalizedOptions = ReturnType; + +type DeepRequired = { + [K in keyof T]-?: NonNullable extends object ? DeepRequired : NonNullable; +}; + +function normalizeOptions(options: WorkspacePluginOptions | undefined): DeepRequired { options ??= {}; - return options as Required; + options.testSSR ??= {}; + options.testSSR.targetName ??= 'test-ssr'; + options.testSSR.include ??= []; + options.testSSR.exclude ??= []; + + options.verifyPackaging ??= {}; + options.verifyPackaging.targetName ??= 'verify-packaging'; + options.verifyPackaging.include ??= []; + options.verifyPackaging.exclude ??= []; + + return options as DeepRequired; } function createNodesInternal( configFilePath: string, options: WorkspacePluginOptions, context: CreateNodesContextV2, + globalConfig: Pick, ): CreateNodesResult { const projectRoot = dirname(configFilePath); @@ -58,7 +97,8 @@ function createNodesInternal( } const normalizedOptions = normalizeOptions(options); - const config = { pmc: getPackageManagerCommand('yarn') }; + + const config = { ...globalConfig }; const targetsConfig = buildWorkspaceTargets(projectRoot, normalizedOptions, context, config); @@ -78,7 +118,7 @@ interface TaskBuilderConfig { function buildWorkspaceTargets( projectRoot: string, - options: Required, + options: NormalizedOptions, context: CreateNodesContextV2, sharedConfig: Pick, ) { @@ -94,50 +134,33 @@ function buildWorkspaceTargets( targets.format = buildFormatTarget({}, context, config); targets['type-check'] = buildTypeCheckTarget({}, context, config); - const lintTarget = buildLintTarget(projectRoot, normalizeOptions, context, config); + const lintTarget = buildLintTarget(projectRoot, options, context, config); if (lintTarget) { targets.lint = lintTarget; } - const testTarget = buildTestTarget(projectRoot, normalizeOptions, context, config); + const testTarget = buildTestTarget(projectRoot, options, context, config); if (testTarget) { targets.test = testTarget; } + const storybookTarget = buildStorybookTarget(projectRoot, options, context, config); + if (storybookTarget) { + targets.storybook = storybookTarget; + } + // react v9 lib if (projectJSON.projectType === 'library' && tags.includes('vNext')) { // *-stories projects if (tags.includes('type:stories')) { - targets['test-ssr'] = { - cache: true, - command: `${config.pmc.exec} test-ssr "./src/**/*.stories.tsx"`, - options: { cwd: projectRoot }, - metadata: { - technologies: ['test-ssr'], - help: { - command: `${config.pmc.exec} test-ssr --help`, - example: {}, - }, - }, - }; - targets.start = { command: `${config.pmc.exec} storybook`, options: { cwd: projectRoot } }; - targets.storybook = { - command: `${config.pmc.exec} storybook dev`, - inputs: [ - 'production', - '{workspaceRoot}/.storybook/**', - '{projectRoot}/.storybook/**', - { externalDependencies: ['storybook'] }, - ], - options: { cwd: projectRoot }, - metadata: { - technologies: ['storybook'], - help: { - command: `${config.pmc.exec} storybook dev --help`, - example: {}, - }, - }, - }; + const testSsrTarget = buildTestSsrTarget(projectRoot, options, context, config); + if (testSsrTarget) { + targets[options.testSSR.targetName] = testSsrTarget; + } + + if (storybookTarget) { + targets.start = { command: `nx run ${config.projectJSON.name}:storybook`, cache: true }; + } return targets; } @@ -204,18 +227,11 @@ function buildWorkspaceTargets( }, }; - targets.start = { - command: `${config.pmc.exec} storybook`, - options: { cwd: projectRoot }, - }; - targets.storybook = { - cache: true, - command: `${config.pmc.exec} --cwd ../stories storybook`, - options: { cwd: projectRoot }, - metadata: { - technologies: ['storybook'], - }, - }; + if (existsSync(join(projectRoot, '../stories/project.json'))) { + const storybookTarget = { command: `nx run ${config.projectJSON.name}-stories:storybook`, cache: true }; + targets.storybook = storybookTarget; + targets.start = storybookTarget; + } const bundleSizeTarget = buildBundleSizeTarget(projectRoot, options, context, config); if (bundleSizeTarget) { @@ -227,9 +243,9 @@ function buildWorkspaceTargets( targets.e2e = e2eTarget; } - const verifyPackagingTarget = buildVerifyPackagingTarget(projectRoot, normalizeOptions, context, config); + const verifyPackagingTarget = buildVerifyPackagingTarget(projectRoot, options, context, config); if (verifyPackagingTarget) { - targets['verify-packaging'] = verifyPackagingTarget; + targets[options.verifyPackaging.targetName] = verifyPackagingTarget; } return targets; @@ -310,10 +326,17 @@ function buildLintTarget( function buildVerifyPackagingTarget( projectRoot: string, - options: Required, + options: NormalizedOptions, context: CreateNodesContextV2, config: TaskBuilderConfig, ): TargetConfiguration | null { + if (options.verifyPackaging.include.length && !options.verifyPackaging.include.includes(config.projectJSON.name!)) { + return null; + } + if (options.verifyPackaging.exclude.length && options.verifyPackaging.exclude.includes(config.projectJSON.name!)) { + return null; + } + if (config.packageJSON.private) { return null; } @@ -386,6 +409,7 @@ function buildE2eTarget( { externalDependencies: ['cypress', '@cypress/react'] }, ], metadata: { + technologies: ['cypress'], help: { command: `${config.pmc.exec} cypress run --help`, example: {}, @@ -408,9 +432,10 @@ function buildE2eTarget( '{projectRoot}/playwright.config.ts', '!{projectRoot}/**/?(*.)+spec.[jt]s?(x)?', '!{projectRoot}/**/?(*.)+spec-e2e.[jt]s?(x)?', - { externalDependencies: ['playwright'] }, + { externalDependencies: ['@playwright/test'] }, ], metadata: { + technologies: ['playwright'], help: { command: `${config.pmc.exec} playwright test --help`, example: {}, @@ -421,3 +446,60 @@ function buildE2eTarget( return null; } + +function buildTestSsrTarget( + projectRoot: string, + options: NormalizedOptions, + context: CreateNodesContextV2, + config: TaskBuilderConfig, +): TargetConfiguration | null { + if (options.testSSR.include.length && !options.testSSR.include.includes(config.projectJSON.name!)) { + return null; + } + if (options.testSSR.exclude.length && options.testSSR.exclude.includes(config.projectJSON.name!)) { + return null; + } + + return { + cache: true, + command: `${config.pmc.exec} test-ssr "./src/**/*.stories.tsx"`, + options: { cwd: projectRoot }, + metadata: { + technologies: ['test-ssr'], + help: { + command: `${config.pmc.exec} test-ssr --help`, + example: {}, + }, + }, + }; +} + +function buildStorybookTarget( + projectRoot: string, + options: NormalizedOptions, + context: CreateNodesContextV2, + config: TaskBuilderConfig, +): TargetConfiguration | null { + if (!existsSync(join(projectRoot, '.storybook/main.js'))) { + return null; + } + + return { + command: `${config.pmc.exec} storybook dev`, + cache: true, + inputs: [ + 'production', + '{workspaceRoot}/.storybook/**', + '{projectRoot}/.storybook/**', + { externalDependencies: ['storybook'] }, + ], + options: { cwd: projectRoot }, + metadata: { + technologies: ['storybook'], + help: { + command: `${config.pmc.exec} storybook dev --help`, + example: {}, + }, + }, + }; +} From e32acb83484182f022e2bcf89a6d704760e06d7c Mon Sep 17 00:00:00 2001 From: Fluent UI Build Date: Thu, 24 Oct 2024 04:08:20 +0000 Subject: [PATCH 4/5] release: applying package updates - web-components --- ...ents-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json | 7 ------- packages/web-components/CHANGELOG.json | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) delete mode 100644 change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json diff --git a/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json b/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json deleted file mode 100644 index c53be7ff1e9396..00000000000000 --- a/change/@fluentui-web-components-ad9feaa2-0083-4a09-a62c-4f26d54356c6.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "none", - "comment": "resolve eslint errors after upgrade to typescript-eslint v8", - "packageName": "@fluentui/web-components", - "email": "vgenaev@gmail.com", - "dependentChangeType": "none" -} diff --git a/packages/web-components/CHANGELOG.json b/packages/web-components/CHANGELOG.json index 8b0d8699724241..87b2e05aae3391 100644 --- a/packages/web-components/CHANGELOG.json +++ b/packages/web-components/CHANGELOG.json @@ -1,6 +1,21 @@ { "name": "@fluentui/web-components", "entries": [ + { + "date": "Thu, 24 Oct 2024 04:08:05 GMT", + "tag": "@fluentui/web-components_v3.0.0-beta.69", + "version": "3.0.0-beta.69", + "comments": { + "none": [ + { + "author": "vgenaev@gmail.com", + "package": "@fluentui/web-components", + "commit": "d0e28c6674287caeeef341f1f355e53d152fcf37", + "comment": "resolve eslint errors after upgrade to typescript-eslint v8" + } + ] + } + }, { "date": "Tue, 15 Oct 2024 04:07:48 GMT", "tag": "@fluentui/web-components_v3.0.0-beta.69", From 348c46dd86e644719f586d41fd6848dd690662c0 Mon Sep 17 00:00:00 2001 From: Oleksandr Fediashov Date: Thu, 24 Oct 2024 11:12:36 +0200 Subject: [PATCH 5/5] docs: improve UI in examples (#33121) --- .../useUncontrolledFocus/Default.stories.tsx | 46 ++++++++++++++----- .../useUncontrolledFocusDescription.md | 2 +- .../src/Carousel/CarouselAutoplay.stories.tsx | 37 +++++++-------- .../CarouselFirstRunExperience.stories.tsx | 35 +++++++------- .../stories/src/Carousel/index.stories.tsx | 2 +- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/Default.stories.tsx b/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/Default.stories.tsx index 46ceb5b070c933..5aae21f4a6f64b 100644 --- a/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/Default.stories.tsx +++ b/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/Default.stories.tsx @@ -4,21 +4,28 @@ import { FocusTrapZone } from '@fluentui/react'; import { useUncontrolledFocus, Field, Switch, Button, makeStyles, tokens } from '@fluentui/react-components'; const useStyles = makeStyles({ + container: { + display: 'flex', + flexDirection: 'column', + gap: '10px', + placeItems: 'start', + }, focusTrapZone: { display: 'flex', - columnGap: '10px', + gap: '20px', padding: '20px 10px 10px 10px', position: 'relative', - maxWidth: '400px', + width: '400px', border: `2px solid ${tokens.colorBrandBackground}`, + '::after': { content: `'FocusTrapZone'`, position: 'absolute', - padding: '1px 4px 1px', + padding: '4px', top: '-2px', left: '-2px', fontFamily: 'monospace', - fontSize: '15px', + fontSize: '14px', fontWeight: 900, lineHeight: 1, letterSpacing: '1px', @@ -26,28 +33,43 @@ const useStyles = makeStyles({ backgroundColor: tokens.colorBrandBackground, }, }, + controls: { + flex: 1, + display: 'flex', + gap: '10px', + alignItems: 'end', + justifyContent: 'end', + }, }); export const Default = () => { const attr = useUncontrolledFocus(); - const [uncontrolled, setUncontrolled] = React.useState(false); const styles = useStyles(); + + const [enabled, setEnabled] = React.useState(true); + return ( - <> +
+ - - setUncontrolled(data.checked)} /> + + setEnabled(data.checked)} /> - - + +
+ + +
+ - +
); }; diff --git a/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/useUncontrolledFocusDescription.md b/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/useUncontrolledFocusDescription.md index bf0ee44dc8d905..d3769484a6eb2e 100644 --- a/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/useUncontrolledFocusDescription.md +++ b/apps/public-docsite-v9/src/Utilities/FocusManagement/useUncontrolledFocus/useUncontrolledFocusDescription.md @@ -3,4 +3,4 @@ only focus management framework in an application. However, it's understandable other focus management frameworks. In these cases, the `useUncontrolledFocus` hook can be used to explicitly remove explicit focus controlling for a region of DOM. -This is particularly useful to support legacy v8 focus management components such as `FocusZone` and `FocusTrapZone` +This is particularly useful to support legacy v8 focus management components such as `FocusZone` and `FocusTrapZone`. diff --git a/packages/react-components/react-carousel/stories/src/Carousel/CarouselAutoplay.stories.tsx b/packages/react-components/react-carousel/stories/src/Carousel/CarouselAutoplay.stories.tsx index f71221595c3da7..e27b2362502439 100644 --- a/packages/react-components/react-carousel/stories/src/Carousel/CarouselAutoplay.stories.tsx +++ b/packages/react-components/react-carousel/stories/src/Carousel/CarouselAutoplay.stories.tsx @@ -42,7 +42,6 @@ const useClasses = makeStyles({ display: 'grid', gridTemplateColumns: '1fr', gridTemplateRows: 'auto 1fr', - paddingBottom: '24px', boxShadow: tokens.shadow16, }, card: { @@ -146,23 +145,25 @@ export const Autoplay = () => { setAutoplayEnabled(!autoplayEnabled)} /> - - - {IMAGES.map((imageSrc, index) => ( - - Card {index + 1} - - ))} - - - {index => } - - +
+ + + {IMAGES.map((imageSrc, index) => ( + + Card {index + 1} + + ))} + + + {index => } + + +
); }; diff --git a/packages/react-components/react-carousel/stories/src/Carousel/CarouselFirstRunExperience.stories.tsx b/packages/react-components/react-carousel/stories/src/Carousel/CarouselFirstRunExperience.stories.tsx index 1a6506732813d2..291f12c9c0ab48 100644 --- a/packages/react-components/react-carousel/stories/src/Carousel/CarouselFirstRunExperience.stories.tsx +++ b/packages/react-components/react-carousel/stories/src/Carousel/CarouselFirstRunExperience.stories.tsx @@ -16,7 +16,6 @@ import { tokens, typographyStyles, } from '@fluentui/react-components'; -import { useEffect } from 'react'; const useStyles = makeStyles({ surface: { @@ -67,7 +66,7 @@ const getAnnouncement: CarouselAnnouncerFunction = (index: number, totalSlides: return `Carousel slide ${index + 1} of ${totalSlides}, ${PAGES[index].header}`; }; -export const CarouselFirstRunExperience = () => { +export const FirstRunExperience = () => { const styles = useStyles(); const [activeIndex, setActiveIndex] = React.useState(0); const [open, setModalOpen] = React.useState(false); @@ -80,19 +79,9 @@ export const CarouselFirstRunExperience = () => { } setActiveIndex(page); }; - // NearButton and FarButton are function components that handle navigation and focus management - const NearButton = () => ( - - ); - - const FarButton = () => ( - - ); - useEffect(() => { - // Reset or initialize page on open if nessecary + React.useEffect(() => { + // Reset or initialize page on open if necessary if (open) { setActiveIndex(0); } @@ -114,7 +103,7 @@ export const CarouselFirstRunExperience = () => { onActiveIndexChange={(e, data) => setActiveIndex(data.index)} > - {PAGES.map((page, index) => ( + {PAGES.map(page => (

@@ -125,14 +114,26 @@ export const CarouselFirstRunExperience = () => { ))}
- {NearButton()} + + {index => } - {FarButton()} + +
); }; + +FirstRunExperience.parameters = { + docs: { + description: { + story: 'Carousel can be used in a Dialog to create a _first-run_ experience.', + }, + }, +}; diff --git a/packages/react-components/react-carousel/stories/src/Carousel/index.stories.tsx b/packages/react-components/react-carousel/stories/src/Carousel/index.stories.tsx index 42e651e9e0e346..8ededd3dd166ee 100644 --- a/packages/react-components/react-carousel/stories/src/Carousel/index.stories.tsx +++ b/packages/react-components/react-carousel/stories/src/Carousel/index.stories.tsx @@ -19,7 +19,7 @@ export { Controlled } from './CarouselControlled.stories'; export { ImageSlideshow } from './CarouselImageBox.stories'; export { AlignmentAndWhitespace } from './CarouselActionCards.stories'; export { Autoplay } from './CarouselAutoplay.stories'; -export { CarouselFirstRunExperience } from './CarouselFirstRunExperience.stories'; +export { FirstRunExperience } from './CarouselFirstRunExperience.stories'; export default { title: 'Components/Carousel',