@normed/bundle 4.1.0 → 4.2.0

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,3 +1,28 @@
1
1
  import "@normed/json-types";
2
- import { APIOptions_Bundle } from "./types";
3
- export default function bundle(options?: APIOptions_Bundle): Promise<undefined>;
2
+ import { Entrypoint, APIOptions_Bundle } from "./types";
3
+ import { WrappedErrors } from "./errors";
4
+ import { BundlePlugins } from "./plugins";
5
+ export default function bundle(options?: APIOptions_Bundle, plugins?: BundlePlugins): Promise<WrappedErrors | {
6
+ completed: boolean;
7
+ errors: Error[];
8
+ warnings: Error[];
9
+ watchFiles: import("./File").FileInfo[];
10
+ watchDirs: {
11
+ path: string;
12
+ }[];
13
+ producedFiles: import("./File").FileInfo[];
14
+ entrypoints: Entrypoint[];
15
+ duration_ms: number;
16
+ children: ({
17
+ completed: boolean;
18
+ watchFiles: import("./File").FileInfo[];
19
+ watchDirs: {
20
+ path: string;
21
+ }[];
22
+ producedFiles: import("./File").FileInfo[];
23
+ } & import("./errors").ErrorLog & {
24
+ entrypoints: Entrypoint[];
25
+ builder: import("./types").Builder;
26
+ duration_ms: number;
27
+ })[];
28
+ }>;
@@ -1,4 +1,4 @@
1
1
  import "@normed/json-types";
2
2
  import { Entrypoint, BuildConfig } from "./types";
3
3
  import { NoMatchingBuilder } from "./errors";
4
- export default function getEntrypoints(buildConfig: BuildConfig, manuallySpecified?: string[]): Promise<(Entrypoint | NoMatchingBuilder)[]>;
4
+ export default function getEntrypoints(buildConfig: BuildConfig, manuallySpecified?: string[]): Promise<(NoMatchingBuilder | Entrypoint)[]>;
@@ -1,3 +1,24 @@
1
+ export interface MetaField {
2
+ meta?: JSONishObject | undefined;
3
+ }
4
+ export type WithMeta<V> = V & MetaField;
5
+ export interface ErrorLog {
6
+ errors?: Error[];
7
+ warnings?: Error[];
8
+ }
9
+ export declare function combineErrorLogs(...logs: ErrorLog[]): ErrorLog;
10
+ export declare class WrappedErrors extends AggregateError implements MetaField, ErrorLog {
11
+ meta?: JSONishObject | undefined;
12
+ warnings?: Error[];
13
+ constructor(errors: Error[] | ErrorLog, message: string, meta?: JSONishObject | undefined);
14
+ static fromErrorLog(errorLog: ErrorLog, message: string, meta?: JSONishObject): WrappedErrors;
15
+ static fromError(error: Error, message: string, meta?: JSONishObject): WrappedErrors;
16
+ static fromErrors(errors: Error[], message: string, meta?: JSONishObject): WrappedErrors;
17
+ static fromValue(value: unknown, message: string, meta?: JSONishObject): WrappedErrors;
18
+ static fromValues(values: unknown[], message: string, meta?: JSONishObject): WrappedErrors;
19
+ }
20
+ export declare function asError(value: unknown): Error;
21
+ export declare function asError(value: unknown, meta: JSONishObject): WithMeta<Error>;
1
22
  export declare class NoMatchingBuilder extends Error {
2
23
  readonly file: string;
3
24
  readonly ext: string;
package/bundles/index.js CHANGED
@@ -68594,6 +68594,34 @@ function groupBy(objs, extractSubgroupFuncs) {
68594
68594
  }
68595
68595
  return groups;
68596
68596
  }
