@@ -37,6 +37,8 @@ import instantiateSampleReadme from "../../templates/sampleReadme.md";
3737import { convert } from "./tsToJs" ;
3838
3939import devToolPackageJson from "../../../package.json" ;
40+ import { findMatchingFiles } from "../../util/findMatchingFiles" ;
41+ import { EOL } from "os" ;
4042
4143const log = createPrinter ( "publish" ) ;
4244
@@ -194,23 +196,26 @@ async function processSources(
194196 const tags = ts . getJSDocTags ( node ) ;
195197
196198 // Look for the @summary jsdoc tag block as well
197- if ( summary === undefined && tags . some ( ( { tagName : { text } } ) => text === "summary" ) ) {
199+ if ( summary === undefined ) {
198200 for ( const tag of tags ) {
201+ log . debug ( `File ${ relativeSourcePath } has tag ${ tag . tagName . text } ` ) ;
199202 if ( tag . tagName . text === "summary" ) {
200203 log . debug ( "Found summary tag on node:" , node . getText ( sourceFile ) ) ;
201204 // Replace is required due to multi-line splitting messing with table formatting
202205 summary = tag . comment ?. replace ( / \s * \r ? \n \s * / g, " " ) ;
203- } else if (
204- tag . tagName . text . startsWith ( `${ AZSDK_META_TAG_PREFIX } ` ) &&
205- tag . comment !== undefined
206- ) {
206+ } else if ( tag . tagName . text . startsWith ( `${ AZSDK_META_TAG_PREFIX } ` ) ) {
207207 // We ran into an `azsdk` directive in the metadata
208208 const metaTag = tag . tagName . text . replace (
209209 new RegExp ( `^${ AZSDK_META_TAG_PREFIX } ` ) ,
210210 ""
211211 ) as keyof AzSdkMetaTags ;
212+ log . debug ( `File ${ relativeSourcePath } has azsdk tag ${ tag . tagName . text } ` ) ;
212213 if ( VALID_AZSDK_META_TAGS . includes ( metaTag ) ) {
213- azSdkTags [ metaTag as keyof AzSdkMetaTags ] = JSON . parse ( tag . comment ) ;
214+ const comment = tag . comment ?. trim ( ) ;
215+ // If there was _no_ comment, then we can assume it is a boolean tag
216+ // and so being specified at all is an indication that we should use
217+ // `true`
218+ azSdkTags [ metaTag as keyof AzSdkMetaTags ] = comment ? JSON . parse ( comment ) : true ;
214219 } else {
215220 log . warn (
216221 `Invalid azsdk tag ${ metaTag } . Valid tags include ${ VALID_AZSDK_META_TAGS } `
@@ -228,17 +233,26 @@ async function processSources(
228233 return sourceFile ;
229234 } ;
230235
236+ const jsModuleText = convert ( sourceText , {
237+ fileName : source ,
238+ transformers : {
239+ before : [ sourceProcessor ]
240+ }
241+ } ) ;
242+
243+ if ( summary === undefined && azSdkTags . util !== true ) {
244+ log . debug ( azSdkTags . util , summary ) ;
245+ fail (
246+ `${ relativeSourcePath } does not include an @summary tag and is not marked as a util (using @azsdk-util true).`
247+ ) ;
248+ }
249+
231250 return {
232251 filePath : source ,
233252 relativeSourcePath,
234253 text : sourceText ,
235- jsModuleText : convert ( sourceText , {
236- fileName : source ,
237- transformers : {
238- before : [ sourceProcessor ]
239- }
240- } ) ,
241- summary : summary ?? fail ( `${ relativeSourcePath } does not include an @summary tag.` ) ,
254+ jsModuleText,
255+ summary,
242256 importedModules : importedModules . filter ( isDependency ) ,
243257 usedEnvironmentVariables,
244258 azSdkTags
@@ -248,6 +262,16 @@ async function processSources(
248262 return Promise . all ( jobs ) ;
249263}
250264
265+ async function collect < T > ( i : AsyncIterableIterator < T > ) : Promise < T [ ] > {
266+ const out = [ ] ;
267+
268+ for await ( const v of i ) {
269+ out . push ( v ) ;
270+ }
271+
272+ return out ;
273+ }
274+
251275/**
252276 * Extracts the sample generation metainformation from the sample sources and
253277 * configuration in package.json.
@@ -261,9 +285,10 @@ async function makeSampleGenerationInfo(
261285 onError : ( ) => void
262286) : Promise < SampleGenerationInfo > {
263287 const sampleSourcesPath = path . join ( projectInfo . path , DEV_SAMPLES_BASE ) ;
264- const sampleSources = ( await fs . readdir ( sampleSourcesPath ) )
265- . filter ( ( name ) => name . endsWith ( ".ts" ) )
266- . map ( ( name ) => path . join ( sampleSourcesPath , name ) ) ;
288+
289+ const sampleSources = await collect (
290+ findMatchingFiles ( sampleSourcesPath , ( name ) => name . endsWith ( ".ts" ) )
291+ ) ;
267292
268293 const sampleConfiguration = getSampleConfiguration ( projectInfo . packageJson ) ;
269294
@@ -398,7 +423,8 @@ function createReadme(outputKind: OutputKind, info: SampleGenerationInfo): strin
398423 } ,
399424 publicationDirectory : PUBLIC_SAMPLES_BASE + "/" + info . topLevelDirectory ,
400425 useTypeScript : outputKind === OutputKind . TypeScript ,
401- ...info
426+ ...info ,
427+ moduleInfos : info . moduleInfos . filter ( ( mod ) => mod . summary !== undefined )
402428 } ) ;
403429}
404430
@@ -440,7 +466,18 @@ async function makeSamplesFactory(
440466 */
441467 function postProcess ( moduleText : string | Buffer ) : string {
442468 const content = Buffer . isBuffer ( moduleText ) ? moduleText . toString ( "utf8" ) : moduleText ;
443- return content . replace ( new RegExp ( `^\\s*\\*\\s*@${ AZSDK_META_TAG_PREFIX } .*\n` , "gm" ) , "" ) ;
469+ return (
470+ content
471+ . replace ( new RegExp ( `^\\s*\\*\\s*@${ AZSDK_META_TAG_PREFIX } .*\n` , "gm" ) , "" )
472+ // We also need to clean up extra blank lines that might be left behind by
473+ // removing azsdk tags. These regular expressions are extremely frustrating
474+ // because they deal almost exclusively in the literal "/" and "*" characters.
475+ . replace ( / ( \s + \* ) + \/ / s, EOL + " */" )
476+ // Clean up blank lines at the beginning
477+ . replace ( / \/ \* \* ( \s + \* ) * / s, `/**${ EOL } *` )
478+ // Finally remove empty doc comments.
479+ . replace ( / \s * \/ \* \* ( \s + \* ) * \/ \s * / s, EOL + EOL )
480+ ) ;
444481 }
445482
446483 // We use a tempdir at the outer layer to avoid creating dirty trees
@@ -455,8 +492,8 @@ async function makeSamplesFactory(
455492 // We copy the samples sources in to the `src` folder on the typescript side
456493 dir (
457494 "src" ,
458- info . moduleInfos . map ( ( { filePath } ) =>
459- file ( path . basename ( filePath ) , ( ) => postProcess ( fs . readFileSync ( filePath ) ) )
495+ info . moduleInfos . map ( ( { relativeSourcePath , filePath } ) =>
496+ file ( relativeSourcePath , ( ) => postProcess ( fs . readFileSync ( filePath ) ) )
460497 )
461498 )
462499 ] ) ,
@@ -465,8 +502,8 @@ async function makeSamplesFactory(
465502 file ( "package.json" , ( ) => jsonify ( createPackageJson ( info , OutputKind . JavaScript ) ) ) ,
466503 copy ( "sample.env" , path . join ( projectInfo . path , "sample.env" ) ) ,
467504 // Extract the JS Module Text from the module info structures
468- ...info . moduleInfos . map ( ( { filePath , jsModuleText } ) =>
469- file ( path . basename ( filePath ) . replace ( / \. t s $ / , ".js" ) , ( ) => postProcess ( jsModuleText ) )
505+ ...info . moduleInfos . map ( ( { relativeSourcePath , jsModuleText } ) =>
506+ file ( relativeSourcePath . replace ( / \. t s $ / , ".js" ) , ( ) => postProcess ( jsModuleText ) )
470507 )
471508 ] ) ,
472509 // Copy extraFiles by reducing all configured destinations for each input file
0 commit comments