@rn-org/react-native-thread 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -22
- package/lib/module/babel-plugin.js +328 -2
- package/lib/module/babel-plugin.js.map +1 -1
- package/lib/module/index.js +59 -8
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/babel-plugin.js +411 -2
- package/src/index.tsx +83 -12
package/lib/module/index.js
CHANGED
|
@@ -20,20 +20,52 @@ function _register(id, name) {
|
|
|
20
20
|
function _unregister(id) {
|
|
21
21
|
_registry.delete(id);
|
|
22
22
|
}
|
|
23
|
+
function _isBytecode(src) {
|
|
24
|
+
return src.includes('[bytecode]') || /^\s*function\s*\(\)\s*\{\s*bytecode\s*\}/.test(src);
|
|
25
|
+
}
|
|
26
|
+
function _serializeValue(value) {
|
|
27
|
+
if (value === undefined) return 'undefined';
|
|
28
|
+
if (value === null) return 'null';
|
|
29
|
+
if (typeof value === 'function') {
|
|
30
|
+
const src = value.toString();
|
|
31
|
+
if (_isBytecode(src)) {
|
|
32
|
+
if (__DEV__) {
|
|
33
|
+
console.warn('[react-native-thread] A function param returned a Hermes bytecode placeholder. ' + "Add the Babel plugin: plugins: ['@rn-org/react-native-thread/babel-plugin']");
|
|
34
|
+
}
|
|
35
|
+
return 'undefined';
|
|
36
|
+
}
|
|
37
|
+
return src;
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === 'string') return JSON.stringify(value);
|
|
40
|
+
if (typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
41
|
+
if (Array.isArray(value)) return '[' + value.map(_serializeValue).join(',') + ']';
|
|
42
|
+
if (typeof value === 'object') {
|
|
43
|
+
const rec = value;
|
|
44
|
+
if (typeof rec.__rnThreadFn === 'string') {
|
|
45
|
+
return rec.__rnThreadFn;
|
|
46
|
+
}
|
|
47
|
+
const entries = Object.entries(rec).map(([k, v]) => `${JSON.stringify(k)}:${_serializeValue(v)}`).join(',');
|
|
48
|
+
return '{' + entries + '}';
|
|
49
|
+
}
|
|
50
|
+
return String(value);
|
|
51
|
+
}
|
|
52
|
+
function _wrapWithErrorHandler(code) {
|
|
53
|
+
return `try { ${code} } catch(__e__) { resolveThreadMessage(JSON.stringify({ __rnThreadError: true, message: __e__.message || String(__e__), stack: __e__.stack || '' })); }`;
|
|
54
|
+
}
|
|
23
55
|
function toCode(task, params) {
|
|
24
56
|
if (typeof task === 'string') {
|
|
25
|
-
const
|
|
26
|
-
return `var __params__ = ${
|
|
57
|
+
const paramsCode = params !== undefined ? _serializeValue(params) : 'undefined';
|
|
58
|
+
return _wrapWithErrorHandler(`var __params__ = ${paramsCode};\n${task}`);
|
|
27
59
|
}
|
|
28
60
|
const src = task.toString();
|
|
29
|
-
if (
|
|
61
|
+
if (_isBytecode(src)) {
|
|
30
62
|
if (__DEV__) {
|
|
31
63
|
console.warn('[react-native-thread] fn.toString() returned a Hermes bytecode placeholder. ' + "Add the Babel plugin: plugins: ['@rn-org/react-native-thread/babel-plugin']");
|
|
32
64
|
}
|
|
33
65
|
return '/* bytecode: no-op */';
|
|
34
66
|
}
|
|
35
|
-
const argsStr = params !== undefined ?
|
|
36
|
-
return `(${src})(${argsStr})
|
|
67
|
+
const argsStr = params !== undefined ? _serializeValue(params) : '';
|
|
68
|
+
return _wrapWithErrorHandler(`(${src})(${argsStr})`);
|
|
37
69
|
}
|
|
38
70
|
const SHARED_THREAD_NAME = 'RNOrgThread';
|
|
39
71
|
let _sharedThreadId = null;
|
|
@@ -122,6 +154,9 @@ export function onMessage(handler) {
|
|
|
122
154
|
});
|
|
123
155
|
});
|
|
124
156
|
}
|
|
157
|
+
function _isThreadError(data) {
|
|
158
|
+
return typeof data === 'object' && data !== null && data.__rnThreadError === true;
|
|
159
|
+
}
|
|
125
160
|
function createThreadHandle(id, name) {
|
|
126
161
|
return {
|
|
127
162
|
id,
|
|
@@ -132,18 +167,34 @@ function createThreadHandle(id, name) {
|
|
|
132
167
|
onMessage: function (handler) {
|
|
133
168
|
if (handler) {
|
|
134
169
|
return onMessage((data, threadId) => {
|
|
135
|
-
if (threadId === id) handler(data);
|
|
170
|
+
if (threadId === id && !_isThreadError(data)) handler(data);
|
|
136
171
|
});
|
|
137
172
|
}
|
|
138
|
-
return new Promise(resolve => {
|
|
173
|
+
return new Promise((resolve, reject) => {
|
|
139
174
|
const unsub = onMessage((data, threadId) => {
|
|
140
175
|
if (threadId === id) {
|
|
141
176
|
unsub();
|
|
142
|
-
|
|
177
|
+
if (_isThreadError(data)) {
|
|
178
|
+
const err = new Error(data.message);
|
|
179
|
+
err.stack = data.stack;
|
|
180
|
+
reject(err);
|
|
181
|
+
} else {
|
|
182
|
+
resolve(data);
|
|
183
|
+
}
|
|
143
184
|
}
|
|
144
185
|
});
|
|
145
186
|
});
|
|
146
187
|
},
|
|
188
|
+
onError(handler) {
|
|
189
|
+
return onMessage((data, threadId) => {
|
|
190
|
+
if (threadId === id && _isThreadError(data)) {
|
|
191
|
+
handler({
|
|
192
|
+
message: data.message,
|
|
193
|
+
stack: data.stack
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
},
|
|
147
198
|
destroy() {
|
|
148
199
|
destroyThread(id);
|
|
149
200
|
}
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","ReactNativeThread","_emitter","RN_THREAD_MESSAGE_EVENT","_registry","Map","_findByName","name","info","values","undefined","_register","id","set","_unregister","delete","
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","ReactNativeThread","_emitter","RN_THREAD_MESSAGE_EVENT","_registry","Map","_findByName","name","info","values","undefined","_register","id","set","_unregister","delete","_isBytecode","src","includes","test","_serializeValue","value","toString","__DEV__","console","warn","JSON","stringify","String","Array","isArray","map","join","rec","__rnThreadFn","entries","Object","k","v","_wrapWithErrorHandler","code","toCode","task","params","paramsCode","argsStr","SHARED_THREAD_NAME","_sharedThreadId","getSharedThread","createThread","runOnJS","runOnThread","runOnNewJS","existing","createThreadHandle","resolvedName","getThreads","from","destroyThread","idOrName","targetId","has","onMessage","handler","sub","addListener","event","parsed","data","parse","threadId","remove","Promise","resolve","_isThreadError","__rnThreadError","run","reject","unsub","err","Error","message","stack","onError","destroy"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,QAAQ,cAAc;AACjD,OAAOC,iBAAiB,MAAM,8BAA2B;AAwBzD,MAAMC,QAAQ,GAAG,IAAIF,kBAAkB,CAACC,iBAAiB,CAAC;AAC1D,MAAME,uBAAuB,GAAG,iBAAiB;AAEjD,MAAMC,SAAS,GAAG,IAAIC,GAAG,CAAqB,CAAC;AAE/C,SAASC,WAAWA,CAACC,IAAY,EAA0B;EACzD,KAAK,MAAMC,IAAI,IAAIJ,SAAS,CAACK,MAAM,CAAC,CAAC,EAAE;IACrC,IAAID,IAAI,CAACD,IAAI,KAAKA,IAAI,EAAE,OAAOC,IAAI;EACrC;EACA,OAAOE,SAAS;AAClB;AAEA,SAASC,SAASA,CAACC,EAAU,EAAEL,IAAY,EAAQ;EACjDH,SAAS,CAACS,GAAG,CAACD,EAAE,EAAE;IAAEA,EAAE;IAAEL;EAAK,CAAC,CAAC;AACjC;AAEA,SAASO,WAAWA,CAACF,EAAU,EAAQ;EACrCR,SAAS,CAACW,MAAM,CAACH,EAAE,CAAC;AACtB;AAEA,SAASI,WAAWA,CAACC,GAAW,EAAW;EACzC,OACEA,GAAG,CAACC,QAAQ,CAAC,YAAY,CAAC,IAC1B,0CAA0C,CAACC,IAAI,CAACF,GAAG,CAAC;AAExD;AAEA,SAASG,eAAeA,CAACC,KAAc,EAAU;EAC/C,IAAIA,KAAK,KAAKX,SAAS,EAAE,OAAO,WAAW;EAC3C,IAAIW,KAAK,KAAK,IAAI,EAAE,OAAO,MAAM;EACjC,IAAI,OAAOA,KAAK,KAAK,UAAU,EAAE;IAC/B,MAAMJ,GAAG,GAAGI,KAAK,CAACC,QAAQ,CAAC,CAAC;IAC5B,IAAIN,WAAW,CAACC,GAAG,CAAC,EAAE;MACpB,IAAIM,OAAO,EAAE;QACXC,OAAO,CAACC,IAAI,CACV,iFAAiF,GAC/E,6EACJ,CAAC;MACH;MACA,OAAO,WAAW;IACpB;IACA,OAAOR,GAAG;EACZ;EACA,IAAI,OAAOI,KAAK,KAAK,QAAQ,EAAE,OAAOK,IAAI,CAACC,SAAS,CAACN,KAAK,CAAC;EAC3D,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAI,OAAOA,KAAK,KAAK,SAAS,EACzD,OAAOO,MAAM,CAACP,KAAK,CAAC;EACtB,IAAIQ,KAAK,CAACC,OAAO,CAACT,KAAK,CAAC,EACtB,OAAO,GAAG,GAAGA,KAAK,CAACU,GAAG,CAACX,eAAe,CAAC,CAACY,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG;EACzD,IAAI,OAAOX,KAAK,KAAK,QAAQ,EAAE;IAC7B,MAAMY,GAAG,GAAGZ,KAAgC;IAC5C,IAAI,OAAOY,GAAG,CAACC,YAAY,KAAK,QAAQ,EAAE;MACxC,OAAOD,GAAG,CAACC,YAAY;IACzB;IACA,MAAMC,OAAO,GAAGC,MAAM,CAACD,OAAO,CAACF,GAAG,CAAC,CAChCF,GAAG,CAAC,CAAC,CAACM,CAAC,EAAEC,CAAC,CAAC,KAAK,GAAGZ,IAAI,CAACC,SAAS,CAACU,CAAC,CAAC,IAAIjB,eAAe,CAACkB,CAAC,CAAC,EAAE,CAAC,CAC7DN,IAAI,CAAC,GAAG,CAAC;IACZ,OAAO,GAAG,GAAGG,OAAO,GAAG,GAAG;EAC5B;EACA,OAAOP,MAAM,CAACP,KAAK,CAAC;AACtB;AAEA,SAASkB,qBAAqBA,CAACC,IAAY,EAAU;EACnD,OAAO,SAASA,IAAI,yJAAyJ;AAC/K;AAEA,SAASC,MAAMA,CAACC,IAAgB,EAAEC,MAAgB,EAAU;EAC1D,IAAI,OAAOD,IAAI,KAAK,QAAQ,EAAE;IAC5B,MAAME,UAAU,GACdD,MAAM,KAAKjC,SAAS,GAAGU,eAAe,CAACuB,MAAM,CAAC,GAAG,WAAW;IAC9D,OAAOJ,qBAAqB,CAAC,oBAAoBK,UAAU,MAAMF,IAAI,EAAE,CAAC;EAC1E;EAEA,MAAMzB,GAAG,GAAGyB,IAAI,CAACpB,QAAQ,CAAC,CAAC;EAC3B,IAAIN,WAAW,CAACC,GAAG,CAAC,EAAE;IACpB,IAAIM,OAAO,EAAE;MACXC,OAAO,CAACC,IAAI,CACV,8EAA8E,GAC5E,6EACJ,CAAC;IACH;IACA,OAAO,uBAAuB;EAChC;EAEA,MAAMoB,OAAO,GAAGF,MAAM,KAAKjC,SAAS,GAAGU,eAAe,CAACuB,MAAM,CAAC,GAAG,EAAE;EACnE,OAAOJ,qBAAqB,CAAC,IAAItB,GAAG,KAAK4B,OAAO,GAAG,CAAC;AACtD;AAEA,MAAMC,kBAAkB,GAAG,aAAa;AACxC,IAAIC,eAA8B,GAAG,IAAI;AAEzC,SAASC,eAAeA,CAAA,EAAW;EACjC,IAAID,eAAe,KAAK,IAAI,EAAE;IAC5BA,eAAe,GAAG9C,iBAAiB,CAACgD,YAAY,CAAC,CAAC;IAClDtC,SAAS,CAACoC,eAAe,EAAED,kBAAkB,CAAC;EAChD;EACA,OAAOC,eAAe;AACxB;AAEA,OAAO,SAASG,OAAOA,CAACR,IAAgB,EAAEC,MAAgB,EAAQ;EAChE1C,iBAAiB,CAACkD,WAAW,CAACH,eAAe,CAAC,CAAC,EAAEP,MAAM,CAACC,IAAI,EAAEC,MAAM,CAAC,CAAC;AACxE;AAEA,OAAO,SAASS,UAAUA,CACxBV,IAAgB,EAChBC,MAAgB,EAChBpC,IAAa,EACC;EACd,IAAIA,IAAI,IAAI,IAAI,EAAE;IAChB,MAAM8C,QAAQ,GAAG/C,WAAW,CAACC,IAAI,CAAC;IAClC,IAAI8C,QAAQ,EAAE;MACZ,OAAOC,kBAAkB,CAACD,QAAQ,CAACzC,EAAE,EAAEyC,QAAQ,CAAC9C,IAAI,CAAC;IACvD;EACF;EACA,MAAMK,EAAE,GAAGX,iBAAiB,CAACgD,YAAY,CAAC,CAAC;EAC3C,MAAMM,YAAY,GAAGhD,IAAI,IAAI,YAAYK,EAAE,EAAE;EAC7CD,SAAS,CAACC,EAAE,EAAE2C,YAAY,CAAC;EAC3BtD,iBAAiB,CAACkD,WAAW,CAACvC,EAAE,EAAE6B,MAAM,CAACC,IAAI,EAAEC,MAAM,CAAC,CAAC;EACvD,OAAOW,kBAAkB,CAAC1C,EAAE,EAAE2C,YAAY,CAAC;AAC7C;AAEA,OAAO,SAASN,YAAYA,CAAC1C,IAAa,EAAgB;EACxD,IAAIA,IAAI,IAAI,IAAI,EAAE;IAChB,MAAM8C,QAAQ,GAAG/C,WAAW,CAACC,IAAI,CAAC;IAClC,IAAI8C,QAAQ,EAAE;MACZ,OAAOC,kBAAkB,CAACD,QAAQ,CAACzC,EAAE,EAAEyC,QAAQ,CAAC9C,IAAI,CAAC;IACvD;EACF;EACA,MAAMK,EAAE,GAAGX,iBAAiB,CAACgD,YAAY,CAAC,CAAC;EAC3C,MAAMM,YAAY,GAAGhD,IAAI,IAAI,YAAYK,EAAE,EAAE;EAC7CD,SAAS,CAACC,EAAE,EAAE2C,YAAY,CAAC;EAC3B,OAAOD,kBAAkB,CAAC1C,EAAE,EAAE2C,YAAY,CAAC;AAC7C;AAEA,OAAO,SAASC,UAAUA,CAAA,EAAiB;EACzC,OAAO3B,KAAK,CAAC4B,IAAI,CAACrD,SAAS,CAACK,MAAM,CAAC,CAAC,CAAC;AACvC;AAEA,OAAO,SAASiD,aAAaA,CAACC,QAAyB,EAAQ;EAC7D,IAAIC,QAA4B;EAEhC,IAAI,OAAOD,QAAQ,KAAK,QAAQ,EAAE;IAChC,IAAIvD,SAAS,CAACyD,GAAG,CAACF,QAAQ,CAAC,EAAEC,QAAQ,GAAGD,QAAQ;EAClD,CAAC,MAAM;IACL,KAAK,MAAMnD,IAAI,IAAIJ,SAAS,CAACK,MAAM,CAAC,CAAC,EAAE;MACrC,IAAID,IAAI,CAACD,IAAI,KAAKoD,QAAQ,EAAE;QAC1BC,QAAQ,GAAGpD,IAAI,CAACI,EAAE;QAClB;MACF;IACF;EACF;EAEA,IAAIgD,QAAQ,KAAKlD,SAAS,EAAE;IAC1B,IAAIa,OAAO,EAAE;MACXC,OAAO,CAACC,IAAI,CACV,6DAA6DkC,QAAQ,GACvE,CAAC;IACH;IACA;EACF;EAEA7C,WAAW,CAAC8C,QAAQ,CAAC;EACrB,IAAIA,QAAQ,KAAKb,eAAe,EAAEA,eAAe,GAAG,IAAI;EACxD9C,iBAAiB,CAACyD,aAAa,CAACE,QAAQ,CAAC;AAC3C;AAMA,OAAO,SAASE,SAASA,CACvBC,OAAmD,EACU;EAC7D,IAAIA,OAAO,EAAE;IACX,MAAMC,GAAG,GAAG9D,QAAQ,CAAC+D,WAAW,CAAC9D,uBAAuB,EAAG+D,KAAU,IAAK;MACxE,IAAIC,MAAe,GAAGD,KAAK,CAACE,IAAI;MAChC,IAAI;QACFD,MAAM,GAAGzC,IAAI,CAAC2C,KAAK,CAACH,KAAK,CAACE,IAAI,CAAC;MACjC,CAAC,CAAC,MAAM,CAAC;MACTL,OAAO,CAACI,MAAM,EAAED,KAAK,CAACI,QAAkB,CAAC;IAC3C,CAAC,CAAC;IACF,OAAO,MAAMN,GAAG,CAACO,MAAM,CAAC,CAAC;EAC3B;EAEA,OAAO,IAAIC,OAAO,CAAuCC,OAAO,IAAK;IACnE,MAAMT,GAAG,GAAG9D,QAAQ,CAAC+D,WAAW,CAAC9D,uBAAuB,EAAG+D,KAAU,IAAK;MACxE,IAAIC,MAAe,GAAGD,KAAK,CAACE,IAAI;MAChC,IAAI;QACFD,MAAM,GAAGzC,IAAI,CAAC2C,KAAK,CAACH,KAAK,CAACE,IAAI,CAAC;MACjC,CAAC,CAAC,MAAM,CAAC;MACTJ,GAAG,CAACO,MAAM,CAAC,CAAC;MACZE,OAAO,CAAC;QAAEL,IAAI,EAAED,MAAM;QAAEG,QAAQ,EAAEJ,KAAK,CAACI;MAAmB,CAAC,CAAC;IAC/D,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ;AAEA,SAASI,cAAcA,CACrBN,IAAa,EACsD;EACnE,OACE,OAAOA,IAAI,KAAK,QAAQ,IACxBA,IAAI,KAAK,IAAI,IACZA,IAAI,CAASO,eAAe,KAAK,IAAI;AAE1C;AAEA,SAASrB,kBAAkBA,CAAC1C,EAAU,EAAEL,IAAY,EAAgB;EAClE,OAAO;IACLK,EAAE;IACFL,IAAI;IACJqE,GAAGA,CAAClC,IAAgB,EAAEC,MAAgB,EAAE;MACtC1C,iBAAiB,CAACkD,WAAW,CAACvC,EAAE,EAAE6B,MAAM,CAACC,IAAI,EAAEC,MAAM,CAAC,CAAC;IACzD,CAAC;IACDmB,SAAS,EAAE,SAAAA,CAAUC,OAAiC,EAAE;MACtD,IAAIA,OAAO,EAAE;QACX,OAAOD,SAAS,CAAC,CAACM,IAAI,EAAEE,QAAQ,KAAK;UACnC,IAAIA,QAAQ,KAAK1D,EAAE,IAAI,CAAC8D,cAAc,CAACN,IAAI,CAAC,EAAEL,OAAO,CAACK,IAAI,CAAC;QAC7D,CAAC,CAAC;MACJ;MACA,OAAO,IAAII,OAAO,CAAU,CAACC,OAAO,EAAEI,MAAM,KAAK;QAC/C,MAAMC,KAAK,GAAGhB,SAAS,CAAC,CAACM,IAAI,EAAEE,QAAQ,KAAK;UAC1C,IAAIA,QAAQ,KAAK1D,EAAE,EAAE;YACnBkE,KAAK,CAAC,CAAC;YACP,IAAIJ,cAAc,CAACN,IAAI,CAAC,EAAE;cACxB,MAAMW,GAAG,GAAG,IAAIC,KAAK,CAACZ,IAAI,CAACa,OAAO,CAAC;cACnCF,GAAG,CAACG,KAAK,GAAGd,IAAI,CAACc,KAAK;cACtBL,MAAM,CAACE,GAAG,CAAC;YACb,CAAC,MAAM;cACLN,OAAO,CAACL,IAAI,CAAC;YACf;UACF;QACF,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ,CAA8B;IAC9Be,OAAOA,CAACpB,OAAqC,EAAE;MAC7C,OAAOD,SAAS,CAAC,CAACM,IAAI,EAAEE,QAAQ,KAAK;QACnC,IAAIA,QAAQ,KAAK1D,EAAE,IAAI8D,cAAc,CAACN,IAAI,CAAC,EAAE;UAC3CL,OAAO,CAAC;YAAEkB,OAAO,EAAEb,IAAI,CAACa,OAAO;YAAEC,KAAK,EAAEd,IAAI,CAACc;UAAM,CAAC,CAAC;QACvD;MACF,CAAC,CAAC;IACJ,CAAC;IACDE,OAAOA,CAAA,EAAG;MACR1B,aAAa,CAAC9C,EAAE,CAAC;IACnB;EACF,CAAC;AACH","ignoreList":[]}
|
|
@@ -3,12 +3,17 @@ export type ThreadInfo = {
|
|
|
3
3
|
readonly id: number;
|
|
4
4
|
readonly name: string;
|
|
5
5
|
};
|
|
6
|
+
export type ThreadError = {
|
|
7
|
+
message: string;
|
|
8
|
+
stack: string;
|
|
9
|
+
};
|
|
6
10
|
export type ThreadHandle = {
|
|
7
11
|
readonly id: number;
|
|
8
12
|
readonly name: string;
|
|
9
13
|
run(task: ThreadTask, params?: unknown): void;
|
|
10
14
|
onMessage(handler: (data: unknown) => void): () => void;
|
|
11
15
|
onMessage(): Promise<unknown>;
|
|
16
|
+
onError(handler: (error: ThreadError) => void): () => void;
|
|
12
17
|
destroy(): void;
|
|
13
18
|
};
|
|
14
19
|
export declare function runOnJS(task: ThreadTask, params?: unknown): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxD,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9C,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACxD,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC3D,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;AAoGF,wBAAgB,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,IAAI,CAEhE;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,UAAU,EAChB,MAAM,CAAC,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,YAAY,CAYd;AAED,wBAAgB,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,CAWxD;AAED,wBAAgB,UAAU,IAAI,UAAU,EAAE,CAEzC;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B7D;AAED,wBAAgB,SAAS,CACvB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GACjD,MAAM,IAAI,CAAC;AACd,wBAAgB,SAAS,IAAI,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rn-org/react-native-thread",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Run JavaScript on real background threads in React Native — no Workers, no Worklets. Uses JavaScriptCore on iOS and Mozilla Rhino on Android. Built as a New Architecture TurboModule.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
package/src/babel-plugin.js
CHANGED
|
@@ -1,10 +1,299 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const nodePath = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
|
|
3
6
|
const TOP_LEVEL_API = new Set(['runOnJS', 'runOnNewJS']);
|
|
4
7
|
|
|
5
8
|
const METHOD_API = new Set(['run']);
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
const SKIP_KEYS = new Set([
|
|
11
|
+
'type',
|
|
12
|
+
'start',
|
|
13
|
+
'end',
|
|
14
|
+
'loc',
|
|
15
|
+
'leadingComments',
|
|
16
|
+
'trailingComments',
|
|
17
|
+
'innerComments',
|
|
18
|
+
'extra',
|
|
19
|
+
'range',
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
module.exports = function reactNativeThreadPlugin({ types: t, ...babel }) {
|
|
23
|
+
const parser = (babel.parser && babel.parser) || require('@babel/parser');
|
|
24
|
+
|
|
25
|
+
// ── Cross-module import resolution ─────────────────────────────
|
|
26
|
+
|
|
27
|
+
const RESOLVE_EXTS = ['.ts', '.tsx', '.js', '.jsx', ''];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Given a relative import source (e.g. './Utility') and the
|
|
31
|
+
* filename of the importing file, try to resolve, read, parse,
|
|
32
|
+
* and extract the source of the named export `exportName`.
|
|
33
|
+
*
|
|
34
|
+
* Returns the raw function source string or null.
|
|
35
|
+
*/
|
|
36
|
+
function resolveImportedFnSource(importSource, exportName, state) {
|
|
37
|
+
const currentFile = state.filename || state.file.opts.filename;
|
|
38
|
+
if (!currentFile || !importSource.startsWith('.')) return null;
|
|
39
|
+
|
|
40
|
+
const dir = nodePath.dirname(currentFile);
|
|
41
|
+
let resolvedFile = null;
|
|
42
|
+
|
|
43
|
+
for (const ext of RESOLVE_EXTS) {
|
|
44
|
+
const candidate = nodePath.resolve(dir, importSource + ext);
|
|
45
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
46
|
+
resolvedFile = candidate;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (!resolvedFile) {
|
|
51
|
+
// Try as directory with index file
|
|
52
|
+
for (const ext of RESOLVE_EXTS) {
|
|
53
|
+
const candidate = nodePath.resolve(dir, importSource, 'index' + ext);
|
|
54
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
|
|
55
|
+
resolvedFile = candidate;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!resolvedFile) return null;
|
|
61
|
+
|
|
62
|
+
let source;
|
|
63
|
+
try {
|
|
64
|
+
source = fs.readFileSync(resolvedFile, 'utf8');
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
let ast;
|
|
70
|
+
try {
|
|
71
|
+
ast = parser.parse(source, {
|
|
72
|
+
sourceType: 'module',
|
|
73
|
+
plugins: ['typescript', 'jsx'],
|
|
74
|
+
});
|
|
75
|
+
} catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Walk top-level statements to find the exported function
|
|
80
|
+
for (const stmt of ast.program.body) {
|
|
81
|
+
// export function foo() { ... }
|
|
82
|
+
if (t.isExportNamedDeclaration(stmt) && stmt.declaration) {
|
|
83
|
+
if (
|
|
84
|
+
t.isFunctionDeclaration(stmt.declaration) &&
|
|
85
|
+
stmt.declaration.id &&
|
|
86
|
+
stmt.declaration.id.name === exportName
|
|
87
|
+
) {
|
|
88
|
+
const raw = source.slice(
|
|
89
|
+
stmt.declaration.start,
|
|
90
|
+
stmt.declaration.end
|
|
91
|
+
);
|
|
92
|
+
return transpileForThread(raw, { filename: resolvedFile });
|
|
93
|
+
}
|
|
94
|
+
// export const foo = () => { ... }
|
|
95
|
+
if (t.isVariableDeclaration(stmt.declaration)) {
|
|
96
|
+
for (const decl of stmt.declaration.declarations) {
|
|
97
|
+
if (
|
|
98
|
+
t.isVariableDeclarator(decl) &&
|
|
99
|
+
t.isIdentifier(decl.id) &&
|
|
100
|
+
decl.id.name === exportName &&
|
|
101
|
+
decl.init &&
|
|
102
|
+
(t.isFunctionExpression(decl.init) ||
|
|
103
|
+
t.isArrowFunctionExpression(decl.init))
|
|
104
|
+
) {
|
|
105
|
+
const raw = source.slice(decl.init.start, decl.init.end);
|
|
106
|
+
return transpileForThread(raw, { filename: resolvedFile });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── AST helpers ────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
/** Collect all identifiers that appear in reference position inside `node`. */
|
|
119
|
+
function collectReferencedIds(node) {
|
|
120
|
+
const ids = new Set();
|
|
121
|
+
function walk(n, skipId) {
|
|
122
|
+
if (!n || typeof n !== 'object') return;
|
|
123
|
+
if (Array.isArray(n)) {
|
|
124
|
+
n.forEach((el) => walk(el, false));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (!n.type) return;
|
|
128
|
+
if (t.isIdentifier(n) && !skipId) {
|
|
129
|
+
ids.add(n.name);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (t.isMemberExpression(n)) {
|
|
133
|
+
walk(n.object, false);
|
|
134
|
+
if (n.computed) walk(n.property, false);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (t.isObjectProperty(n)) {
|
|
138
|
+
if (n.computed) walk(n.key, false);
|
|
139
|
+
walk(n.value, false);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (
|
|
143
|
+
t.isFunctionExpression(n) ||
|
|
144
|
+
t.isArrowFunctionExpression(n) ||
|
|
145
|
+
t.isFunctionDeclaration(n)
|
|
146
|
+
) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
for (const key of Object.keys(n)) {
|
|
150
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
151
|
+
walk(n[key], false);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
walk(node, false);
|
|
155
|
+
return ids;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Collect names declared locally inside a function (params + body). */
|
|
159
|
+
function collectLocalNames(fnNode) {
|
|
160
|
+
const names = new Set();
|
|
161
|
+
if (fnNode.params) {
|
|
162
|
+
for (const p of fnNode.params) {
|
|
163
|
+
if (t.isIdentifier(p)) names.add(p.name);
|
|
164
|
+
if (t.isAssignmentPattern(p) && t.isIdentifier(p.left))
|
|
165
|
+
names.add(p.left.name);
|
|
166
|
+
if (t.isRestElement(p) && t.isIdentifier(p.argument))
|
|
167
|
+
names.add(p.argument.name);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (fnNode.id && t.isIdentifier(fnNode.id)) names.add(fnNode.id.name);
|
|
171
|
+
function walk(n) {
|
|
172
|
+
if (!n || typeof n !== 'object') return;
|
|
173
|
+
if (Array.isArray(n)) {
|
|
174
|
+
n.forEach(walk);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (!n.type) return;
|
|
178
|
+
if (t.isVariableDeclarator(n) && t.isIdentifier(n.id))
|
|
179
|
+
names.add(n.id.name);
|
|
180
|
+
if (t.isFunctionDeclaration(n) && n.id) {
|
|
181
|
+
names.add(n.id.name);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (t.isFunctionExpression(n) || t.isArrowFunctionExpression(n)) return;
|
|
185
|
+
for (const key of Object.keys(n)) {
|
|
186
|
+
if (SKIP_KEYS.has(key)) continue;
|
|
187
|
+
walk(n[key]);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (fnNode.body) walk(fnNode.body);
|
|
191
|
+
return names;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* For each free variable in `fnNode`, try to resolve it to a
|
|
196
|
+
* compile-time value (literal or function) via scope bindings.
|
|
197
|
+
* Handles transitive closures: if a captured function itself has
|
|
198
|
+
* free variables, those are captured too.
|
|
199
|
+
*
|
|
200
|
+
* Returns an array of source strings like `"var b = 3;"` or
|
|
201
|
+
* `"var add = (x) => x + b;"`.
|
|
202
|
+
*/
|
|
203
|
+
function getCaptureDecls(fnNode, scope, state) {
|
|
204
|
+
const captures = [];
|
|
205
|
+
const seen = new Set();
|
|
206
|
+
|
|
207
|
+
function capture(targetFnNode) {
|
|
208
|
+
const referenced = collectReferencedIds(targetFnNode.body);
|
|
209
|
+
const locals = collectLocalNames(targetFnNode);
|
|
210
|
+
|
|
211
|
+
for (const name of referenced) {
|
|
212
|
+
if (locals.has(name) || seen.has(name)) continue;
|
|
213
|
+
seen.add(name);
|
|
214
|
+
|
|
215
|
+
const binding = scope.getBinding(name);
|
|
216
|
+
if (!binding) continue;
|
|
217
|
+
|
|
218
|
+
const bNode = binding.path.node;
|
|
219
|
+
|
|
220
|
+
// const/let/var x = <literal>
|
|
221
|
+
if (
|
|
222
|
+
t.isVariableDeclarator(bNode) &&
|
|
223
|
+
bNode.init &&
|
|
224
|
+
t.isLiteral(bNode.init)
|
|
225
|
+
) {
|
|
226
|
+
const initSrc = state.file.code.slice(
|
|
227
|
+
bNode.init.start,
|
|
228
|
+
bNode.init.end
|
|
229
|
+
);
|
|
230
|
+
captures.push('var ' + name + ' = ' + initSrc + ';');
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// const/let/var x = <arrow / function expression>
|
|
235
|
+
if (
|
|
236
|
+
t.isVariableDeclarator(bNode) &&
|
|
237
|
+
bNode.init &&
|
|
238
|
+
(t.isFunctionExpression(bNode.init) ||
|
|
239
|
+
t.isArrowFunctionExpression(bNode.init))
|
|
240
|
+
) {
|
|
241
|
+
// Recursively capture the inner function's free vars first
|
|
242
|
+
capture(bNode.init);
|
|
243
|
+
const initSrc = state.file.code.slice(
|
|
244
|
+
bNode.init.start,
|
|
245
|
+
bNode.init.end
|
|
246
|
+
);
|
|
247
|
+
captures.push(
|
|
248
|
+
'var ' + name + ' = ' + transpileForThread(initSrc, state) + ';'
|
|
249
|
+
);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// function declaration
|
|
254
|
+
if (t.isFunctionDeclaration(bNode)) {
|
|
255
|
+
capture(bNode);
|
|
256
|
+
const fnSrc = state.file.code.slice(bNode.start, bNode.end);
|
|
257
|
+
captures.push(transpileForThread(fnSrc, state));
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
capture(fnNode);
|
|
264
|
+
return captures;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// ── Core transform helpers ─────────────────────────────────────
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Transpile extracted source for the thread engine. Always downlevels
|
|
271
|
+
* to ES5 (for Rhino). Also strips TypeScript when the host file is TS.
|
|
272
|
+
*/
|
|
273
|
+
function transpileForThread(code, state) {
|
|
274
|
+
try {
|
|
275
|
+
const babelCore = require('@babel/core');
|
|
276
|
+
const fn =
|
|
277
|
+
state.filename || (state.file.opts && state.file.opts.filename) || '';
|
|
278
|
+
const isTS = /\.tsx?$/.test(fn);
|
|
279
|
+
const plugins = isTS
|
|
280
|
+
? [['@babel/plugin-transform-typescript', { isTSX: true }]]
|
|
281
|
+
: [];
|
|
282
|
+
const result = babelCore.transformSync(code, {
|
|
283
|
+
presets: [
|
|
284
|
+
['@babel/preset-env', { targets: { ie: '11' }, modules: false }],
|
|
285
|
+
],
|
|
286
|
+
plugins,
|
|
287
|
+
configFile: false,
|
|
288
|
+
babelrc: false,
|
|
289
|
+
filename: isTS ? 'thread.tsx' : 'thread.js',
|
|
290
|
+
});
|
|
291
|
+
return ((result && result.code) || code).replace(/;\s*$/, '');
|
|
292
|
+
} catch {
|
|
293
|
+
return code;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
8
297
|
function maybeTransformArg(callPath, state, argNode, index) {
|
|
9
298
|
if (
|
|
10
299
|
!t.isArrowFunctionExpression(argNode) &&
|
|
@@ -14,12 +303,126 @@ module.exports = function reactNativeThreadPlugin({ types: t }) {
|
|
|
14
303
|
}
|
|
15
304
|
|
|
16
305
|
const originalCode = state.file.code;
|
|
17
|
-
const fnSource =
|
|
306
|
+
const fnSource = transpileForThread(
|
|
307
|
+
originalCode.slice(argNode.start, argNode.end),
|
|
308
|
+
state
|
|
309
|
+
);
|
|
18
310
|
const iife = `(${fnSource})(__params__)`;
|
|
19
311
|
|
|
20
312
|
callPath.node.arguments[index] = t.stringLiteral(iife);
|
|
21
313
|
}
|
|
22
314
|
|
|
315
|
+
/**
|
|
316
|
+
* Resolve a node to its function source **and** any captured free-variable
|
|
317
|
+
* declarations. Returns the ready-to-eval source string, or null.
|
|
318
|
+
*/
|
|
319
|
+
function extractFnSource(node, callPath, state) {
|
|
320
|
+
let fnNode = null;
|
|
321
|
+
let fnSource = null;
|
|
322
|
+
let isImported = false;
|
|
323
|
+
|
|
324
|
+
if (t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) {
|
|
325
|
+
fnNode = node;
|
|
326
|
+
fnSource = state.file.code.slice(node.start, node.end);
|
|
327
|
+
} else if (t.isIdentifier(node)) {
|
|
328
|
+
const binding = callPath.scope.getBinding(node.name);
|
|
329
|
+
if (!binding) return null;
|
|
330
|
+
const bNode = binding.path.node;
|
|
331
|
+
if (t.isFunctionDeclaration(bNode)) {
|
|
332
|
+
fnNode = bNode;
|
|
333
|
+
fnSource = state.file.code.slice(bNode.start, bNode.end);
|
|
334
|
+
} else if (t.isVariableDeclarator(bNode) && bNode.init) {
|
|
335
|
+
if (
|
|
336
|
+
t.isFunctionExpression(bNode.init) ||
|
|
337
|
+
t.isArrowFunctionExpression(bNode.init)
|
|
338
|
+
) {
|
|
339
|
+
fnNode = bNode.init;
|
|
340
|
+
fnSource = state.file.code.slice(bNode.init.start, bNode.init.end);
|
|
341
|
+
}
|
|
342
|
+
} else if (
|
|
343
|
+
t.isImportSpecifier(bNode) ||
|
|
344
|
+
t.isImportDefaultSpecifier(bNode)
|
|
345
|
+
) {
|
|
346
|
+
// Cross-module import: resolve the source file and extract the function
|
|
347
|
+
const importDecl = binding.path.parentPath.node;
|
|
348
|
+
const importSource = importDecl.source.value;
|
|
349
|
+
const exportName =
|
|
350
|
+
t.isImportSpecifier(bNode) && bNode.imported
|
|
351
|
+
? t.isIdentifier(bNode.imported)
|
|
352
|
+
? bNode.imported.name
|
|
353
|
+
: bNode.imported.value
|
|
354
|
+
: 'default';
|
|
355
|
+
const imported = resolveImportedFnSource(
|
|
356
|
+
importSource,
|
|
357
|
+
exportName,
|
|
358
|
+
state
|
|
359
|
+
);
|
|
360
|
+
if (imported) {
|
|
361
|
+
fnSource = imported;
|
|
362
|
+
isImported = true;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!fnSource) return null;
|
|
368
|
+
|
|
369
|
+
// For imported functions we already have the full source (no local AST node
|
|
370
|
+
// to walk for captures — the function must be self-contained or only depend
|
|
371
|
+
// on its own module's scope which was already inlined).
|
|
372
|
+
if (isImported) return fnSource;
|
|
373
|
+
|
|
374
|
+
if (!fnNode) return null;
|
|
375
|
+
|
|
376
|
+
fnSource = transpileForThread(fnSource, state);
|
|
377
|
+
|
|
378
|
+
const captures = getCaptureDecls(fnNode, callPath.scope, state);
|
|
379
|
+
if (captures.length > 0) {
|
|
380
|
+
fnSource =
|
|
381
|
+
'(function(){' + captures.join('\n') + '\nreturn ' + fnSource + ';})()';
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return fnSource;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function tagFnValue(source) {
|
|
388
|
+
return t.objectExpression([
|
|
389
|
+
t.objectProperty(t.identifier('__rnThreadFn'), t.stringLiteral(source)),
|
|
390
|
+
]);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function maybeTransformParams(callPath, state, paramsNode) {
|
|
394
|
+
if (!t.isObjectExpression(paramsNode)) return;
|
|
395
|
+
for (const prop of paramsNode.properties) {
|
|
396
|
+
if (!t.isObjectProperty(prop)) continue;
|
|
397
|
+
const fnSrc = extractFnSource(prop.value, callPath, state);
|
|
398
|
+
if (fnSrc) {
|
|
399
|
+
prop.value = tagFnValue(fnSrc);
|
|
400
|
+
prop.shorthand = false;
|
|
401
|
+
} else if (t.isObjectExpression(prop.value)) {
|
|
402
|
+
maybeTransformParams(callPath, state, prop.value);
|
|
403
|
+
} else if (t.isArrayExpression(prop.value)) {
|
|
404
|
+
maybeTransformArrayParams(callPath, state, prop.value);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function maybeTransformArrayParams(callPath, state, arrNode) {
|
|
410
|
+
for (let i = 0; i < arrNode.elements.length; i++) {
|
|
411
|
+
const el = arrNode.elements[i];
|
|
412
|
+
if (!el) continue;
|
|
413
|
+
const fnSrc = extractFnSource(el, callPath, state);
|
|
414
|
+
if (fnSrc) {
|
|
415
|
+
arrNode.elements[i] = tagFnValue(fnSrc);
|
|
416
|
+
} else if (t.isObjectExpression(el)) {
|
|
417
|
+
maybeTransformParams(callPath, state, el);
|
|
418
|
+
} else if (t.isArrayExpression(el)) {
|
|
419
|
+
maybeTransformArrayParams(callPath, state, el);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ── Visitor ────────────────────────────────────────────────────
|
|
425
|
+
|
|
23
426
|
return {
|
|
24
427
|
name: 'react-native-thread',
|
|
25
428
|
visitor: {
|
|
@@ -30,6 +433,9 @@ module.exports = function reactNativeThreadPlugin({ types: t }) {
|
|
|
30
433
|
if (args.length >= 1) {
|
|
31
434
|
maybeTransformArg(path, state, args[0], 0);
|
|
32
435
|
}
|
|
436
|
+
if (args.length >= 2) {
|
|
437
|
+
maybeTransformParams(path, state, args[1]);
|
|
438
|
+
}
|
|
33
439
|
return;
|
|
34
440
|
}
|
|
35
441
|
|
|
@@ -42,6 +448,9 @@ module.exports = function reactNativeThreadPlugin({ types: t }) {
|
|
|
42
448
|
if (args.length >= 1) {
|
|
43
449
|
maybeTransformArg(path, state, args[0], 0);
|
|
44
450
|
}
|
|
451
|
+
if (args.length >= 2) {
|
|
452
|
+
maybeTransformParams(path, state, args[1]);
|
|
453
|
+
}
|
|
45
454
|
}
|
|
46
455
|
},
|
|
47
456
|
},
|