68597
+ function keyBy(objs, extractKeyFuncs) {
68598
+ const result = /* @__PURE__ */ new Map();
68599
+ const knownKeys = [];
68600
+ for (const obj of objs) {
68601
+ const key = {};
68602
+ for (const [keyName, extractKeyFunc] of Object.entries(extractKeyFuncs)) {
68603
+ key[keyName] = extractKeyFunc(obj);
68604
+ }
68605
+ let knownKey = knownKeys.find(
68606
+ (knownKey2) => Object.keys(knownKey2).length === Object.keys(key).length && Object.keys(knownKey2).every(
68607
+ (k) => knownKey2[k] === key[k]
68608
+ )
68609
+ );
68610
+ if (!knownKey) {
68611
+ knownKey = key;
68612
+ knownKeys.push(key);
68613
+ result.set(knownKey, [obj]);
68614
+ } else {
68615
+ const group = result.get(knownKey);
68616
+ if (group) {
68617
+ group.push(obj);
68618
+ } else {
68619
+ throw new Error(`Keying failed in keyBy`);
68620
+ }
68621
+ }
68622
+ }
68623
+ return result;
68624
+ }
68597
68625
  function divide(list, divider) {
68598
68626
  const a = [];
68599
68627
  const b = [];
@@ -68890,6 +68918,68 @@ function mergeDeep(into, from) {
68890
68918
  }
68891
68919
 
68892
68920
  // pnp:/builds/normed/bundle/packages/bundle/src/errors.ts
68921
+ function combineErrorLogs(...logs) {
68922
+ const combined = {
68923
+ errors: [],
68924
+ warnings: []
68925
+ };
68926
+ for (const log of logs) {
68927
+ if (log.errors) {
68928
+ combined.errors.push(...log.errors);
68929
+ }
68930
+ if (log.warnings) {
68931
+ combined.warnings.push(...log.warnings);
68932
+ }
68933
+ }
68934
+ return combined;
68935
+ }
68936
+ var WrappedErrors = class _WrappedErrors extends AggregateError {
68937
+ constructor(errors, message, meta) {
68938
+ var __super = (...args) => {
68939
+ super(...args);
68940
+ this.meta = meta;
68941
+ return this;
68942
+ };
68943
+ if (Array.isArray(errors)) {
68944
+ __super(errors, message);
68945
+ } else {
68946
+ __super(errors.errors ?? [], message);
68947
+ this.warnings = errors.warnings ?? [];
68948
+ }
68949
+ this.name = "WrappedError";
68950
+ }
68951
+ warnings;
68952
+ static fromErrorLog(errorLog, message, meta) {
68953
+ return new _WrappedErrors(errorLog, message, meta);
68954
+ }
68955
+ static fromError(error, message, meta) {
68956
+ return new _WrappedErrors([error], message, meta);
68957
+ }
68958
+ static fromErrors(errors, message, meta) {
68959
+ return new _WrappedErrors(errors, message, meta);
68960
+ }
68961
+ static fromValue(value, message, meta) {
68962
+ const error = asError(value);
68963
+ return new _WrappedErrors([error], message, meta);
68964
+ }
68965
+ static fromValues(values, message, meta) {
68966
+ const errors = values.map(asError);
68967
+ return new _WrappedErrors(errors, message, meta);
68968
+ }
68969
+ };
68970
+ function asError(value, meta) {
68971
+ let error;
68972
+ if (!(value instanceof Error)) {
68973
+ error = new Error(String(value));
68974
+ } else {
68975
+ error = value;
68976
+ }
68977
+ if (meta) {
68978
+ let existingMeta = error.meta ?? {};
68979
+ error.meta = { ...existingMeta, ...meta };
68980
+ }
68981
+ return error;
68982
+ }
68893
68983
  var NoMatchingBuilder = class extends Error {
68894
68984
  file;
68895
68985
  ext;
@@ -68914,6 +69004,14 @@ var copyBuilder = {
68914
69004
  copy(infile.absolute, outfile.absolute);
68915
69005
  })
68916
69006
  );
69007
+ return {
69008
+ warnings: [],
69009
+ errors: [],
69010
+ watchFiles: entrypoints.map((e) => e.infile),
69011
+ watchDirs: [],
69012
+ producedFiles: entrypoints.map((e) => e.outfile),
69013
+ completed: true
69014
+ };
68917
69015
  }
68918
69016
  };
68919
69017
 
@@ -69042,6 +69140,30 @@ var load_less_default = plugin;
69042
69140
  var import_pug = __toESM(require_lib14());
69043
69141
  var import_fs4 = __toESM(require("fs"));
69044
69142
  var import_path5 = __toESM(require("path"));
