@mintlify/prebuild 1.0.1537 → 1.0.1539

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,11 @@
1
- import { parseGraphqlSelector, resolveGraphqlOperation, } from '@mintlify/common';
1
+ import { getNamedGraphqlType, parseGraphqlSelector, resolveGraphqlOperation, } from '@mintlify/common';
2
2
  import { parseGraphqlSdl } from '@mintlify/scraping';
3
3
  import fse from 'fs-extra';
4
+ import kebabCase from 'lodash/kebabCase.js';
5
+ import { createHash } from 'node:crypto';
4
6
  import { open } from 'node:fs/promises';
5
7
  import path from 'node:path';
8
+ import { addWarning } from '../../warnings.js';
6
9
  import { getGeneratedRouteKey } from './generatedRouteCollisions.js';
7
10
  import { loadRemoteGraphqlSdl, MAX_GRAPHQL_SCHEMA_BYTES } from './loadRemoteGraphqlSdl.js';
8
11
  const DEFAULT_OUTPUT_DIR = 'graphql-reference';
@@ -13,11 +16,71 @@ function graphqlConfig(config) {
13
16
  ? { source: config, directory: DEFAULT_OUTPUT_DIR }
14
17
  : { source: config.source, directory: config.directory ?? DEFAULT_OUTPUT_DIR };
15
18
  }
