eddev 2.0.0-beta.51 → 2.0.0-beta.53

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.
@@ -34,7 +34,6 @@ export function configureEditorBlocks(config) {
34
34
  blocks = transformTemplateToBlocks(config.defaultBlocks, false);
35
35
  }
36
36
  let newBlocks = [...header, ...blocks, ...footer];
37
- // console.log("Configuring", newBlocks)
38
37
  wp.data.dispatch("core/block-editor").resetBlocks(newBlocks);
39
38
  function syncBlocks(blocks) {
40
39
  return blocks.map((block) => {
@@ -174,7 +173,6 @@ function setWrapperBlock(blockName, blocks) {
174
173
  }
175
174
  function setTemplate(template) {
176
175
  const wp = window.wp;
177
- // console.log("Setting template", template)
178
176
  let currentBlocks = wp.data.select("core/block-editor").getBlocks();
179
177
  wp.data.dispatch("core/block-editor").updateSettings({
180
178
  templateLock: "all",
@@ -109,7 +109,13 @@ export type RouterAPI = {
109
109
  replaceQuery: (search: Record<string, string | string[]>) => void;
110
110
  /** Replace the hash */
111
111
  replaceHash: (hash: string) => void;
112
- /** Handle link clicking events */
112
+ /**
113
+ * Handle a click event, potentially triggering a route change.
114
+ *
115
+ * @param e A pointer or mouse event.
116
+ * @param href An optional URL. This must be provided if no `href` property exists on the clicked element
117
+ * @param preferBack If set, clicking this link will send the user 'back', when clicking a link to the previous history item.
118
+ */
113
119
  handleClickEvent(e: PointerOrMouseEvent, href?: string, preferBack?: boolean | "exact"): void;
114
120
  /** A reference to the route loader (mostly for internal use) */
115
121
  loader: RouteLoader;
@@ -117,7 +123,7 @@ export type RouterAPI = {
117
123
  subscribe: (subscribe: RouterSubscriber) => () => void;
118
124
  /** This function is used by the routing system automatically */
119
125
  emitEvent: (event: RouterEvent) => void;
120
- /** Returns the current RouterState */
126
+ /** Returns the current RouterAPIState */
121
127
  getState: () => RouterAPIState | null;
122
128
  /** Go back to a previous route in the history stack, or push it onto the stack if it isn't currently on the stack. */
123
129
  restoreRoute: (route: RouteState) => void;
@@ -106,7 +106,11 @@ if (!isMainThread) {
106
106
  pipeLog(frontendLog);
107
107
  }
108
108
  else if (mode === "graphql") {
109
- const codegen = new GraphQLGenerator(project);
109
+ const codegen = new GraphQLGenerator(project, {
110
+ generate: true,
111
+ optimize: true,
112
+ watch: true,
113
+ });
110
114
  codegen.start();
111
115
  pipeLog(graphqlLog);
112
116
  }
@@ -6,7 +6,7 @@ import { AdminBundler, adminLog } from "../compiler/bundler.admin.js";
6
6
  import { FrontendBundler, frontendLog } from "../compiler/bundler.frontend.js";
7
7
  import { DevServer, serverlessLog } from "../compiler/dev-server.js";
8
8
  import { createVinxiCodegen } from "../compiler/vinxi-codegen.js";
9
- import { graphqlLog } from "../graphql/graphql-codegen.js";
9
+ import { GraphQLGenerator, graphqlLog } from "../graphql/graphql-codegen.js";
10
10
  import { BuildInfoWriter } from "../project/eddev-build-file.js";
11
11
  import { Project, projectLog } from "../project/project.js";
12
12
  import { describeBlockManifest } from "../types/block-type.js";
@@ -143,6 +143,9 @@ program
143
143
  .option("-s, --serverless", 'Build in "serverless" mode', false)
144
144
  .option("--verbose", "Show extra debugging info", false)
145
145
  .action(async (options) => {
146
+ process.env["NODE_ENV"] = "development";
147
+ /** Ignore self-signed certificate errors in dev mode */
148
+ process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
146
149
  init(options.verbose);
147
150
  configureCliMode({
148
151
  interactive: false,
@@ -181,7 +184,10 @@ program
181
184
  const frontend = new FrontendBundler(project, {
182
185
  mode: "production",
183
186
  });
184
- await Promise.all([admin.start(), frontend.start()]);
187
+ const graphql = new GraphQLGenerator(project, {
188
+ optimize: true,
189
+ });
190
+ await Promise.all([admin.start(), frontend.start(), graphql.start()]);
185
191
  console.log("Done building SPA WordPress");
186
192
  }
187
193
  });
@@ -37,7 +37,7 @@ export function CLIApp(props) {
37
37
  process.stdout.write("\u001b[3J\u001b[1J");
38
38
  console.clear();
39
39
  props.logs.serverless?.resetLog();
40
- redraw();
40
+ setImmediate(redraw);
41
41
  }
42
42
  else if (input === "q") {
43
43
  process.exit(0);
@@ -1 +1 @@
1
- export declare const VERSION = "2.0.0-beta.51";
1
+ export declare const VERSION = "2.0.0-beta.53";
@@ -1 +1 @@
1
- export const VERSION = "2.0.0-beta.51";
1
+ export const VERSION = "2.0.0-beta.53";
@@ -1,7 +1,13 @@
1
1
  import { Project } from "../project/project.js";
2
2
  export declare const graphqlLog: import("../utils/stateful-log.js").StatefulLog<GraphQLGenerator>;
3
+ type GraphQLGeneratorOptions = {
4
+ watch?: boolean;
5
+ optimize?: boolean;
6
+ generate?: boolean;
7
+ };
3
8
  export declare class GraphQLGenerator {
4
9
  project: Project;
10
+ opts: GraphQLGeneratorOptions;
5
11
  private needsRegenerate;
6
12
  private needsReload;
7
13
  private regenerateReason;
@@ -9,14 +15,16 @@ export declare class GraphQLGenerator {
9
15
  private isGenerating;
10
16
  private schemaLoader;
11
17
  private fileLoader;
18
+ private optimizeWriter;
12
19
  private debouncer?;
13
20
  private retryTimer?;
14
- constructor(project: Project);
21
+ constructor(project: Project, opts: GraphQLGeneratorOptions);
15
22
  queueRegenerate(full: boolean, reason: string, info?: string | string[]): Promise<void>;
16
23
  start(): Promise<void>;
17
24
  private listen;
18
25
  scheduleRetry(): void;
19
26
  generate(): Promise<void>;
27
+ private getOptimizedQueries;
20
28
  /**
21
29
  * Validates a GraphQL manifest against a schema, ensuring there are no user errors.
22
30
  */
@@ -28,3 +36,4 @@ export declare class GraphQLGenerator {
28
36
  */
29
37
  private writeSchemaFile;
30
38
  }
39
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { codegen } from "@graphql-codegen/core";
2
- import { Kind, visit } from "graphql";
2
+ import { Kind, visit, print, } from "graphql";
3
3
  import { NoUnusedFragmentsRule, specifiedRules, validate } from "graphql/validation/index.js";
4
4
  import { join, relative, resolve } from "path";
5
5
  import { ProjectEnvUtils } from "../project/env.js";
@@ -16,6 +16,7 @@ import { watchFileTreeForChanges } from "../utils/watch-file-tree.js";
16
16
  import pluginFiles from "./plugins/gql-plugin-files.js";
17
17
  import pluginNoDuplicates from "./plugins/gql-plugin-no-duplicates.js";
18
18
  import pluginQueries from "./plugins/gql-plugin-queries.js";
19
+ import { FSCodegen } from "../utils/fs-codegen.js";
19
20
  export const graphqlLog = createConsole("GraphQL Codegen", "graphql");
20
21
  const console = graphqlLog;
21
22
  class GraphQLValidationError {
@@ -49,6 +50,7 @@ class GraphQLValidationError {
49
50
  }
50
51
  export class GraphQLGenerator {
51
52
  project;
53
+ opts;
52
54
  needsRegenerate = false;
53
55
  needsReload = true;
54
56
  regenerateReason = "";
@@ -56,11 +58,13 @@ export class GraphQLGenerator {
56
58
  isGenerating = false;
57
59
  schemaLoader;
58
60
  fileLoader;
61
+ optimizeWriter;
59
62
  debouncer;
60
63
  retryTimer;
61
- constructor(project) {
64
+ constructor(project, opts) {
62
65
  this.project = project;
63
- this.schemaLoader = new GraphQLSchemaLoader(ProjectEnvUtils.get("DEBUG_GRAPHQL_URL"));
66
+ this.opts = opts;
67
+ this.schemaLoader = new GraphQLSchemaLoader(ProjectEnvUtils.getSafe("DEBUG_GRAPHQL_URL"));
64
68
  this.fileLoader = createGraphQLFileLoader(this.project, [
65
69
  {
66
70
  baseFolder: "queries/fragments",
@@ -83,6 +87,38 @@ export class GraphQLGenerator {
83
87
  key: "queries",
84
88
  },
85
89
  ]);
90
+ this.optimizeWriter = new FSCodegen(project, {
91
+ outDir: "./.eddev/queries",
92
+ });
93
+ this.optimizeWriter.register({
94
+ getFiles: async () => {
95
+ const files = await this.fileLoader.get();
96
+ const { queries, fragments } = this.getOptimizedQueries(files, true);
97
+ const optimizedQueries = Object.entries(queries).flatMap(([_, group]) => {
98
+ return Object.entries(group).flatMap(([name, ast]) => {
99
+ let content = [
100
+ ast.leadingComments ? ast.leadingComments + "\n" : "",
101
+ print(ast),
102
+ ast.trailingComments ? "\n" + ast.trailingComments : "",
103
+ ].join("");
104
+ return {
105
+ name,
106
+ content,
107
+ };
108
+ });
109
+ });
110
+ return [
111
+ ...optimizedQueries,
112
+ {
113
+ name: "fragments.json",
114
+ content: JSON.stringify(Object.values(fragments).map(print), null, 2),
115
+ },
116
+ ];
117
+ },
118
+ susbcribe: (callback) => {
119
+ return this.fileLoader.subscribe(callback);
120
+ },
121
+ });
86
122
  }
87
123
  async queueRegenerate(full, reason, info) {
88
124
  this.needsRegenerate = true;
@@ -107,14 +143,26 @@ export class GraphQLGenerator {
107
143
  // Do initial load of blocks
108
144
  await this.project.blocks.get();
109
145
  await this.project.views.get();
110
- try {
111
- await this.generate();
146
+ if (this.opts.generate) {
147
+ try {
148
+ await this.generate();
149
+ }
150
+ catch (err) { }
151
+ }
152
+ if (this.opts.watch) {
153
+ this.project.blocks.subscribeFuture(() => {
154
+ this.generateUtilTypes();
155
+ });
156
+ this.listen();
157
+ }
158
+ if (this.opts.optimize) {
159
+ if (this.opts.watch) {
160
+ await this.optimizeWriter.runAndWatch();
161
+ }
162
+ else {
163
+ await this.optimizeWriter.run();
164
+ }
112
165
  }
113
- catch (err) { }
114
- this.project.blocks.subscribeFuture(() => {
115
- this.generateUtilTypes();
116
- });
117
- this.listen();
118
166
  }
119
167
  async listen() {
120
168
  // Subscribe to changes in block names
@@ -138,14 +186,23 @@ export class GraphQLGenerator {
138
186
  this.queueRegenerate(false, "GraphQL file(s) modifed", events?.map(stringifyFileEvent));
139
187
  });
140
188
  // Look out for PHP and acf-json file changes
141
- watchFileTreeForChanges(["backend/**/*.php"], (event) => {
142
- this.queueRegenerate(true, "PHP file change detected", stringifyFileEvent(event));
189
+ watchFileTreeForChanges({
190
+ pattern: ["backend/**/*.php"],
191
+ callback: (event) => {
192
+ this.queueRegenerate(true, "PHP file change detected", stringifyFileEvent(event));
193
+ },
143
194
  });
144
- watchFileTreeForChanges(["vendor/**/*.php"], (change) => {
145
- this.queueRegenerate(true, "PHP Vendor folder change detected", stringifyFileEvent(change));
195
+ watchFileTreeForChanges({
196
+ pattern: ["vendor/**/*.php"],
197
+ callback: (change) => {
198
+ this.queueRegenerate(true, "PHP Vendor folder change detected", stringifyFileEvent(change));
199
+ },
146
200
  });
147
- watchFileTreeForChanges(["acf-json/**/*.json"], (change) => {
148
- this.queueRegenerate(true, "ACF Field change detected", stringifyFileEvent(change));
201
+ watchFileTreeForChanges({
202
+ pattern: ["acf-json/**/*.json"],
203
+ callback: (change) => {
204
+ this.queueRegenerate(true, "ACF Field change detected", stringifyFileEvent(change));
205
+ },
149
206
  });
150
207
  }
151
208
  scheduleRetry() {
@@ -337,14 +394,9 @@ export class GraphQLGenerator {
337
394
  this.generate();
338
395
  }
339
396
  }
340
- /**
341
- * Validates a GraphQL manifest against a schema, ensuring there are no user errors.
342
- */
343
- validateGraphQLFiles(graphQLFiles, schema) {
344
- /**
345
- * Use all rules, except for No Unused Fragments — since we prepend those fragments to every test
346
- */
347
- const validationRules = specifiedRules.filter((rule) => rule !== NoUnusedFragmentsRule);
397
+ getOptimizedQueries(graphQLFiles, rewrite = false) {
398
+ const result = {};
399
+ const allFragments = {};
348
400
  /**
349
401
  * Get all the base fragment definitions
350
402
  */
@@ -355,7 +407,11 @@ export class GraphQLGenerator {
355
407
  .flat()
356
408
  .filter((n) => n.kind === Kind.FRAGMENT_DEFINITION)
357
409
  .forEach((node) => baseFragments.set(node.name.value, node));
410
+ baseFragments.forEach((node) => {
411
+ allFragments[node.name.value] = node;
412
+ });
358
413
  function findFragments(defs, map = new Map()) {
414
+ // console.log("findFragments", defs.length)
359
415
  for (let def of defs) {
360
416
  if (def.kind === Kind.FRAGMENT_DEFINITION) {
361
417
  map.set(def.name.value, def);
@@ -379,6 +435,40 @@ export class GraphQLGenerator {
379
435
  definitions: defs.filter((n) => n.kind !== Kind.FRAGMENT_DEFINITION),
380
436
  };
381
437
  }
438
+ for (let [groupName, fileMap] of Object.entries(graphQLFiles)) {
439
+ result[groupName] = {};
440
+ for (let [path, file] of Object.entries(fileMap)) {
441
+ if (!file.parseError) {
442
+ // Find all fragments
443
+ const { fragments, definitions } = findFragments(file?.ast?.definitions ?? []);
444
+ const ast = {
445
+ kind: Kind.DOCUMENT,
446
+ definitions: [...definitions, ...fragments],
447
+ loc: file.ast.loc,
448
+ leadingComments: file.leadingComments,
449
+ trailingComments: file.trailingComments,
450
+ };
451
+ result[groupName][path] = ast;
452
+ }
453
+ }
454
+ }
455
+ return {
456
+ queries: result,
457
+ fragments: allFragments,
458
+ };
459
+ }
460
+ /**
461
+ * Validates a GraphQL manifest against a schema, ensuring there are no user errors.
462
+ */
463
+ validateGraphQLFiles(graphQLFiles, schema) {
464
+ /**
465
+ * Use all rules, except for No Unused Fragments — since we prepend those fragments to every test
466
+ */
467
+ const validationRules = specifiedRules.filter((rule) => rule !== NoUnusedFragmentsRule);
468
+ /**
469
+ * Get the optimized files — queries with all fragments included
470
+ */
471
+ const { queries } = this.getOptimizedQueries(graphQLFiles);
382
472
  /**
383
473
  * Only report the same error once (mostly for preventing repeats of the same fragment errors)
384
474
  */
@@ -388,18 +478,17 @@ export class GraphQLGenerator {
388
478
  */
389
479
  const report = [];
390
480
  for (let [groupName, fileMap] of Object.entries(graphQLFiles)) {
481
+ const group = queries[groupName];
391
482
  for (let [path, file] of Object.entries(fileMap)) {
392
483
  if (file.parseError) {
393
484
  report.push(new GraphQLValidationError(file.parseError.message, path, file.parseError.line, file.parseError.column, file.contents));
394
485
  }
395
486
  else {
396
487
  // Find all fragments
397
- const { fragments, definitions } = findFragments(file?.ast?.definitions ?? []);
398
- const validationAST = {
399
- kind: Kind.DOCUMENT,
400
- definitions: [...fragments, ...definitions],
401
- loc: file.ast.loc,
402
- };
488
+ const validationAST = group[path];
489
+ if (!validationAST) {
490
+ continue;
491
+ }
403
492
  const errors = validate(schema, validationAST, validationRules);
404
493
  if (errors.length > 0) {
405
494
  for (let error of errors) {
@@ -67,7 +67,7 @@ export default {
67
67
  // Another convention, the query name and file name should be the same
68
68
  const baseName = basename(fileName);
69
69
  if (baseName.replace(".graphql", "") !== name) {
70
- throwErrorAtLocation(item.name.loc, `Expected your query name and file name to match, for conventions sake (eg. '${baseName}' should be '${name}.graphql')`);
70
+ throwErrorAtLocation(item.name.loc, `Expected GraphQL operation name to match the filename.\nYou should either:\na) rename the file to '${name}.graphql'\nb) rename the operation to '${baseName}'`);
71
71
  }
72
72
  // Only import variables if the operation has variables
73
73
  if (variablesTypeName) {
@@ -10,6 +10,8 @@ type Entry = {
10
10
  line?: number;
11
11
  column?: number;
12
12
  } | null;
13
+ leadingComments?: string;
14
+ trailingComments?: string;
13
15
  };
14
16
  export type GraphQLManifest<TKeys extends string> = {
15
17
  [K in TKeys]: {
@@ -21,6 +23,7 @@ type PatternMap<TKeys extends string> = {
21
23
  key: TKeys;
22
24
  baseFolder: string;
23
25
  pattern: string;
26
+ ignore?: string[];
24
27
  }[];
25
28
  export declare function createGraphQLFileLoader<TKeys extends string>(project: Project, patterns: PatternMap<TKeys>): import("../project/manifest/manifest.js").ManifestGenerator<Entry, GraphQLManifest<TKeys>>;
26
29
  export {};
@@ -7,6 +7,7 @@ export function createGraphQLFileLoader(project, patterns) {
7
7
  return createManifestGenerator({
8
8
  baseDir: project.rootDir,
9
9
  pattern: patterns.map((p) => join(p.baseFolder, p.pattern)),
10
+ ignore: patterns.flatMap((p) => p.ignore?.map((ignore) => join(p.baseFolder, ignore)) ?? []),
10
11
  watch: cliMode.watch,
11
12
  async generateManifest(entries) {
12
13
  let result = {};
@@ -32,6 +33,8 @@ export function createGraphQLFileLoader(project, patterns) {
32
33
  const contents = await fs.readFile(path, "utf8");
33
34
  let ast = null;
34
35
  let parseError = null;
36
+ const leadingComments = contents.match(/^(\n|#[^\n]*)+\n/)?.[0].trim();
37
+ const trailingComments = contents.match(/(\n|#[^\n]*)+$/)?.[0].trim();
35
38
  try {
36
39
  ast = parse(contents);
37
40
  }
@@ -48,6 +51,8 @@ export function createGraphQLFileLoader(project, patterns) {
48
51
  contents,
49
52
  ast,
50
53
  parseError,
54
+ leadingComments,
55
+ trailingComments,
51
56
  };
52
57
  },
53
58
  });
@@ -134,6 +134,7 @@ function readBlockDataAsJSONExport(file, contents) {
134
134
  result.frontendMode = userData.frontendMode;
135
135
  if (userData.postMetaBlock) {
136
136
  result.postMetaBlock = {
137
+ postTypes: userData.postMetaBlock.postTypes,
137
138
  fieldName: userData.postMetaBlock.fieldName,
138
139
  };
139
140
  result.types = userData.postMetaBlock.postTypes;
@@ -8,6 +8,7 @@ type ManifestEntry<TEntryData> = {
8
8
  type ManifestGeneratorArgs<TEntryData, TManifest> = {
9
9
  baseDir: string;
10
10
  pattern: string | string[];
11
+ ignore?: string[];
11
12
  watch: boolean;
12
13
  loadValue: (path: string, key: string) => Promise<TEntryData>;
13
14
  getKey: (path: string) => string | null;
@@ -31,20 +31,24 @@ export function createManifestGenerator(args) {
31
31
  }
32
32
  };
33
33
  if (args.watch) {
34
- const disposer = await watchFileTree(args.pattern, (fileList, event) => {
35
- files = fileList;
36
- cache = new Map();
37
- if (args.onFileChange)
38
- fileList.forEach(args.onFileChange);
39
- update();
40
- if (event) {
41
- events.push(event);
42
- }
34
+ const disposer = await watchFileTree({
35
+ pattern: args.pattern,
36
+ ignore: args.ignore,
37
+ callback: (fileList, event) => {
38
+ files = fileList;
39
+ cache = new Map();
40
+ if (args.onFileChange)
41
+ fileList.forEach(args.onFileChange);
42
+ update();
43
+ if (event) {
44
+ events.push(event);
45
+ }
46
+ },
43
47
  });
44
48
  disposers.push(disposer);
45
49
  }
46
50
  else {
47
- files = await getFileTree(args.pattern);
51
+ files = await getFileTree({ pattern: args.pattern, ignore: args.ignore });
48
52
  update();
49
53
  }
50
54
  });
@@ -23,10 +23,13 @@ export declare const BlockMetaSchema: z.ZodObject<{
23
23
  cache: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
24
24
  allowMultiple: z.ZodDefault<z.ZodBoolean>;
25
25
  postMetaBlock: z.ZodOptional<z.ZodObject<{
26
+ postTypes: z.ZodArray<z.ZodString, "many">;
26
27
  fieldName: z.ZodString;
27
28
  }, "strip", z.ZodTypeAny, {
29
+ postTypes: string[];
28
30
  fieldName: string;
29
31
  }, {
32
+ postTypes: string[];
30
33
  fieldName: string;
31
34
  }>>;
32
35
  frontendMode: z.ZodDefault<z.ZodEnum<["hidden", "childrenOnly", "default"]>>;
@@ -56,6 +59,7 @@ export declare const BlockMetaSchema: z.ZodObject<{
56
59
  keywords?: string[] | undefined;
57
60
  templates?: string[] | null | undefined;
58
61
  postMetaBlock?: {
62
+ postTypes: string[];
59
63
  fieldName: string;
60
64
  } | undefined;
61
65
  }, {
@@ -81,6 +85,7 @@ export declare const BlockMetaSchema: z.ZodObject<{
81
85
  dynamic?: boolean | undefined;
82
86
  allowMultiple?: boolean | undefined;
83
87
  postMetaBlock?: {
88
+ postTypes: string[];
84
89
  fieldName: string;
85
90
  } | undefined;
86
91
  frontendMode?: "hidden" | "childrenOnly" | "default" | undefined;
@@ -27,6 +27,7 @@ export const BlockMetaSchema = z.object({
27
27
  allowMultiple: z.boolean().default(true),
28
28
  postMetaBlock: z
29
29
  .object({
30
+ postTypes: z.array(z.string()),
30
31
  fieldName: z.string(),
31
32
  })
32
33
  .optional(),
@@ -15,6 +15,7 @@ export declare class FSCodegen {
15
15
  project: Project;
16
16
  opts: {
17
17
  outDir: string;
18
+ onWritten?: (opts: Set<string>) => void;
18
19
  };
19
20
  outDir: string;
20
21
  private generators;
@@ -23,6 +24,7 @@ export declare class FSCodegen {
23
24
  private flushScheduled;
24
25
  constructor(project: Project, opts: {
25
26
  outDir: string;
27
+ onWritten?: (opts: Set<string>) => void;
26
28
  });
27
29
  register(generator: CodeGenerator): void;
28
30
  registerFile({ name, generate, subscribe, }: {
@@ -77,7 +77,7 @@ export class FSCodegen {
77
77
  }
78
78
  async flush() {
79
79
  const files = Array.from(this.generatorFiles.values()).flat();
80
- const existing = (await globby(this.outDir + "/**/*")).map((path) => resolve(this.project.rootDir, path));
80
+ const existing = (await globby(join(this.outDir, "/**/*"))).map((path) => resolve(this.project.rootDir, path));
81
81
  const written = new Set();
82
82
  await Promise.all(files.map(async (file) => {
83
83
  const path = join(this.project.rootDir, this.outDir, file.name);
@@ -89,6 +89,7 @@ export class FSCodegen {
89
89
  await fs.rm(path);
90
90
  }
91
91
  }));
92
+ this.opts.onWritten?.(written);
92
93
  }
93
94
  stop() {
94
95
  this.unsubscribers.forEach((unsub) => unsub());
@@ -5,7 +5,21 @@ export type FileEvent = {
5
5
  type: FileWatchEvent;
6
6
  file: string;
7
7
  };
8
- export declare function watchFileTree(pattern: string | string[], callback: (files: FileList, event?: FileEvent) => void): Promise<Disposer>;
9
- export declare function watchFileTreeForChanges(pattern: string | string[], callback: (event: FileEvent) => void): Promise<Disposer>;
10
- export declare function getFileTree(pattern: string | string[]): Promise<FileList>;
8
+ type WatchTreeOpts = {
9
+ pattern: string | string[];
10
+ ignore?: string[];
11
+ callback: (files: FileList, event?: FileEvent) => void;
12
+ };
13
+ export declare function watchFileTree({ pattern, callback, ignore }: WatchTreeOpts): Promise<Disposer>;
14
+ type WatchTreeChangesOpts = {
15
+ pattern: string | string[];
16
+ ignore?: string | RegExp | string[];
17
+ callback: (event: FileEvent) => void;
18
+ };
19
+ export declare function watchFileTreeForChanges({ pattern, callback, ignore }: WatchTreeChangesOpts): Promise<Disposer>;
20
+ type GetTreeOpts = {
21
+ pattern: string | string[];
22
+ ignore?: string[];
23
+ };
24
+ export declare function getFileTree(opts: GetTreeOpts): Promise<FileList>;
11
25
  export {};
@@ -1,11 +1,13 @@
1
1
  import chokidar from "chokidar";
2
2
  import { globby } from "globby";
3
- export function watchFileTree(pattern, callback) {
3
+ export function watchFileTree({ pattern, callback, ignore }) {
4
4
  const files = [];
5
5
  let ready = false;
6
6
  return new Promise((resolve) => {
7
7
  const watcher = chokidar
8
- .watch(pattern)
8
+ .watch(pattern, {
9
+ ignored: ignore,
10
+ })
9
11
  .on("add", (path) => {
10
12
  files.push(path);
11
13
  if (ready)
@@ -31,7 +33,7 @@ export function watchFileTree(pattern, callback) {
31
33
  });
32
34
  });
33
35
  }
34
- export function watchFileTreeForChanges(pattern, callback) {
36
+ export function watchFileTreeForChanges({ pattern, callback, ignore }) {
35
37
  let ready = false;
36
38
  return new Promise((resolve) => {
37
39
  const watcher = chokidar
@@ -50,9 +52,14 @@ export function watchFileTreeForChanges(pattern, callback) {
50
52
  })
51
53
  .on("ready", () => {
52
54
  ready = true;
55
+ resolve(() => {
56
+ watcher.close();
57
+ });
53
58
  });
54
59
  });
55
60
  }
56
- export function getFileTree(pattern) {
57
- return globby(pattern);
61
+ export function getFileTree(opts) {
62
+ return globby(opts.pattern, {
63
+ ignore: opts.ignore,
64
+ });
58
65
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eddev",
3
- "version": "2.0.0-beta.51",
3
+ "version": "2.0.0-beta.53",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",