@wafertools/wafermap 0.27.0 → 0.28.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.
- package/AGENTS.md +10 -2
- package/CHANGELOG.md +310 -0
- package/README.md +1 -1
- package/dist/packages/canvas-adapter/charts/binCluster.d.ts +0 -1
- package/dist/packages/canvas-adapter/charts/boxplot.d.ts +8 -1
- package/dist/packages/canvas-adapter/charts/boxplot.js +1 -1
- package/dist/packages/canvas-adapter/charts/capability.d.ts +0 -1
- package/dist/packages/canvas-adapter/charts/correlation.d.ts +0 -1
- package/dist/packages/canvas-adapter/charts/histogram.d.ts +0 -1
- package/dist/packages/canvas-adapter/charts/histogram.js +1 -1
- package/dist/packages/canvas-adapter/charts/regionYieldDiagram.d.ts +0 -1
- package/dist/packages/canvas-adapter/charts/scatter.d.ts +6 -1
- package/dist/packages/canvas-adapter/charts/scatter.js +1 -1
- package/dist/packages/canvas-adapter/charts/trend.d.ts +7 -0
- package/dist/packages/canvas-adapter/charts/trend.js +1 -1
- package/dist/packages/canvas-adapter/hitGrid.d.ts +22 -0
- package/dist/packages/canvas-adapter/hitGrid.js +1 -0
- package/dist/packages/canvas-adapter/index.d.ts +1 -0
- package/dist/packages/canvas-adapter/index.js +1 -1
- package/dist/packages/canvas-adapter/insightsTab.d.ts +24 -2
- package/dist/packages/canvas-adapter/insightsTab.js +1 -1
- package/dist/packages/canvas-adapter/maplessSummary.d.ts +5 -1
- package/dist/packages/canvas-adapter/maplessSummary.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferGallery.js +1 -1
- package/dist/packages/canvas-adapter/renderWaferMap.d.ts +38 -1
- package/dist/packages/canvas-adapter/renderWaferMap.js +1 -1
- package/dist/packages/canvas-adapter/summaryPanel.d.ts +15 -5
- package/dist/packages/canvas-adapter/summaryPanel.js +3 -3
- package/dist/packages/canvas-adapter/toCanvas.js +1 -1
- package/dist/packages/canvas-adapter/toolbar.d.ts +42 -9
- package/dist/packages/canvas-adapter/toolbar.js +2 -2
- package/dist/packages/canvas-adapter/userGuideHtml.d.ts +1 -1
- package/dist/packages/canvas-adapter/userGuideHtml.js +27 -16
- package/dist/packages/canvas-adapter/version.d.ts +2 -2
- package/dist/packages/canvas-adapter/version.js +1 -1
- package/dist/packages/canvas-adapter/warnings.d.ts +25 -0
- package/dist/packages/canvas-adapter/warnings.js +1 -1
- package/dist/packages/core/dies.d.ts +11 -0
- package/dist/packages/core/dies.js +1 -1
- package/dist/packages/renderer/binColors.d.ts +80 -0
- package/dist/packages/renderer/binColors.js +1 -0
- package/dist/packages/renderer/buildView.d.ts +67 -6
- package/dist/packages/renderer/buildView.js +1 -1
- package/dist/packages/renderer/buildWaferMap.d.ts +8 -2
- package/dist/packages/renderer/buildWaferMap.js +1 -1
- package/dist/packages/renderer/colorMap.d.ts +16 -15
- package/dist/packages/renderer/colorMap.js +1 -1
- package/dist/packages/renderer/colorSchemes.d.ts +45 -26
- package/dist/packages/renderer/colorSchemes.js +1 -1
- package/dist/packages/renderer/index.d.ts +3 -1
- package/dist/packages/renderer/index.js +1 -1
- package/dist/packages/stats/analyzeWaferLot.js +1 -1
- package/dist/packages/stats/analyzeWaferMap.js +1 -1
- package/dist/packages/stats/histogram.d.ts +28 -1
- package/dist/packages/stats/histogram.js +1 -1
- package/dist/packages/stats/population.d.ts +23 -0
- package/dist/packages/stats/population.js +1 -0
- package/dist/packages/stats/renderFindingsReport.js +10 -10
- package/dist/packages/stats/renderSummaryReport.js +22 -22
- package/dist/packages/stats/yield.js +1 -1
- package/package.json +5 -3
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import{isParametricTest as
|
|
2
|
-
<td class="tight">${
|
|
3
|
-
<td class="tight">${S(
|
|
4
|
-
<td>${S(
|
|
5
|
-
<td class="numeric">${S(
|
|
6
|
-
<td class="numeric">${S(
|
|
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>
|
|
7
7
|
</tr>`).join(`
|
|
8
8
|
`);return`<table class="report-table findings-table compact"><thead><tr>
|
|
9
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
|
|
11
|
-
`)),f?
|
|
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(`
|
|
12
12
|
`);return`<!DOCTYPE html>
|
|
13
13
|
<html lang="en">
|
|
14
14
|
<head>
|
|
15
15
|
<meta charset="UTF-8">
|
|
16
16
|
<title>${S(w)}</title>
|
|
17
17
|
<style>
|
|
18
|
-
${
|
|
18
|
+
${W()}
|
|
19
19
|
</style>
|
|
20
20
|
</head>
|
|
21
21
|
<body>
|
|
@@ -28,30 +28,30 @@ ${R()}
|
|
|
28
28
|
<p class="footer">Generated ${S(p)}</p>
|
|
29
29
|
</main>
|
|
30
30
|
</body>
|
|
31
|
-
</html>`}function
|
|
32
|
-
`))}const
|
|
33
|
-
`)}`)}if(!o.length)return"";const r=
|
|
34
|
-
`)+r)}function
|
|
35
|
-
`);return{lotSummary:r,sections:
|
|
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">
|
|
36
36
|
<header class="report-header">
|
|
37
|
-
<h1>${S(
|
|
37
|
+
<h1>${S(s)}</h1>
|
|
38
38
|
<p class="report-subtitle">Generated ${S(i)}</p>
|
|
39
39
|
</header>
|
|
40
40
|
${l}
|
|
41
41
|
<p class="footer">Generated ${S(i)}</p>
|
|
42
|
-
</main>`}export function renderLotSummaryReportHtml(
|
|
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>
|
|
43
43
|
<html lang="en">
|
|
44
44
|
<head>
|
|
45
45
|
<meta charset="UTF-8">
|
|
46
|
-
<title>${S(
|
|
46
|
+
<title>${S(y)}</title>
|
|
47
47
|
<style>
|
|
48
|
-
${
|
|
48
|
+
${W()}
|
|
49
49
|
</style>
|
|
50
50
|
</head>
|
|
51
51
|
<body>
|
|
52
|
-
${
|
|
52
|
+
${Z(y,f,u)}
|
|
53
53
|
</body>
|
|
54
|
-
</html>`}const c=l.title??"
|
|
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
55
|
${p}`).join(`
|
|
56
56
|
`);return`<!DOCTYPE html>
|
|
57
57
|
<html lang="en">
|
|
@@ -59,7 +59,7 @@ ${p}`).join(`
|
|
|
59
59
|
<meta charset="UTF-8">
|
|
60
60
|
<title>${S(c)}</title>
|
|
61
61
|
<style>
|
|
62
|
-
${
|
|
62
|
+
${W()}
|
|
63
63
|
</style>
|
|
64
64
|
</head>
|
|
65
65
|
<body>
|
|
@@ -68,4 +68,4 @@ ${m}
|
|
|
68
68
|
</div>
|
|
69
69
|
${w}
|
|
70
70
|
</body>
|
|
71
|
-
</html>`}export{
|
|
71
|
+
</html>`}export{he as openHtmlReport};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isYieldEligibleDie as
|
|
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}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wafertools/wafermap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.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",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"build": "node scripts/build-user-guide.mjs && node scripts/sync-icons.mjs && node scripts/sync-version.mjs && rm -rf dist && tsc -p tsconfig.build.json",
|
|
76
76
|
"build:guide": "node scripts/build-user-guide.mjs",
|
|
77
77
|
"clean": "rm -rf dist",
|
|
78
|
-
"check": "node scripts/build-user-guide.mjs && node scripts/sync-version.mjs && tsc --noEmit -p tsconfig.json && node scripts/check-examples-manifest.mjs && node scripts/build-agents-page.mjs --check && node scripts/check-agents-guide.mjs && node scripts/check-toolbar-docs.mjs && node scripts/check-overlay-conventions.mjs && node scripts/check-changelog.mjs && node scripts/help.mjs --check && node scripts/check-api-claims.mjs && node scripts/check-style-scales.mjs packages/canvas-adapter && node scripts/check-clones.mjs packages",
|
|
78
|
+
"check": "node scripts/build-user-guide.mjs && node scripts/sync-version.mjs && tsc --noEmit -p tsconfig.json && node scripts/check-examples-manifest.mjs && node scripts/build-agents-page.mjs --check && node scripts/check-agents-guide.mjs && node scripts/check-toolbar-docs.mjs && node scripts/check-doc-links.mjs && node scripts/check-quickstart-snippet.mjs && node scripts/check-overlay-conventions.mjs && node scripts/check-changelog.mjs && node scripts/help.mjs --check && node scripts/check-api-claims.mjs && node scripts/check-style-scales.mjs packages/canvas-adapter && node scripts/check-clones.mjs packages",
|
|
79
79
|
"build:examples-index": "node scripts/build-examples-index.mjs",
|
|
80
80
|
"check:drift": "node scripts/check-drift.mjs",
|
|
81
81
|
"dev": "rm -rf docs/dist && cp -r dist docs/dist && ./.venv/bin/zensical serve --dev-addr localhost:8001",
|
|
@@ -95,7 +95,9 @@
|
|
|
95
95
|
"build:images": "npm run build && node scripts/capture-screenshots.mjs",
|
|
96
96
|
"build:agents-page": "node scripts/build-agents-page.mjs",
|
|
97
97
|
"check:styles": "node scripts/check-style-scales.mjs packages/canvas-adapter",
|
|
98
|
-
"check:api": "node scripts/check-api-claims.mjs"
|
|
98
|
+
"check:api": "node scripts/check-api-claims.mjs",
|
|
99
|
+
"ui:surface": "node scripts/ui-surface.mjs",
|
|
100
|
+
"ui:surface:check": "node scripts/ui-surface.mjs --check"
|
|
99
101
|
},
|
|
100
102
|
"keywords": [
|
|
101
103
|
"wafer-map",
|