@wafertools/wafermap 0.28.0 → 0.30.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.
Files changed (66) hide show
  1. package/AGENTS.md +13 -14
  2. package/CHANGELOG.md +291 -0
  3. package/README.md +5 -5
  4. package/dist/packages/canvas-adapter/deprecated.d.ts +10 -0
  5. package/dist/packages/canvas-adapter/deprecated.js +1 -0
  6. package/dist/packages/canvas-adapter/dieList.d.ts +1 -3
  7. package/dist/packages/canvas-adapter/dieList.js +7 -7
  8. package/dist/packages/canvas-adapter/index.d.ts +1 -3
  9. package/dist/packages/canvas-adapter/index.js +1 -1
  10. package/dist/packages/canvas-adapter/insightsTab.d.ts +0 -1
  11. package/dist/packages/canvas-adapter/insightsTab.js +1 -1
  12. package/dist/packages/canvas-adapter/maplessSummary.d.ts +3 -0
  13. package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
  14. package/dist/packages/canvas-adapter/renderWaferGallery.d.ts +1 -40
  15. package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
  16. package/dist/packages/canvas-adapter/renderWaferMap.d.ts +81 -104
  17. package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
  18. package/dist/packages/canvas-adapter/summaryPanel.d.ts +11 -8
  19. package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
  20. package/dist/packages/canvas-adapter/toCanvas.d.ts +20 -12
  21. package/dist/packages/canvas-adapter/toCanvas.js +1 -1
  22. package/dist/packages/canvas-adapter/toolbar.d.ts +2 -0
  23. package/dist/packages/canvas-adapter/toolbar.js +2 -2
  24. package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
  25. package/dist/packages/canvas-adapter/userGuideHtml.js +14 -10
  26. package/dist/packages/canvas-adapter/version.d.ts +2 -2
  27. package/dist/packages/canvas-adapter/version.js +1 -1
  28. package/dist/packages/canvas-adapter/warnings.js +1 -1
  29. package/dist/packages/core/deprecated.d.ts +64 -0
  30. package/dist/packages/core/deprecated.js +1 -0
  31. package/dist/packages/core/index.d.ts +1 -3
  32. package/dist/packages/core/index.js +1 -1
  33. package/dist/packages/core/passBins.d.ts +33 -0
  34. package/dist/packages/core/passBins.js +1 -0
  35. package/dist/packages/core/waferLabel.d.ts +25 -0
  36. package/dist/packages/core/waferLabel.js +1 -0
  37. package/dist/packages/renderer/binColors.d.ts +67 -13
  38. package/dist/packages/renderer/binColors.js +1 -1
  39. package/dist/packages/renderer/buildView.d.ts +23 -9
  40. package/dist/packages/renderer/buildView.js +1 -1
  41. package/dist/packages/renderer/buildWaferMap.d.ts +47 -13
  42. package/dist/packages/renderer/buildWaferMap.js +1 -1
  43. package/dist/packages/renderer/colorMap.d.ts +4 -3
  44. package/dist/packages/renderer/colorSchemes.d.ts +21 -6
  45. package/dist/packages/renderer/colorSchemes.js +1 -1
  46. package/dist/packages/renderer/deprecate.d.ts +24 -0
  47. package/dist/packages/renderer/deprecate.js +1 -0
  48. package/dist/packages/renderer/deprecated.d.ts +45 -0
  49. package/dist/packages/renderer/deprecated.js +1 -0
  50. package/dist/packages/renderer/index.d.ts +2 -3
  51. package/dist/packages/renderer/index.js +1 -1
  52. package/dist/packages/stats/analyzeWaferMap.js +1 -1
  53. package/dist/packages/stats/binPareto.d.ts +6 -1
  54. package/dist/packages/stats/clusterDetection.d.ts +0 -2
  55. package/dist/packages/stats/deprecated.d.ts +87 -0
  56. package/dist/packages/stats/deprecated.js +1 -0
  57. package/dist/packages/stats/index.d.ts +3 -14
  58. package/dist/packages/stats/index.js +1 -1
  59. package/dist/packages/stats/regions.d.ts +7 -2
  60. package/dist/packages/stats/regions.js +1 -1
  61. package/dist/packages/stats/renderSummaryReport.d.ts +3 -0
  62. package/dist/packages/stats/renderSummaryReport.js +34 -34
  63. package/dist/packages/stats/types.d.ts +0 -43
  64. package/dist/packages/stats/yield.d.ts +12 -6
  65. package/dist/packages/stats/yield.js +1 -1
  66. package/package.json +1 -1
