Skip to content

Commit c4f1375

Browse files
committed
Merge branch 'main' into youssef_fix_event_firing_twice
2 parents f4c6f1a + 675a19a commit c4f1375

405 files changed

Lines changed: 16761 additions & 6369 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/scripts/createDocsRoutes.ts

Lines changed: 68 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type Section = {
1212
href: string;
1313
title: string;
1414
articles?: Article[];
15+
sections?: Section[];
1516
};
1617

1718
type Hub = {
@@ -60,16 +61,14 @@ function toTitleCase(str: string): string {
6061
}
6162

6263
/**
63-
* @param filename - The name of the file (path used for href)
64+
* @param filename - The name of the file
6465
* @param order - Optional order from front matter
65-
* @param titleOverride - Optional display title (e.g. subfolder name: "Export-Errors" -> "Export Errors")
6666
*/
67-
function getArticleObj(filename: string, order?: number, titleOverride?: string): Article {
67+
function getArticleObj(filename: string, order?: number): Article {
6868
const href = filename.replace('.md', '');
69-
const title = titleOverride ? toTitleCase(titleOverride.replaceAll('-', ' ')) : toTitleCase(href.replaceAll('-', ' '));
7069
return {
7170
href,
72-
title,
71+
title: toTitleCase(href.replaceAll('-', ' ')),
7372
order,
7473
};
7574
}
@@ -97,76 +96,87 @@ function pushOrCreateEntry<TKey extends HubEntriesKey>(hubs: Hub[], hub: string,
9796
}
9897

9998
function getOrderFromArticleFrontMatter(path: string): number | undefined {
100-
const frontmatter = fs.readFileSync(path, 'utf8').split('---').at(1);
101-
if (!frontmatter) {
102-
return;
99+
try {
100+
const frontmatter = fs.readFileSync(path, 'utf8').split('---').at(1);
101+
if (!frontmatter) {
102+
return undefined;
103+
}
104+
const frontmatterObject = yaml.load(frontmatter) as Record<string, unknown>;
105+
return frontmatterObject.order as number | undefined;
106+
} catch {
107+
return undefined;
103108
}
104-
const frontmatterObject = yaml.load(frontmatter) as Record<string, unknown>;
105-
return frontmatterObject.order as number | undefined;
109+
}
110+
111+
/**
112+
* Build a section from a directory path, with optional parent path for nested href
113+
*/
114+
function buildSection(platformName: string, hub: string, sectionPath: string, parentHref: string): Section {
115+
const sectionName = sectionPath.split('/').pop() ?? sectionPath;
116+
const fullPath = `${docsDir}/articles/${platformName}/${hub}/${sectionPath}`;
117+
const articles: Article[] = [];
118+
const childSections: Section[] = [];
119+
const href = parentHref ? `${parentHref}/${sectionName}` : sectionName;
120+
121+
for (const entry of fs.readdirSync(fullPath)) {
122+
const entryPath = `${fullPath}/${entry}`;
123+
if (entry.endsWith('.md')) {
124+
const order = getOrderFromArticleFrontMatter(entryPath);
125+
articles.push(getArticleObj(entry, order));
126+
} else if (fs.statSync(entryPath).isDirectory()) {
127+
childSections.push(buildSection(platformName, hub, `${sectionPath}/${entry}`, href));
128+
}
129+
}
130+
131+
const section: Section = {
132+
href,
133+
title: toTitleCase(sectionName.replaceAll('-', ' ')),
134+
...(articles.length > 0 && {articles}),
135+
...(childSections.length > 0 && {sections: childSections}),
136+
};
137+
return section;
138+
}
139+
140+
/**
141+
* Flatten sections for lookup by full path (e.g. netsuite/troubleshooting/connection-errors)
142+
*/
143+
function flattenSections(sections: Section[]): Section[] {
144+
const result: Section[] = [];
145+
for (const s of sections) {
146+
result.push(s);
147+
if (s.sections?.length) {
148+
result.push(...flattenSections(s.sections));
149+
}
150+
}
151+
return result;
106152
}
107153

108154
/**
109155
* Add articles and sections to hubs
110156
* @param hubs - The hubs inside docs/articles/ for a platform
111157
* @param platformName - Expensify Classic or New Expensify
112-
* @param routeHubs - The hubs insude docs/data/_routes.yml for a platform
158+
* @param routeHubs - The hubs inside docs/data/_routes.yml for a platform
113159
*/
114160
function createHubsWithArticles(hubs: string[], platformName: ValueOf<typeof platformNames>, routeHubs: Hub[]) {
115161
for (const hub of hubs) {
116-
// Iterate through each directory in articles
117-
for (const fileOrFolder of fs.readdirSync(`${docsDir}/articles/${platformName}/${hub}`)) {
118-
// If the directory content is a markdown file, then it is an article
162+
const basePath = `${docsDir}/articles/${platformName}/${hub}`;
163+
164+
for (const fileOrFolder of fs.readdirSync(basePath)) {
119165
if (fileOrFolder.endsWith('.md')) {
120166
const articleObj = getArticleObj(fileOrFolder);
121167
pushOrCreateEntry(routeHubs, hub, 'articles', articleObj);
122168
continue;
123169
}
124170

125-
// For readability, we will use the term section to refer to subfolders
126-
const section = fileOrFolder;
127-
const articles: Article[] = [];
128-
129-
// Section can contain .md files directly and/or subfolders (and nested subfolders) that contain .md files
130-
const sectionPath = `${docsDir}/articles/${platformName}/${hub}/${section}`;
131-
for (const entry of fs.readdirSync(sectionPath)) {
132-
const entryPath = `${sectionPath}/${entry}`;
133-
if (entry.endsWith('.md') && fs.statSync(entryPath).isFile()) {
134-
const order = getOrderFromArticleFrontMatter(entryPath);
135-
articles.push(getArticleObj(entry, order));
136-
continue;
137-
}
138-
if (fs.statSync(entryPath).isDirectory()) {
139-
// One level: section/SubFolder/file.md -> href "SubFolder/file", display title = "Troubleshoot SubFolder"
140-
for (const file of fs.readdirSync(entryPath)) {
141-
const filePath = `${entryPath}/${file}`;
142-
if (file.endsWith('.md') && fs.statSync(filePath).isFile()) {
143-
const order = getOrderFromArticleFrontMatter(filePath);
144-
articles.push(getArticleObj(`${entry}/${file}`, order, `Troubleshoot ${entry}`));
145-
continue;
146-
}
147-
if (fs.statSync(filePath).isDirectory()) {
148-
// Two levels: section/SubFolder/NestedFolder/file.md -> href "SubFolder/NestedFolder/file", display title = "Troubleshoot NestedFolder" (e.g. "Troubleshoot Export Errors")
149-
for (const nestedFile of fs.readdirSync(filePath)) {
150-
if (!nestedFile.endsWith('.md')) {
151-
continue;
152-
}
153-
const nestedPath = `${filePath}/${nestedFile}`;
154-
if (!fs.statSync(nestedPath).isFile()) {
155-
continue;
156-
}
157-
const order = getOrderFromArticleFrontMatter(nestedPath);
158-
articles.push(getArticleObj(`${entry}/${file}/${nestedFile}`, order, `Troubleshoot ${file}`));
159-
}
160-
}
161-
}
162-
}
163-
}
171+
const sectionPath = fileOrFolder;
172+
const section = buildSection(platformName, hub, sectionPath, '');
173+
pushOrCreateEntry(routeHubs, hub, 'sections', section);
174+
}
164175

165-
pushOrCreateEntry(routeHubs, hub, 'sections', {
166-
href: section,
167-
title: toTitleCase(section.replaceAll('-', ' ')),
168-
articles,
169-
});
176+
// Add flat section list for nested section page lookup
177+
const hubObj = routeHubs.find((obj) => obj.href === hub);
178+
if (hubObj?.sections?.length) {
179+
(hubObj as Hub & {flatSections?: Section[]}).flatSections = flattenSections(hubObj.sections);
170180
}
171181
}
172182
}

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009033400
115-
versionName "9.3.34-0"
114+
versionCode 1009033500
115+
versionName "9.3.35-0"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"

babel.config.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const webpack = {
6363
};
6464

6565
const metro = {
66-
presets: [require('@react-native/babel-preset')],
66+
presets: [[require('@react-native/babel-preset'), {disableImportExportTransform: true}]],
6767
plugins: [
6868
['babel-plugin-react-compiler', ReactCompilerConfig], // must run first!
6969

@@ -174,5 +174,14 @@ module.exports = (api) => {
174174
const runningIn = api.caller((args = {}) => args.name);
175175
console.debug(' - running in: ', runningIn);
176176

177-
return ['metro', 'babel-jest'].includes(runningIn) ? metro : webpack;
177+
// Jest runs in Node.js without Metro's experimentalImportSupport transform,
178+
// so Babel must handle import/export transforms for tests.
179+
if (runningIn === 'babel-jest') {
180+
return {
181+
...metro,
182+
presets: [[require('@react-native/babel-preset'), {disableImportExportTransform: false}]],
183+
};
184+
}
185+
186+
return runningIn === 'metro' ? metro : webpack;
178187
};

0 commit comments

Comments
 (0)