Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
"use strict";

// 0. export rollup configs
//   - dev, sourcemap files, amd, cjs, iife, typescript definitions
// 1. compile (tsc, babel, buble)
//   - src -> dist
// 2. compile (babel, buble)
//   - test -> test-dist
// 3. copy:
//   - dist -> root
// 4. bundle (rollup)
//   - dist -> index.bundle
// 5. compile (tsc)
//   - index.bundle -> index.compiled
// 6. bundle (rollup)
//   -> index.compiled -> index.js
// 6. ops:
//   - run test
// - run cov
const _require = require('path'),
      resolve = _require.resolve,
      basename = _require.basename;

const jetpack = require('fs-jetpack');

const fwf = require('funwithflags');

const Script = require('script-chain');

const log = require('fliplog');

const _require2 = require('flipfile'),
      read = _require2.read,
      write = _require2.write;

const eslint = require('eslint'); // const docdown = require('docdown')


const find = require('chain-able-find');

const Chainable = require("../exports");

const _require3 = require("./util"),
      del = _require3.del,
      _res = _require3._res,
      fromTo = _require3.fromTo;

const _require4 = require("./plugins/ast"),
      stripRollup = _require4.stripRollup;

const linter = eslint.linter,
      CLIEngine = eslint.CLIEngine;

const res = _res(__dirname);

const resRoot = _res('../');

const replace = Chainable.replace,
      pipe = Chainable.pipe,
      dot = Chainable.dot,
      traverse = Chainable.traverse,
      uniq = Chainable.uniq,
      includes = Chainable.includes,
      not = Chainable.not,
      and = Chainable.and,
      trim = Chainable.trim;
const hasColon = includes(':');
const hasDot = includes('.'); // https://github.com/chalk/ansi-regex/blob/master/index.js

const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]/g;
const stripAnsi = replace(ansiRegex, '');
const timer = log.fliptime();
timer.start('cli');
log.registerCatch(); // startsWith '//' || '/*'

const stripWhitespace = replace(/(\s|\t|\n)+/g, '');

const _isComment = x => x.startsWith('//') || x.startsWith('*') || x.startsWith('/*') || x.includes('remapped from');

const isComment = pipe(trim, stripWhitespace, _isComment); // setup args
// src: [rollup, typescript, buble, babel, browserify, copy/strip]

const argvOpts = {
  boolean: ['cov', 'src', 'copy', 'production', 'docs', 'optimize', 'diff', 'doctrine', 'easyexports', 'cleaneasyexports', 'quick'],
  string: ['format'],
  default: {
    optimize: true,
    docs: false,
    clean: false,
    tests: false,
    cov: false,
    quick: false,
    diff: false,
    production: true,
    doctrine: false,
    easyexports: false,
    cleaneasyexports: false,
    format: ['amd', 'iife', 'dev', 'es', 'cjs', 'umd']
  }
};
const argvs = fwf(process.argv.slice(2), argvOpts);
const production = argvs.production,
      quick = argvs.quick,
      tests = argvs.tests,
      cov = argvs.cov,
      clean = argvs.clean,
      docs = argvs.docs,
      diff = argvs.diff,
      doctrine = argvs.doctrine,
      easyexports = argvs.easyexports,
      cleaneasyexports = argvs.cleaneasyexports;
const OPTIMIZE_JS_FILE = '../dists/umd/index.js';
const TSC_SOURCE = '../dists/dev/index.js';
const TSC_OUT = '../dists/tsc/bundle.js';
const ROLLUP_CONFIG_CLI = './rollup.config.cli.js';

if (clean) {
  const toClean = {
    files: ['browserified', 'MethodChain', 'Chainable', 'ChainedMap', 'ChainedMapBase', 'FactoryChain', 'MergeChain', 'ChainedSet', 'TraverseChain', 'index'],
    dirs: ['dist', 'test-dist', 'disted', 'dists', 'dist', 'compose', 'plugins', 'coverage', '.nyc_output', 'deps']
  };
  toClean.files.map(file => del(res('../' + file + '.js')));
  toClean.files.map(file => del(res('../' + file + '.js.map')));
  toClean.dirs.map(file => del(res('../' + file + '/')));
  process.exit();
} // script factory


