repo_description: Package your Node.js project into an executable
repo_topics: binaries cli compiler nodejs
code: import assert from 'assert';
  import fs from 'fs';
  import path from 'path';
  
  export const STORE_BLOB = 0;
  export const STORE_CONTENT = 1;
  export const STORE_LINKS = 2;
  export const STORE_STAT = 3;
  export const ALIAS_AS_RELATIVE = 0; // require("./file.js") // file or directory
  export const ALIAS_AS_RESOLVABLE = 1; // require("package")
  
  const win32 = process.platform === 'win32';
  const hasURL = typeof URL !== 'undefined';
  
  function uppercaseDriveLetter(f: string) {
    if (f.slice(1, 3) !== ':\\') return f;
    return f[0].toUpperCase() + f.slice(1);
  }
  
  function removeTrailingSlashes(f: string) {
    if (f === '/') {
      return f; // dont remove from "/"
    }
  
    if (f.slice(1) === ':\\') {
      return f; // dont remove from "D:\"
    }
  
    let last = f.length - 1;
  
    while (true) {
      const char = f.charAt(last);
  
      if (char === '\\') {
        f = f.slice(0, -1);
        last -= 1;
      } else if (char === '/') {
        f = f.slice(0, -1);
        last -= 1;
      } else {
        break;
      }
    }
    return f;
  }
  
  const isUrl = (p: unknown): p is URL => hasURL && p instanceof URL;
  
  function pathToString(p: string | URL | Buffer, win: boolean): string {
    let result: string;
  
    if (Buffer.isBuffer(p)) {
      result = p.toString();
    } else if (isUrl(p)) {
      result = win ? p.pathname.replace(/^\//, '') : p.pathname;
    } else {
      result = p;
    }
  
    return result;
  }
  
  export function isRootPath(p: string | URL | Buffer) {
    let file = pathToString(p, false);
  
    if (file === '.') {
      file = path.resolve(file);
    }
  
    return path.dirname(file) === p;
  }
  
  export function normalizePath(f: string | URL | Buffer) {
    let file = pathToString(f, win32);
  
    if (!/^.:$/.test(file)) {
      file = path.normalize(file);
    } // 'c:' -> 'c:.'
  
    if (win32) {
      file = uppercaseDriveLetter(file);
    }
  
    return removeTrailingSlashes(file);
  }
  
  export function isPackageJson(file: string) {
    return path.basename(file) === 'package.json';
  }
  
  export function isDotJS(file: string) {
    return path.extname(file) === '.js';
  }
  
  export function isDotJSON(file: string) {
    return path.extname(file) === '.json';
  }
  
  export function isDotNODE(file: string) {
    return path.extname(file) === '.node';
  }
  
  function replaceSlashes(file: string, slash: string) {
    if (/^.:\\/.test(file)) {
      if (slash === '/') {
        return file.slice(2).replace(/\\/g, '/');
      }
    } else if (/^\//.test(file)) {
      if (slash === '\\') {
        return `C:${file.replace(/\//g, '\\')}`;
      }
    }
  
    return file;
  }
  
  function injectSnapshot(file: string) {
    if (/^.:\\/.test(file)) {
      // C:\path\to
      if (file.length === 3) {
        // C:\
        file = file.slice(0, -1);
      }
      // by convention, on windows we use C:\\snapshot
      return `C:\\snapshot${file.slice(2)}`;
    }
  
    if (/^\//.test(file)) {
      // /home/user/project
      if (file.length === 1) {
        // /
        file = file.slice(0, -1);
      }
  
      return `/snapshot${file}`;
    }
  
    return file;
  }
  
  function longestCommonLength(s1: string, s2: string) {
    const length = Math.min(s1.length, s2.length);
  
    for (let i = 0; i < length; i += 1) {
      if (s1.charCodeAt(i) !== s2.charCodeAt(i)) {
        return i;
      }
    }
  
    return length;
  }
  
  function withoutNodeModules(file: string) {
    return file.split(`${path.sep}node_modules${path.sep}`)[0];
  }
  
  export function retrieveDenominator(files: string[]) {
    assert(files.length > 0);
  
    let s1 = withoutNodeModules(files[0]) + path.sep;
  
    for (let i = 1; i < files.length; i += 1) {
      const s2 = withoutNodeModules(files[i]) + path.sep;
      s1 = s1.slice(0, longestCommonLength(s1, s2));
    }
  
    if (s1 === '') {
      return win32 ? 2 : 0;
    }
  
    return s1.lastIndexOf(path.sep);
  }
  
  export function substituteDenominator(f: string, denominator: number) {
    const rootLength = win32 ? 2 : 0;
    return f.slice(0, rootLength) + f.slice(denominator);
  }
  
  export function snapshotify(file: string, slash: string) {
    return injectSnapshot(replaceSlashes(file, slash));
  }
  
  export function insideSnapshot(f: Buffer | string | URL) {
    f = pathToString(f, win32);
  
    if (typeof f !== 'string') {
      return false;
    }
  
    if (win32) {
      const slice112 = f.slice(1, 12);
  
      return (
        slice112 === ':\\snapshot\\' ||
        slice112 === ':/snapshot\\' ||
        slice112 === ':\\snapshot/' ||
        slice112 === ':/snapshot/' ||
        slice112 === ':\\snapshot' ||
        slice112 === ':/snapshot'
      );
    }
  
    const slice010 = f.slice(0, 10);
  
    return slice010 === '/snapshot/' || slice010 === '/snapshot';
  }
  
  export function stripSnapshot(f: string) {
    const file = normalizePath(f);
  
    if (/^.:\\snapshot$/.test(file)) {
      return `${file[0]}:\\**\\`;
    }
  
    if (/^.:\\snapshot\\/.test(file)) {
      return `${file[0]}:\\**${file.slice(11)}`;
    }
  
    if (/^\/snapshot$/.test(file)) {
      return '/**/';
    }
  
    if (/^\/snapshot\//.test(file)) {
      return `/**${file.slice(9)}`;
    }
  
    return f; // not inside
  }
  
  export function removeUplevels(f: string) {
    if (win32) {
      while (true) {
        if (f.slice(0, 3) === '..\\') {
          f = f.slice(3);
        } else if (f === '..') {
          f = '.';
        } else {
          break;
        }
      }
  
      return f;
    }
  
    while (true) {
      if (f.slice(0, 3) === '../') {
        f = f.slice(3);
      } else if (f === '..') {
        f = '.';
      } else {
        break;
      }
    }
  
    return f;
  }
  
  export function toNormalizedRealPath(requestPath: string) {
    const file = normalizePath(requestPath);
  
    if (fs.existsSync(file)) {
      return fs.realpathSync(file);
    }
  
    return file;
  }
  