/**
 * Copyright © 2019 Johnson & Johnson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
};
import path from 'path';
import fs from 'fs-extra';
import walkdir from 'walkdir';
import flow from 'lodash/flow';
import { treeHOPromiseFlow } from './promiseUtils';
// A function for setting a value deep in a Tree
/**
 * withDeepValue returns a TreeHO that will change a value deep in the tree that it accepts
 * @param key An array of keys to walk in the Tree.
 * @param value The value to set when you have walk all keys.
 */
export var withDeepValue = function (key, value) { return function (tree) {
    var _a, _b, _c;
    var keys = typeof key === 'string' ? [key] : key;
    if (keys.length === 1) {
        return __assign(__assign({}, tree), (_a = {}, _a[keys[0]] = value, _a));
    }
    var first = keys[0], rest = keys.slice(1);
    if (Object.keys(tree).includes(first)) {
        var subTree = tree[first];
        return __assign(__assign({}, tree), (_b = {}, _b[first] = withDeepValue(rest, value)(subTree), _b));
    }
    return __assign(__assign({}, tree), (_c = {}, _c[first] = withDeepValue(rest, value)({}), _c));
}; };
/**
 * getTreeFromDir returns a promise that will walk a directory and resolve to
 * an TreeHO that describes that directory
 * @param startDir
 */
export var getTreeFromDir = function (startDir) { return (new Promise(function (resolve) {
    var updates = [];
    var walker = walkdir(startDir, { follow_symlinks: true });
    walker.on('file', function (filePath) {
        var keys = path.relative(startDir, filePath).split(path.sep);
        updates.push(withDeepValue(keys, filePath));
    });
    walker.on('end', function () {
        resolve(flow.apply(void 0, updates));
    });
})); };
/**
 * PrePendPath take a path and returns a treeHO that will walk though a passed in Tree
 * and prepend the path to every docuement in the tree.
 * @param prePend
 */
export var prependPath = function (prePend) { return function (tree) { return (Object.keys(tree).reduce(function (acc, key) {
    var _a, _b;
    if (typeof tree[key] === 'string') {
        return __assign((_a = {}, _a[key] = path.join(prePend, tree[key]), _a), acc);
    }
    var subTree = prependPath(prePend)(tree[key]);
    return __assign((_b = {}, _b[key] = subTree, _b), acc);
}, {})); }; };
/**
 * withTree returns a TreeHO that will merge the tree pass to withTree with the Tree
 * passed in to the TreeHO.  The main value is to resolve issue around directory vs files
 * @param newTree
 */
export var withTree = function (newTree) { return function (tree) { return (Object.keys(newTree).reduce(function (acc, key) {
    var _a, _b, _c, _d, _e;
    // Add a obj if we do not have a current location that matches the key.
    // If we are adding on object but currently we have a string then we need to move the current
    // item to README.md.
    if (typeof newTree[key] === 'object' && typeof tree[key] === 'string') {
        var indexPath = tree[key];
        return __assign(__assign({}, acc), (_a = {}, _a[key] = withTree(newTree[key])({ 'README.md': indexPath }), _a));
    }
    if (typeof newTree[key] === 'object' && typeof tree[key] === 'object') {
        return __assign(__assign({}, acc), (_b = {}, _b[key] = withTree(newTree[key])(tree[key]), _b));
    }
    if (typeof newTree[key] === 'object' && typeof tree[key] === 'undefined') {
        return __assign(__assign({}, acc), (_c = {}, _c[key] = newTree[key], _c));
    }
    if (typeof newTree[key] === 'string' && typeof tree[key] === 'object') {
        return __assign(__assign({}, acc), (_d = {}, _d[key] = withTree({ 'README.md': newTree[key] })(tree[key]), _d));
    }
    return __assign(__assign({}, acc), (_e = {}, _e[key] = newTree[key], _e));
}, tree)); }; };
/**
 * WithTreeFromFile returns a Promise, that will Read and parse a json file, and resolve to a
 * TreeHO that was described by the Json file.
 * @param filePath
 */
export var withTreeFromFile = function (filePath) {
    var dirPath = path.dirname(filePath);
    return fs.readJson(filePath)
        .then(function (fileJSON) {
        var _dir = fileJSON._dir, rawTree = __rest(fileJSON, ["_dir"]);
        var updateTree = withTree(prependPath(dirPath)(rawTree));
        if (_dir) {
            var docPath = path.join(dirPath, _dir);
            var promises = [
                Promise.resolve(updateTree),
                getTreeFromDir(docPath),
            ];
            return treeHOPromiseFlow.apply(void 0, promises);
        }
        return updateTree;
    });
};
/**
 * getSipmlePaths returns a simple list of paths gathered from a nested tree.
 * @param tree
 */
export var getSimplePaths = function (tree) {
    var simplePathsList = [];
    var walkTree = function (tree1) {
        Object.keys(tree1).forEach(function (key) {
            var branch = tree1[key];
            if (typeof branch === 'object') {
                walkTree(branch);
            }
            else {
                simplePathsList.push(branch);
            }
        });
    };
    walkTree(tree);
    return simplePathsList;
};
/**
 * validatePaths checks whether the passed paths are equal to their native
 * counterparts in the file system.
 * This check is needed when we want to be sure to get the same build results
 * on MacOS (case-insensitive) and Linux (case-sensitive).
 * https://stackoverflow.com/questions/13617863/can-i-force-node-js-require-to-be-case-sensitive
 * @param pathsToDocs
 */
export var validatePaths = function (pathsToDocs) {
    pathsToDocs.forEach(function (pathToDoc) {
        var defaultPath = path.resolve(pathToDoc);
        var nativePath = fs.realpathSync.native(defaultPath);
        if (defaultPath !== nativePath) {
            var errorMessage = "\n        The file path specified in docs.json is not equal to the real file path.\n        ".concat(defaultPath, "\n        !==\n        ").concat(nativePath, "\n        Make sure the path is case-sensitively correct.\n      ");
            throw new Error(errorMessage);
        }
    });
};
//# sourceMappingURL=tree.js.map