@staticbolt/core 1.0.0-beta.3 → 1.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- export { };
1
+ export {}
package/lib/cli/index.mjs CHANGED
@@ -1,21 +1,9 @@
1
- #!/usr/bin/env -S node --experimental-vm-modules --no-warnings
2
- import { f as join, r as CONFIG_FILE_NAME, t as Log, u as isAbsolute, y as resolve } from "../logger-BuxMGhij.mjs";
1
+ #!/usr/bin/env node
2
+ import { c as isAbsolute, d as join, r as Log, t as CONFIG_FILE_NAME, v as resolve } from "../common-DUFKS3lW.mjs";
3
+ import { t as loadConfigFile } from "../load-config-D-FtbUws.mjs";
3
4
  import * as z from "zod";
4
- import { parseArgs } from "node:util";
5
5
  import { coerce, defineArguments, defineCLI, defineOptions, defineSubcommand } from "@staticbolt/args-parser";
6
6
 
7
- //#region src/helpers/load-config.ts
8
- async function loadConfigFile(configPath) {
9
- try {
10
- const loadedConfig = await import(configPath + `?update=${Date.now()}`);
11
- if (!loadedConfig.default) return [null, /* @__PURE__ */ new Error(`Failed to load config file at "${configPath}"`)];
12
- return [loadedConfig.default, null];
13
- } catch (error) {
14
- return [null, error];
15
- }
16
- }
17
-
18
- //#endregion
19
7
  //#region src/cli/commands/help.ts
