diff --git a/.scripts/generate-sdks.ts b/.scripts/generate-sdks.ts index 8dcd9fb5277..8106d03334b 100644 --- a/.scripts/generate-sdks.ts +++ b/.scripts/generate-sdks.ts @@ -4,19 +4,33 @@ * license information. */ -import * as colors from "colors"; import * as fssync from "fs"; import { promises as fs } from "fs"; import * as path from "path"; import * as minimist from "minimist"; +import * as yaml from "js-yaml"; import { CommandLineOptions, SdkType } from "./commandLineOptions"; import { Logger } from "./logger"; +interface readmeSettings { + "nodejs": { + "azure-arm": boolean; + "license-header": string; + "payload-flattening-threshold": number; + "package-name": string; + "output-folder": string; + "generate-license-txt": boolean | undefined; + "generate-package-json": boolean | undefined; + "generate-readme-md": boolean | undefined; + "generate-metadata": boolean | undefined; + } | undefined; +} + const repositoryName = "azure-rest-api-specs"; const specificationsSegment = "specification"; const args = minimist(process.argv.slice(2), { - string: [ "package", "type" ], + string: ["package", "type"], boolean: ["debug", "verbose"], alias: { d: "debug", @@ -28,7 +42,11 @@ const args = minimist(process.argv.slice(2), { } }) as CommandLineOptions; -const logger = new Logger(args); +const _logger = new Logger(args); + +if (!fs) { + throw new Error("This script has to be run on Node.js 10.0+"); +} function contains(array: T[], el: T): boolean { return array.indexOf(el) != -1 @@ -47,9 +65,9 @@ async function exists(path: string): Promise { }); } -args.getSdkType = function() { - const resourceManagerStrings = [ "arm", "rm", "resourcemanager" ] - const dataPlaneStrings = [ "dp", "data", "dataplane" ] +args.getSdkType = function () { + const resourceManagerStrings = ["arm", "rm", "resourcemanager"] + const dataPlaneStrings = ["dp", "data", "dataplane"] const type = this.type.toLowerCase().replace("-", ""); if (contains(resourceManagerStrings, type)) { @@ -57,7 +75,7 @@ args.getSdkType = function() { } else if (contains(dataPlaneStrings, type)) { return SdkType.DataPlane; } else { - throw new Error("Uknown SDK type"); + throw new Error("Unknown SDK type"); } } @@ -101,7 +119,7 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom for (const serviceDirectory of serviceSpecs) { const fullServicePath = path.resolve(specsDirectory, serviceDirectory); - if (!(await !isDirectory(fullServicePath))) { + if (!(await isDirectory(fullServicePath))) { continue; } @@ -122,16 +140,17 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom } else if (readmeFiles.length == 1) { const readmeMdPath = readmeFiles[0]; if (await doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath)) { - console.log(colors.red(fullSpecName)) - } else { - console.log(colors.green(fullSpecName)) + missingSdks.push(fullSdkPath); + _logger.logRed(`${fullSpecName}`); + } else if (args.debug) { + _logger.logGreen(fullSpecName); } } else if (contains(readmeFiles, "readme.nodejs.md")) { if (!contains(readmeFiles, "readme.typescript.md")) { missingSdks.push(fullSdkPath); - console.log(colors.red(fullSpecName)) + _logger.logRed(`${fullSpecName}`); } else if (args.debug) { - console.log(colors.green(fullSpecName)) + _logger.logGreen(fullSpecName); } } } @@ -140,16 +159,19 @@ export async function findMissingSdks(azureRestApiSpecsRepository: string): Prom return missingSdks; } +async function getYamlSection(buffer: Buffer, sectionBeginning: string, sectionEnd: string): Promise { + const beginningIndex = buffer.indexOf(sectionBeginning); + const trimmedBuffer = buffer.slice(beginningIndex + (sectionBeginning.length)); + + const endIndex = trimmedBuffer.indexOf(sectionEnd, 3); + const sectionBuffer = trimmedBuffer.slice(0, endIndex); + + return sectionBuffer; +} + async function doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath: string): Promise { const readmeMdBuffer = await fs.readFile(readmeMdPath); - const sectionBeginning = "``` yaml $(swagger-to-sdk)" - const sectionEnd = "```" - - const beginningIndex = readmeMdBuffer.indexOf(sectionBeginning); - const trimmedBuffer = readmeMdBuffer.slice(beginningIndex); - - const endIndex = trimmedBuffer.indexOf(sectionEnd); - const sectionBuffer = trimmedBuffer.slice(0, endIndex); + const sectionBuffer = await getYamlSection(readmeMdBuffer, "``` yaml $(swagger-to-sdk)", "```"); if (sectionBuffer.includes("azure-sdk-for-js")) { return true; @@ -158,12 +180,12 @@ async function doesReadmeMdFileSpecifiesTypescriptSdk(readmeMdPath: string): Pro return false; } -export async function copyExistingNodeJsReadme(sdkPath: string): Promise { +export async function copyExistingNodeJsReadme(sdkPath: string): Promise { const nodeJsReadmePath = path.resolve(sdkPath, "readme.nodejs.md"); const typescriptReadmePath = path.resolve(sdkPath, "readme.typescript.md"); if (args.verbose) { - console.log(`Copying ${nodeJsReadmePath} to ${typescriptReadmePath}`) + _logger.log(`Copying ${nodeJsReadmePath} to ${typescriptReadmePath}`) } if (await exists(typescriptReadmePath)) { @@ -171,4 +193,64 @@ export async function copyExistingNodeJsReadme(sdkPath: string): Promise { } await fs.copyFile(nodeJsReadmePath, typescriptReadmePath); + return typescriptReadmePath; } + +async function updatePackageName(settings: readmeSettings): Promise { + const packageName = settings.nodejs["package-name"] + if (packageName.startsWith("arm") || !packageName.startsWith("azure-")) { + return settings; + } + + settings.nodejs["package-name"] = packageName.replace("azure-", ""); + return settings; +} + +async function updateMetadataFields(settings: readmeSettings): Promise { + settings.nodejs["generate-metadata"] = true; + delete settings.nodejs["generate-license-txt"] + delete settings.nodejs["generate-package-json"] + delete settings.nodejs["generate-readme-md"]; + + return settings; +} + +async function updateOutputFolder(settings: readmeSettings): Promise { + settings.nodejs["output-folder"] = `$(typescript-sdks-folder)/packages/${settings.nodejs["package-name"]}`; + return settings; +} + +async function updateYamlSection(sectionText: string): Promise { + const section = yaml.safeLoad(sectionText); + await updatePackageName(section); + await updateMetadataFields(section); + await updateOutputFolder(section); + section["typescript"] = section.nodejs; + delete section.nodejs; + + return yaml.safeDump(section).trim(); +} + +export async function updateTypeScriptReadmeFile(typescriptReadmePath: string): Promise { + const readmeBuffer: Buffer = await fs.readFile(typescriptReadmePath); + const readme: string = readmeBuffer.toString(); + let outputReadme = readme; + + const yamlSection = await getYamlSection(readmeBuffer, "``` yaml $(nodejs)", "```"); + const sectionText = yamlSection.toString().trim(); + const updatedYamlSection = await updateYamlSection(sectionText); + + outputReadme = outputReadme.replace(sectionText, updatedYamlSection); + outputReadme = outputReadme.replace("azure-sdk-for-node", "azure-sdk-for-js"); + outputReadme = outputReadme.replace("Node.js", "TypeScript"); + outputReadme = outputReadme.replace("$(nodejs)", "$(typescript)"); + outputReadme = outputReadme.replace("nodejs", "typescript"); + outputReadme = outputReadme.replace("Node", "TypeScript"); + outputReadme = outputReadme.replace("node", "typescript"); + + return outputReadme; +} + +export async function saveContentToFile(filePath: string, content: string): Promise { + await fs.writeFile(filePath, content); +} \ No newline at end of file diff --git a/.scripts/logger.ts b/.scripts/logger.ts index 5d8ba75699d..804236a543e 100644 --- a/.scripts/logger.ts +++ b/.scripts/logger.ts @@ -4,25 +4,49 @@ * license information. */ +import * as colors from "colors"; import { CommandLineOptions } from "./commandLineOptions"; +export enum Color { + Red, + Green +} + export class Logger { + private _colorsMap = { + [Color.Red]: colors.red, + [Color.Green]: colors.green + } + constructor(private _options: CommandLineOptions) { } - log(text: string): void { - console.log(text); + log(text: string, color?: Color): void { + if (color !== undefined) { + const coloredText = this._colorsMap[color](text); + console.log(coloredText); + } else { + console.log(text); + } } - logVerbose(text: string): void { + logRed(text: string): void { + this.log(text, Color.Red) + } + + logGreen(text: string): void { + this.log(text, Color.Green) + } + + logVerbose(text: string, color?: Color): void { if (this._options.verbose) { - console.log(text); + this.log(text, color); } } - logDebug(text: string): void { + logDebug(text: string, color?: Color): void { if (this._options.debug) { - console.log(text); + this.log(text, color); } } } \ No newline at end of file diff --git a/gulpfile.ts b/gulpfile.ts index 3d0edc170b3..6a55674ba05 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -10,7 +10,7 @@ import * as glob from "glob"; import * as gulp from "gulp"; import * as path from "path"; import { argv } from "yargs"; -import { findAzureRestApiSpecsRepository, findSdkDirectory, findMissingSdks, copyExistingNodeJsReadme } from "./.scripts/generate-sdks"; +import { findAzureRestApiSpecsRepository, findSdkDirectory, findMissingSdks, copyExistingNodeJsReadme, updateTypeScriptReadmeFile, saveContentToFile } from "./.scripts/generate-sdks"; const azureSDKForJSRepoRoot: string = __dirname; const azureRestAPISpecsRoot: string = argv['azure-rest-api-specs-root'] || path.resolve(azureSDKForJSRepoRoot, '..', 'azure-rest-api-specs'); @@ -269,14 +269,20 @@ gulp.task("generate-ts-readme", async () => { try { console.log(`Passed arguments: ${process.argv}`); - const azureRestApiSpecsRepository = await findAzureRestApiSpecsRepository(); + const azureRestApiSpecsRepository: string = await findAzureRestApiSpecsRepository(); console.log(`Found azure-rest-api-specs repository in ${azureRestApiSpecsRepository}`); - const sdkPath = await findSdkDirectory(azureRestApiSpecsRepository); + const sdkPath: string = await findSdkDirectory(azureRestApiSpecsRepository); console.log(`Found specification in ${sdkPath}`); - await copyExistingNodeJsReadme(sdkPath); + const typescriptReadmePath: string = await copyExistingNodeJsReadme(sdkPath); console.log(`Copied readme file successfully`); + + const newContent: string = await updateTypeScriptReadmeFile(typescriptReadmePath); + console.log(`Generated content of the new readme file successfully`); + + await saveContentToFile(typescriptReadmePath, newContent); + console.log(`Content saved successfully to ${typescriptReadmePath}`); } catch (error) { console.error(error); diff --git a/package.json b/package.json index e38dfe50baa..9604f8fd167 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,13 @@ }, "devDependencies": { "@types/colors": "^1.2.1", + "@types/js-yaml": "^3.11.2", "@types/minimist": "^1.2.0", "@types/node": "^10.11.4", "colors": "^1.3.2", "fs": "0.0.1-security", "gulp": "^3.9.1", + "js-yaml": "^3.12.0", "minimist": "^1.2.0", "path": "^0.12.7", "ts-node": "^7.0.1",