diff --git a/packages/eslint-config-universe/CHANGELOG.md b/packages/eslint-config-universe/CHANGELOG.md index d72bb34a6c1d20..5a85b97f8820d6 100644 --- a/packages/eslint-config-universe/CHANGELOG.md +++ b/packages/eslint-config-universe/CHANGELOG.md @@ -6,6 +6,8 @@ ### 🎉 New features +- Disabled `import/no-named-as-default` in both core and TypeScript presets ([#45088](https://github.com/expo/expo/pull/45088) by [@hassankhan](https://github.com/hassankhan)) + ### 🐛 Bug fixes ### 💡 Others diff --git a/packages/eslint-config-universe/flat/shared/core.js b/packages/eslint-config-universe/flat/shared/core.js index 0a622f80aa91ba..ed5c53a3bddd7a 100644 --- a/packages/eslint-config-universe/flat/shared/core.js +++ b/packages/eslint-config-universe/flat/shared/core.js @@ -260,6 +260,7 @@ module.exports = defineConfig([ ], 'import/default': 'off', + 'import/no-named-as-default': 'off', 'import/export': 'error', 'import/first': 'warn', diff --git a/packages/eslint-config-universe/flat/shared/typescript.js b/packages/eslint-config-universe/flat/shared/typescript.js index e9431e9bd47897..ddde0f0522e0b6 100644 --- a/packages/eslint-config-universe/flat/shared/typescript.js +++ b/packages/eslint-config-universe/flat/shared/typescript.js @@ -101,6 +101,9 @@ module.exports = defineConfig([ // TODO (Kadi): Enable this. Disabling for now because import/recommended adds it, but we didn't use to have it enabled 'import/no-unresolved': 'off', + + // NOTE(@hassankhan): This is disabled in `core`, but `eslint-plugin-import`'s recommended rules re-enable it + 'import/no-named-as-default': 'off', }, }, ]); diff --git a/packages/eslint-config-universe/shared/core.js b/packages/eslint-config-universe/shared/core.js index f3e09f926b287f..4521b91308208d 100644 --- a/packages/eslint-config-universe/shared/core.js +++ b/packages/eslint-config-universe/shared/core.js @@ -141,6 +141,7 @@ module.exports = { yoda: ['warn', 'never', { exceptRange: true }], 'import/default': 'off', + 'import/no-named-as-default': 'off', 'import/export': 'error', 'import/first': 'warn', 'import/namespace': ['error', { allowComputed: true }], diff --git a/packages/eslint-config-universe/shared/typescript.js b/packages/eslint-config-universe/shared/typescript.js index d09b1b102d8b62..6a9d3a6773677a 100644 --- a/packages/eslint-config-universe/shared/typescript.js +++ b/packages/eslint-config-universe/shared/typescript.js @@ -55,6 +55,9 @@ module.exports = { // The typescript-eslint FAQ recommends turning off "no-undef" in favor of letting tsc check for // undefined variables, including types 'no-undef': 'off', + + // NOTE(@hassankhan): This is disabled in `core`, but `eslint-plugin-import`'s recommended rules re-enable it + 'import/no-named-as-default': 'off', }, settings: { 'import/extensions': allExtensions, diff --git a/packages/expo-modules-core/CHANGELOG.md b/packages/expo-modules-core/CHANGELOG.md index 128168bc73e554..615ab0bf90d8b2 100644 --- a/packages/expo-modules-core/CHANGELOG.md +++ b/packages/expo-modules-core/CHANGELOG.md @@ -22,6 +22,7 @@ ### 🐛 Bug fixes +- [iOS] Fix random crash when concurrent access of the same `Record` on `Field.options`. The set is now guarded by a per-field lock and accessed through a single `withOptions` API. ([#45072](https://github.com/expo/expo/pull/45072) by [@nishan](https://github.com/intergalacticspacehighway)) - [iOS] Fixed converting `Enumerable` function results to JS values. ([#45168](https://github.com/expo/expo/pull/45168) by [@tsapeta](https://github.com/tsapeta)) - [iOS] Fixed prebuild dependencies for `ExpoModulesJSI` ([#45124](https://github.com/expo/expo/pull/45124) by [@chrfalch](https://github.com/chrfalch)) - [iOS] Add async/await overload for StaticAsyncFunction ([#44471](https://github.com/expo/expo/pull/44471) by [@Wenszel](https://github.com/Wenszel)) diff --git a/packages/expo-modules-core/ios/Core/Records/AnyField.swift b/packages/expo-modules-core/ios/Core/Records/AnyField.swift index 57e3707d54d1cd..ad40bc77cf3b2d 100644 --- a/packages/expo-modules-core/ios/Core/Records/AnyField.swift +++ b/packages/expo-modules-core/ios/Core/Records/AnyField.swift @@ -12,7 +12,6 @@ public protocol AnyField { */ internal protocol AnyFieldInternal: AnyField { var key: String? { get } - var options: Set { get set } var fieldType: AnyDynamicType { get } /** @@ -22,6 +21,9 @@ internal protocol AnyFieldInternal: AnyField { */ var isRequired: Bool { get } + // Read‑modify‑write inside `body` is atomic. + func withOptions(_ body: (inout Set) -> T) -> T + func set(_ newValue: Any?, appContext: AppContext) throws @JavaScriptActor diff --git a/packages/expo-modules-core/ios/Core/Records/Field.swift b/packages/expo-modules-core/ios/Core/Records/Field.swift index 911a91731d2270..79c1c66f3a61af 100644 --- a/packages/expo-modules-core/ios/Core/Records/Field.swift +++ b/packages/expo-modules-core/ios/Core/Records/Field.swift @@ -16,16 +16,23 @@ public final class Field: AnyFieldInternal, @unchecked Sendab Sadly, property wrappers don't receive properties' label, so we must wait until it's assigned by `Record`. */ internal var key: String? { - return options.first { $0.rawValue == FieldOption.keyed("").rawValue }?.key + return withOptions { options in + options.first { $0.rawValue == FieldOption.keyed("").rawValue }?.key + } } /** Additional options of the field, such is if providing the value is required (`FieldOption.required`). + Locked because `fieldsOf` lazily writes the keyed option while other threads may read. Access only via `withOptions`. */ - internal var options: Set = Set() + private let _options: Mutex> + + internal func withOptions(_ body: (inout Set) -> T) -> T { + return _options.withLock { body(&$0) } + } internal var isRequired: Bool { - options.contains(.required) + withOptions { $0.contains(.required) } } /** @@ -33,7 +40,7 @@ public final class Field: AnyFieldInternal, @unchecked Sendab */ public init(wrappedValue: Type, _ options: FieldOption...) { self.wrappedValue = wrappedValue - self.options = Set(options) + self._options = Mutex(Set(options)) } /** @@ -42,7 +49,7 @@ public final class Field: AnyFieldInternal, @unchecked Sendab */ public init(wrappedValue: Type, _ options: [FieldOption]) { self.wrappedValue = wrappedValue - self.options = Set(options) + self._options = Mutex(Set(options)) } /** @@ -51,11 +58,12 @@ public final class Field: AnyFieldInternal, @unchecked Sendab */ public init(wrappedValue: Type = nil) where Type: ExpressibleByNilLiteral { self.wrappedValue = wrappedValue + self._options = Mutex(Set()) } public init(wrappedValue: Type = nil, _ options: FieldOption...) where Type: ExpressibleByNilLiteral { self.wrappedValue = wrappedValue - self.options = Set(options) + self._options = Mutex(Set(options)) } /** diff --git a/packages/expo-modules-core/ios/Core/Records/Record.swift b/packages/expo-modules-core/ios/Core/Records/Record.swift index 8aa18ce439e6ea..d459c81bc46a42 100644 --- a/packages/expo-modules-core/ios/Core/Records/Record.swift +++ b/packages/expo-modules-core/ios/Core/Records/Record.swift @@ -140,10 +140,15 @@ internal func allMirrorChildren(_ mirror: Mirror) -> [Mirror.Child] { internal func fieldsOf(_ record: Record) -> [AnyFieldInternal] { let mirror = Mirror(reflecting: record) return allMirrorChildren(mirror).compactMap { (label: String?, value: Any) in - guard var field = value as? AnyFieldInternal, let key = field.key ?? convertLabelToKey(label) else { + guard let field = value as? AnyFieldInternal, let key = field.key ?? convertLabelToKey(label) else { return nil } - field.options = field.options.union([.keyed(key)]) + field.withOptions { options in + let alreadyKeyed = options.contains { $0.rawValue == FieldOption.keyed("").rawValue } + if !alreadyKeyed { + options.insert(.keyed(key)) + } + } return field } } diff --git a/packages/expo-modules-core/ios/Tests/RecordSpec.swift b/packages/expo-modules-core/ios/Tests/RecordSpec.swift index e0f2884f2c46f8..9a8b48b260382c 100644 --- a/packages/expo-modules-core/ios/Tests/RecordSpec.swift +++ b/packages/expo-modules-core/ios/Tests/RecordSpec.swift @@ -116,5 +116,38 @@ class RecordSpec: ExpoSpec { expect(error).to(beAKindOf(FieldInvalidTypeException.self)) }) } + + it("serializes concurrently on a shared record without crashing") { + struct StressRecord: Record { + @Field var a: String? = nil + @Field var b: String? = nil + @Field var c: String? = nil + } + + let record = StressRecord(a: "a", b: "b", c: "c") + let workers = 16 + let iterations = 100 + let group = DispatchGroup() + let startGate = DispatchSemaphore(value: 0) + + for _ in 0..=7.0.0' - eslint-config-universe@14.3.0: - resolution: {integrity: sha512-AQjW1QxwrJPq8CZjTAK7F5q5FeITXcCMwzzoB6pMiDBCEyuUjPE1RbpQNaF/7kpVnxgzgks6rxNwnNIpd50ALg==} - peerDependencies: - eslint: '>=9' - prettier: '>=3' - peerDependenciesMeta: - prettier: - optional: true - eslint-formatter-pretty@4.1.0: resolution: {integrity: sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==} engines: {node: '>=10'} @@ -19756,22 +19747,6 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 - '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/type-utils': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 - eslint: 8.57.1 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3))(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -19788,18 +19763,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 - eslint: 8.57.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.57.1 @@ -19812,15 +19775,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.57.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/project-service@8.57.1(typescript@6.0.3)': dependencies: '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@6.0.3) @@ -19849,26 +19803,10 @@ snapshots: '@typescript-eslint/types': 8.57.1 '@typescript-eslint/visitor-keys': 8.57.1 - '@typescript-eslint/tsconfig-utils@8.57.1(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.57.1(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.57.1(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - debug: 4.4.3 - eslint: 8.57.1 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.57.1 @@ -19883,21 +19821,6 @@ snapshots: '@typescript-eslint/types@8.57.1': {} - '@typescript-eslint/typescript-estree@8.57.1(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.57.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.1(typescript@5.9.3) - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/visitor-keys': 8.57.1 - debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/typescript-estree@8.57.1(typescript@6.0.3)': dependencies: '@typescript-eslint/project-service': 8.57.1(typescript@6.0.3) @@ -19913,17 +19836,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.57.1(eslint@8.57.1)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.57.1 - '@typescript-eslint/types': 8.57.1 - '@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3) - eslint: 8.57.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/utils@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) @@ -21616,46 +21528,15 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-compat-utils@0.5.1(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - semver: 7.7.4 - eslint-compat-utils@0.5.1(eslint@9.39.4(jiti@1.21.7)): dependencies: eslint: 9.39.4(jiti@1.21.7) semver: 7.7.4 - eslint-config-prettier@9.1.2(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-config-prettier@9.1.2(eslint@9.39.4(jiti@1.21.7)): dependencies: eslint: 9.39.4(jiti@1.21.7) - eslint-config-universe@14.3.0(@types/eslint@9.6.1)(eslint@8.57.1)(prettier@3.5.3)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - eslint: 8.57.1 - eslint-config-prettier: 9.1.2(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1) - eslint-plugin-n: 17.24.0(eslint@8.57.1)(typescript@5.9.3) - eslint-plugin-node: 11.1.0(eslint@8.57.1) - eslint-plugin-prettier: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3) - eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) - globals: 16.5.0 - optionalDependencies: - prettier: 3.5.3 - transitivePeerDependencies: - - '@types/eslint' - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - - typescript - eslint-formatter-pretty@4.1.0: dependencies: '@types/eslint': 7.29.0 @@ -21690,16 +21571,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): - dependencies: - debug: 3.2.7 - optionalDependencies: - '@typescript-eslint/parser': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@1.21.7)): dependencies: debug: 3.2.7 @@ -21711,13 +21582,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-es-x@7.8.0(eslint@8.57.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.2 - eslint: 8.57.1 - eslint-compat-utils: 0.5.1(eslint@8.57.1) - eslint-plugin-es-x@7.8.0(eslint@9.39.4(jiti@1.21.7)): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) @@ -21725,12 +21589,6 @@ snapshots: eslint: 9.39.4(jiti@1.21.7) eslint-compat-utils: 0.5.1(eslint@9.39.4(jiti@1.21.7)) - eslint-plugin-es@3.0.1(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-utils: 2.1.0 - regexpp: 3.2.0 - eslint-plugin-es@3.0.1(eslint@9.39.4(jiti@1.21.7)): dependencies: eslint: 9.39.4(jiti@1.21.7) @@ -21743,35 +21601,6 @@ snapshots: eslint: 9.39.4(jiti@1.21.7) estraverse: 5.3.0 - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1): - dependencies: - '@rtsao/scc': 1.1.0 - array-includes: 3.1.9 - array.prototype.findlastindex: 1.2.6 - array.prototype.flat: 1.3.3 - array.prototype.flatmap: 1.3.3 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.57.1(eslint@8.57.1)(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) - hasown: 2.0.2 - is-core-module: 2.16.1 - is-glob: 4.0.3 - minimatch: 3.1.5 - object.fromentries: 2.0.8 - object.groupby: 1.0.3 - object.values: 1.2.1 - semver: 6.3.1 - string.prototype.trimend: 1.0.9 - tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.57.1(eslint@8.57.1)(typescript@5.9.3) - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.57.1(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.4(jiti@1.21.7)): dependencies: '@rtsao/scc': 1.1.0 @@ -21801,26 +21630,11 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-lodash@7.4.0(eslint@8.57.1): + eslint-plugin-lodash@7.4.0(eslint@9.39.4(jiti@1.21.7)): dependencies: - eslint: 8.57.1 + eslint: 9.39.4(jiti@1.21.7) lodash: 4.17.23 - eslint-plugin-n@17.24.0(eslint@8.57.1)(typescript@5.9.3): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) - enhanced-resolve: 5.20.1 - eslint: 8.57.1 - eslint-plugin-es-x: 7.8.0(eslint@8.57.1) - get-tsconfig: 4.13.6 - globals: 15.15.0 - globrex: 0.1.2 - ignore: 5.3.2 - semver: 7.7.4 - ts-declaration-location: 1.0.7(typescript@5.9.3) - transitivePeerDependencies: - - typescript - eslint-plugin-n@17.24.0(eslint@9.39.4(jiti@1.21.7))(typescript@6.0.3): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) @@ -21836,16 +21650,6 @@ snapshots: transitivePeerDependencies: - typescript - eslint-plugin-node@11.1.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-plugin-es: 3.0.1(eslint@8.57.1) - eslint-utils: 2.1.0 - ignore: 5.3.2 - minimatch: 3.1.5 - resolve: 1.22.11 - semver: 6.3.1 - eslint-plugin-node@11.1.0(eslint@9.39.4(jiti@1.21.7)): dependencies: eslint: 9.39.4(jiti@1.21.7) @@ -21856,16 +21660,6 @@ snapshots: resolve: 1.22.11 semver: 6.3.1 - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@8.57.1))(eslint@8.57.1)(prettier@3.5.3): - dependencies: - eslint: 8.57.1 - prettier: 3.5.3 - prettier-linter-helpers: 1.0.1 - synckit: 0.11.12 - optionalDependencies: - '@types/eslint': 9.6.1 - eslint-config-prettier: 9.1.2(eslint@8.57.1) - eslint-plugin-prettier@5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@9.1.2(eslint@9.39.4(jiti@1.21.7)))(eslint@9.39.4(jiti@1.21.7))(prettier@3.5.3): dependencies: eslint: 9.39.4(jiti@1.21.7) @@ -21876,36 +21670,10 @@ snapshots: '@types/eslint': 9.6.1 eslint-config-prettier: 9.1.2(eslint@9.39.4(jiti@1.21.7)) - eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - eslint-plugin-react-hooks@5.2.0(eslint@9.39.4(jiti@1.21.7)): dependencies: eslint: 9.39.4(jiti@1.21.7) - eslint-plugin-react@7.37.5(eslint@8.57.1): - dependencies: - array-includes: 3.1.9 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.3 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.3.1 - eslint: 8.57.1 - estraverse: 5.3.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.5 - object.entries: 1.1.9 - object.fromentries: 2.0.8 - object.values: 1.2.1 - prop-types: 15.8.1 - resolve: 2.0.0-next.6 - semver: 6.3.1 - string.prototype.matchall: 4.0.12 - string.prototype.repeat: 1.0.0 - eslint-plugin-react@7.37.5(eslint@9.39.4(jiti@1.21.7)): dependencies: array-includes: 3.1.9 @@ -27080,19 +26848,10 @@ snapshots: trim-newlines@3.0.1: {} - ts-api-utils@2.4.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - ts-api-utils@2.4.0(typescript@6.0.3): dependencies: typescript: 6.0.3 - ts-declaration-location@1.0.7(typescript@5.9.3): - dependencies: - picomatch: 4.0.3 - typescript: 5.9.3 - ts-declaration-location@1.0.7(typescript@6.0.3): dependencies: picomatch: 4.0.3 diff --git a/tools/.eslintrc.js b/tools/.eslintrc.js deleted file mode 100644 index 4435e42674e0f1..00000000000000 --- a/tools/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - root: true, - extends: ['universe/node'], - plugins: ['lodash'], - ignorePatterns: ['**/build', '**/cache', '**/node_modules'], - rules: { - 'lodash/import-scope': [2, 'method'], - // note(simek): I'm not brave enough to touch the RegExps I did not write, - // if you are, feel free to remove line below and fix the reported issues - 'no-useless-escape': 0, - }, -}; diff --git a/tools/bin/expotools.js b/tools/bin/expotools.js index 47108fa641dac2..8c35ba04650fff 100755 --- a/tools/bin/expotools.js +++ b/tools/bin/expotools.js @@ -1,5 +1,4 @@ 'use strict'; -/* eslint-env node */ // This script is just a wrapper around expotools that ensures node modules are installed // and TypeScript files are compiled. To make it work even when node_modules are empty, diff --git a/tools/eslint.config.mjs b/tools/eslint.config.mjs new file mode 100644 index 00000000000000..0bf5780b21517a --- /dev/null +++ b/tools/eslint.config.mjs @@ -0,0 +1,20 @@ +// https://docs.expo.dev/guides/using-eslint/ +import { defineConfig, globalIgnores } from 'eslint/config'; +import universeNodeConfig from 'eslint-config-universe/flat/node.js'; +import lodash from 'eslint-plugin-lodash'; + +export default defineConfig([ + globalIgnores(['**/build', '**/cache', '**/node_modules']), + universeNodeConfig, + { + plugins: { + lodash, + }, + rules: { + 'lodash/import-scope': [2, 'method'], + // note(simek): I'm not brave enough to touch the RegExps I did not write, + // if you are, feel free to remove line below and fix the reported issues + 'no-useless-escape': 0, + }, + }, +]); diff --git a/tools/package.json b/tools/package.json index 7f119180bb4408..c2e57c19bf650a 100644 --- a/tools/package.json +++ b/tools/package.json @@ -86,8 +86,8 @@ "@types/npm-registry-fetch": "^8.0.7", "@types/semver": "^7.5.8", "@types/uuid": "^9.0.2", - "eslint": "^8.57.1", - "eslint-config-universe": "^14.0.0", + "eslint": "^9.39.4", + "eslint-config-universe": "workspace:^15.0.3", "eslint-plugin-lodash": "^7.4.0", "prettier": "^3.3.3", "taskr": "1.1.0", diff --git a/tools/src/NpmOtp.ts b/tools/src/NpmOtp.ts index a1e678867534d1..6f67df28de17be 100644 --- a/tools/src/NpmOtp.ts +++ b/tools/src/NpmOtp.ts @@ -30,7 +30,6 @@ export async function promptOtp(): Promise { * succeeds or a non-OTP error is thrown. */ export async function withOtpRetry(fn: () => Promise): Promise { - // eslint-disable-next-line no-constant-condition while (true) { try { await fn(); diff --git a/tools/src/android-update-native-dependencies/updateGradleFiles.ts b/tools/src/android-update-native-dependencies/updateGradleFiles.ts index 826dc6b67b6db1..63e727016d9426 100644 --- a/tools/src/android-update-native-dependencies/updateGradleFiles.ts +++ b/tools/src/android-update-native-dependencies/updateGradleFiles.ts @@ -47,7 +47,7 @@ function replaceVersionInGradleFile( }); // val PUBG_API_WRAPPER by extra("0.8.1") - // eslint-disable-next-line no-useless-escape + const regexKotlinValExtra = new RegExp(`${variableName}.+\(("|')${oldVersion}("|')\)`); regexKotlinValExtra .exec(modifiedBody) diff --git a/tools/src/check-packages/checkDependenciesAsync.ts b/tools/src/check-packages/checkDependenciesAsync.ts index ec641f67fac5c9..5e635d7de027b2 100644 --- a/tools/src/check-packages/checkDependenciesAsync.ts +++ b/tools/src/check-packages/checkDependenciesAsync.ts @@ -13,7 +13,7 @@ import { DependencyKind, type PackageDependency, type Package } from '../Package type PackageCheckType = ActionOptions['checkPackageType']; -/** The three levels of of which dangerous dependencies are allowed. +/** The three levels of which dangerous dependencies are allowed. * @remarks * We can configure selectively invalid dependencies to be allowed in `SPECIAL_DEPENDENCIES` below. * - `types-only` means we allow any type-only import diff --git a/tools/src/commands/BumpReactNativeVersion.ts b/tools/src/commands/BumpReactNativeVersion.ts index f96ad1b8a1f0b8..b00411e2e2e3c7 100644 --- a/tools/src/commands/BumpReactNativeVersion.ts +++ b/tools/src/commands/BumpReactNativeVersion.ts @@ -158,7 +158,6 @@ async function updateBundledNativeModules(newVersion: string): Promise { async function podInstallAsync(cwd: string): Promise { const depsToUpdate = new Set(); - // eslint-disable-next-line no-constant-condition while (true) { try { if (depsToUpdate.size > 0) { diff --git a/tools/src/commands/CheckSdkPrsCommand.ts b/tools/src/commands/CheckSdkPrsCommand.ts index 5a7ae75c1a23e5..f282e32b5b0a30 100644 --- a/tools/src/commands/CheckSdkPrsCommand.ts +++ b/tools/src/commands/CheckSdkPrsCommand.ts @@ -147,7 +147,7 @@ function formatPublishInfo(info: PublishInfo): string { } // Matches SGR codes (\x1b[...m) and OSC 8 hyperlinks (\x1b]8;;...\x07) -// eslint-disable-next-line no-control-regex + const ANSI_RE = /\x1b\[[0-9;]*m|\x1b\]8;;[^\x07]*\x07/g; function pad(str: string, width: number): string {