@@ -15,6 +15,11 @@ const OUTPUT_PATH = path.join(
1515 '..' ,
1616 'packages/dd-trace/src/config/generated-config-types.d.ts'
1717)
18+ const CONFIG_INDEX_PATH = path . join (
19+ __dirname ,
20+ '..' ,
21+ 'packages/dd-trace/src/config/index.js'
22+ )
1823
1924const BASE_TYPES = {
2025 array : 'string[]' ,
@@ -54,8 +59,78 @@ function getPropertyName (canonicalName, entry) {
5459 return configurationNames ?. [ 0 ] ?? canonicalName
5560}
5661
57- function withUndefined ( type , entry ) {
58- return entry . default === null ? `${ type } | undefined` : type
62+ const FALLBACK_PATTERN =
63+ / i f \s * \( \s * ! \s * t h i s \. ( [ \w . ] + ) \s * \) \s * \{ [ \s \S ] * ?s e t A n d T r a c k \s * \( \s * t h i s \s * , \s * [ ' " ] ( [ \w . ] + ) [ ' " ] \s * , / g
64+
65+ // Expression whose tail (after any top-level `||`/`??`, or the whole expression) is a string or
66+ // template literal — i.e. the result is guaranteed defined at runtime.
67+ const GUARANTEED_DEFINED = / (?: ^ | \| \| | \? \? ) \s * (?: ' [ ^ ' ] * ' | " [ ^ " ] * " | ` (?: \$ \{ [ ^ } ` ] * \} | [ ^ ` ] ) * ` ) \s * $ /
68+
69+ // Returns the index right after the `close` that balances the `open` preceding `start`, or -1 if
70+ // unbalanced. Skips over string and template literals so their contents don't affect depth.
71+ function balancedEnd ( s , start , open , close ) {
72+ let depth = 1
73+ let i = start
74+ while ( i < s . length ) {
75+ const ch = s [ i ]
76+ if ( ch === open ) {
77+ depth ++
78+ i ++
79+ } else if ( ch === close ) {
80+ i ++
81+ if ( -- depth === 0 ) return i
82+ } else if ( ch === '"' || ch === '\'' || ch === '`' ) {
83+ i = skipQuoted ( s , i , ch )
84+ } else {
85+ i ++
86+ }
87+ }
88+ return - 1
89+ }
90+
91+ function skipQuoted ( s , i , quote ) {
92+ const isTemplate = quote === '`'
93+ i ++
94+ while ( i < s . length ) {
95+ if ( s [ i ] === '\\' ) { i += 2 ; continue }
96+ if ( s [ i ] === quote ) return i + 1
97+ if ( isTemplate && s [ i ] === '$' && s [ i + 1 ] === '{' ) {
98+ i = balancedEnd ( s , i + 2 , '{' , '}' )
99+ if ( i === - 1 ) return s . length
100+ continue
101+ }
102+ i ++
103+ }
104+ return i
105+ }
106+
107+ function findCalculatedFallbackProperties ( ) {
108+ const source = readFileSync ( CONFIG_INDEX_PATH , 'utf8' )
109+ const marker = / # a p p l y C a l c u l a t e d \s * \( \s * \) \s * \{ / . exec ( source )
110+ if ( ! marker ) throw new Error ( 'Could not locate #applyCalculated() in config/index.js' )
111+
112+ const bodyStart = marker . index + marker [ 0 ] . length
113+ const body = source . slice ( bodyStart , balancedEnd ( source , bodyStart , '{' , '}' ) - 1 )
114+
115+ const properties = new Set ( )
116+ let match
117+ while ( ( match = FALLBACK_PATTERN . exec ( body ) ) !== null ) {
118+ if ( match [ 1 ] !== match [ 2 ] ) continue
119+ const valueStart = match . index + match [ 0 ] . length
120+ const valueEnd = balancedEnd ( body , valueStart , '(' , ')' )
121+ if ( valueEnd === - 1 ) continue
122+ const value = body . slice ( valueStart , valueEnd - 1 ) . trim ( )
123+ if ( GUARANTEED_DEFINED . test ( value ) ) properties . add ( match [ 1 ] )
124+ }
125+ return properties
126+ }
127+
128+ const CALCULATED_FALLBACK_PROPERTIES = findCalculatedFallbackProperties ( )
129+
130+ function withUndefined ( type , entry , propertyName ) {
131+ if ( entry . default !== null ) return type
132+ if ( CALCULATED_FALLBACK_PROPERTIES . has ( propertyName ) ) return type
133+ return `${ type } | undefined`
59134}
60135
61136function getAllowedType ( entry ) {
@@ -93,7 +168,7 @@ function getTypeForEntry (propertyName, entry) {
93168 throw new Error ( `Unsupported configuration type for ${ propertyName } : ${ entry . type } ` )
94169 }
95170
96- return withUndefined ( override , entry )
171+ return withUndefined ( override , entry , propertyName )
97172}
98173
99174function addProperty ( root , propertyName , type ) {
0 commit comments