16
- function makePage(source, directory, kind, name, entry) {
19
+ function getPathSegments(names) {
20
+ const firstNames = new Map();
21
+ for (const name of names) {
22
+ const key = name.toLowerCase();
23
+ const current = firstNames.get(key);
24
+ if (current === undefined || name < current)
25
+ firstNames.set(key, name);
26
+ }
27
+ const renamed = names.filter((name) => firstNames.get(name.toLowerCase()) !== name);
28
+ const segmentCounts = new Map();
29
+ for (const name of renamed) {
30
+ const segment = kebabCase(name);
31
+ segmentCounts.set(segment, (segmentCounts.get(segment) ?? 0) + 1);
32
+ }
33
+ return new Map(names.map((name) => {
34
+ const firstName = firstNames.get(name.toLowerCase());
35
+ if (firstName === name)
36
+ return [name, name];
37
+ const kebabName = kebabCase(name);
38
+ const segment = kebabName.includes('-') && segmentCounts.get(kebabName) === 1
39
+ ? kebabName
40
+ : `${kebabName ? `${kebabName}-` : ''}${createHash('sha256').update(name).digest('hex').slice(0, 6)}`;
41
+ addWarning({
42
+ type: 'graphql',
43
+ message: `GraphQL name "${name}" shares its URL with "${firstName}", so its page uses "${segment}"`,
44
+ });
45
+ return [name, segment];
46
+ }));
47
+ }
48
+ const typePathCache = new WeakMap();
49
+ const fieldSegmentCache = new WeakMap();
50
+ function getTypePath(reference, name) {
51
+ let typePaths = typePathCache.get(reference);
52
+ if (!typePaths) {
53
+ typePaths = getPathSegments(reference.types.filter((type) => isDocumentedType(reference, type)).map((type) => type.name));
54
+ typePathCache.set(reference, typePaths);
55
+ }
56
+ return typePaths.get(name);
57
+ }
58
+ function getFieldSegment(fields, name) {
59
+ let segments = fieldSegmentCache.get(fields);
60
+ if (!segments) {
61
+ segments = getPathSegments(fields.map((field) => field.name));
62
+ fieldSegmentCache.set(fields, segments);
63
+ }
64
+ return segments.get(name);
65
+ }
66
+ function getOperationPath(reference, rootType, name) {
67
+ let typeName = rootType;
68
+ return path.posix.join(...name.split('.').map((fieldName) => {
69
+ const parent = reference.types.find((type) => type.name === typeName);
70
+ const fields = parent?.kind === 'object' || parent?.kind === 'interface' ? parent.fields : [];
71
+ const field = fields.find((candidate) => candidate.name === fieldName);
72
+ typeName = field ? getNamedGraphqlType(field.type) : undefined;
73
+ return getFieldSegment(fields, fieldName) ?? fieldName;
74
+ }));
75
+ }
76
+ function makePage(reference, source, directory, kind, name, entry) {
17
77
  const section = kind === 'query' ? 'queries' : kind === 'mutation' ? 'mutations' : 'types';
18
78
  const sectionPath = path.posix.join(directory, section);
79
+ const pagePath = kind === 'type'
80
+ ? (getTypePath(reference, name) ?? name)
81
+ : getOperationPath(reference, kind === 'query' ? reference.queryType : reference.mutationType, name);
19
82
  return {
20
- slug: path.posix.join(sectionPath, ...name.split('.')),
83
+ slug: path.posix.join(sectionPath, pagePath),
21
84
  directory: path.posix.dirname(sectionPath),
22
85
  title: name.slice(name.lastIndexOf('.') + 1),
23
86
  ...('description' in entry && entry.description ? { description: entry.description } : {}),
@@ -34,10 +97,22 @@ const DOCUMENTED_TYPE_KINDS = [
34
97
  'interface',
35
98
  'union',
36
99
  'enum',
100
+ 'scalar',
37
101
  ];
102
+ function isReferencedType(reference, name) {
103
+ return reference.types.some((type) => ('fields' in type &&
104
+ type.fields.some((field) => getNamedGraphqlType(field.type) === name ||
105
+ ('arguments' in field &&
106
+ field.arguments.some((arg) => getNamedGraphqlType(arg.type) === name)))) ||
107
+ ('possibleTypes' in type && type.possibleTypes.includes(name)));
108
+ }
38
109
  function isDocumentedType(reference, type) {
39
- const roots = [reference.queryType, reference.mutationType, reference.subscriptionType];
40
- return !roots.includes(type.name) && DOCUMENTED_TYPE_KINDS.includes(type.kind);
110
+ if (type.name === reference.queryType || type.name === reference.mutationType)
111
+ return false;
112
+ if (type.name === reference.subscriptionType && !isReferencedType(reference, type.name)) {
113
+ return false;
114
+ }
115
+ return DOCUMENTED_TYPE_KINDS.includes(type.kind);
41
116
  }
42
117
  function makeSelectedPage(reference, source, directory, selector) {
43
118
  const label = `GraphQL ${selector.kind} ${selector.name}`;
@@ -46,12 +121,12 @@ function makeSelectedPage(reference, source, directory, selector) {
46
121
  if (!type || !isDocumentedType(reference, type)) {
47
122
  throw new Error(`${label} not found in ${source}`);
48
123
  }
49
- return makePage(source, directory, 'type', selector.name, type);
124
+ return makePage(reference, source, directory, 'type', selector.name, type);
50
125
  }
51
126
  const resolved = resolveGraphqlOperation(reference, selector);
52
127
  if (!resolved)
53
128
  throw new Error(`${label} not found in ${source}`);
54
- return makePage(source, directory, selector.kind, selector.name, resolved.field);
129
+ return makePage(reference, source, directory, selector.kind, selector.name, resolved.field);
55
130
  }
56
131
  function generatePages(reference, source, directory) {
57
132
  const typeByName = new Map(reference.types.map((type) => [type.name, type]));
@@ -71,16 +146,16 @@ function generatePages(reference, source, directory) {
71
146
  queries: queryFields
72
147
  .slice()
73
148
  .sort(byName)
74
- .map((field) => makePage(source, directory, 'query', field.name, field)),
149
+ .map((field) => makePage(reference, source, directory, 'query', field.name, field)),
75
150
  mutations: mutationFields
76
151
  .slice()
77
152
  .sort(byName)
78
- .map((field) => makePage(source, directory, 'mutation', field.name, field)),
153
+ .map((field) => makePage(reference, source, directory, 'mutation', field.name, field)),
79
154
  types: reference.types
80
155
  .filter((type) => isDocumentedType(reference, type))
81
156
  .slice()
82
157
  .sort(byName)
83
- .map((type) => makePage(source, directory, 'type', type.name, type)),
158
+ .map((type) => makePage(reference, source, directory, 'type', type.name, type)),
84
159
  };
85
160
  }
86
161
  function mdxStub(page) {
@@ -1,5 +1,5 @@
1
1
  export type Warning = {
2
- type: 'missing-file' | 'missing-nav-page' | 'openapi' | 'invalid-import-path' | 'import-resolution-error' | 'default-import-no-default-export' | 'export-collision' | 'undeclared-package' | 'package-import-conflict' | 'parse-error';
2
+ type: 'missing-file' | 'missing-nav-page' | 'openapi' | 'invalid-import-path' | 'import-resolution-error' | 'default-import-no-default-export' | 'export-collision' | 'undeclared-package' | 'package-import-conflict' | 'parse-error' | 'graphql';
3
3
  message: string;
4
4
  file?: string;
5
5
  line?: number;