index.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. 'use strict'
  2. // Copyright (c) 2018 inspiredware
  3. var path = require('path')
  4. var pkg = require(path.resolve('package.json'))
  5. var versionArray = process.version
  6. .substr(1)
  7. .replace(/-.*$/, '')
  8. .split('.')
  9. .map(function (item) {
  10. return +item
  11. })
  12. /**
  13. *
  14. * A set of utilities to assist developers of tools that build
  15. * [N-API](https://nodejs.org/api/n-api.html#n_api_n_api) native add-ons.
  16. *
  17. * The main repository can be found
  18. * [here](https://github.com/inspiredware/napi-build-utils#napi-build-utils).
  19. *
  20. * @module napi-build-utils
  21. */
  22. /**
  23. * Implements a consistent name of `napi` for N-API runtimes.
  24. *
  25. * @param {string} runtime The runtime string.
  26. * @returns {boolean}
  27. */
  28. exports.isNapiRuntime = function (runtime) {
  29. return runtime === 'napi'
  30. }
  31. /**
  32. * Determines whether the specified N-API version is supported
  33. * by both the currently running Node instance and the package.
  34. *
  35. * @param {string} napiVersion The N-API version to check.
  36. * @returns {boolean}
  37. */
  38. exports.isSupportedVersion = function (napiVersion) {
  39. var version = parseInt(napiVersion, 10)
  40. return version <= exports.getNapiVersion() && exports.packageSupportsVersion(version)
  41. }
  42. /**
  43. * Determines whether the specified N-API version is supported by the package.
  44. * The N-API version must be preseent in the `package.json`
  45. * `binary.napi_versions` array.
  46. *
  47. * @param {number} napiVersion The N-API version to check.
  48. * @returns {boolean}
  49. * @private
  50. */
  51. exports.packageSupportsVersion = function (napiVersion) {
  52. if (pkg.binary && pkg.binary.napi_versions &&
  53. pkg.binary.napi_versions instanceof Array) {
  54. for (var i = 0; i < pkg.binary.napi_versions.length; i++) {
  55. if (pkg.binary.napi_versions[i] === napiVersion) return true
  56. };
  57. };
  58. return false
  59. }
  60. /**
  61. * Issues a warning to the supplied log if the N-API version is not supported
  62. * by the current Node instance or if the N-API version is not supported
  63. * by the package.
  64. *
  65. * @param {string} napiVersion The N-API version to check.
  66. * @param {Object} log The log object to which the warnings are to be issued.
  67. * Must implement the `warn` method.
  68. */
  69. exports.logUnsupportedVersion = function (napiVersion, log) {
  70. if (!exports.isSupportedVersion(napiVersion)) {
  71. if (exports.packageSupportsVersion(napiVersion)) {
  72. log.warn('This Node instance does not support N-API version ' + napiVersion)
  73. } else {
  74. log.warn('This package does not support N-API version ' + napiVersion)
  75. }
  76. }
  77. }
  78. /**
  79. * Issues warnings to the supplied log for those N-API versions not supported
  80. * by the N-API runtime or the package.
  81. *
  82. * Note that this function is specific to the
  83. * [`prebuild`](https://github.com/prebuild/prebuild#prebuild) package.
  84. *
  85. * `target` is the list of targets to be built and is determined in one of
  86. * three ways from the command line arguments:
  87. * (1) `--target` specifies a specific target to build.
  88. * (2) `--all` specifies all N-API versions supported by the package.
  89. * (3) Neither of these specifies to build the single "best version available."
  90. *
  91. * `prebuild` is an array of objects in the form `{runtime: 'napi', target: '2'}`.
  92. * The array contains the list of N-API versions that are supported by both the
  93. * package being built and the currently running Node instance.
  94. *
  95. * The objective of this function is to issue a warning for those items that appear
  96. * in the `target` argument but not in the `prebuild` argument.
  97. * If a specific target is supported by the package (`packageSupportsVersion`) but
  98. * but note in `prebuild`, the assumption is that the target is not supported by
  99. * Node.
  100. *
  101. * @param {(Array<string>|string)} target The N-API version(s) to check. Target is
  102. * @param {Array<Object>} prebuild A config object created by the `prebuild` package.
  103. * @param {Object} log The log object to which the warnings are to be issued.
  104. * Must implement the `warn` method.
  105. * @private
  106. */
  107. exports.logMissingNapiVersions = function (target, prebuild, log) {
  108. if (exports.getNapiBuildVersions()) {
  109. var targets = [].concat(target)
  110. targets.forEach(function (napiVersion) {
  111. if (!prebuildExists(prebuild, napiVersion)) {
  112. if (exports.packageSupportsVersion(parseInt(napiVersion, 10))) {
  113. log.warn('This Node instance does not support N-API version ' + napiVersion)
  114. } else {
  115. log.warn('This package does not support N-API version ' + napiVersion)
  116. }
  117. }
  118. })
  119. } else {
  120. log.error('Builds with runtime \'napi\' require a binary.napi_versions ' +
  121. 'property on the package.json file')
  122. }
  123. }
  124. /**
  125. * Determines whether the specified N-API version exists in the prebuild
  126. * configuration object.
  127. *
  128. * Note that this function is speicifc to the `prebuild` and `prebuild-install`
  129. * packages.
  130. *
  131. * @param {Object} prebuild A config object created by the `prebuild` package.
  132. * @param {string} napiVersion The N-APi version to be checked.
  133. * @return {boolean}
  134. * @private
  135. */
  136. var prebuildExists = function (prebuild, napiVersion) {
  137. if (prebuild) {
  138. for (var i = 0; i < prebuild.length; i++) {
  139. if (prebuild[i].target === napiVersion) return true
  140. }
  141. }
  142. return false
  143. }
  144. /**
  145. * Returns the best N-API version to build given the highest N-API
  146. * version supported by the current Node instance and the N-API versions
  147. * supported by the package, or undefined if a suitable N-API version
  148. * cannot be determined.
  149. *
  150. * The best build version is the greatest N-API version supported by
  151. * the package that is less than or equal to the highest N-API version
  152. * supported by the current Node instance.
  153. *
  154. * @returns {number|undefined}
  155. */
  156. exports.getBestNapiBuildVersion = function () {
  157. var bestNapiBuildVersion = 0
  158. var napiBuildVersions = exports.getNapiBuildVersions(pkg)
  159. if (napiBuildVersions) {
  160. var ourNapiVersion = exports.getNapiVersion()
  161. napiBuildVersions.forEach(function (napiBuildVersion) {
  162. if (napiBuildVersion > bestNapiBuildVersion &&
  163. napiBuildVersion <= ourNapiVersion) {
  164. bestNapiBuildVersion = napiBuildVersion
  165. }
  166. })
  167. }
  168. return bestNapiBuildVersion === 0 ? undefined : bestNapiBuildVersion
  169. }
  170. /**
  171. * Returns an array of N-API versions supported by the package.
  172. *
  173. * @returns {Array<string>}
  174. */
  175. exports.getNapiBuildVersions = function () {
  176. var napiBuildVersions = []
  177. // remove duplicates, convert to text
  178. if (pkg.binary && pkg.binary.napi_versions) {
  179. pkg.binary.napi_versions.forEach(function (napiVersion) {
  180. var duplicated = napiBuildVersions.indexOf('' + napiVersion) !== -1
  181. if (!duplicated) {
  182. napiBuildVersions.push('' + napiVersion)
  183. }
  184. })
  185. }
  186. return napiBuildVersions.length ? napiBuildVersions : undefined
  187. }
  188. /**
  189. * Returns the highest N-API version supported by the current node instance
  190. * or undefined if N-API is not supported.
  191. *
  192. * @returns {string|undefined}
  193. */
  194. exports.getNapiVersion = function () {
  195. var version = process.versions.napi // string, can be undefined
  196. if (!version) { // this code should never need to be updated
  197. if (versionArray[0] === 9 && versionArray[1] >= 3) version = '2' // 9.3.0+
  198. else if (versionArray[0] === 8) version = '1' // 8.0.0+
  199. }
  200. return version
  201. }