@@ -24,6 +24,105 @@ InternalConsole.registerConsole(internalConsole)
2424 */
2525const filterRelativePathItems = ( items ) => items . filter ( ( part ) => part !== '' )
2626
27+ /**
28+ * Return the default Netlify Graph configuration for a generic site
29+ * @param {object } context
30+ * @param {string[] } context.detectedFunctionsPath
31+ * @param {string[] } context.siteRoot
32+ */
33+ const makeDefaultNetlifGraphConfig = ( { baseConfig, detectedFunctionsPath } ) => {
34+ const functionsPath = filterRelativePathItems ( [ ...detectedFunctionsPath ] )
35+ const webhookBasePath = '/.netlify/functions'
36+ const netlifyGraphPath = [ ...functionsPath , 'netlifyGraph' ]
37+ const netlifyGraphImplementationFilename = [ ...netlifyGraphPath , `index.${ baseConfig . extension } ` ]
38+ const netlifyGraphTypeDefinitionsFilename = [ ...netlifyGraphPath , `index.d.ts` ]
39+ const graphQLOperationsSourceFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultSourceOperationsFilename ]
40+ const graphQLSchemaFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultGraphQLSchemaFilename ]
41+ const netlifyGraphRequirePath = [ `./netlifyGraph` ]
42+ const moduleType = baseConfig . moduleType || 'esm'
43+
44+ return {
45+ functionsPath,
46+ webhookBasePath,
47+ netlifyGraphPath,
48+ netlifyGraphImplementationFilename,
49+ netlifyGraphTypeDefinitionsFilename,
50+ graphQLOperationsSourceFilename,
51+ graphQLSchemaFilename,
52+ netlifyGraphRequirePath,
53+ moduleType,
54+ }
55+ }
56+
57+ /**
58+ * Return the default Netlify Graph configuration for a Nextjs site
59+ * @param {object } context
60+ * @param {string[] } context.detectedFunctionsPath
61+ * @param {string[] } context.siteRoot
62+ */
63+ const makeDefaultNextJsNetlifGraphConfig = ( { baseConfig, siteRoot } ) => {
64+ const functionsPath = filterRelativePathItems ( [ ...siteRoot , 'pages' , 'api' ] )
65+ const webhookBasePath = '/api'
66+ const netlifyGraphPath = filterRelativePathItems ( [ ...siteRoot , 'lib' , 'netlifyGraph' ] )
67+ const netlifyGraphImplementationFilename = [ ...netlifyGraphPath , `index.${ baseConfig . extension } ` ]
68+ const netlifyGraphTypeDefinitionsFilename = [ ...netlifyGraphPath , `index.d.ts` ]
69+ const graphQLOperationsSourceFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultSourceOperationsFilename ]
70+ const graphQLSchemaFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultGraphQLSchemaFilename ]
71+ const netlifyGraphRequirePath = [ '..' , '..' , 'lib' , 'netlifyGraph' ]
72+ const moduleType = baseConfig . moduleType || 'esm'
73+
74+ return {
75+ functionsPath,
76+ webhookBasePath,
77+ netlifyGraphPath,
78+ netlifyGraphImplementationFilename,
79+ netlifyGraphTypeDefinitionsFilename,
80+ graphQLOperationsSourceFilename,
81+ graphQLSchemaFilename,
82+ netlifyGraphRequirePath,
83+ moduleType,
84+ }
85+ }
86+
87+ /**
88+ * Return the default Netlify Graph configuration for a Remix site
89+ * @param {object } context
90+ * @param {string[] } context.detectedFunctionsPath
91+ * @param {string[] } context.siteRoot
92+ */
93+ const makeDefaultRemixNetlifGraphConfig = ( { baseConfig, detectedFunctionsPath, siteRoot } ) => {
94+ const functionsPath = filterRelativePathItems ( [ ...detectedFunctionsPath ] )
95+ const webhookBasePath = '/webhooks'
96+ const netlifyGraphPath = filterRelativePathItems ( [
97+ ...siteRoot ,
98+ ...NetlifyGraph . defaultNetlifyGraphConfig . netlifyGraphPath ,
99+ ] )
100+ const netlifyGraphImplementationFilename = [ ...netlifyGraphPath , `index.${ baseConfig . extension } ` ]
101+ const netlifyGraphTypeDefinitionsFilename = [ ...netlifyGraphPath , `index.d.ts` ]
102+ const graphQLOperationsSourceFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultSourceOperationsFilename ]
103+ const graphQLSchemaFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultGraphQLSchemaFilename ]
104+ const netlifyGraphRequirePath = [ `../../netlify/functions/netlifyGraph` ]
105+ const moduleType = 'esm'
106+
107+ return {
108+ functionsPath,
109+ webhookBasePath,
110+ netlifyGraphPath,
111+ netlifyGraphImplementationFilename,
112+ netlifyGraphTypeDefinitionsFilename,
113+ graphQLOperationsSourceFilename,
114+ graphQLSchemaFilename,
115+ netlifyGraphRequirePath,
116+ moduleType,
117+ }
118+ }
119+
120+ const defaultFrameworkLookup = {
121+ 'Next.js' : makeDefaultNextJsNetlifGraphConfig ,
122+ Remix : makeDefaultRemixNetlifGraphConfig ,
123+ default : makeDefaultNetlifGraphConfig ,
124+ }
125+
27126/**
28127 * Return a full NetlifyGraph config with any defaults overridden by netlify.toml
29128 * @param {import('../base-command').BaseCommand } command
@@ -48,7 +147,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
48147 try {
49148 settings = await detectServerSettings ( devConfig , options , site . root )
50149 } catch ( detectServerSettingsError ) {
51- error ( detectServerSettingsError )
150+ settings = { }
151+ warn ( 'Error while auto-detecting project settings, Netlify Graph encounter problems' , detectServerSettingsError )
52152 }
53153 }
54154
@@ -58,26 +158,55 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
58158 const autodetectedLanguage = fs . existsSync ( tsConfig ) ? 'typescript' : 'javascript'
59159
60160 const framework = settings . framework || userSpecifiedConfig . framework
61- const isNextjs = framework === 'Next.js'
161+ const makeDefaultFrameworkConfig = defaultFrameworkLookup [ framework ] || defaultFrameworkLookup . default
162+
62163 const detectedFunctionsPathString = getFunctionsDir ( { config, options } )
63- const detectedFunctionsPath = detectedFunctionsPathString ? detectedFunctionsPathString . split ( path . sep ) : null
64- const functionsPath = filterRelativePathItems ( isNextjs ? [ ...siteRoot , 'pages' , 'api' ] : [ ...detectedFunctionsPath ] )
65- const netlifyGraphPath = filterRelativePathItems (
66- isNextjs
67- ? [ ...siteRoot , 'lib' , 'netlifyGraph' ]
68- : [ ...siteRoot , ...NetlifyGraph . defaultNetlifyGraphConfig . netlifyGraphPath ] ,
69- )
164+ const detectedFunctionsPath = detectedFunctionsPathString
165+ ? [ path . sep , ...detectedFunctionsPathString . split ( path . sep ) ]
166+ : null
70167 const baseConfig = { ...NetlifyGraph . defaultNetlifyGraphConfig , ...userSpecifiedConfig }
71- const netlifyGraphImplementationFilename = [ ...netlifyGraphPath , `index.${ baseConfig . extension } ` ]
72- const netlifyGraphTypeDefinitionsFilename = [ ...netlifyGraphPath , `index.d.ts` ]
73- const graphQLOperationsSourceFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultSourceOperationsFilename ]
74- const graphQLSchemaFilename = [ ...netlifyGraphPath , NetlifyGraph . defaultGraphQLSchemaFilename ]
75- const netlifyGraphRequirePath = isNextjs ? [ '..' , '..' , 'lib' , 'netlifyGraph' ] : [ `./netlifyGraph` ]
76- const language = userSpecifiedConfig . language || autodetectedLanguage
77- const moduleType = baseConfig . moduleType || isNextjs ? 'esm' : 'commonjs'
168+ const defaultFrameworkConfig = makeDefaultFrameworkConfig ( { baseConfig, detectedFunctionsPath, siteRoot } )
169+
170+ const functionsPath =
171+ ( userSpecifiedConfig . functionsPath && userSpecifiedConfig . functionsPath . split ( path . sep ) ) ||
172+ defaultFrameworkConfig . functionsPath
173+ const netlifyGraphPath =
174+ ( userSpecifiedConfig . netlifyGraphPath && userSpecifiedConfig . netlifyGraphPath . split ( path . sep ) ) ||
175+ defaultFrameworkConfig . netlifyGraphPath
176+ const netlifyGraphImplementationFilename =
177+ ( userSpecifiedConfig . netlifyGraphImplementationFilename &&
178+ userSpecifiedConfig . netlifyGraphImplementationFilename . split ( path . sep ) ) ||
179+ defaultFrameworkConfig . netlifyGraphImplementationFilename
180+ const netlifyGraphTypeDefinitionsFilename =
181+ ( userSpecifiedConfig . netlifyGraphTypeDefinitionsFilename &&
182+ userSpecifiedConfig . netlifyGraphTypeDefinitionsFilename . split ( path . sep ) ) ||
183+ defaultFrameworkConfig . netlifyGraphTypeDefinitionsFilename
184+ const graphQLOperationsSourceFilename =
185+ ( userSpecifiedConfig . graphQLOperationsSourceFilename &&
186+ userSpecifiedConfig . graphQLOperationsSourceFilename . split ( path . sep ) ) ||
187+ defaultFrameworkConfig . graphQLOperationsSourceFilename
188+ const graphQLSchemaFilename =
189+ ( userSpecifiedConfig . graphQLSchemaFilename && userSpecifiedConfig . graphQLSchemaFilename . split ( path . sep ) ) ||
190+ defaultFrameworkConfig . graphQLSchemaFilename
191+ const netlifyGraphRequirePath =
192+ ( userSpecifiedConfig . netlifyGraphRequirePath && userSpecifiedConfig . netlifyGraphRequirePath . split ( path . sep ) ) ||
193+ defaultFrameworkConfig . netlifyGraphRequirePath
194+ const moduleType =
195+ ( userSpecifiedConfig . moduleType && userSpecifiedConfig . moduleType . split ( path . sep ) ) ||
196+ defaultFrameworkConfig . moduleType
197+ const language =
198+ ( userSpecifiedConfig . language && userSpecifiedConfig . language . split ( path . sep ) ) || autodetectedLanguage
199+ const webhookBasePath =
200+ ( userSpecifiedConfig . webhookBasePath && userSpecifiedConfig . webhookBasePath . split ( path . sep ) ) ||
201+ defaultFrameworkConfig . webhookBasePath
202+ const customGeneratorFile =
203+ userSpecifiedConfig . customGeneratorFile && userSpecifiedConfig . customGeneratorFile . split ( path . sep )
204+ const runtimeTargetEnv = userSpecifiedConfig . runtimeTargetEnv || defaultFrameworkConfig . runtimeTargetEnv || 'node'
205+
78206 const fullConfig = {
79207 ...baseConfig ,
80208 functionsPath,
209+ webhookBasePath,
81210 netlifyGraphPath,
82211 netlifyGraphImplementationFilename,
83212 netlifyGraphTypeDefinitionsFilename,
@@ -87,6 +216,8 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
87216 framework,
88217 language,
89218 moduleType,
219+ customGeneratorFile,
220+ runtimeTargetEnv,
90221 }
91222
92223 return fullConfig
@@ -97,30 +228,36 @@ const getNetlifyGraphConfig = async ({ command, options, settings }) => {
97228 * @param {NetlifyGraphConfig } netlifyGraphConfig
98229 */
99230const ensureNetlifyGraphPath = ( netlifyGraphConfig ) => {
100- fs . mkdirSync ( path . resolve ( ...netlifyGraphConfig . netlifyGraphPath ) , { recursive : true } )
231+ const fullPath = path . resolve ( ...netlifyGraphConfig . netlifyGraphPath )
232+ fs . mkdirSync ( fullPath , { recursive : true } )
101233}
102234
103235/**
104236 * Given a NetlifyGraphConfig, ensure that the functionsPath exists
105237 * @param {NetlifyGraphConfig } netlifyGraphConfig
106238 */
107239const ensureFunctionsPath = ( netlifyGraphConfig ) => {
108- fs . mkdirSync ( path . resolve ( ...netlifyGraphConfig . functionsPath ) , { recursive : true } )
240+ const fullPath = path . resolve ( ...netlifyGraphConfig . functionsPath )
241+ fs . mkdirSync ( fullPath , { recursive : true } )
109242}
110243
111244/**
112245 * Generate a library file with type definitions for a given NetlifyGraphConfig, operationsDoc, and schema, writing them to the filesystem
113- * @param {NetlifyGraphConfig } netlifyGraphConfig
114- * @param {GraphQLSchema } schema The schema to use when generating the functions and their types
115- * @param {string } operationsDoc The GraphQL operations doc to use when generating the functions
116- * @param {NetlifyGraph.ParsedFunction } queries The parsed queries with metadata to use when generating library functions
246+ * @param {object } context
247+ * @param {NetlifyGraphConfig } context.netlifyGraphConfig
248+ * @param {GraphQLSchema } context.schema The schema to use when generating the functions and their types
249+ * @param {string } context.operationsDoc The GraphQL operations doc to use when generating the functions
250+ * @param {NetlifyGraph.ParsedFunction } context.functions The parsed queries with metadata to use when generating library functions
251+ * @param {NetlifyGraph.ParsedFragment } context.fragments The parsed queries with metadata to use when generating library functions
252+ * @returns {void } Void, effectfully writes the generated library to the filesystem
117253 */
118- const generateFunctionsFile = ( netlifyGraphConfig , schema , operationsDoc , queries ) => {
254+ const generateFunctionsFile = ( { fragments , functions , netlifyGraphConfig , operationsDoc, schema } ) => {
119255 const { clientSource, typeDefinitionsSource } = NetlifyGraph . generateFunctionsSource (
120256 netlifyGraphConfig ,
121257 schema ,
122258 operationsDoc ,
123- queries ,
259+ functions ,
260+ fragments ,
124261 )
125262
126263 ensureNetlifyGraphPath ( netlifyGraphConfig )
@@ -199,13 +336,15 @@ const generateHandler = (netlifyGraphConfig, schema, operationId, handlerOptions
199336 currentOperationsDoc = NetlifyGraph . defaultExampleOperationsDoc
200337 }
201338
202- const result = NetlifyGraph . generateHandlerSource ( {
339+ const payload = {
203340 handlerOptions,
204341 schema,
205342 netlifyGraphConfig,
206343 operationId,
207344 operationsDoc : currentOperationsDoc ,
208- } )
345+ }
346+
347+ const result = NetlifyGraph . generateHandlerSource ( payload )
209348
210349 if ( ! result ) {
211350 warn ( `No handler was generated for operationId ${ operationId } ` )
@@ -237,6 +376,11 @@ const generateHandler = (netlifyGraphConfig, schema, operationId, handlerOptions
237376 filenameArr = [ path . sep , ...netlifyGraphConfig . functionsPath , baseFilename ]
238377 }
239378
379+ const parentDir = path . resolve ( ...filterRelativePathItems ( filenameArr . slice ( 0 , - 1 ) ) )
380+
381+ // Make sure the parent directory exists
382+ fs . mkdirSync ( parentDir , { recursive : true } )
383+
240384 const absoluteFilename = path . resolve ( ...filenameArr )
241385
242386 fs . writeFileSync ( absoluteFilename , content )
@@ -254,7 +398,7 @@ const { buildSchema, parse } = GraphQL
254398 * @returns {string } The url to the Netlify Graph UI for the current session
255399 */
256400const getGraphEditUrlBySiteName = ( { oneGraphSessionId, siteName } ) => {
257- const host = 'app.netlify.com' || process . env . NETLIFY_APP_HOST
401+ const host = process . env . NETLIFY_APP_HOST || 'app.netlify.com'
258402 // http because app.netlify.com will redirect to https, and localhost will still work for development
259403 const url = `http://${ host } /sites/${ siteName } /graph/explorer?cliSessionId=${ oneGraphSessionId } `
260404
0 commit comments