@immense/vue-pom-generator 1.0.41 → 1.0.42

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.
package/RELEASE_NOTES.md CHANGED
@@ -1,41 +1,38 @@
1
- # Release Notes - v1.0.41
1
+ Based on the PR information and the specified release window (2026-04-06T12:50:48-05:00 to
2
+ 2026-04-06T17:25:31-05:00), only PR #6 falls within this window. PRs #1 and #4 were merged
3
+ earlier (February and April 1st respectively) and should not be included in v1.0.42.
2
4
 
5
+ ```markdown
3
6
  ## Highlights
4
7
 
5
- - Fixed keyed click test ID scoping to prevent conflicts
6
- - Aligned attachment scopes for consistent behavior
7
- - Aligned dev snapshot options across plugin configurations
8
- - Added PR release notes preview comments via GitHub Actions
9
- - Expanded test coverage with new dev plugin options tests
8
+ - Dev mode now fails fast on snapshot generation errors instead of silently continuing
9
+ - Snapshot maps are rebuilt atomically to prevent partial state after compilation failures
10
+ - Dev server behavior now matches build-mode semantics for strict snapshot errors
11
+ - Added regression test coverage for strict collision failures during dev startup
10
12
 
11
13
  ## Changes
12
14
 
13
- **Bug Fixes**
14
- - Fixed keyed click test ID scoping issues
15
- - Aligned attachment scopes for proper C# navigation returns
16
- - Aligned dev snapshot options across build and dev plugins
17
-
18
- **Tooling & CI**
19
- - Updated release workflow to use npm 11.5.1 via npx
20
- - Added automated PR release notes preview comments
15
+ **Error Handling**
16
+ - Dev startup now awaits snapshot generation so strict transform failures reject instead of
17
+ silently continuing
18
+ - Snapshot maps are rebuilt atomically during startup and batched regeneration to avoid partial
19
+ state on failed recompiles
21
20
 
22
21
  **Testing**
23
- - Added comprehensive dev plugin options test suite (`tests/dev-plugin-options.test.ts`)
24
- - Expanded transform tests with additional coverage
22
+ - Added regression coverage for strict collision failures during dev startup
23
+
24
+ ## Breaking Changes
25
25
 
26
- **Internal**
27
- - Updated utility functions for improved scoping logic
28
- - Refined plugin configuration handling
26
+ None
29
27
 
30
28
  ## Pull Requests Included
31
29
 
32
- - [#4 Fix keyed POM dedupe and C# navigation
33
- returns](https://github.com/immense/vue-pom-generator/pull/4) (@dkattan)
34
- - [#1 Add PR release-notes preview
35
- comments](https://github.com/immense/vue-pom-generator/pull/1) (@dkattan)
30
+ - #6 fix: fail fast on dev snapshot generation errors
31
+ (https://github.com/immense/vue-pom-generator/pull/6)
36
32
 
37
33
  ## Testing
38
34
 
39
- Added 160+ lines of new tests for dev plugin options. Existing transform tests expanded with
40
- additional assertions.
35
+ Added regression test coverage for strict collision failures during dev startup. All tests
36
+ passing with validation via eslint, typecheck, build, and test suite.
37
+ ```
41
38
 
package/dist/index.cjs CHANGED
@@ -6037,7 +6037,7 @@ function createDevProcessorPlugin(options) {
6037
6037
  return;
6038
6038
  scheduleVueFileRegen(ctx.file, "hmr");
6039
6039
  },
