all files / lib/ url.js

100% Statements 53/53
95% Branches 19/20
100% Functions 8/8
100% Lines 36/36
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145                                         91× 91×   91×       20×     71×   80×   80× 80×     80×   80× 79×   79× 79×           70×                     79×                                               150×   92×         16×             150×                   150× 150×                                        
import moment from 'moment';
import slug from 'slug';
import path from 'path';
 
/**
 * Are we running within a dist build (i.e. pre-compiled)?
 * @type {boolean} True if we're running in the dist folder.
 */
const isDistBuild = __dirname.indexOf('dist') > -1;
 
// Cached slug options.
let slugOptions;
 
const Url = {
  /**
   * Interpolates variables into a permalink structure.
   * @example
   * // returns '/hello-world/'
   * interpolatePermalink('/:title/', {
   *   title: 'hello-world'
   * });
   * @param {string} permalink A permalink template.
   * @param {Object} context An object with keys that if matched to the
   *   permalink will have the value interpolated to the string.
   * @return {string} Actual permalink value.
   */
  interpolatePermalink(permalink, context) {
    const PERMALINK_REGEX = /:(\w+[\|A-Z]*)/g;
 
    let params = permalink.match(PERMALINK_REGEX);
 
    // If we found no tags in the permalink then just return the given string.
    if (!params) {
      return permalink;
    }
 
    params.forEach(param => {
      // Replace ':title' -> 'title'.
      let paramKey = param.substr(1);
 
      let paramPipe;
      if (paramKey.includes('|')) {
        [paramKey, paramPipe] = paramKey.split('|');
      }
 
      let paramValue = context[paramKey];
 
      if (paramValue) {
        if (paramPipe) {
          paramValue = moment(paramValue).format(paramPipe);
        }
        var sanitized = Url.slug(paramValue);
        permalink = permalink.replace(param, sanitized);
      } else {
        throw new Error('interpolatePermalink: could not find param value ' +
          'for key: ' + paramKey);
      }
    });
 
    return permalink;
  },
 
  /**
   * Wrapper around the slug module. Handles taking a string and making it
   * into a slug, a URL safe string.
   * @param {string} str String to slugify.
   * @param {Object} options Slug options.
   * @return {string} Slugified string.
   */
  slug(str, options) {
    return slug(str, {
      ...slugOptions,
      options,
    });
  },
 
  /**
   * Set slug options to be used by Url.slug.
   * @param {Object} options Options
   */
  setSlugOptions(options) {
    slugOptions = options;
  },
 
  /**
   * When writing to the file system update the permalink so that it renders
   * correctly.
   * @example
   * // returns '/hello-world/index.html'
   * Url.makeUrlFileSystemSafe('/hello-world');
   * @param {string} url Url to make file system safe.
   * @return {string} Safe url.
   */
  makeUrlFileSystemSafe(url) {
    // If the url does not end with an extension then we need to modify the URL.
    if (!path.extname(url)) {
      // If we don't have a leading / then add it.
      if (!url.startsWith('/')) {
        url = '/' + url;
      }
 
      // If we don't have a trailing / then add it.
      if (!url.endsWith('/')) {
        url += '/';
      }
 
      // Append the default file name.
      url += 'index.html';
    }
 
    return url;
  },
 
  /**
   * Given a URL that ends with 'index.html' it'll strip it off and return the
   * resulting value. Useful when creating URLs in a template.
   * @param {string} url Url to augment.
   * @return {string} Augmented url.
   */
  makePretty(url) {
    const makePrettyRegEx = /\/index.html$/;
    return url.replace(makePrettyRegEx, '/');
  },
 
  /**
   * Resolve a path from the root of the Yarn project, taking into account
   * the relative depth we need to go to get to the root of the Yarn project,
   * depending if we're in a pre-compiled build or not.
   * @param {...string} args Splat of strings.
   * @return {string} Full path.
   */
  pathFromRoot(...args) {
    // Push relative distance from root of project.
    args.unshift(
      isDistBuild ? '../../' : '../'
    );
 
    // Add dirname relative from.
    args.unshift(__dirname);
 
    return path.resolve.apply(path, args);
  },
};
 
export default Url;