Skip to content

Commit fa175d3

Browse files
committed
Dedup and prefer remix package exports
1 parent f912647 commit fa175d3

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

docs/generate.ts

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import packageJson from '../packages/remix/package.json' with { type: 'json' }
66
import * as prettier from 'prettier'
77

88
// TODO:
9-
// - Handle preferring exports from remix package versus others
9+
// - Handle sub-modules: `import { createCookie } from 'remix/cookie'`
10+
// - Handle alias re-exports: `export { openFile as getFile } `
1011

11-
/***** Types *****/
12+
//#region Types
1213

1314
// Function parameter or Class property
1415
type ParameterOrProperty = {
@@ -51,10 +52,10 @@ type DocumentedAPI = DocumentedFunction | DocumentedClass
5152

5253
type Maps = {
5354
comments: Map<string, typedoc.Reflection> // full name => TypeDoc Reflection
54-
apisToDocument: Set<string> // APIS we should generate docs for
55+
apisToDocument: Set<string> // APIs we should generate docs for
5556
}
5657

57-
/***** CLI *****/
58+
//#region CLI
5859

5960
let { values: cliArgs } = util.parseArgs({
6061
options: {
@@ -102,14 +103,17 @@ async function main() {
102103
let project = await loadTypedocJson()
103104
let { comments, apisToDocument } = createLookupMaps(project)
104105

106+
// Prefer `remix` package exports over other package exports
107+
getDuplicateAPIS(apisToDocument).forEach((dup) => apisToDocument.delete(dup))
108+
105109
// Parse JSDocs into DocumentedAPI instances we can write out to markdown
106110
let documentedAPIs = [...apisToDocument].map((name) => getDocumentedAPI(comments.get(name)!))
107111

108112
// Write out docs
109113
await writeMarkdownFiles(documentedAPIs)
110114
}
111115

112-
/***** TypeDoc *****/
116+
//#region TypeDoc Loading
113117

114118
// Load the TypeDoc JSON representation, either from a JSON file or by running
115119
// TypeDoc against the project
@@ -223,6 +227,43 @@ function createLookupMaps(reflection: typedoc.ProjectReflection): Maps {
223227
}
224228
}
225229

230+
// Deduplicate APIs that are exported from multiple packages, preferring the remix package
231+
function getDuplicateAPIS(apisToDocument: Set<string>): Set<string> {
232+
let apisByName = new Map<string, string[]>()
233+
let duplicates = new Set<string>()
234+
235+
// Group APIs by short name
236+
for (let fullName of apisToDocument) {
237+
let apiName = fullName.split('.').slice(0, -1)[0]
238+
apisByName.set(apiName, [...(apisByName.get(apiName) || []), fullName])
239+
}
240+
241+
// Process each group of APIs with the same name
242+
for (let [apiName, fullNames] of apisByName) {
243+
if (fullNames.length <= 1) {
244+
continue
245+
}
246+
247+
let remixAPI = fullNames.find((name) => name.split('.')[0] === 'remix')
248+
let nonRemixAPIs = fullNames.filter((name) => name.split('.')[0] !== 'remix')
249+
250+
if (remixAPI && nonRemixAPIs.length > 0) {
251+
// Remove non-remix APIs, keep the remix one
252+
for (let api of nonRemixAPIs) {
253+
log(`Preferring remix export for ${apiName}, removing: ${api}`)
254+
duplicates.add(api)
255+
}
256+
} else if (!remixAPI && fullNames.length > 1) {
257+
// Multiple non-remix packages export this API
258+
warn(`Multiple packages export ${apiName} but none is remix: ${fullNames.join(', ')}`)
259+
}
260+
}
261+
262+
return duplicates
263+
}
264+
265+
//#region DocumentedAPI
266+
226267
// Convert a typedoc reflection for a given node into a documentable instance
227268
function getDocumentedAPI(node: typedoc.Reflection): DocumentedAPI {
228269
try {
@@ -456,7 +497,7 @@ function processComment(parts: typedoc.CommentDisplayPart[]): string {
456497
}, '')
457498
}
458499

459-
/***** Markdown Generation ****/
500+
//#region Markdown
460501

461502
async function writeMarkdownFiles(comments: DocumentedAPI[]) {
462503
for (let comment of comments) {
@@ -554,7 +595,7 @@ async function getClassMarkdown(comment: DocumentedClass): Promise<string> {
554595
.join('\n\n')
555596
}
556597

557-
/***** Utils *****/
598+
//#region utils
558599

559600
function log(...args: unknown[]) {
560601
console.log(...args)
@@ -574,7 +615,7 @@ function invariant(condition: unknown, message?: string): asserts condition {
574615
}
575616
}
576617

577-
/***** Reference ****/
618+
//#region Reference
578619

579620
// export declare enum ReflectionKind {
580621
// Project = 1,

docs/server.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ async function discoverMarkdownFiles(): Promise<DocFile[]> {
4343
walk(fullPath)
4444
} else if (entry.isFile() && entry.name.endsWith('.md')) {
4545
let relativePath = path.relative(DOCS_DIR, fullPath)
46-
let packageName = pkgMap[relativePath.split(path.sep)[0]]
46+
let parts = relativePath.split(path.sep)
47+
let packageName = parts.slice(0, parts.length - 1).join('/')
4748
let urlPath = '/docs/' + relativePath.replace(/\.md$/, '').replace(/\\/g, '/')
4849

4950
files.push({
@@ -74,11 +75,21 @@ function buildNavigation(currentPath: string): string {
7475

7576
let navItems: string[] = []
7677

77-
for (let [packageName, files] of Array.from(packageGroups.entries()).sort((a, b) => {
78-
if (a[0] === 'remix') return -1
79-
if (b[0] === 'remix') return 1
78+
let comparator = (a, b) => {
79+
// remix above remix/*
80+
if (a[0] === 'remix' && b[0].startsWith('remix/')) return -1
81+
if (b[0] === 'remix' && a[0].startsWith('remix/')) return 1
82+
// remix/* alphabetical
83+
if (a[0].startsWith('remix/') && b[0].startsWith('remix/')) return a[0].localeCompare(b[0])
84+
// remix and remix/* above all others
85+
if (a[0] === 'remix' || a[0].startsWith('remix/')) return -1
86+
if (b[0] === 'remix' || b[0].startsWith('remix/')) return 1
87+
// Everything else alphabetical
8088
return a[0].localeCompare(b[0])
81-
})) {
89+
}
90+
let sortedNavItems = Array.from(packageGroups.entries()).sort(comparator)
91+
92+
for (let [packageName, files] of sortedNavItems) {
8293
let fileLinks = files
8394
.map((file) => {
8495
let isActive = currentPath === file.urlPath

packages/remix/src/cookie.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { createCookie } from '@remix-run/cookie'
1+
export { createCookie, Cookie } from '@remix-run/cookie'

0 commit comments

Comments
 (0)