From 91d2b4e1c54af6a99f09d6e7c9cd476e4ee524f4 Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Tue, 2 Mar 2021 16:57:02 +0100
Subject: [PATCH] feat: static modules (#8679)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
---
 lib/datasource/api.ts                         |  69 ++++++++++
 lib/datasource/index.spec.ts                  |  10 +-
 lib/datasource/index.ts                       |   2 +-
 lib/manager/api.ts                            | 123 ++++++++++++++++++
 lib/manager/index.spec.ts                     |   5 +-
 lib/manager/index.ts                          |   2 +-
 lib/platform/__snapshots__/index.spec.ts.snap |  10 +-
 lib/platform/api.ts                           |  17 +++
 lib/platform/index.spec.ts                    |   6 +-
 lib/platform/index.ts                         |   2 +-
 lib/versioning/api.ts                         |  45 +++++++
 lib/versioning/index.ts                       |   2 +-
 tools/generate-imports.ts                     |  69 ----------
 13 files changed, 273 insertions(+), 89 deletions(-)
 create mode 100644 lib/datasource/api.ts
 create mode 100644 lib/manager/api.ts
 create mode 100644 lib/platform/api.ts
 create mode 100644 lib/versioning/api.ts

diff --git a/lib/datasource/api.ts b/lib/datasource/api.ts
new file mode 100644
index 0000000000..af2186b39a
--- /dev/null
+++ b/lib/datasource/api.ts
@@ -0,0 +1,69 @@
+import * as bitbucketTags from './bitbucket-tags';
+import * as cdnjs from './cdnjs';
+import * as clojure from './clojure';
+import type { DatasourceApi } from './common';
+import * as crate from './crate';
+import * as dart from './dart';
+import * as docker from './docker';
+import * as galaxy from './galaxy';
+import * as gitRefs from './git-refs';
+import * as gitSubmodules from './git-submodules';
+import * as gitTags from './git-tags';
+import * as githubReleases from './github-releases';
+import * as githubTags from './github-tags';
+import * as gitlabTags from './gitlab-tags';
+import * as go from './go';
+import * as gradleVersion from './gradle-version';
+import * as helm from './helm';
+import * as hex from './hex';
+import * as jenkinsPlugins from './jenkins-plugins';
+import * as maven from './maven';
+import * as npm from './npm';
+import * as nuget from './nuget';
+import * as orb from './orb';
+import * as packagist from './packagist';
+import * as pod from './pod';
+import * as pypi from './pypi';
+import * as repology from './repology';
+import * as rubyVersion from './ruby-version';
+import * as rubygems from './rubygems';
+import * as sbtPackage from './sbt-package';
+import * as sbtPlugin from './sbt-plugin';
+import * as terraformModule from './terraform-module';
+import * as terraformProvider from './terraform-provider';
+
+const api = new Map<string, DatasourceApi>();
+export default api;
+
+api.set('bitbucket-tags', bitbucketTags);
+api.set('cdnjs', cdnjs);
+api.set('clojure', clojure);
+api.set('crate', crate);
+api.set('dart', dart);
+api.set('docker', docker);
+api.set('galaxy', galaxy);
+api.set('git-refs', gitRefs);
+api.set('git-submodules', gitSubmodules);
+api.set('git-tags', gitTags);
+api.set('github-releases', githubReleases);
+api.set('github-tags', githubTags);
+api.set('gitlab-tags', gitlabTags);
+api.set('go', go);
+api.set('gradle-version', gradleVersion);
+api.set('helm', helm);
+api.set('hex', hex);
+api.set('jenkins-plugins', jenkinsPlugins);
+api.set('maven', maven);
+api.set('npm', npm);
+api.set('nuget', nuget);
+api.set('orb', orb);
+api.set('packagist', packagist);
+api.set('pod', pod);
+api.set('pypi', pypi);
+api.set('repology', repology);
+api.set('ruby-version', rubyVersion);
+api.set('rubygems', rubygems);
+api.set('sbt-package', sbtPackage);
+api.set('sbt-plugin', sbtPlugin);
+api.set('terraform-module', terraformModule);
+api.set('terraform-provider', terraformProvider);
diff --git a/lib/datasource/index.spec.ts b/lib/datasource/index.spec.ts
index ee1ec40b11..2d37ae1366 100644
--- a/lib/datasource/index.spec.ts
+++ b/lib/datasource/index.spec.ts
@@ -1,10 +1,11 @@
-import { mocked } from '../../test/util';
+import { getName, mocked } from '../../test/util';
 import {
   EXTERNAL_HOST_ERROR,
   HOST_DISABLED,
 } from '../constants/error-messages';
 import { ExternalHostError } from '../types/errors/external-host-error';
 import { loadModules } from '../util/modules';
+import type { Datasource } from './common';
 import * as datasourceDocker from './docker';
 import * as datasourceGithubTags from './github-tags';
 import * as datasourceMaven from './maven';
@@ -22,7 +23,7 @@ const mavenDatasource = mocked(datasourceMaven);
 const npmDatasource = mocked(datasourceNpm);
 const packagistDatasource = mocked(datasourcePackagist);
 
-describe('datasource/index', () => {
+describe(getName(__filename), () => {
   beforeEach(() => {
     jest.resetAllMocks();
   });
@@ -31,10 +32,7 @@ describe('datasource/index', () => {
     expect(datasource.getDatasourceList()).toBeDefined();
   });
   it('validates dataource', () => {
-    function validateDatasource(
-      module: datasource.Datasource,
-      name: string
-    ): boolean {
+    function validateDatasource(module: Datasource, name: string): boolean {
       if (!module.getReleases) {
         return false;
       }
diff --git a/lib/datasource/index.ts b/lib/datasource/index.ts
index d907fb674c..94f99bf850 100644
--- a/lib/datasource/index.ts
+++ b/lib/datasource/index.ts
@@ -8,7 +8,7 @@ import * as packageCache from '../util/cache/package';
 import { clone } from '../util/clone';
 import { regEx } from '../util/regex';
 import * as allVersioning from '../versioning';
-import datasources from './api.generated';
+import datasources from './api';
 import {
   Datasource,
   DigestConfig,
diff --git a/lib/manager/api.ts b/lib/manager/api.ts
new file mode 100644
index 0000000000..8bf6ba4e13
--- /dev/null
+++ b/lib/manager/api.ts
@@ -0,0 +1,123 @@
+import * as ansible from './ansible';
+import * as ansibleGalaxy from './ansible-galaxy';
+import * as azurePipelines from './azure-pipelines';
+import * as batect from './batect';
+import * as batectWrapper from './batect-wrapper';
+import * as bazel from './bazel';
+import * as buildkite from './buildkite';
+import * as bundler from './bundler';
+import * as cargo from './cargo';
+import * as cdnurl from './cdnurl';
+import * as circleci from './circleci';
+import * as cloudbuild from './cloudbuild';
+import * as cocoapods from './cocoapods';
+import type { ManagerApi } from './common';
+import * as composer from './composer';
+import * as depsEdn from './deps-edn';
+import * as dockerCompose from './docker-compose';
+import * as dockerfile from './dockerfile';
+import * as droneci from './droneci';
+import * as gitSubmodules from './git-submodules';
+import * as githubActions from './github-actions';
+import * as gitlabci from './gitlabci';
+import * as gitlabciInclude from './gitlabci-include';
+import * as gomod from './gomod';
+import * as gradle from './gradle';
+import * as gradleLite from './gradle-lite';
+import * as gradleWrapper from './gradle-wrapper';
+import * as helmRequirements from './helm-requirements';
+import * as helmValues from './helm-values';
+import * as helmfile from './helmfile';
+import * as helmv3 from './helmv3';
+import * as homebrew from './homebrew';
+import * as html from './html';
+import * as jenkins from './jenkins';
+import * as kubernetes from './kubernetes';
+import * as kustomize from './kustomize';
+import * as leiningen from './leiningen';
+import * as maven from './maven';
+import * as meteor from './meteor';
+import * as mix from './mix';
+import * as nodenv from './nodenv';
+import * as npm from './npm';
+import * as nuget from './nuget';
+import * as nvm from './nvm';
+import * as pip_requirements from './pip_requirements';
+import * as pip_setup from './pip_setup';
+import * as pipenv from './pipenv';
+import * as poetry from './poetry';
+import * as preCommit from './pre-commit';
+import * as pub from './pub';
+import * as regex from './regex';
+import * as rubyVersion from './ruby-version';
+import * as sbt from './sbt';
+import * as setupCfg from './setup-cfg';
+import * as swift from './swift';
+import * as terraform from './terraform';
+import * as terraformVersion from './terraform-version';
+import * as terragrunt from './terragrunt';
+import * as terragruntVersion from './terragrunt-version';
+import * as travis from './travis';
+
+const api = new Map<string, ManagerApi>();
+export default api;
+
+api.set('ansible', ansible);
+api.set('ansible-galaxy', ansibleGalaxy);
+api.set('azure-pipelines', azurePipelines);
+api.set('batect', batect);
+api.set('batect-wrapper', batectWrapper);
+api.set('bazel', bazel);
+api.set('buildkite', buildkite);
+api.set('bundler', bundler);
+api.set('cargo', cargo);
+api.set('cdnurl', cdnurl);
+api.set('circleci', circleci);
+api.set('cloudbuild', cloudbuild);
+api.set('cocoapods', cocoapods);
+api.set('composer', composer);
+api.set('deps-edn', depsEdn);
+api.set('docker-compose', dockerCompose);
+api.set('dockerfile', dockerfile);
+api.set('droneci', droneci);
+api.set('git-submodules', gitSubmodules);
+api.set('github-actions', githubActions);
+api.set('gitlabci', gitlabci);
+api.set('gitlabci-include', gitlabciInclude);
+api.set('gomod', gomod);
+api.set('gradle', gradle);
+api.set('gradle-lite', gradleLite);
+api.set('gradle-wrapper', gradleWrapper);
+api.set('helm-requirements', helmRequirements);
+api.set('helm-values', helmValues);
+api.set('helmfile', helmfile);
+api.set('helmv3', helmv3);
+api.set('homebrew', homebrew);
+api.set('html', html);
+api.set('jenkins', jenkins);
+api.set('kubernetes', kubernetes);
+api.set('kustomize', kustomize);
+api.set('leiningen', leiningen);
+api.set('maven', maven);
+api.set('meteor', meteor);
+api.set('mix', mix);
+api.set('nodenv', nodenv);
+api.set('npm', npm);
+api.set('nuget', nuget);
+api.set('nvm', nvm);
+api.set('pip_requirements', pip_requirements);
+api.set('pip_setup', pip_setup);
+api.set('pipenv', pipenv);
+api.set('poetry', poetry);
+api.set('pre-commit', preCommit);
+api.set('pub', pub);
+api.set('regex', regex);
+api.set('ruby-version', rubyVersion);
+api.set('sbt', sbt);
+api.set('setup-cfg', setupCfg);
+api.set('swift', swift);
+api.set('terraform', terraform);
+api.set('terraform-version', terraformVersion);
+api.set('terragrunt', terragrunt);
+api.set('terragrunt-version', terragruntVersion);
+api.set('travis', travis);
diff --git a/lib/manager/index.spec.ts b/lib/manager/index.spec.ts
index 2ba4d073b6..5b213c181a 100644
--- a/lib/manager/index.spec.ts
+++ b/lib/manager/index.spec.ts
@@ -1,8 +1,9 @@
+import { getName } from '../../test/util';
 import { loadModules } from '../util/modules';
-import { ManagerApi } from './common';
+import type { ManagerApi } from './common';
 import * as manager from '.';
 
-describe('manager', () => {
+describe(getName(__filename), () => {
   describe('get()', () => {
     it('gets something', () => {
       expect(manager.get('dockerfile', 'extractPackageFile')).not.toBeNull();
diff --git a/lib/manager/index.ts b/lib/manager/index.ts
index dd8d987b5d..48f5c8e903 100644
--- a/lib/manager/index.ts
+++ b/lib/manager/index.ts
@@ -12,7 +12,7 @@ import {
   LANGUAGE_RUST,
 } from '../constants/languages';
 import { RangeStrategy } from '../types';
-import managers from './api.generated';
+import managers from './api';
 import {
   ExtractConfig,
   LookupUpdate,
diff --git a/lib/platform/__snapshots__/index.spec.ts.snap b/lib/platform/__snapshots__/index.spec.ts.snap
index c6720de416..3f2dbd6f9e 100644
--- a/lib/platform/__snapshots__/index.spec.ts.snap
+++ b/lib/platform/__snapshots__/index.spec.ts.snap
@@ -1,8 +1,8 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`platform escapes names 1`] = `"name [what]"`;
+exports[`platform/index escapes names 1`] = `"name [what]"`;
 
-exports[`platform initializes 1`] = `
+exports[`platform/index initializes 1`] = `
 Object {
   "endpoint": "https://api.bitbucket.org/",
   "gitAuthor": "user@domain.com",
@@ -18,7 +18,7 @@ Object {
 }
 `;
 
-exports[`platform initializes no author 1`] = `
+exports[`platform/index initializes no author 1`] = `
 Object {
   "endpoint": "https://api.bitbucket.org/",
   "hostRules": Array [
@@ -33,14 +33,14 @@ Object {
 }
 `;
 
-exports[`platform parses bot email 1`] = `
+exports[`platform/index parses bot email 1`] = `
 Object {
   "address": "some[bot]@users.noreply.github.com",
   "name": "some[bot]",
 }
 `;
 
-exports[`platform parses bot name and email 1`] = `
+exports[`platform/index parses bot name and email 1`] = `
 Object {
   "address": "some[bot]@users.noreply.github.com",
   "name": "some[bot]",
diff --git a/lib/platform/api.ts b/lib/platform/api.ts
new file mode 100644
index 0000000000..7be6d66a58
--- /dev/null
+++ b/lib/platform/api.ts
@@ -0,0 +1,17 @@
+import * as azure from './azure';
+import * as bitbucket from './bitbucket';
+import * as bitbucketServer from './bitbucket-server';
+import type { Platform } from './common';
+import * as gitea from './gitea';
+import * as github from './github';
+import * as gitlab from './gitlab';
+
+const api = new Map<string, Platform>();
+export default api;
+
+api.set('azure', azure);
+api.set('bitbucket', bitbucket);
+api.set('bitbucket-server', bitbucketServer);
+api.set('gitea', gitea);
+api.set('github', github);
+api.set('gitlab', gitlab);
diff --git a/lib/platform/index.spec.ts b/lib/platform/index.spec.ts
index 6669e8f732..480976cf38 100644
--- a/lib/platform/index.spec.ts
+++ b/lib/platform/index.spec.ts
@@ -1,13 +1,13 @@
+import { getName } from '../../test/util';
 import { PLATFORM_NOT_FOUND } from '../constants/error-messages';
 import { PLATFORM_TYPE_BITBUCKET } from '../constants/platforms';
 import { loadModules } from '../util/modules';
-
+import type { Platform } from './common';
 import * as platform from '.';
-import { Platform } from '.';
 
 jest.unmock('.');
 
-describe('platform', () => {
+describe(getName(__filename), () => {
   beforeEach(() => {
     jest.resetModules();
   });
diff --git a/lib/platform/index.ts b/lib/platform/index.ts
index 3cc642d8f3..67df26ecd8 100644
--- a/lib/platform/index.ts
+++ b/lib/platform/index.ts
@@ -5,7 +5,7 @@ import { PLATFORM_NOT_FOUND } from '../constants/error-messages';
 import { logger } from '../logger';
 import { setPrivateKey } from '../util/git';
 import * as hostRules from '../util/host-rules';
-import platforms from './api.generated';
+import platforms from './api';
 import { Platform } from './common';
 
 export * from './common';
diff --git a/lib/versioning/api.ts b/lib/versioning/api.ts
new file mode 100644
index 0000000000..c5163d3c8c
--- /dev/null
+++ b/lib/versioning/api.ts
@@ -0,0 +1,45 @@
+import * as cargo from './cargo';
+import type { VersioningApi, VersioningApiConstructor } from './common';
+import * as composer from './composer';
+import * as docker from './docker';
+import * as git from './git';
+import * as gradle from './gradle';
+import * as hashicorp from './hashicorp';
+import * as hex from './hex';
+import * as ivy from './ivy';
+import * as loose from './loose';
+import * as maven from './maven';
+import * as node from './node';
+import * as npm from './npm';
+import * as nuget from './nuget';
+import * as pep440 from './pep440';
+import * as poetry from './poetry';
+import * as regex from './regex';
+import * as ruby from './ruby';
+import * as semver from './semver';
+import * as swift from './swift';
+import * as ubuntu from './ubuntu';
+
+const api = new Map<string, VersioningApi | VersioningApiConstructor>();
+export default api;
+
+api.set('cargo', cargo.api);
+api.set('composer', composer.api);
+api.set('docker', docker.api);
+api.set('git', git.api);
+api.set('gradle', gradle.api);
+api.set('hashicorp', hashicorp.api);
+api.set('hex', hex.api);
+api.set('ivy', ivy.api);
+api.set('loose', loose.api);
+api.set('maven', maven.api);
+api.set('node', node.api);
+api.set('npm', npm.api);
+api.set('nuget', nuget.api);
+api.set('pep440', pep440.api);
+api.set('poetry', poetry.api);
+api.set('regex', regex.api);
+api.set('ruby', ruby.api);
+api.set('semver', semver.api);
+api.set('swift', swift.api);
+api.set('ubuntu', ubuntu.api);
diff --git a/lib/versioning/index.ts b/lib/versioning/index.ts
index 5d872a34a4..429023918a 100644
--- a/lib/versioning/index.ts
+++ b/lib/versioning/index.ts
@@ -1,5 +1,5 @@
 import { logger } from '../logger';
-import versionings from './api.generated';
+import versionings from './api';
 import {
   VersioningApi,
   VersioningApiConstructor,
diff --git a/tools/generate-imports.ts b/tools/generate-imports.ts
index 898da74cda..90c2b2009b 100644
--- a/tools/generate-imports.ts
+++ b/tools/generate-imports.ts
@@ -14,15 +14,6 @@ if (!fs.existsSync('data')) {
   shell.exit(0);
 }
 
-function findModules(dirname: string): string[] {
-  return fs
-    .readdirSync(dirname, { withFileTypes: true })
-    .filter((dirent) => dirent.isDirectory())
-    .map((dirent) => dirent.name)
-    .filter((name) => !name.startsWith('__'))
-    .sort();
-}
-
 async function updateFile(file: string, code: string): Promise<void> {
   const oldCode = fs.existsSync(file) ? await fs.readFile(file, 'utf8') : null;
   if (code !== oldCode) {
@@ -31,45 +22,6 @@ async function updateFile(file: string, code: string): Promise<void> {
   newFiles.add(file);
 }
 
-function camelCase(input: string): string {
-  return input
-    .replace(/(?:^\w|[A-Z]|\b\w)/g, (char, index) =>
-      index === 0 ? char.toLowerCase() : char.toUpperCase()
-    )
-    .replace(/-/g, '');
-}
-
-async function generate({
-  path,
-  types,
-  map = '',
-  excludes = [],
-}: {
-  path: string;
-  types: string[];
-  map?: string;
-  excludes?: string[];
-}): Promise<void> {
-  shell.echo(`> lib/${path}/`);
-  let imports = '';
-  let maps = '';
-  for (const ds of findModules(`lib/${path}`).filter(
-    (n) => !excludes?.includes(n)
-  )) {
-    const name = camelCase(ds);
-    imports += `import * as ${name} from './${ds}';\n`;
-    maps += `api.set('${ds}', ${name}${map});\n`;
-  }
-
-  const code = `import { ${types.join(', ')} } from './common';
-    ${imports}\n
-    const api = new Map<string, ${types.join(' | ')}>();
-    export default api;
-    ${maps}`;
-
-  await updateFile(`lib/${path}/api.generated.ts`, code.replace(/^\s+/gm, ''));
-}
-
 async function generateData(): Promise<void> {
   const files = fs
     .readdirSync('data', { withFileTypes: true })
@@ -106,27 +58,6 @@ async function generateData(): Promise<void> {
   try {
     // data-files
     await generateData();
-
-    // datasources
-    await generate({ path: 'datasource', types: ['DatasourceApi'] });
-
-    // managers
-    await generate({ path: 'manager', types: ['ManagerApi'] });
-
-    // platform
-    await generate({
-      path: 'platform',
-      types: ['Platform'],
-      excludes: ['utils', 'git'],
-    });
-
-    // versioning
-    await generate({
-      path: 'versioning',
-      types: ['VersioningApi', 'VersioningApiConstructor'],
-      map: '.api',
-    });
-
     await Promise.all(
       shell
         .find('lib/**/*.generated.ts')
-- 
GitLab