const script = (bin = 'rollup', flags = '') => {
  let scripty = new Script();
  scripty.remember = {
    start() {},

    finish() {}

  };
  scripty = scripty.stdout('inherit').debug(false).add().npm(bin);
  flags.split(' ').map(flag => scripty.raw(flag));
  return scripty.run();
};

const root = res('../');
const entry = res('../src');
const srcFiles = find.init().recursive(true).ignoreDirs(['ignant']).matchFiles(['**/*.js']).abs(true).sync(true).find(entry).results();
const typings = find.init().recursive(true).matchFiles(['**/*.d.ts']).abs(true).sync(true).find(res('../typings')).results();
const testFiles = find.init().recursive(true).matchFiles(['**/*.js']).abs(true).sync(true).find(res('../test')).results();

const toRel = filepath => filepath.replace(root, '').replace(entry, '');

const repoPath = 'https://github.com/fluents/chain-able/blob/master';
const repoDocPath = 'https://github.com/fluents/chain-able/blob/master/docs/docdown';

const toDocPath = filepathBasename => (res('../docs/docdown/') + '/' + filepathBasename).replace('.js', '.md');

const toRepoDocPath = filepathBasename => repoDocPath + filepathBasename;

const toBasename = filePath => basename(filePath);

const toAnchor = (label, href) => `[${basename(label)}](${href || label})`;