@@ -0,0 +1,87 @@
1
+ import { buildCapabilityData as buildCapabilityDataImpl } from './capability.js';
2
+ import { buildCorrelationMatrix as buildCorrelationMatrixImpl, filterCorrelationMatrix as filterCorrelationMatrixImpl } from './correlation.js';
3
+ import { buildTestBoxplotData as buildTestBoxplotDataImpl } from './boxplot.js';
4
+ import { buildTestTrendData as buildTestTrendDataImpl, trendCentre as trendCentreImpl } from './trend.js';
5
+ import { buildTestPassRateData as buildTestPassRateDataImpl, hasJudgeableTests as hasJudgeableTestsImpl } from './testPassRate.js';
6
+ import { buildTestHistogramData as buildTestHistogramDataImpl, buildTestHistogramSeries as buildTestHistogramSeriesImpl } from './histogram.js';
7
+ import { buildScatterData as buildScatterDataImpl, buildScatterDataGrouped as buildScatterDataGroupedImpl } from './scatter.js';
8
+ import { buildYieldData as buildYieldDataImpl, buildYieldDataCombined as buildYieldDataCombinedImpl } from './yield.js';
9
+ import { buildBinParetoData as buildBinParetoDataImpl, buildBinClusterData as buildBinClusterDataImpl } from './binPareto.js';
10
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
11
+ export declare const buildCapabilityData: typeof buildCapabilityDataImpl;
12
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
13
+ export declare const buildCorrelationMatrix: typeof buildCorrelationMatrixImpl;
14
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
15
+ export declare const filterCorrelationMatrix: typeof filterCorrelationMatrixImpl;
16
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
17
+ export declare const buildTestBoxplotData: typeof buildTestBoxplotDataImpl;
18
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
19
+ export declare const buildTestTrendData: typeof buildTestTrendDataImpl;
20
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
21
+ export declare const trendCentre: typeof trendCentreImpl;
22
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
23
+ export declare const buildTestPassRateData: typeof buildTestPassRateDataImpl;
24
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
25
+ export declare const hasJudgeableTests: typeof hasJudgeableTestsImpl;
26
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
27
+ export declare const buildTestHistogramData: typeof buildTestHistogramDataImpl;
28
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
29
+ export declare const buildTestHistogramSeries: typeof buildTestHistogramSeriesImpl;
30
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
31
+ export declare const buildScatterData: typeof buildScatterDataImpl;
32
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
33
+ export declare const buildScatterDataGrouped: typeof buildScatterDataGroupedImpl;
34
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
35
+ export declare const buildYieldData: typeof buildYieldDataImpl;
36
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
37
+ export declare const buildYieldDataCombined: typeof buildYieldDataCombinedImpl;
38
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
39
+ export declare const buildBinParetoData: typeof buildBinParetoDataImpl;
40
+ /** @deprecated Removed in 0.31.0. Prepared data for the Insights charts, which wmap now draws itself (`insights: { enabled: true }`). */
41
+ export declare const buildBinClusterData: typeof buildBinClusterDataImpl;
42
+ import { buildRingRegions as buildRingRegionsImpl, buildQuadrantRegions as buildQuadrantRegionsImpl, buildSectorRegions as buildSectorRegionsImpl, buildReticlePositionRegions as buildReticlePositionRegionsImpl, buildTestSiteRegions as buildTestSiteRegionsImpl, buildRegionYieldData as buildRegionYieldDataImpl, areQuadrantsAdjacent as areQuadrantsAdjacentImpl, parseRegionKey as parseRegionKeyImpl, sectorCompassNames as sectorCompassNamesImpl } from './regions.js';
43
+ import { classifyPattern as classifyPatternImpl } from './patternClassification.js';
44
+ import { visibleFindings as visibleFindingsImpl } from './filterFindings.js';
45
+ import { computeFunctionalYield as computeFunctionalYieldImpl } from './analyzeWaferMap.js';
46
+ import { resolveMetadataColumns as resolveMetadataColumnsImpl, discoverDieMetadataKeys as discoverDieMetadataKeysImpl } from './metadataColumns.js';
47
+ import { renderFindingsReportHtml as renderFindingsReportHtmlImpl, openHtmlReport as openHtmlReportImpl } from './renderFindingsReport.js';
48
+ import { renderSummaryReportHtml as renderSummaryReportHtmlImpl, renderLotSummaryReportHtml as renderLotSummaryReportHtmlImpl } from './renderSummaryReport.js';
49
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
50
+ export declare const buildRingRegions: typeof buildRingRegionsImpl;
51
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
52
+ export declare const buildQuadrantRegions: typeof buildQuadrantRegionsImpl;
53
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
54
+ export declare const buildSectorRegions: typeof buildSectorRegionsImpl;
55
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
56
+ export declare const buildReticlePositionRegions: typeof buildReticlePositionRegionsImpl;
57
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
58
+ export declare const buildTestSiteRegions: typeof buildTestSiteRegionsImpl;
59
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
60
+ export declare const buildRegionYieldData: typeof buildRegionYieldDataImpl;
61
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
62
+ export declare const areQuadrantsAdjacent: typeof areQuadrantsAdjacentImpl;
63
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
64
+ export declare const parseRegionKey: typeof parseRegionKeyImpl;
65
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
66
+ export declare const sectorCompassNames: typeof sectorCompassNamesImpl;
67
+ /** @deprecated Removed in 0.31.0. `analyzeWaferMap` reports the classified pattern as a finding (comparison.family 'spatial-pattern'). */
68
+ export declare const classifyPattern: typeof classifyPatternImpl;
69
+ /** @deprecated Removed in 0.31.0. It is an internal helper that was exported by accident; `buildWaferMap`, `analyzeWaferMap` and the renderers already apply it. */
70
+ export declare const visibleFindings: typeof visibleFindingsImpl;
71
+ /** @deprecated Removed in 0.31.0. `analyzeWaferMap` returns the same figures as `stats.functionalYield`. */
72
+ export declare const computeFunctionalYield: typeof computeFunctionalYieldImpl;
73
+ /** @deprecated Removed in 0.31.0. The die list resolves its metadata columns itself (the `dieList.metadataColumns` option). */
74
+ export declare const resolveMetadataColumns: typeof resolveMetadataColumnsImpl;
75
+ /** @deprecated Removed in 0.31.0. The die list resolves its metadata columns itself (the `dieList.metadataColumns` option). */
76
+ export declare const discoverDieMetadataKeys: typeof discoverDieMetadataKeysImpl;
77
+ /** @deprecated Removed in 0.31.0. Reports open from the Summary panel's report button; route them into your host with `setReportOpener`. */
78
+ export declare const renderFindingsReportHtml: typeof renderFindingsReportHtmlImpl;
79
+ /** @deprecated Removed in 0.31.0. Reports open from the Summary panel's report button; route them into your host with `setReportOpener`. */
80
+ export declare const openHtmlReport: typeof openHtmlReportImpl;
81
+ /** @deprecated Removed in 0.31.0. Reports open from the Summary panel's report button; route them into your host with `setReportOpener`. */
82
+ export declare const renderSummaryReportHtml: typeof renderSummaryReportHtmlImpl;
83
+ /** @deprecated Removed in 0.31.0. Reports open from the Summary panel's report button; route them into your host with `setReportOpener`. */
84
+ export declare const renderLotSummaryReportHtml: typeof renderLotSummaryReportHtmlImpl;
85
+ /** @deprecated Removed in 0.31.0. `buildFacetTable` applies it by default. */
86
+ export declare const DEFAULT_FACET_CURATION: Record<string, import("./facets.js").FacetCuration>;
87
+ //# sourceMappingURL=deprecated.d.ts.map
@@ -0,0 +1 @@
1
+ import{deprecated as t}from"../renderer/deprecate.js";import{buildCapabilityData as s}from"./capability.js";import{buildCorrelationMatrix as l,filterCorrelationMatrix as n}from"./correlation.js";import{buildTestBoxplotData as d}from"./boxplot.js";import{buildTestTrendData as p,trendCentre as m}from"./trend.js";import{buildTestPassRateData as u,hasJudgeableTests as b}from"./testPassRate.js";import{buildTestHistogramData as c,buildTestHistogramSeries as R}from"./histogram.js";import{buildScatterData as D,buildScatterDataGrouped as g}from"./scatter.js";import{buildYieldData as I,buildYieldDataCombined as T}from"./yield.js";import{buildBinParetoData as C,buildBinClusterData as x}from"./binPareto.js";const a="It prepared data for the Insights charts, which wmap now draws itself (insights: { enabled: true }). If you depend on it, say so at https://github.com/wafertools/wafermap/issues.";export const buildCapabilityData=t(s,"buildCapabilityData",a),buildCorrelationMatrix=t(l,"buildCorrelationMatrix",a),filterCorrelationMatrix=t(n,"filterCorrelationMatrix",a),buildTestBoxplotData=t(d,"buildTestBoxplotData",a),buildTestTrendData=t(p,"buildTestTrendData",a),trendCentre=t(m,"trendCentre",a),buildTestPassRateData=t(u,"buildTestPassRateData",a),hasJudgeableTests=t(b,"hasJudgeableTests",a),buildTestHistogramData=t(c,"buildTestHistogramData",a),buildTestHistogramSeries=t(R,"buildTestHistogramSeries",a),buildScatterData=t(D,"buildScatterData",a),buildScatterDataGrouped=t(g,"buildScatterDataGrouped",a),buildYieldData=t(I,"buildYieldData",a),buildYieldDataCombined=t(T,"buildYieldDataCombined",a),buildBinParetoData=t(C,"buildBinParetoData",a),buildBinClusterData=t(x,"buildBinClusterData",a);import{deprecatedValue as f}from"../renderer/deprecate.js";import{buildRingRegions as y,buildQuadrantRegions as $,buildSectorRegions as S,buildReticlePositionRegions as A,buildTestSiteRegions as h,buildRegionYieldData as H,areQuadrantsAdjacent as E,parseRegionKey as F,sectorCompassNames as M}from"./regions.js";import{classifyPattern as P}from"./patternClassification.js";import{visibleFindings as Y}from"./filterFindings.js";import{computeFunctionalYield as _}from"./analyzeWaferMap.js";import{resolveMetadataColumns as N,discoverDieMetadataKeys as v}from"./metadataColumns.js";import{renderFindingsReportHtml as B,openHtmlReport as L}from"./renderFindingsReport.js";import{renderSummaryReportHtml as w,renderLotSummaryReportHtml as U}from"./renderSummaryReport.js";import{DEFAULT_FACET_CURATION as O}from"./facets.js";const e="If you depend on it, say so at https://github.com/wafertools/wafermap/issues.",i="It is an internal helper that was exported by accident; buildWaferMap, analyzeWaferMap and the renderers already apply it.",K="analyzeWaferMap reports the classified pattern as a finding (comparison.family 'spatial-pattern').",Q="analyzeWaferMap returns the same figures as stats.functionalYield.",r="The die list resolves its metadata columns itself (the dieList.metadataColumns option).",o="Reports open from the Summary panel's report button; route them into your host with setReportOpener.";export const buildRingRegions=t(y,"buildRingRegions",`${i} ${e}`),buildQuadrantRegions=t($,"buildQuadrantRegions",`${i} ${e}`),buildSectorRegions=t(S,"buildSectorRegions",`${i} ${e}`),buildReticlePositionRegions=t(A,"buildReticlePositionRegions",`${i} ${e}`),buildTestSiteRegions=t(h,"buildTestSiteRegions",`${i} ${e}`),buildRegionYieldData=t(H,"buildRegionYieldData",`${i} ${e}`),areQuadrantsAdjacent=t(E,"areQuadrantsAdjacent",`${i} ${e}`),parseRegionKey=t(F,"parseRegionKey",`${i} ${e}`),sectorCompassNames=t(M,"sectorCompassNames",`${i} ${e}`),classifyPattern=t(P,"classifyPattern",`${K} ${e}`),visibleFindings=t(Y,"visibleFindings",`${i} ${e}`),computeFunctionalYield=t(_,"computeFunctionalYield",`${Q} ${e}`),resolveMetadataColumns=t(N,"resolveMetadataColumns",`${r} ${e}`),discoverDieMetadataKeys=t(v,"discoverDieMetadataKeys",`${r} ${e}`),renderFindingsReportHtml=t(B,"renderFindingsReportHtml",`${o} ${e}`),openHtmlReport=t(L,"openHtmlReport",`${o} ${e}`),renderSummaryReportHtml=t(w,"renderSummaryReportHtml",`${o} ${e}`),renderLotSummaryReportHtml=t(U,"renderLotSummaryReportHtml",`${o} ${e}`),DEFAULT_FACET_CURATION=f(O,"DEFAULT_FACET_CURATION");
@@ -3,33 +3,22 @@ export * from './regions.js';
3
3
  export * from './analyzeWaferMap.js';
4
4
  export * from './analyzeWaferLot.js';
5
5
  export * from './filterFindings.js';
6
- export { classifyPattern } from './patternClassification.js';
7
6
  export type { PatternLabel, PatternClassification, PatternFeatures } from './patternClassification.js';
8
- export { renderFindingsReportHtml, openHtmlReport, setReportOpener } from './renderFindingsReport.js';
7
+ export { setReportOpener } from './renderFindingsReport.js';
9
8
  export type { SummaryReportParams, LotSummaryReportParams } from './renderSummaryReport.js';
10
- export { renderSummaryReportHtml, renderLotSummaryReportHtml } from './renderSummaryReport.js';
11
- export { buildFacetTable, facetValueOf, FACET_NONE_VALUE, DEFAULT_FACET_CURATION } from './facets.js';
9
+ export { buildFacetTable, facetValueOf, FACET_NONE_VALUE } from './facets.js';
12
10
  export type { FacetField, FacetValue, FacetCuration, FacetItem, BuildFacetTableOptions } from './facets.js';
13
- export { resolveMetadataColumns, discoverDieMetadataKeys } from './metadataColumns.js';
14
11
  export type { MetadataColumn, MetadataColumnScope, MetadataColumnSet, MetadataKeySelection, ResolveMetadataColumnsOptions, } from './metadataColumns.js';
15
12
  export { mergeTestDefs } from './mergeTestDefs.js';
16
13
  export type { MergedTestDefs, TestDefConflict, TestDefConflictKind } from './mergeTestDefs.js';
17
- export { buildCapabilityData } from './capability.js';
18
14
  export type { CapabilityDatum, CapabilityItem } from './capability.js';
19
- export { buildCorrelationMatrix, filterCorrelationMatrix } from './correlation.js';
20
15
  export type { CorrelationTestInfo, CorrelationCell, CorrelationMatrix, CorrelationSummary } from './correlation.js';
21
- export { buildTestBoxplotData } from './boxplot.js';
22
16
  export type { BoxplotDatum, BoxplotItem } from './boxplot.js';
23
- export { buildTestTrendData, trendCentre } from './trend.js';
24
17
  export type { TrendDatum, TrendItem } from './trend.js';
25
- export { buildTestPassRateData, hasJudgeableTests } from './testPassRate.js';
26
18
  export type { TestPassKind, TestPassRateData, TestPassRateItem, TestPassRateRow, TestPassRateValue } from './testPassRate.js';
27
- export { buildTestHistogramData, buildTestHistogramSeries } from './histogram.js';
28
19
  export type { HistogramBucket, HistogramItem, HistogramSeries, HistogramSeriesData } from './histogram.js';
29
- export { buildScatterData, buildScatterDataGrouped } from './scatter.js';
30
20
  export type { ScatterPoint, ScatterItem } from './scatter.js';
31
- export { buildYieldData, buildYieldDataCombined } from './yield.js';
32
21
  export type { ChartDatum, YieldItem, YieldSortBy } from './yield.js';
33
- export { buildBinParetoData, buildBinClusterData } from './binPareto.js';
34
22
  export type { BinType, BinItem, BinCluster, BinClusterData } from './binPareto.js';
