177 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
 | 
						|
 | 
						|
const HELPERS = {
 | 
						|
  require: `
 | 
						|
    import {createRequire as CREATE_REQUIRE_NAME} from "module";
 | 
						|
    const require = CREATE_REQUIRE_NAME(import.meta.url);
 | 
						|
  `,
 | 
						|
  interopRequireWildcard: `
 | 
						|
    function interopRequireWildcard(obj) {
 | 
						|
      if (obj && obj.__esModule) {
 | 
						|
        return obj;
 | 
						|
      } else {
 | 
						|
        var newObj = {};
 | 
						|
        if (obj != null) {
 | 
						|
          for (var key in obj) {
 | 
						|
            if (Object.prototype.hasOwnProperty.call(obj, key)) {
 | 
						|
              newObj[key] = obj[key];
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        newObj.default = obj;
 | 
						|
        return newObj;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  interopRequireDefault: `
 | 
						|
    function interopRequireDefault(obj) {
 | 
						|
      return obj && obj.__esModule ? obj : { default: obj };
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  createNamedExportFrom: `
 | 
						|
    function createNamedExportFrom(obj, localName, importedName) {
 | 
						|
      Object.defineProperty(exports, localName, {enumerable: true, configurable: true, get: () => obj[importedName]});
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  // Note that TypeScript and Babel do this differently; TypeScript does a simple existence
 | 
						|
  // check in the exports object and does a plain assignment, whereas Babel uses
 | 
						|
  // defineProperty and builds an object of explicitly-exported names so that star exports can
 | 
						|
  // always take lower precedence. For now, we do the easier TypeScript thing.
 | 
						|
  createStarExport: `
 | 
						|
    function createStarExport(obj) {
 | 
						|
      Object.keys(obj)
 | 
						|
        .filter((key) => key !== "default" && key !== "__esModule")
 | 
						|
        .forEach((key) => {
 | 
						|
          if (exports.hasOwnProperty(key)) {
 | 
						|
            return;
 | 
						|
          }
 | 
						|
          Object.defineProperty(exports, key, {enumerable: true, configurable: true, get: () => obj[key]});
 | 
						|
        });
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  nullishCoalesce: `
 | 
						|
    function nullishCoalesce(lhs, rhsFn) {
 | 
						|
      if (lhs != null) {
 | 
						|
        return lhs;
 | 
						|
      } else {
 | 
						|
        return rhsFn();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  asyncNullishCoalesce: `
 | 
						|
    async function asyncNullishCoalesce(lhs, rhsFn) {
 | 
						|
      if (lhs != null) {
 | 
						|
        return lhs;
 | 
						|
      } else {
 | 
						|
        return await rhsFn();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  optionalChain: `
 | 
						|
    function optionalChain(ops) {
 | 
						|
      let lastAccessLHS = undefined;
 | 
						|
      let value = ops[0];
 | 
						|
      let i = 1;
 | 
						|
      while (i < ops.length) {
 | 
						|
        const op = ops[i];
 | 
						|
        const fn = ops[i + 1];
 | 
						|
        i += 2;
 | 
						|
        if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
 | 
						|
          return undefined;
 | 
						|
        }
 | 
						|
        if (op === 'access' || op === 'optionalAccess') {
 | 
						|
          lastAccessLHS = value;
 | 
						|
          value = fn(value);
 | 
						|
        } else if (op === 'call' || op === 'optionalCall') {
 | 
						|
          value = fn((...args) => value.call(lastAccessLHS, ...args));
 | 
						|
          lastAccessLHS = undefined;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return value;
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  asyncOptionalChain: `
 | 
						|
    async function asyncOptionalChain(ops) {
 | 
						|
      let lastAccessLHS = undefined;
 | 
						|
      let value = ops[0];
 | 
						|
      let i = 1;
 | 
						|
      while (i < ops.length) {
 | 
						|
        const op = ops[i];
 | 
						|
        const fn = ops[i + 1];
 | 
						|
        i += 2;
 | 
						|
        if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
 | 
						|
          return undefined;
 | 
						|
        }
 | 
						|
        if (op === 'access' || op === 'optionalAccess') {
 | 
						|
          lastAccessLHS = value;
 | 
						|
          value = await fn(value);
 | 
						|
        } else if (op === 'call' || op === 'optionalCall') {
 | 
						|
          value = await fn((...args) => value.call(lastAccessLHS, ...args));
 | 
						|
          lastAccessLHS = undefined;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return value;
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  optionalChainDelete: `
 | 
						|
    function optionalChainDelete(ops) {
 | 
						|
      const result = OPTIONAL_CHAIN_NAME(ops);
 | 
						|
      return result == null ? true : result;
 | 
						|
    }
 | 
						|
  `,
 | 
						|
  asyncOptionalChainDelete: `
 | 
						|
    async function asyncOptionalChainDelete(ops) {
 | 
						|
      const result = await ASYNC_OPTIONAL_CHAIN_NAME(ops);
 | 
						|
      return result == null ? true : result;
 | 
						|
    }
 | 
						|
  `,
 | 
						|
};
 | 
						|
 | 
						|
export class HelperManager {
 | 
						|
  __init() {this.helperNames = {}}
 | 
						|
  __init2() {this.createRequireName = null}
 | 
						|
  constructor( nameManager) {;this.nameManager = nameManager;HelperManager.prototype.__init.call(this);HelperManager.prototype.__init2.call(this);}
 | 
						|
 | 
						|
  getHelperName(baseName) {
 | 
						|
    let helperName = this.helperNames[baseName];
 | 
						|
    if (helperName) {
 | 
						|
      return helperName;
 | 
						|
    }
 | 
						|
    helperName = this.nameManager.claimFreeName(`_${baseName}`);
 | 
						|
    this.helperNames[baseName] = helperName;
 | 
						|
    return helperName;
 | 
						|
  }
 | 
						|
 | 
						|
  emitHelpers() {
 | 
						|
    let resultCode = "";
 | 
						|
    if (this.helperNames.optionalChainDelete) {
 | 
						|
      this.getHelperName("optionalChain");
 | 
						|
    }
 | 
						|
    if (this.helperNames.asyncOptionalChainDelete) {
 | 
						|
      this.getHelperName("asyncOptionalChain");
 | 
						|
    }
 | 
						|
    for (const [baseName, helperCodeTemplate] of Object.entries(HELPERS)) {
 | 
						|
      const helperName = this.helperNames[baseName];
 | 
						|
      let helperCode = helperCodeTemplate;
 | 
						|
      if (baseName === "optionalChainDelete") {
 | 
						|
        helperCode = helperCode.replace("OPTIONAL_CHAIN_NAME", this.helperNames.optionalChain);
 | 
						|
      } else if (baseName === "asyncOptionalChainDelete") {
 | 
						|
        helperCode = helperCode.replace(
 | 
						|
          "ASYNC_OPTIONAL_CHAIN_NAME",
 | 
						|
          this.helperNames.asyncOptionalChain,
 | 
						|
        );
 | 
						|
      } else if (baseName === "require") {
 | 
						|
        if (this.createRequireName === null) {
 | 
						|
          this.createRequireName = this.nameManager.claimFreeName("_createRequire");
 | 
						|
        }
 | 
						|
        helperCode = helperCode.replace(/CREATE_REQUIRE_NAME/g, this.createRequireName);
 | 
						|
      }
 | 
						|
      if (helperName) {
 | 
						|
        resultCode += " ";
 | 
						|
        resultCode += helperCode.replace(baseName, helperName).replace(/\s+/g, " ").trim();
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return resultCode;
 | 
						|
  }
 | 
						|
}
 |