client-creator.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. var fs = require('fs');
  2. var path = require('path');
  3. /**
  4. * Generate service clients
  5. *
  6. * Pass optional path to target directory.
  7. * The directory must include the apis/ folder and service customizations at
  8. * `lib/services`. Clients will be generated in `clients/`.
  9. *
  10. * If parameter is not passed the repository root will be used.
  11. */
  12. function ClientCreator(basePath) {
  13. basePath = basePath || path.join(__dirname, '..');
  14. this._metadataPath = path.join(basePath, 'apis', 'metadata.json');
  15. this._apisFolderPath = path.join(basePath, 'apis');
  16. this._clientFolderPath = path.join(basePath, 'clients');
  17. this._serviceCustomizationsFolderPath = path.join(basePath, 'lib', 'services');
  18. this._packageJsonPath = path.join(basePath, 'package.json');
  19. // Lazy loading values on usage to avoid side-effects in constructor
  20. this._apiFileNames = null;
  21. this._metadata = null;
  22. }
  23. ClientCreator.prototype.loadMetadata = function loadMetadata() {
  24. if (this._metadata) {
  25. return this._metadata;
  26. }
  27. var metadataFile = fs.readFileSync(this._metadataPath);
  28. this.metadata = JSON.parse(metadataFile);
  29. return this.metadata;
  30. };
  31. ClientCreator.prototype.getAllApiFilenames = function getAllApiFilenames() {
  32. if (this._apiFileNames) {
  33. return this._apiFileNames;
  34. }
  35. var apiFileNames = fs.readdirSync(this._apisFolderPath);
  36. // filter out metadata
  37. this._apiFileNames = apiFileNames.filter(function(name) {
  38. return name !== 'metadata.json';
  39. });
  40. return this._apiFileNames;
  41. };
  42. ClientCreator.prototype.getAllApiFilenamesForService = function getAllApiFilenamesForService(modelName) {
  43. var serviceRegex = new RegExp('(^' + modelName + '-([\\d]{4}-[\\d]{2}-[\\d]{2})\\.([\\w]+))\\.json$');
  44. var modelRegex = /(([\d]{4}-[\d]{2}-[\d]{2})\.([\w]+))\.json$/;
  45. var models = {};
  46. var versions = {};
  47. this.getAllApiFilenames().filter(function(name) {
  48. return name.search(serviceRegex) === 0;
  49. }).forEach(function(name) {
  50. var matches = name.match(serviceRegex);
  51. if (!matches) {
  52. return;
  53. }
  54. var model = matches[1];
  55. var version = matches[2];
  56. var modelType = matches[3];
  57. if (!versions.hasOwnProperty(version)) {
  58. versions[version] = {};
  59. }
  60. var versionInfo = versions[version];
  61. switch (modelType) {
  62. case 'min':
  63. versionInfo.api = model;
  64. break;
  65. case 'paginators':
  66. versionInfo.paginators = model;
  67. break;
  68. case 'waiters2':
  69. versionInfo.waiters = model;
  70. break;
  71. default:
  72. return;
  73. }
  74. });
  75. models.versions = versions;
  76. return models;
  77. };
  78. ClientCreator.prototype.customizationsExist = function customizationsExist(serviceName) {
  79. var customizationsFolder = this._serviceCustomizationsFolderPath;
  80. return fs.existsSync(path.join(customizationsFolder, serviceName + '.js'));
  81. };
  82. ClientCreator.prototype.generateClientFileSource = function generateClientFileSource(serviceMetadata, specifiedVersion) {
  83. var clientFolderPath = this._clientFolderPath;
  84. var className = serviceMetadata.name;
  85. var serviceName = className.toLowerCase();
  86. var modelName = serviceMetadata.prefix || serviceName;
  87. specifiedVersion = specifiedVersion || '*';
  88. // get models for the service
  89. var models = this.getAllApiFilenamesForService(modelName);
  90. var modelVersions = models && models.versions;
  91. if (!modelVersions) {
  92. throw new Error('Unable to get models for ' + modelName);
  93. }
  94. var obsoleteVersions = serviceMetadata.versions || [];
  95. var versionNumbers = Object.keys(modelVersions);
  96. var tab = ' ';
  97. var code = '';
  98. code += 'require(\'../lib/node_loader\');\n';
  99. code += 'var AWS = require(\'../lib/core\');\n';
  100. code += 'var Service = AWS.Service;\n';
  101. code += 'var apiLoader = AWS.apiLoader;\n\n';
  102. code += 'apiLoader.services[\'' + serviceName +'\'] = {};\n';
  103. code += 'AWS.' + className + ' = Service.defineService(\'' + serviceName + '\', [\'' + [].concat(obsoleteVersions, versionNumbers).sort().join('\', \'') + '\']);\n';
  104. // pull in service customizations
  105. if (this.customizationsExist(serviceName)) {
  106. code += 'require(\'../lib/services/' + serviceName + '\');\n';
  107. }
  108. versionNumbers.forEach(function(version) {
  109. // check version
  110. if (specifiedVersion !== '*' && specifiedVersion !== version) {
  111. return;
  112. }
  113. var versionInfo = modelVersions[version];
  114. if (!versionInfo.hasOwnProperty('api')) {
  115. throw new Error('No API model for ' + serviceName + '-' + version);
  116. }
  117. code += 'Object.defineProperty(apiLoader.services[\'' + serviceName +'\'], \'' + version + '\', {\n';
  118. code += tab + 'get: function get() {\n';
  119. code += tab + tab + 'var model = require(\'../apis/' + versionInfo.api + '.json\');\n';
  120. if (versionInfo.hasOwnProperty('paginators')) {
  121. code += tab + tab + 'model.paginators = require(\'../apis/' + versionInfo.paginators + '.json\').pagination;\n';
  122. }
  123. if (versionInfo.hasOwnProperty('waiters')) {
  124. code += tab + tab + 'model.waiters = require(\'../apis/' + versionInfo.waiters + '.json\').waiters;\n';
  125. }
  126. code += tab + tab + 'return model;\n';
  127. code += tab + '},\n';
  128. code += tab + 'enumerable: true,\n';
  129. code += tab + 'configurable: true\n';
  130. code += '});\n';
  131. });
  132. code += '\n';
  133. code += 'module.exports = AWS.' + className + ';\n';
  134. return {
  135. code: code,
  136. path: path.join(clientFolderPath, serviceName + '.js'),
  137. service: serviceName,
  138. };
  139. };
  140. ClientCreator.prototype.tabs = function tabs(count) {
  141. var tab = '';
  142. for (var i = 0; i < count; i++) {
  143. tab += ' ';
  144. }
  145. return tab;
  146. };
  147. ClientCreator.prototype.generateDefinePropertySource = function generateDefinePropertySource(objName, serviceName, className) {
  148. var tabs = this.tabs;
  149. var code = '';
  150. code += 'var ' + serviceName + ' = null;\n';
  151. code += 'Object.defineProperty(' + objName + ', \'' + className + '\', {\n';
  152. code += tabs(1) + 'get: function get() {\n';
  153. code += tabs(2) + 'return ' + serviceName + ' || require(\'./' + serviceName + '\');\n';
  154. code += tabs(1) + '},\n';
  155. code += tabs(1) + 'set: function set(svc) {\n';
  156. code += tabs(2) + serviceName + ' = svc;\n';
  157. code += tabs(1) + '},\n';
  158. code += tabs(1) + 'enumerable: true,\n';
  159. code += tabs(1) + 'configurable: true\n';
  160. code += '});\n';
  161. return code;
  162. };
  163. ClientCreator.prototype.generateAllServicesSource = function generateAllServicesSource(services, fileName) {
  164. var metadata = this.loadMetadata();
  165. var self = this;
  166. var code = '';
  167. code += 'require(\'../lib/node_loader\');\n';
  168. code += 'module.exports = {\n';
  169. services.forEach(function(service, idx) {
  170. var className = metadata[service].name;
  171. var tab = ' ';
  172. var isLast = idx === services.length - 1;
  173. code += self.tabs(1) + className + ': require(\'./' + service + '\')' + (isLast ? '' : ',') + '\n';
  174. });
  175. code += '};';
  176. return {
  177. code: code,
  178. path: path.join(this._clientFolderPath, fileName + '.js'),
  179. service: fileName
  180. };
  181. };
  182. ClientCreator.prototype.getDefaultServices = function getDefaultServices() {
  183. var metadata = this.loadMetadata();
  184. var services = [];
  185. for (var key in metadata) {
  186. if (!metadata.hasOwnProperty(key)) {
  187. continue;
  188. }
  189. var className = metadata[key].name;
  190. var serviceName = className.toLowerCase();
  191. services.push(serviceName);
  192. }
  193. return services;
  194. };
  195. ClientCreator.prototype.writeClientServices = function writeClientServices() {
  196. var metadata = this.loadMetadata();
  197. var services = [];
  198. var corsServices = [];
  199. for (var key in metadata) {
  200. if (!metadata.hasOwnProperty(key)) {
  201. continue;
  202. }
  203. var clientInfo = this.generateClientFileSource(metadata[key]);
  204. fs.writeFileSync(clientInfo.path, clientInfo.code);
  205. services.push(clientInfo.service);
  206. // check if service supports CORS
  207. if (metadata[key].cors === true) {
  208. corsServices.push(clientInfo.service);
  209. }
  210. }
  211. var allClientInfo = this.generateAllServicesSource(services, 'all');
  212. fs.writeFileSync(allClientInfo.path, allClientInfo.code);
  213. var browserClientInfo = this.generateAllServicesSource(corsServices, 'browser_default');
  214. fs.writeFileSync(browserClientInfo.path, browserClientInfo.code);
  215. };
  216. module.exports = ClientCreator;