@@ -5,12 +5,20 @@ import ora from 'ora'
55import * as path from 'path'
66import { autoPrompt } from '../lib/prompt'
77import { loadDestination } from '../lib/destinations'
8- import type { JSONSchema7 } from 'json-schema'
98import { DestinationDefinition } from '../lib/destinations'
109import { BrowserDestinationDefinition } from '@segment/destinations-manifest'
11- import type { DestinationDefinition as CloudModeDestinationDefinition , InputField } from '@segment/actions-core'
10+ import {
11+ GlobalSetting ,
12+ isDirective ,
13+ DestinationDefinition as CloudModeDestinationDefinition ,
14+ InputField
15+ } from '@segment/actions-core'
16+ import Chance from 'chance'
17+ import { getRawKeys } from '@segment/actions-core/mapping-kit/value-keys'
18+ import { set } from 'lodash'
1219export default class GenerateTestPayload extends Command {
1320 private spinner : ora . Ora = ora ( )
21+ private chance : Chance . Chance = new Chance ( 'Payload' )
1422
1523 static description = `Generates sample test payload curl commands for a cloud mode destination.`
1624
@@ -152,6 +160,14 @@ export default class GenerateTestPayload extends Command {
152160 } else if ( ( destination as CloudModeDestinationDefinition ) . mode == 'cloud' ) {
153161 const destinationSettings = ( destination as CloudModeDestinationDefinition ) . authentication ?. fields
154162 settings = this . generateSampleFromSchema ( destinationSettings || { } )
163+ if ( ( destination as CloudModeDestinationDefinition ) . authentication ?. scheme === 'oauth2' ) {
164+ settings = {
165+ oauth : {
166+ accessToken : 'YOUR_ACCESS_TOKEN' ,
167+ refreshToken : 'YOUR_REFRESH_TOKEN'
168+ }
169+ }
170+ }
155171 }
156172
157173 // Generate sample mapping based on action fields
@@ -161,8 +177,6 @@ export default class GenerateTestPayload extends Command {
161177 for ( const [ fieldKey , field ] of Object . entries ( fields ) ) {
162178 if ( field . default ) {
163179 mapping [ fieldKey ] = field . default
164- } else if ( field . required ) {
165- mapping [ fieldKey ] = this . generatePlaceholderValue ( field )
166180 }
167181 }
168182
@@ -188,133 +202,145 @@ export default class GenerateTestPayload extends Command {
188202 }
189203 }
190204
191- generateSampleFromSchema ( schema : JSONSchema7 ) : Record < string , any > {
205+ generateSampleFromSchema ( schema : Record < string , GlobalSetting > ) : Record < string , any > {
192206 const result : Record < string , any > = { }
193-
194- if ( ! schema . properties ) {
195- return result
196- }
197-
198- for ( const [ propName , propSchema ] of Object . entries ( schema . properties ) ) {
199- const prop = propSchema as JSONSchema7
200-
201- if ( prop . default !== undefined ) {
202- result [ propName ] = prop . default
203- } else if ( ( schema . required || [ ] ) . includes ( propName ) ) {
204- result [ propName ] = this . generatePlaceholderForSchema ( prop )
207+ for ( const [ propName , setting ] of Object . entries ( schema ) ) {
208+ if ( setting . default !== undefined ) {
209+ result [ propName ] = setting . default
210+ } else if ( setting . required ) {
211+ result [ propName ] = this . generatePlaceholderForSchema ( setting )
205212 }
206213 }
207214
208215 return result
209216 }
210217
211- generatePlaceholderForSchema ( schema : JSONSchema7 ) : any {
212- const type = Array . isArray ( schema . type ) ? schema . type [ 0 ] : schema . type
218+ generatePlaceholderForSchema ( schema : GlobalSetting ) : any {
219+ const type = schema . type
213220
214221 switch ( type ) {
215222 case 'string' :
216- if ( schema . enum && schema . enum . length > 0 ) {
217- return schema . enum [ 0 ]
223+ if ( schema . choices ) {
224+ return schema . choices [ 0 ]
218225 }
219- return `YOUR_${ schema . title || 'VALUE' } `
226+ return `YOUR_${ schema . label || 'VALUE' } `
220227 case 'number' :
221- case 'integer' :
222228 return 0
223229 case 'boolean' :
224230 return false
225- case 'object' :
226- return this . generateSampleFromSchema ( schema )
227- case 'array' :
228- if ( schema . items && ! Array . isArray ( schema . items ) ) {
229- return [ this . generatePlaceholderForSchema ( schema . items as JSONSchema7 ) ]
230- }
231- return [ ]
231+ case 'password' :
232+ return `YOUR_${ schema . label || 'PASSWORD' } `
232233 default :
233234 return null
234235 }
235236 }
236237
237- generatePlaceholderValue ( field : any ) : any {
238- if ( field . type === 'boolean' ) {
239- return false
240- } else if ( field . type === 'number' ) {
241- return 0
242- } else if ( field . type === 'object' ) {
243- return { }
244- } else if ( field . type === 'array' ) {
245- return [ ]
246- }
247-
248- // For string type
249- return `YOUR_${ field . label || field . title || 'VALUE' } `
250- }
251-
252238 generateSamplePayloadFromMapping ( mapping : Record < string , any > ) : Record < string , any > {
239+ const chance = new Chance ( 'payload' )
253240 const payload : Record < string , any > = {
254- userId : 'user123' ,
255- anonymousId : 'anon456' ,
241+ userId : chance . guid ( ) ,
242+ anonymousId : chance . guid ( ) ,
256243 event : 'Example Event' ,
257244 type : 'track' ,
258245 timestamp : new Date ( ) . toISOString ( ) ,
259246 properties : { } ,
260247 context : {
261- ip : '127.0.0.1' ,
262- userAgent : 'Mozilla/5.0' ,
248+ ip : chance . ip ( ) ,
249+ userAgent :
250+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36' ,
263251 page : {
264- path : '/' ,
265- url : 'https://example.com/' ,
266- referrer : '' ,
267- title : 'Example Page'
252+ path : `/${ chance . word ( ) } ` ,
253+ url : chance . url ( ) ,
254+ referrer : chance . url ( ) ,
255+ title : `${ chance . capitalize ( chance . word ( ) ) } ${ chance . capitalize ( chance . word ( ) ) } `
256+ } ,
257+ locale : chance . locale ( ) ,
258+ library : {
259+ name : 'analytics.js' ,
260+ version : `${ chance . integer ( { min : 1 , max : 5 } ) } .${ chance . integer ( { min : 0 , max : 20 } ) } .${ chance . integer ( {
261+ min : 0 ,
262+ max : 99
263+ } ) } `
268264 }
269265 }
270266 }
271267
272- // Add properties based on mapping
273- for ( const [ key , value ] of Object . entries ( mapping ) ) {
274- payload . properties [ key ] = value
268+ // Add properties based on mapping with better values
269+ for ( const [ _ , value ] of Object . entries ( mapping ) ) {
270+ if ( isDirective ( value ) ) {
271+ const [ key ] = getRawKeys ( value )
272+ const path = key . replace ( '$.' , '' )
273+ set ( payload , path , this . generateValueByFieldName ( path ) )
274+ }
275275 }
276276
277- // Add properties based on mapping
278- for ( const [ key , value ] of Object . entries ( mapping ) ) {
279- if ( typeof value === 'string' && value . startsWith ( '$.' ) ) {
280- // Handle field value from mapping path
281- const path = value . substring ( 2 ) . split ( '.' )
282- if ( path [ 0 ] === 'properties' ) {
283- const propName = path . slice ( 1 ) . join ( '.' )
284- payload . properties [ propName ] = `SAMPLE_${ key . toUpperCase ( ) } `
285- } else if ( path [ 0 ] === 'context' ) {
286- const nestedPath = path . slice ( 1 )
287- let current = payload . context
288-
289- for ( let i = 0 ; i < nestedPath . length - 1 ; i ++ ) {
290- if ( ! current [ nestedPath [ i ] ] ) {
291- current [ nestedPath [ i ] ] = { }
292- }
293- current = current [ nestedPath [ i ] ]
294- }
277+ return payload
278+ }
295279
296- if ( nestedPath . length > 0 ) {
297- current [ nestedPath [ nestedPath . length - 1 ] ] = `SAMPLE_${ key . toUpperCase ( ) } `
298- }
299- } else if ( path [ 0 ] === 'traits' ) {
300- if ( ! payload . traits ) {
301- payload . traits = { }
302- }
303- const propName = path . slice ( 1 ) . join ( '.' )
304- payload . traits [ propName ] = `SAMPLE_${ key . toUpperCase ( ) } `
305- } else if ( path [ 0 ] === 'userId' || path [ 0 ] === 'anonymousId' || path [ 0 ] === 'event' ) {
306- // These are already set
307- } else {
308- // Handle top-level fields
309- payload [ path [ 0 ] ] = `SAMPLE_${ key . toUpperCase ( ) } `
310- }
311- } else if ( typeof value === 'string' ) {
312- // Handle literal values from mappings
313- payload . properties [ key ] = value
280+ generateValueByFieldName ( fieldName : string ) : any {
281+ const lowerFieldName = fieldName . toLowerCase ( )
282+
283+ // Check for common field name patterns
284+ if ( lowerFieldName . includes ( 'email' ) ) {
285+ return this . chance . email ( )
286+ } else if ( lowerFieldName . includes ( 'phone' ) || lowerFieldName . includes ( 'mobile' ) ) {
287+ return `+${ this . chance . phone ( { formatted : false } ) } `
288+ } else if ( lowerFieldName . includes ( 'name' ) ) {
289+ if ( lowerFieldName . includes ( 'first' ) ) {
290+ return this . chance . first ( )
291+ } else if ( lowerFieldName . includes ( 'last' ) ) {
292+ return this . chance . last ( )
293+ } else if ( lowerFieldName . includes ( 'full' ) ) {
294+ return this . chance . name ( )
295+ } else {
296+ return this . chance . name ( )
314297 }
298+ } else if ( lowerFieldName . includes ( 'url' ) || lowerFieldName . includes ( 'link' ) ) {
299+ return this . chance . url ( )
300+ } else if ( lowerFieldName . includes ( 'date' ) ) {
301+ return this . chance . date ( ) . toISOString ( )
302+ } else if ( lowerFieldName . includes ( 'time' ) ) {
303+ return this . chance . date ( ) . toISOString ( )
304+ } else if (
305+ lowerFieldName . includes ( 'price' ) ||
306+ lowerFieldName . includes ( 'amount' ) ||
307+ lowerFieldName . includes ( 'total' )
308+ ) {
309+ return this . chance . floating ( { min : 1 , max : 1000 , fixed : 2 } )
310+ } else if ( lowerFieldName . includes ( 'currency' ) ) {
311+ return this . chance . currency ( ) . code
312+ } else if ( lowerFieldName . includes ( 'country' ) ) {
313+ return this . chance . country ( )
314+ } else if ( lowerFieldName . includes ( 'city' ) ) {
315+ return this . chance . city ( )
316+ } else if ( lowerFieldName . includes ( 'state' ) || lowerFieldName . includes ( 'province' ) ) {
317+ return this . chance . state ( )
318+ } else if ( lowerFieldName . includes ( 'zip' ) || lowerFieldName . includes ( 'postal' ) ) {
319+ return this . chance . zip ( )
320+ } else if ( lowerFieldName . includes ( 'address' ) ) {
321+ return this . chance . address ( )
322+ } else if ( lowerFieldName . includes ( 'company' ) || lowerFieldName . includes ( 'organization' ) ) {
323+ return this . chance . company ( )
324+ } else if ( lowerFieldName . includes ( 'description' ) ) {
325+ return this . chance . paragraph ( )
326+ } else if ( lowerFieldName . includes ( 'id' ) ) {
327+ return this . chance . guid ( )
328+ } else if ( lowerFieldName . includes ( 'quantity' ) || lowerFieldName . includes ( 'count' ) ) {
329+ return this . chance . integer ( { min : 1 , max : 10 } )
330+ } else if ( lowerFieldName . includes ( 'age' ) ) {
331+ return this . chance . age ( )
332+ } else if ( lowerFieldName === 'gender' ) {
333+ return this . chance . gender ( )
334+ } else if (
335+ lowerFieldName . includes ( 'boolean' ) ||
336+ lowerFieldName . includes ( 'enabled' ) ||
337+ lowerFieldName . includes ( 'active' )
338+ ) {
339+ return this . chance . bool ( )
340+ } else {
341+ // Default fallback
342+ return this . chance . word ( )
315343 }
316-
317- return payload
318344 }
319345
320346 async catch ( error : unknown ) {
0 commit comments