repro-surgeon 0.1.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/CHANGELOG.md +15 -0
- package/CODE_OF_CONDUCT.md +7 -0
- package/CONTRIBUTING.md +31 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/SECURITY.md +15 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +165 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.js +177 -0
- package/dist/config.js.map +1 -0
- package/dist/dependencies.d.ts +37 -0
- package/dist/dependencies.js +237 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/engine.d.ts +25 -0
- package/dist/engine.js +327 -0
- package/dist/engine.js.map +1 -0
- package/dist/export.d.ts +7 -0
- package/dist/export.js +520 -0
- package/dist/export.js.map +1 -0
- package/dist/graph.d.ts +3 -0
- package/dist/graph.js +247 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/oracle.d.ts +2 -0
- package/dist/oracle.js +81 -0
- package/dist/oracle.js.map +1 -0
- package/dist/protection.d.ts +2 -0
- package/dist/protection.js +6 -0
- package/dist/protection.js.map +1 -0
- package/dist/report.d.ts +5 -0
- package/dist/report.js +539 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.js +195 -0
- package/dist/runner.js.map +1 -0
- package/dist/snapshot.d.ts +11 -0
- package/dist/snapshot.js +220 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/state.d.ts +9 -0
- package/dist/state.js +143 -0
- package/dist/state.js.map +1 -0
- package/dist/transforms.d.ts +3 -0
- package/dist/transforms.js +188 -0
- package/dist/transforms.js.map +1 -0
- package/dist/types.d.ts +207 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/docs/architecture.md +91 -0
- package/docs/assets/report.png +0 -0
- package/docs/configuration.md +73 -0
- package/docs/evidence/dependency-removal.json +109 -0
- package/docs/evidence/next-frameworks.json +271 -0
- package/docs/evidence/next-pages.json +152 -0
- package/docs/evidence/rounding.json +46 -0
- package/docs/report-surface.md +22 -0
- package/docs/troubleshooting.md +47 -0
- package/docs/validation.md +103 -0
- package/examples/next-container/README.md +7 -0
- package/examples/next-container/app/about/page.jsx +1 -0
- package/examples/next-container/app/case.css +5 -0
- package/examples/next-container/app/layout.jsx +3 -0
- package/examples/next-container/app/page.jsx +4 -0
- package/examples/next-container/lib/catalog.js +2 -0
- package/examples/next-container/next.config.mjs +1 -0
- package/examples/next-container/package-lock.json +952 -0
- package/examples/next-container/package.json +13 -0
- package/examples/next-container/repro-surgeon.json +37 -0
- package/examples/next-css-bom/README.md +7 -0
- package/examples/next-css-bom/app/about/page.jsx +1 -0
- package/examples/next-css-bom/app/case.css +3 -0
- package/examples/next-css-bom/app/layout.jsx +3 -0
- package/examples/next-css-bom/app/page.jsx +4 -0
- package/examples/next-css-bom/lib/catalog.js +2 -0
- package/examples/next-css-bom/next.config.mjs +1 -0
- package/examples/next-css-bom/package-lock.json +952 -0
- package/examples/next-css-bom/package.json +13 -0
- package/examples/next-css-bom/repro-surgeon.json +36 -0
- package/examples/next-pages/README.md +14 -0
- package/examples/next-pages/lib/unused-catalog.js +5 -0
- package/examples/next-pages/next.config.mjs +1 -0
- package/examples/next-pages/package-lock.json +952 -0
- package/examples/next-pages/package.json +11 -0
- package/examples/next-pages/pages/health.jsx +3 -0
- package/examples/next-pages/pages/index.jsx +9 -0
- package/examples/next-pages/repro-surgeon.json +18 -0
- package/examples/next-root-param/README.md +7 -0
- package/examples/next-root-param/app/[lang-country]/about/page.jsx +1 -0
- package/examples/next-root-param/app/[lang-country]/layout.tsx +4 -0
- package/examples/next-root-param/app/[lang-country]/page.tsx +3 -0
- package/examples/next-root-param/lib/catalog.js +2 -0
- package/examples/next-root-param/next-env.d.ts +2 -0
- package/examples/next-root-param/next.config.mjs +1 -0
- package/examples/next-root-param/package-lock.json +1016 -0
- package/examples/next-root-param/package.json +19 -0
- package/examples/next-root-param/repro-surgeon.json +37 -0
- package/examples/next-root-param/tsconfig.json +35 -0
- package/examples/rounding/README.md +16 -0
- package/examples/rounding/check.mjs +6 -0
- package/examples/rounding/config/store.json +7 -0
- package/examples/rounding/fixtures/invoice.json +11 -0
- package/examples/rounding/package-lock.json +7 -0
- package/examples/rounding/package.json +7 -0
- package/examples/rounding/repro-surgeon.json +12 -0
- package/examples/rounding/src/catalog.mjs +9 -0
- package/examples/rounding/src/shipping.mjs +7 -0
- package/examples/rounding/src/totals.mjs +11 -0
- package/package.json +29 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "repro-next-root-param",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "next build"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"next": "16.3.3",
|
|
10
|
+
"react": "19.2.8",
|
|
11
|
+
"react-dom": "19.2.8"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"typescript": "5.9.3",
|
|
15
|
+
"@types/node": "24.13.3",
|
|
16
|
+
"@types/react": "19.2.14",
|
|
17
|
+
"@types/react-dom": "19.2.3"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"name": "Next.js #97927 reconstruction",
|
|
4
|
+
"command": [
|
|
5
|
+
"npm",
|
|
6
|
+
"run",
|
|
7
|
+
"build"
|
|
8
|
+
],
|
|
9
|
+
"oracle": {
|
|
10
|
+
"exitCode": 1,
|
|
11
|
+
"allOf": [
|
|
12
|
+
".next/types/root-params.d.ts(4,23): error TS1005: '(' expected.",
|
|
13
|
+
".next/types/root-params.d.ts(4,33): error TS1005: ';' expected.",
|
|
14
|
+
"Failed to type check."
|
|
15
|
+
],
|
|
16
|
+
"noneOf": [
|
|
17
|
+
"Module not found",
|
|
18
|
+
"Cannot find module",
|
|
19
|
+
"Failed to fetch"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"adapter": "next",
|
|
23
|
+
"budget": {
|
|
24
|
+
"maxEvaluations": 80,
|
|
25
|
+
"maxSeconds": 900
|
|
26
|
+
},
|
|
27
|
+
"execution": {
|
|
28
|
+
"timeoutMs": 120000,
|
|
29
|
+
"installTimeoutMs": 180000
|
|
30
|
+
},
|
|
31
|
+
"reduce": {
|
|
32
|
+
"dependencies": false
|
|
33
|
+
},
|
|
34
|
+
"preserve": [
|
|
35
|
+
"next.config.mjs"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": [
|
|
5
|
+
"dom",
|
|
6
|
+
"dom.iterable",
|
|
7
|
+
"esnext"
|
|
8
|
+
],
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"module": "esnext",
|
|
15
|
+
"moduleResolution": "bundler",
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"isolatedModules": true,
|
|
18
|
+
"jsx": "preserve",
|
|
19
|
+
"incremental": true,
|
|
20
|
+
"plugins": [
|
|
21
|
+
{
|
|
22
|
+
"name": "next"
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"include": [
|
|
27
|
+
"next-env.d.ts",
|
|
28
|
+
"**/*.ts",
|
|
29
|
+
"**/*.tsx",
|
|
30
|
+
".next/types/**/*.ts"
|
|
31
|
+
],
|
|
32
|
+
"exclude": [
|
|
33
|
+
"node_modules"
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Rounding regression
|
|
2
|
+
|
|
3
|
+
A small, deliberately failing application for learning the workflow. No external dependencies. The calculation rounds each fractional line price before summing, producing 33 cents. The assertion expects rounding once at the end, producing 32 cents.
|
|
4
|
+
|
|
5
|
+
From the Repro Surgeon repository:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm ci
|
|
9
|
+
npm run build
|
|
10
|
+
node dist/cli.js reduce examples/rounding --out /tmp/rounding-repro
|
|
11
|
+
node /tmp/rounding-repro/repro/.repro/verify.mjs
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Choose a new output path for each run. Open `/tmp/rounding-repro/report.html` to inspect the changes. The checker is pinned so the reducer cannot rewrite the assertion. The remaining files and JSON fields are eligible for reduction.
|
|
15
|
+
|
|
16
|
+
This is demonstration data, not an upstream framework bug or a competitive benchmark. All source is covered by the repository's MIT license.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { totalCents } from './src/totals.mjs';
|
|
4
|
+
|
|
5
|
+
const invoice = JSON.parse(readFileSync(new URL('./fixtures/invoice.json', import.meta.url)));
|
|
6
|
+
assert.equal(totalCents(invoice.items), 32, 'Line totals must round only once');
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "example-001",
|
|
3
|
+
"currency": "USD",
|
|
4
|
+
"customer": { "name": "Example customer", "delivery": "local" },
|
|
5
|
+
"items": [
|
|
6
|
+
{ "sku": "sample-a", "price": 0.105, "description": "Fractional unit sample A" },
|
|
7
|
+
{ "sku": "sample-b", "price": 0.105, "description": "Fractional unit sample B" },
|
|
8
|
+
{ "sku": "sample-c", "price": 0.105, "description": "Fractional unit sample C" }
|
|
9
|
+
],
|
|
10
|
+
"notes": ["Demonstration data only", "Round the aggregate to integer cents"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"name": "Rounding regression",
|
|
4
|
+
"command": ["node", "check.mjs"],
|
|
5
|
+
"oracle": {
|
|
6
|
+
"exitCode": 1,
|
|
7
|
+
"allOf": ["AssertionError", "Line totals must round only once", "33 !== 32"],
|
|
8
|
+
"noneOf": ["ERR_MODULE_NOT_FOUND", "SyntaxError", "TypeError"]
|
|
9
|
+
},
|
|
10
|
+
"preserve": ["check.mjs"],
|
|
11
|
+
"budget": { "maxEvaluations": 200, "maxSeconds": 120 }
|
|
12
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const catalog = [
|
|
2
|
+
{ sku: 'paper', title: 'Recycled paper', price: 4.50, tags: ['office'] },
|
|
3
|
+
{ sku: 'pencil', title: 'Graphite pencil', price: 1.25, tags: ['office'] },
|
|
4
|
+
{ sku: 'notebook', title: 'Plain notebook', price: 6.00, tags: ['office', 'travel'] },
|
|
5
|
+
];
|
|
6
|
+
|
|
7
|
+
export function findProduct(sku) {
|
|
8
|
+
return catalog.find(product => product.sku === sku);
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const shippingZones = { local: 0, domestic: 500, international: 1800 };
|
|
2
|
+
|
|
3
|
+
export function shippingCents(zone, subtotal) {
|
|
4
|
+
if (subtotal >= 10000) return 0;
|
|
5
|
+
if (!(zone in shippingZones)) throw new Error(`Unknown shipping zone: ${zone}`);
|
|
6
|
+
return shippingZones[zone];
|
|
7
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function totalCents(items) {
|
|
2
|
+
return items.reduce((total, item) => total + Math.round(item.price * 100), 0);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function formatCents(cents, currency = 'USD') {
|
|
6
|
+
return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(cents / 100);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function withTax(cents, rate) {
|
|
10
|
+
return Math.round(cents * (1 + rate));
|
|
11
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "repro-surgeon",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shrink a failing application into an independently verified reproduction.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": { "repro-surgeon": "dist/cli.js" },
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
10
|
+
"files": ["dist", "examples", "README.md", "LICENSE", "SECURITY.md", "CONTRIBUTING.md", "CODE_OF_CONDUCT.md", "CHANGELOG.md", "docs"],
|
|
11
|
+
"engines": { "node": ">=22.18.0", "npm": ">=10" },
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc -p tsconfig.json",
|
|
14
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
15
|
+
"test": "node --test tests/*.test.ts",
|
|
16
|
+
"check": "npm run typecheck && npm test && npm run build",
|
|
17
|
+
"test:package": "node scripts/test-package.mjs",
|
|
18
|
+
"test:next": "npm run build && node scripts/validate-next.mjs",
|
|
19
|
+
"prepack": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": { "ignore": "7.0.8", "picomatch": "4.0.7", "typescript": "5.9.3" },
|
|
22
|
+
"devDependencies": { "@types/node": "24.13.3", "@types/picomatch": "4.0.2" },
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "Pavan <pavan.gupta.352@gmail.com>",
|
|
25
|
+
"repository": { "type": "git", "url": "https://github.com/pavangupta352/repro-surgeon.git" },
|
|
26
|
+
"bugs": { "url": "https://github.com/pavangupta352/repro-surgeon/issues" },
|
|
27
|
+
"homepage": "https://github.com/pavangupta352/repro-surgeon#readme",
|
|
28
|
+
"keywords": ["reproduction", "delta-debugging", "nextjs", "debugging", "test-case-reduction", "typescript"]
|
|
29
|
+
}
|