6040
- configureServer(server) {
6040
+ async configureServer(server) {
6041
6041
  const getViewsDirAbs = () => path.isAbsolute(viewsDir) ? viewsDir : path.resolve(projectRootRef.current, viewsDir);
6042
6042
  const routerInitPromise = (async () => {
6043
6043
  if (!routerAwarePoms) {
@@ -6114,8 +6114,8 @@ function createDevProcessorPlugin(options) {
6114
6114
  }
6115
6115
  return out;
6116
6116
  };
6117
- const snapshotHierarchy = /* @__PURE__ */ new Map();
6118
- const snapshotVuePathMap = /* @__PURE__ */ new Map();
6117
+ let snapshotHierarchy = /* @__PURE__ */ new Map();
6118
+ let snapshotVuePathMap = /* @__PURE__ */ new Map();
6119
6119
  const filePathToComponentName = /* @__PURE__ */ new Map();
6120
6120
  const getComponentNameForFile = (filePath) => {
6121
6121
  const normalized = path.resolve(filePath);
@@ -6132,12 +6132,12 @@ function createDevProcessorPlugin(options) {
6132
6132
  filePathToComponentName.set(normalized, name);
6133
6133
  return name;
6134
6134
  };
6135
- const compileVueFileIntoSnapshot = (filePath) => {
6135
+ const compileVueFileIntoSnapshot = (filePath, targetHierarchy = snapshotHierarchy, targetVuePathMap = snapshotVuePathMap) => {
6136
6136
  const started = node_perf_hooks.performance.now();
6137
6137
  const absolutePath = path.resolve(filePath);
6138
6138
  const componentName = getComponentNameForFile(absolutePath);
6139
- snapshotVuePathMap.set(componentName, absolutePath);
6140
- snapshotHierarchy.delete(componentName);
6139
+ targetVuePathMap.set(componentName, absolutePath);
6140
+ targetHierarchy.delete(componentName);
6141
6141
  let sfc = "";
6142
6142
  try {
6143
6143
  sfc = fs.readFileSync(absolutePath, "utf8");
@@ -6147,36 +6147,33 @@ function createDevProcessorPlugin(options) {
6147
6147
  const template = extractTemplateFromSfc(sfc, absolutePath);
6148
6148
  if (!template.trim())
6149
6149
  return { componentName, ms: node_perf_hooks.performance.now() - started, compiled: true };
6150
- try {
6151
- compilerDom__namespace.compile(template, {
6152
- filename: absolutePath,
6153
- prefixIdentifiers: true,
6154
- nodeTransforms: [
6155
- createTestIdTransform(
6156
- componentName,
6157
- snapshotHierarchy,
6158
- nativeWrappers,
6159
- excludedComponents,
6160
- getViewsDirAbs(),
6161
- {
6162
- existingIdBehavior: "preserve",
6163
- nameCollisionBehavior,
6164
- testIdAttribute,
6165
- warn: (message) => loggerRef.current.warn(message),
6166
- vueFilesPathMap: snapshotVuePathMap,
6167
- wrapperSearchRoots: getWrapperSearchRoots()
6168
- }
6169
- )
6170
- ]
6171
- });
6172
- } catch {
6173
- }
6150
+ compilerDom__namespace.compile(template, {
6151
+ filename: absolutePath,
6152
+ prefixIdentifiers: true,
6153
+ nodeTransforms: [
6154
+ createTestIdTransform(
6155
+ componentName,
6156
+ targetHierarchy,
6157
+ nativeWrappers,
6158
+ excludedComponents,
6159
+ getViewsDirAbs(),
6160
+ {
6161
+ existingIdBehavior: "preserve",
6162
+ nameCollisionBehavior,
6163
+ testIdAttribute,
6164
+ warn: (message) => loggerRef.current.warn(message),
6165
+ vueFilesPathMap: targetVuePathMap,
6166
+ wrapperSearchRoots: getWrapperSearchRoots()
6167
+ }
6168
+ )
6169
+ ]
6170
+ });
6174
6171
  return { componentName, ms: node_perf_hooks.performance.now() - started, compiled: true };
6175
6172
  };
6176
6173
  const fullRebuildSnapshotFromFilesystem = () => {
6177
6174
  const t0 = node_perf_hooks.performance.now();
6178
- snapshotHierarchy.clear();
6179
- snapshotVuePathMap.clear();
6175
+ const nextHierarchy = /* @__PURE__ */ new Map();
6176
+ const nextVuePathMap = /* @__PURE__ */ new Map();
6180
6177
  filePathToComponentName.clear();
6181
6178
  let totalVueFiles = 0;
6182
6179
  let compiledCount = 0;
@@ -6187,11 +6184,13 @@ function createDevProcessorPlugin(options) {
6187
6184
  const vueFiles = walkFilesRecursive(absDir);
6188
6185
  totalVueFiles += vueFiles.length;
6189
6186
  for (const file of vueFiles) {
6190
- const res = compileVueFileIntoSnapshot(file);
6187
+ const res = compileVueFileIntoSnapshot(file, nextHierarchy, nextVuePathMap);
6191
6188
  if (res.compiled)
6192
6189
  compiledCount++;
6193
6190
  }
6194
6191
  }
6192
+ snapshotHierarchy = nextHierarchy;
6193
+ snapshotVuePathMap = nextVuePathMap;
6195
6194
  const t1 = node_perf_hooks.performance.now();
6196
6195
  logInfo(`initial scan: found ${totalVueFiles} .vue files in ${scanDirs.join(", ")}`);
6197
6196
  logInfo(`initial compile: ${compiledCount}/${totalVueFiles} files in ${formatMs(t1 - t0)} (components=${snapshotHierarchy.size})`);
@@ -6218,6 +6217,10 @@ function createDevProcessorPlugin(options) {
6218
6217
  const t1 = node_perf_hooks.performance.now();
6219
6218
  logInfo(`generate(${reason}): components=${snapshotHierarchy.size} in ${formatMs(t1 - t0)}`);
6220
6219
  };
6220
+ let timer = null;
6221
+ let maxWaitTimer = null;
6222
+ const pendingChangedVueFiles = /* @__PURE__ */ new Set();
6223
+ const pendingDeletedComponents = /* @__PURE__ */ new Set();
6221
6224
  const initialBuildPromise = (async () => {
6222
6225
  const t0 = node_perf_hooks.performance.now();
6223
6226
  await routerInitPromise;
@@ -6226,13 +6229,44 @@ function createDevProcessorPlugin(options) {
6226
6229
  const t1 = node_perf_hooks.performance.now();
6227
6230
  logInfo(`startup total: ${formatMs(t1 - t0)}`);
6228
6231
  })();
6232
+ const logGenerationError = (reason, message) => {
6233
+ server.config.logger.error(`[vue-pom-generator] dev generation failed during ${reason}: ${message}`);
6234
+ };
6235
+ const regenerateFromPending = async (reason) => {
6236
+ const t0 = node_perf_hooks.performance.now();
6237
+ await initialBuildPromise;
6238
+ const nextHierarchy = new Map(snapshotHierarchy);
6239
+ const nextVuePathMap = new Map(snapshotVuePathMap);
6240
+ for (const componentName of pendingDeletedComponents) {
6241
+ nextHierarchy.delete(componentName);
6242
+ nextVuePathMap.delete(componentName);
6243
+ }
6244
+ const files = Array.from(pendingChangedVueFiles);
6245
+ const deletedCount = pendingDeletedComponents.size;
6246
+ pendingChangedVueFiles.clear();
6247
+ pendingDeletedComponents.clear();
6248
+ let compileMs = 0;
6249
+ for (const f of files) {
6250
+ const res = compileVueFileIntoSnapshot(f, nextHierarchy, nextVuePathMap);
6251
+ compileMs += res.ms;
6252
+ }
6253
+ snapshotHierarchy = nextHierarchy;
6254
+ snapshotVuePathMap = nextVuePathMap;
6255
+ const t1 = node_perf_hooks.performance.now();
6256
+ generateAggregatedFromSnapshot(reason);
6257
+ const t2 = node_perf_hooks.performance.now();
6258
+ return {
6259
+ files,
6260
+ deletedCount,
6261
+ compileMs,
6262
+ preGenerateMs: t1 - t0,
6263
+ generateMs: t2 - t1,
6264
+ totalMs: t2 - t0
6265
+ };
6266
+ };
6229
6267
  const watchedVueGlobs = scanDirs.map((dir) => path.resolve(projectRootRef.current, dir, "**", "*.vue"));
6230
6268
  const watchedPluginGlob = path.resolve(projectRootRef.current, "vite-plugins", "vue-pom-generator", "**", "*.ts");
6231
6269
  server.watcher.add([...watchedVueGlobs, watchedPluginGlob, basePageClassPath]);
6232
- let timer = null;
6233
- let maxWaitTimer = null;
6234
- const pendingChangedVueFiles = /* @__PURE__ */ new Set();
6235
- const pendingDeletedComponents = /* @__PURE__ */ new Set();
6236
6270
  scheduleVueFileRegenLocal = (filePath, source) => {
6237
6271
  pendingChangedVueFiles.add(filePath);
6238
6272
  logDebug(`queued(${source}): files=${pendingChangedVueFiles.size} deleted=${pendingDeletedComponents.size}`);
@@ -6249,29 +6283,14 @@ function createDevProcessorPlugin(options) {
6249
6283
  timer = null;
6250
6284
  }
6251
6285
  maxWaitTimer = null;
6252
- void (async () => {
6253
- const t0 = node_perf_hooks.performance.now();
6254
- await initialBuildPromise;
6255
- for (const componentName of pendingDeletedComponents) {
6256
- snapshotHierarchy.delete(componentName);
6257
- snapshotVuePathMap.delete(componentName);
6258
- }
6259
- const files = Array.from(pendingChangedVueFiles);
6260
- const deletedCount = pendingDeletedComponents.size;
6261
- pendingChangedVueFiles.clear();
6262
- pendingDeletedComponents.clear();
6263
- let compileMs = 0;
6264
- for (const f of files) {
6265
- const res = compileVueFileIntoSnapshot(f);
6266
- compileMs += res.ms;
6267
- }
6268
- const t1 = node_perf_hooks.performance.now();
6269
- generateAggregatedFromSnapshot("max-wait");
6270
- const t2 = node_perf_hooks.performance.now();
6286
+ void regenerateFromPending("max-wait").then(({ files, deletedCount, compileMs, preGenerateMs, generateMs, totalMs }) => {
6271
6287
  logInfo(
6272
- `max-wait: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(t1 - t0)} gen=${formatMs(t2 - t1)} total=${formatMs(t2 - t0)}`
6288
+ `max-wait: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(preGenerateMs)} gen=${formatMs(generateMs)} total=${formatMs(totalMs)}`
6273
6289
  );
6274
- })();
6290
+ }).catch((error) => {
6291
+ const message = error instanceof Error ? error.message : String(error);
6292
+ logGenerationError("max-wait", message);
6293
+ });
6275
6294
  }, MAX_WAIT_MS);
6276
6295
  }
6277
6296
  if (wasEmpty) {
@@ -6287,31 +6306,17 @@ function createDevProcessorPlugin(options) {
6287
6306
  clearTimeout(maxWaitTimer);
6288
6307
  maxWaitTimer = null;
6289
6308
  }
6290
- void (async () => {
6291
- const t0 = node_perf_hooks.performance.now();
6292
- await initialBuildPromise;
6293
- for (const componentName of pendingDeletedComponents) {
6294
- snapshotHierarchy.delete(componentName);
6295
- snapshotVuePathMap.delete(componentName);
6296
- }
6297
- const files = Array.from(pendingChangedVueFiles);
6298
- const deletedCount = pendingDeletedComponents.size;
6299
- pendingChangedVueFiles.clear();
6300
- pendingDeletedComponents.clear();
6301
- let compileMs = 0;
6302
- for (const f of files) {
6303
- const res = compileVueFileIntoSnapshot(f);
6304
- compileMs += res.ms;
6305
- }
6306
- const t1 = node_perf_hooks.performance.now();
6307
- generateAggregatedFromSnapshot(files.length || deletedCount ? "batched" : "noop");
6308
- const t2 = node_perf_hooks.performance.now();
6309
+ const reason = pendingChangedVueFiles.size || pendingDeletedComponents.size ? "batched" : "noop";
6310
+ void regenerateFromPending(reason).then(({ files, deletedCount, compileMs, preGenerateMs, generateMs, totalMs }) => {
6309
6311
  if (files.length || deletedCount) {
6310
6312
  logInfo(
6311
- `batched: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(t1 - t0)} gen=${formatMs(t2 - t1)} total=${formatMs(t2 - t0)}`
6313
+ `batched: files=${files.length} deleted=${deletedCount} compile=${formatMs(compileMs)} wall=${formatMs(preGenerateMs)} gen=${formatMs(generateMs)} total=${formatMs(totalMs)}`
6312
6314
  );
6313
6315
  }
6314
- })();
6316
+ }).catch((error) => {
6317
+ const message = error instanceof Error ? error.message : String(error);
6318
+ logGenerationError(reason, message);
6319
+ });
6315
6320
  }, 75);
6316
6321
  }
6317
6322
  server.watcher.on("change", async (changedPath) => {
@@ -6363,6 +6368,7 @@ function createDevProcessorPlugin(options) {
6363
6368
  });
6364
6369
  setTimeout(() => {
6365
6370
  }, 250);
6371
+ await initialBuildPromise;
6366
6372
  }
6367
6373
  };
6368
6374
  }