23
+ export { buildCapabilityData, buildCorrelationMatrix, filterCorrelationMatrix, buildTestBoxplotData, buildTestTrendData, trendCentre, buildTestPassRateData, hasJudgeableTests, buildTestHistogramData, buildTestHistogramSeries, buildScatterData, buildScatterDataGrouped, buildYieldData, buildYieldDataCombined, buildBinParetoData, buildBinClusterData, buildRingRegions, buildQuadrantRegions, buildSectorRegions, buildReticlePositionRegions, buildTestSiteRegions, buildRegionYieldData, areQuadrantsAdjacent, parseRegionKey, sectorCompassNames, classifyPattern, visibleFindings, computeFunctionalYield, resolveMetadataColumns, discoverDieMetadataKeys, renderFindingsReportHtml, openHtmlReport, renderSummaryReportHtml, renderLotSummaryReportHtml, DEFAULT_FACET_CURATION, } from './deprecated.js';
35
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- export*from"./types.js";export*from"./regions.js";export*from"./analyzeWaferMap.js";export*from"./analyzeWaferLot.js";export*from"./filterFindings.js";export{classifyPattern}from"./patternClassification.js";export{renderFindingsReportHtml,openHtmlReport,setReportOpener}from"./renderFindingsReport.js";export{renderSummaryReportHtml,renderLotSummaryReportHtml}from"./renderSummaryReport.js";export{buildFacetTable,facetValueOf,FACET_NONE_VALUE,DEFAULT_FACET_CURATION}from"./facets.js";export{resolveMetadataColumns,discoverDieMetadataKeys}from"./metadataColumns.js";export{mergeTestDefs}from"./mergeTestDefs.js";export{buildCapabilityData}from"./capability.js";export{buildCorrelationMatrix,filterCorrelationMatrix}from"./correlation.js";export{buildTestBoxplotData}from"./boxplot.js";export{buildTestTrendData,trendCentre}from"./trend.js";export{buildTestPassRateData,hasJudgeableTests}from"./testPassRate.js";export{buildTestHistogramData,buildTestHistogramSeries}from"./histogram.js";export{buildScatterData,buildScatterDataGrouped}from"./scatter.js";export{buildYieldData,buildYieldDataCombined}from"./yield.js";export{buildBinParetoData,buildBinClusterData}from"./binPareto.js";
1
+ export*from"./types.js";export*from"./regions.js";export*from"./analyzeWaferMap.js";export*from"./analyzeWaferLot.js";export*from"./filterFindings.js";export{setReportOpener}from"./renderFindingsReport.js";export{buildFacetTable,facetValueOf,FACET_NONE_VALUE}from"./facets.js";export{mergeTestDefs}from"./mergeTestDefs.js";export{buildCapabilityData,buildCorrelationMatrix,filterCorrelationMatrix,buildTestBoxplotData,buildTestTrendData,trendCentre,buildTestPassRateData,hasJudgeableTests,buildTestHistogramData,buildTestHistogramSeries,buildScatterData,buildScatterDataGrouped,buildYieldData,buildYieldDataCombined,buildBinParetoData,buildBinClusterData,buildRingRegions,buildQuadrantRegions,buildSectorRegions,buildReticlePositionRegions,buildTestSiteRegions,buildRegionYieldData,areQuadrantsAdjacent,parseRegionKey,sectorCompassNames,classifyPattern,visibleFindings,computeFunctionalYield,resolveMetadataColumns,discoverDieMetadataKeys,renderFindingsReportHtml,openHtmlReport,renderSummaryReportHtml,renderLotSummaryReportHtml,DEFAULT_FACET_CURATION}from"./deprecated.js";
@@ -1,4 +1,4 @@
1
- import { type Die, type PositionedDie, type Wafer } from '../core/index.js';
1
+ import type { Die, PositionedDie, Wafer } from '../core/index.js';
2
2
  import type { ReticleConfig } from '../renderer/buildWaferMap.js';
