text: "use strict";
  
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  
  exports.__esModule = true;
  exports.default = buildHeadersProgram;
  
  var _lodash = _interopRequireDefault(require("lodash"));
  
  var _fsExtra = require("fs-extra");
  
  var _path = require("path");
  
  var _kebabHash = _interopRequireDefault(require("kebab-hash"));
  
  var _constants = require("./constants");
  
  function getHeaderName(header) {
    const matches = header.match(/^([^:]+):/);
    return matches && matches[1];
  }
  
  function validHeaders(headers, reporter) {
    if (!headers || !_lodash.default.isObject(headers)) {
      return false;
    }
  
    return _lodash.default.every(headers, (headersList, path) => _lodash.default.isArray(headersList) && _lodash.default.every(headersList, header => {
      if (_lodash.default.isString(header)) {
        if (!getHeaderName(header)) {
          // TODO panic on builds on v3
          reporter.warn(`[gatsby-plugin-netlify] ${path} contains an invalid header (${header}). Please check your plugin configuration`);
        }
  
        return true;
      }
  
      return false;
    }));
  }
  
  function linkTemplate(assetPath, type = `script`) {
    return `Link: <${assetPath}>; rel=preload; as=${type}`;
  }
  
  function pathChunkName(path) {
    const name = path === `/` ? `index` : (0, _kebabHash.default)(path);
    return `path---${name}`;
  }
  
  function createScriptHeaderGenerator(manifest, pathPrefix) {
    return script => {
      const chunk = manifest[script];
  
      if (!chunk) {
        return null;
      } // convert to array if it's not already
  
  
      const chunks = _lodash.default.isArray(chunk) ? chunk : [chunk];
      return chunks.filter(script => {
        const parsed = (0, _path.parse)(script); // handle only .js, .css content is inlined already
        // and doesn't need to be pushed
  
        return parsed.ext === `.js`;
      }).map(script => linkTemplate(`${pathPrefix}/${script}`)).join(`\n  `);
    };
  }
  
  function linkHeaders(scripts, manifest, pathPrefix) {
    return _lodash.default.compact(scripts.map(createScriptHeaderGenerator(manifest, pathPrefix)));
  }
  
  function headersPath(pathPrefix, path) {
    return `${pathPrefix}${path}`;
  }
  
  function preloadHeadersByPage(pages, manifest, pathPrefix) {
    let linksByPage = {};
    pages.forEach(page => {
      const scripts = [..._constants.COMMON_BUNDLES, pathChunkName(page.path), page.componentChunkName];
      const pathKey = headersPath(pathPrefix, page.path);
      linksByPage[pathKey] = linkHeaders(scripts, manifest, pathPrefix);
    });
    return linksByPage;
  }
  
  function defaultMerge(...headers) {
    function unionMerge(objValue, srcValue) {
      if (_lodash.default.isArray(objValue)) {
        return _lodash.default.union(objValue, srcValue);
      } else {
        return undefined; // opt into default merge behavior
      }
    }
  
    return _lodash.default.mergeWith({}, ...headers, unionMerge);
  }
  
  function headersMerge(userHeaders, defaultHeaders) {
    const merged = {};
    Object.keys(defaultHeaders).forEach(path => {
      if (!userHeaders[path]) {
        merged[path] = defaultHeaders[path];
        return;
      }
  
      const headersMap = {};
      defaultHeaders[path].forEach(header => {
        headersMap[getHeaderName(header)] = header;
      });
      userHeaders[path].forEach(header => {
        headersMap[getHeaderName(header)] = header; // override if exists
      });
      merged[path] = Object.values(headersMap);
    });
    Object.keys(userHeaders).forEach(path => {
      if (!merged[path]) {
        merged[path] = userHeaders[path];
      }
    });
    return merged;
  }
  
  function transformLink(manifest, publicFolder, pathPrefix) {
    return header => header.replace(_constants.LINK_REGEX, (__, prefix, file, suffix) => {
      const hashed = manifest[file];
  
      if (hashed) {
        return `${prefix}${pathPrefix}${hashed}${suffix}`;
      } else if ((0, _fsExtra.existsSync)(publicFolder(file))) {
        return `${prefix}${pathPrefix}${file}${suffix}`;
      } else {
        throw new Error(`Could not find the file specified in the Link header \`${header}\`.` + `The gatsby-plugin-netlify is looking for a matching file (with or without a ` + `webpack hash). Check the public folder and your gatsby-config.js to ensure you are ` + `pointing to a public file.`);
      }
    });
  } // Writes out headers file format, with two spaces for indentation
  // https://www.netlify.com/docs/headers-and-basic-auth/
  
  
  function stringifyHeaders(headers) {
    return _lodash.default.reduce(headers, (text, headerList, path) => {
      const headersString = _lodash.default.reduce(headerList, (accum, header) => `${accum}  ${header}\n`, ``);
  
      return `${text}${path}\n${headersString}`;
    }, ``);
  } // program methods
  
  
  const validateUserOptions = (pluginOptions, reporter) => headers => {
    if (!validHeaders(headers, reporter)) {
      throw new Error(`The "headers" option to gatsby-plugin-netlify is in the wrong shape. ` + `You should pass in a object with string keys (representing the paths) and an array ` + `of strings as the value (representing the headers). ` + `Check your gatsby-config.js.`);
    }
  
    ;
    [`mergeSecurityHeaders`, `mergeLinkHeaders`, `mergeCachingHeaders`].forEach(mergeOption => {
      if (!_lodash.default.isBoolean(pluginOptions[mergeOption])) {
        throw new Error(`The "${mergeOption}" option to gatsby-plugin-netlify must be a boolean. ` + `Check your gatsby-config.js.`);
      }
    });
  
    if (!_lodash.default.isFunction(pluginOptions.transformHeaders)) {
      throw new Error(`The "transformHeaders" option to gatsby-plugin-netlify must be a function ` + `that returns a array of header strings.` + `Check your gatsby-config.js.`);
    }
  
    return headers;
  };
  
  const mapUserLinkHeaders = ({
    manifest,
    pathPrefix,
    publicFolder
  }) => headers => _lodash.default.mapValues(headers, headerList => _lodash.default.map(headerList, transformLink(manifest, publicFolder, pathPrefix)));
  
  const mapUserLinkAllPageHeaders = (pluginData, {
    allPageHeaders
  }) => headers => {
    if (!allPageHeaders) {
      return headers;
    }
  
    const {
      pages,
      manifest,
      publicFolder,
      pathPrefix
    } = pluginData;
  
    const headersList = _lodash.default.map(allPageHeaders, transformLink(manifest, publicFolder, pathPrefix));
  
    const duplicateHeadersByPage = {};
    pages.forEach(page => {
      const pathKey = headersPath(pathPrefix, page.path);
      duplicateHeadersByPage[pathKey] = headersList;
    });
    return defaultMerge(headers, duplicateHeadersByPage);
  };
  
  const applyLinkHeaders = (pluginData, {
    mergeLinkHeaders
  }) => headers => {
    if (!mergeLinkHeaders) {
      return headers;
    }
  
    const {
      pages,
      manifest,
      pathPrefix
    } = pluginData;
    const perPageHeaders = preloadHeadersByPage(pages, manifest, pathPrefix);
    return defaultMerge(headers, perPageHeaders);
  };
  
  const applySecurityHeaders = ({
    mergeSecurityHeaders
  }) => headers => {
    if (!mergeSecurityHeaders) {
      return headers;
    }
  
    return headersMerge(headers, _constants.SECURITY_HEADERS);
  };
  
  const applyCachingHeaders = (pluginData, {
    mergeCachingHeaders
  }) => headers => {
    if (!mergeCachingHeaders) {
      return headers;
    }
  
    const chunks = Array.from(pluginData.pages.values()).map(page => page.componentChunkName);
    chunks.push(`pages-manifest`, `app`);
    const files = [].concat(...chunks.map(chunk => pluginData.manifest[chunk]));
    const cachingHeaders = {};
    files.forEach(file => {
      cachingHeaders[`/` + file] = [_constants.IMMUTABLE_CACHING_HEADER];
    });
    return defaultMerge(headers, cachingHeaders, _constants.CACHING_HEADERS);
  };
  
  const applyTransfromHeaders = ({
    transformHeaders
  }) => headers => _lodash.default.mapValues(headers, transformHeaders);
  
  const transformToString = headers => `${_constants.HEADER_COMMENT}\n\n${stringifyHeaders(headers)}`;
  
  const writeHeadersFile = ({
    publicFolder
  }) => contents => (0, _fsExtra.writeFile)(publicFolder(_constants.NETLIFY_HEADERS_FILENAME), contents);
  
  function buildHeadersProgram(pluginData, pluginOptions, reporter) {
    return _lodash.default.flow(validateUserOptions(pluginOptions, reporter), mapUserLinkHeaders(pluginData), applySecurityHeaders(pluginOptions), applyCachingHeaders(pluginData, pluginOptions), mapUserLinkAllPageHeaders(pluginData, pluginOptions), applyLinkHeaders(pluginData, pluginOptions), applyTransfromHeaders(pluginOptions), transformToString, writeHeadersFile(pluginData))(pluginOptions.headers);
  }