check-napi.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. 'use strict';
  2. // Descend into a directory structure and, for each file matching *.node, output
  3. // based on the imports found in the file whether it's an N-API module or not.
  4. const fs = require('fs');
  5. const path = require('path');
  6. const child_process = require('child_process');
  7. // Read the output of the command, break it into lines, and use the reducer to
  8. // decide whether the file is an N-API module or not.
  9. function checkFile(file, command, argv, reducer) {
  10. const child = child_process.spawn(command, argv, {
  11. stdio: ['inherit', 'pipe', 'inherit']
  12. });
  13. let leftover = '';
  14. let isNapi = undefined;
  15. child.stdout.on('data', (chunk) => {
  16. if (isNapi === undefined) {
  17. chunk = (leftover + chunk.toString()).split(/[\r\n]+/);
  18. leftover = chunk.pop();
  19. isNapi = chunk.reduce(reducer, isNapi);
  20. if (isNapi !== undefined) {
  21. child.kill();
  22. }
  23. }
  24. });
  25. child.on('close', (code, signal) => {
  26. if ((code === null && signal !== null) || (code !== 0)) {
  27. console.log(
  28. command + ' exited with code: ' + code + ' and signal: ' + signal);
  29. } else {
  30. // Green if it's a N-API module, red otherwise.
  31. console.log(
  32. '\x1b[' + (isNapi ? '42' : '41') + 'm' +
  33. (isNapi ? ' N-API' : 'Not N-API') +
  34. '\x1b[0m: ' + file);
  35. }
  36. });
  37. }
  38. // Use nm -a to list symbols.
  39. function checkFileUNIX(file) {
  40. checkFile(file, 'nm', ['-a', file], (soFar, line) => {
  41. if (soFar === undefined) {
  42. line = line.match(/([0-9a-f]*)? ([a-zA-Z]) (.*$)/);
  43. if (line[2] === 'U') {
  44. if (/^napi/.test(line[3])) {
  45. soFar = true;
  46. }
  47. }
  48. }
  49. return soFar;
  50. });
  51. }
  52. // Use dumpbin /imports to list symbols.
  53. function checkFileWin32(file) {
  54. checkFile(file, 'dumpbin', ['/imports', file], (soFar, line) => {
  55. if (soFar === undefined) {
  56. line = line.match(/([0-9a-f]*)? +([a-zA-Z0-9]) (.*$)/);
  57. if (line && /^napi/.test(line[line.length - 1])) {
  58. soFar = true;
  59. }
  60. }
  61. return soFar;
  62. });
  63. }
  64. // Descend into a directory structure and pass each file ending in '.node' to
  65. // one of the above checks, depending on the OS.
  66. function recurse(top) {
  67. fs.readdir(top, (error, items) => {
  68. if (error) {
  69. throw ("error reading directory " + top + ": " + error);
  70. }
  71. items.forEach((item) => {
  72. item = path.join(top, item);
  73. fs.stat(item, ((item) => (error, stats) => {
  74. if (error) {
  75. throw ("error about " + item + ": " + error);
  76. }
  77. if (stats.isDirectory()) {
  78. recurse(item);
  79. } else if (/[.]node$/.test(item) &&
  80. // Explicitly ignore files called 'nothing.node' because they are
  81. // artefacts of node-addon-api having identified a version of
  82. // Node.js that ships with a correct implementation of N-API.
  83. path.basename(item) !== 'nothing.node') {
  84. process.platform === 'win32' ?
  85. checkFileWin32(item) :
  86. checkFileUNIX(item);
  87. }
  88. })(item));
  89. });
  90. });
  91. }
  92. // Start with the directory given on the command line or the current directory
  93. // if nothing was given.
  94. recurse(process.argv.length > 3 ? process.argv[2] : '.');