3
3
  export interface StatsRegion {
4
4
  family: 'ring' | 'quadrant' | 'reticle-position' | 'test-site' | 'sector';
@@ -21,8 +21,13 @@ export interface RegionYieldDatum {
21
21
  * computation — consumed by both the summary panel's progress-bar rows and
22
22
  * the ring/quadrant yield diagrams, which previously each recomputed the
23
23
  * same pass/total tally independently.
24
+ *
25
+ * `passBins` is one set for every wafer, or a lookup by wafer index for a lot
26
+ * whose wafers were built with different pass bins (pass each item's
27
+ * `WaferMapResult.passBins`). Each die is judged by `diePassStatus`, the rule
28
+ * yield itself uses.
24
29
  */
25
- export declare function buildRegionYieldData(diesByWafer: Die[][], allWafers: Wafer[], ringCount: number, passBins: number[], regionBuilder: (dies: PositionedDie[], wafer: Wafer, ringCount: number) => StatsRegion[]): RegionYieldDatum[];
30
+ export declare function buildRegionYieldData(diesByWafer: Die[][], allWafers: Wafer[], ringCount: number, passBins: readonly number[] | ((waferIndex: number) => readonly number[]), regionBuilder: (dies: PositionedDie[], wafer: Wafer, ringCount: number) => StatsRegion[]): RegionYieldDatum[];
26
31
  /** Compass bearing names for a given sector count, ordered CCW from East. */
27
32
  export declare function sectorCompassNames(sectorCount: number): string[];
28
33
  /** True when two quadrants share an edge (NE–NW, NE–SE, NW–SW, SE–SW); diagonals are not adjacent. */
@@ -1 +1 @@
1
- import{classifyDie as E,getReticleCell as W,getRingLabel as b,isPositionedDie as M,getDieKey as k}from"../core/index.js";function y(t){return k(t)}export function buildRegionYieldData(t,s,o,e,n){const i=new Set(e),r=new Map,a=[];for(let l=0;l<s.length;l++){const c=t[l];if(!c?.length)continue;const d=n(c.filter(M),s[l],o),S=new Map(c.map(u=>[y(u),u]));for(const u of d){a.includes(u.key)||a.push(u.key);const g=r.get(u.key)??{label:u.label,pass:0,total:0};for(const h of u.dieKeys){const f=S.get(h);if(!f||f.partial||f.edgeExcluded)continue;const p=f.hbin??f.sbin;p!=null&&(g.total++,i.has(p)&&g.pass++)}r.set(u.key,g)}}return a.map(l=>{const c=r.get(l);return c.total===0?null:{key:l,label:c.label,n:c.total,yieldPercent:c.pass/c.total*100}}).filter(l=>l!==null)}const x=["E","ENE","NE","NNE","N","NNW","NW","WNW","W","WSW","SW","SSW","S","SSE","SE","ESE"],R=["E","NE","N","NW","W","SW","S","SE"],K=["E","N","W","S"];export function sectorCompassNames(t){const s=[4,8,16,32].includes(t)?t:16;return s===4?K:s===8?R:x}const q={NE:["NW","SE"],NW:["NE","SW"],SE:["NE","SW"],SW:["NW","SE"]};export function areQuadrantsAdjacent(t,s){return q[t]?.includes(s)??!1}export function parseRegionKey(t){return t.startsWith("ring:")?{family:"ring",ring:Number(t.slice(5))}:t.startsWith("quadrant:")?{family:"quadrant",quadrant:t.slice(9)}:t.startsWith("sector:")?{family:"sector",sector:t.slice(7)}:{family:"unknown"}}export function buildRingRegions(t,s,o){const e=new Map;for(const n of t){const{ring:i}=E(n,s,{ringCount:o}),r=`ring:${i}`,a=e.get(r)??{family:"ring",key:r,label:b(i,o),dieKeys:[]};a.dieKeys.push(y(n)),e.set(r,a)}return[...e.values()].sort((n,i)=>n.key.localeCompare(i.key))}export function buildQuadrantRegions(t,s,o){const e=new Map;for(const i of t){const{quadrant:r}=E(i,s,{ringCount:o}),a=`quadrant:${r}`,l=e.get(a)??{family:"quadrant",key:a,label:r,dieKeys:[]};l.dieKeys.push(y(i)),e.set(a,l)}const n=new Map([["quadrant:NE",0],["quadrant:NW",1],["quadrant:SE",2],["quadrant:SW",3]]);return[...e.values()].sort((i,r)=>(n.get(i.key)??4)-(n.get(r.key)??4))}export function buildReticlePositionRegions(t,s){if(!s)return[];const o=new Map;for(const e of t){const{column:n,row:i}=W(e,s),r=`reticle-position:cell:${n},${i}`,a=o.get(r)??{family:"reticle-position",key:r,label:`Reticle cell (${n}, ${i})`,dieKeys:[]};a.dieKeys.push(y(e)),o.set(r,a)}return[...o.values()].sort((e,n)=>e.key.localeCompare(n.key))}const w=3;export function buildTestSiteRegions(t,s=!1){const o=new Map;for(const e of t){if(e.siteNum===void 0)continue;const n=o.get(e.siteNum)??[];n.push(y(e)),o.set(e.siteNum,n)}if(!s){let e=0;for(const n of o.values())n.length>=w&&e++;if(e<2)return[]}return[...o.entries()].sort(([e],[n])=>e-n).map(([e,n])=>({family:"test-site",key:`test-site:${e}`,label:`Site ${e}`,dieKeys:n}))}export function buildSectorRegions(t,s,o){const e=[4,8,16,32].includes(o)?o:16,n=sectorCompassNames(e),i=new Map,r=s.center.x,a=s.center.y,l=s.radius;for(const c of t){const d=c.physX-r,S=c.physY-a;if(Math.hypot(d,S)/l<.2)continue;const g=Math.PI/e,h=(Math.atan2(S,d)+2*Math.PI+g)%(2*Math.PI),f=Math.floor(h/(2*Math.PI)*e)%e,p=n[f],N=`sector:${p}`,m=i.get(N)??{family:"sector",key:N,label:`Sector ${p}`,dieKeys:[]};m.dieKeys.push(y(c)),i.set(N,m)}return[...i.values()].sort((c,d)=>c.key.localeCompare(d.key))}
1
+ import{classifyDie as E,getRingLabel as W}from"../core/classify.js";import{getReticleCell as b}from"../core/reticle.js";import{isPositionedDie as M,diePassStatus as k,getDieKey as x}from"../core/dies.js";function y(t){return x(t)}export function buildRegionYieldData(t,o,r,e,n){const i=new Map,a=[];for(let s=0;s<o.length;s++){const c=t[s];if(!c?.length)continue;const u=new Set(typeof e=="function"?e(s):e),f=n(c.filter(M),o[s],r),S=new Map(c.map(l=>[y(l),l]));for(const l of f){a.includes(l.key)||a.push(l.key);const g=i.get(l.key)??{label:l.label,pass:0,total:0};for(const m of l.dieKeys){const d=S.get(m);if(!d||d.partial||d.edgeExcluded)continue;const p=k(d,u);p!==void 0&&(g.total++,p&&g.pass++)}i.set(l.key,g)}}return a.map(s=>{const c=i.get(s);return c.total===0?null:{key:s,label:c.label,n:c.total,yieldPercent:c.pass/c.total*100}}).filter(s=>s!==null)}const R=["E","ENE","NE","NNE","N","NNW","NW","WNW","W","WSW","SW","SSW","S","SSE","SE","ESE"],K=["E","NE","N","NW","W","SW","S","SE"],q=["E","N","W","S"];export function sectorCompassNames(t){const o=[4,8,16,32].includes(t)?t:16;return o===4?q:o===8?K:R}const P={NE:["NW","SE"],NW:["NE","SW"],SE:["NE","SW"],SW:["NW","SE"]};export function areQuadrantsAdjacent(t,o){return P[t]?.includes(o)??!1}export function parseRegionKey(t){return t.startsWith("ring:")?{family:"ring",ring:Number(t.slice(5))}:t.startsWith("quadrant:")?{family:"quadrant",quadrant:t.slice(9)}:t.startsWith("sector:")?{family:"sector",sector:t.slice(7)}:{family:"unknown"}}export function buildRingRegions(t,o,r){const e=new Map;for(const n of t){const{ring:i}=E(n,o,{ringCount:r}),a=`ring:${i}`,s=e.get(a)??{family:"ring",key:a,label:W(i,r),dieKeys:[]};s.dieKeys.push(y(n)),e.set(a,s)}return[...e.values()].sort((n,i)=>n.key.localeCompare(i.key))}export function buildQuadrantRegions(t,o,r){const e=new Map;for(const i of t){const{quadrant:a}=E(i,o,{ringCount:r}),s=`quadrant:${a}`,c=e.get(s)??{family:"quadrant",key:s,label:a,dieKeys:[]};c.dieKeys.push(y(i)),e.set(s,c)}const n=new Map([["quadrant:NE",0],["quadrant:NW",1],["quadrant:SE",2],["quadrant:SW",3]]);return[...e.values()].sort((i,a)=>(n.get(i.key)??4)-(n.get(a.key)??4))}export function buildReticlePositionRegions(t,o){if(!o)return[];const r=new Map;for(const e of t){const{column:n,row:i}=b(e,o),a=`reticle-position:cell:${n},${i}`,s=r.get(a)??{family:"reticle-position",key:a,label:`Reticle cell (${n}, ${i})`,dieKeys:[]};s.dieKeys.push(y(e)),r.set(a,s)}return[...r.values()].sort((e,n)=>e.key.localeCompare(n.key))}const w=3;export function buildTestSiteRegions(t,o=!1){const r=new Map;for(const e of t){if(e.siteNum===void 0)continue;const n=r.get(e.siteNum)??[];n.push(y(e)),r.set(e.siteNum,n)}if(!o){let e=0;for(const n of r.values())n.length>=w&&e++;if(e<2)return[]}return[...r.entries()].sort(([e],[n])=>e-n).map(([e,n])=>({family:"test-site",key:`test-site:${e}`,label:`Site ${e}`,dieKeys:n}))}export function buildSectorRegions(t,o,r){const e=[4,8,16,32].includes(r)?r:16,n=sectorCompassNames(e),i=new Map,a=o.center.x,s=o.center.y,c=o.radius;for(const u of t){const f=u.physX-a,S=u.physY-s;if(Math.hypot(f,S)/c<.2)continue;const g=Math.PI/e,m=(Math.atan2(S,f)+2*Math.PI+g)%(2*Math.PI),d=Math.floor(m/(2*Math.PI)*e)%e,p=n[d],N=`sector:${p}`,h=i.get(N)??{family:"sector",key:N,label:`Sector ${p}`,dieKeys:[]};h.dieKeys.push(y(u)),i.set(N,h)}return[...i.values()].sort((u,f)=>u.key.localeCompare(f.key))}
@@ -32,6 +32,8 @@ export interface LotSummaryReportParams {
32
32
  label: string;
33
33
  wafer?: Wafer;
34
34
  dies?: Die[];
35
+ /** This wafer's own pass bins (`WaferMapResult.passBins`). Omitted ⇒ the top-level `passBins`. */
36
+ passBins?: number[];
35
37
  /** Reused directly as `analyzeWaferLot`'s `perWaferSummaries` — the expensive
36
38
  * per-wafer pass (`analyzeWaferMap`) is never re-run here. */
37
39
  statsSummary?: StatsSummary;
@@ -39,6 +41,7 @@ export interface LotSummaryReportParams {
39
41
  hbinDefs?: BinDef[];
40
42
  sbinDefs?: BinDef[];
41
43
  testDefs?: TestDef[];
44
+ /** Fallback for items that carry no `passBins` of their own. Default `[1]`. */
42
45
  passBins?: number[];
43
46
  ringCount?: number;
44
47
  /** Passthrough to the internal per-group `analyzeWaferLot` call, e.g. `{ enableTestValueAnalysis: true }`. */
@@ -1,71 +1,71 @@
1
- import{isParametricTest as ge}from"../renderer/buildWaferMap.js";import{buildRingRegions as E,buildQuadrantRegions as k}from"./regions.js";import{openHtmlReport as he}from"./renderFindingsReport.js";import{analyzeWaferLot as be}from"./analyzeWaferLot.js";import{computeFunctionalYield as ye}from"./analyzeWaferMap.js";import{sortBinsForDisplay as C}from"./binPareto.js";import{buildFacetTable as Se,facetValueOf as we,FACET_NONE_VALUE as $e}from"./facets.js";import{visibleFindings as H}from"./filterFindings.js";import{buildYieldDataCombined as xe}from"./yield.js";import{describeWaferPopulation as I,populationLabel as ve}from"./population.js";import{buildTestPassRateData as Te,hasJudgeableTests as Fe,poolFunctionalYield as De}from"./testPassRate.js";import{buildCapabilityData as Pe}from"./capability.js";import{fmt as B}from"../renderer/fmt.js";import{getDieKey as L,isPositionedDie as j}from"../core/dies.js";import{formatFindingDelta as Be,formatFindingCoverage as Ye,formatFindingTooltip as Me,escHtml as S,renderMetadataSection as A,renderMetricGrid as O,renderSection as v,renderSeverityBadge as Ne,renderTable as F,reportStyles as W}from"./reportHtml.js";function Y(s,l){return l===0?"\u2014":`${(s/l*100).toFixed(1)}%`}function We(s){if(!s)return"";const l=s.lot??s.lotId,i=s.wafer??s.waferId,n=[l,i].filter(Boolean).map(String);return n.length?` \u2014 ${n.map(S).join(" \xB7 ")}`:""}function z(s,l,i,n,a=[1]){const e=new Map;if(n)for(const[t,c]of Object.entries(n))e.set(Number(t),c);else for(const t of s){if(t.partial||t.edgeExcluded)continue;const c=i==="hard"?t.hbin:t.sbin;c!=null&&e.set(c,(e.get(c)??0)+1)}if(!e.size)return"";const o=[...e.values()].reduce((t,c)=>t+c,0),r=l?new Map(l.map(t=>[t.bin,t])):null,d=C(e.entries(),a).map(([t,c])=>{const m=r?.get(t)?.name??"\u2014";return[String(t),m,String(c),Y(c,o)]});return v(i==="hard"?"Hard Bin Breakdown":"Soft Bin Breakdown",F(["Bin","Name","Count","%"],d,{className:"compact"}))}function G(s,l,i,n){const a=new Set(n),e=new Map(i.map(d=>[L(d),d]));if(!i.some(d=>d.hbin!=null||d.sbin!=null)||!l.length)return"";const r=[];for(const d of l){let u=0,t=0;for(const c of d.dieKeys){const b=e.get(c);if(!b||b.partial||b.edgeExcluded)continue;const m=b.hbin??b.sbin;m!=null&&(t++,a.has(m)&&u++)}t&&r.push([d.label,String(u),String(t),Y(u,t)])}return r.length?v(s,F(["Region","Pass","Total","Yield"],r,{className:"compact"})):""}function K(s,l,i){if(!l.length)return"";const n=s.filter(o=>!o.partial&&!o.edgeExcluded),a=new Map((i??[]).map(o=>[o.testNumber,o])),e=[];for(const o of l.filter(ge)){const r=o.testNumber,d=o.unit||void 0,u=a.get(r);let t,c,b;if(u)({min:t,max:c,mean:b}=u);else{const m=n.map(w=>w.testValues?.[r]).filter(w=>w!==void 0&&isFinite(w));if(!m.length)continue;m.sort((w,p)=>w-p),t=m[0],c=m[m.length-1],b=m.reduce((w,p)=>w+p,0)/m.length}e.push([S(o.name),B(t,d),B(b,d),B(c,d)])}return e.length?v("Test Values",F(["Test","Min","Mean","Max"],e,{className:"compact"})):""}function U(s,l,i){const n=i??ye(s,l);if(!n?.length)return"";const a=n.map(e=>[S(e.label),String(e.totalDies),String(e.passDies),String(e.failDies),e.passRatePercent!==null?`${e.passRatePercent.toFixed(1)}%`:"\u2014"]);return v("Functional Tests",F(["Test","N","Pass","Fail","Pass Rate"],a,{className:"compact"}))}function V(s,l){const i=Pe(s,l);if(!i.length)return"";const n=e=>e===null?"\u2014":e.toFixed(2),a=i.map(e=>[S(e.label),e.hasSpec?`${B(e.lsl,e.unit)} \u2013 ${B(e.usl,e.unit)}`:"\u2014",B(e.mean,e.unit),n(e.cp),n(e.cpk),n(e.pp),n(e.ppk)]);return v("Process Capability",F(["Test","Spec (LSL\u2013USL)","Mean","Cp","Cpk","Pp","Ppk"],a,{className:"compact"}))}function _(s,l){const i=s.map(a=>`<tr title="${S(Me(a))}">
2
- <td class="tight">${Ne(a.severity)}</td>
3
- <td class="tight">${S(a.comparison.left)}</td>
4
- <td>${S(a.variable.label)}</td>
5
- <td class="numeric">${S(Be(a))}</td>
6
- <td class="numeric">${S(Ye(a,l))}</td>
1
+ import{waferDisplayLabel as ye}from"../core/waferLabel.js";import{binPassSets as Se,binPassSetsByWafer as we}from"../renderer/binColors.js";import{itemPassBins as R,passBinsLabel as $e}from"../core/passBins.js";import{isParametricTest as xe}from"../renderer/buildWaferMap.js";import{buildRingRegions as H,buildQuadrantRegions as I,buildRegionYieldData as ve}from"./regions.js";import{openHtmlReport as Te}from"./renderFindingsReport.js";import{analyzeWaferLot as Fe}from"./analyzeWaferLot.js";import{computeFunctionalYield as Be}from"./analyzeWaferMap.js";import{sortBinsForDisplay as j}from"./binPareto.js";import{buildFacetTable as De,facetValueOf as Pe,FACET_NONE_VALUE as Ye}from"./facets.js";import{visibleFindings as A}from"./filterFindings.js";import{buildYieldDataCombined as Me}from"./yield.js";import{describeWaferPopulation as O,populationLabel as We}from"./population.js";import{buildTestPassRateData as Ne,hasJudgeableTests as Re,poolFunctionalYield as Ce}from"./testPassRate.js";import{buildCapabilityData as Ee}from"./capability.js";import{fmt as D}from"../renderer/fmt.js";import{getDieKey as ke,isPositionedDie as Le,diePassStatus as G}from"../core/dies.js";import{formatFindingDelta as He,formatFindingCoverage as Ie,formatFindingTooltip as je,escHtml as h,renderMetadataSection as z,renderMetricGrid as U,renderSection as x,renderSeverityBadge as Ae,renderTable as F,reportStyles as C}from"./reportHtml.js";function N(a,r){return r===0?"\u2014":`${(a/r*100).toFixed(1)}%`}function Oe(a){if(!a)return"";const r=a.lot??a.lotId,o=a.wafer??a.waferId,t=[r,o].filter(Boolean).map(String);return t.length?` \u2014 ${t.map(h).join(" \xB7 ")}`:""}function V(a,r,o,t,i=[1]){const e=new Map;if(t)for(const[n,c]of Object.entries(t))e.set(Number(n),c);else for(const n of a){if(n.partial||n.edgeExcluded)continue;const c=o==="hard"?n.hbin:n.sbin;c!=null&&e.set(c,(e.get(c)??0)+1)}if(!e.size)return"";const s=[...e.values()].reduce((n,c)=>n+c,0),l=r?new Map(r.map(n=>[n.bin,n])):null,d=j(e.entries(),Se(a,i)[o]).map(([n,c])=>{const f=l?.get(n)?.name??"\u2014";return[String(n),f,String(c),N(c,s)]});return x(o==="hard"?"Hard Bin Breakdown":"Soft Bin Breakdown",F(["Bin","Name","Count","%"],d,{className:"compact"}))}function _(a,r,o,t){const i=new Set(t),e=new Map(o.map(d=>[ke(d),d]));if(!o.some(d=>d.hbin!=null||d.sbin!=null)||!r.length)return"";const l=[];for(const d of r){let m=0,n=0;for(const c of d.dieKeys){const b=e.get(c);if(!b||b.partial||b.edgeExcluded)continue;const f=G(b,i);f!==void 0&&(n++,f&&m++)}n&&l.push([d.label,String(m),String(n),N(m,n)])}return l.length?x(a,F(["Region","Pass","Total","Yield"],l,{className:"compact"})):""}function K(a,r,o){if(!r.length)return"";const t=a.filter(s=>!s.partial&&!s.edgeExcluded),i=new Map((o??[]).map(s=>[s.testNumber,s])),e=[];for(const s of r.filter(xe)){const l=s.testNumber,d=s.unit||void 0,m=i.get(l);let n,c,b;if(m)({min:n,max:c,mean:b}=m);else{const f=t.map(w=>w.testValues?.[l]).filter(w=>w!==void 0&&isFinite(w));if(!f.length)continue;f.sort((w,y)=>w-y),n=f[0],c=f[f.length-1],b=f.reduce((w,y)=>w+y,0)/f.length}e.push([h(s.name),D(n,d),D(b,d),D(c,d)])}return e.length?x("Test Values",F(["Test","Min","Mean","Max"],e,{className:"compact"})):""}function Q(a,r,o){const t=o??Be(a,r);if(!t?.length)return"";const i=t.map(e=>[h(e.label),String(e.totalDies),String(e.passDies),String(e.failDies),e.passRatePercent!==null?`${e.passRatePercent.toFixed(1)}%`:"\u2014"]);return x("Functional Tests",F(["Test","N","Pass","Fail","Pass Rate"],i,{className:"compact"}))}function q(a,r){const o=Ee(a,r);if(!o.length)return"";const t=e=>e===null?"\u2014":e.toFixed(2),i=o.map(e=>[h(e.label),e.hasSpec?`${D(e.lsl,e.unit)} \u2013 ${D(e.usl,e.unit)}`:"\u2014",D(e.mean,e.unit),t(e.cp),t(e.cpk),t(e.pp),t(e.ppk)]);return x("Process Capability",F(["Test","Spec (LSL\u2013USL)","Mean","Cp","Cpk","Pp","Ppk"],i,{className:"compact"}))}function J(a,r){const o=a.map(i=>`<tr title="${h(je(i))}">
2
+ <td class="tight">${Ae(i.severity)}</td>
3
+ <td class="tight">${h(i.comparison.left)}</td>
4
+ <td>${h(i.variable.label)}</td>
5
+ <td class="numeric">${h(He(i))}</td>
6
+ <td class="numeric">${h(Ie(i,r))}</td>
7
7
  </tr>`).join(`
8
8
  `);return`<table class="report-table findings-table compact"><thead><tr>
9
- <th>Severity</th><th>Region</th><th>Metric</th><th class="numeric">Delta</th><th class="numeric">${l!==void 0?"Wafers":"N (region/rest)"}</th>
10
- </tr></thead><tbody>${i}</tbody></table>`}function Q(s,l){const i=H(s);return i.length?v("Findings",_(i,l)):""}export function renderSummaryReportHtml(s,l={}){const{wafer:i,dies:n,yieldSummary:a,dataCoverage:e,hbinDefs:o,sbinDefs:r,testDefs:d=[],statsSummary:u,passBins:t=[1],ringCount:c=4}=s,b=i.metadata,m=We(b),w=l.title??`Wafer Summary${m}`,p=new Date().toLocaleString(),f=n.some(P=>P.hbin!=null),g=n.some(P=>P.sbin!=null),y=n.filter(j),$=E(y,i,c),x=k(y,i,c),T=[{label:"Total dies",value:String(a.totalDies)},{label:"Filled dies",value:String(e.filledDies),hint:`${Y(e.filledDies,e.totalDies)} fill`},{label:"Pass dies",value:String(a.passDies)},{label:"Fail dies",value:String(a.failDies)},...a.partialDies>0?[{label:"Partial",value:String(a.partialDies)}]:[],...a.yieldPercent!==null?[{label:`Yield (pass: ${t.length===1?`bin ${t[0]}`:`bins ${t.join(", ")}`})`,value:`${a.yieldPercent.toFixed(1)}%`}]:[],...a.edgeExcludedDies>0?[{label:"Edge excluded (outer zone)",value:String(a.edgeExcludedDies)}]:[]],N=[A([{metadata:i.metadata}]),v("Summary",[O(T)].filter(Boolean).join(`
11
- `)),f?z(n,o,"hard",u?.stats.hardBinCounts,t):g?z(n,r,"soft",u?.stats.softBinCounts,t):"",G("Ring Yield",$,n,t),G("Quadrant Yield",x,n,t),K(n,d,u?.stats.perTestStats),U(n,d,u?.stats.functionalYield),V([{dies:n}],d),u?Q(u.findings):""].filter(Boolean).join(`
9
+ <th>Severity</th><th>Region</th><th>Metric</th><th class="numeric">Delta</th><th class="numeric">${r!==void 0?"Wafers":"N (region/rest)"}</th>
10
+ </tr></thead><tbody>${o}</tbody></table>`}function X(a,r){const o=A(a);return o.length?x("Findings",J(o,r)):""}export function renderSummaryReportHtml(a,r={}){const{wafer:o,dies:t,yieldSummary:i,dataCoverage:e,hbinDefs:s,sbinDefs:l,testDefs:d=[],statsSummary:m,passBins:n=[1],ringCount:c=4}=a,b=o.metadata,f=Oe(b),w=r.title??`Wafer Summary${f}`,y=new Date().toLocaleString(),u=t.some(Y=>Y.hbin!=null),g=t.some(Y=>Y.sbin!=null),S=t.filter(Le),v=H(S,o,c),$=I(S,o,c),T=[{label:"Total dies",value:String(i.totalDies)},{label:"Filled dies",value:String(e.filledDies),hint:`${N(e.filledDies,e.totalDies)} fill`},{label:"Pass dies",value:String(i.passDies)},{label:"Fail dies",value:String(i.failDies)},...i.partialDies>0?[{label:"Partial",value:String(i.partialDies)}]:[],...i.yieldPercent!==null?[{label:`Yield (pass: ${$e([n])})`,value:`${i.yieldPercent.toFixed(1)}%`}]:[],...i.edgeExcludedDies>0?[{label:"Edge excluded (outer zone)",value:String(i.edgeExcludedDies)}]:[]],P=[z([{metadata:o.metadata}]),x("Summary",[U(T)].filter(Boolean).join(`
11
+ `)),u?V(t,s,"hard",m?.stats.hardBinCounts,n):g?V(t,l,"soft",m?.stats.softBinCounts,n):"",_("Ring Yield",v,t,n),_("Quadrant Yield",$,t,n),K(t,d,m?.stats.perTestStats),Q(t,d,m?.stats.functionalYield),q([{dies:t}],d),m?X(m.findings):""].filter(Boolean).join(`
12
12
  `);return`<!DOCTYPE html>
13
13
  <html lang="en">
14
14
  <head>
15
15
  <meta charset="UTF-8">
16
- <title>${S(w)}</title>
16
+ <title>${h(w)}</title>
17
17
  <style>
18
- ${W()}
18
+ ${C()}
19
19
  </style>
20
20
  </head>
21
21
  <body>
22
22
  <main class="report">
23
23
  <header class="report-header">
24
- <h1>${S(w)}</h1>
25
- <p class="report-subtitle">Generated ${S(p)}</p>
24
+ <h1>${h(w)}</h1>
25
+ <p class="report-subtitle">Generated ${h(y)}</p>
26
26
  </header>
27
- ${N}
28
- <p class="footer">Generated ${S(p)}</p>
27
+ ${P}
28
+ <p class="footer">Generated ${h(y)}</p>
29
29
  </main>
30
30
  </body>
31
- </html>`}function Re(s,l){const i=s.perWafer.map(n=>{const a=l[n.waferIndex]?.label??`W${n.waferIndex+1}`,e=n.summary.stats.yieldPercent;return[a,e!==null?`${e.toFixed(1)}%`:"N/A"]});return F(["Wafer","Yield"],i,{className:"compact"})}function Ee(s){const l=[];for(const e of s.perWafer){const o=H(e.summary.findings);if(!o.length)continue;const r=e.summary.wafer?.waferId??`Wafer ${e.waferIndex+1}`;l.push(`<h3 class="report-subheading">${S(r)}</h3>`+_(o))}if(!l.length)return"";const i=l.length,n=s.perWafer.length,a=`<p class="report-note">${i} of ${n} wafer${n===1?"":"s"} have per-wafer findings; the rest had none.</p>`;return v("Findings by Wafer",a+l.join(`
32
- `))}const ke=3;function Ce(s,l,i){const n=s.map(d=>({metadata:d.wafer?.metadata})),a=Se(n,{facetableOnly:!0}).filter(d=>d.splittable);if(!a.length)return"";const e=a.slice(0,ke),o=[];for(const d of e){const u=new Map;s.forEach((f,g)=>{const y=we(f.wafer?.metadata,d.key)??$e;(u.get(y)??u.set(y,[]).get(y)).push(g)});const t=[...u.entries()].map(([f,g])=>({key:f,items:g.map(y=>s[y])}));if(t.length<2)continue;const c=t.map(f=>[S(f.key),S(f.items.map(g=>g.label).join(", "))]),b=xe(t.map(f=>({key:f.key,items:f.items.map(g=>({label:g.label,dies:g.dies}))})),i).map(f=>[S(f.label),String(f.itemCount),`${f.percent.toFixed(1)}%`]),m=[F([d.label,"Wafers"],c,{className:"compact"}),F([d.label,"Wafers","Yield"],b,{className:"compact"})],w=s.flatMap(f=>f.dies??[]);let p=0;for(const f of["spec","testFlag","functional"]){if(!Fe(l,f,w))continue;const g=Te(t.map(x=>({key:x.key,items:x.items.map(T=>({dies:T.dies,testSpecYield:T.statsSummary?.stats.testSpecYield,functionalYield:T.statsSummary?.stats.functionalYield}))})),l,f);if(!g.rows.length)continue;const y=g.rows.map(x=>[S(x.label),...x.byGroup.map(T=>T.passRatePercent===null?"\u2014":`${T.passRatePercent.toFixed(1)}%`),x.overall.passRatePercent===null?"\u2014":`${x.overall.passRatePercent.toFixed(1)}%`]),$=f==="spec"?"Pass rate \xB7 spec limits":f==="testFlag"?"Pass rate \xB7 tester flag":"Pass rate \xB7 functional";g.disagreementDies&&(p=g.disagreementDies),m.push(`<h4 class="report-subheading">${S($)}</h4>`+F(["Test",...g.groups,"All"],y,{className:"compact"}))}p&&m.push(`<p class="report-note">${p.toLocaleString()} dies judged differently by limits and tester flag.</p>`),o.push(`<h3 class="report-subheading">${S(d.label)}</h3>${m.join(`
33
- `)}`)}if(!o.length)return"";const r=a.length>e.length?`<p class="report-note">${a.length-e.length} further splittable field(s) not shown.</p>`:"";return v("Split Comparison",o.join(`
34
- `)+r)}function q(s,l,i,n,a=[1]){const e=new Map,o=i==="hard"?"hardBinCounts":"softBinCounts";if(n?.length&&n.every(t=>t.stats[o]!==void 0))for(const t of n)for(const[c,b]of Object.entries(t.stats[o])){const m=Number(c);e.set(m,(e.get(m)??0)+b)}else for(const t of s){if(t.partial||t.edgeExcluded)continue;const c=i==="hard"?t.hbin:t.sbin;c!=null&&e.set(c,(e.get(c)??0)+1)}if(!e.size)return"";const r=[...e.values()].reduce((t,c)=>t+c,0),d=l?new Map(l.map(t=>[t.bin,t])):null,u=C(e.entries(),a).map(([t,c])=>{const b=d?.get(t);return[b?.name?`Bin ${t} \xB7 ${b.name} (${c})`:`Bin ${t} (${c})`,Y(c,r)]});return v(i==="hard"?"Hard Bin Breakdown (All Wafers)":"Soft Bin Breakdown (All Wafers)",F(["Bin","Yield"],u,{className:"compact"}))}function J(s,l,i,n,a,e){const o=new Set(e),r=new Map,d=[];for(let t=0;t<n.length;t++){const c=n[t],b=i[t]??[];if(!b.length)continue;const m=l(b.filter(j),c,a),w=new Map(b.map(p=>[L(p),p]));for(const p of m){d.includes(p.label)||d.push(p.label);const f=r.get(p.label)??{pass:0,total:0};for(const g of p.dieKeys){const y=w.get(g);if(!y||y.partial||y.edgeExcluded)continue;const $=y.hbin??y.sbin;$!=null&&(f.total++,o.has($)&&f.pass++)}r.set(p.label,f)}}if(!r.size)return"";const u=d.filter(t=>r.get(t)?.total).map(t=>{const c=r.get(t);return[t,Y(c.pass,c.total)]});return u.length?v(s,F(["Region","Yield"],u,{className:"compact"})):""}function He(s,l,i){let n;if(i?.length&&i.every(a=>a.stats.perTestStats!==void 0)){const a=new Map;for(const e of i)for(const o of e.stats.perTestStats??[]){const r=a.get(o.testNumber);r?(r.n+=o.count,r.sum+=o.mean*o.count,r.min=Math.min(r.min,o.min),r.max=Math.max(r.max,o.max)):a.set(o.testNumber,{n:o.count,sum:o.mean*o.count,min:o.min,max:o.max})}n=[...a.entries()].map(([e,o])=>({testNumber:e,min:o.min,max:o.max,mean:o.sum/o.n}))}return K(s,l,n)}function Ie(s,l,i){const n=De(i);return U(s,l,n)}const R=["lot","product","testProgram","temperature"];function Le(s){const l=new Map(R.map(e=>[e,new Set]));for(const e of s)for(const o of R){const r=e.wafer?.metadata?.[o];r!=null&&r!==""&&l.get(o).add(String(r))}const i=R.filter(e=>l.get(e).size>1);if(i.length===0)return[{label:"",items:s,varying:i}];const n=new Map,a=[];for(const e of s){const o=i.map(r=>String(e.wafer?.metadata?.[r]??"(none)")).join(" \xB7 ");n.has(o)||(n.set(o,[]),a.push(o)),n.get(o).push(e)}return a.map(e=>({label:e,items:n.get(e),varying:i}))}function X(s,l,i,n,a,e,o){const r=be(s,{perWaferSummaries:s.map(h=>h.statsSummary),...o}),d=[],u=[],t=[];for(const h of s){const D=h.dies??[];h.wafer&&(d.push(h.wafer),t.push(D)),D.length&&u.push(...D)}const c=u.some(h=>h.hbin!=null),b=u.some(h=>h.sbin!=null),m=c||b,w=r.perWafer.map(h=>h.summary.stats.yieldPercent).filter(h=>h!==null),p=w.length?w.reduce((h,D)=>h+D,0)/w.length:null,f=new Set(a);let g=0,y=0,$=0,x=0,T=0;for(const h of u){if(g++,h.edgeExcluded&&x++,h.partial&&T++,h.partial||h.edgeExcluded)continue;const D=h.hbin??h.sbin;D!=null&&(y++,f.has(D)&&$++)}const N=y-$,P=y>0?$/y*100:null,ee=[{label:"Wafers",value:String(r.stats.waferCount)},{label:"Total dies",value:String(g)},...m?[{label:"Good dies",value:String($)},{label:"Bad dies",value:String(N)}]:[],...x>0?[{label:"Edge excluded",value:String(x)}]:[],...T>0?[{label:"Partial dies",value:String(T)}]:[],...p!==null?[{label:"Mean wafer yield",value:`${p.toFixed(1)}%`}]:[],...P!==null?[{label:"Total yield",value:`${P.toFixed(1)}%`}]:[]],te=I(r.perWafer.map(h=>h.summary.wafer)),ne=v(te.lotId!==void 0?"Lot Summary":"Summary",O(ee)),ae=A(s.map(h=>({metadata:h.wafer?.metadata}))),se=v("Per-Wafer Yield",Re(r,s)),oe=Ce(s,n,a),M=r.perWafer.map(h=>h.summary),ie=m?c?q(u,l,"hard",M,a):q(u,i,"soft",M,a):"",le=m&&d.length?J("Ring Yield (All Wafers)",E,t,d,e,a):"",re=m&&d.length?J("Quadrant Yield (All Wafers)",k,t,d,e,a):"",ce=n.length?He(u,n,M):"",de=n.length?Ie(u,n,M):"",ue=n.length?V(s,n):"",fe=r.findings.length?Q(r.findings,r.stats.waferCount):"",me=Ee(r),pe=[ne,ae,se,oe,ie,le,re,ce,de,ue,fe,me].filter(Boolean).join(`
35
- `);return{lotSummary:r,sections:pe}}function Z(s,l,i){return`<main class="report">
31
+ </html>`}function Ge(a,r){const o=a.perWafer.map(t=>{const i=ye(r[t.waferIndex],t.waferIndex),e=t.summary.stats.yieldPercent;return[i,e!==null?`${e.toFixed(1)}%`:"N/A"]});return F(["Wafer","Yield"],o,{className:"compact"})}function ze(a){const r=[];for(const e of a.perWafer){const s=A(e.summary.findings);if(!s.length)continue;const l=e.summary.wafer?.waferId??`Wafer ${e.waferIndex+1}`;r.push(`<h3 class="report-subheading">${h(l)}</h3>`+J(s))}if(!r.length)return"";const o=r.length,t=a.perWafer.length,i=`<p class="report-note">${o} of ${t} wafer${t===1?"":"s"} have per-wafer findings; the rest had none.</p>`;return x("Findings by Wafer",i+r.join(`
32
+ `))}const Ue=3;function Ve(a,r,o){const t=a.map(d=>({metadata:d.wafer?.metadata})),i=De(t,{facetableOnly:!0}).filter(d=>d.splittable);if(!i.length)return"";const e=i.slice(0,Ue),s=[];for(const d of e){const m=new Map;a.forEach((u,g)=>{const S=Pe(u.wafer?.metadata,d.key)??Ye;(m.get(S)??m.set(S,[]).get(S)).push(g)});const n=[...m.entries()].map(([u,g])=>({key:u,items:g.map(S=>a[S])}));if(n.length<2)continue;const c=n.map(u=>[h(u.key),h(u.items.map(g=>g.label).join(", "))]),b=Me(n.map(u=>({key:u.key,items:u.items.map(g=>({label:g.label,dies:g.dies,passBins:R(g,o)}))})),o).map(u=>[h(u.label),String(u.itemCount),`${u.percent.toFixed(1)}%`]),f=[F([d.label,"Wafers"],c,{className:"compact"}),F([d.label,"Wafers","Yield"],b,{className:"compact"})],w=a.flatMap(u=>u.dies??[]);let y=0;for(const u of["spec","testFlag","functional"]){if(!Re(r,u,w))continue;const g=Ne(n.map($=>({key:$.key,items:$.items.map(T=>({dies:T.dies,testSpecYield:T.statsSummary?.stats.testSpecYield,functionalYield:T.statsSummary?.stats.functionalYield}))})),r,u);if(!g.rows.length)continue;const S=g.rows.map($=>[h($.label),...$.byGroup.map(T=>T.passRatePercent===null?"\u2014":`${T.passRatePercent.toFixed(1)}%`),$.overall.passRatePercent===null?"\u2014":`${$.overall.passRatePercent.toFixed(1)}%`]),v=u==="spec"?"Pass rate \xB7 spec limits":u==="testFlag"?"Pass rate \xB7 tester flag":"Pass rate \xB7 functional";g.disagreementDies&&(y=g.disagreementDies),f.push(`<h4 class="report-subheading">${h(v)}</h4>`+F(["Test",...g.groups,"All"],S,{className:"compact"}))}y&&f.push(`<p class="report-note">${y.toLocaleString()} dies judged differently by limits and tester flag.</p>`),s.push(`<h3 class="report-subheading">${h(d.label)}</h3>${f.join(`
33
+ `)}`)}if(!s.length)return"";const l=i.length>e.length?`<p class="report-note">${i.length-e.length} further splittable field(s) not shown.</p>`:"";return x("Split Comparison",s.join(`
34
+ `)+l)}function Z(a,r,o,t,i){const e=new Map,s=o==="hard"?"hardBinCounts":"softBinCounts";if(t?.length&&t.every(n=>n.stats[s]!==void 0))for(const n of t)for(const[c,b]of Object.entries(n.stats[s])){const f=Number(c);e.set(f,(e.get(f)??0)+b)}else for(const n of a){if(n.partial||n.edgeExcluded)continue;const c=o==="hard"?n.hbin:n.sbin;c!=null&&e.set(c,(e.get(c)??0)+1)}if(!e.size)return"";const l=[...e.values()].reduce((n,c)=>n+c,0),d=r?new Map(r.map(n=>[n.bin,n])):null,m=j(e.entries(),we(i)[o]).map(([n,c])=>{const b=d?.get(n);return[b?.name?`Bin ${n} \xB7 ${b.name} (${c})`:`Bin ${n} (${c})`,N(c,l)]});return x(o==="hard"?"Hard Bin Breakdown (All Wafers)":"Soft Bin Breakdown (All Wafers)",F(["Bin","Yield"],m,{className:"compact"}))}function ee(a,r,o,t,i,e){const s=ve(o,t,i,l=>e[l],r).map(l=>[l.label,`${l.yieldPercent.toFixed(1)}%`]);return s.length?x(a,F(["Region","Yield"],s,{className:"compact"})):""}function _e(a,r,o){let t;if(o?.length&&o.every(i=>i.stats.perTestStats!==void 0)){const i=new Map;for(const e of o)for(const s of e.stats.perTestStats??[]){const l=i.get(s.testNumber);l?(l.n+=s.count,l.sum+=s.mean*s.count,l.min=Math.min(l.min,s.min),l.max=Math.max(l.max,s.max)):i.set(s.testNumber,{n:s.count,sum:s.mean*s.count,min:s.min,max:s.max})}t=[...i.entries()].map(([e,s])=>({testNumber:e,min:s.min,max:s.max,mean:s.sum/s.n}))}return K(a,r,t)}function Ke(a,r,o){const t=Ce(o);return Q(a,r,t)}const E=["lot","product","testProgram","temperature"];function Qe(a){const r=new Map(E.map(e=>[e,new Set]));for(const e of a)for(const s of E){const l=e.wafer?.metadata?.[s];l!=null&&l!==""&&r.get(s).add(String(l))}const o=E.filter(e=>r.get(e).size>1);if(o.length===0)return[{label:"",items:a,varying:o}];const t=new Map,i=[];for(const e of a){const s=o.map(l=>String(e.wafer?.metadata?.[l]??"(none)")).join(" \xB7 ");t.has(s)||(t.set(s,[]),i.push(s)),t.get(s).push(e)}return i.map(e=>({label:e,items:t.get(e),varying:o}))}function te(a,r,o,t,i,e,s){const l=Fe(a,{perWaferSummaries:a.map(p=>p.statsSummary),...s}),d=[],m=[],n=[],c=[];for(const p of a){const B=p.dies??[];p.wafer&&(d.push(p.wafer),n.push(B),c.push(R(p,i))),B.length&&m.push(...B)}const b=a.map(p=>({dies:p.dies??[],passBins:R(p,i)})),f=m.some(p=>p.hbin!=null),w=m.some(p=>p.sbin!=null),y=f||w,u=l.perWafer.map(p=>p.summary.stats.yieldPercent).filter(p=>p!==null),g=u.length?u.reduce((p,B)=>p+B,0)/u.length:null;let S=0,v=0,$=0,T=0,P=0;for(const p of b){const B=new Set(p.passBins);for(const M of p.dies){if(S++,M.edgeExcluded&&T++,M.partial&&P++,M.partial||M.edgeExcluded)continue;const L=G(M,B);L!==void 0&&(v++,L&&$++)}}const Y=v-$,k=v>0?$/v*100:null,ae=[{label:"Wafers",value:String(l.stats.waferCount)},{label:"Total dies",value:String(S)},...y?[{label:"Good dies",value:String($)},{label:"Bad dies",value:String(Y)}]:[],...T>0?[{label:"Edge excluded",value:String(T)}]:[],...P>0?[{label:"Partial dies",value:String(P)}]:[],...g!==null?[{label:"Mean wafer yield",value:`${g.toFixed(1)}%`}]:[],...k!==null?[{label:"Total yield",value:`${k.toFixed(1)}%`}]:[]],se=O(l.perWafer.map(p=>p.summary.wafer)),oe=x(se.lotId!==void 0?"Lot Summary":"Summary",U(ae)),ie=z(a.map(p=>({metadata:p.wafer?.metadata}))),re=x("Per-Wafer Yield",Ge(l,a)),le=Ve(a,t,i),W=l.perWafer.map(p=>p.summary),ce=y?f?Z(m,r,"hard",W,b):Z(m,o,"soft",W,b):"",de=y&&d.length?ee("Ring Yield (All Wafers)",H,n,d,e,c):"",ue=y&&d.length?ee("Quadrant Yield (All Wafers)",I,n,d,e,c):"",me=t.length?_e(m,t,W):"",pe=t.length?Ke(m,t,W):"",fe=t.length?q(a,t):"",ge=l.findings.length?X(l.findings,l.stats.waferCount):"",he=ze(l),be=[oe,ie,re,le,ce,de,ue,me,pe,fe,ge,he].filter(Boolean).join(`
35
+ `);return{lotSummary:l,sections:be}}function ne(a,r,o){return`<main class="report">
36
36
  <header class="report-header">
37
- <h1>${S(s)}</h1>
38
- <p class="report-subtitle">Generated ${S(i)}</p>
37
+ <h1>${h(a)}</h1>
38
+ <p class="report-subtitle">Generated ${h(o)}</p>
39
39
  </header>
40
- ${l}
41
- <p class="footer">Generated ${S(i)}</p>
42
- </main>`}export function renderLotSummaryReportHtml(s,l={}){const{items:i,hbinDefs:n,sbinDefs:a,testDefs:e=[],passBins:o=[1],ringCount:r=4,analyzeOptions:d}=s,u=new Date().toLocaleString(),t=Le(i);if(t.length===1){const{lotSummary:p,sections:f}=X(t[0].items,n,a,e,o,r,d),g=I(p.perWafer.map($=>$.summary.wafer)),y=l.title??(g.lotId!==void 0?`Lot Summary \u2014 ${g.lotId}`:`Summary \u2014 ${ve(g)}`);return`<!DOCTYPE html>
40
+ ${r}
41
+ <p class="footer">Generated ${h(o)}</p>
42
+ </main>`}export function renderLotSummaryReportHtml(a,r={}){const{items:o,hbinDefs:t,sbinDefs:i,testDefs:e=[],passBins:s=[1],ringCount:l=4,analyzeOptions:d}=a,m=new Date().toLocaleString(),n=Qe(o);if(n.length===1){const{lotSummary:y,sections:u}=te(n[0].items,t,i,e,s,l,d),g=O(y.perWafer.map(v=>v.summary.wafer)),S=r.title??(g.lotId!==void 0?`Lot Summary \u2014 ${g.lotId}`:`Summary \u2014 ${We(g)}`);return`<!DOCTYPE html>
43
43
  <html lang="en">
44
44
  <head>
45
45
  <meta charset="UTF-8">
46
- <title>${S(y)}</title>
46
+ <title>${h(S)}</title>
47
47
  <style>
48
- ${W()}
48
+ ${C()}
49
49
  </style>
50
50
  </head>
51
51
  <body>
52
- ${Z(y,f,u)}
52
+ ${ne(S,u,m)}
53
53
  </body>
54
- </html>`}const c=l.title??"Summary",b=t.map(p=>{const{lotSummary:f,sections:g}=X(p.items,n,a,e,o,r,d),y=p.varying.includes("lot")?void 0:f.lot?.lot??f.lot?.lotId,$=y?`${p.label} \xB7 Lot ${String(y)}`:p.label;return Z(`${c} \u2014 ${$}`,g,u)}),m=`<p style="max-width:1080px;margin:0 auto 8px;padding:8px 12px;background:var(--report-surface);border:1px solid var(--report-line);border-radius:4px;font-size:12px;color:var(--report-muted);">This load spans ${t.length} groups by identity \u2014 shown separately below so stats are never pooled across them.</p>`,w=b.map((p,f)=>`${f===0?"":'<hr style="max-width:1080px;margin:32px auto 0;border:none;border-top:3px solid var(--report-line-strong);">'}
55
- ${p}`).join(`
54
+ </html>`}const c=r.title??"Summary",b=n.map(y=>{const{lotSummary:u,sections:g}=te(y.items,t,i,e,s,l,d),S=y.varying.includes("lot")?void 0:u.lot?.lot??u.lot?.lotId,v=S?`${y.label} \xB7 Lot ${String(S)}`:y.label;return ne(`${c} \u2014 ${v}`,g,m)}),f=`<p style="max-width:1080px;margin:0 auto 8px;padding:8px 12px;background:var(--report-surface);border:1px solid var(--report-line);border-radius:4px;font-size:12px;color:var(--report-muted);">This load spans ${n.length} groups by identity \u2014 shown separately below so stats are never pooled across them.</p>`,w=b.map((y,u)=>`${u===0?"":'<hr style="max-width:1080px;margin:32px auto 0;border:none;border-top:3px solid var(--report-line-strong);">'}
55
+ ${y}`).join(`
56
56
  `);return`<!DOCTYPE html>
57
57
  <html lang="en">
58
58
  <head>
59
59
  <meta charset="UTF-8">
60
- <title>${S(c)}</title>
60
+ <title>${h(c)}</title>
61
61
  <style>
62
- ${W()}
62
+ ${C()}
63
63
  </style>
64
64
  </head>
65
65
  <body>
66
66
  <div class="report" style="padding-top:24px;">
67
- ${m}
67
+ ${f}
68
68
  </div>
69
69
  ${w}
70
70
  </body>
71
- </html>`}export{he as openHtmlReport};
71
+ </html>`}export{Te as openHtmlReport};
@@ -342,35 +342,6 @@ export interface LotStatsSummary {
342
342
  }>;
343
343
  }
344
344
  export interface AnalyzeWaferMapOptions {
345
- /**
346
- * Should mirror the ring count used by the renderer for consistent semantics.
347
- * Defaults to 4, which matches the current render default.
348
- */
349
- ringCount?: number;
350
- passBins?: number[];
351
- /**
352
- * REMOVED in 0.27.0 — `significanceLevel`, `minimumEffectSize` and
353
- * `minimumRelativeEffect` are now internal constants, not options.
354
- *
355
- * They decide what counts as a finding, so a wrong value does not make the
356
- * output *look* different, it makes it wrong — and silently. A negative
357
- * `significanceLevel` returned zero findings across the board, which reads as
358
- * "nothing wrong with this wafer": the worst failure an analysis tool has.
359
- * `minimumSampleSize` was already internal for exactly this reason, and
360
- * `adaptOptions()` declines to adapt `significanceLevel` even internally
361
- * because it perturbs the multiple-comparison correction unpredictably. The
362
- * library was being more careful with itself than with its callers.
363
- *
364
- * The gates are documented in docs/api.md §7.3.2, so a reader can still learn
365
- * *why* a pattern did or did not produce a finding — which is what callers
366
- * actually wanted. Values passed by untyped (plain-JS) callers are now
367
- * validated and clamped rather than honoured; see `resolveOptions`.
368
- */
369
- includePartial?: boolean;
370
- includeEdgeExcluded?: boolean;
371
- enableYieldAnalysis?: boolean;
372
- enableHardBinAnalysis?: boolean;
373
- enableSoftBinAnalysis?: boolean;
374
345
  /**
375
346
  * Full parametric **spatial significance** analysis: Welch comparisons of each
376
347
  * test's values between every region (ring/quadrant/reticle/site/sector) and
@@ -393,22 +364,8 @@ export interface AnalyzeWaferMapOptions {
393
364
  * Off by default. Implied by `enableTestValueAnalysis`.
394
365
  */
395
366
  computePerTestStats?: boolean;
396
- enableReticlePositionAnalysis?: boolean;
397
- /**
398
- * Analyse yield and bin distributions by test site (`siteNum`).
399
- * Enabled automatically when the wafer contains meaningful site duplication
400
- * (at least 2 distinct site numbers each appearing on 3 or more dies).
401
- * Set to `false` to suppress, or `true` to force-enable regardless of the guard.
402
- */
403
- enableTestSiteAnalysis?: boolean;
404
- /** Detect contiguous failure clusters and edge arc damage. Default true. */
405
- enableClusterAnalysis?: boolean;
406
- /** Angular sector analysis (finer-grained than quadrants). Default true. */
407
- enableAngularAnalysis?: boolean;
408
367
  /** Number of angular sectors for sector analysis. Must be 4, 8, 16, or 32. Default 8. */
409
368
  sectorCount?: number;
410
- /** Classify the spatial failure pattern (center, edge-ring, scratch, etc.). Default true. */
411
- enablePatternClassification?: boolean;
412
369
  /**
413
370
  * Restrict test value analysis to a specific subset of test numbers.
414
371
  * When omitted and more than 250 tests are present in the data, test value
@@ -13,10 +13,10 @@ export interface ChartDatum {
13
13
  * `label` — a caller with an `onOpen` callback should resolve back to its
14
14
  * own item by `key`, not by re-searching for `label`. Labels are only
15
15
  * guaranteed unique when the caller supplies one per item; an item with no
16
- * `label` falls back to a shared default elsewhere (e.g. `analysisTab.ts`
17
- * falls back to `''` when both `label` and `wafer.metadata.waferId` are
18
- * absent), so two rows can carry an identical, ambiguous label — matching
19
- * on it would silently resolve to the wrong item. Absent on group rows
16
+ * `label` is named by its wafer ID (`waferDisplayLabel`, core/waferLabel.ts),
17
+ * and two wafers from different lots can share an ID — so two rows can carry
18
+ * an identical, ambiguous label, and matching on it would silently resolve
19
+ * to the wrong item. Absent on group rows
20
20
  * (`itemCount > 1`), which are drilled into rather than opened directly.
21
21
  */
22
22
  key?: string | number;
@@ -24,6 +24,12 @@ export interface ChartDatum {
24
24
  export interface YieldItem {
25
25
  label?: string;
26
26
  dies?: Die[];
27
+ /**
28
+ * This item's own pass bins (`WaferMapResult.passBins`). Wins over the
29
+ * function's `passBins` argument, which only fills in for items without —
30
+ * a lot can mix wafers built with different pass bins.
31
+ */
32
+ passBins?: readonly number[];
27
33
  /**
28
34
  * Precomputed yield percent for this item (e.g. from `analyzeWaferLot`'s
29
35
  * `lotYieldSeries[waferIndex].yieldPercent`) — used directly when present.
@@ -35,7 +41,7 @@ export interface YieldItem {
35
41
  }
36
42
  export type YieldSortBy = 'yield' | 'label';
37
43
  /** One bar per item. */
38
- export declare function buildYieldData(items: YieldItem[], passBins?: number[], sortBy?: YieldSortBy): ChartDatum[];
44
+ export declare function buildYieldData(items: YieldItem[], passBins?: readonly number[], sortBy?: YieldSortBy): ChartDatum[];
39
45
  /**
40
46
  * Combined yield: one bar per group, pooling the group's items. The pooled
41
47
  * yield is the yield-eligible-die-count-weighted mean of per-item yields —
@@ -52,5 +58,5 @@ export declare function buildYieldData(items: YieldItem[], passBins?: number[],
52
58
  export declare function buildYieldDataCombined(groups: {
53
59
  key: string;
54
60
  items: YieldItem[];
55
- }[], passBins?: number[], sortBy?: YieldSortBy): ChartDatum[];
61
+ }[], passBins?: readonly number[], sortBy?: YieldSortBy): ChartDatum[];
56
62
  //# sourceMappingURL=yield.d.ts.map
@@ -1 +1 @@
1
- import{isYieldEligibleDie as c,diePassStatus as p}from"../core/dies.js";import{compareNatural as b}from"../core/utils.js";function m(e,n){let i=0,t=0;const l=new Set(n);for(const r of e){if(!c(r))continue;const o=p(r,l);o!==void 0&&(t++,o&&i++)}return t>0?i/t*100:0}function d(e,n){return e.yieldPercent!==void 0?e.yieldPercent??0:m(e.dies??[],n)}function y(e){let n=0;for(const i of e)c(i)&&n++;return n}function f(e,n){n==="yield"?e.sort((i,t)=>t.value-i.value):e.sort((i,t)=>b(i.label,t.label))}export function buildYieldData(e,n=[1],i="label"){const t=e.map((l,r)=>{const o=d(l,n);return{label:l.label??`#${r}`,value:o,percent:o,itemCount:1,key:l.key}});return f(t,i),t}export function buildYieldDataCombined(e,n=[1],i="label"){const t=e.map(l=>{let r=0,o=0;for(const a of l.items){const s=y(a.dies??[]);r+=d(a,n)*s,o+=s}const u=o>0?r/o:0;return{label:l.key,value:u,percent:u,itemCount:l.items.length}});return f(t,i),t}
1
+ import{isYieldEligibleDie as c,diePassStatus as p}from"../core/dies.js";import{compareNatural as b}from"../core/utils.js";function m(e,n){let i=0,t=0;const l=new Set(n);for(const r of e){if(!c(r))continue;const o=p(r,l);o!==void 0&&(t++,o&&i++)}return t>0?i/t*100:0}function d(e,n){return e.yieldPercent!==void 0?e.yieldPercent??0:m(e.dies??[],e.passBins??n)}function y(e){let n=0;for(const i of e)c(i)&&n++;return n}function f(e,n){n==="yield"?e.sort((i,t)=>t.value-i.value):e.sort((i,t)=>b(i.label,t.label))}export function buildYieldData(e,n=[1],i="label"){const t=e.map((l,r)=>{const o=d(l,n);return{label:l.label??`#${r}`,value:o,percent:o,itemCount:1,key:l.key}});return f(t,i),t}export function buildYieldDataCombined(e,n=[1],i="label"){const t=e.map(l=>{let r=0,o=0;for(const a of l.items){const u=y(a.dies??[]);r+=d(a,n)*u,o+=u}const s=o>0?r/o:0;return{label:l.key,value:s,percent:s,itemCount:l.items.length}});return f(t,i),t}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wafertools/wafermap",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "Interactive wafer map visualization and yield analysis for semiconductor test data. Hard bins, soft bins, test values, retests, edge exclusion, reticle overlays, spatial statistics, failure clustering, and lot-level trend analysis — pure ES modules, no runtime dependencies, no server required.",
5
5
  "type": "module",
6
6
  "license": "MIT",