Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
- name: Lint
run: yarn lint

- name: Prettier
run: yarn prettier
- name: Format
run: yarn format:check

typecheck:
runs-on: ubuntu-latest
Expand Down
15 changes: 15 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"sortImports": {
"groups": [
"side_effect",
["builtin", "external", "internal", "subpath", "unknown"],
["parent", "sibling", "index"]
]
},
"sortPackageJson": false,
"ignorePatterns": ["node_modules/", ".yarn", "codemods/**/tests/fixtures/**"]
}
3 changes: 0 additions & 3 deletions .prettierignore

This file was deleted.

2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- `yarn test:ci`
- `yarn typecheck`
- `yarn lint`
- `yarn prettier`
- `yarn format:check`
- `yarn build`
- `yarn validate`
- Task-specific guidance:
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ Our pre-commit hooks verify that your commit message matches this format when co

### Linting and tests

We use TypeScript for type checking, `eslint` with `prettier` for linting and formatting the code, and `jest` for testing. Our pre-commit hooks verify that the linter and tests pass when committing. You can also run the following commands manually:
We use TypeScript for type checking, `eslint` and `oxfmt` for linting and formatting the code, and `jest` for testing. Our pre-commit hooks verify that the linter and tests pass when committing. You can also run the following commands manually:

- `yarn typecheck`: run TypeScript compiler on all files.
- `yarn lint`: run eslint and prettier.
- `yarn lint`: run eslint.
- `yarn test`: run tests.

### Sending a pull request
Expand Down
4 changes: 2 additions & 2 deletions agents/build-and-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
- Run tests in CI mode: `yarn test:ci`
- Type check: `yarn typecheck`
- Lint source files: `yarn lint`
- Check formatting: `yarn prettier`
- Check formatting: `yarn format:check`
- Validate the main package: `yarn validate`
- Build the package: `yarn build`

## Command notes

- `yarn lint` runs ESLint on `src`.
- `yarn validate` runs typecheck, tests, lint, and Prettier checks for the main package.
- `yarn validate` runs typecheck, tests, lint, and oxfmt checks for the main package.
- `yarn build` cleans `dist/`, transpiles source with Babel, and emits TypeScript declarations.

## Repo layout
Expand Down
4 changes: 2 additions & 2 deletions agents/code-style.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

- ESLint uses `@callstack/eslint-config` together with `typescript-eslint`.
- Important enforced rules include `no-console` and consistent type imports.
- Prettier is the formatter.
- oxfmt is the formatter.
- Formatting defaults include single quotes and trailing commas.

## Imports

- Keep imports sorted with `eslint-plugin-simple-import-sort`.
- Keep imports sorted with `oxfmt`.
29 changes: 22 additions & 7 deletions codemods/v14-async-functions/scripts/codemod.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Edit, SgNode } from '@codemod.com/jssg-types/main';
import type { Transform } from 'codemod:ast-grep';
import type TSX from 'codemod:ast-grep/langs/tsx';
import type { Edit, SgNode } from '@codemod.com/jssg-types/main';

