JSFiddle - React, Tailwind, and code Playground

by Vlad Rasenko

JavaScript

const JSLicense = (function () {
  const hierarchy = new WeakMap()

  function JSLicense (author) {
    if (typeof global === 'object' ? this === global : this === window) throw new Error('Licenses should be generated using new')
    if (!author) throw new Error('Applying for a fresh license without a name')
    const ctx = new Context(author)
    return create(ctx)
  }
  Object.defineProperty(JSLicense, Symbol.hasInstance, { 
    value: function (obj) { return inMap(obj, hierarchy) }
  })
  

  function create (ctx) {
    const license = function (author) {
      return JSLicense.call(this, author || ctx)
    }
    ctx.rootHierarchy.set(license, ctx.hierarchy)
    Object.defineProperties(license, {
      owner: { get: function () { return ctx.owner } },
      renewed: { get: function () { return ctx.renewed } },
      toString: { value: function () { return `JSLicense: Licensed to ${this.owner}, renewed ${this.renewed} time(s)` } },
      [Symbol.hasInstance]: function (obj) { return inMap(obj, ctx.hierarchy) }
    })
    return license
  }

  function Context (author) {
    this.hierarchy = new WeakMap()
    if (author instanceof Context) {
      this.owner = author.owner
      this.renewed = author.renewed + 1
      this.rootHierarchy = author.hierarchy
    } else {
      this.owner = author
      this.renewed = 0
      this.rootHierarchy = hierarchy
    }
  }
  
  function inMap(obj, map) {
  	debugger
    if (!map.size) return false
    for (let key of map.keys()) {
      if (key === obj) return true
      if (inMap(obj, map.get(key))) return true
    }
    return false
  }

  return JSLicense
})()

l1 = new JSLicense('1')
console.log(l1 instanceof JSLicense)