UNPKG

14.4 kBJavaScriptView Raw
1#!/usr/bin/env node
2/*********************************************************************
3 * NAN - Native Abstractions for Node.js
4 *
5 * Copyright (c) 2018 NAN contributors
6 *
7 * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
8 ********************************************************************/
9
10var commander = require('commander'),
11 fs = require('fs'),
12 glob = require('glob'),
13 groups = [],
14 total = 0,
15 warning1 = '/* ERROR: Rewrite using Buffer */\n',
16 warning2 = '\\/\\* ERROR\\: Rewrite using Buffer \\*\\/\\n',
17 length,
18 i;
19
20fs.readFile(__dirname + '/package.json', 'utf8', function (err, data) {
21 if (err) {
22 throw err;
23 }
24
25 commander
26 .version(JSON.parse(data).version)
27 .usage('[options] <file ...>')
28 .parse(process.argv);
29
30 if (!process.argv.slice(2).length) {
31 commander.outputHelp();
32 }
33});
34
35/* construct strings representing regular expressions
36 each expression contains a unique group allowing for identification of the match
37 the index of this key group, relative to the regular expression in question,
38 is indicated by the first array member */
39
40/* simple substistutions, key group is the entire match, 0 */
41groups.push([0, [
42 '_NAN_',
43 'NODE_SET_METHOD',
44 'NODE_SET_PROTOTYPE_METHOD',
45 'NanAsciiString',
46 'NanEscapeScope',
47 'NanReturnValue',
48 'NanUcs2String'].join('|')]);
49
50/* substitutions of parameterless macros, key group is 1 */
51groups.push([1, ['(', [
52 'NanEscapableScope',
53 'NanReturnNull',
54 'NanReturnUndefined',
55 'NanScope'].join('|'), ')\\(\\)'].join('')]);
56
57/* replace TryCatch with NanTryCatch once, gobbling possible namespace, key group 2 */
58groups.push([2, '(?:(?:v8\\:\\:)?|(Nan)?)(TryCatch)']);
59
60/* NanNew("string") will likely not fail a ToLocalChecked(), key group 1 */
61groups.push([1, ['(NanNew)', '(\\("[^\\"]*"[^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]);
62
63/* Removed v8 APIs, warn that the code needs rewriting using node::Buffer, key group 2 */
64groups.push([2, ['(', warning2, ')?', '^.*?(', [
65 'GetIndexedPropertiesExternalArrayDataLength',
66 'GetIndexedPropertiesExternalArrayData',
67 'GetIndexedPropertiesExternalArrayDataType',
68 'GetIndexedPropertiesPixelData',
69 'GetIndexedPropertiesPixelDataLength',
70 'HasIndexedPropertiesInExternalArrayData',
71 'HasIndexedPropertiesInPixelData',
72 'SetIndexedPropertiesToExternalArrayData',
73 'SetIndexedPropertiesToPixelData'].join('|'), ')'].join('')]);
74
75/* No need for NanScope in V8-exposed methods, key group 2 */
76groups.push([2, ['((', [
77 'NAN_METHOD',
78 'NAN_GETTER',
79 'NAN_SETTER',
80 'NAN_PROPERTY_GETTER',
81 'NAN_PROPERTY_SETTER',
82 'NAN_PROPERTY_ENUMERATOR',
83 'NAN_PROPERTY_DELETER',
84 'NAN_PROPERTY_QUERY',
85 'NAN_INDEX_GETTER',
86 'NAN_INDEX_SETTER',
87 'NAN_INDEX_ENUMERATOR',
88 'NAN_INDEX_DELETER',
89 'NAN_INDEX_QUERY'].join('|'), ')\\([^\\)]*\\)\\s*\\{)\\s*NanScope\\(\\)\\s*;'].join('')]);
90
91/* v8::Value::ToXXXXXXX returns v8::MaybeLocal<T>, key group 3 */
92groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->(', [
93 'Boolean',
94 'Number',
95 'String',
96 'Object',
97 'Integer',
98 'Uint32',
99 'Int32'].join('|'), ')\\('].join('')]);
100
101/* v8::Value::XXXXXXXValue returns v8::Maybe<T>, key group 3 */
102groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->((?:', [
103 'Boolean',
104 'Number',
105 'Integer',
106 'Uint32',
107 'Int32'].join('|'), ')Value)\\('].join('')]);
108
109/* NAN_WEAK_CALLBACK macro was removed, write out callback definition, key group 1 */
110groups.push([1, '(NAN_WEAK_CALLBACK)\\(([^\\s\\)]+)\\)']);
111
112/* node::ObjectWrap and v8::Persistent have been replaced with Nan implementations, key group 1 */
113groups.push([1, ['(', [
114 'NanDisposePersistent',
115 'NanObjectWrapHandle'].join('|'), ')\\s*\\(\\s*([^\\s\\)]+)'].join('')]);
116
117/* Since NanPersistent there is no need for NanMakeWeakPersistent, key group 1 */
118groups.push([1, '(NanMakeWeakPersistent)\\s*\\(\\s*([^\\s,]+)\\s*,\\s*']);
119
120/* Many methods of v8::Object and others now return v8::MaybeLocal<T>, key group 3 */
121groups.push([3, ['([\\s])([^\\s]+)->(', [
122 'GetEndColumn',
123 'GetFunction',
124 'GetLineNumber',
125 'NewInstance',
126 'GetPropertyNames',
127 'GetOwnPropertyNames',
128 'GetSourceLine',
129 'GetStartColumn',
130 'ObjectProtoToString',
131 'ToArrayIndex',
132 'ToDetailString',
133 'CallAsConstructor',
134 'CallAsFunction',
135 'CloneElementAt',
136 'Delete',
137 'ForceSet',
138 'Get',
139 'GetPropertyAttributes',
140 'GetRealNamedProperty',
141 'GetRealNamedPropertyInPrototypeChain',
142 'Has',
143 'HasOwnProperty',
144 'HasRealIndexedProperty',
145 'HasRealNamedCallbackProperty',
146 'HasRealNamedProperty',
147 'Set',
148 'SetAccessor',
149 'SetIndexedPropertyHandler',
150 'SetNamedPropertyHandler',
151 'SetPrototype'].join('|'), ')\\('].join('')]);
152
153/* You should get an error if any of these fail anyways,
154 or handle the error better, it is indicated either way, key group 2 */
155groups.push([2, ['NanNew(<(?:v8\\:\\:)?(', ['Date', 'String', 'RegExp'].join('|'), ')>)(\\([^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]);
156
157/* v8::Value::Equals now returns a v8::Maybe, key group 3 */
158groups.push([3, '([\\s\\(\\)])([^\\s\\(\\)]+)->(Equals)\\(([^\\s\\)]+)']);
159
160/* NanPersistent makes this unnecessary, key group 1 */
161groups.push([1, '(NanAssignPersistent)(?:<v8\\:\\:[^>]+>)?\\(([^,]+),\\s*']);
162
163/* args has been renamed to info, key group 2 */
164groups.push([2, '(\\W)(args)(\\W)'])
165
166/* node::ObjectWrap was replaced with NanObjectWrap, key group 2 */
167groups.push([2, '(\\W)(?:node\\:\\:)?(ObjectWrap)(\\W)']);
168
169/* v8::Persistent was replaced with NanPersistent, key group 2 */
170groups.push([2, '(\\W)(?:v8\\:\\:)?(Persistent)(\\W)']);
171
172/* counts the number of capturing groups in a well-formed regular expression,
173 ignoring non-capturing groups and escaped parentheses */
174function groupcount(s) {
175 var positive = s.match(/\((?!\?)/g),
176 negative = s.match(/\\\(/g);
177 return (positive ? positive.length : 0) - (negative ? negative.length : 0);
178}
179
180/* compute the absolute position of each key group in the joined master RegExp */
181for (i = 1, length = groups.length; i < length; i++) {
182 total += groupcount(groups[i - 1][1]);
183 groups[i][0] += total;
184}
185
186/* create the master RegExp, whis is the union of all the groups' expressions */
187master = new RegExp(groups.map(function (a) { return a[1]; }).join('|'), 'gm');
188
189/* replacement function for String.replace, receives 21 arguments */
190function replace() {
191 /* simple expressions */
192 switch (arguments[groups[0][0]]) {
193 case '_NAN_':
194 return 'NAN_';
195 case 'NODE_SET_METHOD':
196 return 'NanSetMethod';
197 case 'NODE_SET_PROTOTYPE_METHOD':
198 return 'NanSetPrototypeMethod';
199 case 'NanAsciiString':
200 return 'NanUtf8String';
201 case 'NanEscapeScope':
202 return 'scope.Escape';
203 case 'NanReturnNull':
204 return 'info.GetReturnValue().SetNull';
205 case 'NanReturnValue':
206 return 'info.GetReturnValue().Set';
207 case 'NanUcs2String':
208 return 'v8::String::Value';
209 default:
210 }
211
212 /* macros without arguments */
213 switch (arguments[groups[1][0]]) {
214 case 'NanEscapableScope':
215 return 'NanEscapableScope scope'
216 case 'NanReturnUndefined':
217 return 'return';
218 case 'NanScope':
219 return 'NanScope scope';
220 default:
221 }
222
223 /* TryCatch, emulate negative backref */
224 if (arguments[groups[2][0]] === 'TryCatch') {
225 return arguments[groups[2][0] - 1] ? arguments[0] : 'NanTryCatch';
226 }
227
228 /* NanNew("foo") --> NanNew("foo").ToLocalChecked() */
229 if (arguments[groups[3][0]] === 'NanNew') {
230 return [arguments[0], '.ToLocalChecked()'].join('');
231 }
232
233 /* insert warning for removed functions as comment on new line above */
234 switch (arguments[groups[4][0]]) {
235 case 'GetIndexedPropertiesExternalArrayData':
236 case 'GetIndexedPropertiesExternalArrayDataLength':
237 case 'GetIndexedPropertiesExternalArrayDataType':
238 case 'GetIndexedPropertiesPixelData':
239 case 'GetIndexedPropertiesPixelDataLength':
240 case 'HasIndexedPropertiesInExternalArrayData':
241 case 'HasIndexedPropertiesInPixelData':
242 case 'SetIndexedPropertiesToExternalArrayData':
243 case 'SetIndexedPropertiesToPixelData':
244 return arguments[groups[4][0] - 1] ? arguments[0] : [warning1, arguments[0]].join('');
245 default:
246 }
247
248 /* remove unnecessary NanScope() */
249 switch (arguments[groups[5][0]]) {
250 case 'NAN_GETTER':
251 case 'NAN_METHOD':
252 case 'NAN_SETTER':
253 case 'NAN_INDEX_DELETER':
254 case 'NAN_INDEX_ENUMERATOR':
255 case 'NAN_INDEX_GETTER':
256 case 'NAN_INDEX_QUERY':
257 case 'NAN_INDEX_SETTER':
258 case 'NAN_PROPERTY_DELETER':
259 case 'NAN_PROPERTY_ENUMERATOR':
260 case 'NAN_PROPERTY_GETTER':
261 case 'NAN_PROPERTY_QUERY':
262 case 'NAN_PROPERTY_SETTER':
263 return arguments[groups[5][0] - 1];
264 default:
265 }
266
267 /* Value converstion */
268 switch (arguments[groups[6][0]]) {
269 case 'Boolean':
270 case 'Int32':
271 case 'Integer':
272 case 'Number':
273 case 'Object':
274 case 'String':
275 case 'Uint32':
276 return [arguments[groups[6][0] - 2], 'NanTo<v8::', arguments[groups[6][0]], '>(', arguments[groups[6][0] - 1]].join('');
277 default:
278 }
279
280 /* other value conversion */
281 switch (arguments[groups[7][0]]) {
282 case 'BooleanValue':
283 return [arguments[groups[7][0] - 2], 'NanTo<bool>(', arguments[groups[7][0] - 1]].join('');
284 case 'Int32Value':
285 return [arguments[groups[7][0] - 2], 'NanTo<int32_t>(', arguments[groups[7][0] - 1]].join('');
286 case 'IntegerValue':
287 return [arguments[groups[7][0] - 2], 'NanTo<int64_t>(', arguments[groups[7][0] - 1]].join('');
288 case 'Uint32Value':
289 return [arguments[groups[7][0] - 2], 'NanTo<uint32_t>(', arguments[groups[7][0] - 1]].join('');
290 default:
291 }
292
293 /* NAN_WEAK_CALLBACK */
294 if (arguments[groups[8][0]] === 'NAN_WEAK_CALLBACK') {
295 return ['template<typename T>\nvoid ',
296 arguments[groups[8][0] + 1], '(const NanWeakCallbackInfo<T> &data)'].join('');
297 }
298
299 /* use methods on NAN classes instead */
300 switch (arguments[groups[9][0]]) {
301 case 'NanDisposePersistent':
302 return [arguments[groups[9][0] + 1], '.Reset('].join('');
303 case 'NanObjectWrapHandle':
304 return [arguments[groups[9][0] + 1], '->handle('].join('');
305 default:
306 }
307
308 /* use method on NanPersistent instead */
309 if (arguments[groups[10][0]] === 'NanMakeWeakPersistent') {
310 return arguments[groups[10][0] + 1] + '.SetWeak(';
311 }
312
313 /* These return Maybes, the upper ones take no arguments */
314 switch (arguments[groups[11][0]]) {
315 case 'GetEndColumn':
316 case 'GetFunction':
317 case 'GetLineNumber':
318 case 'GetOwnPropertyNames':
319 case 'GetPropertyNames':
320 case 'GetSourceLine':
321 case 'GetStartColumn':
322 case 'NewInstance':
323 case 'ObjectProtoToString':
324 case 'ToArrayIndex':
325 case 'ToDetailString':
326 return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1]].join('');
327 case 'CallAsConstructor':
328 case 'CallAsFunction':
329 case 'CloneElementAt':
330 case 'Delete':
331 case 'ForceSet':
332 case 'Get':
333 case 'GetPropertyAttributes':
334 case 'GetRealNamedProperty':
335 case 'GetRealNamedPropertyInPrototypeChain':
336 case 'Has':
337 case 'HasOwnProperty':
338 case 'HasRealIndexedProperty':
339 case 'HasRealNamedCallbackProperty':
340 case 'HasRealNamedProperty':
341 case 'Set':
342 case 'SetAccessor':
343 case 'SetIndexedPropertyHandler':
344 case 'SetNamedPropertyHandler':
345 case 'SetPrototype':
346 return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1], ', '].join('');
347 default:
348 }
349
350 /* Automatic ToLocalChecked(), take it or leave it */
351 switch (arguments[groups[12][0]]) {
352 case 'Date':
353 case 'String':
354 case 'RegExp':
355 return ['NanNew', arguments[groups[12][0] - 1], arguments[groups[12][0] + 1], '.ToLocalChecked()'].join('');
356 default:
357 }
358
359 /* NanEquals is now required for uniformity */
360 if (arguments[groups[13][0]] === 'Equals') {
361 return [arguments[groups[13][0] - 1], 'NanEquals(', arguments[groups[13][0] - 1], ', ', arguments[groups[13][0] + 1]].join('');
362 }
363
364 /* use method on replacement class instead */
365 if (arguments[groups[14][0]] === 'NanAssignPersistent') {
366 return [arguments[groups[14][0] + 1], '.Reset('].join('');
367 }
368
369 /* args --> info */
370 if (arguments[groups[15][0]] === 'args') {
371 return [arguments[groups[15][0] - 1], 'info', arguments[groups[15][0] + 1]].join('');
372 }
373
374 /* ObjectWrap --> NanObjectWrap */
375 if (arguments[groups[16][0]] === 'ObjectWrap') {
376 return [arguments[groups[16][0] - 1], 'NanObjectWrap', arguments[groups[16][0] + 1]].join('');
377 }
378
379 /* Persistent --> NanPersistent */
380 if (arguments[groups[17][0]] === 'Persistent') {
381 return [arguments[groups[17][0] - 1], 'NanPersistent', arguments[groups[17][0] + 1]].join('');
382 }
383
384 /* This should not happen. A switch is probably missing a case if it does. */
385 throw 'Unhandled match: ' + arguments[0];
386}
387
388/* reads a file, runs replacement and writes it back */
389function processFile(file) {
390 fs.readFile(file, {encoding: 'utf8'}, function (err, data) {
391 if (err) {
392 throw err;
393 }
394
395 /* run replacement twice, might need more runs */
396 fs.writeFile(file, data.replace(master, replace).replace(master, replace), function (err) {
397 if (err) {
398 throw err;
399 }
400 });
401 });
402}
403
404/* process file names from command line and process the identified files */
405for (i = 2, length = process.argv.length; i < length; i++) {
406 glob(process.argv[i], function (err, matches) {
407 if (err) {
408 throw err;
409 }
410 matches.forEach(processFile);
411 });
412}