| #!/usr/bin/env node | 
| /********************************************************************* | 
|  * NAN - Native Abstractions for Node.js | 
|  * | 
|  * Copyright (c) 2018 NAN contributors | 
|  * | 
|  * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md> | 
|  ********************************************************************/ | 
|   | 
| var commander = require('commander'), | 
|     fs = require('fs'), | 
|     glob = require('glob'), | 
|     groups = [], | 
|     total = 0, | 
|     warning1 = '/* ERROR: Rewrite using Buffer */\n', | 
|     warning2 = '\\/\\* ERROR\\: Rewrite using Buffer \\*\\/\\n', | 
|     length, | 
|     i; | 
|   | 
| fs.readFile(__dirname + '/package.json', 'utf8', function (err, data) { | 
|   if (err) { | 
|     throw err; | 
|   } | 
|   | 
|   commander | 
|       .version(JSON.parse(data).version) | 
|       .usage('[options] <file ...>') | 
|       .parse(process.argv); | 
|   | 
|   if (!process.argv.slice(2).length) { | 
|     commander.outputHelp(); | 
|   } | 
| }); | 
|   | 
| /* construct strings representing regular expressions | 
|    each expression contains a unique group allowing for identification of the match | 
|    the index of this key group, relative to the regular expression in question, | 
|     is indicated by the first array member */ | 
|   | 
| /* simple substistutions, key group is the entire match, 0 */ | 
| groups.push([0, [ | 
|   '_NAN_', | 
|   'NODE_SET_METHOD', | 
|   'NODE_SET_PROTOTYPE_METHOD', | 
|   'NanAsciiString', | 
|   'NanEscapeScope', | 
|   'NanReturnValue', | 
|   'NanUcs2String'].join('|')]); | 
|   | 
| /* substitutions of parameterless macros, key group is 1 */ | 
| groups.push([1, ['(', [ | 
|   'NanEscapableScope', | 
|   'NanReturnNull', | 
|   'NanReturnUndefined', | 
|   'NanScope'].join('|'), ')\\(\\)'].join('')]); | 
|   | 
| /* replace TryCatch with NanTryCatch once, gobbling possible namespace, key group 2 */ | 
| groups.push([2, '(?:(?:v8\\:\\:)?|(Nan)?)(TryCatch)']); | 
|   | 
| /* NanNew("string") will likely not fail a ToLocalChecked(), key group 1 */  | 
| groups.push([1, ['(NanNew)', '(\\("[^\\"]*"[^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]); | 
|   | 
| /* Removed v8 APIs, warn that the code needs rewriting using node::Buffer, key group 2 */ | 
| groups.push([2, ['(', warning2, ')?', '^.*?(', [ | 
|       'GetIndexedPropertiesExternalArrayDataLength', | 
|       'GetIndexedPropertiesExternalArrayData', | 
|       'GetIndexedPropertiesExternalArrayDataType', | 
|       'GetIndexedPropertiesPixelData', | 
|       'GetIndexedPropertiesPixelDataLength', | 
|       'HasIndexedPropertiesInExternalArrayData', | 
|       'HasIndexedPropertiesInPixelData', | 
|       'SetIndexedPropertiesToExternalArrayData', | 
|       'SetIndexedPropertiesToPixelData'].join('|'), ')'].join('')]); | 
|   | 
| /* No need for NanScope in V8-exposed methods, key group 2 */ | 
| groups.push([2, ['((', [ | 
|       'NAN_METHOD', | 
|       'NAN_GETTER', | 
|       'NAN_SETTER', | 
|       'NAN_PROPERTY_GETTER', | 
|       'NAN_PROPERTY_SETTER', | 
|       'NAN_PROPERTY_ENUMERATOR', | 
|       'NAN_PROPERTY_DELETER', | 
|       'NAN_PROPERTY_QUERY', | 
|       'NAN_INDEX_GETTER', | 
|       'NAN_INDEX_SETTER', | 
|       'NAN_INDEX_ENUMERATOR', | 
|       'NAN_INDEX_DELETER', | 
|       'NAN_INDEX_QUERY'].join('|'), ')\\([^\\)]*\\)\\s*\\{)\\s*NanScope\\(\\)\\s*;'].join('')]); | 
|   | 
| /* v8::Value::ToXXXXXXX returns v8::MaybeLocal<T>, key group 3 */ | 
| groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->(', [ | 
|       'Boolean', | 
|       'Number', | 
|       'String', | 
|       'Object', | 
|       'Integer', | 
|       'Uint32', | 
|       'Int32'].join('|'), ')\\('].join('')]); | 
|   | 
| /* v8::Value::XXXXXXXValue returns v8::Maybe<T>, key group 3 */ | 
| groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->((?:', [ | 
|       'Boolean', | 
|       'Number', | 
|       'Integer', | 
|       'Uint32', | 
|       'Int32'].join('|'), ')Value)\\('].join('')]); | 
|   | 
| /* NAN_WEAK_CALLBACK macro was removed, write out callback definition, key group 1 */ | 
| groups.push([1, '(NAN_WEAK_CALLBACK)\\(([^\\s\\)]+)\\)']); | 
|   | 
| /* node::ObjectWrap and v8::Persistent have been replaced with Nan implementations, key group 1 */ | 
| groups.push([1, ['(', [ | 
|   'NanDisposePersistent', | 
|   'NanObjectWrapHandle'].join('|'), ')\\s*\\(\\s*([^\\s\\)]+)'].join('')]); | 
|   | 
| /* Since NanPersistent there is no need for NanMakeWeakPersistent, key group 1 */ | 
| groups.push([1, '(NanMakeWeakPersistent)\\s*\\(\\s*([^\\s,]+)\\s*,\\s*']); | 
|   | 
| /* Many methods of v8::Object and others now return v8::MaybeLocal<T>, key group 3 */ | 
| groups.push([3, ['([\\s])([^\\s]+)->(', [ | 
|   'GetEndColumn', | 
|   'GetFunction', | 
|   'GetLineNumber', | 
|   'NewInstance', | 
|   'GetPropertyNames', | 
|   'GetOwnPropertyNames', | 
|   'GetSourceLine', | 
|   'GetStartColumn', | 
|   'ObjectProtoToString', | 
|   'ToArrayIndex', | 
|   'ToDetailString', | 
|   'CallAsConstructor', | 
|   'CallAsFunction', | 
|   'CloneElementAt', | 
|   'Delete', | 
|   'ForceSet', | 
|   'Get', | 
|   'GetPropertyAttributes', | 
|   'GetRealNamedProperty', | 
|   'GetRealNamedPropertyInPrototypeChain', | 
|   'Has', | 
|   'HasOwnProperty', | 
|   'HasRealIndexedProperty', | 
|   'HasRealNamedCallbackProperty', | 
|   'HasRealNamedProperty', | 
|   'Set', | 
|   'SetAccessor', | 
|   'SetIndexedPropertyHandler', | 
|   'SetNamedPropertyHandler', | 
|   'SetPrototype'].join('|'), ')\\('].join('')]); | 
|   | 
| /* You should get an error if any of these fail anyways, | 
|    or handle the error better, it is indicated either way, key group 2 */ | 
| groups.push([2, ['NanNew(<(?:v8\\:\\:)?(', ['Date', 'String', 'RegExp'].join('|'), ')>)(\\([^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]); | 
|   | 
| /* v8::Value::Equals now returns a v8::Maybe, key group 3 */ | 
| groups.push([3, '([\\s\\(\\)])([^\\s\\(\\)]+)->(Equals)\\(([^\\s\\)]+)']); | 
|   | 
| /* NanPersistent makes this unnecessary, key group 1 */ | 
| groups.push([1, '(NanAssignPersistent)(?:<v8\\:\\:[^>]+>)?\\(([^,]+),\\s*']); | 
|   | 
| /* args has been renamed to info, key group 2 */ | 
| groups.push([2, '(\\W)(args)(\\W)']) | 
|   | 
| /* node::ObjectWrap was replaced with NanObjectWrap, key group 2 */ | 
| groups.push([2, '(\\W)(?:node\\:\\:)?(ObjectWrap)(\\W)']); | 
|   | 
| /* v8::Persistent was replaced with NanPersistent, key group 2 */ | 
| groups.push([2, '(\\W)(?:v8\\:\\:)?(Persistent)(\\W)']); | 
|   | 
| /* counts the number of capturing groups in a well-formed regular expression, | 
|    ignoring non-capturing groups and escaped parentheses */ | 
| function groupcount(s) { | 
|   var positive = s.match(/\((?!\?)/g), | 
|       negative = s.match(/\\\(/g); | 
|   return (positive ? positive.length : 0) - (negative ? negative.length : 0); | 
| } | 
|   | 
| /* compute the absolute position of each key group in the joined master RegExp */ | 
| for (i = 1, length = groups.length; i < length; i++) { | 
|     total += groupcount(groups[i - 1][1]); | 
|     groups[i][0] += total; | 
| } | 
|   | 
| /* create the master RegExp, whis is the union of all the groups' expressions */ | 
| master = new RegExp(groups.map(function (a) { return a[1]; }).join('|'), 'gm'); | 
|   | 
| /* replacement function for String.replace, receives 21 arguments */ | 
| function replace() { | 
|     /* simple expressions */ | 
|       switch (arguments[groups[0][0]]) { | 
|         case '_NAN_': | 
|           return 'NAN_'; | 
|         case 'NODE_SET_METHOD': | 
|           return 'NanSetMethod'; | 
|         case 'NODE_SET_PROTOTYPE_METHOD': | 
|           return 'NanSetPrototypeMethod'; | 
|         case 'NanAsciiString': | 
|           return 'NanUtf8String'; | 
|         case 'NanEscapeScope': | 
|           return 'scope.Escape'; | 
|         case 'NanReturnNull': | 
|           return 'info.GetReturnValue().SetNull'; | 
|         case 'NanReturnValue': | 
|           return 'info.GetReturnValue().Set'; | 
|         case 'NanUcs2String': | 
|           return 'v8::String::Value'; | 
|         default: | 
|       } | 
|   | 
|       /* macros without arguments */ | 
|       switch (arguments[groups[1][0]]) { | 
|         case 'NanEscapableScope': | 
|           return 'NanEscapableScope scope' | 
|         case 'NanReturnUndefined': | 
|           return 'return'; | 
|         case 'NanScope': | 
|           return 'NanScope scope'; | 
|         default: | 
|       } | 
|   | 
|       /* TryCatch, emulate negative backref */ | 
|       if (arguments[groups[2][0]] === 'TryCatch') { | 
|         return arguments[groups[2][0] - 1] ? arguments[0] : 'NanTryCatch'; | 
|       } | 
|   | 
|       /* NanNew("foo") --> NanNew("foo").ToLocalChecked() */ | 
|       if (arguments[groups[3][0]] === 'NanNew') { | 
|         return [arguments[0], '.ToLocalChecked()'].join(''); | 
|       } | 
|   | 
|       /* insert warning for removed functions as comment on new line above */ | 
|       switch (arguments[groups[4][0]]) { | 
|         case 'GetIndexedPropertiesExternalArrayData': | 
|         case 'GetIndexedPropertiesExternalArrayDataLength': | 
|         case 'GetIndexedPropertiesExternalArrayDataType': | 
|         case 'GetIndexedPropertiesPixelData': | 
|         case 'GetIndexedPropertiesPixelDataLength': | 
|         case 'HasIndexedPropertiesInExternalArrayData': | 
|         case 'HasIndexedPropertiesInPixelData': | 
|         case 'SetIndexedPropertiesToExternalArrayData': | 
|         case 'SetIndexedPropertiesToPixelData': | 
|           return arguments[groups[4][0] - 1] ? arguments[0] : [warning1, arguments[0]].join(''); | 
|         default: | 
|       } | 
|   | 
|      /* remove unnecessary NanScope() */ | 
|       switch (arguments[groups[5][0]]) { | 
|         case 'NAN_GETTER': | 
|         case 'NAN_METHOD': | 
|         case 'NAN_SETTER': | 
|         case 'NAN_INDEX_DELETER': | 
|         case 'NAN_INDEX_ENUMERATOR': | 
|         case 'NAN_INDEX_GETTER': | 
|         case 'NAN_INDEX_QUERY': | 
|         case 'NAN_INDEX_SETTER': | 
|         case 'NAN_PROPERTY_DELETER': | 
|         case 'NAN_PROPERTY_ENUMERATOR': | 
|         case 'NAN_PROPERTY_GETTER': | 
|         case 'NAN_PROPERTY_QUERY': | 
|         case 'NAN_PROPERTY_SETTER': | 
|           return arguments[groups[5][0] - 1]; | 
|         default: | 
|       } | 
|   | 
|       /* Value conversion */ | 
|       switch (arguments[groups[6][0]]) { | 
|         case 'Boolean': | 
|         case 'Int32': | 
|         case 'Integer': | 
|         case 'Number': | 
|         case 'Object': | 
|         case 'String': | 
|         case 'Uint32': | 
|           return [arguments[groups[6][0] - 2], 'NanTo<v8::', arguments[groups[6][0]], '>(',  arguments[groups[6][0] - 1]].join(''); | 
|         default: | 
|       } | 
|   | 
|       /* other value conversion */ | 
|       switch (arguments[groups[7][0]]) { | 
|         case 'BooleanValue': | 
|           return [arguments[groups[7][0] - 2], 'NanTo<bool>(', arguments[groups[7][0] - 1]].join(''); | 
|         case 'Int32Value': | 
|           return [arguments[groups[7][0] - 2], 'NanTo<int32_t>(', arguments[groups[7][0] - 1]].join(''); | 
|         case 'IntegerValue': | 
|           return [arguments[groups[7][0] - 2], 'NanTo<int64_t>(', arguments[groups[7][0] - 1]].join(''); | 
|         case 'Uint32Value': | 
|           return [arguments[groups[7][0] - 2], 'NanTo<uint32_t>(', arguments[groups[7][0] - 1]].join(''); | 
|         default: | 
|       } | 
|   | 
|       /* NAN_WEAK_CALLBACK */ | 
|       if (arguments[groups[8][0]] === 'NAN_WEAK_CALLBACK') { | 
|         return ['template<typename T>\nvoid ', | 
|           arguments[groups[8][0] + 1], '(const NanWeakCallbackInfo<T> &data)'].join(''); | 
|       } | 
|   | 
|       /* use methods on NAN classes instead */ | 
|       switch (arguments[groups[9][0]]) { | 
|         case 'NanDisposePersistent': | 
|           return [arguments[groups[9][0] + 1], '.Reset('].join(''); | 
|         case 'NanObjectWrapHandle': | 
|           return [arguments[groups[9][0] + 1], '->handle('].join(''); | 
|         default: | 
|       } | 
|   | 
|       /* use method on NanPersistent instead */ | 
|       if (arguments[groups[10][0]] === 'NanMakeWeakPersistent') { | 
|         return arguments[groups[10][0] + 1] + '.SetWeak('; | 
|       } | 
|   | 
|       /* These return Maybes, the upper ones take no arguments */ | 
|       switch (arguments[groups[11][0]]) { | 
|         case 'GetEndColumn': | 
|         case 'GetFunction': | 
|         case 'GetLineNumber': | 
|         case 'GetOwnPropertyNames': | 
|         case 'GetPropertyNames': | 
|         case 'GetSourceLine': | 
|         case 'GetStartColumn': | 
|         case 'NewInstance': | 
|         case 'ObjectProtoToString': | 
|         case 'ToArrayIndex': | 
|         case 'ToDetailString': | 
|           return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1]].join(''); | 
|         case 'CallAsConstructor': | 
|         case 'CallAsFunction': | 
|         case 'CloneElementAt': | 
|         case 'Delete': | 
|         case 'ForceSet': | 
|         case 'Get': | 
|         case 'GetPropertyAttributes': | 
|         case 'GetRealNamedProperty': | 
|         case 'GetRealNamedPropertyInPrototypeChain': | 
|         case 'Has': | 
|         case 'HasOwnProperty': | 
|         case 'HasRealIndexedProperty': | 
|         case 'HasRealNamedCallbackProperty': | 
|         case 'HasRealNamedProperty': | 
|         case 'Set': | 
|         case 'SetAccessor': | 
|         case 'SetIndexedPropertyHandler': | 
|         case 'SetNamedPropertyHandler': | 
|         case 'SetPrototype': | 
|           return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1], ', '].join(''); | 
|         default: | 
|       } | 
|   | 
|       /* Automatic ToLocalChecked(), take it or leave it */ | 
|       switch (arguments[groups[12][0]]) { | 
|         case 'Date': | 
|         case 'String': | 
|         case 'RegExp': | 
|           return ['NanNew', arguments[groups[12][0] - 1], arguments[groups[12][0] + 1], '.ToLocalChecked()'].join(''); | 
|         default: | 
|       } | 
|   | 
|       /* NanEquals is now required for uniformity */ | 
|       if (arguments[groups[13][0]] === 'Equals') { | 
|         return [arguments[groups[13][0] - 1], 'NanEquals(', arguments[groups[13][0] - 1], ', ', arguments[groups[13][0] + 1]].join(''); | 
|       } | 
|   | 
|       /* use method on replacement class instead */ | 
|       if (arguments[groups[14][0]] === 'NanAssignPersistent') { | 
|         return [arguments[groups[14][0] + 1], '.Reset('].join(''); | 
|       } | 
|   | 
|       /* args --> info */ | 
|       if (arguments[groups[15][0]] === 'args') { | 
|         return [arguments[groups[15][0] - 1], 'info', arguments[groups[15][0] + 1]].join(''); | 
|       } | 
|   | 
|       /* ObjectWrap --> NanObjectWrap */ | 
|       if (arguments[groups[16][0]] === 'ObjectWrap') { | 
|         return [arguments[groups[16][0] - 1], 'NanObjectWrap', arguments[groups[16][0] + 1]].join(''); | 
|       } | 
|   | 
|       /* Persistent --> NanPersistent */ | 
|       if (arguments[groups[17][0]] === 'Persistent') { | 
|         return [arguments[groups[17][0] - 1], 'NanPersistent', arguments[groups[17][0] + 1]].join(''); | 
|       } | 
|   | 
|       /* This should not happen. A switch is probably missing a case if it does. */ | 
|       throw 'Unhandled match: ' + arguments[0]; | 
| } | 
|   | 
| /* reads a file, runs replacement and writes it back */ | 
| function processFile(file) { | 
|   fs.readFile(file, {encoding: 'utf8'}, function (err, data) { | 
|     if (err) { | 
|       throw err; | 
|     } | 
|   | 
|     /* run replacement twice, might need more runs */ | 
|     fs.writeFile(file, data.replace(master, replace).replace(master, replace), function (err) { | 
|       if (err) { | 
|         throw err; | 
|       } | 
|     }); | 
|   }); | 
| } | 
|   | 
| /* process file names from command line and process the identified files */ | 
| for (i = 2, length = process.argv.length; i < length; i++) { | 
|   glob(process.argv[i], function (err, matches) { | 
|     if (err) { | 
|       throw err; | 
|     } | 
|     matches.forEach(processFile); | 
|   }); | 
| } |