69143
+ function pugTransformer(test, onFound) {
69144
+ return {
69145
+ preCodeGen(ast) {
69146
+ const pending = [...ast?.nodes || []];
69147
+ const found = [];
69148
+ while (pending.length > 0) {
69149
+ const node = pending.shift();
69150
+ if (!node) continue;
69151
+ if (node.block?.nodes) {
69152
+ pending.push(...node.block.nodes);
69153
+ }
69154
+ if (!test(node)) continue;
69155
+ found.push(node);
69156
+ }
69157
+ if (found.length) {
69158
+ onFound(found);
69159
+ }
69160
+ return ast;
69161
+ }
69162
+ };
69163
+ }
69164
+ function isScriptNodeWithSrcAttr(node) {
69165
+ return node.name === "script" && node.attrs.some((attr) => attr.name === "src");
69166
+ }
69045
69167
  async function loadAsText2(_filepath) {
69046
69168
  return {
69047
69169
  loader: "text"
@@ -69066,19 +69188,29 @@ async function loadAsHtml(filepath, options) {
69066
69188
  const contents = import_pug.default.render(fileData, {
69067
69189
  name: "render",
69068
69190
  filename: filepath,
69069
- basedir: options.outbase
69191
+ basedir: options.outbase,
69192
+ plugins: [
69193
+ pugTransformer(isScriptNodeWithSrcAttr, (nodes) => {
69194
+ nodes;
69195
+ })
69196
+ ]
69070
69197
  });
69071
69198
  return {
69072
69199
  contents,
69073
69200
  loader: "js"
69074
69201
  };
69075
69202
  }
69076
- async function loadAsCopy(filepath, options) {
69203
+ async function loadAsEntrypoint(filepath, options) {
69077
69204
  const fileData = await import_fs4.default.promises.readFile(filepath, "utf8");
69078
69205
  const contents = import_pug.default.render(fileData, {
69079
69206
  filename: filepath,
69080
69207
  basedir: options.outbase,
69081
- name: "render"
69208
+ name: "render",
69209
+ plugins: [
69210
+ pugTransformer(isScriptNodeWithSrcAttr, (nodes) => {
69211
+ nodes;
69212
+ })
69213
+ ]
69082
69214
  });
69083
69215
  return {
69084
69216
  contents,
@@ -69130,7 +69262,7 @@ var plugin2 = {
69130
69262
  }) => {
69131
69263
  const isEntryPoint = pluginData?.[name2]?.entrypoint;
69132
69264
  if (isEntryPoint) {
69133
- return loadAsCopy(filepath, build2.initialOptions);
69265
+ return loadAsEntrypoint(filepath, build2.initialOptions);
69134
69266
  }
69135
69267
  const type = withArg?.["type"] ?? "js";
69136
69268
  switch (type) {
@@ -69448,6 +69580,18 @@ var esbuilder = {
69448
69580
  }
69449
69581
  await Promise.all(promises);
69450
69582
  }
69583
+ return {
69584
+ // TODO: rewrite to return warnings
69585
+ warnings: [],
69586
+ // TODO: rewrite to return errors
69587
+ errors: [],
69588
+ watchFiles: entrypoints.map((e) => e.infile),
69589
+ watchDirs: [],
69590
+ // TODO: these are not the correct files
69591
+ producedFiles: entrypoints.map((e) => e.outfile),
69592
+ // TODO: rewrite to only return true if all builds were successful
69593
+ completed: true
69594
+ };
69451
69595
  }
69452
69596
  };
69453
69597
  async function compileToTypeDeclarations(fileNames, options) {
@@ -70321,7 +70465,7 @@ async function getEntrypoints(buildConfig, manuallySpecified) {
70321
70465
  }
70322
70466
 
70323
70467
  // pnp:/builds/normed/bundle/packages/bundle/src/bundle.ts
70324
- async function bundle(options = {}) {
70468
+ async function getBuildConfig(options) {
70325
70469
  const buildConfig = {
70326
70470
  dir: {
70327
70471
  in: getInDir(options),
@@ -70435,125 +70579,116 @@ async function bundle(options = {}) {
70435
70579
  "Build Config - post reading package.json",
70436
70580
  JSON.stringify(buildConfig.baseConfig, null, 2)
70437
70581
  );
70438
- const [raw_entrypoints, missingBuilders] = divide(
70439
- await getEntrypoints(buildConfig, options.entrypoints),
70440
- (v) => {
70441
- return !(v instanceof NoMatchingBuilder);
70442
- }
70443
- );
70444
- const [allContextEntrypoints, entrypoints] = divide(
70445
- raw_entrypoints,
70446
- (e) => e.origin === "discovered" && e.infile.modifiers.includes("context")
70582
+ return buildConfig;
70583
+ }
70584
+ async function discoverEntrypoints(buildConfig, entrypoints, plugins = {}) {
70585
+ let initialEntrypoints = await getEntrypoints(buildConfig, entrypoints);
70586
+ initialEntrypoints = await plugins.initialEntrypoints?.(initialEntrypoints) ?? initialEntrypoints;
70587
+ const [missing, found] = divide(
70588
+ initialEntrypoints,
70589
+ (e) => e instanceof NoMatchingBuilder
70447
70590
  );
70448
- let skippedContextFile = false;
70449
- await Promise.all(
70450
- allContextEntrypoints.map(async (contextEntrypoint) => {
70451
- if (4 > 1) {
70452
- if (!skippedContextFile) {
70453
- log_default.warn(`Context files are not yet supported`);
70454
- skippedContextFile = true;
70455
- }
70456
- log_default.warn(` - skipping ${contextEntrypoint.infile.relative}`);
70457
- return;
70458
- }
70459
- skippedContextFile = false;
70460
- const matchingEntrypoints = entrypoints.filter(
70461
- (e) => e.infile.bare === contextEntrypoint.infile.bare
70462
- );
70463
- if (!matchingEntrypoints.length) {
70464
- log_default.warn(
70465
- `Context file ${contextEntrypoint.infile.bare} is not used by any entrypoint`
70466
- );
70467
- return;
70468
- }
70469
- log_default.verbose(
70470
- `Context file ${contextEntrypoint.infile.bare} is used by ${matchingEntrypoints.length} entrypoints`
70471
- );
70472
- async function compile(_v) {
70473
- throw new Error("Function not implemented.");
70474
- }
70475
- const compiled = await compile(contextEntrypoint);
70476
- const { context } = await compiled.run();
70477
- if (!context) {
70478
- log_default.warn(
70479
- `Context file ${contextEntrypoint.infile.bare} did not export a context function`
70480
- );
70481
- return;
70482
- }
70483
- const contextResult = await context();
70484
- if (!contextResult) {
70485
- log_default.warn(
70486
- `Context file ${contextEntrypoint.infile.bare} did not return a context object`
70487
- );
70488
- return;
70591
+ if (missing.length) {
70592
+ const missingBuilders = missing.filter((v, i, a) => a.indexOf(v) === i);
70593
+ return WrappedErrors.fromErrors(
70594
+ missing,
70595
+ "Missing builders for entrypoints",
70596
+ {
70597
+ missingBuilders: missingBuilders.map((b) => b.name),
70598
+ missingBuilders_count: missingBuilders.length
70489
70599
  }
70490
- const builderNames = matchingEntrypoints.map((e) => e.builder.name).filter((v, i, a) => a.indexOf(v) === i);
70491
- const builderNamesWithContexts = builderNames.filter(
70492
- (name3) => contextResult[name3]
70493
- );
70494
- if (!builderNamesWithContexts.length) {
70495
- log_default.warn(
70496
- `Context file ${contextEntrypoint.infile.bare} did not return any context for any of the builders: ${builderNames.join(", ")}`
70497
- );
70498
- return;
70499
- }
70500
- for (const builderName of builderNamesWithContexts) {
70501
- await Promise.all(
70502
- matchingEntrypoints.filter((e) => e.builder.name === builderName).map(async (entrypoint) => {
70503
- const func = contextResult[builderName];
70504
- if (!func) {
70505
- log_default.warn(
70506
- `Context file ${contextEntrypoint.infile.bare} did not return a context for builder ${builderName}`
70507
- );
70508
- return;
70509
- }
70510
- entrypoint.context = await func();
70511
- })
70512
- );
70513
- }
70514
- })
70600
+ );
70601
+ }
70602
+ return plugins.discoveredEntrypoints?.(found) ?? found;
70603
+ }
70604
+ async function bundle(options = {}, plugins = {}) {
70605
+ const start = Date.now();
70606
+ const buildConfig = await getBuildConfig(options);
70607
+ const entrypoints = await discoverEntrypoints(
70608
+ buildConfig,
70609
+ options.entrypoints,
70610
+ plugins
70515
70611
  );
70516
- log_default.warn(missingBuilders.map((missing) => missing.message).join("\n"));
70517
- log_default.info(entrypoints.length + " entrypoints");
70518
- const grouped = entrypoints.reduce((acc, entryPoint) => {
70519
- const index = buildConfig.builders.indexOf(entryPoint.builder);
70520
- if (!acc[index]) {
70521
- acc[index] = [];
70522
- }
70523
- acc[index]?.push(entryPoint);
70524
- return acc;
70525
- }, []);
70526
- for (const index in grouped) {
70527
- const group = grouped[index];
70528
- const builder = buildConfig.builders[index];
70529
- if (!builder) {
70530
- continue;
70531
- }
70532
- log_default.info(
70533
- builder.color(
70534
- `${builder.name}:
70535
- ${group?.map((i) => `${i.infile.relative} => ${i.outfile.relative}`).join("\n ")}`
70536
- )
70612
+ if (entrypoints instanceof WrappedErrors) {
70613
+ return WrappedErrors.fromError(
70614
+ entrypoints,
70615
+ "Failed to discover entrypoints"
70537
70616
  );
70538
70617
  }
70539
- const results = await Promise.all(
70540
- grouped.map(
70541
- (entrypoints2, index) => (async () => {
70542
- const start = Date.now();
70543
- await buildConfig.builders[index]?.build(entrypoints2);
70544
- const duration = Math.floor((Date.now() - start) / 10) / 100;
70545
- const builder = buildConfig.builders[index];
70546
- if (!builder) {
70547
- log_default.info(`Unknown builder: ${duration} seconds`);
70548
- } else {
70549
- log_default.info(builder.color(`${builder.name}: ${duration} seconds`));
70618
+ let grouped = keyBy(entrypoints, {
70619
+ builder: (entrypoint) => entrypoint.builder
70620
+ });
70621
+ grouped = await plugins.preBuild?.(grouped) ?? grouped;
70622
+ const results = await Promise.allSettled(
70623
+ Array.from(grouped.entries()).map(
70624
+ async ([
70625
+ { builder },
70626
+ entrypoints2
70627
+ ]) => {
70628
+ const start2 = Date.now();
70629
+ const annotations = {
70630
+ entrypoints: entrypoints2,
70631
+ builder,
70632
+ duration_ms: -1
70633
+ };
70634
+ let result;
70635
+ try {
70636
+ result = await builder.build(entrypoints2);
70637
+ } catch (e) {
70638
+ result = {
70639
+ warnings: [],
70640
+ errors: [WrappedErrors.fromValue(e, "Builder failed to build")],
70641
+ watchFiles: entrypoints2.map((e2) => e2.infile),
70642
+ watchDirs: [],
70643
+ producedFiles: [],
70644
+ completed: false
70645
+ };
70646
+ } finally {
70647
+ annotations.duration_ms = Date.now() - start2;
70550
70648
  }
70551
- })().catch((e) => e)
70649
+ result = await plugins.postBuild?.(result, annotations) ?? result;
70650
+ return {
70651
+ ...result,
70652
+ ...annotations
70653
+ };
70654
+ }
70552
70655
  )
70553
70656
  );
70554
- const errors = results.filter(Boolean).concat(missingBuilders);
70555
- if (errors.length) return Promise.reject(errors);
70556
- return;
70657
+ const [rejected, fulfilled] = divide(
70658
+ results,
70659
+ (r) => r.status === "rejected"
70660
+ );
70661
+ const [uncompleted, completed] = divide(fulfilled, (r) => r.value.completed);
70662
+ const errorLogs = combineErrorLogs(
70663
+ ...uncompleted.map((r) => r.value),
70664
+ ...completed.map((r) => r.value)
70665
+ );
70666
+ const errors = [
70667
+ rejected.length ? WrappedErrors.fromValues(
70668
+ rejected.map((r) => r.reason),
70669
+ "Some builders encountered errors when running",
70670
+ {
70671
+ rejected_count: rejected.length,
70672
+ entrypoints: entrypoints.map((e) => e.infile.relative),
70673
+ builders: Array.from(grouped.keys()).map(
70674
+ ({ builder }) => builder.name
70675
+ )
70676
+ }
70677
+ ) : void 0,
70678
+ ...errorLogs.errors ?? []
70679
+ ];
70680
+ const warnings = errorLogs.warnings ?? [];
70681
+ return {
70682
+ completed: rejected.length === 0 && uncompleted.length === 0,
70683
+ errors: errors.filter(isNot.undefined),
70684
+ warnings,
70685
+ watchFiles: fulfilled.flatMap((r) => r.value.watchFiles),
70686
+ watchDirs: fulfilled.flatMap((r) => r.value.watchDirs),
70687
+ producedFiles: fulfilled.flatMap((r) => r.value.producedFiles),
70688
+ entrypoints,
70689
+ duration_ms: Date.now() - start,
70690
+ children: fulfilled.map((r) => r.value)
70691
+ };
70557
70692
  }
70558
70693
 
70559
70694
  // pnp:/builds/normed/bundle/packages/bundle/src/index.ts