/*!
 * @nuxt/cli v2.16.0 (c) 2016-2023
 * Released under the MIT License
 * Repository: https://github.com/nuxt/nuxt.js
 * Website: https://nuxtjs.org
*/
'use strict';

const utils = require('@nuxt/utils');
const consola = require('consola');
const index = require('./cli-index.js');
const path = require('path');
const upath = require('upath');
const fs = require('fs-extra');
const crc32 = require('crc/crc32');
const globby = require('globby');
const destr = require('destr');
require('@nuxt/config');
require('exit');
require('chalk');
require('std-env');
require('wrap-ansi');
require('boxen');
require('minimist');
require('hable');
require('defu');
require('semver');
require('fs');
require('execa');

async function generate$1(cmd) {
  const nuxt = await getNuxt({ server: true }, cmd);
  const generator = await cmd.getGenerator(nuxt);
  await nuxt.server.listen(0);
  const { errors } = await generator.generate({ build: false });
  await nuxt.close();
  if (cmd.argv["fail-on-error"] && errors.length > 0) {
    throw new Error("Error generating pages, exiting with non-zero code");
  }
}
async function ensureBuild(cmd) {
  const nuxt = await getNuxt({ _build: true, server: false }, cmd);
  const { options } = nuxt;
  if (options.generate.cache === false || destr(process.env.NUXT_BUILD) || cmd.argv["force-build"]) {
    const builder2 = await cmd.getBuilder(nuxt);
    await builder2.build();
    await nuxt.close();
    return;
  }
  const ignore = [
    options.buildDir,
    options.dir.static,
    options.generate.dir,
    "node_modules",
    ".**/*",
    ".*",
    "README.md"
  ];
  const { generate: generate2 } = options;
  if (typeof generate2.cache.ignore === "function") {
    generate2.cache.ignore = generate2.cache.ignore(ignore);
  } else if (Array.isArray(generate2.cache.ignore)) {
    generate2.cache.ignore = generate2.cache.ignore.concat(ignore);
  }
  await nuxt.callHook("generate:cache:ignore", generate2.cache.ignore);
  const snapshotOptions = {
    rootDir: options.rootDir,
    ignore: generate2.cache.ignore.map(upath.normalize),
    globbyOptions: generate2.cache.globbyOptions
  };
  const currentBuildSnapshot = await snapshot(snapshotOptions);
  const processEnv = {};
  if (nuxt.options._nuxtConfigFile) {
    const configSrc = await fs.readFile(nuxt.options._nuxtConfigFile);
    const envRegex = /process.env.(\w+)/g;
    let match;
    while (match = envRegex.exec(configSrc)) {
      processEnv[match[1]] = process.env[match[1]];
    }
  }
  const currentBuild = {
    // @ts-ignore
    nuxtVersion: nuxt.constructor.version,
    ssr: nuxt.options.ssr,
    target: nuxt.options.target,
    snapshot: currentBuildSnapshot,
    env: nuxt.options.env,
    "process.env": processEnv
  };
  const nuxtBuildFile = path.resolve(nuxt.options.buildDir, "build.json");
  if (fs.existsSync(nuxtBuildFile)) {
    const previousBuild = destr(fs.readFileSync(nuxtBuildFile, "utf-8")) || {};
    let needBuild = false;
    const fields = ["nuxtVersion", "ssr", "target"];
    if (nuxt.options.generate.ignoreEnv !== true) {
      fields.push("env", "process.env");
    }
    for (const field of fields) {
      if (JSON.stringify(previousBuild[field]) !== JSON.stringify(currentBuild[field])) {
        needBuild = true;
        consola.info(`Doing webpack rebuild because ${field} changed`);
        break;
      }
    }
    if (!needBuild) {
      const changed = compareSnapshots(previousBuild.snapshot, currentBuild.snapshot);
      if (!changed) {
        consola.success("Skipping webpack build as no changes detected");
        await nuxt.close();
        return;
      } else {
        consola.info(`Doing webpack rebuild because ${changed} modified`);
      }
    }
  }
  const builder = await cmd.getBuilder(nuxt);
  await builder.build();
  fs.writeFileSync(nuxtBuildFile, JSON.stringify(currentBuild, null, 2), "utf-8");
  await nuxt.close();
}
async function getNuxt(args, cmd) {
  const config = await cmd.getNuxtConfig({ dev: false, ...args });
  if (config.target === utils.TARGETS.static) {
    config._export = true;
  } else {
    config._legacyGenerate = true;
  }
  config.buildDir = config.static && config.static.cacheDir || path.resolve(config.rootDir, "node_modules/.cache/nuxt");
  config.build = config.build || {};
  config.build.parallel = false;
  config.build.transpile = config.build.transpile || [];
  if (!config.static || !config.static.cacheDir) {
    config.build.transpile.push(".cache/nuxt");
  }
  const nuxt = await cmd.getNuxt(config);
  return nuxt;
}
function compareSnapshots(from, to) {
  const allKeys = Array.from(/* @__PURE__ */ new Set([
    ...Object.keys(from).sort(),
    ...Object.keys(to).sort()
  ]));
  for (const key of allKeys) {
    if (JSON.stringify(from[key]) !== JSON.stringify(to[key])) {
      return key;
    }
  }
  return false;
}
async function snapshot({ globbyOptions, ignore, rootDir }) {
  const snapshot2 = {};
  const files = await globby("**/*.*", {
    ...globbyOptions,
    ignore,
    cwd: rootDir,
    absolute: true
  });
  await Promise.all(files.map(async (p) => {
    const key = path.relative(rootDir, p);
    try {
      const fileContent = await fs.readFile(p);
      snapshot2[key] = {
        checksum: await crc32(fileContent).toString(16)
      };
    } catch (e) {
      snapshot2[key] = {
        exists: false
      };
    }
  }));
  return snapshot2;
}

