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
25 changes: 19 additions & 6 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import React from 'react';
import { StyleSheet as RnStylesheet } from 'react-native';
import { StyleSheet as RNStylesheet, View } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { KeyboardProvider } from 'react-native-keyboard-controller';
import { StyleSheet } from 'react-native-unistyles';
import {
PortalProvider as TeleportProvider,
PortalHost,
} from 'react-native-teleport';
import { QueryClientProvider } from '@tanstack/react-query';
import { Toaster } from 'sonner-native';
import { ReducedMotionConfig, ReduceMotion } from 'react-native-reanimated';
Expand Down Expand Up @@ -40,21 +44,30 @@ export const App: React.FC = () => {
<SafeAreaProvider>
<QueryClientProvider client={queryClient}>
<ModalProvider stack={modalStack}>
<EventEmitterProvider>
<RootNavigator />
</EventEmitterProvider>
<TeleportProvider>
<EventEmitterProvider>
<View style={styles.overlay} pointerEvents="box-none">
<PortalHost name="overlay" />
</View>
<RootNavigator />
</EventEmitterProvider>
</TeleportProvider>
</ModalProvider>
</QueryClientProvider>
<Toaster position="top-center" />
<Toaster position="top-center" visibleToasts={1} />
</SafeAreaProvider>
</GestureHandlerRootView>
</KeyboardProvider>
</LanguageProvider>
);
};