const stripDot = replace(/[.]/gim, '');
const escapeDot = replace(/[.]/gim, '\\.');
const slashToDot = replace(/\//gim, '.');
const stripExt = replace(/\.[a-zA-Z0-9]{0,3}/, ''); // ensure there is a `/` between them, say if we just resolve a filename

const toRepoPath = filepathBasename => {
  if (repoPath.endsWith('/') || filepathBasename.startsWith('/')) {
    return repoPath + filepathBasename;
  } else {
    return repoPath + '/' + filepathBasename;
  }
}; // cli class


let CLI = class CLI {
  copy(toRoot = false) {
    // @TODO: dist & toRoot (does it ever need to be in dist except for buble?)
    const scripts = new Script().add().bin('flow-remove-types').raw('src/').flag('pretty').flag('quiet').flag('all').flag('out-dir').arg('./dist');

    if (toRoot) {
      scripts.add().bin('flow-remove-types').raw('src/').flag('pretty').flag('quiet').flag('all').flag('out-dir').arg('./');
    }

    scripts.remember = {
      start() {},

      finish() {}

    };
    scripts.toString();
  }

  tsc(buildTests = false) {
    if (buildTests) {
      const flags = '--pretty --sourceMap --allowJs --project test --outDir test-dist';
      return script('tsc', flags);
    }

    return script('tsc');
  }

  ts() {
    const ts = require('typescript');

    const source = read(TSC_SOURCE);
    let result = ts.transpileModule(source, {
      compilerOptions: {
        module: ts.ModuleKind.CommonJS
      }
    });
    write(require.resolve(TSC_OUT), result.outputText);
    console.log(JSON.stringify(result));
    process.exit();
  }

  stripRollup(url = OPTIMIZE_JS_FILE) {
    const file = require.resolve(url);

    let code = read(file);
    log.diff(code);
    let optimized = stripRollup(code).toString(); // no need, but fun
    // const escaped = require('../src/deps/matcher/to-regexp')('Object.create')
    // optimized = optimized.replace(escaped, 'occc')
    // while (optimized.includes('Object.create'))
    //   optimized = optimized.replace('Object.create', 'occc')
    // optimized = 'var occc = Object.create;\n' + optimized

    log.diff(optimized);
    log.echo(); // log.quick({optimized, code})

    write(file, optimized);
    return Promise.resolve();
  }

  optimizejs(url = OPTIMIZE_JS_FILE) {
    const optimizeJs = require('optimize-js');

    const file = require.resolve(url);

    const code = read(file);
    if (diff) log.diff(code);
    const optimized = optimizeJs(code);
    if (diff) log.diff(optimized);
    write(file, optimized);
    if (diff) log.echo();
    return this.stripRollup();
  }

  rollup(flags = '') {
    if (Array.isArray(flags)) return flags.map(flag => this.rollup(flag));
    const config = ROLLUP_CONFIG_CLI;
    return script('rollup', '-c ' + require.resolve(config) + ' ' + flags);
  }

  rollupNode(overrides = {}) {
    return require("./build")(overrides);
  }

  doctrine(source) {
    var doctrineAPI = require('doctrine');

    var ast = doctrineAPI.parse(source, {
      unwrap: true,
      sloppy: true
    });
    log.quick(ast);
  }

  docs() {
    // all the docs in 1 place
    const allInOne = res('../dists/dev/index.js');
    srcFiles.push(allInOne);
    const vfs = {
      toDocPath,
      toRepoPath,
      toRepoDocPath,
      toRel,
      toBasename,
      typings: {
        abs: typings,
        rel: typings.map(toRel)
      },
      tests: {
        abs: testFiles,
        rel: testFiles.map(toRel)
      },
      src: {
        abs: srcFiles,
        rel: srcFiles.map(toRel)
      } // ----------- docs -----------

    };
    timer.start('docs');
    srcFiles.map(filepath => {
      // if (!filepath.includes('dists/dev/index.js')) return
      // if (!filepath.includes('_Playground')) return
      const relatived = filepath.replace(root, ''); // eslint-disable-next-line
      // debugger

      const docdown = require("../_modules/_docdown");

      const markdown = docdown({
        path: filepath,
        url: repoPath + relatived,
        files: vfs
      });
      let filepathBasename = relatived.replace('/src/', '');
      let docpath = toDocPath(filepathBasename);

      if (docpath.includes('dists/')) {
        filepathBasename = relatived.replace('dists/dev/index', 'aio');
        docpath = toDocPath(filepathBasename);
      }

      write(docpath, markdown); // return {[filepath]: markdown}
    });
    timer.stop('docs').log('docs'); // process.exit()

    this.makeTree({
      vfs
    }); // === create
  }

  makeTree(args) {
    const vfs = args.vfs; // ----------- tree -----------
    // === setup

    const allDirs = find.init().recursive(true).ignoreDirs(['node_modules']) // , 'test/**', 'typings/**', 'docs/**'
    .matchFiles(['src/**'].map(resRoot)).abs(true).sync(true).find(resRoot('.')).results();
    let dirs = allDirs.map(dir => hasDot(dir) ? dir.replace(basename(dir), '') : dir).filter(uniq);
    const docFiles = vfs.src.rel.map(vfs.toRepoDocPath).map(rel => rel.replace('/src/', '/'));

    const _require5 = require("../_modules/_docdown/lib/chain-able"),
          filesMatcher = _require5.filesMatcher;

    const findDir = filesMatcher(dirs);
    const docsTree = {};
    docFiles.forEach(doc => {
      let docName = doc.replace(repoDocPath, ''); // file

      if (hasDot(doc)) {
        docName = stripExt(docName);
      }

      let dotPath = slashToDot(docName);
      if (dotPath.startsWith('.')) dotPath = dotPath.slice(1); // let link = `[${basename(docName)}](${doc})`

      dotPath = dotPath.split('.');
      dotPath[dotPath.length - 1] = escapeDot(toAnchor(docName, doc));
      dotPath = dotPath.join('.');
      dot.set(docsTree, dotPath, '');
    }); // traverse(docsTree)
    // log.quick(docsTree)
    // const tree = log.tree(docsTree).returnVals().datas
    // const treeString = tree
    //   .replace(/(\[39|2m,)/gim, '')
    //   .replace(/\'/gim, '')
    //   .replace(/\,/gim, '')

    const toCode = replace(/[├─│─┐└─]/gim, '`$&`');
    const treeify = log.requirePkg('treeify'); // const testColon = test(/\:$/)
    // pipe(trim, testColon)

    const endsWithColon = x => /\:$/.test(x.trim());

    try {
      const tree = treeify.asTree(docsTree, true, true);
      const treeString = tree.split('\n').map(line => '- ' + toCode(line).replace('``', '` `')).map(line => {
        if (hasColon(line)) {
          return line;
        } else {
          return line.replace(/[a-z0-9]+/gim, x => {
            const resolved = findDir(x).map(dir => dir.includes('http') ? dir : toRel(dir)).filter(dir => dir.endsWith(x + '/')).map(dir => dir.includes('http') ? dir : toRepoDocPath(dir)).shift() || x; // console.log({x, resolved})

            return toAnchor(resolved);
          });
        }
      }) // ends with `:`
      .map(line => endsWithColon(line) ? line.substring(0, line.length - 2) : line).join('\n'); // console.log(treeString)

      write(toDocPath('README.md'), treeString);
    } catch (e) {// console.log(e)
      // console.log(
      //   '@TODO: fork and fix obj.hasOwnProp -> Object.prototype.hasOwnProperty.call(obj, prop)'
      // )
    }
  } // @TODO run versions index


  versions() {}

  cleanEasyExports() {
    const _require6 = require("../exports"),
          flatten = _require6.flatten;

    const _require7 = require("./util"),
          fromTo = _require7.fromTo;

    const exported = flatten(fromTo.values());
    exported // .map(exp => {
    //   if (isNotInOutput(exp)) throw new Error(exp)
    //   return exp
    // })
    .forEach(exp => {
      log.red('deleting').data(exp).echo();
      del(exp);
    });
  }

  lintEasyExports() {
    const temp = fromTo.folder;
    const files = jetpack.list(temp) // @TODO example difference currying makes
    // .filter(filename => filename.includes('.js'))
    .filter(includes('.js')).map(filename => res(temp + '/' + filename));
    files.forEach(filename => this.lintEasyExport(filename, temp)); // log.quick({files})
  } // https://github.com/eslint/eslint/issues/4119 Load plugin when using eslint in node via the API


  lintEasyExport(filename, dir) {
    // @HACK @FIXME @TODO just is ignoring this silly copied over files
    if (!filename.includes('build/')) return;
    if (filename.includes('index.web') || filename.includes('_exported') || filename.includes('_es6') || filename.includes('runner')) return;
    let config = {};

    try {
      const configPath = require.resolve("../../.eslintrc.js");

      config = require(configPath);
    } catch (e) {// ignore, some travis issue?
    }

    config.rules = {
      'import/no-unresolved': 2 // 'node/no-missing-require': 'error',

    };
    config.plugins.push('import'); // log.quick(config)

    let source = read(filename);
    log.bold(filename).echo();
    source.split('\n') // ensure relativeish
    .filter(and(includes('require'), includes('/'))) // .filter(not(isComment))
    .map(line => {
      // commented out lines
      if (isComment(line)) return line;
      log.red(line).echo();
      console.log('\n\n');
      const parts = line.split('=');
      const name = parts.shift().trim();
      let requirePath = parts.pop();

      if (!requirePath) {
        // was just a comment 0.0
        return line; // log.quick({parts, name})
      } // comment from exporting


      requirePath = requirePath.split('/*').shift();

      if (requirePath.includes('.js')) {
        // remove .js if needed
        requirePath = requirePath.split('.js').shift();
      } // keeps letters, numbers, `-` & `_` & `.`


      const sillyRegExpSpecial = /(\s|\^|\$|\#|\@|\!|\&|\=|\+|\t|\n|\?|\>|\<|\{|\}|\[|\]|\|\'|\"|\`|\\|\)|\(|\:|\;|\*|\~|\%|\,)*/gmi;
      const dotSlash = /(\.\/)/gmi;
      requirePath = requirePath.replace('require(', '') // .replace(/[\W_-]+/g, '')
      .replace(sillyRegExpSpecial, '').replace(dotSlash, '').replace(/'*/gmi, '');
      log.blue(requirePath).echo();

      if (!requirePath) {
        log.quick(line);
      }

      requirePath = dir + '/' + requirePath; // ensure all paths exist

      try {
        require.resolve(requirePath);
      } catch (error) {
        log.quick({
          error,
          requirePath
        });
        log.catchAndThrow(error);
      }
    });
    const colored = log.colored(source, 'cyan'); // log.cyan('before\n').data(colored).echo() // "var foo = bar;"

    const eslintCli = new CLIEngine({
      // configFile: configPath,
      config
    });
    const executed = eslintCli.executeOnText(source);
    const results = executed.results;
    const unresolved = results[0].messages.filter(msg => msg.ruleId === 'import/no-unresolved'); // .map(msg => msg.message)
    // log.quick(unresolved)
    // log.quick(eslintCli)

    const verifiedMessages = linter.verify(source, config, {
      filename
    });
    const code = linter.getSourceCode(); // ignoring, linting manually
    // log.yellow('messages').data(verifiedMessages).echo()
    // if (!code || !code.text) {
    //   log.red('could not handle this file ').data({filename}).echo()
    //   return source
    // }
    // log.yellow('code').fmtobj(code).echo()
    // log.blue(code.text).echo() // "var foo = bar;"
    // return code.text
  }

  buble() {
    const sourcemaps = true;
    const scripts = new Script().add().bin('buble').raw('-i dist').raw('-o dist').raw('--no forOf,dangerousForOf,computedProperty,spreadRest');
    if (sourcemaps) scripts.raw('-m inline');
    return scripts.run();
  }

  browserify() {// `browserify src -o dists/browserified/index.js`
  }

  babel() {
    return new Script().add().bin('babel').raw('src/ --out-dir dist').run();
  }

  test(built = false) {
    return script('ava', !built ? '--verbose' : 'test-dist/built.js'); // return script('test')
  }

}; // use the cli class, time the operations, use the argv setup

timer.start('go');
const cli = new CLI();

async function src() {
  // copy
  await cli.copy();
} // @NOTE: not using ts now, got worse as manual optimizations got better


async function rollupTypeScriptRollup() {
  await cli.tsc(); // rollup the typescripted rollup... o.o

  await cli.rollup('--environment format:tsc');
  log.log('src');
}

async function compileTests() {
  timer.start('tests');
  await cli.tsc(true);
  timer.stop('tests').log('tests');
}

async function test() {
  timer.start('test');
  await cli.test();
  timer.stop('test');

  if (cov) {
    timer.start('cov');
    await cli.cov();
    timer.stop('cov');
  }
}

const devWith = opts => Object.assign({
  format: 'umd',
  verbose: true,
  env: 'development',
  development: true,
  production: false,
  uglify: false
}, opts);

const prodWith = opts => Object.assign({
  falafel: true,
  env: 'production',
  development: false,
  production: true,
  debug: false,
  uglify: true,
  replace: true
}, opts); // @NOTE this is how rollup can be done with cli flags instead of node api
// await cli.rollup('--environment format:umd --verbose --debug')


async function publishing() {
  const rollupProdWith = opts => cli.rollupNode(prodWith(opts));

  const rollupDevWith = opts => cli.rollupNode(devWith(opts));

  let prodBuilds = [{
    format: 'amd',
    falafel: false
  }, {
    format: 'es'
  }, {
    format: 'cjs'
  }, {
    format: 'iife',
    falafel: false
  }, // @HACK @FIXME just needs sourceType script
  {
    format: 'umd',
    verbose: true,
    debug: false
  }];
  let devBuilds = [{
    exportName: 'debugger',
    debugger: true,
    debug: true,
    replace: {
      debugger: true
    }
  }, {
    exportName: 'window',
    entry: res('../src/index.web.js')
  }, {
    exportName: 'dev'
  }, {
    exportName: 'node'
  }]; // @NOTE quick, just build one

  if (quick) {
    log.bold('quick').echo();
    prodBuilds = prodBuilds.slice(prodBuilds.length - 2);
    devBuilds = [];
  }

  let devOps = devBuilds.map(dev => rollupDevWith(dev));
  let prodOps = prodBuilds.map(prod => rollupProdWith(prod));
  let builds = [].concat(devOps).concat(prodOps);
  const built = await Promise.all(builds);
  return Promise.resolve(built);
}

async function all() {
  timer.start('cli');

  if (cleaneasyexports) {
    await cli.cleanEasyExports();
    process.exit();
  }

  if (easyexports) {
    await cli.lintEasyExports();
    process.exit();
  }

  if (docs) {
    await cli.docs();
    process.exit();
  }

  if (doctrine) {
    await cli.doctrine();
    process.exit();
  }

  if (!quick) {
    await src();
  } // is not really needed now with jest, but should add back tsc
  // if (tests) {
  //   await compileTests()
  //   await test()
  // }


  if (production) await publishing();
  await cli.optimizejs(); // if (cov) await runCov()
  // all ops are done

  timer.stop('cli').log('cli');
}

all();