1'use strict';
2
3const _ = require('lodash');
4const async = require('async');
5const glob = require('glob');
6const path = require('path');
7
8const file = require('../common/file');
9const mapping = require('../common/mapping');
10const util = require('../common/util');
11
12const templatePath = path.join(__dirname, 'template/modules');
13const template = file.globTemplate(path.join(templatePath, '*.jst'));
14
15const aryMethods = _.union(
16  mapping.aryMethod[1],
17  mapping.aryMethod[2],
18  mapping.aryMethod[3],
19  mapping.aryMethod[4]
20);
21
22const categories = [
23  'array',
24  'collection',
25  'date',
26  'function',
27  'lang',
28  'math',
29  'number',
30  'object',
31  'seq',
32  'string',
33  'util'
34];
35
36const ignored = [
37  '_*.js',
38  'core.js',
39  'core.min.js',
40  'fp.js',
41  'index.js',
42  'lodash.js',
43  'lodash.min.js'
44];
45
46/**
47 * Checks if `name` is a method alias.
48 *
49 * @private
50 * @param {string} name The name to check.
51 * @returns {boolean} Returns `true` if `name` is a method alias, else `false`.
52 */
53function isAlias(name) {
54  return _.has(mapping.aliasToReal, name);
55}
56
57/**
58 * Checks if `name` is a category name.
59 *
60 * @private
61 * @param {string} name The name to check.
62 * @returns {boolean} Returns `true` if `name` is a category name, else `false`.
63 */
64function isCategory(name) {
65  return _.includes(categories, name);
66}
67
68/**
69 * Checks if `name` belongs to a method that's passed thru and not wrapped.
70 *
71 * @private
72 * @param {string} name The name to check.
73 * @returns {boolean} Returns `true` if `name` is of a pass thru method,
74 *  else `false`.
75 */
76function isThru(name) {
77  return !_.includes(aryMethods, name);
78}
79
80/**
81 * Gets metadata for `func`.
82 *
83 * @private
84 * @param {Function} func The function to query.
85 * @returns {*} Returns the metadata for `func`.
86 */
87function getTemplate(moduleName) {
88  const data = {
89    'name': _.get(mapping.aliasToReal, moduleName, moduleName),
90    'mapping': mapping
91  };
92
93  if (isAlias(moduleName)) {
94    return template.alias(data);
95  }
96  if (isCategory(moduleName)) {
97    return template.category(data);
98  }
99  if (isThru(moduleName)) {
100    return template.thru(data);
101  }
102  return template.module(data);
103}
104
105/*----------------------------------------------------------------------------*/
106
107/**
108 * Creates FP modules at the `target` path.
109 *
110 * @private
111 * @param {string} target The output directory path.
112 */
113function build(target) {
114  target = path.resolve(target);
115
116  const fpPath = path.join(target, 'fp');
117
118  // Glob existing lodash module paths.
119  const modulePaths = glob.sync(path.join(target, '*.js'), {
120    'nodir': true,
121    'ignore': ignored.map(filename => {
122      return path.join(target, filename);
123    })
124  });
125
126  // Add FP alias and remapped module paths.
127  _.each([mapping.aliasToReal, mapping.remap], data => {
128    _.forOwn(data, (realName, alias) => {
129      const modulePath = path.join(target, alias + '.js');
130      if (!_.includes(modulePaths, modulePath)) {
131        modulePaths.push(modulePath);
132      }
133    });
134  });
135
136  const actions = modulePaths.map(modulePath => {
137    const moduleName = path.basename(modulePath, '.js');
138    return file.write(path.join(fpPath, moduleName + '.js'), getTemplate(moduleName));
139  });
140
141  actions.unshift(file.copy(path.join(__dirname, '../../fp'), fpPath));
142  actions.push(file.write(path.join(fpPath, '_falseOptions.js'), template._falseOptions()));
143  actions.push(file.write(path.join(fpPath, '_util.js'), template._util()));
144  actions.push(file.write(path.join(target, 'fp.js'), template.fp()));
145  actions.push(file.write(path.join(fpPath, 'convert.js'), template.convert()));
146
147  async.series(actions, util.pitch);
148}
149
150build(_.last(process.argv));
151