package-metadata.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const fs_1 = require("fs");
  4. const os_1 = require("os");
  5. const path = require("path");
  6. const ini = require('ini');
  7. const lockfile = require('@yarnpkg/lockfile');
  8. const pacote = require('pacote');
  9. let npmrc;
  10. function ensureNpmrc(logger, usingYarn, verbose) {
  11. if (!npmrc) {
  12. try {
  13. npmrc = readOptions(logger, false, verbose);
  14. }
  15. catch (_a) { }
  16. if (usingYarn) {
  17. try {
  18. npmrc = { ...npmrc, ...readOptions(logger, true, verbose) };
  19. }
  20. catch (_b) { }
  21. }
  22. }
  23. }
  24. function readOptions(logger, yarn = false, showPotentials = false) {
  25. const cwd = process.cwd();
  26. const baseFilename = yarn ? 'yarnrc' : 'npmrc';
  27. const dotFilename = '.' + baseFilename;
  28. let globalPrefix;
  29. if (process.env.PREFIX) {
  30. globalPrefix = process.env.PREFIX;
  31. }
  32. else {
  33. globalPrefix = path.dirname(process.execPath);
  34. if (process.platform !== 'win32') {
  35. globalPrefix = path.dirname(globalPrefix);
  36. }
  37. }
  38. const defaultConfigLocations = [
  39. path.join(globalPrefix, 'etc', baseFilename),
  40. path.join(os_1.homedir(), dotFilename),
  41. ];
  42. const projectConfigLocations = [path.join(cwd, dotFilename)];
  43. const root = path.parse(cwd).root;
  44. for (let curDir = path.dirname(cwd); curDir && curDir !== root; curDir = path.dirname(curDir)) {
  45. projectConfigLocations.unshift(path.join(curDir, dotFilename));
  46. }
  47. if (showPotentials) {
  48. logger.info(`Locating potential ${baseFilename} files:`);
  49. }
  50. let options = {};
  51. for (const location of [...defaultConfigLocations, ...projectConfigLocations]) {
  52. if (fs_1.existsSync(location)) {
  53. if (showPotentials) {
  54. logger.info(`Trying '${location}'...found.`);
  55. }
  56. const data = fs_1.readFileSync(location, 'utf8');
  57. options = {
  58. ...options,
  59. ...(yarn ? lockfile.parse(data) : ini.parse(data)),
  60. };
  61. if (options.cafile) {
  62. const cafile = path.resolve(path.dirname(location), options.cafile);
  63. delete options.cafile;
  64. try {
  65. options.ca = fs_1.readFileSync(cafile, 'utf8').replace(/\r?\n/, '\\n');
  66. }
  67. catch (_a) { }
  68. }
  69. }
  70. else if (showPotentials) {
  71. logger.info(`Trying '${location}'...not found.`);
  72. }
  73. }
  74. // Substitute any environment variable references
  75. for (const key in options) {
  76. if (typeof options[key] === 'string') {
  77. options[key] = options[key].replace(/\$\{([^\}]+)\}/, (_, name) => process.env[name] || '');
  78. }
  79. }
  80. return options;
  81. }
  82. function normalizeManifest(rawManifest) {
  83. // TODO: Fully normalize and sanitize
  84. return {
  85. dependencies: {},
  86. devDependencies: {},
  87. peerDependencies: {},
  88. optionalDependencies: {},
  89. // tslint:disable-next-line:no-any
  90. ...rawManifest,
  91. };
  92. }
  93. async function fetchPackageMetadata(name, logger, options) {
  94. const { usingYarn, verbose, registry } = {
  95. registry: undefined,
  96. usingYarn: false,
  97. verbose: false,
  98. ...options,
  99. };
  100. ensureNpmrc(logger, usingYarn, verbose);
  101. const response = await pacote.packument(name, {
  102. 'full-metadata': true,
  103. ...npmrc,
  104. ...(registry ? { registry } : {}),
  105. });
  106. // Normalize the response
  107. const metadata = {
  108. name: response.name,
  109. tags: {},
  110. versions: {},
  111. };
  112. if (response.versions) {
  113. for (const [version, manifest] of Object.entries(response.versions)) {
  114. metadata.versions[version] = normalizeManifest(manifest);
  115. }
  116. }
  117. if (response['dist-tags']) {
  118. // Store this for use with other npm utility packages
  119. // tslint:disable-next-line: no-any
  120. metadata['dist-tags'] = response['dist-tags'];
  121. for (const [tag, version] of Object.entries(response['dist-tags'])) {
  122. const manifest = metadata.versions[version];
  123. if (manifest) {
  124. metadata.tags[tag] = manifest;
  125. }
  126. else if (verbose) {
  127. logger.warn(`Package ${metadata.name} has invalid version metadata for '${tag}'.`);
  128. }
  129. }
  130. }
  131. return metadata;
  132. }
  133. exports.fetchPackageMetadata = fetchPackageMetadata;
  134. async function fetchPackageManifest(name, logger, options) {
  135. const { usingYarn, verbose, registry } = {
  136. registry: undefined,
  137. usingYarn: false,
  138. verbose: false,
  139. ...options,
  140. };
  141. ensureNpmrc(logger, usingYarn, verbose);
  142. const response = await pacote.manifest(name, {
  143. 'full-metadata': true,
  144. ...npmrc,
  145. ...(registry ? { registry } : {}),
  146. });
  147. return normalizeManifest(response);
  148. }
  149. exports.fetchPackageManifest = fetchPackageManifest;