blogger-hbs 0.0.5 → 0.0.7

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.
Files changed (50) hide show
  1. package/README.md +5 -3
  2. package/dist/cli/index.js +164 -14
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/compiler/ast/imports.js +5 -24
  5. package/dist/compiler/ast/imports.js.map +1 -1
  6. package/dist/compiler/ast/walk.d.ts +2 -2
  7. package/dist/compiler/ast/walk.js +5 -21
  8. package/dist/compiler/ast/walk.js.map +1 -1
  9. package/dist/compiler/compile.d.ts +9 -1
  10. package/dist/compiler/compile.js +18 -13
  11. package/dist/compiler/compile.js.map +1 -1
  12. package/dist/compiler/evaluate.d.ts +8 -0
  13. package/dist/compiler/evaluate.js +13 -0
  14. package/dist/compiler/evaluate.js.map +1 -0
  15. package/dist/compiler/index.d.ts +2 -2
  16. package/dist/compiler/index.js +2 -2
  17. package/dist/compiler/plugins.d.ts +1 -1
  18. package/dist/compiler/plugins.js +162 -142
  19. package/dist/compiler/plugins.js.map +1 -1
  20. package/dist/compiler/precompile.js +2 -2
  21. package/dist/compiler/precompile.js.map +1 -1
  22. package/dist/compiler/rsbuild.d.ts +20 -1
  23. package/dist/compiler/rsbuild.js +55 -28
  24. package/dist/compiler/rsbuild.js.map +1 -1
  25. package/dist/compiler/runtimes.js +10 -24
  26. package/dist/compiler/runtimes.js.map +1 -1
  27. package/dist/compiler/scan.d.ts +1 -1
  28. package/dist/compiler/scan.js +12 -7
  29. package/dist/compiler/scan.js.map +1 -1
  30. package/dist/compiler/watch.js +9 -2
  31. package/dist/compiler/watch.js.map +1 -1
  32. package/dist/constants.d.ts +8 -0
  33. package/dist/constants.js +23 -1
  34. package/dist/constants.js.map +1 -1
  35. package/dist/plugins/index.d.ts +9 -0
  36. package/dist/plugins/index.js +24 -1
  37. package/dist/plugins/index.js.map +1 -1
  38. package/dist/runtime/import.js +69 -40
  39. package/dist/runtime/import.js.map +1 -1
  40. package/dist/runtime/linebreaks.js +6 -4
  41. package/dist/runtime/linebreaks.js.map +1 -1
  42. package/dist/runtime/render.js +4 -20
  43. package/dist/runtime/render.js.map +1 -1
  44. package/dist/runtime/tags.d.ts +3 -2
  45. package/dist/runtime/tags.js +8 -18
  46. package/dist/runtime/tags.js.map +1 -1
  47. package/dist/utils/resolver.d.ts +5 -0
  48. package/dist/utils/resolver.js +80 -8
  49. package/dist/utils/resolver.js.map +1 -1
  50. package/package.json +1 -1
