Skip to content

Commit 1feaf6d

Browse files
janvennemannsgtcoolguy
authored andcommitted
feat: add custom inspect behavior for buffers
1 parent 601105b commit 1feaf6d

File tree

5 files changed

+133
-39
lines changed

5 files changed

+133
-39
lines changed

common/Resources/ti.internal/extensions/node/buffer.js

+65-9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,17 @@
1414
* a Uint8Array in any of our APIs that take a Ti.Buffer and eventually deprecating/removing Ti.Buffer.
1515
*/
1616

17-
import{isInsideNodeModules}from'./internal/util';
17+
import{
18+
customInspectSymbol,
19+
getOwnNonIndexProperties,
20+
isBuffer,
21+
isInsideNodeModules,
22+
propertyFilter
23+
}from'./internal/util';
24+
25+
import{inspectasutilInspect}from'./internal/util/inspect';
26+
27+
const{ALL_PROPERTIES,ONLY_ENUMERABLE}=propertyFilter;
1828

1929
// https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings
2030
constTI_CODEC_MAP=newMap();
@@ -51,6 +61,8 @@ const uint8DoubleArray = new Uint8Array(doubleArray.buffer);
5161
constfloatArray=newFloat32Array(1);
5262
constuint8FloatArray=newUint8Array(floatArray.buffer);
5363

64+
letINSPECT_MAX_BYTES=50;
65+
5466
classBuffer{
5567
/**
5668
* Constructs a new buffer.
@@ -80,17 +92,23 @@ class Buffer {
8092

8193
consttiBuffer=arg;
8294
letstart=encodingOrOffset;
83-
this._tiBuffer=tiBuffer;
8495
if(start===undefined){
8596
start=0;
8697
}
87-
this.byteOffset=start;
8898
if(length===undefined){
89-
this.length=tiBuffer.length-this.byteOffset;
90-
}else{
91-
this.length=length;
99+
length=tiBuffer.length-start;
92100
}
93-
this._isBuffer=true;
101+
Object.defineProperties(this,{
102+
byteOffset: {
103+
value: start
104+
},
105+
length: {
106+
value: length
107+
},
108+
_tiBuffer: {
109+
value: tiBuffer
110+
}
111+
});
94112
// FIXME: Support .buffer property that holds an ArrayBuffer!
95113
}
96114

@@ -1405,10 +1423,46 @@ class Buffer {
14051423
* @returns {boolean}
14061424
*/
14071425
staticisBuffer(obj){
1408-
returnobj!==null&&obj!==undefined&&obj._isBuffer===true;
1426+
returnobj!==null&&obj!==undefined&&obj[isBuffer]===true;
1427+
}
1428+
1429+
// Override how buffers are presented by util.inspect().
1430+
[customInspectSymbol](recurseTimes,ctx){
1431+
constmax=INSPECT_MAX_BYTES;
1432+
constactualMax=Math.min(max,this.length);
1433+
constremaining=this.length-max;
1434+
letstr=this.slice(0,actualMax).toString('hex').replace(/(.{2})/g,'$1 ').trim();
1435+
if(remaining>0){
1436+
str+=` ... ${remaining} more byte${remaining>1 ? 's' : ''}`;
1437+
}
1438+
// Inspect special properties as well, if possible.
1439+
if(ctx){
1440+
letextras=false;
1441+
constfilter=ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
1442+
constobj=getOwnNonIndexProperties(this,filter).reduce((obj,key)=>{
1443+
extras=true;
1444+
obj[key]=this[key];
1445+
returnobj;
1446+
},Object.create(null));
1447+
if(extras){
1448+
if(this.length!==0){
1449+
str+=', ';
1450+
}
1451+
// '[Object: null prototype] {'.length === 26
1452+
// This is guarded with a test.
1453+
str+=utilInspect(obj,{
1454+
...ctx,
1455+
breakLength: Infinity,
1456+
compact: true
1457+
}).slice(27,-2);
1458+
}
1459+
}
1460+
return`<${this.constructor.name}${str}>`;
14091461
}
14101462
}
14111463

1464+
Buffer.prototype.inspect=Buffer.prototype[customInspectSymbol];
1465+
14121466
Buffer.poolSize=8192;
14131467