const generate = {
  name: "generate",
  description: "Generate a static web application (server-rendered)",
  usage: "generate <dir>",
  options: {
    ...index.common,
    ...index.locking,
    build: {
      type: "boolean",
      default: true,
      description: "Only generate pages for dynamic routes, used for incremental builds. Generate has to be run once without this option before using it"
    },
    devtools: {
      type: "boolean",
      default: false,
      description: "Enable Vue devtools",
      prepare(cmd, options, argv) {
        options.vue = options.vue || {};
        options.vue.config = options.vue.config || {};
        if (argv.devtools) {
          options.vue.config.devtools = true;
        }
      }
    },
    quiet: {
      alias: "q",
      type: "boolean",
      description: "Disable output except for errors",
      prepare(cmd, options, argv) {
        options.build = options.build || {};
        if (argv.quiet) {
          options.build.quiet = true;
        }
      }
    },
    modern: {
      ...index.common.modern,
      description: "Generate app in modern build (modern mode can be only client)",
      prepare(cmd, options, argv) {
        if (index.normalizeArg(argv.modern)) {
          options.modern = "client";
        }
      }
    },
    "force-build": {
      type: "boolean",
      default: false,
      description: "Force to build the application with webpack"
    },
    "fail-on-error": {
      type: "boolean",
      default: false,
      description: "Exit with non-zero status code if there are errors when generating pages"
    }
  },
  async run(cmd) {
    const config = await cmd.getNuxtConfig({ dev: false });
    config.build = config.build || {};
    config.build.analyze = false;
    if (config.target === utils.TARGETS.static) {
      await ensureBuild(cmd);
      await generate$1(cmd);
      return;
    }
    config.target = utils.TARGETS.static;
    consola.warn(`When using \`nuxt generate\`, you should set \`target: 'static'\` in your \`nuxt.config\`
       \u{1F449} Learn more about it on https://go.nuxtjs.dev/static-target`);
    config._legacyGenerate = true;
    if (config.build) {
      config.build.parallel = false;
    }
    const nuxt = await cmd.getNuxt(config);
    if (cmd.argv.lock) {
      await cmd.setLock(await index.createLock({
        id: "build",
        dir: nuxt.options.buildDir,
        root: config.rootDir
      }));
      nuxt.hook("build:done", async () => {
        await cmd.releaseLock();
        await cmd.setLock(await index.createLock({
          id: "generate",
          dir: nuxt.options.generate.dir,
          root: config.rootDir
        }));
      });
    }
    const generator = await cmd.getGenerator(nuxt);
    await nuxt.server.listen(0);
    const { errors } = await generator.generate({
      init: true,
      build: cmd.argv.build
    });
    await nuxt.close();
    if (cmd.argv["fail-on-error"] && errors.length > 0) {
      throw new Error("Error generating pages, exiting with non-zero code");
    }
  }
};

exports.default = generate;
