import {ethers} from 'ethers'; function split(s) { return s ? s.split('.') : []; } export class Node extends Map { static create(name) { return name instanceof this ? name : this.root().create(name); } static root(tag = 'root') { return new this(null, ethers.ZeroHash, `[${tag}]`); } constructor(parent, namehash, label, labelhash) { super(); this.parent = parent; this.namehash = namehash; this.label = label; this.labelhash = labelhash; } get dns() { return ethers.getBytes(ethers.dnsEncode(this.name, 255)); } get name() { if (!this.parent) return ''; let v = []; for (let x = this; x.parent; x = x.parent) v.push(x.label); return v.join('.'); } get depth() { let n = 0; for (let x = this; x.parent; x = x.parent) ++n; return n; } get nodeCount() { let n = 0; this.scan(() => ++n); return n; } get root() { let x = this; while (x.parent) x = x.parent; return x; } get isETH2LD() { return this.parent?.name === 'eth'; } path(inc_root) { // raffy.eth => [raffy.eth, eth, ?] let v = []; for (let x = this; inc_root ? x : x.parent; x = x.parent) v.push(x); return v; } find(name) { return split(name).reduceRight((n, s) => n?.get(s), this); } create(name) { return split(name).reduceRight((n, s) => n.child(s), this); } child(label) { let node = this.get(label); if (!node) { let labelhash = ethers.id(label) let namehash = ethers.solidityPackedKeccak256(['bytes32', 'bytes32'], [this.namehash, labelhash]); node = new this.constructor(this, namehash, label, labelhash); this.set(label, node); } return node; } unique(prefix = 'u') { for (let i = 1; ; i++) { let label = prefix + i; if (!this.has(label)) return this.child(label); } } scan(fn, level = 0) { fn(this, level++); for (let x of this.values()) { x.scan(fn, level); } } flat() { let v = []; this.scan(x => v.push(x)); return v; } toString() { return this.name; } print(format = x => x.label) { this.scan((x, n) => console.log(' '.repeat(n) + format(x))); } }