20
8
  const helpCommand = defineSubcommand({
21
9
  name: "help",
@@ -49,6 +37,20 @@ var CliProgram = class CliProgram {
49
37
  example: "staticbolt build \nstaticbolt serve"
50
38
  },
51
39
  options: {
40
+ cwd: {
41
+ schema: z.string().optional(),
42
+ meta: {
43
+ placeholder: "<directory>",
44
+ description: "The directory to run in. Works with every command."
45
+ }
46
+ },
47
+ config: {
48
+ schema: z.string().optional(),
49
+ meta: {
50
+ placeholder: "<path>",
51
+ description: `The config file, relative to the directory. Works with every command. Defaults to "${CONFIG_FILE_NAME}".`
52
+ }
53
+ },
52
54
  help: {
53
55
  aliases: ["h"],
54
56
  schema: z.boolean().optional(),
@@ -77,16 +79,19 @@ var CliProgram = class CliProgram {
77
79
  console.log("v0.0.0");
78
80
  return;
79
81
  }
80
- console.error("No arguments provided. Use `static --help` for more information");
82
+ console.error("No arguments provided. Use `staticbolt --help` for more information");
81
83
  });
82
84
  }
83
- async initializePlugins(config, configPath) {
85
+ async initializePlugins(config, configPath, projectDirectory) {
84
86
  const plugins = config.plugins ?? [];
85
- for (const pluginOrPlugins of plugins) for (const plugin of Array.isArray(pluginOrPlugins) ? pluginOrPlugins : [pluginOrPlugins]) if (plugin.cli) await plugin.cli.call(this, config, configPath);
87
+ for (const pluginOrPlugins of plugins) {
88
+ const pluginsAsArray = Array.isArray(pluginOrPlugins) ? pluginOrPlugins : [pluginOrPlugins];
89
+ for (const plugin of pluginsAsArray) if (plugin.cli) await plugin.cli.call(this, config, configPath, projectDirectory);
90
+ }
86
91
  }
87
- static async init(config, configPath) {
92
+ static async init(config, configPath, projectDirectory) {
88
93
  const cliProgram = new CliProgram();
89
- await cliProgram.initializePlugins(config, configPath);
94
+ await cliProgram.initializePlugins(config, configPath, projectDirectory);
90
95
  return cliProgram;
91
96
  }
92
97
  run(cliArguments) {
@@ -101,7 +106,8 @@ var CliProgram = class CliProgram {
101
106
  this.#programWideType.subcommands = [newSubcommand];
102
107
  return;
103
108
  }
104
- return this.#programWideType.subcommands.push(newSubcommand);
109
+ this.#programWideType.subcommands.push(newSubcommand);
110
+ return this.#programWideType.subcommands.length;
105
111
  }
106
112
  addOptions(newOptions) {
107
113
  if (!this.#programWideType.options) {
@@ -145,32 +151,37 @@ var CliProgram = class CliProgram {
145
151
 
146
152
  //#endregion
147
153
  //#region src/cli/index.ts
148
- const { values } = parseArgs({
149
- options: {
150
- cwd: { type: "string" },
151
- config: { type: "string" }
152
- },
153
- allowPositionals: true,
154
- strict: false
155
- });
156
- const inputCwd = values.cwd ?? process.cwd();
157
- const inputConfigPath = values.config ?? ".staticbolt.ts";
158
- const projectDirectory = resolve(inputCwd);
159
- const configPath = isAbsolute(inputConfigPath) ? inputConfigPath : join(projectDirectory, inputConfigPath);
160
- const [loadedConfig, configError] = await loadConfigFile(configPath);
154
+ const cliArguments = process.argv.slice(2);
155
+ const projectDirectory = resolve(takeOption(cliArguments, "cwd") ?? process.cwd());
156
+ const configFile = takeOption(cliArguments, "config") ?? ".staticbolt.ts";
157
+ const configPath = isAbsolute(configFile) ? configFile : join(projectDirectory, configFile);
158
+ const [config, configError] = await loadConfigFile(configPath, projectDirectory);
161
159
  if (configError) {
162
- Log.warn(`Failed to load config file at "${configPath}"`);
160
+ Log.error(`Failed to load config file at "${configPath}"`);
163
161
  throw configError;
164
162
  }
165
- const config = loadedConfig ?? {};
166
- if (config.root && !isAbsolute(config.root)) config.root = join(projectDirectory, config.root);
167
- if (!config.root) config.root = projectDirectory;
168
- const results = (await CliProgram.init(config, configPath)).run(process.argv.slice(2));
163
+ const results = (await CliProgram.init(config, configPath, projectDirectory)).run(cliArguments);
169
164
  if (results.error) {
170
165
  console.error(results.error.message);
171
- console.log("\n`static --help` for more information, or `static help <command>` for command-specific help\n");
166
+ console.log("\n`staticbolt --help` for more information, or `staticbolt help <command>` for command-specific help\n");
172
167
  process.exit(1);
173
168
  }
169
+ /** Removes every `--name value` or `--name=value` from the arguments and returns the last value. */
170
+ function takeOption(cliArguments, name) {
171
+ const flag = `--${name}`;
172
+ const findFlag = () => cliArguments.findIndex((argument) => argument === flag || argument.startsWith(`${flag}=`));
173
+ let value;
174
+ for (let index = findFlag(); index !== -1; index = findFlag()) {
175
+ const isInlineValue = cliArguments[index] !== flag;
176
+ value = isInlineValue ? cliArguments[index].slice(flag.length + 1) : cliArguments[index + 1];
177
+ if (!value || !isInlineValue && value.startsWith("-")) {
178
+ console.error(`Option ${flag} requires a value`);
179
+ process.exit(1);
180
+ }
181
+ cliArguments.splice(index, isInlineValue ? 1 : 2);
182
+ }
183
+ return value;
184
+ }
174
185
 
175
186
  //#endregion
176
187
  export { };
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["#programWideType"],"sources":["../../src/helpers/load-config.ts","../../src/cli/commands/help.ts","../../src/cli/cli.ts","../../src/cli/index.ts"],"sourcesContent":["import type { ValueOrError } from \"../utilities/value-or-error.ts\";\nimport type { AppConfig } from \"@staticbolt/core\";\n\nexport async function loadConfigFile(configPath: string): Promise<ValueOrError<AppConfig>> {\n try {\n const loadedConfig = (await import(configPath + `?update=${Date.now()}`)) as { default: AppConfig };\n if (!loadedConfig.default) {\n return [null, new Error(`Failed to load config file at \"${configPath}\"`)];\n }\n\n return [loadedConfig.default, null];\n } catch (error) {\n return [null, error as Error];\n }\n}\n","import { defineSubcommand } from \"@staticbolt/args-parser\";\nimport * as z from \"zod\";\n\nexport const helpCommand = defineSubcommand({\n name: \"help\",\n meta: {\n placeholder: \"<command>\",\n description: \"Print help message for a specific command.\",\n example: \"staticbolt help build\",\n },\n\n arguments: {\n command: {\n schema: z.string().optional(),\n meta: {\n description: \"The command to get help for.\",\n },\n },\n },\n});\n\nhelpCommand.onExecute(results => {\n const { command } = results.arguments;\n\n if (!helpCommand.generateCliHelpMessage || !helpCommand.generateSubcommandHelpMessage) {\n throw new Error(\"internal error: missing help functions\");\n }\n\n if (command) {\n console.log(helpCommand.generateSubcommandHelpMessage(command));\n return;\n }\n\n console.log(helpCommand.generateCliHelpMessage());\n});\n","import { coerce, defineArguments, defineCLI, defineOptions, defineSubcommand } from \"@staticbolt/args-parser\";\nimport * as z from \"zod\";\n\nimport { Log } from \"../utilities/logger.ts\";\nimport { helpCommand } from \"./commands/help.ts\";\n\nimport type { Argument, Cli, Option, Subcommand } from \"@staticbolt/args-parser\";\nimport type { AppConfig } from \"@staticbolt/core\";\n\nexport class CliProgram {\n program = defineCLI({\n cliName: \"staticbolt\",\n meta: {\n description: \"Build fast static websites.\",\n example: \"staticbolt build \\nstaticbolt serve\",\n },\n\n options: {\n help: {\n aliases: [\"h\"],\n schema: z.boolean().optional(),\n coerce: coerce.boolean,\n meta: {\n description: \"Show this help message.\",\n },\n },\n version: {\n aliases: [\"v\"],\n schema: z.boolean().optional(),\n coerce: coerce.boolean,\n meta: {\n description: \"Show current version.\",\n },\n },\n },\n });\n\n #programWideType: Cli = this.program;\n\n constructor() {\n this.addCommand(helpCommand);\n\n this.program.onExecute(results => {\n const { help, version } = results.options;\n\n if (help) {\n if (!this.program.generateCliHelpMessage) throw new Error(\"internal error: missing help functions\");\n console.log(this.program.generateCliHelpMessage());\n return;\n }\n\n if (version) {\n console.log(\"v0.0.0\");\n return;\n }\n\n console.error(\"No arguments provided. Use `static --help` for more information\");\n });\n }\n\n async initializePlugins(config: AppConfig, configPath: string) {\n const plugins = config.plugins ?? [];\n\n for (const pluginOrPlugins of plugins) {\n for (const plugin of Array.isArray(pluginOrPlugins) ? pluginOrPlugins : [pluginOrPlugins]) {\n if (plugin.cli) {\n await plugin.cli.call(this, config, configPath);\n }\n }\n }\n }\n\n static async init(config: AppConfig, configPath: string) {\n const cliProgram = new CliProgram();\n await cliProgram.initializePlugins(config, configPath);\n return cliProgram;\n }\n\n run(cliArguments: string[]) {\n return this.program.run(cliArguments);\n }\n\n readonly defineSubcommand = defineSubcommand;\n readonly defineOptions = defineOptions;\n readonly defineArguments = defineArguments;\n readonly coerce = coerce;\n\n addCommand(newSubcommand: Subcommand) {\n if (!this.#programWideType.subcommands) {\n this.#programWideType.subcommands = [newSubcommand];\n return;\n }\n\n return this.#programWideType.subcommands.push(newSubcommand);\n }\n\n addOptions(newOptions: Record<string, Option>) {\n if (!this.#programWideType.options) {\n this.#programWideType.options = newOptions;\n return;\n }\n\n return Object.assign(this.#programWideType.options, newOptions);\n }\n\n addArguments(newArguments: Record<string, Argument>) {\n if (!this.#programWideType.arguments) {\n this.#programWideType.arguments = newArguments;\n return;\n }\n\n return Object.assign(this.#programWideType.arguments, newArguments);\n }\n\n addOptionsToCommand(commandName: string, newOptions: Record<string, Option>) {\n const command = this.#programWideType.subcommands?.find(command => command.name === commandName);\n if (!command) {\n Log.error(`Command \"${commandName}\" not found`);\n return;\n }\n\n if (!command.options) {\n command.options = newOptions;\n return;\n }\n\n return Object.assign(command.options, newOptions);\n }\n\n addArgumentsToCommand(commandName: string, newArguments: Record<string, Argument>) {\n const command = this.#programWideType.subcommands?.find(command => command.name === commandName);\n if (!command) {\n Log.error(`Command \"${commandName}\" not found`);\n return;\n }\n\n if (!command.arguments) {\n command.arguments = newArguments;\n return;\n }\n\n return Object.assign(command.arguments, newArguments);\n }\n}\n","#!/usr/bin/env -S node --experimental-vm-modules --no-warnings\nimport { parseArgs } from \"node:util\";\n\nimport { loadConfigFile } from \"../helpers/load-config.ts\";\nimport { CONFIG_FILE_NAME } from \"../types/common.ts\";\nimport { Log } from \"../utilities/logger.ts\";\nimport { isAbsolute, join, resolve } from \"../utilities/path.ts\";\nimport { CliProgram } from \"./cli.ts\";\n\nconst { values } = parseArgs({\n options: {\n cwd: {\n type: \"string\",\n },\n config: {\n type: \"string\",\n },\n },\n allowPositionals: true,\n strict: false,\n});\n\nconst inputCwd: string = (values.cwd ?? process.cwd()) as string;\nconst inputConfigPath: string = (values.config ?? CONFIG_FILE_NAME) as string;\n\nconst projectDirectory = resolve(inputCwd);\nconst configPath = isAbsolute(inputConfigPath) ? inputConfigPath : join(projectDirectory, inputConfigPath);\n\nconst [loadedConfig, configError] = await loadConfigFile(configPath);\nif (configError) {\n Log.warn(`Failed to load config file at \"${configPath}\"`);\n throw configError;\n}\n\nconst config = loadedConfig ?? {};\n\nif (config.root && !isAbsolute(config.root)) {\n config.root = join(projectDirectory, config.root);\n}\n\nif (!config.root) {\n config.root = projectDirectory;\n}\n\nconst cli = await CliProgram.init(config, configPath);\nconst results = cli.run(process.argv.slice(2));\n\nif (results.error) {\n console.error(results.error.message);\n console.log(\"\\n`static --help` for more information, or `static help <command>` for command-specific help\\n\");\n process.exit(1);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["#programWideType"],"sources":["../../src/cli/commands/help.ts","../../src/cli/cli.ts","../../src/cli/index.ts"],"sourcesContent":["import { defineSubcommand } from \"@staticbolt/args-parser\";\nimport * as z from \"zod\";\n\nexport const helpCommand = defineSubcommand({\n name: \"help\",\n meta: {\n placeholder: \"<command>\",\n description: \"Print help message for a specific command.\",\n example: \"staticbolt help build\",\n },\n\n arguments: {\n command: {\n schema: z.string().optional(),\n meta: {\n description: \"The command to get help for.\",\n },\n },\n },\n});\n\nhelpCommand.onExecute(results => {\n const { command } = results.arguments;\n\n if (!helpCommand.generateCliHelpMessage || !helpCommand.generateSubcommandHelpMessage) {\n throw new Error(\"internal error: missing help functions\");\n }\n\n if (command) {\n console.log(helpCommand.generateSubcommandHelpMessage(command));\n return;\n }\n\n console.log(helpCommand.generateCliHelpMessage());\n});\n","import { coerce, defineArguments, defineCLI, defineOptions, defineSubcommand } from \"@staticbolt/args-parser\";\nimport * as z from \"zod\";\n\nimport { CONFIG_FILE_NAME } from \"../types/common.ts\";\nimport { Log } from \"../utilities/logger.ts\";\nimport { helpCommand } from \"./commands/help.ts\";\n\nimport type { Argument, Cli, Option, Subcommand } from \"@staticbolt/args-parser\";\nimport type { AppConfig } from \"@staticbolt/core\";\n\nexport class CliProgram {\n program = defineCLI({\n cliName: \"staticbolt\",\n meta: {\n description: \"Build fast static websites.\",\n example: \"staticbolt build \\nstaticbolt serve\",\n },\n\n options: {\n cwd: {\n schema: z.string().optional(),\n meta: {\n placeholder: \"<directory>\",\n description: \"The directory to run in. Works with every command.\",\n },\n },\n config: {\n schema: z.string().optional(),\n meta: {\n placeholder: \"<path>\",\n description: `The config file, relative to the directory. Works with every command. Defaults to \"${CONFIG_FILE_NAME}\".`,\n },\n },\n help: {\n aliases: [\"h\"],\n schema: z.boolean().optional(),\n coerce: coerce.boolean,\n meta: {\n description: \"Show this help message.\",\n },\n },\n version: {\n aliases: [\"v\"],\n schema: z.boolean().optional(),\n coerce: coerce.boolean,\n meta: {\n description: \"Show current version.\",\n },\n },\n },\n });\n\n #programWideType: Cli = this.program;\n\n constructor() {\n this.addCommand(helpCommand);\n\n this.program.onExecute(results => {\n const { help, version } = results.options;\n\n if (help) {\n if (!this.program.generateCliHelpMessage) throw new Error(\"internal error: missing help functions\");\n console.log(this.program.generateCliHelpMessage());\n return;\n }\n\n if (version) {\n console.log(\"v0.0.0\");\n return;\n }\n\n console.error(\"No arguments provided. Use `staticbolt --help` for more information\");\n });\n }\n\n async initializePlugins(config: AppConfig, configPath: string, projectDirectory: string) {\n const plugins = config.plugins ?? [];\n\n for (const pluginOrPlugins of plugins) {\n const pluginsAsArray = Array.isArray(pluginOrPlugins) ? pluginOrPlugins : [pluginOrPlugins];\n\n for (const plugin of pluginsAsArray) {\n if (plugin.cli) {\n await plugin.cli.call(this, config, configPath, projectDirectory);\n }\n }\n }\n }\n\n static async init(config: AppConfig, configPath: string, projectDirectory: string) {\n const cliProgram = new CliProgram();\n await cliProgram.initializePlugins(config, configPath, projectDirectory);\n return cliProgram;\n }\n\n run(cliArguments: string[]) {\n return this.program.run(cliArguments);\n }\n\n readonly defineSubcommand = defineSubcommand;\n readonly defineOptions = defineOptions;\n readonly defineArguments = defineArguments;\n readonly coerce = coerce;\n\n addCommand(newSubcommand: Subcommand) {\n if (!this.#programWideType.subcommands) {\n this.#programWideType.subcommands = [newSubcommand];\n return;\n }\n\n this.#programWideType.subcommands.push(newSubcommand);\n\n return this.#programWideType.subcommands.length;\n }\n\n addOptions(newOptions: Record<string, Option>) {\n if (!this.#programWideType.options) {\n this.#programWideType.options = newOptions;\n return;\n }\n\n return Object.assign(this.#programWideType.options, newOptions);\n }\n\n addArguments(newArguments: Record<string, Argument>) {\n if (!this.#programWideType.arguments) {\n this.#programWideType.arguments = newArguments;\n return;\n }\n\n return Object.assign(this.#programWideType.arguments, newArguments);\n }\n\n addOptionsToCommand(commandName: string, newOptions: Record<string, Option>) {\n const command = this.#programWideType.subcommands?.find(command => command.name === commandName);\n if (!command) {\n Log.error(`Command \"${commandName}\" not found`);\n return;\n }\n\n if (!command.options) {\n command.options = newOptions;\n return;\n }\n\n return Object.assign(command.options, newOptions);\n }\n\n addArgumentsToCommand(commandName: string, newArguments: Record<string, Argument>) {\n const command = this.#programWideType.subcommands?.find(command => command.name === commandName);\n if (!command) {\n Log.error(`Command \"${commandName}\" not found`);\n return;\n }\n\n if (!command.arguments) {\n command.arguments = newArguments;\n return;\n }\n\n return Object.assign(command.arguments, newArguments);\n }\n}\n","#!/usr/bin/env node\nimport { loadConfigFile } from \"../helpers/load-config.ts\";\nimport { CONFIG_FILE_NAME } from \"../types/common.ts\";\nimport { Log } from \"../utilities/logger.ts\";\nimport { isAbsolute, join, resolve } from \"../utilities/path.ts\";\nimport { CliProgram } from \"./cli.ts\";\n\nconst cliArguments = process.argv.slice(2);\n\nconst projectDirectory = resolve(takeOption(cliArguments, \"cwd\") ?? process.cwd());\nconst configFile = takeOption(cliArguments, \"config\") ?? CONFIG_FILE_NAME;\nconst configPath = isAbsolute(configFile) ? configFile : join(projectDirectory, configFile);\n\nconst [config, configError] = await loadConfigFile(configPath, projectDirectory);\nif (configError) {\n Log.error(`Failed to load config file at \"${configPath}\"`);\n throw configError;\n}\n\nconst cli = await CliProgram.init(config, configPath, projectDirectory);\nconst results = cli.run(cliArguments);\n\nif (results.error) {\n console.error(results.error.message);\n console.log(\"\\n`staticbolt --help` for more information, or `staticbolt help <command>` for command-specific help\\n\");\n process.exit(1);\n}\n\n/** Removes every `--name value` or `--name=value` from the arguments and returns the last value. */\nfunction takeOption(cliArguments: string[], name: string): string | undefined {\n const flag = `--${name}`;\n const findFlag = () => cliArguments.findIndex(argument => argument === flag || argument.startsWith(`${flag}=`));\n let value: string | undefined;\n\n for (let index = findFlag(); index !== -1; index = findFlag()) {\n const isInlineValue = cliArguments[index] !== flag;\n value = isInlineValue ? cliArguments[index].slice(flag.length + 1) : cliArguments[index + 1];\n\n if (!value || (!isInlineValue && value.startsWith(\"-\"))) {\n console.error(`Option ${flag} requires a value`);\n process.exit(1);\n }\n\n cliArguments.splice(index, isInlineValue ? 1 : 2);\n }\n\n return value;\n}\n"],"mappings":"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"}
@@ -1,19 +1,50 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-DXywRVcq.mjs";
1
2
  import nodePath, { basename, extname, isAbsolute, parse, resolve } from "node:path";
2
3
  import micromatch from "micromatch";
3
- import c from "chalk";
4
+ import chalk from "chalk";
4
5
 
5
6
  //#region src/utilities/path.ts
7
+ var path_exports = /* @__PURE__ */ __exportAll({
8
+ appendForwardSlash: () => appendForwardSlash,
9
+ basename: () => basename,
10
+ dirname: () => dirname,
11
+ extname: () => extname,
12
+ firstPart: () => firstPart,
13
+ isAbsolute: () => isAbsolute,
14
+ isPathMatch: () => isPathMatch,
15
+ isSubpath: () => isSubpath,
16
+ join: () => join,
17
+ normalize: () => normalize,
18
+ parse: () => parse,
19
+ parsePatterns: () => parsePatterns,
20
+ rebaseRelativePath: () => rebaseRelativePath,
21
+ relative: () => relative,
22
+ replaceExtension: () => replaceExtension,
23
+ resolve: () => resolve,
24
+ sourceRelativeToRoot: () => sourceRelativeToRoot,
25
+ trimDotPrefix: () => trimDotPrefix
26
+ });
6
27
  const separatorRe = /\\/g;
7
28
  /** Normalizes a path result to unix separators and ensures relative paths start with `./` */
8
29
  function unixify(path) {
9
- const unix = path.replace(separatorRe, "/");
30
+ const unix = path.includes("\\") ? path.replace(separatorRe, "/") : path;
10
31
  if (unix === ".") return "./";
11
32
  if (unix === "/" || nodePath.isAbsolute(unix)) return unix;
12
33
  if (unix.startsWith("./") || unix.startsWith("../")) return unix;
13
34
  return `./${unix}`;
14
35
  }
15
36
  const join = (...arguments_) => unixify(nodePath.join(...arguments_));
16
- const relative = (from, to) => unixify(nodePath.relative(from, to));
37
+ /** `relative` is pure and called with highly repetitive inputs on hot paths, so cache results. */
38
+ const relativeCache = /* @__PURE__ */ new Map();
39
+ const relative = (from, to) => {
40
+ const key = from + "\0" + to;
41
+ let result = relativeCache.get(key);
42
+ if (result === void 0) {
43
+ result = unixify(nodePath.relative(from, to));
44
+ relativeCache.set(key, result);
45
+ }
46
+ return result;
47
+ };
17
48
  const dirname = (path) => unixify(nodePath.dirname(path));
18
49
  const normalize = (path) => unixify(nodePath.normalize(path));
19
50
  /**
@@ -60,25 +91,46 @@ const appendForwardSlash = (path) => path.endsWith("/") ? path : `${path}/`;
60
91
  const trimDotPrefix = (path) => path.startsWith("./") ? path.slice(2) : path;
61
92
  /** Returns the first segment of a path. */
62
93
  function firstPart(path) {
63
- return normalize(path).replace(/\/$/, "").split("/")[0] ?? "";
94
+ return normalize(path).replace(/\/$/, "").split("/", 1)[0] ?? "";
95
+ }
96
+ /**
97
+ * Splits a semicolon-separated attribute value into an array of trimmed glob patterns.
98
+ *
99
+ * Returns `undefined` when the input is not a string, and an empty array for an empty string.
100
+ */
101
+ function parsePatterns(string) {
102
+ if (typeof string !== "string") return;
103
+ if (!string) return [];
104
+ return string.split(";").flatMap((pattern) => {
105
+ const trimmed = pattern.trim();
106
+ return trimmed ? [trimmed] : [];
107
+ });
108
+ }
109
+ const matcherCache = /* @__PURE__ */ new Map();
110
+ /** `micromatch.isMatch` compiles its patterns on every call; cache the compiled matcher per patterns+options instead. */
111
+ function getMatcher(include, ignore, cwd) {
112
+ const key = JSON.stringify([
113
+ include,
114
+ ignore,
115
+ cwd
116
+ ]);
117
+ let matcher = matcherCache.get(key);
118
+ if (!matcher) {
119
+ matcher = micromatch.matcher(include, cwd === void 0 ? { ignore } : {
120
+ cwd,
121
+ ignore
122
+ });
123
+ matcherCache.set(key, matcher);
124
+ }
125
+ return matcher;
64
126
  }
65
127
  /** Checks if a file path matches a set of patterns. */
66
- function matchPath(filePath, { include, ignore, root }) {
67
- if (filePath.startsWith("..")) return micromatch.isMatch(join(root, filePath), include, { ignore });
128
+ function isPathMatch(filePath, { include, ignore, root }) {
129
+ if (filePath.startsWith("..")) return getMatcher(include, ignore, void 0)(join(root, filePath));
68
130
  const withoutDotPrefix = filePath.replace(/^\.\//, "");
69
- return micromatch.isMatch(withoutDotPrefix, include, {
70
- cwd: root,
71
- ignore
72
- });
131
+ return getMatcher(include, ignore, root)(withoutDotPrefix);
73
132
  }
74
133
 
75
- //#endregion
76
- //#region src/types/common.ts
77
- const CUSTOM_ATTRIBUTES = Object.freeze({
78
- /** For script and style tags to grab the metadata */
79
- MetadataID: "data-metadata-id" });
80
- const CONFIG_FILE_NAME = ".staticbolt.ts";
81
-
82
134
  //#endregion
83
135
  //#region src/utilities/logger.ts
84
136
  const logConfig = {
@@ -87,15 +139,15 @@ const logConfig = {
87
139
  titleWidth: 10,
88
140
  spacer: " ",
89
141
  style: {
90
- success: c.green,
91
- error: c.red,
92
- fatal: c.red,
93
- warning: c.yellow,
94
- verbose: c.dim,
95
- info: c.blueBright,
96
- tip: c.magenta,
97
- log: c.white,
98
- spacer: c.dim
142
+ success: chalk.green,
143
+ error: chalk.red,
144
+ fatal: chalk.red,
145
+ warning: chalk.yellow,
146
+ verbose: chalk.dim,
147
+ info: chalk.blueBright,
148
+ tip: chalk.magenta,
149
+ log: chalk.white,
150
+ spacer: chalk.dim
99
151
  }
100
152
  };
101
153
  function createLog(...defaultMessages) {
@@ -127,8 +179,8 @@ function createLog(...defaultMessages) {
127
179
  if (logConfig.verboseFilter && !logConfig.verboseFilter.test(joined)) return;
128
180
  logFormatter("DEBUG", logConfig.style.verbose, joined);
129
181
  };
130
- Log.enableVerbose = (enabled) => {
131
- logConfig.verboseEnabled = enabled;
182
+ Log.enableVerbose = (isEnabled) => {
183
+ logConfig.verboseEnabled = isEnabled;
132
184
  };
133
185
  Log.setVerboseFilter = (filter) => {
134
186
  logConfig.verboseFilter = filter;
@@ -162,13 +214,13 @@ function logFormatter(title, style, ...messages) {
162
214
  const formattedTitle = formatLogTitle(title, style);
163
215
  const splitByNewLines = content.split("\n");
164
216
  let message = "";
165
- for (const [index, splitByNewLine] of splitByNewLines.entries()) {
217
+ for (const [index, splitByNewline] of splitByNewLines.entries()) {
166
218
  if (index > 0) {
167
219
  const width = logConfig.titleWidth / logConfig.spacer.length;
168
220
  const spacer = logConfig.spacer.repeat(width).padEnd(logConfig.titleWidth);
169
221
  message += "\n" + style.dim(spacer + "↪ ");
170
222
  }
171
- message += splitByNewLine;
223
+ message += splitByNewline;
172
224
  }
173
225
  console.log(prefixNewlines + formattedTitle, message, suffixNewlines);
174
226
  }
@@ -186,5 +238,12 @@ function splitOnNewline(input) {
186
238
  }
187
239
 
188
240
  //#endregion
189
- export { relative as _, appendForwardSlash as a, sourceRelativeToRoot as b, extname as c, isSubpath as d, join as f, rebaseRelativePath as g, parse as h, CUSTOM_ATTRIBUTES as i, firstPart as l, normalize as m, createLog as n, basename as o, matchPath as p, CONFIG_FILE_NAME as r, dirname as s, Log as t, isAbsolute as u, replaceExtension as v, trimDotPrefix as x, resolve as y };
190
- //# sourceMappingURL=logger-BuxMGhij.mjs.map
241
+ //#region src/types/common.ts
242
+ const CUSTOM_ATTRIBUTES = Object.freeze({
243
+ /** For script and style tags to grab the metadata */
244
+ MetadataID: "data-metadata-id" });
245
+ const CONFIG_FILE_NAME = ".staticbolt.ts";
246
+
247
+ //#endregion
248
+ export { replaceExtension as _, basename as a, isAbsolute as c, join as d, normalize as f, relative as g, path_exports as h, createLog as i, isPathMatch as l, parsePatterns as m, CUSTOM_ATTRIBUTES as n, dirname as o, parse as p, Log as r, extname as s, CONFIG_FILE_NAME as t, isSubpath as u, resolve as v };
249
+ //# sourceMappingURL=common-DUFKS3lW.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common-DUFKS3lW.mjs","names":[],"sources":["../src/utilities/path.ts","../src/utilities/logger.ts","../src/types/common.ts"],"sourcesContent":["import nodePath from \"node:path\";\nimport micromatch from \"micromatch\";\n\nexport { basename, extname, isAbsolute, parse, resolve } from \"node:path\";\n\n// For ESM and CSS compatibility:\n// - Always use unix separators (except `resolve`, which returns an absolute path)\n// - Relative paths should always start with `./`\n\nconst separatorRe = /\\\\/g;\n\n/** Normalizes a path result to unix separators and ensures relative paths start with `./` */\nfunction unixify(path: string): string {\n const unix = path.includes(\"\\\\\") ? path.replace(separatorRe, \"/\") : path;\n\n // Example: dirname(\"index.html\") => \".\"\n if (unix === \".\") {\n return \"./\";\n }\n\n if (unix === \"/\" || nodePath.isAbsolute(unix)) {\n return unix;\n }\n\n if (unix.startsWith(\"./\") || unix.startsWith(\"../\")) {\n return unix;\n }\n\n return `./${unix}`;\n}\n\nexport const join = (...arguments_: string[]) => unixify(nodePath.join(...arguments_));\n\n/** `relative` is pure and called with highly repetitive inputs on hot paths, so cache results. */\nconst relativeCache = new Map<string, string>();\n\nexport const relative = (from: string, to: string) => {\n const key = from + \"\\u{0}\" + to;\n\n let result = relativeCache.get(key);\n if (result === undefined) {\n result = unixify(nodePath.relative(from, to));\n relativeCache.set(key, result);\n }\n\n return result;\n};\n\nexport const dirname = (path: string) => unixify(nodePath.dirname(path));\n\nexport const normalize = (path: string) => unixify(nodePath.normalize(path));\n\n/**\n * Recalculates the relative path for a resource after a file has been moved.\n *\n * @param source - The source found in the `oldPath` file.\n * @param oldPath - Absolute or relative original path of the file.\n * @param newPath - Absolute or relative new path of the file.\n * @returns The updated relative path from the new file's directory to the same resource.\n */\nexport function rebaseRelativePath(source: string, oldPath: string, newPath: string): string {\n return relative(dirname(newPath), join(dirname(oldPath), source));\n}\n\n/**\n * Checks if a path (child) is a subpath of another (parent).\n *\n * Note: both paths must be of the same type — either both absolute or both relative. Mixing them will produce incorrect results.\n *\n * @param parentDirectory - The parent directory.\n * @param childPath - The child path (file or directory).\n */\nexport function isSubpath(parentDirectory: string, childPath: string): boolean {\n if (childPath === \"./\") return false;\n const relativePath = relative(normalize(parentDirectory), normalize(childPath));\n return relativePath === \"\" || (!relativePath.startsWith(\"..\") && !nodePath.isAbsolute(relativePath));\n}\n\ninterface SourceRelativeToRootOptions {\n /** The root directory (absolute or resolvable) */\n root: string;\n /** The file path that contains the source path */\n filePath: string;\n /** The source path */\n sourcePath: string;\n}\n\n/** Calculates the relative path of a source path to the root. */\nexport function sourceRelativeToRoot({ root, filePath, sourcePath }: SourceRelativeToRootOptions): string {\n const absRoot = nodePath.resolve(root);\n return relative(absRoot, nodePath.join(absRoot, dirname(filePath), sourcePath));\n}\n\n/** Replaces the extension of a given path. */\nexport function replaceExtension(filePath: string, extension: string): string {\n const { dir, name } = nodePath.parse(filePath);\n return normalize(nodePath.format({ dir, name, ext: extension }));\n}\n\n/** Appends a forward slash to the end of a path if it doesn't already end with one. */\nexport const appendForwardSlash = (path: string) => (path.endsWith(\"/\") ? path : `${path}/`);\n\n/** Removes the leading `./` from a path. */\nexport const trimDotPrefix = (path: string) => (path.startsWith(\"./\") ? path.slice(2) : path);\n\n/** Returns the first segment of a path. */\nexport function firstPart(path: string): string {\n const cleaned = normalize(path).replace(/\\/$/, \"\");\n return cleaned.split(\"/\", 1)[0] ?? \"\";\n}\n\n/**\n * Splits a semicolon-separated attribute value into an array of trimmed glob patterns.\n *\n * Returns `undefined` when the input is not a string, and an empty array for an empty string.\n */\nexport function parsePatterns(string: string | null | undefined): string[] | undefined {\n if (typeof string !== \"string\") return;\n\n if (!string) return [];\n\n return string.split(\";\").flatMap(pattern => {\n const trimmed = pattern.trim();\n return trimmed ? [trimmed] : [];\n });\n}\n\ninterface MatchPathOptions {\n include: string | string[];\n ignore?: string | string[];\n root: string;\n}\n\nconst matcherCache = new Map<string, (path: string) => boolean>();\n\n/** `micromatch.isMatch` compiles its patterns on every call; cache the compiled matcher per patterns+options instead. */\nfunction getMatcher(include: string | string[], ignore: string | string[] | undefined, cwd: string | undefined) {\n const key = JSON.stringify([include, ignore, cwd]);\n\n let matcher = matcherCache.get(key);\n if (!matcher) {\n // The underlying picomatch accepts `string | string[]` patterns, the micromatch typings are just too narrow\n matcher = micromatch.matcher(include as string, cwd === undefined ? { ignore } : { cwd, ignore });\n matcherCache.set(key, matcher);\n }\n\n return matcher;\n}\n\n/** Checks if a file path matches a set of patterns. */\nexport function isPathMatch(filePath: string, { include, ignore, root }: MatchPathOptions): boolean {\n // Case: outside the root directory\n if (filePath.startsWith(\"..\")) {\n return getMatcher(include, ignore, undefined)(join(root, filePath));\n }\n\n // Case: inside the root dir\n const withoutDotPrefix = filePath.replace(/^\\.\\//, \"\");\n return getMatcher(include, ignore, root)(withoutDotPrefix);\n}\n","import chalk from \"chalk\";\n\ntype ChalkInstance = typeof chalk;\n\nconst logConfig = {\n verboseEnabled: false,\n verboseFilter: null as null | RegExp,\n titleWidth: 10,\n spacer: \" \",\n style: {\n success: chalk.green,\n error: chalk.red,\n fatal: chalk.red,\n warning: chalk.yellow,\n verbose: chalk.dim,\n info: chalk.blueBright,\n tip: chalk.magenta,\n log: chalk.white,\n spacer: chalk.dim,\n },\n};\n\nexport function createLog(...defaultMessages: string[]) {\n function Log(...messages: unknown[]) {\n console.log(formatLogTitle(\"LOG\", logConfig.style.log), ...defaultMessages, ...messages);\n }\n\n Log.warn = (...messages: string[]) => {\n logFormatter(\"WARNING\", logConfig.style.warning, ...defaultMessages, ...messages);\n };\n\n Log.success = (...messages: string[]) => {\n logFormatter(\"SUCCESS\", logConfig.style.success, ...defaultMessages, ...messages);\n };\n\n Log.error = (...messages: string[]) => {\n logFormatter(\"ERROR\", logConfig.style.error, ...defaultMessages, ...messages);\n };\n\n Log.fatal = (...messages: string[]) => {\n logFormatter(\"FATAL\", logConfig.style.fatal, ...defaultMessages, ...messages);\n\n // eslint-disable-next-line unicorn/no-process-exit\n process.exit(1);\n };\n\n Log.info = (...messages: string[]) => {\n logFormatter(\"INFO\", logConfig.style.info, ...defaultMessages, ...messages);\n };\n\n Log.tip = (...messages: string[]) => {\n logFormatter(\"TIP\", logConfig.style.tip, ...defaultMessages, ...messages);\n };\n\n Log.debug = (...messages: string[]) => {\n if (!logConfig.verboseEnabled) return;\n\n const joined = defaultMessages.concat(messages).join(\" \");\n if (logConfig.verboseFilter && !logConfig.verboseFilter.test(joined)) return;\n\n logFormatter(\"DEBUG\", logConfig.style.verbose, joined);\n };\n\n Log.enableVerbose = (isEnabled: boolean) => {\n logConfig.verboseEnabled = isEnabled;\n };\n\n Log.setVerboseFilter = (filter: RegExp) => {\n logConfig.verboseFilter = filter;\n };\n\n return Log;\n}\n\n/**\n * - Prints a styled message to the console.\n *\n * @example\n * Log(\"Hello World!\"); // Prints: | LOG | Hello World! |\n * Log.success(\"Hello World!\"); // Prints: | SUCCESS | Hello World! |\n * Log.info(\"Hello World!\"); // Prints: | INFO | Hello World! |\n * Log.error(\"Hello World!\"); // Prints: | ERROR | Hello World! |\n * Log.fatal(\"Hello World!\"); // Prints: | FATAL | Hello World! |\n * Log.warn(\"Hello World!\"); // Prints: | WARNING | Hello World! |\n */\nexport const Log = createLog();\n\nfunction formatLogTitle(title: string, style: ChalkInstance) {\n const width = logConfig.titleWidth;\n const paddingLength = title.length >= width ? 0 : (width - title.length) / 2;\n const paddingStart = \" \".repeat(paddingLength);\n const paddingEnd = \" \".repeat(paddingLength);\n\n title = paddingStart + title + paddingEnd;\n\n // Ensure that the final string has width length\n title = title.padEnd(width, \" \");\n\n // apply style\n title = style(title + \"|\");\n\n return title;\n}\n\nfunction logFormatter(title: string, style: ChalkInstance, ...messages: string[]) {\n const { prefixNewlines, content, suffixNewlines } = splitOnNewline(messages);\n const formattedTitle = formatLogTitle(title, style);\n\n const splitByNewLines = content.split(\"\\n\");\n\n let message = \"\";\n for (const [index, splitByNewline] of splitByNewLines.entries()) {\n if (index > 0) {\n const width = logConfig.titleWidth / logConfig.spacer.length;\n const spacer = logConfig.spacer.repeat(width).padEnd(logConfig.titleWidth);\n message += \"\\n\" + style.dim(spacer + \"↪ \");\n }\n\n message += splitByNewline;\n }\n\n console.log(prefixNewlines + formattedTitle, message, suffixNewlines);\n}\n\nfunction splitOnNewline(input: string[]) {\n const message = input.join(\" \");\n\n // Check for leading newlines\n let newlineStart = 0;\n while (newlineStart < message.length && message[newlineStart] == \"\\n\") {\n newlineStart++;\n }\n\n // Check for trailing newlines\n let newlineEnd = message.length;\n while (newlineEnd > newlineStart && message[newlineEnd - 1] == \"\\n\") {\n newlineEnd--;\n }\n\n const results = {\n prefixNewlines: message.slice(0, Math.max(0, newlineStart)),\n content: message.slice(newlineStart, newlineEnd),\n suffixNewlines: message.slice(Math.max(0, newlineEnd)),\n };\n\n return results;\n}\n","import type { ParseResult } from \"@babel/parser\";\nimport type { Plugin } from \"@staticbolt/core\";\nimport type { Root } from \"mdast\";\nimport type postcss from \"postcss\";\n\nexport type { NodePath } from \"@babel/traverse\";\n\nexport type BabelAst = ParseResult;\nexport type PostcssAst = postcss.Root;\nexport type { HTMLElement, Document } from \"@staticbolt/node-html-parser\";\n\nexport interface MarkdownAst {\n root: Root;\n frontmatter: Record<string, string>;\n render(): Promise<string>;\n}\n\nexport const CUSTOM_ATTRIBUTES = Object.freeze({\n /** For script and style tags to grab the metadata */\n MetadataID: \"data-metadata-id\",\n});\n\nexport const CONFIG_FILE_NAME = \".staticbolt.ts\";\n\nexport interface AppConfig {\n /**\n * The project root. Relative paths in the config are resolved against it.\n *\n * @default process.cwd()\n */\n root?: string;\n\n /** Plugins to run, in order. Nested arrays are flattened, so a plugin preset can be spread in as a single entry. */\n plugins?: (Plugin[] | Plugin)[];\n\n /**\n * The output directory, either absolute or relative to {@link AppConfig.root}.\n *\n * @default \"./dist\"\n */\n outdir?: string;\n\n /**\n * Whether to build for production. In development the project is watched for file changes.\n *\n * @default false\n */\n production?: boolean;\n\n /**\n * Browsers to target, as [browserslist](https://github.com/browserslist/browserslist) queries. Defaults to the project's\n * browserslist configuration.\n *\n * @example\n * [\"last 2 Chrome versions\", \"last 2 Safari versions\"];\n */\n browserslist?: string[];\n\n /**\n * Whether to time each plugin hook and print a breakdown when the build finishes.\n *\n * @default false\n */\n measureExecutionTime?: boolean;\n\n /**\n * Path aliases, merged on top of the ones resolved from `tsconfig.json` — entries defined here win on key conflicts.\n *\n * Keys ending with `/` are directory aliases, otherwise the key is matched as a whole. Values are resolved relative to the\n * project root.\n *\n * @example\n * { \"~/\": \"./src/\", \"@config\": \"./src/config.ts\" }\n */\n aliases?: Record<string, string>;\n}\n"],"mappings":"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"}
@@ -0,0 +1,218 @@
1
+ //#region src/helpers/format-code.ts
2
+ const fallbackConfig = { printWidth: 130 };
3
+ /**
4
+ * Prettier resolves a config per file, and a file gets the same one every time, so the answers are kept. A build can be spread
5
+ * across threads, and a cache that only remembered the first answer would hand a file whatever config the thread happened to
6
+ * start on.
7
+ */
8
+ const prettierConfigs = /* @__PURE__ */ new Map();
9
+ /** - Format code using Prettier */
10
+ async function formatCode(code, filePath, lang) {
11
+ const { format } = await import("prettier");
12
+ try {
13
+ const options = await loadPrettierConfig(filePath);
14
+ const parser = lang === "js" ? "babel" : lang === "ts" ? "typescript" : lang;
15
+ return [await format(code, {
16
+ ...options,
17
+ parser,
18
+ filepath: filePath
19
+ }), null];
20
+ } catch {
21
+ return [null, /* @__PURE__ */ new Error(`Prettier formatting failed for '${filePath}'`)];
22
+ }
23
+ }
24
+ async function loadPrettierConfig(filePath) {
25
+ const cached = prettierConfigs.get(filePath);
26
+ if (cached) return cached;
27
+ const options = await resolvePrettierConfig(filePath);
28
+ prettierConfigs.set(filePath, options);
29
+ return options;
30
+ }
31
+ async function resolvePrettierConfig(filePath) {
32
+ const { resolveConfig } = await import("prettier");
33
+ const organizeImports = await import("prettier-plugin-organize-imports");
34
+ try {
35
+ const resolved = await resolveConfig(filePath) ?? fallbackConfig;
36
+ const plugins = [...resolved.plugins ?? []];
37
+ if (!plugins.includes("prettier-plugin-jsdoc")) plugins.push(organizeImports.default);
38
+ return {
39
+ ...resolved,
40
+ plugins
41
+ };
42
+ } catch {
43
+ return fallbackConfig;
44
+ }
45
+ }
46
+
47
+ //#endregion
48
+ //#region src/helpers/deferred-pass.ts
49
+ let resolved;
50
+ /**
51
+ * Names one of the passes the core plugins export, for a caller that would rather run it somewhere else.
52
+ *
53
+ * The module is resolved through the package's own exports rather than built from a relative path, so the URL still means the
54
+ * same thing to a worker thread, which has no idea where the plugin that handed it a pass was running from.
55
+ */
56
+ function coreDeferredPass(exportName, payload) {
57
+ resolved ??= import.meta.resolve("@staticbolt/core/deferred");
58
+ return {
59
+ module: resolved,
60
+ export: exportName,
61
+ payload
62
+ };
63
+ }
64
+
65
+ //#endregion
66
+ //#region src/plugins/core-plugins/html-metadata/minify-html.ts
67
+ async function minifyHtmlTerser(code) {
68
+ try {
69
+ const { default: htmlTerser } = await import("html-minifier-terser");
70
+ return [await htmlTerser.minify(code, {
71
+ minifyCSS: false,
72
+ minifyJS: false,
73
+ removeComments: true,
74
+ collapseWhitespace: true
75
+ }), null];
76
+ } catch {
77
+ return [null, /* @__PURE__ */ new Error("Failed to minify HTML")];
78
+ }
79
+ }
80
+
81
+ //#endregion
82
+ //#region src/plugins/core-plugins/html-metadata/deferred.ts
83
+ /** The pass `coreHtmlPlugin` runs over a printed document when formatting. */
84
+ const formatHtml = async (code, { filePath }) => {
85
+ const [formatted, formatError] = await formatCode(code, filePath, "html");
86
+ if (formatError) throw formatError;
87
+ return formatted;
88
+ };
89
+ /** The pass `coreHtmlPlugin` runs over a printed document when minifying. */
90
+ const minifyHtml = async (code) => {
91
+ const [minified, minifyError] = await minifyHtmlTerser(code);
92
+ if (minifyError) throw minifyError;
93
+ return minified;
94
+ };
95
+ /** Hands `formatHtml` to a caller that would rather run it somewhere else. */
96
+ const formatHtmlPass = (payload) => coreDeferredPass("formatHtml", payload);
97
+ /** Hands `minifyHtml` to a caller that would rather run it somewhere else. */
98
+ const minifyHtmlPass = () => coreDeferredPass("minifyHtml");
99
+
100
+ //#endregion
101
+ //#region src/plugins/core-plugins/markdown-metadata/deferred.ts
102
+ /** The pass `coreMarkdownPlugin` runs over a printed document when formatting. */
103
+ const formatMarkdown = async (code, { filePath }) => {
104
+ const [formatted, formatError] = await formatCode(code, filePath, "markdown");
105
+ if (formatError) throw formatError;
106
+ return formatted;
107
+ };
108
+ /** Hands `formatMarkdown` to a caller that would rather run it somewhere else. */
109
+ const formatMarkdownPass = (payload) => coreDeferredPass("formatMarkdown", payload);
110
+
111
+ //#endregion
112
+ //#region src/plugins/core-plugins/script-metadata/minify-script.ts
113
+ /**
114
+ * Minification is pure, and the same inline script can appear on many pages (e.g. through layouts), so cache results by content.
115
+ * Only populated in production builds, where minification runs; SWC is imported lazily for the same reason.
116
+ */
117
+ const swcCache = /* @__PURE__ */ new Map();
118
+ async function minifyScriptSWC(code, isModule) {
119
+ const key = (isModule ? "m" : "s") + code;
120
+ const cached = swcCache.get(key);
121
+ if (cached !== void 0) return [cached, null];
122
+ try {
123
+ const { minifySync: swcMinify } = await import("@swc/core");
124
+ const minified = swcMinify(code, { module: isModule });
125
+ if (!minified.code) return [null, /* @__PURE__ */ new Error("Failed to minify script: empty output")];
126
+ swcCache.set(key, minified.code);
127
+ return [minified.code, null];
128
+ } catch (error) {
129
+ return [null, error];
130
+ }
131
+ }
132
+
133
+ //#endregion
134
+ //#region src/plugins/core-plugins/script-metadata/deferred.ts
135
+ /** The pass `coreScriptPlugin` runs over printed code when formatting. */
136
+ const formatScript = async (code, { filePath }) => {
137
+ const [formatted, formatError] = await formatCode(code, filePath, "js");
138
+ if (formatError) throw formatError;
139
+ return formatted;
140
+ };
141
+ /** The pass `coreScriptPlugin` runs over printed code when minifying. */
142
+ const minifyScript = async (code, { module }) => {
143
+ const [minified, minifyError] = await minifyScriptSWC(code, module);
144
+ if (minifyError) throw minifyError;
145
+ return minified;
146
+ };
147
+ /** Hands `formatScript` to a caller that would rather run it somewhere else. */
148
+ const formatScriptPass = (payload) => coreDeferredPass("formatScript", payload);
149
+ /** Hands `minifyScript` to a caller that would rather run it somewhere else. */
150
+ const minifyScriptPass = (payload) => coreDeferredPass("minifyScript", payload);
151
+
152
+ //#endregion
153
+ //#region src/plugins/core-plugins/style-metadata/minify-style.ts
154
+ /**
155
+ * Minification is pure, and the same inline style can appear on many pages (e.g. through layouts), so cache results by content.
156
+ * Only populated in production builds, where minification runs; lightningcss is imported lazily for the same reason.
157
+ */
158
+ const lightningCssCache = /* @__PURE__ */ new Map();
159
+ async function minifyLightingCss(code, filename, targets) {
160
+ const cached = lightningCssCache.get(code);
161
+ if (cached !== void 0) return [cached, null];
162
+ try {
163
+ const { transform } = await import("lightningcss");
164
+ const minified = transform({
165
+ filename,
166
+ code: Buffer.from(code),
167
+ minify: true,
168
+ analyzeDependencies: false,
169
+ targets
170
+ }).code.toString();
171
+ lightningCssCache.set(code, minified);
172
+ return [minified, null];
173
+ } catch (error) {
174
+ return [null, error];
175
+ }
176
+ }
177
+
178
+ //#endregion
179
+ //#region src/plugins/core-plugins/style-metadata/deferred.ts
180
+ /** The pass `coreStylePlugin` runs over a printed stylesheet when formatting. */
181
+ const formatStyle = async (code, { filePath }) => {
182
+ const [formatted, formatError] = await formatCode(code, filePath, "css");
183
+ if (formatError) throw formatError;
184
+ return formatted;
185
+ };
186
+ /** The pass `coreStylePlugin` runs over a printed stylesheet when minifying. */
187
+ const minifyStyle = async (code, { filePath, targets }) => {
188
+ const [minified, minifyError] = await minifyLightingCss(code, filePath, targets);
189
+ if (minifyError) throw minifyError;
190
+ return minified;
191
+ };
192
+ /** Hands `formatStyle` to a caller that would rather run it somewhere else. */
193
+ const formatStylePass = (payload) => coreDeferredPass("formatStyle", payload);
194
+ /** Hands `minifyStyle` to a caller that would rather run it somewhere else. */
195
+ const minifyStylePass = (payload) => coreDeferredPass("minifyStyle", payload);
196
+
197
+ //#endregion
198
+ //#region src/plugins/core-plugins/svg-metadata/deferred.ts
199
+ /** The pass `coreSvgPlugin` runs over a printed drawing when formatting. */
200
+ const formatSvg = async (code, { filePath }) => {
201
+ const [formatted, formatError] = await formatCode(code, filePath, "html");
202
+ if (formatError) throw formatError;
203
+ return formatted;
204
+ };
205
+ /** The pass `coreSvgPlugin` runs over a printed drawing when minifying. */
206
+ const minifySvg = async (code) => {
207
+ const [minified, minifyError] = await minifyHtmlTerser(code);
208
+ if (minifyError) throw minifyError;
209
+ return minified;
210
+ };
211
+ /** Hands `formatSvg` to a caller that would rather run it somewhere else. */
212
+ const formatSvgPass = (payload) => coreDeferredPass("formatSvg", payload);
213
+ /** Hands `minifySvg` to a caller that would rather run it somewhere else. */
214
+ const minifySvgPass = () => coreDeferredPass("minifySvg");
215
+
216
+ //#endregion
217
+ export { minifyHtml as _, formatStyle as a, minifyStylePass as c, minifyScript as d, minifyScriptPass as f, formatHtmlPass as g, formatHtml as h, minifySvgPass as i, formatScript as l, formatMarkdownPass as m, formatSvgPass as n, formatStylePass as o, formatMarkdown as p, minifySvg as r, minifyStyle as s, formatSvg as t, formatScriptPass as u, minifyHtmlPass as v, formatCode as y };
218
+ //# sourceMappingURL=deferred-DTj91vEg.mjs.map