index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 present 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) { // integer 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 specific 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) // array of integer strings
  159. if (napiBuildVersions) {
  160. var ourNapiVersion = exports.getNapiVersion()
  161. napiBuildVersions.forEach(function (napiBuildVersionStr) {
  162. var napiBuildVersion = parseInt(napiBuildVersionStr, 10)
  163. if (napiBuildVersion > bestNapiBuildVersion &&
  164. napiBuildVersion <= ourNapiVersion) {
  165. bestNapiBuildVersion = napiBuildVersion
  166. }
  167. })
  168. }
  169. return bestNapiBuildVersion === 0 ? undefined : bestNapiBuildVersion
  170. }
  171. /**
  172. * Returns an array of N-API versions supported by the package.
  173. *
  174. * @returns {Array<string>|undefined}
  175. */
  176. exports.getNapiBuildVersions = function () {
  177. var napiBuildVersions = []
  178. // remove duplicates, convert to text
  179. if (pkg.binary && pkg.binary.napi_versions) {
  180. pkg.binary.napi_versions.forEach(function (napiVersion) {
  181. var duplicated = napiBuildVersions.indexOf('' + napiVersion) !== -1
  182. if (!duplicated) {
  183. napiBuildVersions.push('' + napiVersion)
  184. }
  185. })
  186. }
  187. return napiBuildVersions.length ? napiBuildVersions : undefined
  188. }
  189. /**
  190. * Returns the highest N-API version supported by the current node instance
  191. * or undefined if N-API is not supported.
  192. *
  193. * @returns {string|undefined}
  194. */
  195. exports.getNapiVersion = function () {
  196. var version = process.versions.napi // integer string, can be undefined
  197. if (!version) { // this code should never need to be updated
  198. if (versionArray[0] === 9 && versionArray[1] >= 3) version = '2' // 9.3.0+
  199. else if (versionArray[0] === 8) version = '1' // 8.0.0+
  200. }
  201. return version
  202. }