14141468
exportdefault{
@@ -1543,6 +1597,8 @@ const arrayIndexHandler = {
15431597
if(Number.isSafeInteger(num)){
15441598
returngetAdjustedIndex(target,num);
15451599
}
1600+
}elseif(propKey===isBuffer){
1601+
returntrue;
15461602
}
15471603
returnReflect.get(target,propKey,receiver);
15481604
},
@@ -1589,7 +1645,7 @@ function setAdjustedIndex(buf, index, value) {
15891645
* @returns {Buffer} wrapped inside a Proxy
15901646
*/
15911647
functionnewBuffer(...args){
1592-
returnnewProxy(newBuffer(...args),arrayIndexHandler);// eslint-disable-line security/detect-new-buffer
1648+
returnnewProxy(newBuffer(...args),arrayIndexHandler);// eslint-disable-line security/detect-new-buffer
15931649
}
15941650

15951651
/**

common/Resources/ti.internal/extensions/node/internal/util.js

+34
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { isNativeError } from './util/types';
33
constkNodeModulesRE=/^(.*)[\\/]node_modules[\\/]/;
44

55
exportconstcustomInspectSymbol=Symbol.for('nodejs.util.inspect.custom');
6+
exportconstisBuffer=Symbol.for('titanium.buffer.isBuffer');
67

78
constcolorRegExp=/\u001b\[\d\d?m/g;// eslint-disable-line no-control-regex
89

@@ -79,3 +80,36 @@ export function uncurryThis(f) {
7980
returnf.call.apply(f,arguments);
8081
};
8182
}
83+
84+
constALL_PROPERTIES=0;
85+
constONLY_ENUMERABLE=2;
86+
87+
exportconstpropertyFilter={
88+
ALL_PROPERTIES,
89+
ONLY_ENUMERABLE
90+
};
91+
92+
exportfunctiongetOwnNonIndexProperties(obj,filter){
93+
constprops=[];
94+
constkeys=filter===ONLY_ENUMERABLE ? Object.keys(obj) : Object.getOwnPropertyNames(obj);
95+
for(vari=0;i<keys.length;++i){
96+
constkey=keys[i];
97+
if(!isAllDigits(key)){
98+
props.push(key);
99+
}
100+
}
101+
returnprops;
102+
}
103+
104+
functionisAllDigits(s){
105+
if(s.length===0){
106+
returnfalse;
107+
}
108+
for(vari=0;i<s.length;++i){
109+
constcode=s.charCodeAt(i);
110+
if(code<48||code>57){
111+
returnfalse;
112+
}
113+
}
114+
returntrue;
115+
}

common/Resources/ti.internal/extensions/node/internal/util/inspect.js

+4-28
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ import {
3838
import{codes,isStackOverflowError}from'../errors';
3939
import{
4040
customInspectSymbol,
41+
getOwnNonIndexProperties,
4142
isError,
4243
join,
44+
propertyFilter,
4345
removeColors,
4446
uncurryThis
4547
}from'../util';
4648

49+
const{ALL_PROPERTIES,ONLY_ENUMERABLE}=propertyFilter;
50+
4751
constBooleanPrototype=Boolean.prototype;
4852
constDatePrototype=Date.prototype;
4953
constErrorPrototype=Error.prototype;
@@ -482,34 +486,6 @@ function noPrototypeIterator(ctx, value, recurseTimes) {
482486
}
483487
}
484488

485-
functionisAllDigits(s){
486-
if(s.length===0){
487-
returnfalse;
488-
}
489-
for(vari=0;i<s.length;++i){
490-
constcode=s.charCodeAt(i);
491-
if(code<48||code>57){
492-
returnfalse;
493-
}
494-
}
495-
returntrue;
496-
}
497-
498-
functiongetOwnNonIndexProperties(obj,filter){
499-
constprops=[];
500-
constkeys=filter===ONLY_ENUMERABLE ? Object.keys(obj) : Object.getOwnPropertyNames(obj);
501-
for(vari=0;i<keys.length;++i){
502-
constkey=keys[i];
503-
if(!isAllDigits(key)){
504-
props.push(key);
505-
}
506-
}
507-
returnprops;
508-
}
509-
510-
constALL_PROPERTIES=0;
511-
constONLY_ENUMERABLE=2;
512-
513489
functionformatValue(ctx,value,recurseTimes,typedArray){
514490
// Primitive types cannot have properties.
515491
if(typeofvalue!=='object'&&typeofvalue!=='function'){

common/Resources/ti.internal/extensions/node/internal/util/types.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import{uncurryThis}from'../util';
1+
import{isBuffer,uncurryThis}from'../util';
22

33
constTypedArrayPrototype=Object.getPrototypeOf(Uint8Array.prototype);
44

@@ -176,7 +176,12 @@ export function isSymbolObject(value) {
176176
}
177177

178178
exportfunctionisTypedArray(value){
179-
returnTypedArrayProto_toStringTag(value)!==undefined;
179+
constisBuiltInTypedArray=TypedArrayProto_toStringTag(value)!==undefined;
180+
if(isBuiltInTypedArray){
181+
returntrue;
182+
}
183+
184+
returnvalue[isBuffer]===true;
180185
}
181186

182187
exportfunctionisUint8Array(value){

tests/Resources/util.test.js

+23
Original file line numberDiff line numberDiff line change
@@ -1485,6 +1485,29 @@ describe('util', () => {
14851485
});
14861486
});
14871487

1488+
describe('#isTypedArray()',()=>{
1489+
it('should return true for built-in typed arrays',()=>{
1490+
should(util.types.isTypedArray(newUint8Array())).be.true;
1491+
should(util.types.isTypedArray(newUint8ClampedArray())).be.true;
1492+
should(util.types.isTypedArray(newUint16Array())).be.true;
1493+
should(util.types.isTypedArray(newUint32Array())).be.true;
1494+
should(util.types.isTypedArray(newInt8Array())).be.true;
1495+
should(util.types.isTypedArray(newInt16Array())).be.true;
1496+
should(util.types.isTypedArray(newInt32Array())).be.true;
1497+
should(util.types.isTypedArray(newFloat32Array())).be.true;
1498+
should(util.types.isTypedArray(newFloat64Array())).be.true;
1499+
});
1500+
1501+
it('should return true for our own Buffer',()=>{
1502+
should(util.types.isTypedArray(Buffer.alloc())).be.true;
1503+
});
1504+
1505+
it('should return false for other values',()=>{
1506+
util.types.isTypedArray({}).should.be.false;
1507+
util.types.isTypedArray([]).should.be.false;
1508+
});
1509+
});
1510+
14881511
describe('Typed Arrays',()=>{
14891512
it('should correctly check typed arrays',()=>{
14901513
should(!util.types.isUint8Array({[Symbol.toStringTag]: 'Uint8Array'})).be.true;

0 commit comments

Comments
 (0)
close