const FUNCTIONS_TO_MAKE_ASYNC = new Set(['render', 'renderHook', 'act', 'fireEvent']);
const FIRE_EVENT_METHODS_TO_MAKE_ASYNC = new Set(['press', 'changeText', 'scroll']);
Expand Down Expand Up @@ -241,10 +241,16 @@ function extractImportedFunctionNames(
edits: Edit[],
): {
importedFunctions: Set<string>;
specifiersToRemove: Array<{ specifier: SgNode<TSX>; importStmt: SgNode<TSX> }>;
specifiersToRemove: Array<{
specifier: SgNode<TSX>;
importStmt: SgNode<TSX>;
}>;
} {
const importedFunctions = new Set<string>();
const specifiersToRemove: Array<{ specifier: SgNode<TSX>; importStmt: SgNode<TSX> }> = [];
const specifiersToRemove: Array<{
specifier: SgNode<TSX>;
importStmt: SgNode<TSX>;
}> = [];

for (const importStmt of rntlImports) {
const importClause = importStmt.find({
Expand Down Expand Up @@ -332,7 +338,10 @@ function extractImportedFunctionNames(
* @param edits - Array to collect edit operations
*/
function removeDuplicateImportSpecifiers(
specifiersToRemove: Array<{ specifier: SgNode<TSX>; importStmt: SgNode<TSX> }>,
specifiersToRemove: Array<{
specifier: SgNode<TSX>;
importStmt: SgNode<TSX>;
}>,
rootNode: SgNode<TSX>,
edits: Edit[],
): void {
Expand Down Expand Up @@ -464,11 +473,17 @@ function findFireEventMethodCalls(
for (const [asyncName, syncName] of ASYNC_FUNCTIONS_TO_RENAME.entries()) {
if (syncName === 'fireEvent') {
const wasImported = rntlImports.some((importStmt) => {
const importClause = importStmt.find({ rule: { kind: 'import_clause' } });
const importClause = importStmt.find({
rule: { kind: 'import_clause' },
});
if (!importClause) return false;
const namedImports = importClause.find({ rule: { kind: 'named_imports' } });
const namedImports = importClause.find({
rule: { kind: 'named_imports' },
});
if (!namedImports) return false;
const specifiers = namedImports.findAll({ rule: { kind: 'import_specifier' } });
const specifiers = namedImports.findAll({
rule: { kind: 'import_specifier' },
});
return specifiers.some((spec) => {
const identifier = spec.find({ rule: { kind: 'identifier' } });
return identifier && identifier.text() === asyncName;
Expand Down
4 changes: 3 additions & 1 deletion docs/api/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,9 @@ expect(

// Include hidden elements
expect(
screen.getByText('Hidden from accessibility', { includeHiddenElements: true }),
screen.getByText('Hidden from accessibility', {
includeHiddenElements: true,
}),
).toBeOnTheScreen();
```

Expand Down
5 changes: 4 additions & 1 deletion docs/api/screen.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ You can also transform prop values so that they are more readable (e.g., flatten
import { StyleSheet } from 'react-native';

screen.debug({
mapProps: ({ style, ...props }) => ({ style: StyleSheet.flatten(style), ...props }),
mapProps: ({ style, ...props }) => ({
style: StyleSheet.flatten(style),
...props,
}),
});
```

Expand Down
17 changes: 2 additions & 15 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import tseslint from 'typescript-eslint';
import callstackConfig from '@callstack/eslint-config/react-native.flat.js';
import { fixupPluginRules } from '@eslint/compat';
import pluginJest from 'eslint-plugin-jest';
import simpleImportSort from 'eslint-plugin-simple-import-sort';
import tseslint from 'typescript-eslint';

const additionalTestBlockFunctions = ['testGateReact19_2'];

Expand All @@ -26,23 +25,11 @@ export default [
},
...patchedCallstackConfig,
...tseslint.configs.strict,
{
plugins: {
'simple-import-sort': simpleImportSort,
},
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [['^\\u0000', '^react', '^@?\\w', '^'], ['^\\.']],
},
],
},
},
{
rules: {
'no-console': 'error',
'import/order': 'off',
'prettier/prettier': 'off',
'@typescript-eslint/consistent-type-imports': 'error',
},
},
Expand Down
3 changes: 2 additions & 1 deletion examples/basic/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { LoginForm } from './components/LoginForm';

import { Home } from './components/Home';
import { LoginForm } from './components/LoginForm';

const App = () => {
const [user, setUser] = React.useState<string | null>(null);
Expand Down
3 changes: 2 additions & 1 deletion examples/basic/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { render, screen, userEvent } from '@testing-library/react-native';
import * as React from 'react';

import App from '../App';

jest.useFakeTimers();
Expand Down
1 change: 1 addition & 0 deletions examples/basic/components/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { StyleSheet, View, Text, TextInput, Pressable, ActivityIndicator } from 'react-native';

import { theme } from '../theme';

type Props = {
Expand Down
3 changes: 2 additions & 1 deletion examples/basic/components/__tests__/AnimatedView.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { act, render, screen } from '@testing-library/react-native';
import * as React from 'react';
import { Text } from 'react-native';
import { act, render, screen } from '@testing-library/react-native';

import { AnimatedView } from '../AnimatedView';

describe('AnimatedView', () => {
Expand Down
3 changes: 2 additions & 1 deletion examples/cookbook/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { Stack } from 'expo-router';
import * as React from 'react';

import theme from '../theme';

export default function RootLayout() {
Expand Down
3 changes: 2 additions & 1 deletion examples/cookbook/app/custom-render/WelcomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { useUser } from './providers/user-provider';

import { useTheme } from './providers/theme-provider';
import { useUser } from './providers/user-provider';

export default function WelcomeScreen() {
const theme = useTheme();
Expand Down
3 changes: 2 additions & 1 deletion examples/cookbook/app/custom-render/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { screen } from '@testing-library/react-native';
import * as React from 'react';

import WelcomeScreen from '../WelcomeScreen';
import { renderWithProviders } from './test-utils';

Expand Down
5 changes: 3 additions & 2 deletions examples/cookbook/app/custom-render/__tests__/test-utils.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import { render } from '@testing-library/react-native';
import { User, UserProvider } from '../../../app/custom-render/providers/user-provider';
import * as React from 'react';

import { Theme, ThemeProvider } from '../../../app/custom-render/providers/theme-provider';
import { User, UserProvider } from '../../../app/custom-render/providers/user-provider';

interface RenderWithProvidersProps {
user?: User | null;
Expand Down
3 changes: 2 additions & 1 deletion examples/cookbook/app/custom-render/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { UserProvider } from './providers/user-provider';

import { ThemeProvider } from './providers/theme-provider';
import { UserProvider } from './providers/user-provider';
import WelcomeScreen from './WelcomeScreen';

export default function Example() {
Expand Down
9 changes: 7 additions & 2 deletions examples/cookbook/app/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useRouter } from 'expo-router';
import React from 'react';
import { FlatList, Image, Pressable, StyleSheet, Text, View } from 'react-native';
import { useRouter } from 'expo-router';

import theme from '../theme';

// React Native static assets are resolved via require().
Expand Down Expand Up @@ -86,5 +87,9 @@ type Recipe = {
const recipes: Recipe[] = [
{ id: 1, title: 'Welcome Screen with Custom Render', path: 'custom-render/' },
{ id: 2, title: 'Task List with Jotai', path: 'state-management/jotai/' },
{ id: 3, title: 'Phone book with\na Variety of Net. Req. Methods', path: 'network-requests/' },
{
id: 3,
title: 'Phone book with\na Variety of Net. Req. Methods',
path: 'network-requests/',
},
];
7 changes: 4 additions & 3 deletions examples/cookbook/app/network-requests/PhoneBook.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useEffect, useState } from 'react';
import { Text } from 'react-native';
import { User } from './types';
import ContactsList from './components/ContactsList';
import FavoritesList from './components/FavoritesList';

import getAllContacts from './api/getAllContacts';
import getAllFavorites from './api/getAllFavorites';
import ContactsList from './components/ContactsList';
import FavoritesList from './components/FavoritesList';
import { User } from './types';

export default () => {
const [usersData, setUsersData] = useState<User[]>([]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react-native';
import React from 'react';

import PhoneBook from '../PhoneBook';
import {
mockServerFailureForGetAllContacts,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { User } from '../types';
import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';

import { User } from '../types';

// Define request handlers and response resolvers for random user API.
// By default, we always return the happy path response.
const handlers = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FlatList, Image, StyleSheet, Text, View } from 'react-native';
import React, { useCallback } from 'react';
import type { ListRenderItem } from '@react-native/virtualized-lists';
import React, { useCallback } from 'react';
import { FlatList, Image, StyleSheet, Text, View } from 'react-native';

import { User } from '../types';

export default ({ users }: { users: User[] }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FlatList, Image, StyleSheet, Text, View } from 'react-native';
import React, { useCallback } from 'react';
import type { ListRenderItem } from '@react-native/virtualized-lists';
import React, { useCallback } from 'react';
import { FlatList, Image, StyleSheet, Text, View } from 'react-native';

import { User } from '../types';

export default ({ users }: { users: User[] }) => {
Expand Down Expand Up @@ -55,5 +56,9 @@ const styles = StyleSheet.create({
borderColor: '#9b6dff',
borderWidth: 2,
},
loaderContainer: { height: 52, justifyContent: 'center', alignItems: 'center' },
loaderContainer: {
height: 52,
justifyContent: 'center',
alignItems: 'center',
},
});
1 change: 1 addition & 0 deletions examples/cookbook/app/network-requests/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';

import PhoneBook from './PhoneBook';

export default function Example() {
Expand Down
4 changes: 3 additions & 1 deletion examples/cookbook/app/state-management/jotai/TaskList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import 'react-native-get-random-values';

import { useAtom } from 'jotai';
import { nanoid } from 'nanoid';
import * as React from 'react';
import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
import { useAtom } from 'jotai';

import { newTaskTitleAtom, tasksAtom } from './state';

export function TaskList() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import * as React from 'react';
import { render, screen, userEvent } from '@testing-library/react-native';
import * as React from 'react';

import { addTask, getAllTasks, newTaskTitleAtom, store, tasksAtom } from '../state';
import { TaskList } from '../TaskList';
import { Task } from '../types';
import { addTask, getAllTasks, newTaskTitleAtom, store, tasksAtom } from '../state';
import { renderWithAtoms } from './test-utils';

jest.useFakeTimers();
Expand Down
Loading
Loading