package/README.md CHANGED
@@ -29,9 +29,11 @@ export default defineConfig({
29
29
  ```
30
30
 
31
31
  ```sh
32
- blogger-hbs # build to dist/theme.xml
33
- blogger-hbs --watch # build again on changes
34
- blogger-hbs --help # all the options
32
+ blogger-hbs # build to dist/theme.xml
33
+ blogger-hbs --watch # build again on changes
34
+ blogger-hbs validate theme.xml # validate a theme
35
+ blogger-hbs format theme.xml -o out.xml # format it
36
+ blogger-hbs --help # all the options
35
37
  ```
36
38
 
37
39
  The same is available from JavaScript with `compileTemplate`, `watchTemplate` and `renderTemplate`.
package/dist/cli/index.js CHANGED
@@ -2,7 +2,7 @@ import { CompileError } from "../compiler/errors.js";
2
2
  import { withLocation } from "../plugins/index.js";
3
3
  import { didYouMean } from "../utils/suggest.js";
4
4
  import { COMPILE_OPTION_KEYS, assertCompileOptions, assertDirectories, assertEntry, resolvePaths } from "../compiler/options.js";
5
- import { processXml } from "../xml/process.js";
5
+ import { XmlError, processXml } from "../xml/process.js";
6
6
  import { compileTemplate } from "../compiler/compile.js";
7
7
  import { watchTemplate } from "../compiler/watch.js";
8
8
  import { loadConfig } from "../config.js";
@@ -14,13 +14,18 @@ import { watch } from "node:fs";
14
14
  import { styleText } from "node:util";
15
15
  import { cac } from "cac";
16
16
  //#region src/cli/index.ts
17
- const { version } = JSON.parse(await fs.readFile(new URL("../../package.json", import.meta.url), "utf-8"));
18
- const log = {
19
- success: (message) => console.log(`${styleText("green", "✓")} ${message}`),
20
- info: (message) => console.log(`${styleText("cyan", "●")} ${message}`),
21
- warn: (message) => console.warn(`${styleText("yellow", "⚠")} ${message}`),
22
- error: (error) => console.error(`${styleText("red", "✗")} ${formatError(error)}`)
23
- };
17
+ const { version, license, repository } = JSON.parse(await fs.readFile(new URL("../../package.json", import.meta.url), "utf-8"));
18
+ /** What the CLI prints, with `write`, warnings and errors on stderr. */
19
+ function logTo(write) {
20
+ return {
21
+ write,
22
+ success: (message) => write(`${styleText("green", "✓")} ${message}`),
23
+ info: (message) => write(`${styleText("cyan", "●")} ${message}`),
24
+ warn: (message) => console.warn(`${styleText("yellow", "⚠")} ${message}`),
25
+ error: (error) => console.error(`${styleText("red", "✗")} ${formatError(error)}`)
26
+ };
27
+ }
28
+ const log = logTo(console.log);
24
29
  const cli = cac("blogger-hbs");
25
30
  cli.command("[root]", "Compile the template and render it").alias("build").option("-c, --config <file>", "Path of the config file").option("--entry <file>", "Entry template, relative to the root").option("-o, --out-dir <dir>", "Output directory, relative to the root").option("--context <file>", "JSON file with the context to render with").option("-w, --watch", "Build again when a file changes").option("--no-clean", "Keep the files in the output directory").option("--no-validate", "Do not validate the rendered template as XML, nor format it (templates are always validated when compiling)").option("--no-format", "Do not format the rendered template").example("blogger-hbs").example("blogger-hbs --watch").example("blogger-hbs ./theme --entry src/index.hbs --context context.json").action(async (rootArg, rawFlags) => {
26
31
  printHeader();
@@ -36,22 +41,45 @@ cli.command("[root]", "Compile the template and render it").alias("build").optio
36
41
  if (flags.watch) await watchBuild(root, flags);
37
42
  else await build(root, flags);
38
43
  });
44
+ cli.command("validate <file>", "Validate a theme as Blogger reads it").option("--json", "Print the result as JSON").example("blogger-hbs validate dist/theme.xml").example("blogger-hbs validate dist/theme.xml --json").action(async (file, flags) => {
45
+ await processFile(String(file), {
46
+ format: false,
47
+ json: flags.json
48
+ });
49
+ });
50
+ cli.command("format <file>", "Format a theme as Blogger saves it, written to stdout, or to --out").option("-o, --out <file>", "Write it to this file instead of stdout").option("--json", "Print the result as JSON, the theme in it without --out").example("blogger-hbs format theme.xml").example("blogger-hbs format theme.xml -o theme.formatted.xml").action(async (file, flags) => {
51
+ const out = flags.out === void 0 ? void 0 : String(flags.out);
52
+ await processFile(String(file), {
53
+ format: true,
54
+ out,
55
+ json: flags.json
56
+ });
57
+ });
39
58
  cli.help();
40
- cli.version(version);
59
+ cli.globalCommand.versionNumber = version;
60
+ cli.option("-v, --version", "Display the version, the copyright and the license");
61
+ /** Whether the header is printed, so that an error before a command runs prints it too. */
62
+ let headerPrinted = false;
41
63
  try {
42
64
  cli.parse(process.argv, { run: false });
43
- await cli.runMatchedCommand();
65
+ if (cli.options.version) await printVersion();
66
+ else await cli.runMatchedCommand();
44
67
  } catch (error) {
68
+ if (!headerPrinted && !cli.options.json) printHeader(formatsToStdout() ? console.error : console.log);
45
69
  log.error(describeCliError(error));
46
70
  process.exitCode = 1;
47
71
  }
72
+ /** Whether the command formats a theme to stdout, which has nothing else on it. */
73
+ function formatsToStdout() {
74
+ return cli.matchedCommandName === "format" && cli.options.out === void 0;
75
+ }
48
76
  /** Adds a suggestion and a pointer to `--help` to the errors of the arguments. */
49
77
  function describeCliError(error) {
50
78
  if (!(error instanceof Error) || error.name !== "CACError") return error;
51
79
  const flags = [...cli.commands, cli.globalCommand].flatMap((command) => command.options.flatMap((option) => option.rawName.match(/--[\w-]+/g) ?? []));
52
80
  const unknown = /^Unknown option `(.+)`$/.exec(error.message)?.[1];
53
81
  const hint = unknown ? didYouMean(unknown, flags, "`") : "";
54
- return /* @__PURE__ */ new Error(`${error.message}${hint}\nRun 'blogger-hbs --help' to see the available options`);
82
+ return /* @__PURE__ */ new Error(`${error.message}${hint}\nRun 'blogger-hbs ${cli.matchedCommandName ? `${cli.matchedCommandName} ` : ""}--help' to see the available options`);
55
83
  }
56
84
  async function setup(root, flags) {
57
85
  const cwd = process.cwd();
@@ -352,13 +380,135 @@ async function writeTheme(current, compiled, templateFile) {
352
380
  };
353
381
  }
354
382
  /**
383
+ * Validates the theme in `file`, and with `format` formats it, written to
384
+ * `out` or to stdout. Warnings are placed in what is written, errors in
385
+ * `file`, and nothing is written when it is not valid.
386
+ */
387
+ async function processFile(file, { format, out, json }) {
388
+ if (json) {
389
+ const report = await reportOf(file, {
390
+ format,
391
+ out
392
+ });
393
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
394
+ if (!report.valid) process.exitCode = 1;
395
+ return;
396
+ }
397
+ const toStdout = format && out === void 0;
398
+ const print = toStdout ? logTo(console.error) : log;
399
+ if (!toStdout) printHeader(print.write);
400
+ const start = performance.now();
401
+ const { result, written } = await processTheme(file, {
402
+ format,
403
+ out
404
+ });
405
+ for (const { message, loc } of result.warnings) print.warn(withLocation(message, loc));
406
+ if (!format) print.success(`Validated in ${elapsed(start)}`);
407
+ else if (out === void 0) process.stdout.write(result.xml);
408
+ else print.success(`Formatted in ${elapsed(start)}, written to ${written}`);
409
+ }
410
+ /**
411
+ * Reads, processes and, with `out`, writes the theme in `file`. Its
412
+ * warnings and info are placed in what is written, and an error throws.
413
+ */
414
+ async function processTheme(file, { format, out }) {
415
+ const shown = path.relative(process.cwd(), path.resolve(file));
416
+ const xml = await readTheme(file, shown);
417
+ let result;
418
+ try {
419
+ result = processXml(xml, {
420
+ path: shown,
421
+ format
422
+ });
423
+ } catch (error) {
424
+ throw new Error(`${shown} is not valid XML`, { cause: error });
425
+ }
426
+ const written = !format ? shown : out === void 0 ? "<stdout>" : path.relative(process.cwd(), path.resolve(out));
427
+ const at = (item) => ({
428
+ ...item,
429
+ loc: {
430
+ ...item.loc,
431
+ path: written
432
+ }
433
+ });
434
+ result = {
435
+ ...result,
436
+ warnings: result.warnings.map(at),
437
+ info: {
438
+ ...result.info,
439
+ sections: result.info.sections.map(at),
440
+ widgets: result.info.widgets.map(at)
441
+ }
442
+ };
443
+ if (format && out !== void 0) {
444
+ await fs.mkdir(path.dirname(path.resolve(out)), { recursive: true });
445
+ await fs.writeFile(out, result.xml);
446
+ }
447
+ return {
448
+ result,
449
+ written
450
+ };
451
+ }
452
+ async function reportOf(file, { format, out }) {
453
+ try {
454
+ const { result, written } = await processTheme(file, {
455
+ format,
456
+ out
457
+ });
458
+ return {
459
+ valid: true,
460
+ warnings: result.warnings,
461
+ info: result.info,
462
+ ...format && out === void 0 && { xml: result.xml },
463
+ ...format && out !== void 0 && { written }
464
+ };
465
+ } catch (error) {
466
+ const cause = error instanceof Error ? error.cause : void 0;
467
+ return {
468
+ valid: false,
469
+ errors: cause instanceof XmlError ? [...cause.errors] : [{ message: messageOf(error) }]
470
+ };
471
+ }
472
+ }
473
+ /** The message of an error and of what caused it, on one line. */
474
+ function messageOf(error) {
475
+ const messages = [];
476
+ for (let current = error; current !== void 0;) {
477
+ messages.push(current instanceof Error ? current.message : String(current));
478
+ current = current instanceof Error ? current.cause : void 0;
479
+ }
480
+ return messages.join(": ");
481
+ }
482
+ /** The text of the theme in `file`, an error saying so when it can not be read. */
483
+ async function readTheme(file, shown) {
484
+ try {
485
+ return await fs.readFile(file, "utf-8");
486
+ } catch (error) {
487
+ throw new Error(`Can not read ${shown}`, { cause: error });
488
+ }
489
+ }
490
+ /** The version, the copyright and the license, where the project is, and the runtime. */
491
+ async function printVersion() {
492
+ printHeader();
493
+ const notice = await fs.readFile(new URL("../../LICENSE.md", import.meta.url), "utf-8").catch(() => "");
494
+ const copyright = /^Copyright .*$/m.exec(notice)?.[0];
495
+ console.log([
496
+ copyright,
497
+ `Released under the ${license} License, provided as is, without warranty.`,
498
+ repository.url,
499
+ "",
500
+ `Node.js ${process.version} on ${process.platform}-${process.arch}`
501
+ ].filter((line) => line !== void 0).join("\n"));
502
+ }
503
+ /**
355
504
  * A blank line, `blogger-hbs v0.0.4` right-aligned on a cyan line under it,
356
- * before what a build prints.
505
+ * before what a command prints, with `write`.
357
506
  */
358
- function printHeader() {
507
+ function printHeader(write = console.log) {
508
+ headerPrinted = true;
359
509
  const text = `blogger-hbs v${version}`;
360
510
  const width = text.length + 2;
361
- console.log(`\n${" ".repeat(width - text.length)}${styleText("bold", "blogger-hbs")} ${styleText("dim", `v${version}`)}\n${styleText("cyan", "─".repeat(width))}`);
511
+ write(`\n${" ".repeat(width - text.length)}${styleText("bold", "blogger-hbs")} ${styleText("dim", `v${version}`)}\n${styleText("cyan", "─".repeat(width))}`);
362
512
  }
363
513
  function elapsed(start) {
364
514
  return styleText("yellow", `${Math.round(performance.now() - start)}ms`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["import { type FSWatcher, watch } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { styleText } from 'node:util';\nimport { cac } from 'cac';\nimport {\n\ttype CompiledTemplate,\n\tCompileError,\n\ttype CompileTemplateOptions,\n\tcompileTemplate,\n\ttype TemplateWatcher,\n\twatchTemplate,\n} from '../compiler';\nimport {\n\tassertCompileOptions,\n\tassertDirectories,\n\tassertEntry,\n\tCOMPILE_OPTION_KEYS,\n\tresolvePaths,\n} from '../compiler/options';\nimport { type LoadedConfig, loadConfig } from '../config';\nimport { withLocation } from '../plugins';\nimport { createRenderer } from '../runtime';\nimport { didYouMean } from '../utils/suggest';\nimport {\n\tprocessXml,\n\ttype XmlError,\n\ttype XmlInfo,\n\ttype XmlResult,\n} from '../xml';\nimport {\n\ttype BuildStats,\n\tcollectStats,\n\tformatStats,\n\ttype WrittenFile,\n} from './stats';\n\nconst { version } = JSON.parse(\n\tawait fs.readFile(new URL('../../package.json', import.meta.url), 'utf-8'),\n) as { version: string };\n\ninterface BuildFlags {\n\tconfig?: string;\n\tentry?: string;\n\toutDir?: string;\n\tcontext?: string;\n\twatch?: boolean;\n\tclean?: boolean;\n\tvalidate?: boolean;\n\tformat?: boolean;\n}\n\n/** Everything a build needs, from the config file and the flags. */\ninterface BuildSetup {\n\toptions: CompileTemplateOptions;\n\tloaded: LoadedConfig;\n\toutDir: string;\n\tmoduleFile: string | false;\n\ttemplateFile: string | false;\n\tclean: boolean;\n\tcontext: unknown;\n\t/** Whether the rendered template is validated. */\n\tvalidate: boolean;\n\t/** Whether the rendered template is formatted, only when it is validated. */\n\tformat: boolean;\n\t/** Absolute path of the public directory, undefined when nothing is copied. */\n\tpublicDir?: string;\n\t/** Sizes of the files written last, by path, to show their changes when watching. */\n\tsizes: Map<string, number>;\n\t/** What the theme was made of at the last build, when watching. */\n\ttheme?: BuildStats['theme'];\n}\n\nconst log = {\n\tsuccess: (message: string) =>\n\t\tconsole.log(`${styleText('green', '✓')} ${message}`),\n\tinfo: (message: string) =>\n\t\tconsole.log(`${styleText('cyan', '●')} ${message}`),\n\twarn: (message: string) =>\n\t\tconsole.warn(`${styleText('yellow', '⚠')} ${message}`),\n\terror: (error: unknown) =>\n\t\tconsole.error(`${styleText('red', '✗')} ${formatError(error)}`),\n};\n\nconst cli = cac('blogger-hbs');\n\ncli\n\t.command('[root]', 'Compile the template and render it')\n\t.alias('build')\n\t.option('-c, --config <file>', 'Path of the config file')\n\t.option('--entry <file>', 'Entry template, relative to the root')\n\t.option('-o, --out-dir <dir>', 'Output directory, relative to the root')\n\t.option('--context <file>', 'JSON file with the context to render with')\n\t.option('-w, --watch', 'Build again when a file changes')\n\t.option('--no-clean', 'Keep the files in the output directory')\n\t.option(\n\t\t'--no-validate',\n\t\t'Do not validate the rendered template as XML, nor format it (templates are always validated when compiling)',\n\t)\n\t.option('--no-format', 'Do not format the rendered template')\n\t.example('blogger-hbs')\n\t.example('blogger-hbs --watch')\n\t.example('blogger-hbs ./theme --entry src/index.hbs --context context.json')\n\t.action(async (rootArg: unknown, rawFlags: BuildFlags) => {\n\t\tprintHeader();\n\t\t// cac turns values that look like numbers into numbers, `-o 2024`\n\t\tconst text = (value: unknown) =>\n\t\t\tvalue === undefined ? undefined : String(value);\n\t\tconst root = text(rootArg);\n\t\tconst flags: BuildFlags = {\n\t\t\t...rawFlags,\n\t\t\tconfig: text(rawFlags.config),\n\t\t\tentry: text(rawFlags.entry),\n\t\t\toutDir: text(rawFlags.outDir),\n\t\t\tcontext: text(rawFlags.context),\n\t\t};\n\n\t\tif (flags.watch) {\n\t\t\tawait watchBuild(root, flags);\n\t\t} else {\n\t\t\tawait build(root, flags);\n\t\t}\n\t});\n\ncli.help();\ncli.version(version);\n\ntry {\n\tcli.parse(process.argv, { run: false });\n\tawait cli.runMatchedCommand();\n} catch (error) {\n\tlog.error(describeCliError(error));\n\tprocess.exitCode = 1;\n}\n\n/** Adds a suggestion and a pointer to `--help` to the errors of the arguments. */\nfunction describeCliError(error: unknown): unknown {\n\tif (!(error instanceof Error) || error.name !== 'CACError') {\n\t\treturn error;\n\t}\n\n\tconst flags = [...cli.commands, cli.globalCommand].flatMap((command) =>\n\t\tcommand.options.flatMap(\n\t\t\t(option) => option.rawName.match(/--[\\w-]+/g) ?? [],\n\t\t),\n\t);\n\tconst unknown = /^Unknown option `(.+)`$/.exec(error.message)?.[1];\n\tconst hint = unknown ? didYouMean(unknown, flags, '`') : '';\n\n\treturn new Error(\n\t\t`${error.message}${hint}\\nRun 'blogger-hbs --help' to see the available options`,\n\t);\n}\n\nasync function setup(\n\troot: string | undefined,\n\tflags: BuildFlags,\n): Promise<BuildSetup> {\n\tconst cwd = process.cwd();\n\tconst rootFlag = root === undefined ? undefined : path.resolve(cwd, root);\n\n\t// the config is looked for in the root, which has to exist for that\n\tif (rootFlag !== undefined && !(await isDirectory(rootFlag))) {\n\t\tthrow new CompileError(\n\t\t\t(await exists(rootFlag))\n\t\t\t\t? `Root '${root}' is not a directory`\n\t\t\t\t: `Root directory '${root}' does not exist`,\n\t\t);\n\t}\n\n\tconst loaded = await loadConfig({\n\t\tcwd: rootFlag ?? cwd,\n\t\tconfigFile: flags.config && path.resolve(cwd, flags.config),\n\t\twatch: flags.watch,\n\t});\n\tconst { config } = loaded;\n\n\tconst resolvedRoot = rootFlag ?? config.root ?? cwd;\n\tconst output = config.output ?? {};\n\n\t// the config has more than the compile options\n\tconst options: CompileTemplateOptions = {};\n\tfor (const key of COMPILE_OPTION_KEYS) {\n\t\tif (key in config) {\n\t\t\tObject.assign(options, { [key]: config[key as keyof typeof config] });\n\t\t}\n\t}\n\toptions.root = resolvedRoot;\n\toptions.entry = flags.entry ?? config.entry;\n\toptions.onWarn ??= log.warn;\n\n\tassertCompileOptions(options);\n\tawait assertDirectories(options);\n\n\tconst outDir = path.resolve(\n\t\tresolvedRoot,\n\t\tflags.outDir ?? output.dir ?? 'dist',\n\t);\n\tconst clean = flags.clean === false ? false : (output.clean ?? true);\n\tif (clean) {\n\t\tassertCleanable(outDir, options);\n\t}\n\n\treturn {\n\t\toptions,\n\t\tloaded,\n\t\toutDir,\n\t\tmoduleFile: output.module ?? 'compiled.js',\n\t\ttemplateFile: output.template ?? 'theme.xml',\n\t\tvalidate: flags.validate === false ? false : (output.validate ?? true),\n\t\tformat: flags.format === false ? false : (output.format ?? true),\n\t\tclean,\n\t\tcontext: flags.context\n\t\t\t? await readContext(path.resolve(cwd, flags.context), flags.context)\n\t\t\t: (config.context ?? {}),\n\t\tpublicDir: await resolvePublicDir(resolvedRoot, config.publicDir, outDir),\n\t\tsizes: new Map(),\n\t};\n}\n\n/** The public directory, `public` when it exists unless set otherwise. */\nasync function resolvePublicDir(\n\troot: string,\n\tvalue: string | false | undefined,\n\toutDir: string,\n): Promise<string | undefined> {\n\tif (value === false) {\n\t\treturn;\n\t}\n\n\tconst directory = path.resolve(root, value ?? 'public');\n\tconst shown = path.relative(process.cwd(), directory) || '.';\n\n\tif (!(await isDirectory(directory))) {\n\t\tif (value === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthrow new CompileError(\n\t\t\t(await exists(directory))\n\t\t\t\t? `Public directory '${shown}' is not a directory`\n\t\t\t\t: `Public directory '${shown}' does not exist, set 'publicDir: false' to not copy anything`,\n\t\t);\n\t}\n\n\tif (isInside(outDir, directory) || isInside(directory, outDir)) {\n\t\tthrow new CompileError(\n\t\t\t`Public directory '${shown}' and output directory '${path.relative(process.cwd(), outDir) || '.'}' overlap, they must be separate`,\n\t\t);\n\t}\n\n\treturn directory;\n}\n\n/** Copies the public directory into the output directory. */\nasync function copyPublic({\n\tpublicDir,\n\toutDir,\n\tmoduleFile,\n\ttemplateFile,\n}: BuildSetup): Promise<void> {\n\tif (publicDir === undefined) {\n\t\treturn;\n\t}\n\n\tfor (const name of await fs.readdir(publicDir)) {\n\t\tif (name === moduleFile || name === templateFile) {\n\t\t\tthrow new CompileError(\n\t\t\t\t`'${name}' in the public directory has the same name as the ${name === moduleFile ? 'compiled module' : 'rendered template'} and would be overwritten, rename it or set 'output.${name === moduleFile ? 'module' : 'template'}'`,\n\t\t\t);\n\t\t}\n\t}\n\n\tawait fs.cp(publicDir, outDir, { recursive: true, force: true });\n}\n\n/**\n * Cleaning removes everything in the output directory, which must not hold the\n * project: the root, the working directory, the templates or an alias target.\n */\nfunction assertCleanable(outDir: string, options: CompileTemplateOptions) {\n\tconst { root, entry } = resolvePaths(options);\n\tconst shown = path.relative(process.cwd(), outDir) || '.';\n\tconst kept: [string, string][] = [\n\t\t[root, 'the root'],\n\t\t[process.cwd(), 'the working directory'],\n\t\t[path.dirname(entry), 'the entry template'],\n\t\t...Object.entries(options.alias ?? {}).map(\n\t\t\t([name, target]): [string, string] => [\n\t\t\t\tpath.resolve(root, target),\n\t\t\t\t`the target of the alias '${name}'`,\n\t\t\t],\n\t\t),\n\t];\n\n\tfor (const [directory, what] of kept) {\n\t\tif (isInside(directory, outDir)) {\n\t\t\tthrow new CompileError(\n\t\t\t\t`Refusing to clean the output directory '${shown}', it contains ${what}. Use another output directory, or --no-clean / 'output.clean: false' to keep its files`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nasync function readContext(file: string, shown: string): Promise<unknown> {\n\tlet text: string;\n\ttry {\n\t\ttext = await fs.readFile(file, 'utf-8');\n\t} catch (cause) {\n\t\tif ((cause as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tthrow new CompileError(`Context file '${shown}' not found`);\n\t\t}\n\t\tthrow new CompileError(`Failed to read the context file '${shown}'`, {\n\t\t\tcause,\n\t\t});\n\t}\n\n\ttry {\n\t\treturn JSON.parse(text);\n\t} catch (cause) {\n\t\tthrow new CompileError(\n\t\t\t`Context file '${shown}' is not valid JSON: ${(cause as Error).message}`,\n\t\t);\n\t}\n}\n\n/** Whether `child` is `parent` or inside of it. */\nfunction isInside(child: string, parent: string): boolean {\n\tconst relative = path.relative(parent, child);\n\treturn (\n\t\trelative === '' ||\n\t\t(!relative.startsWith('..') && !path.isAbsolute(relative))\n\t);\n}\n\nasync function exists(file: string): Promise<boolean> {\n\treturn fs.stat(file).then(\n\t\t() => true,\n\t\t() => false,\n\t);\n}\n\nasync function isDirectory(file: string): Promise<boolean> {\n\treturn fs.stat(file).then(\n\t\t(stats) => stats.isDirectory(),\n\t\t() => false,\n\t);\n}\n\nasync function build(root: string | undefined, flags: BuildFlags) {\n\tconst current = await setup(root, flags);\n\t// nothing is written when there is nothing to build, the watcher waits\n\t// for the entry instead\n\tawait assertEntry(current.options);\n\tawait prepareOutDir(current);\n\tawait copyPublic(current);\n\n\tconst start = performance.now();\n\tconst compiled = await compileTemplate(current.options);\n\tlog.success(`Compiled in ${elapsed(start)}`);\n\n\tawait write(current, compiled, start);\n}\n\n/** Watches the template and restarts when the config file changes. */\nasync function watchBuild(root: string | undefined, flags: BuildFlags) {\n\tlet current = await setup(root, flags);\n\tawait prepareOutDir(current);\n\n\tlet watcher: TemplateWatcher | undefined;\n\tlet watchers: FSWatcher[] = [];\n\tlet restarting = false;\n\n\tconst start = async () => {\n\t\tlet begin = performance.now();\n\t\tlet first = true;\n\t\t/** Shown before what a rebuild prints, after the first build. */\n\t\tlet divider = '';\n\n\t\t/** Once, before the first thing a rebuild prints, its output can be the same. */\n\t\tconst printDivider = () => {\n\t\t\tif (divider) {\n\t\t\t\tconsole.log(divider);\n\t\t\t\tdivider = '';\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tawait copyPublic(current);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\n\t\twatcher = await watchTemplate({\n\t\t\t...current.options,\n\t\t\tonStart({ files }) {\n\t\t\t\tbegin = performance.now();\n\t\t\t\tdivider = first ? '' : formatDivider(files);\n\t\t\t},\n\t\t\tasync onCompile(compiled) {\n\t\t\t\tprintDivider();\n\t\t\t\tlog.success(`${first ? 'Compiled' : 'Rebuilt'} in ${elapsed(begin)}`);\n\t\t\t\tawait write(current, compiled, begin);\n\t\t\t\tfirst = false;\n\t\t\t},\n\t\t\tonError(error) {\n\t\t\t\tprintDivider();\n\t\t\t\tlog.error(error);\n\t\t\t},\n\t\t});\n\n\t\tfor (const file of current.loaded.dependencies) {\n\t\t\ttry {\n\t\t\t\tconst configWatcher = watch(file, () => {\n\t\t\t\t\t// saving fires more than once, a restart is enough\n\t\t\t\t\tif (!restarting) {\n\t\t\t\t\t\trestarting = true;\n\t\t\t\t\t\trestart().finally(() => {\n\t\t\t\t\t\t\trestarting = false;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconfigWatcher.on('error', () => configWatcher.close());\n\t\t\t\twatchers.push(configWatcher);\n\t\t\t} catch {\n\t\t\t\t// a dependency that can not be watched does not restart\n\t\t\t}\n\t\t}\n\n\t\tif (current.publicDir !== undefined) {\n\t\t\twatchers.push(watchPublic(current));\n\t\t}\n\t};\n\n\tconst stopWatchers = () => {\n\t\tfor (const fileWatcher of watchers) {\n\t\t\tfileWatcher.close();\n\t\t}\n\t\twatchers = [];\n\t};\n\n\tconst restart = async () => {\n\t\tlog.info(\n\t\t\t`Config changed, restarting ${styleText('dim', path.relative(process.cwd(), current.loaded.file ?? ''))}`,\n\t\t);\n\t\tstopWatchers();\n\t\tawait watcher?.close();\n\t\ttry {\n\t\t\tcurrent = await setup(root, flags);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\t\tawait start();\n\t};\n\n\tawait start();\n\tlog.info(\n\t\t`Watching for changes ${styleText('dim', '(press Ctrl+C to stop)')}`,\n\t);\n\n\tconst stop = async () => {\n\t\tstopWatchers();\n\t\tawait watcher?.close();\n\t\t// the process ends once nothing is left running: `process.exit` would skip\n\t\t// the cleanup of rspack's native bindings, which then warn about leaks,\n\t\t// so it is only a fallback for something left running, a plugin's timer\n\t\tsetTimeout(() => process.exit(0), 3000).unref();\n\t};\n\tprocess.once('SIGINT', stop);\n\tprocess.once('SIGTERM', stop);\n}\n\n/** Copies the public directory again when something in it changes. */\nfunction watchPublic(current: BuildSetup): FSWatcher {\n\tconst publicDir = current.publicDir as string;\n\tconst changed = new Set<string>();\n\tlet timer: NodeJS.Timeout | undefined;\n\n\tconst sync = async () => {\n\t\tconst names = [...changed];\n\t\tchanged.clear();\n\t\ttry {\n\t\t\t// what was deleted from the public directory goes from the output too\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!(await exists(path.join(publicDir, name)))) {\n\t\t\t\t\tawait fs.rm(path.join(current.outDir, name), {\n\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t\tforce: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait copyPublic(current);\n\t\t\tlog.success(\n\t\t\t\t`Copied ${styleText('dim', path.relative(process.cwd(), publicDir))}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\t};\n\n\tconst publicWatcher = watch(\n\t\tpublicDir,\n\t\t{ recursive: true },\n\t\t(_event, name) => {\n\t\t\tif (name) {\n\t\t\t\tchanged.add(name);\n\t\t\t}\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = setTimeout(sync, 50);\n\t\t},\n\t);\n\tpublicWatcher.on('error', () => publicWatcher.close());\n\tpublicWatcher.on('close', () => clearTimeout(timer));\n\treturn publicWatcher;\n}\n\nasync function prepareOutDir({ outDir, clean }: BuildSetup) {\n\tif (clean) {\n\t\tawait fs.rm(outDir, { recursive: true, force: true });\n\t}\n\tawait fs.mkdir(outDir, { recursive: true });\n}\n\n/**\n * Writes the compiled module and the rendered template, validated and\n * formatted after rendering when enabled.\n */\nasync function write(\n\tcurrent: BuildSetup,\n\tcompiled: CompiledTemplate,\n\tbegin: number,\n) {\n\tconst { outDir, moduleFile, templateFile } = current;\n\tconst written: WrittenFile[] = [];\n\tlet theme: WrittenTheme | undefined;\n\n\tif (moduleFile) {\n\t\tconst file = path.join(outDir, moduleFile);\n\t\tawait fs.writeFile(file, compiled.source);\n\t\twritten.push({\n\t\t\tpath: path.relative(process.cwd(), file),\n\t\t\tcontent: compiled.source,\n\t\t});\n\t}\n\tif (templateFile) {\n\t\ttheme = await writeTheme(current, compiled, templateFile);\n\t\twritten.unshift(theme.file);\n\t}\n\n\tconst stats = await collectStats(\n\t\tcompiled,\n\t\twritten,\n\t\ttheme?.info && { ...theme.file, info: theme.info },\n\t);\n\tconsole.log(\n\t\tformatStats(stats, current.sizes, { previousTheme: current.theme }),\n\t);\n\tcurrent.sizes = new Map(stats.files.map(({ path, size }) => [path, size]));\n\tcurrent.theme = stats.theme;\n\tlog.success(`Built in ${elapsed(begin)}`);\n}\n\n/** `─── 14:32:05 · src/header.hbs +2 ───────`, dim. */\nfunction formatDivider(files: readonly string[]): string {\n\tconst time = new Date().toLocaleTimeString('en-GB', { hour12: false });\n\tconst [file, ...others] = files.map((item) =>\n\t\tpath.relative(process.cwd(), item),\n\t);\n\tconst what = file\n\t\t? ` · ${file}${others.length > 0 ? ` +${others.length}` : ''}`\n\t\t: '';\n\tconst text = `─── ${time}${what} `;\n\treturn `\\n${styleText('dim', text + '─'.repeat(Math.max(3, 50 - text.length)))}`;\n}\n\ninterface WrittenTheme {\n\tfile: WrittenFile;\n\t/** What it is made of, when it is validated. */\n\tinfo?: XmlInfo;\n}\n\n/** Renders, validates and formats the theme, as enabled, and writes it. */\nasync function writeTheme(\n\tcurrent: BuildSetup,\n\tcompiled: CompiledTemplate,\n\ttemplateFile: string,\n): Promise<WrittenTheme> {\n\tconst { outDir, context } = current;\n\tconst file = path.join(outDir, templateFile);\n\tconst shown = path.relative(process.cwd(), file);\n\n\t// the same as anywhere else the compiled module is rendered\n\tlet start = performance.now();\n\tconst renderer = createRenderer(compiled);\n\tconst rendered = await renderer.render(context);\n\tlog.success(`Rendered in ${elapsed(start)}`);\n\n\tif (!current.validate) {\n\t\tawait fs.writeFile(file, rendered);\n\t\treturn { file: { path: shown, content: rendered } };\n\t}\n\n\tstart = performance.now();\n\tlet result: XmlResult;\n\ttry {\n\t\tresult = processXml(rendered, { path: shown, format: current.format });\n\t} catch (error) {\n\t\t// written anyway, to look at where it is invalid\n\t\tawait fs.writeFile(file, rendered);\n\t\tthrow new CompileError('The rendered template is not valid XML', {\n\t\t\tcause: error,\n\t\t\tloc: (error as XmlError).loc,\n\t\t});\n\t}\n\tfor (const { message, loc } of result.warnings) {\n\t\tlog.warn(withLocation(message, loc));\n\t}\n\tlog.success(\n\t\t`${current.format ? 'Formatted' : 'Validated'} in ${elapsed(start)}`,\n\t);\n\n\tawait fs.writeFile(file, result.xml);\n\treturn { file: { path: shown, content: result.xml }, info: result.info };\n}\n\n/**\n * A blank line, `blogger-hbs v0.0.4` right-aligned on a cyan line under it,\n * before what a build prints.\n */\nfunction printHeader(): void {\n\tconst text = `blogger-hbs v${version}`;\n\tconst width = text.length + 2;\n\tconsole.log(\n\t\t`\\n${' '.repeat(width - text.length)}${styleText('bold', 'blogger-hbs')} ${styleText('dim', `v${version}`)}\\n${styleText('cyan', '─'.repeat(width))}`,\n\t);\n}\n\nfunction elapsed(start: number): string {\n\treturn styleText('yellow', `${Math.round(performance.now() - start)}ms`);\n}\n\n/**\n * The message of the error and of everything that caused it, a cause whose\n * message is already in the one before is not repeated. The lines of a\n * message are indented under its first.\n */\nfunction formatError(error: unknown): string {\n\tconst lines: string[] = [];\n\tlet previous = '';\n\tlet current: unknown = error;\n\n\twhile (current !== undefined) {\n\t\tconst message =\n\t\t\tcurrent instanceof Error ? current.message : String(current);\n\t\tif (lines.length === 0 || !previous.includes(message)) {\n\t\t\tlines.push(\n\t\t\t\t`${lines.length === 0 ? '' : 'Caused by: '}${message.replaceAll('\\n', '\\n ')}`,\n\t\t\t);\n\t\t}\n\t\tprevious = message;\n\t\tcurrent = current instanceof Error ? current.cause : undefined;\n\t}\n\n\treturn lines.join('\\n ');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/cli/index.ts"],"sourcesContent":["import { type FSWatcher, watch } from 'node:fs';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { styleText } from 'node:util';\nimport { cac } from 'cac';\nimport {\n\ttype CompiledTemplate,\n\tCompileError,\n\ttype CompileTemplateOptions,\n\tcompileTemplate,\n\ttype TemplateWatcher,\n\twatchTemplate,\n} from '../compiler';\nimport {\n\tassertCompileOptions,\n\tassertDirectories,\n\tassertEntry,\n\tCOMPILE_OPTION_KEYS,\n\tresolvePaths,\n} from '../compiler/options';\nimport { type LoadedConfig, loadConfig } from '../config';\nimport { type Location, withLocation } from '../plugins';\nimport { createRenderer } from '../runtime';\nimport { didYouMean } from '../utils/suggest';\nimport { processXml, XmlError, type XmlInfo, type XmlResult } from '../xml';\nimport {\n\ttype BuildStats,\n\tcollectStats,\n\tformatStats,\n\ttype WrittenFile,\n} from './stats';\n\nconst { version, license, repository } = JSON.parse(\n\tawait fs.readFile(new URL('../../package.json', import.meta.url), 'utf-8'),\n) as { version: string; license: string; repository: { url: string } };\n\ninterface BuildFlags {\n\tconfig?: string;\n\tentry?: string;\n\toutDir?: string;\n\tcontext?: string;\n\twatch?: boolean;\n\tclean?: boolean;\n\tvalidate?: boolean;\n\tformat?: boolean;\n}\n\n/** Everything a build needs, from the config file and the flags. */\ninterface BuildSetup {\n\toptions: CompileTemplateOptions;\n\tloaded: LoadedConfig;\n\toutDir: string;\n\tmoduleFile: string | false;\n\ttemplateFile: string | false;\n\tclean: boolean;\n\tcontext: unknown;\n\t/** Whether the rendered template is validated. */\n\tvalidate: boolean;\n\t/** Whether the rendered template is formatted, only when it is validated. */\n\tformat: boolean;\n\t/** Absolute path of the public directory, undefined when nothing is copied. */\n\tpublicDir?: string;\n\t/** Sizes of the files written last, by path, to show their changes when watching. */\n\tsizes: Map<string, number>;\n\t/** What the theme was made of at the last build, when watching. */\n\ttheme?: BuildStats['theme'];\n}\n\n/** What the CLI prints, with `write`, warnings and errors on stderr. */\nfunction logTo(write: (text: string) => void) {\n\treturn {\n\t\twrite,\n\t\tsuccess: (message: string) =>\n\t\t\twrite(`${styleText('green', '✓')} ${message}`),\n\t\tinfo: (message: string) => write(`${styleText('cyan', '●')} ${message}`),\n\t\twarn: (message: string) =>\n\t\t\tconsole.warn(`${styleText('yellow', '⚠')} ${message}`),\n\t\terror: (error: unknown) =>\n\t\t\tconsole.error(`${styleText('red', '✗')} ${formatError(error)}`),\n\t};\n}\n\nconst log = logTo(console.log);\n\nconst cli = cac('blogger-hbs');\n\ncli\n\t.command('[root]', 'Compile the template and render it')\n\t.alias('build')\n\t.option('-c, --config <file>', 'Path of the config file')\n\t.option('--entry <file>', 'Entry template, relative to the root')\n\t.option('-o, --out-dir <dir>', 'Output directory, relative to the root')\n\t.option('--context <file>', 'JSON file with the context to render with')\n\t.option('-w, --watch', 'Build again when a file changes')\n\t.option('--no-clean', 'Keep the files in the output directory')\n\t.option(\n\t\t'--no-validate',\n\t\t'Do not validate the rendered template as XML, nor format it (templates are always validated when compiling)',\n\t)\n\t.option('--no-format', 'Do not format the rendered template')\n\t.example('blogger-hbs')\n\t.example('blogger-hbs --watch')\n\t.example('blogger-hbs ./theme --entry src/index.hbs --context context.json')\n\t.action(async (rootArg: unknown, rawFlags: BuildFlags) => {\n\t\tprintHeader();\n\t\t// cac turns values that look like numbers into numbers, `-o 2024`\n\t\tconst text = (value: unknown) =>\n\t\t\tvalue === undefined ? undefined : String(value);\n\t\tconst root = text(rootArg);\n\t\tconst flags: BuildFlags = {\n\t\t\t...rawFlags,\n\t\t\tconfig: text(rawFlags.config),\n\t\t\tentry: text(rawFlags.entry),\n\t\t\toutDir: text(rawFlags.outDir),\n\t\t\tcontext: text(rawFlags.context),\n\t\t};\n\n\t\tif (flags.watch) {\n\t\t\tawait watchBuild(root, flags);\n\t\t} else {\n\t\t\tawait build(root, flags);\n\t\t}\n\t});\n\ncli\n\t.command('validate <file>', 'Validate a theme as Blogger reads it')\n\t.option('--json', 'Print the result as JSON')\n\t.example('blogger-hbs validate dist/theme.xml')\n\t.example('blogger-hbs validate dist/theme.xml --json')\n\t.action(async (file: unknown, flags: { json?: boolean }) => {\n\t\tawait processFile(String(file), { format: false, json: flags.json });\n\t});\n\ncli\n\t.command(\n\t\t'format <file>',\n\t\t'Format a theme as Blogger saves it, written to stdout, or to --out',\n\t)\n\t.option('-o, --out <file>', 'Write it to this file instead of stdout')\n\t.option('--json', 'Print the result as JSON, the theme in it without --out')\n\t.example('blogger-hbs format theme.xml')\n\t.example('blogger-hbs format theme.xml -o theme.formatted.xml')\n\t.action(async (file: unknown, flags: { out?: unknown; json?: boolean }) => {\n\t\tconst out = flags.out === undefined ? undefined : String(flags.out);\n\t\tawait processFile(String(file), { format: true, out, json: flags.json });\n\t});\n\ncli.help();\n// cac's own `--version` prints `name/version platform`, this one says more,\n// and the help still has the version in its heading\ncli.globalCommand.versionNumber = version;\ncli.option(\n\t'-v, --version',\n\t'Display the version, the copyright and the license',\n);\n\n/** Whether the header is printed, so that an error before a command runs prints it too. */\nlet headerPrinted = false;\n\ntry {\n\tcli.parse(process.argv, { run: false });\n\tif (cli.options.version) {\n\t\tawait printVersion();\n\t} else {\n\t\tawait cli.runMatchedCommand();\n\t}\n} catch (error) {\n\t// with the theme on stdout, the header of an error is on stderr with it\n\tif (!headerPrinted && !cli.options.json) {\n\t\tprintHeader(formatsToStdout() ? console.error : console.log);\n\t}\n\tlog.error(describeCliError(error));\n\tprocess.exitCode = 1;\n}\n\n/** Whether the command formats a theme to stdout, which has nothing else on it. */\nfunction formatsToStdout(): boolean {\n\treturn cli.matchedCommandName === 'format' && cli.options.out === undefined;\n}\n\n/** Adds a suggestion and a pointer to `--help` to the errors of the arguments. */\nfunction describeCliError(error: unknown): unknown {\n\tif (!(error instanceof Error) || error.name !== 'CACError') {\n\t\treturn error;\n\t}\n\n\tconst flags = [...cli.commands, cli.globalCommand].flatMap((command) =>\n\t\tcommand.options.flatMap(\n\t\t\t(option) => option.rawName.match(/--[\\w-]+/g) ?? [],\n\t\t),\n\t);\n\tconst unknown = /^Unknown option `(.+)`$/.exec(error.message)?.[1];\n\tconst hint = unknown ? didYouMean(unknown, flags, '`') : '';\n\n\treturn new Error(\n\t\t`${error.message}${hint}\\nRun 'blogger-hbs ${cli.matchedCommandName ? `${cli.matchedCommandName} ` : ''}--help' to see the available options`,\n\t);\n}\n\nasync function setup(\n\troot: string | undefined,\n\tflags: BuildFlags,\n): Promise<BuildSetup> {\n\tconst cwd = process.cwd();\n\tconst rootFlag = root === undefined ? undefined : path.resolve(cwd, root);\n\n\t// the config is looked for in the root, which has to exist for that\n\tif (rootFlag !== undefined && !(await isDirectory(rootFlag))) {\n\t\tthrow new CompileError(\n\t\t\t(await exists(rootFlag))\n\t\t\t\t? `Root '${root}' is not a directory`\n\t\t\t\t: `Root directory '${root}' does not exist`,\n\t\t);\n\t}\n\n\tconst loaded = await loadConfig({\n\t\tcwd: rootFlag ?? cwd,\n\t\tconfigFile: flags.config && path.resolve(cwd, flags.config),\n\t\twatch: flags.watch,\n\t});\n\tconst { config } = loaded;\n\n\tconst resolvedRoot = rootFlag ?? config.root ?? cwd;\n\tconst output = config.output ?? {};\n\n\t// the config has more than the compile options\n\tconst options: CompileTemplateOptions = {};\n\tfor (const key of COMPILE_OPTION_KEYS) {\n\t\tif (key in config) {\n\t\t\tObject.assign(options, { [key]: config[key as keyof typeof config] });\n\t\t}\n\t}\n\toptions.root = resolvedRoot;\n\toptions.entry = flags.entry ?? config.entry;\n\toptions.onWarn ??= log.warn;\n\n\tassertCompileOptions(options);\n\tawait assertDirectories(options);\n\n\tconst outDir = path.resolve(\n\t\tresolvedRoot,\n\t\tflags.outDir ?? output.dir ?? 'dist',\n\t);\n\tconst clean = flags.clean === false ? false : (output.clean ?? true);\n\tif (clean) {\n\t\tassertCleanable(outDir, options);\n\t}\n\n\treturn {\n\t\toptions,\n\t\tloaded,\n\t\toutDir,\n\t\tmoduleFile: output.module ?? 'compiled.js',\n\t\ttemplateFile: output.template ?? 'theme.xml',\n\t\tvalidate: flags.validate === false ? false : (output.validate ?? true),\n\t\tformat: flags.format === false ? false : (output.format ?? true),\n\t\tclean,\n\t\tcontext: flags.context\n\t\t\t? await readContext(path.resolve(cwd, flags.context), flags.context)\n\t\t\t: (config.context ?? {}),\n\t\tpublicDir: await resolvePublicDir(resolvedRoot, config.publicDir, outDir),\n\t\tsizes: new Map(),\n\t};\n}\n\n/** The public directory, `public` when it exists unless set otherwise. */\nasync function resolvePublicDir(\n\troot: string,\n\tvalue: string | false | undefined,\n\toutDir: string,\n): Promise<string | undefined> {\n\tif (value === false) {\n\t\treturn;\n\t}\n\n\tconst directory = path.resolve(root, value ?? 'public');\n\tconst shown = path.relative(process.cwd(), directory) || '.';\n\n\tif (!(await isDirectory(directory))) {\n\t\tif (value === undefined) {\n\t\t\treturn;\n\t\t}\n\t\tthrow new CompileError(\n\t\t\t(await exists(directory))\n\t\t\t\t? `Public directory '${shown}' is not a directory`\n\t\t\t\t: `Public directory '${shown}' does not exist, set 'publicDir: false' to not copy anything`,\n\t\t);\n\t}\n\n\tif (isInside(outDir, directory) || isInside(directory, outDir)) {\n\t\tthrow new CompileError(\n\t\t\t`Public directory '${shown}' and output directory '${path.relative(process.cwd(), outDir) || '.'}' overlap, they must be separate`,\n\t\t);\n\t}\n\n\treturn directory;\n}\n\n/** Copies the public directory into the output directory. */\nasync function copyPublic({\n\tpublicDir,\n\toutDir,\n\tmoduleFile,\n\ttemplateFile,\n}: BuildSetup): Promise<void> {\n\tif (publicDir === undefined) {\n\t\treturn;\n\t}\n\n\tfor (const name of await fs.readdir(publicDir)) {\n\t\tif (name === moduleFile || name === templateFile) {\n\t\t\tthrow new CompileError(\n\t\t\t\t`'${name}' in the public directory has the same name as the ${name === moduleFile ? 'compiled module' : 'rendered template'} and would be overwritten, rename it or set 'output.${name === moduleFile ? 'module' : 'template'}'`,\n\t\t\t);\n\t\t}\n\t}\n\n\tawait fs.cp(publicDir, outDir, { recursive: true, force: true });\n}\n\n/**\n * Cleaning removes everything in the output directory, which must not hold the\n * project: the root, the working directory, the templates or an alias target.\n */\nfunction assertCleanable(outDir: string, options: CompileTemplateOptions) {\n\tconst { root, entry } = resolvePaths(options);\n\tconst shown = path.relative(process.cwd(), outDir) || '.';\n\tconst kept: [string, string][] = [\n\t\t[root, 'the root'],\n\t\t[process.cwd(), 'the working directory'],\n\t\t[path.dirname(entry), 'the entry template'],\n\t\t...Object.entries(options.alias ?? {}).map(\n\t\t\t([name, target]): [string, string] => [\n\t\t\t\tpath.resolve(root, target),\n\t\t\t\t`the target of the alias '${name}'`,\n\t\t\t],\n\t\t),\n\t];\n\n\tfor (const [directory, what] of kept) {\n\t\tif (isInside(directory, outDir)) {\n\t\t\tthrow new CompileError(\n\t\t\t\t`Refusing to clean the output directory '${shown}', it contains ${what}. Use another output directory, or --no-clean / 'output.clean: false' to keep its files`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nasync function readContext(file: string, shown: string): Promise<unknown> {\n\tlet text: string;\n\ttry {\n\t\ttext = await fs.readFile(file, 'utf-8');\n\t} catch (cause) {\n\t\tif ((cause as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tthrow new CompileError(`Context file '${shown}' not found`);\n\t\t}\n\t\tthrow new CompileError(`Failed to read the context file '${shown}'`, {\n\t\t\tcause,\n\t\t});\n\t}\n\n\ttry {\n\t\treturn JSON.parse(text);\n\t} catch (cause) {\n\t\tthrow new CompileError(\n\t\t\t`Context file '${shown}' is not valid JSON: ${(cause as Error).message}`,\n\t\t);\n\t}\n}\n\n/** Whether `child` is `parent` or inside of it. */\nfunction isInside(child: string, parent: string): boolean {\n\tconst relative = path.relative(parent, child);\n\treturn (\n\t\trelative === '' ||\n\t\t(!relative.startsWith('..') && !path.isAbsolute(relative))\n\t);\n}\n\nasync function exists(file: string): Promise<boolean> {\n\treturn fs.stat(file).then(\n\t\t() => true,\n\t\t() => false,\n\t);\n}\n\nasync function isDirectory(file: string): Promise<boolean> {\n\treturn fs.stat(file).then(\n\t\t(stats) => stats.isDirectory(),\n\t\t() => false,\n\t);\n}\n\nasync function build(root: string | undefined, flags: BuildFlags) {\n\tconst current = await setup(root, flags);\n\t// nothing is written when there is nothing to build, the watcher waits\n\t// for the entry instead\n\tawait assertEntry(current.options);\n\tawait prepareOutDir(current);\n\tawait copyPublic(current);\n\n\tconst start = performance.now();\n\tconst compiled = await compileTemplate(current.options);\n\tlog.success(`Compiled in ${elapsed(start)}`);\n\n\tawait write(current, compiled, start);\n}\n\n/** Watches the template and restarts when the config file changes. */\nasync function watchBuild(root: string | undefined, flags: BuildFlags) {\n\tlet current = await setup(root, flags);\n\tawait prepareOutDir(current);\n\n\tlet watcher: TemplateWatcher | undefined;\n\tlet watchers: FSWatcher[] = [];\n\tlet restarting = false;\n\n\tconst start = async () => {\n\t\tlet begin = performance.now();\n\t\tlet first = true;\n\t\t/** Shown before what a rebuild prints, after the first build. */\n\t\tlet divider = '';\n\n\t\t/** Once, before the first thing a rebuild prints, its output can be the same. */\n\t\tconst printDivider = () => {\n\t\t\tif (divider) {\n\t\t\t\tconsole.log(divider);\n\t\t\t\tdivider = '';\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\tawait copyPublic(current);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\n\t\twatcher = await watchTemplate({\n\t\t\t...current.options,\n\t\t\tonStart({ files }) {\n\t\t\t\tbegin = performance.now();\n\t\t\t\tdivider = first ? '' : formatDivider(files);\n\t\t\t},\n\t\t\tasync onCompile(compiled) {\n\t\t\t\tprintDivider();\n\t\t\t\tlog.success(`${first ? 'Compiled' : 'Rebuilt'} in ${elapsed(begin)}`);\n\t\t\t\tawait write(current, compiled, begin);\n\t\t\t\tfirst = false;\n\t\t\t},\n\t\t\tonError(error) {\n\t\t\t\tprintDivider();\n\t\t\t\tlog.error(error);\n\t\t\t},\n\t\t});\n\n\t\tfor (const file of current.loaded.dependencies) {\n\t\t\ttry {\n\t\t\t\tconst configWatcher = watch(file, () => {\n\t\t\t\t\t// saving fires more than once, a restart is enough\n\t\t\t\t\tif (!restarting) {\n\t\t\t\t\t\trestarting = true;\n\t\t\t\t\t\trestart().finally(() => {\n\t\t\t\t\t\t\trestarting = false;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tconfigWatcher.on('error', () => configWatcher.close());\n\t\t\t\twatchers.push(configWatcher);\n\t\t\t} catch {\n\t\t\t\t// a dependency that can not be watched does not restart\n\t\t\t}\n\t\t}\n\n\t\tif (current.publicDir !== undefined) {\n\t\t\twatchers.push(watchPublic(current));\n\t\t}\n\t};\n\n\tconst stopWatchers = () => {\n\t\tfor (const fileWatcher of watchers) {\n\t\t\tfileWatcher.close();\n\t\t}\n\t\twatchers = [];\n\t};\n\n\tconst restart = async () => {\n\t\tlog.info(\n\t\t\t`Config changed, restarting ${styleText('dim', path.relative(process.cwd(), current.loaded.file ?? ''))}`,\n\t\t);\n\t\tstopWatchers();\n\t\tawait watcher?.close();\n\t\ttry {\n\t\t\tcurrent = await setup(root, flags);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\t\tawait start();\n\t};\n\n\tawait start();\n\tlog.info(\n\t\t`Watching for changes ${styleText('dim', '(press Ctrl+C to stop)')}`,\n\t);\n\n\tconst stop = async () => {\n\t\tstopWatchers();\n\t\tawait watcher?.close();\n\t\t// the process ends once nothing is left running: `process.exit` would skip\n\t\t// the cleanup of rspack's native bindings, which then warn about leaks,\n\t\t// so it is only a fallback for something left running, a plugin's timer\n\t\tsetTimeout(() => process.exit(0), 3000).unref();\n\t};\n\tprocess.once('SIGINT', stop);\n\tprocess.once('SIGTERM', stop);\n}\n\n/** Copies the public directory again when something in it changes. */\nfunction watchPublic(current: BuildSetup): FSWatcher {\n\tconst publicDir = current.publicDir as string;\n\tconst changed = new Set<string>();\n\tlet timer: NodeJS.Timeout | undefined;\n\n\tconst sync = async () => {\n\t\tconst names = [...changed];\n\t\tchanged.clear();\n\t\ttry {\n\t\t\t// what was deleted from the public directory goes from the output too\n\t\t\tfor (const name of names) {\n\t\t\t\tif (!(await exists(path.join(publicDir, name)))) {\n\t\t\t\t\tawait fs.rm(path.join(current.outDir, name), {\n\t\t\t\t\t\trecursive: true,\n\t\t\t\t\t\tforce: true,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tawait copyPublic(current);\n\t\t\tlog.success(\n\t\t\t\t`Copied ${styleText('dim', path.relative(process.cwd(), publicDir))}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlog.error(error);\n\t\t}\n\t};\n\n\tconst publicWatcher = watch(\n\t\tpublicDir,\n\t\t{ recursive: true },\n\t\t(_event, name) => {\n\t\t\tif (name) {\n\t\t\t\tchanged.add(name);\n\t\t\t}\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = setTimeout(sync, 50);\n\t\t},\n\t);\n\tpublicWatcher.on('error', () => publicWatcher.close());\n\tpublicWatcher.on('close', () => clearTimeout(timer));\n\treturn publicWatcher;\n}\n\nasync function prepareOutDir({ outDir, clean }: BuildSetup) {\n\tif (clean) {\n\t\tawait fs.rm(outDir, { recursive: true, force: true });\n\t}\n\tawait fs.mkdir(outDir, { recursive: true });\n}\n\n/**\n * Writes the compiled module and the rendered template, validated and\n * formatted after rendering when enabled.\n */\nasync function write(\n\tcurrent: BuildSetup,\n\tcompiled: CompiledTemplate,\n\tbegin: number,\n) {\n\tconst { outDir, moduleFile, templateFile } = current;\n\tconst written: WrittenFile[] = [];\n\tlet theme: WrittenTheme | undefined;\n\n\tif (moduleFile) {\n\t\tconst file = path.join(outDir, moduleFile);\n\t\tawait fs.writeFile(file, compiled.source);\n\t\twritten.push({\n\t\t\tpath: path.relative(process.cwd(), file),\n\t\t\tcontent: compiled.source,\n\t\t});\n\t}\n\tif (templateFile) {\n\t\ttheme = await writeTheme(current, compiled, templateFile);\n\t\twritten.unshift(theme.file);\n\t}\n\n\tconst stats = await collectStats(\n\t\tcompiled,\n\t\twritten,\n\t\ttheme?.info && { ...theme.file, info: theme.info },\n\t);\n\tconsole.log(\n\t\tformatStats(stats, current.sizes, { previousTheme: current.theme }),\n\t);\n\tcurrent.sizes = new Map(stats.files.map(({ path, size }) => [path, size]));\n\tcurrent.theme = stats.theme;\n\tlog.success(`Built in ${elapsed(begin)}`);\n}\n\n/** `─── 14:32:05 · src/header.hbs +2 ───────`, dim. */\nfunction formatDivider(files: readonly string[]): string {\n\tconst time = new Date().toLocaleTimeString('en-GB', { hour12: false });\n\tconst [file, ...others] = files.map((item) =>\n\t\tpath.relative(process.cwd(), item),\n\t);\n\tconst what = file\n\t\t? ` · ${file}${others.length > 0 ? ` +${others.length}` : ''}`\n\t\t: '';\n\tconst text = `─── ${time}${what} `;\n\treturn `\\n${styleText('dim', text + '─'.repeat(Math.max(3, 50 - text.length)))}`;\n}\n\ninterface WrittenTheme {\n\tfile: WrittenFile;\n\t/** What it is made of, when it is validated. */\n\tinfo?: XmlInfo;\n}\n\n/** Renders, validates and formats the theme, as enabled, and writes it. */\nasync function writeTheme(\n\tcurrent: BuildSetup,\n\tcompiled: CompiledTemplate,\n\ttemplateFile: string,\n): Promise<WrittenTheme> {\n\tconst { outDir, context } = current;\n\tconst file = path.join(outDir, templateFile);\n\tconst shown = path.relative(process.cwd(), file);\n\n\t// the same as anywhere else the compiled module is rendered\n\tlet start = performance.now();\n\tconst renderer = createRenderer(compiled);\n\tconst rendered = await renderer.render(context);\n\tlog.success(`Rendered in ${elapsed(start)}`);\n\n\tif (!current.validate) {\n\t\tawait fs.writeFile(file, rendered);\n\t\treturn { file: { path: shown, content: rendered } };\n\t}\n\n\tstart = performance.now();\n\tlet result: XmlResult;\n\ttry {\n\t\tresult = processXml(rendered, { path: shown, format: current.format });\n\t} catch (error) {\n\t\t// written anyway, to look at where it is invalid\n\t\tawait fs.writeFile(file, rendered);\n\t\tthrow new CompileError('The rendered template is not valid XML', {\n\t\t\tcause: error,\n\t\t\tloc: (error as XmlError).loc,\n\t\t});\n\t}\n\tfor (const { message, loc } of result.warnings) {\n\t\tlog.warn(withLocation(message, loc));\n\t}\n\tlog.success(\n\t\t`${current.format ? 'Formatted' : 'Validated'} in ${elapsed(start)}`,\n\t);\n\n\tawait fs.writeFile(file, result.xml);\n\treturn { file: { path: shown, content: result.xml }, info: result.info };\n}\n\ninterface ProcessFileOptions {\n\tformat: boolean;\n\t/** The file to write the formatted theme to, stdout without it. */\n\tout?: string;\n\t/** Whether to print the result as JSON, alone on stdout. */\n\tjson?: boolean;\n}\n\n/**\n * Validates the theme in `file`, and with `format` formats it, written to\n * `out` or to stdout. Warnings are placed in what is written, errors in\n * `file`, and nothing is written when it is not valid.\n */\nasync function processFile(\n\tfile: string,\n\t{ format, out, json }: ProcessFileOptions,\n): Promise<void> {\n\tif (json) {\n\t\tconst report = await reportOf(file, { format, out });\n\t\tprocess.stdout.write(`${JSON.stringify(report, null, 2)}\\n`);\n\t\tif (!report.valid) {\n\t\t\tprocess.exitCode = 1;\n\t\t}\n\t\treturn;\n\t}\n\n\t// a formatted theme on stdout has it to itself\n\tconst toStdout = format && out === undefined;\n\tconst print = toStdout ? logTo(console.error) : log;\n\t// on stdout, only the theme, with warnings and errors besides it\n\tif (!toStdout) {\n\t\tprintHeader(print.write);\n\t}\n\n\tconst start = performance.now();\n\tconst { result, written } = await processTheme(file, { format, out });\n\tfor (const { message, loc } of result.warnings) {\n\t\tprint.warn(withLocation(message, loc));\n\t}\n\n\tif (!format) {\n\t\tprint.success(`Validated in ${elapsed(start)}`);\n\t} else if (out === undefined) {\n\t\tprocess.stdout.write(result.xml);\n\t} else {\n\t\tprint.success(`Formatted in ${elapsed(start)}, written to ${written}`);\n\t}\n}\n\n/**\n * Reads, processes and, with `out`, writes the theme in `file`. Its\n * warnings and info are placed in what is written, and an error throws.\n */\nasync function processTheme(\n\tfile: string,\n\t{ format, out }: ProcessFileOptions,\n): Promise<{ result: XmlResult; written: string }> {\n\tconst shown = path.relative(process.cwd(), path.resolve(file));\n\tconst xml = await readTheme(file, shown);\n\n\tlet result: XmlResult;\n\ttry {\n\t\tresult = processXml(xml, { path: shown, format });\n\t} catch (error) {\n\t\tthrow new Error(`${shown} is not valid XML`, { cause: error });\n\t}\n\n\tconst written = !format\n\t\t? shown\n\t\t: out === undefined\n\t\t\t? '<stdout>'\n\t\t\t: path.relative(process.cwd(), path.resolve(out));\n\tconst at = <T extends { loc: Location }>(item: T): T => ({\n\t\t...item,\n\t\tloc: { ...item.loc, path: written },\n\t});\n\tresult = {\n\t\t...result,\n\t\twarnings: result.warnings.map(at),\n\t\tinfo: {\n\t\t\t...result.info,\n\t\t\tsections: result.info.sections.map(at),\n\t\t\twidgets: result.info.widgets.map(at),\n\t\t},\n\t};\n\n\tif (format && out !== undefined) {\n\t\tawait fs.mkdir(path.dirname(path.resolve(out)), { recursive: true });\n\t\tawait fs.writeFile(out, result.xml);\n\t}\n\treturn { result, written };\n}\n\n/** What `--json` prints: the result of a valid theme, or every error. */\ntype Report =\n\t| {\n\t\t\tvalid: true;\n\t\t\twarnings: XmlResult['warnings'];\n\t\t\tinfo: XmlResult['info'];\n\t\t\t/** The formatted theme, without `--out`. */\n\t\t\txml?: string;\n\t\t\t/** Where the formatted theme is written, with `--out`. */\n\t\t\twritten?: string;\n\t }\n\t| { valid: false; errors: { message: string; loc?: Location }[] };\n\nasync function reportOf(\n\tfile: string,\n\t{ format, out }: ProcessFileOptions,\n): Promise<Report> {\n\ttry {\n\t\tconst { result, written } = await processTheme(file, { format, out });\n\t\treturn {\n\t\t\tvalid: true,\n\t\t\twarnings: result.warnings,\n\t\t\tinfo: result.info,\n\t\t\t...(format && out === undefined && { xml: result.xml }),\n\t\t\t...(format && out !== undefined && { written }),\n\t\t};\n\t} catch (error) {\n\t\tconst cause = error instanceof Error ? error.cause : undefined;\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors:\n\t\t\t\tcause instanceof XmlError\n\t\t\t\t\t? [...cause.errors]\n\t\t\t\t\t: [{ message: messageOf(error) }],\n\t\t};\n\t}\n}\n\n/** The message of an error and of what caused it, on one line. */\nfunction messageOf(error: unknown): string {\n\tconst messages: string[] = [];\n\tfor (let current: unknown = error; current !== undefined; ) {\n\t\tmessages.push(current instanceof Error ? current.message : String(current));\n\t\tcurrent = current instanceof Error ? current.cause : undefined;\n\t}\n\treturn messages.join(': ');\n}\n\n/** The text of the theme in `file`, an error saying so when it can not be read. */\nasync function readTheme(file: string, shown: string): Promise<string> {\n\ttry {\n\t\treturn await fs.readFile(file, 'utf-8');\n\t} catch (error) {\n\t\tthrow new Error(`Can not read ${shown}`, { cause: error });\n\t}\n}\n\n/** The version, the copyright and the license, where the project is, and the runtime. */\nasync function printVersion(): Promise<void> {\n\tprintHeader();\n\t// the copyright of the license, npm publishing it with the package\n\tconst notice = await fs\n\t\t.readFile(new URL('../../LICENSE.md', import.meta.url), 'utf-8')\n\t\t.catch(() => '');\n\tconst copyright = /^Copyright .*$/m.exec(notice)?.[0];\n\tconsole.log(\n\t\t[\n\t\t\tcopyright,\n\t\t\t`Released under the ${license} License, provided as is, without warranty.`,\n\t\t\trepository.url,\n\t\t\t'',\n\t\t\t`Node.js ${process.version} on ${process.platform}-${process.arch}`,\n\t\t]\n\t\t\t.filter((line) => line !== undefined)\n\t\t\t.join('\\n'),\n\t);\n}\n\n/**\n * A blank line, `blogger-hbs v0.0.4` right-aligned on a cyan line under it,\n * before what a command prints, with `write`.\n */\nfunction printHeader(write: (text: string) => void = console.log): void {\n\theaderPrinted = true;\n\tconst text = `blogger-hbs v${version}`;\n\tconst width = text.length + 2;\n\twrite(\n\t\t`\\n${' '.repeat(width - text.length)}${styleText('bold', 'blogger-hbs')} ${styleText('dim', `v${version}`)}\\n${styleText('cyan', '─'.repeat(width))}`,\n\t);\n}\n\nfunction elapsed(start: number): string {\n\treturn styleText('yellow', `${Math.round(performance.now() - start)}ms`);\n}\n\n/**\n * The message of the error and of everything that caused it, a cause whose\n * message is already in the one before is not repeated. The lines of a\n * message are indented under its first.\n */\nfunction formatError(error: unknown): string {\n\tconst lines: string[] = [];\n\tlet previous = '';\n\tlet current: unknown = error;\n\n\twhile (current !== undefined) {\n\t\tconst message =\n\t\t\tcurrent instanceof Error ? current.message : String(current);\n\t\tif (lines.length === 0 || !previous.includes(message)) {\n\t\t\tlines.push(\n\t\t\t\t`${lines.length === 0 ? '' : 'Caused by: '}${message.replaceAll('\\n', '\\n ')}`,\n\t\t\t);\n\t\t}\n\t\tprevious = message;\n\t\tcurrent = current instanceof Error ? current.cause : undefined;\n\t}\n\n\treturn lines.join('\\n ');\n}\n"],"mappings":"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"}
@@ -1,27 +1,8 @@
1
- import { ATTRIBUTE_NAME_REGEX } from "../../constants.js";
1
+ import { ATTRIBUTE_NAME_REGEX, OUTPUT_FLAGS } from "../../constants.js";
2
2
  import { walk } from "./walk.js";
3
3
  //#region src/compiler/ast/imports.ts
4
4
  const ASSET_KEYS = /* @__PURE__ */ new Set(["script", "style"]);
5
5
  const ASSET_ATTRIBUTE_REGEX = /^(?:script|style):(.+)$/s;
6
- /** Options rendering only the script or the styles of an import, raw without a tag. */
7
- const FLAG_KEYS = /* @__PURE__ */ new Map([
8
- ["script:raw", {
9
- tag: "script",
10
- raw: true
11
- }],
12
- ["style:raw", {
13
- tag: "style",
14
- raw: true
15
- }],
16
- ["script:only", {
17
- tag: "script",
18
- raw: false
19
- }],
20
- ["style:only", {
21
- tag: "style",
22
- raw: false
23
- }]
24
- ]);
25
6
  function extractImports(node) {
26
7
  const imports = [];
27
8
  for (const importNode of extractImportNodes(node)) {
@@ -73,7 +54,7 @@ function extractImports(node) {
73
54
  }
74
55
  continue;
75
56
  }
76
- if (FLAG_KEYS.has(key)) {
57
+ if (OUTPUT_FLAGS.has(key)) {
77
58
  if (!isFlagValue(value)) {
78
59
  reason = `'import' option '${key}' must be true, 'true' or '', got: ${describeValue(value)}`;
79
60
  break;
@@ -88,11 +69,11 @@ function extractImports(node) {
88
69
  reason = `'import' received an invalid option '${key}'`;
89
70
  break;
90
71
  }
91
- const flag = hashKeys.find((key) => FLAG_KEYS.has(key));
92
- const mode = flag === void 0 ? void 0 : FLAG_KEYS.get(flag);
72
+ const flag = hashKeys.find((key) => OUTPUT_FLAGS.has(key));
73
+ const mode = flag === void 0 ? void 0 : OUTPUT_FLAGS.get(flag);
93
74
  if (reason === void 0 && flag !== void 0 && mode !== void 0) {
94
75
  const omitted = mode.tag === "script" ? "style" : "script";
95
- const conflict = hashKeys.find((key) => key !== flag && (mode.raw || FLAG_KEYS.has(key) || key === omitted || key.startsWith(`${omitted}:`)));
76
+ const conflict = hashKeys.find((key) => key !== flag && (mode.raw || OUTPUT_FLAGS.has(key) || key === omitted || key.startsWith(`${omitted}:`)));
96
77
  if (conflict !== void 0) reason = `'import' option '${flag}' cannot be combined with '${conflict}'`;
97
78
  }
98
79
  if (reason !== void 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"imports.js","names":[],"sources":["../../../src/compiler/ast/imports.ts"],"sourcesContent":["import { ATTRIBUTE_NAME_REGEX } from '../../constants';\nimport type {\n\tBlockStatement,\n\tExpression,\n\tMustacheStatement,\n\tNode,\n\tPathExpression,\n\tSubExpression,\n} from './types';\nimport { walk } from './walk';\n\nconst ASSET_KEYS = new Set(['script', 'style']);\nconst ASSET_ATTRIBUTE_REGEX = /^(?:script|style):(.+)$/s;\n/** Options rendering only the script or the styles of an import, raw without a tag. */\nconst FLAG_KEYS = new Map<string, { tag: 'script' | 'style'; raw: boolean }>([\n\t['script:raw', { tag: 'script', raw: true }],\n\t['style:raw', { tag: 'style', raw: true }],\n\t['script:only', { tag: 'script', raw: false }],\n\t['style:only', { tag: 'style', raw: false }],\n]);\n\ninterface Location {\n\tstart: [number, number];\n\tend: [number, number];\n\tnode: ImportNode;\n}\n\nexport interface ValidImport extends Location {\n\tvalid: true;\n\tspecifier: string;\n\tdependsOn: string[];\n\thashKeys: string[];\n}\n\nexport interface InvalidImport extends Location {\n\tvalid: false;\n\treason: string;\n}\n\nexport type Import = ValidImport | InvalidImport;\n\nexport function extractImports(node: Node): Import[] {\n\tconst imports: Import[] = [];\n\n\tfor (const importNode of extractImportNodes(node)) {\n\t\tconst { params, loc, hash } = importNode;\n\t\tconst location: Location = {\n\t\t\tstart: [loc.start.line, loc.start.column],\n\t\t\tend: [loc.end.line, loc.end.column],\n\t\t\tnode: importNode,\n\t\t};\n\n\t\tconst invalid = (reason: string): void => {\n\t\t\timports.push({\n\t\t\t\t...location,\n\t\t\t\tvalid: false,\n\t\t\t\treason,\n\t\t\t});\n\t\t};\n\n\t\tif (params.length === 0) {\n\t\t\tinvalid(\"'import' expects a string literal argument\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (params.length > 1) {\n\t\t\tinvalid(\"'import' accepts only one argument\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst specifier = params[0];\n\t\tif (specifier.type !== 'StringLiteral') {\n\t\t\tinvalid(\"First argument to 'import' must be a string literal\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet dependsOn: string[] = [];\n\t\tconst hashKeys: string[] = [];\n\t\tconst seenKeys = new Set<string>();\n\t\tlet reason: string | undefined;\n\n\t\tfor (const { key, value } of hash?.pairs || []) {\n\t\t\tif (seenKeys.has(key)) {\n\t\t\t\treason = `'import' option '${key}' was specified more than once`;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tseenKeys.add(key);\n\n\t\t\tif (key === 'depends-on') {\n\t\t\t\tif (value.type !== 'StringLiteral') {\n\t\t\t\t\treason = \"'import' 'depends-on' must be a string literal\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdependsOn = value.value\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((item) => item.trim())\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\t// an empty list would let the option pass where it is not supported\n\t\t\t\tif (dependsOn.length === 0) {\n\t\t\t\t\treason =\n\t\t\t\t\t\t\"'import' 'depends-on' must list at least one script or style\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (FLAG_KEYS.has(key)) {\n\t\t\t\tif (!isFlagValue(value)) {\n\t\t\t\t\treason = `'import' option '${key}' must be true, 'true' or '', got: ${describeValue(value)}`;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\thashKeys.push(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (ASSET_KEYS.has(key) || isAssetAttribute(key)) {\n\t\t\t\thashKeys.push(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treason = `'import' received an invalid option '${key}'`;\n\t\t\tbreak;\n\t\t}\n\n\t\t// raw output has no tag, so there is nothing other options could apply to,\n\t\t// and the options of the tag left out by `only` would be ignored\n\t\tconst flag = hashKeys.find((key) => FLAG_KEYS.has(key));\n\t\tconst mode = flag === undefined ? undefined : FLAG_KEYS.get(flag);\n\t\tif (reason === undefined && flag !== undefined && mode !== undefined) {\n\t\t\tconst omitted = mode.tag === 'script' ? 'style' : 'script';\n\t\t\tconst conflict = hashKeys.find(\n\t\t\t\t(key) =>\n\t\t\t\t\tkey !== flag &&\n\t\t\t\t\t(mode.raw ||\n\t\t\t\t\t\tFLAG_KEYS.has(key) ||\n\t\t\t\t\t\tkey === omitted ||\n\t\t\t\t\t\tkey.startsWith(`${omitted}:`)),\n\t\t\t);\n\t\t\tif (conflict !== undefined) {\n\t\t\t\treason = `'import' option '${flag}' cannot be combined with '${conflict}'`;\n\t\t\t}\n\t\t}\n\n\t\tif (reason !== undefined) {\n\t\t\tinvalid(reason);\n\t\t\tcontinue;\n\t\t}\n\n\t\timports.push({\n\t\t\t...location,\n\t\t\tvalid: true,\n\t\t\tspecifier: specifier.value,\n\t\t\tdependsOn,\n\t\t\thashKeys,\n\t\t});\n\t}\n\n\treturn imports;\n}\n\nfunction extractImportNodes(node: Node): ImportNode[] {\n\tconst nodes: ImportNode[] = [];\n\twalk(node, (node) => {\n\t\tif (isImportNode(node)) {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn nodes;\n}\n\nexport type ImportNode = (\n\t| MustacheStatement\n\t| BlockStatement\n\t| SubExpression\n) & {\n\tpath: PathExpression;\n};\n\nexport function isImportNode(node: Node): node is ImportNode {\n\treturn (\n\t\t(node.type === 'MustacheStatement' ||\n\t\t\tnode.type === 'BlockStatement' ||\n\t\t\tnode.type === 'SubExpression') &&\n\t\tnode.path.type === 'PathExpression' &&\n\t\tnode.path.parts.length === 1 &&\n\t\tnode.path.parts[0] === 'import'\n\t);\n}\n\n/** `script:raw` / `style:raw` / `script:only` / `style:only` take `true`, `'true'` or an empty string. */\nfunction isFlagValue(value: Expression): boolean {\n\treturn (\n\t\t(value.type === 'BooleanLiteral' && value.value) ||\n\t\t(value.type === 'StringLiteral' &&\n\t\t\t(value.value === 'true' || value.value === ''))\n\t);\n}\n\nfunction describeValue(value: Expression): string {\n\tswitch (value.type) {\n\t\tcase 'StringLiteral':\n\t\t\treturn `'${value.value}'`;\n\t\tcase 'BooleanLiteral':\n\t\tcase 'NumberLiteral':\n\t\t\treturn String(value.value);\n\t\tcase 'NullLiteral':\n\t\t\treturn 'null';\n\t\tcase 'UndefinedLiteral':\n\t\t\treturn 'undefined';\n\t\tcase 'PathExpression':\n\t\t\treturn `variable '${value.original}'`;\n\t\tcase 'SubExpression':\n\t\t\treturn `subexpression '${value.path.original}'`;\n\t}\n}\n\nfunction isAssetAttribute(key: string): boolean {\n\tconst name = ASSET_ATTRIBUTE_REGEX.exec(key)?.[1];\n\treturn name !== undefined && ATTRIBUTE_NAME_REGEX.test(name);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"imports.js","names":[],"sources":["../../../src/compiler/ast/imports.ts"],"sourcesContent":["import { ATTRIBUTE_NAME_REGEX, OUTPUT_FLAGS } from '../../constants';\nimport type {\n\tBlockStatement,\n\tExpression,\n\tMustacheStatement,\n\tNode,\n\tPathExpression,\n\tSubExpression,\n} from './types';\nimport { walk } from './walk';\n\nconst ASSET_KEYS = new Set(['script', 'style']);\nconst ASSET_ATTRIBUTE_REGEX = /^(?:script|style):(.+)$/s;\n\ninterface Location {\n\tstart: [number, number];\n\tend: [number, number];\n\tnode: ImportNode;\n}\n\nexport interface ValidImport extends Location {\n\tvalid: true;\n\tspecifier: string;\n\tdependsOn: string[];\n\thashKeys: string[];\n}\n\nexport interface InvalidImport extends Location {\n\tvalid: false;\n\treason: string;\n}\n\nexport type Import = ValidImport | InvalidImport;\n\nexport function extractImports(node: Node): Import[] {\n\tconst imports: Import[] = [];\n\n\tfor (const importNode of extractImportNodes(node)) {\n\t\tconst { params, loc, hash } = importNode;\n\t\tconst location: Location = {\n\t\t\tstart: [loc.start.line, loc.start.column],\n\t\t\tend: [loc.end.line, loc.end.column],\n\t\t\tnode: importNode,\n\t\t};\n\n\t\tconst invalid = (reason: string): void => {\n\t\t\timports.push({\n\t\t\t\t...location,\n\t\t\t\tvalid: false,\n\t\t\t\treason,\n\t\t\t});\n\t\t};\n\n\t\tif (params.length === 0) {\n\t\t\tinvalid(\"'import' expects a string literal argument\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (params.length > 1) {\n\t\t\tinvalid(\"'import' accepts only one argument\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst specifier = params[0];\n\t\tif (specifier.type !== 'StringLiteral') {\n\t\t\tinvalid(\"First argument to 'import' must be a string literal\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet dependsOn: string[] = [];\n\t\tconst hashKeys: string[] = [];\n\t\tconst seenKeys = new Set<string>();\n\t\tlet reason: string | undefined;\n\n\t\tfor (const { key, value } of hash?.pairs || []) {\n\t\t\tif (seenKeys.has(key)) {\n\t\t\t\treason = `'import' option '${key}' was specified more than once`;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tseenKeys.add(key);\n\n\t\t\tif (key === 'depends-on') {\n\t\t\t\tif (value.type !== 'StringLiteral') {\n\t\t\t\t\treason = \"'import' 'depends-on' must be a string literal\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tdependsOn = value.value\n\t\t\t\t\t.split(',')\n\t\t\t\t\t.map((item) => item.trim())\n\t\t\t\t\t.filter(Boolean);\n\t\t\t\t// an empty list would let the option pass where it is not supported\n\t\t\t\tif (dependsOn.length === 0) {\n\t\t\t\t\treason =\n\t\t\t\t\t\t\"'import' 'depends-on' must list at least one script or style\";\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (OUTPUT_FLAGS.has(key)) {\n\t\t\t\tif (!isFlagValue(value)) {\n\t\t\t\t\treason = `'import' option '${key}' must be true, 'true' or '', got: ${describeValue(value)}`;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\thashKeys.push(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (ASSET_KEYS.has(key) || isAssetAttribute(key)) {\n\t\t\t\thashKeys.push(key);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treason = `'import' received an invalid option '${key}'`;\n\t\t\tbreak;\n\t\t}\n\n\t\t// raw output has no tag, so there is nothing other options could apply to,\n\t\t// and the options of the tag left out by `only` would be ignored\n\t\tconst flag = hashKeys.find((key) => OUTPUT_FLAGS.has(key));\n\t\tconst mode = flag === undefined ? undefined : OUTPUT_FLAGS.get(flag);\n\t\tif (reason === undefined && flag !== undefined && mode !== undefined) {\n\t\t\tconst omitted = mode.tag === 'script' ? 'style' : 'script';\n\t\t\tconst conflict = hashKeys.find(\n\t\t\t\t(key) =>\n\t\t\t\t\tkey !== flag &&\n\t\t\t\t\t(mode.raw ||\n\t\t\t\t\t\tOUTPUT_FLAGS.has(key) ||\n\t\t\t\t\t\tkey === omitted ||\n\t\t\t\t\t\tkey.startsWith(`${omitted}:`)),\n\t\t\t);\n\t\t\tif (conflict !== undefined) {\n\t\t\t\treason = `'import' option '${flag}' cannot be combined with '${conflict}'`;\n\t\t\t}\n\t\t}\n\n\t\tif (reason !== undefined) {\n\t\t\tinvalid(reason);\n\t\t\tcontinue;\n\t\t}\n\n\t\timports.push({\n\t\t\t...location,\n\t\t\tvalid: true,\n\t\t\tspecifier: specifier.value,\n\t\t\tdependsOn,\n\t\t\thashKeys,\n\t\t});\n\t}\n\n\treturn imports;\n}\n\nfunction extractImportNodes(node: Node): ImportNode[] {\n\tconst nodes: ImportNode[] = [];\n\twalk(node, (node) => {\n\t\tif (isImportNode(node)) {\n\t\t\tnodes.push(node);\n\t\t}\n\t});\n\treturn nodes;\n}\n\nexport type ImportNode = (\n\t| MustacheStatement\n\t| BlockStatement\n\t| SubExpression\n) & {\n\tpath: PathExpression;\n};\n\nexport function isImportNode(node: Node): node is ImportNode {\n\treturn (\n\t\t(node.type === 'MustacheStatement' ||\n\t\t\tnode.type === 'BlockStatement' ||\n\t\t\tnode.type === 'SubExpression') &&\n\t\tnode.path.type === 'PathExpression' &&\n\t\tnode.path.parts.length === 1 &&\n\t\tnode.path.parts[0] === 'import'\n\t);\n}\n\n/** `script:raw` / `style:raw` / `script:only` / `style:only` take `true`, `'true'` or an empty string. */\nfunction isFlagValue(value: Expression): boolean {\n\treturn (\n\t\t(value.type === 'BooleanLiteral' && value.value) ||\n\t\t(value.type === 'StringLiteral' &&\n\t\t\t(value.value === 'true' || value.value === ''))\n\t);\n}\n\nfunction describeValue(value: Expression): string {\n\tswitch (value.type) {\n\t\tcase 'StringLiteral':\n\t\t\treturn `'${value.value}'`;\n\t\tcase 'BooleanLiteral':\n\t\tcase 'NumberLiteral':\n\t\t\treturn String(value.value);\n\t\tcase 'NullLiteral':\n\t\t\treturn 'null';\n\t\tcase 'UndefinedLiteral':\n\t\t\treturn 'undefined';\n\t\tcase 'PathExpression':\n\t\t\treturn `variable '${value.original}'`;\n\t\tcase 'SubExpression':\n\t\t\treturn `subexpression '${value.path.original}'`;\n\t}\n}\n\nfunction isAssetAttribute(key: string): boolean {\n\tconst name = ASSET_ATTRIBUTE_REGEX.exec(key)?.[1];\n\treturn name !== undefined && ATTRIBUTE_NAME_REGEX.test(name);\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { BlockStatement, BooleanLiteral, CommentStatement, ContentStatement, Decorator, DecoratorBlock, Expression, Hash, HashPair, Literal, MustacheStatement, Node, NullLiteral, NumberLiteral, PartialBlockStatement, PartialStatement, PathExpression, Position, Program, SourceLocation, Statement, StringLiteral, StripFlags, SubExpression, UndefinedLiteral } from "./types.js";
1
+ import { Node } from "./types.js";
2
2
  //#region src/compiler/ast/walk.d.ts
3
+ /** Calls `callback` with `node` and every node in it, parents first. */
3
4
  export declare function walk(node: Node, callback: (node: Node) => void): void;
4
5
  //#endregion
5
- export { BlockStatement, BooleanLiteral, CommentStatement, ContentStatement, Decorator, DecoratorBlock, Expression, Hash, HashPair, Literal, MustacheStatement, Node, NullLiteral, NumberLiteral, PartialBlockStatement, PartialStatement, PathExpression, Position, Program, SourceLocation, Statement, StringLiteral, StripFlags, SubExpression, UndefinedLiteral };
6
6
  //# sourceMappingURL=walk.d.ts.map
@@ -1,4 +1,5 @@
1
1
  //#region src/compiler/ast/walk.ts
2
+ /** Calls `callback` with `node` and every node in it, parents first. */
2
3
  function walk(node, callback) {
3
4
  callback(node);
4
5
  switch (node.type) {
@@ -7,33 +8,16 @@ function walk(node, callback) {
7
8
  break;
8
9
  case "MustacheStatement":
9
10
  case "Decorator":
10
- walk(node.path, callback);
11
- for (const param of node.params) walk(param, callback);
12
- if (node.hash) walk(node.hash, callback);
13
- break;
11
+ case "SubExpression":
14
12
  case "BlockStatement":
15
13
  case "DecoratorBlock":
16
- walk(node.path, callback);
17
- for (const param of node.params) walk(param, callback);
18
- if (node.hash) walk(node.hash, callback);
19
- walk(node.program, callback);
20
- if (node.inverse) walk(node.inverse, callback);
21
- break;
22
14
  case "PartialStatement":
23
- walk(node.name, callback);
24
- for (const param of node.params) walk(param, callback);
25
- if (node.hash) walk(node.hash, callback);
26
- break;
27
15
  case "PartialBlockStatement":
28
- walk(node.name, callback);
29
- for (const param of node.params) walk(param, callback);
30
- if (node.hash) walk(node.hash, callback);
31
- walk(node.program, callback);
32
- break;
33
- case "SubExpression":
34
- walk(node.path, callback);
16
+ walk("path" in node ? node.path : node.name, callback);
35
17
  for (const param of node.params) walk(param, callback);
36
18
  if (node.hash) walk(node.hash, callback);
19
+ if ("program" in node && node.program) walk(node.program, callback);
20
+ if ("inverse" in node && node.inverse) walk(node.inverse, callback);
37
21
  break;
38
22
  case "Hash":
39
23
  for (const pair of node.pairs) walk(pair, callback);
@@ -1 +1 @@
1
- {"version":3,"file":"walk.js","names":[],"sources":["../../../src/compiler/ast/walk.ts"],"sourcesContent":["import type { Node } from './types';\n\nexport function walk(node: Node, callback: (node: Node) => void): void {\n\tcallback(node);\n\n\tswitch (node.type) {\n\t\tcase 'Program':\n\t\t\tfor (const statement of node.body) {\n\t\t\t\twalk(statement, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'MustacheStatement':\n\t\tcase 'Decorator':\n\t\t\twalk(node.path, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'BlockStatement':\n\t\tcase 'DecoratorBlock':\n\t\t\twalk(node.path, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\twalk(node.program, callback);\n\n\t\t\tif (node.inverse) {\n\t\t\t\twalk(node.inverse, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'PartialStatement':\n\t\t\twalk(node.name, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'PartialBlockStatement':\n\t\t\twalk(node.name, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\twalk(node.program, callback);\n\t\t\tbreak;\n\n\t\tcase 'SubExpression':\n\t\t\twalk(node.path, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'Hash':\n\t\t\tfor (const pair of node.pairs) {\n\t\t\t\twalk(pair, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'HashPair':\n\t\t\twalk(node.value, callback);\n\t\t\tbreak;\n\t}\n}\n\nexport * from './types';\n"],"mappings":";AAEA,SAAgB,KAAK,MAAY,UAAsC;CACtE,SAAS,IAAI;CAEb,QAAQ,KAAK,MAAb;EACC,KAAK;GACJ,KAAK,MAAM,aAAa,KAAK,MAC5B,KAAK,WAAW,QAAQ;GAEzB;EAED,KAAK;EACL,KAAK;GACJ,KAAK,KAAK,MAAM,QAAQ;GACxB,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB;EAED,KAAK;EACL,KAAK;GACJ,KAAK,KAAK,MAAM,QAAQ;GACxB,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB,KAAK,KAAK,SAAS,QAAQ;GAE3B,IAAI,KAAK,SACR,KAAK,KAAK,SAAS,QAAQ;GAE5B;EAED,KAAK;GACJ,KAAK,KAAK,MAAM,QAAQ;GACxB,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB;EAED,KAAK;GACJ,KAAK,KAAK,MAAM,QAAQ;GACxB,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB,KAAK,KAAK,SAAS,QAAQ;GAC3B;EAED,KAAK;GACJ,KAAK,KAAK,MAAM,QAAQ;GACxB,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB;EAED,KAAK;GACJ,KAAK,MAAM,QAAQ,KAAK,OACvB,KAAK,MAAM,QAAQ;GAEpB;EAED,KAAK,YACJ,KAAK,KAAK,OAAO,QAAQ;CAE3B;AACD"}
1
+ {"version":3,"file":"walk.js","names":[],"sources":["../../../src/compiler/ast/walk.ts"],"sourcesContent":["import type { Node } from './types';\n\n/** Calls `callback` with `node` and every node in it, parents first. */\nexport function walk(node: Node, callback: (node: Node) => void): void {\n\tcallback(node);\n\n\tswitch (node.type) {\n\t\tcase 'Program':\n\t\t\tfor (const statement of node.body) {\n\t\t\t\twalk(statement, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\t// a call: its name, its arguments and its hash, and the blocks of a block\n\t\tcase 'MustacheStatement':\n\t\tcase 'Decorator':\n\t\tcase 'SubExpression':\n\t\tcase 'BlockStatement':\n\t\tcase 'DecoratorBlock':\n\t\tcase 'PartialStatement':\n\t\tcase 'PartialBlockStatement':\n\t\t\twalk('path' in node ? node.path : node.name, callback);\n\t\t\tfor (const param of node.params) {\n\t\t\t\twalk(param, callback);\n\t\t\t}\n\t\t\tif (node.hash) {\n\t\t\t\twalk(node.hash, callback);\n\t\t\t}\n\t\t\tif ('program' in node && node.program) {\n\t\t\t\twalk(node.program, callback);\n\t\t\t}\n\t\t\tif ('inverse' in node && node.inverse) {\n\t\t\t\twalk(node.inverse, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'Hash':\n\t\t\tfor (const pair of node.pairs) {\n\t\t\t\twalk(pair, callback);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 'HashPair':\n\t\t\twalk(node.value, callback);\n\t\t\tbreak;\n\t}\n}\n"],"mappings":";;AAGA,SAAgB,KAAK,MAAY,UAAsC;CACtE,SAAS,IAAI;CAEb,QAAQ,KAAK,MAAb;EACC,KAAK;GACJ,KAAK,MAAM,aAAa,KAAK,MAC5B,KAAK,WAAW,QAAQ;GAEzB;EAGD,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;GACJ,KAAK,UAAU,OAAO,KAAK,OAAO,KAAK,MAAM,QAAQ;GACrD,KAAK,MAAM,SAAS,KAAK,QACxB,KAAK,OAAO,QAAQ;GAErB,IAAI,KAAK,MACR,KAAK,KAAK,MAAM,QAAQ;GAEzB,IAAI,aAAa,QAAQ,KAAK,SAC7B,KAAK,KAAK,SAAS,QAAQ;GAE5B,IAAI,aAAa,QAAQ,KAAK,SAC7B,KAAK,KAAK,SAAS,QAAQ;GAE5B;EAED,KAAK;GACJ,KAAK,MAAM,QAAQ,KAAK,OACvB,KAAK,MAAM,QAAQ;GAEpB;EAED,KAAK,YACJ,KAAK,KAAK,OAAO,QAAQ;CAE3B;AACD"}
@@ -1,5 +1,6 @@
1
1
  import { CompilePlugin } from "../plugins/index.js";
2
2
  import { PluginData } from "../runtime/chunks.js";
3
+ import { Resolver } from "../utils/resolver.js";
3
4
  import { Chunks, PartialChunk } from "./chunks.js";
4
5
  import { RuntimeRequest } from "./plugins.js";
5
6
  import { RsbuildOptions } from "./rsbuild.js";
@@ -55,9 +56,16 @@ export interface PrepareOptions {
55
56
  onRead?: (file: string) => void;
56
57
  /** Whether the template is compiled again on changes, told to plugins. */
57
58
  watch?: boolean;
59
+ /**
60
+ * The resolver to reuse between compilations, cleared when files change,
61
+ * see `createTemplateResolver`. A new one without it.
62
+ */
63
+ resolver?: Resolver;
58
64
  }
65
+ /** The resolver of the imports of the templates, for the root and aliases of the options. */
66
+ export declare function createTemplateResolver(options: CompileTemplateOptions): Resolver;
59
67
  /** Everything but bundling the scripts, styles and plugin runtimes, for validated options. */
60
- export declare function prepareTemplate(options?: CompileTemplateOptions, { onRead, watch }?: PrepareOptions): Promise<PreparedTemplate>;
68
+ export declare function prepareTemplate(options?: CompileTemplateOptions, { onRead, watch, resolver }?: PrepareOptions): Promise<PreparedTemplate>;
61
69
  /** Emits the module source of a template whose scripts, styles and runtimes are bundled. */
62
70
  export declare function finishTemplate({ entry, chunks, partials, pluginData }: PreparedTemplate, bundle: RuntimeBundle | undefined): CompiledTemplate;
63
71
  //#endregion