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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions apps/src/tests/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const path = require('path');
const Module = require('module');

const pluginPath = require.resolve(
path.join(__dirname, 'eslint-plugin-local-rules'),
);
const originalResolve = Module._resolveFilename;
Module._resolveFilename = function (request, ...args) {
if (request === 'eslint-plugin-local-rules') {
return pluginPath;
}
return originalResolve.call(this, request, ...args);
};

Comment on lines +1 to +14
module.exports = {
overrides: [
{
files: [
'single-feature-tests/**/*.tsx',
'single-feature-tests/**/*.ts',
'component-integration-tests/**/*.tsx',
'component-integration-tests/**/*.ts',
],
plugins: ['local-rules'],
rules: {
'local-rules/require-top-level-exports': 'error',
},
},
],
};
2 changes: 1 addition & 1 deletion apps/src/tests/component-integration-tests/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type ParamsList = { [k: keyof typeof COMPONENT_SCENARIOS]: undefined } & {
Home: undefined;
};

function HomeScreen() {
export function HomeScreen() {
return (
<ScrollView contentInsetAdjustmentBehavior="automatic">
{Object.entries(COMPONENT_SCENARIOS).map(([key, scenarioGroup]) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const scenarioDescription: ScenarioDescription = {
platforms: ['ios'],
};

function ConfigScreen() {
export function ConfigScreen() {
const {
routeKey: tabRouteKey,
routeOptions: tabRouteOptions,
Expand Down Expand Up @@ -70,7 +70,7 @@ const STACK_ROUTE_CONFIGS: StackRouteConfig[] = [
},
];

function StackScreen() {
export function StackScreen() {
return <StackContainer routeConfigs={STACK_ROUTE_CONFIGS} />;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const scenarioDescription: ScenarioDescription = {
platforms: ['ios'],
};

function ConfigScreen() {
export function ConfigScreen() {
const {
routeKey: stackRouteKey,
routeOptions: stackRouteOptions,
Expand Down Expand Up @@ -81,7 +81,7 @@ const TAB_ROUTE_CONFIGS: TabRouteConfig[] = [
},
];

function TabsScreen() {
export function TabsScreen() {
return <TabsContainer routeConfigs={TAB_ROUTE_CONFIGS} />;
}

Expand Down
5 changes: 5 additions & 0 deletions apps/src/tests/eslint-plugin-local-rules/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
rules: {
'require-top-level-exports': require('./require-top-level-exports'),
},
};
6 changes: 6 additions & 0 deletions apps/src/tests/eslint-plugin-local-rules/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "eslint-plugin-local-rules",
"version": "1.0.0",
"private": true,
"main": "index.js"
}
101 changes: 101 additions & 0 deletions apps/src/tests/eslint-plugin-local-rules/require-top-level-exports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'Require top-level React component declarations to be exported',
},
schema: [],
messages: {
requireExport: 'Top-level component "{{name}}" must be exported.',
},
},
create(context) {
return {
Program(node) {
const exportedNames = collectExportedNames(node);

for (const stmt of node.body) {
const name = getComponentName(stmt);
if (name === null) {
continue;
}

if (!exportedNames.has(name)) {
context.report({
node: stmt,
messageId: 'requireExport',
data: { name },
});
}
}
},
};
},
};

function isPascalCase(name) {
return /^[A-Z]/.test(name);
}

function getComponentName(stmt) {
if (
stmt.type === 'FunctionDeclaration' &&
stmt.id?.name &&
isPascalCase(stmt.id.name)
) {
return stmt.id.name;
}

if (stmt.type === 'VariableDeclaration' && stmt.declarations.length === 1) {
const decl = stmt.declarations[0];
const name = decl.id?.name;
if (
name &&
isPascalCase(name) &&
decl.init &&
(decl.init.type === 'ArrowFunctionExpression' ||
decl.init.type === 'FunctionExpression')
) {
return name;
}
}
Comment on lines +51 to +63

return null;
}

function collectExportedNames(program) {
const names = new Set();

for (const stmt of program.body) {
if (stmt.type === 'ExportNamedDeclaration') {
if (stmt.declaration) {
for (const name of getDeclaredNames(stmt.declaration)) {
names.add(name);
}
}
for (const specifier of stmt.specifiers) {
names.add(specifier.local.name);
}
}

if (stmt.type === 'ExportDefaultDeclaration') {
const decl = stmt.declaration;
if (decl.type === 'Identifier') {
names.add(decl.name);
} else if (decl.id) {
names.add(decl.id.name);
}
}
}

return names;
}

function getDeclaredNames(stmt) {
if (stmt.type === 'VariableDeclaration') {
return stmt.declarations.map(d => d.id?.name).filter(Boolean);
}
return stmt.id?.name ? [stmt.id.name] : [];
}
2 changes: 1 addition & 1 deletion apps/src/tests/single-feature-tests/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type ParamsList = { [k: keyof typeof COMPONENT_SCENARIOS]: undefined } & {
Home: undefined;
};

function HomeScreen() {
export function HomeScreen() {
return (
<ScrollView contentInsetAdjustmentBehavior="automatic"
testID="single-feature-tests-scrollview">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function App() {
);
}

function ContentScreen() {
export function ContentScreen() {
return (
<View
style={[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function App() {
);
}

function ColumnContent(props: {
export function ColumnContent(props: {
columnTitle: string;
hostRef: React.RefObject<SplitHostCommands | null>;
}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function App() {
);
}

function ColumnContent(props: { columnTitle: string }) {
export function ColumnContent(props: { columnTitle: string }) {
return (
<View style={styles.container}>
<Text style={styles.columnTitle}>{props.columnTitle}</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type StackParamList = {
Screen1: undefined;
};

function ConfigScreen() {
export function ConfigScreen() {
const [config, dispatch] = useStackConfigState<StackParamList>();

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function App() {
);
}

function StackSetup() {
export function StackSetup() {
const toast = useToast();

return (
Expand Down Expand Up @@ -77,7 +77,7 @@ function StackSetup() {
);
}

function HomeScreen() {
export function HomeScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="Home" />
Expand All @@ -89,7 +89,7 @@ function HomeScreen() {
);
}

function AScreen() {
export function AScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.YellowLight40 }}>
<RouteInformation routeName="A" />
Expand All @@ -102,7 +102,7 @@ function AScreen() {
);
}

function BScreen() {
export function BScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.GreenLight100 }}>
<RouteInformation routeName="B" />
Expand All @@ -116,7 +116,7 @@ function BScreen() {
);
}

function NestedStackScreen() {
export function NestedStackScreen() {
const toast = useToast();

return (
Expand Down Expand Up @@ -168,7 +168,7 @@ function NestedStackScreen() {
);
}

function NestedHomeScreen() {
export function NestedHomeScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="NestedHome" />
Expand All @@ -182,7 +182,7 @@ function NestedHomeScreen() {
);
}

function NestedAScreen() {
export function NestedAScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="NestedA" />
Expand All @@ -195,7 +195,7 @@ function NestedAScreen() {
);
}

function NestedBScreen() {
export function NestedBScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="NestedB" />
Expand All @@ -209,7 +209,7 @@ function NestedBScreen() {
);
}

function RouteInformation(props: { routeName: string }) {
export function RouteInformation(props: { routeName: string }) {
const routeKey = useStackNavigationContext().routeKey;

return (
Expand All @@ -220,7 +220,7 @@ function RouteInformation(props: { routeName: string }) {
);
}

function TogglePreventNativeDismiss() {
export function TogglePreventNativeDismiss() {
const navigation = useStackNavigationContext();

return (
Expand All @@ -235,7 +235,7 @@ function TogglePreventNativeDismiss() {
);
}

function PreventNativeDismissInfo() {
export function PreventNativeDismissInfo() {
const navContext = useStackNavigationContext();

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function App() {
);
}

function StackSetup() {
export function StackSetup() {
const toast = useToast();

return (
Expand Down Expand Up @@ -69,7 +69,7 @@ function StackSetup() {
);
}

function HomeScreen() {
export function HomeScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.BlueLight40 }}>
<RouteInformation routeName="Home" />
Expand All @@ -78,7 +78,7 @@ function HomeScreen() {
);
}

function AScreen() {
export function AScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.YellowLight40 }}>
<RouteInformation routeName="A" />
Expand All @@ -88,7 +88,7 @@ function AScreen() {
);
}

function BScreen() {
export function BScreen() {
return (
<CenteredLayoutView style={{ backgroundColor: Colors.GreenLight100 }}>
<RouteInformation routeName="B" />
Expand All @@ -99,7 +99,7 @@ function BScreen() {
);
}

function RouteInformation(props: { routeName: string }) {
export function RouteInformation(props: { routeName: string }) {
const routeKey = useStackNavigationContext().routeKey;

return (
Expand All @@ -110,7 +110,7 @@ function RouteInformation(props: { routeName: string }) {
);
}

function TogglePreventNativeDismiss() {
export function TogglePreventNativeDismiss() {
const navigation = useStackNavigationContext();

return (
Expand All @@ -125,7 +125,7 @@ function TogglePreventNativeDismiss() {
);
}

function PreventNativeDismissInfo() {
export function PreventNativeDismissInfo() {
const navContext = useStackNavigationContext();

return (
Expand Down
Loading
Loading