From 439701e3f8402d01429c026a1a2d7b7ab4749ff7 Mon Sep 17 00:00:00 2001 From: Ernest Landrito Date: Thu, 11 May 2017 10:33:45 -0700 Subject: [PATCH 1/2] Use general readme snippet. --- .../transformer/PackageMetadataNamer.java | 16 +- .../NodeJSPackageMetadataTransformer.java | 144 ++++++++++++++++-- .../nodejs/NodeJSSurfaceNamer.java | 25 +++ .../ruby/RubyPackageMetadataNamer.java | 19 --- .../google/api/codegen/nodejs/README.md.snip | 23 +++ .../{package.snip => package.json.snip} | 0 .../testdata/nodejs_README_library.baseline | 51 +++++++ .../nodejs_README_no_path_templates.baseline | 26 ++++ .../nodejs_doc_README_library.baseline | 51 +++++++ 9 files changed, 323 insertions(+), 32 deletions(-) create mode 100644 src/main/resources/com/google/api/codegen/nodejs/README.md.snip rename src/main/resources/com/google/api/codegen/nodejs/{package.snip => package.json.snip} (100%) create mode 100644 src/test/java/com/google/api/codegen/testdata/nodejs_README_library.baseline create mode 100644 src/test/java/com/google/api/codegen/testdata/nodejs_README_no_path_templates.baseline create mode 100644 src/test/java/com/google/api/codegen/testdata/nodejs_doc_README_library.baseline diff --git a/src/main/java/com/google/api/codegen/transformer/PackageMetadataNamer.java b/src/main/java/com/google/api/codegen/transformer/PackageMetadataNamer.java index b5bda1d23a..3bd06d6b1f 100644 --- a/src/main/java/com/google/api/codegen/transformer/PackageMetadataNamer.java +++ b/src/main/java/com/google/api/codegen/transformer/PackageMetadataNamer.java @@ -38,9 +38,21 @@ public String getOutputFileName() { return getNotImplementedString("PackageMetadataNamer.getOutputFileName"); } - // TODO: (landrito) this is copied from SurfaceNamer. Figure out a way to consolidate the methods. public String getReleaseAnnotation(ReleaseLevel releaseLevel) { - return getNotImplementedString("SurfaceNamer.getReleaseAnnotation"); + switch (releaseLevel) { + case UNSET_RELEASE_LEVEL: + // fallthrough + case ALPHA: + return "Alpha"; + case BETA: + return "Beta"; + case GA: + return "Production/Stable"; + case DEPRECATED: + return "Inactive"; + default: + throw new IllegalStateException("Invalid development status"); + } } /** Returns the unimplemented string message */ diff --git a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java index a329b5996d..bce8b03061 100644 --- a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java +++ b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java @@ -16,24 +16,58 @@ import com.google.api.codegen.InterfaceView; import com.google.api.codegen.TargetLanguage; +import com.google.api.codegen.config.FlatteningConfig; import com.google.api.codegen.config.GapicProductConfig; import com.google.api.codegen.config.PackageMetadataConfig; +import com.google.api.codegen.nodejs.NodeJSUtils; +import com.google.api.codegen.transformer.DynamicLangApiMethodTransformer; +import com.google.api.codegen.transformer.FileHeaderTransformer; +import com.google.api.codegen.transformer.GapicInterfaceContext; +import com.google.api.codegen.transformer.GapicMethodContext; +import com.google.api.codegen.transformer.InitCodeTransformer; import com.google.api.codegen.transformer.ModelToViewTransformer; +import com.google.api.codegen.transformer.ModelTypeTable; import com.google.api.codegen.transformer.PackageMetadataTransformer; +import com.google.api.codegen.transformer.TestCaseTransformer; +import com.google.api.codegen.util.js.JSTypeTable; +import com.google.api.codegen.util.testing.StandardValueProducer; +import com.google.api.codegen.util.testing.ValueProducer; +import com.google.api.codegen.viewmodel.ApiMethodView; +import com.google.api.codegen.viewmodel.ImportSectionView; +import com.google.api.codegen.viewmodel.InitCodeView; +import com.google.api.codegen.viewmodel.OptionalArrayMethodView; import com.google.api.codegen.viewmodel.ViewModel; import com.google.api.tools.framework.model.Interface; +import com.google.api.tools.framework.model.Method; import com.google.api.tools.framework.model.Model; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** Responsible for producing package metadata related views for NodeJS */ public class NodeJSPackageMetadataTransformer implements ModelToViewTransformer { - private static final String PACKAGE_FILE = "nodejs/package.snip"; + private static final String README_FILE = "nodejs/README.md.snip"; + private static final String README_OUTPUT_FILE = "README.md"; + private static final List TOP_LEVEL_FILES = ImmutableList.of("nodejs/package.json.snip"); - PackageMetadataConfig packageConfig; - PackageMetadataTransformer metadataTransformer = new PackageMetadataTransformer(); + private static final String GITHUB_DOC_HOST = + "https://googlecloudplatform.github.io/google-cloud-node"; + private static final String GITHUB_REPO_HOST = + "https://github.com/GoogleCloudPlatform/google-cloud-node"; + private static final String AUTH_DOC_PATH = "/#/docs/google-cloud/master/guides/authentication"; + private static final String LIB_DOC_PATH = "/#/docs/%s"; + private static final String MAIN_README_PATH = "/blob/master/README.md"; + private static final String VERSIONING_DOC_PATH = "#versioning"; + + private static String NODE_PREFIX = "nodejs/"; + + private final FileHeaderTransformer fileHeaderTransformer = + new FileHeaderTransformer(new NodeJSImportSectionTransformer()); + private final PackageMetadataConfig packageConfig; + private final PackageMetadataTransformer metadataTransformer = new PackageMetadataTransformer(); + private final ValueProducer valueProducer = new StandardValueProducer(); + private final TestCaseTransformer testCaseTransformer = new TestCaseTransformer(valueProducer); public NodeJSPackageMetadataTransformer(PackageMetadataConfig packageConfig) { this.packageConfig = packageConfig; @@ -41,28 +75,116 @@ public NodeJSPackageMetadataTransformer(PackageMetadataConfig packageConfig) { @Override public List getTemplateFileNames() { - return Arrays.asList(PACKAGE_FILE); + return ImmutableList.builder().addAll(TOP_LEVEL_FILES).add(README_FILE).build(); } @Override public List transform(Model model, GapicProductConfig productConfig) { - Iterable services = new InterfaceView().getElementIterable(model); - boolean hasMultipleServices = Iterables.size(services) > 1; List models = new ArrayList(); NodeJSPackageMetadataNamer namer = new NodeJSPackageMetadataNamer( productConfig.getPackageName(), productConfig.getDomainLayerLocation()); - models.add(generateMetadataView(model, namer, hasMultipleServices)); + models.addAll(generateMetadataViews(model, namer)); + models.add(generateReadmeView(model, productConfig, namer)); return models; } - private ViewModel generateMetadataView( - Model model, NodeJSPackageMetadataNamer namer, boolean hasMultipleServices) { + private ViewModel generateReadmeView( + Model model, GapicProductConfig productConfig, NodeJSPackageMetadataNamer namer) { + List exampleMethods = generateExampleMethods(model, productConfig); return metadataTransformer .generateMetadataView( - packageConfig, model, PACKAGE_FILE, "package.json", TargetLanguage.NODEJS) + packageConfig, model, README_FILE, README_OUTPUT_FILE, TargetLanguage.NODEJS) + .identifier(namer.getMetadataIdentifier()) + .fileHeader( + fileHeaderTransformer.generateFileHeader( + productConfig, + ImportSectionView.newBuilder().build(), + new NodeJSSurfaceNamer( + productConfig.getPackageName(), NodeJSUtils.isGcloud(productConfig)))) + .developmentStatus( + namer.getReleaseAnnotation(packageConfig.releaseLevel(TargetLanguage.NODEJS))) + .exampleMethods(exampleMethods) + .targetLanguage("NodeJS") + .mainReadmeLink(GITHUB_REPO_HOST + MAIN_README_PATH) + .libraryDocumentationLink( + GITHUB_DOC_HOST + String.format(LIB_DOC_PATH, packageConfig.shortName())) + .authDocumentationLink(GITHUB_DOC_HOST + AUTH_DOC_PATH) + .versioningDocumentationLink(GITHUB_REPO_HOST + VERSIONING_DOC_PATH) + .build(); + } + + // Generates methods used as examples for the README.md file. + // Note: This is based on sample gen method calls. In the future, the example + // methods may be configured separately. + private List generateExampleMethods( + Model model, GapicProductConfig productConfig) { + ImmutableList.Builder exampleMethods = ImmutableList.builder(); + for (Interface apiInterface : new InterfaceView().getElementIterable(model)) { + GapicInterfaceContext context = createContext(apiInterface, productConfig); + if (context.getInterfaceConfig().getSmokeTestConfig() != null) { + Method method = context.getInterfaceConfig().getSmokeTestConfig().getMethod(); + FlatteningConfig flatteningGroup = + testCaseTransformer.getSmokeTestFlatteningGroup( + context.getMethodConfig(method), context.getInterfaceConfig().getSmokeTestConfig()); + GapicMethodContext flattenedMethodContext = + context.asFlattenedMethodContext(method, flatteningGroup); + exampleMethods.add(createExampleApiMethodView(flattenedMethodContext)); + } + } + return exampleMethods.build(); + } + + private OptionalArrayMethodView createExampleApiMethodView(GapicMethodContext context) { + OptionalArrayMethodView initialApiMethodView = + new DynamicLangApiMethodTransformer(new NodeJSApiMethodParamTransformer()) + .generateMethod(context); + + OptionalArrayMethodView.Builder apiMethodView = initialApiMethodView.toBuilder(); + + InitCodeTransformer initCodeTransformer = new InitCodeTransformer(); + InitCodeView initCodeView = + initCodeTransformer.generateInitCode( + context, testCaseTransformer.createSmokeTestInitContext(context)); + apiMethodView.initCode(initCodeView); + + return apiMethodView.build(); + } + + private List generateMetadataViews(Model model, NodeJSPackageMetadataNamer namer) { + ImmutableList.Builder views = ImmutableList.builder(); + for (String template : TOP_LEVEL_FILES) { + views.add(generateMetadataView(model, template, namer)); + } + return views.build(); + } + + private ViewModel generateMetadataView( + Model model, String template, NodeJSPackageMetadataNamer namer) { + String noLeadingNodeDir = + template.startsWith(NODE_PREFIX) ? template.substring(NODE_PREFIX.length()) : template; + int extensionIndex = noLeadingNodeDir.lastIndexOf("."); + String outputPath = noLeadingNodeDir.substring(0, extensionIndex); + + Iterable services = new InterfaceView().getElementIterable(model); + boolean hasMultipleServices = Iterables.size(services) > 1; + + return metadataTransformer + .generateMetadataView(packageConfig, model, template, outputPath, TargetLanguage.NODEJS) .identifier(namer.getMetadataIdentifier()) .hasMultipleServices(hasMultipleServices) .build(); } + + private GapicInterfaceContext createContext( + Interface apiInterface, GapicProductConfig productConfig) { + return GapicInterfaceContext.create( + apiInterface, + productConfig, + new ModelTypeTable( + new JSTypeTable(productConfig.getPackageName()), + new NodeJSModelTypeNameConverter(productConfig.getPackageName())), + new NodeJSSurfaceNamer(productConfig.getPackageName(), NodeJSUtils.isGcloud(productConfig)), + new NodeJSFeatureConfig()); + } } diff --git a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSSurfaceNamer.java b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSSurfaceNamer.java index 4e1231d64f..eb6eeeb63e 100644 --- a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSSurfaceNamer.java +++ b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSSurfaceNamer.java @@ -21,12 +21,14 @@ import com.google.api.codegen.config.GrpcStreamingConfig.GrpcStreamingType; import com.google.api.codegen.config.SingleResourceNameConfig; import com.google.api.codegen.config.VisibilityConfig; +import com.google.api.codegen.metacode.InitFieldConfig; import com.google.api.codegen.transformer.FeatureConfig; import com.google.api.codegen.transformer.GapicInterfaceContext; import com.google.api.codegen.transformer.ModelTypeFormatterImpl; import com.google.api.codegen.transformer.ModelTypeTable; import com.google.api.codegen.transformer.SurfaceNamer; import com.google.api.codegen.transformer.Synchronicity; +import com.google.api.codegen.util.CommonRenderingUtil; import com.google.api.codegen.util.Name; import com.google.api.codegen.util.NamePath; import com.google.api.codegen.util.js.JSCommentReformatter; @@ -40,9 +42,11 @@ import com.google.api.tools.framework.model.Method; import com.google.api.tools.framework.model.ProtoFile; import com.google.api.tools.framework.model.TypeRef; +import com.google.common.base.Joiner; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -465,4 +469,25 @@ public String getStreamTypeName(GrpcStreamingType type) { "SurfaceNamer.getStreamTypeName(GrpcStreamingType." + type.toString() + ")"); } } + + @Override + public String injectRandomStringGeneratorCode(String randomString) { + String delimiter = ","; + String[] split = + CommonRenderingUtil.stripQuotes(randomString) + .replace( + InitFieldConfig.RANDOM_TOKEN, delimiter + InitFieldConfig.RANDOM_TOKEN + delimiter) + .split(delimiter); + ArrayList stringParts = new ArrayList<>(); + for (String token : split) { + if (token.length() > 0) { + if (token.equals(InitFieldConfig.RANDOM_TOKEN)) { + stringParts.add("Date.now().toString()"); + } else { + stringParts.add("\"" + token + "\""); + } + } + } + return Joiner.on(" + ").join(stringParts); + } } diff --git a/src/main/java/com/google/api/codegen/transformer/ruby/RubyPackageMetadataNamer.java b/src/main/java/com/google/api/codegen/transformer/ruby/RubyPackageMetadataNamer.java index bf8dacea73..65cf6c1fd3 100644 --- a/src/main/java/com/google/api/codegen/transformer/ruby/RubyPackageMetadataNamer.java +++ b/src/main/java/com/google/api/codegen/transformer/ruby/RubyPackageMetadataNamer.java @@ -14,7 +14,6 @@ */ package com.google.api.codegen.transformer.ruby; -import com.google.api.codegen.ReleaseLevel; import com.google.api.codegen.transformer.PackageMetadataNamer; import com.google.api.codegen.util.Name; import com.google.common.base.Joiner; @@ -47,22 +46,4 @@ public String getMetadataIdentifier() { public String getOutputFileName() { return getMetadataIdentifier() + ".gemspec"; } - - @Override - public String getReleaseAnnotation(ReleaseLevel releaseLevel) { - switch (releaseLevel) { - case UNSET_RELEASE_LEVEL: - // fallthrough - case ALPHA: - return "Alpha"; - case BETA: - return "Beta"; - case GA: - return "Production/Stable"; - case DEPRECATED: - return "Inactive"; - default: - throw new IllegalStateException("Invalid development status"); - } - } } diff --git a/src/main/resources/com/google/api/codegen/nodejs/README.md.snip b/src/main/resources/com/google/api/codegen/nodejs/README.md.snip new file mode 100644 index 0000000000..1322d7e70d --- /dev/null +++ b/src/main/resources/com/google/api/codegen/nodejs/README.md.snip @@ -0,0 +1,23 @@ +@extends "nodejs/method_sample.snip" +@extends "readme.snip" + +@snippet generate(metadata) + {@readme(metadata, exampleMethods(metadata.exampleMethods, metadata), installationLines(metadata))} +@end + +@private exampleMethods(methods, metadata) + @join method : methods on BREAK + @#### {@method.apiClassName} + ```js + var {@method.apiModuleName} = require('{@metadata.identifier}').{@metadata.majorVersion}({ + // optional auth parameters. + }); + + {@decorateSampleCode(method, sampleCode(method))} + ``` + @end +@end + +@private installationLines(metadata) + $ npm install {@metadata.identifier} +@end diff --git a/src/main/resources/com/google/api/codegen/nodejs/package.snip b/src/main/resources/com/google/api/codegen/nodejs/package.json.snip similarity index 100% rename from src/main/resources/com/google/api/codegen/nodejs/package.snip rename to src/main/resources/com/google/api/codegen/nodejs/package.json.snip diff --git a/src/test/java/com/google/api/codegen/testdata/nodejs_README_library.baseline b/src/test/java/com/google/api/codegen/testdata/nodejs_README_library.baseline new file mode 100644 index 0000000000..c4aff52a5a --- /dev/null +++ b/src/test/java/com/google/api/codegen/testdata/nodejs_README_library.baseline @@ -0,0 +1,51 @@ +============== file: README.md ============== +# NodeJS Client for Google Example Library API ([Alpha](https://github.com/GoogleCloudPlatform/google-cloud-node#versioning)) + +Idiomatic NodeJS client for [Google Example Library API][Product Documentation] +- [Client Library Documentation][] +- [Product Documentation][] + +## Quick Start +In order to use this library, you first need to go through the following steps: + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) +2. [Enable the library api.](https://console.cloud.google.com/apis/api/library) +3. [Setup Authentication.](https://googlecloudplatform.github.io/google-cloud-node/#/docs/google-cloud/master/guides/authentication) + +### Installation +``` +$ npm install @google-cloud/library +``` + +### Preview +#### LibraryServiceClient +```js + var libraryV1 = require('@google-cloud/library').v1({ + // optional auth parameters. + }); + + var client = libraryV1.libraryServiceClient(); + var formattedName = client.bookPath("testShelf-" + Date.now().toString(), projectId); + var rating = libraryV1.Book.Rating.GOOD; + var book = { + rating : rating + }; + var request = { + name: formattedName, + book: book + }; + client.updateBook(request).then(function(responses) { + var response = responses[0]; + // doThingsWith(response) + }).catch(function(err) { + console.error(err); + }); +``` + +### Next Steps +- Read the [Client Library Documentation][] for Google Example Library API to see other available methods on the client. +- Read the [Google Example Library API Product documentation][Product Documentation] to learn more about the product and see How-to Guides. +- View this [repository's main README](https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/README.md) to see the full list of Cloud APIs that we cover. + +[Client Library Documentation]: https://googlecloudplatform.github.io/google-cloud-node/#/docs/library +[Product Documentation]: https://cloud.google.com/library diff --git a/src/test/java/com/google/api/codegen/testdata/nodejs_README_no_path_templates.baseline b/src/test/java/com/google/api/codegen/testdata/nodejs_README_no_path_templates.baseline new file mode 100644 index 0000000000..b621c3d28e --- /dev/null +++ b/src/test/java/com/google/api/codegen/testdata/nodejs_README_no_path_templates.baseline @@ -0,0 +1,26 @@ +============== file: README.md ============== +# NodeJS Client for Google Fake API ([Alpha](https://github.com/GoogleCloudPlatform/google-cloud-node#versioning)) + +Idiomatic NodeJS client for [Google Fake API][Product Documentation] +- [Client Library Documentation][] +- [Product Documentation][] + +## Quick Start +In order to use this library, you first need to go through the following steps: + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) +2. [Enable the library api.](https://console.cloud.google.com/apis/api/library) +3. [Setup Authentication.](https://googlecloudplatform.github.io/google-cloud-node/#/docs/google-cloud/master/guides/authentication) + +### Installation +``` +$ npm install example +``` + +### Next Steps +- Read the [Client Library Documentation][] for Google Fake API to see other available methods on the client. +- Read the [Google Fake API Product documentation][Product Documentation] to learn more about the product and see How-to Guides. +- View this [repository's main README](https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/README.md) to see the full list of Cloud APIs that we cover. + +[Client Library Documentation]: https://googlecloudplatform.github.io/google-cloud-node/#/docs/library +[Product Documentation]: https://cloud.google.com/library diff --git a/src/test/java/com/google/api/codegen/testdata/nodejs_doc_README_library.baseline b/src/test/java/com/google/api/codegen/testdata/nodejs_doc_README_library.baseline new file mode 100644 index 0000000000..c4aff52a5a --- /dev/null +++ b/src/test/java/com/google/api/codegen/testdata/nodejs_doc_README_library.baseline @@ -0,0 +1,51 @@ +============== file: README.md ============== +# NodeJS Client for Google Example Library API ([Alpha](https://github.com/GoogleCloudPlatform/google-cloud-node#versioning)) + +Idiomatic NodeJS client for [Google Example Library API][Product Documentation] +- [Client Library Documentation][] +- [Product Documentation][] + +## Quick Start +In order to use this library, you first need to go through the following steps: + +1. [Select or create a Cloud Platform project.](https://console.cloud.google.com/project) +2. [Enable the library api.](https://console.cloud.google.com/apis/api/library) +3. [Setup Authentication.](https://googlecloudplatform.github.io/google-cloud-node/#/docs/google-cloud/master/guides/authentication) + +### Installation +``` +$ npm install @google-cloud/library +``` + +### Preview +#### LibraryServiceClient +```js + var libraryV1 = require('@google-cloud/library').v1({ + // optional auth parameters. + }); + + var client = libraryV1.libraryServiceClient(); + var formattedName = client.bookPath("testShelf-" + Date.now().toString(), projectId); + var rating = libraryV1.Book.Rating.GOOD; + var book = { + rating : rating + }; + var request = { + name: formattedName, + book: book + }; + client.updateBook(request).then(function(responses) { + var response = responses[0]; + // doThingsWith(response) + }).catch(function(err) { + console.error(err); + }); +``` + +### Next Steps +- Read the [Client Library Documentation][] for Google Example Library API to see other available methods on the client. +- Read the [Google Example Library API Product documentation][Product Documentation] to learn more about the product and see How-to Guides. +- View this [repository's main README](https://github.com/GoogleCloudPlatform/google-cloud-node/blob/master/README.md) to see the full list of Cloud APIs that we cover. + +[Client Library Documentation]: https://googlecloudplatform.github.io/google-cloud-node/#/docs/library +[Product Documentation]: https://cloud.google.com/library From c70fd5881dd3267e496c8260d03d7a65ac137052 Mon Sep 17 00:00:00 2001 From: Ernest Landrito Date: Mon, 22 May 2017 10:04:08 -0700 Subject: [PATCH 2/2] fix --- .../transformer/nodejs/NodeJSPackageMetadataTransformer.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java index bce8b03061..6e3dd89caf 100644 --- a/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java +++ b/src/main/java/com/google/api/codegen/transformer/nodejs/NodeJSPackageMetadataTransformer.java @@ -92,6 +92,8 @@ public List transform(Model model, GapicProductConfig productConfig) private ViewModel generateReadmeView( Model model, GapicProductConfig productConfig, NodeJSPackageMetadataNamer namer) { List exampleMethods = generateExampleMethods(model, productConfig); + Iterable services = new InterfaceView().getElementIterable(model); + boolean hasMultipleServices = Iterables.size(services) > 1; return metadataTransformer .generateMetadataView( packageConfig, model, README_FILE, README_OUTPUT_FILE, TargetLanguage.NODEJS) @@ -102,9 +104,10 @@ private ViewModel generateReadmeView( ImportSectionView.newBuilder().build(), new NodeJSSurfaceNamer( productConfig.getPackageName(), NodeJSUtils.isGcloud(productConfig)))) - .developmentStatus( + .developmentStatusTitle( namer.getReleaseAnnotation(packageConfig.releaseLevel(TargetLanguage.NODEJS))) .exampleMethods(exampleMethods) + .hasMultipleServices(hasMultipleServices) .targetLanguage("NodeJS") .mainReadmeLink(GITHUB_REPO_HOST + MAIN_README_PATH) .libraryDocumentationLink(