const styles = RnStylesheet.create({
const styles = RNStylesheet.create({
layout: {
flex: 1,
},
overlay: {
...RNStylesheet.absoluteFillObject,
zIndex: 9999,
},
});
6 changes: 0 additions & 6 deletions metro.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;

/**
* Metro configuration
* https://reactnative.dev/docs/metro
*
* @type {import('metro-config').MetroConfig}
*/
const config = {
transformer: {
babelTransformerPath: require.resolve(
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"prepare": "husky"
},
"dependencies": {
"@gorhom/portal": "^1.0.14",
"@legendapp/state": "^3.0.0-beta.30",
"@react-native-vector-icons/icomoon": "^12.2.0",
"@react-navigation/bottom-tabs": "7.2.0",
Expand Down Expand Up @@ -57,6 +56,7 @@
"react-native-safe-area-context": "5.6.0",
"react-native-screens": "4.14.0",
"react-native-svg": "15.12.1",
"react-native-teleport": "^0.3.0",
"react-native-unistyles": "3.0.10",
"react-native-vector-icons": "10.2.0",
"sonner-native": "0.21.1",
Expand All @@ -74,10 +74,10 @@
"@react-native/eslint-config": "0.79.0",
"@react-native/metro-config": "0.79.0",
"@react-native/typescript-config": "0.79.0",
"@rozenite/metro": "1.0.0-alpha.12",
"@rozenite/mmkv-plugin": "1.0.0-alpha.12",
"@rozenite/network-activity-plugin": "1.0.0-alpha.12",
"@rozenite/tanstack-query-plugin": "1.0.0-alpha.12",
"@rozenite/metro": "1.0.0-alpha.14",
"@rozenite/mmkv-plugin": "1.0.0-alpha.14",
"@rozenite/network-activity-plugin": "1.0.0-alpha.14",
"@rozenite/tanstack-query-plugin": "1.0.0-alpha.14",
"@svgr/cli": "^8.1.0",
"@types/react": "^19.1.2",
"@types/react-native-vector-icons": "^6.4.18",
Expand Down
65 changes: 24 additions & 41 deletions scripts/api-codegen/check-generics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,50 +49,33 @@ std::string readFileContent(const std::filesystem::path &filePath) {
return buffer.str();
}

void validateEndpoints(const std::filesystem::path &filePath,
const std::string &fileContent) {
std::regex endpointsBlockPattern(
R"(endpoints:\s*builder\s*=>\s*\(\{[^}]+\}\))");
std::regex endpointPattern(
R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|getAsMutation|post|postAsQuery|delete|put|patch|paginate|paginateAsPrefetch)\s*(<[^>]+>)?\s*\()");

std::smatch endpointsMatch;
if (!std::regex_search(fileContent, endpointsMatch, endpointsBlockPattern)) {
std::cout << "⚠️ No endpoints found in file: " << filePath << "\n";
void validateCreateApiUsage(const std::filesystem::path &filePath,
const std::string &fileContent) {
// Pattern to match createApi<SomeInterface>()
std::regex createApiPattern(
R"(createApi<([a-zA-Z0-9_]+)>\(\)\()");

std::smatch match;
if (!std::regex_search(fileContent, match, createApiPattern)) {
std::cout << "⚠️ No createApi usage found in file: " << filePath << "\n";
return;
}

std::sregex_iterator iter(fileContent.begin(), fileContent.end(),
endpointPattern);
std::sregex_iterator end;

if (iter == end) {
std::cout << "⚠️ No endpoints found in file: " << filePath << "\n";
std::string interfaceName = match[1].str();

// Check if the interface is defined in the same file
std::regex interfacePattern(
R"(interface\s+)" + interfaceName + R"(\s*\{)");

if (!std::regex_search(fileContent, interfacePattern)) {
std::cerr << "❌ Error: Interface '" << interfaceName << "' used in createApi<"
<< interfaceName << "> is not defined in file '" << filePath << "'.\n";
std::cerr << "πŸ’‘ Hint: Make sure to define the interface that describes all endpoints.\n";
ERROR_FOUND = true;
return;
}

while (iter != end) {
std::smatch match = *iter;
std::string endpointName = match[1].str();
std::string generics = match[3].str();

if (generics.empty()) {
std::cerr << "❌ Error: Endpoint '" << endpointName << "' in file '"
<< filePath << "' is missing generics (no < >).\n";
ERROR_FOUND = true;
} else {
std::regex genericSplitPattern(R"(<([^,>]+),([^,>]+)>)");
std::smatch genericsMatch;
if (!std::regex_match(generics, genericsMatch, genericSplitPattern)) {
std::cerr << "❌ Error: Endpoint '" << endpointName << "' in file '"
<< filePath
<< "' has incorrect generics format (missing a comma or "
"second generic).\n";
ERROR_FOUND = true;
}
}
++iter;
}
std::cout << "βœ… Found valid createApi<" << interfaceName << "> with interface definition.\n";
}

int main() {
Expand Down Expand Up @@ -123,7 +106,7 @@ int main() {

std::cout << "⏳ Processing file: " << path << "\n";
std::string fileContent = readFileContent(path);
validateEndpoints(path, fileContent);
validateCreateApiUsage(path, fileContent);
}
}
}
Expand All @@ -138,8 +121,8 @@ int main() {
return 1;
}

std::cout << "\nπŸŽ‰ No errors found. You passed all necessary generics!\n";
std::cout << "βœ… Generics check completed.\n";
std::cout << "\nπŸŽ‰ No errors found. All createApi interfaces are properly defined!\n";
std::cout << "βœ… Interface validation completed.\n";

return 0;
}
Empty file modified scripts/api-codegen/compile-all.sh
100644 β†’ 100755
Empty file.
65 changes: 42 additions & 23 deletions scripts/api-codegen/query-keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,51 +70,70 @@ void extractEndpoints(
std::vector<std::pair<std::string, std::string>> &queryEndpoints,
std::vector<std::string> &mutationEndpoints) {

std::regex endpointPattern(
R"(([a-zA-Z0-9_]+):\s*builder\.(get|getAsPrefetch|paginate|paginateAsPrefetch|post|postAsQuery|delete|put|patch|getAsMutation)<([^>]+)>\([^)]*\))");

std::sregex_iterator iter(fileContent.begin(), fileContent.end(), endpointPattern);
// First, find the interface that defines the API
std::regex createApiPattern(R"(createApi<([a-zA-Z0-9_]+)>\(\))");
std::smatch createApiMatch;

if (!std::regex_search(fileContent, createApiMatch, createApiPattern)) {
return; // No createApi found
}

std::string interfaceName = createApiMatch[1].str();

// Find the interface definition
std::regex interfacePattern(
R"(interface\s+)" + interfaceName + R"(\s*\{([^}]+)\})");
std::smatch interfaceMatch;

if (!std::regex_search(fileContent, interfaceMatch, interfacePattern)) {
return; // Interface not found
}

std::string interfaceContent = interfaceMatch[1].str();

// Extract endpoint definitions from interface (e.g., "getUser: Promisify<Test, CreateAccountResponse[]>;")
std::regex endpointDefPattern(
R"(([a-zA-Z0-9_]+):\s*Promisify<([^,]+),\s*([^>]+)>)");

std::sregex_iterator iter(interfaceContent.begin(), interfaceContent.end(), endpointDefPattern);
std::sregex_iterator end;

while (iter != end) {
std::smatch match = *iter;
std::string endpointName = match[1].str();
std::string method = match[2].str();
std::string fullGeneric = match[3].str();

std::stringstream ss(fullGeneric);
std::string responseType, requestType;
std::getline(ss, responseType, ',');
std::getline(ss, requestType, ',');

responseType.erase(
remove_if(responseType.begin(), responseType.end(), ::isspace),
responseType.end());
std::string requestType = match[2].str();
std::string responseType = match[3].str();

// Clean up whitespace
requestType.erase(
remove_if(requestType.begin(), requestType.end(), ::isspace),
requestType.end());

bool isMutation = method == "post" || method == "postAsQuery" || method == "delete" ||
method == "put" || method == "patch" || method == "getAsMutation";

responseType.erase(
remove_if(responseType.begin(), responseType.end(), ::isspace),
responseType.end());

// Check if it's a mutation by looking at the actual builder usage
std::regex mutationPattern(endpointName + R"(:\s*builder\.mutation\s*\()");
bool isMutation = std::regex_search(fileContent, mutationPattern);

if (!requestType.empty() && requestType != "void" &&
requestType != "unknown" && requestType != "null" &&
requestType != "any" && requestType != "boolean" &&
requestType != "string" && requestType != "true" &&
requestType != "false" && requestType != "Object" &&
requestType != "{}" && requestType != "0" && requestType != "1" &&
requestType != "BigInt" && requestType != "[]") {
if (!isMutation && std::find(usedInterfaces.begin(), usedInterfaces.end(), requestType) == usedInterfaces.end()) {
if (std::find(usedInterfaces.begin(), usedInterfaces.end(), requestType) == usedInterfaces.end()) {
usedInterfaces.push_back(requestType);
}
}

if (isMutation) {
mutationEndpoints.push_back(endpointName);
} else {
queryEndpoints.push_back({endpointName, requestType});
}

++iter;
}
}
Expand Down
Loading