diff --git a/CHANGELOG.md b/CHANGELOG.md index 359ccfce..ce925039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,12 @@ - Adds `arrConcat` as a dedicated array helper and `fnBindArgs` as a dedicated function helper - Improves function binding typing with exported `BoundFunction` and updated signatures for `fnBind` / `fnBindArgs` +### Bug Fixes + +- [#568](https://github.com/nevware21/ts-utils/issues/568) Rolldown `INVALID_ANNOTATION` warnings caused by non-canonical PURE annotation spacing in generated output + - [#569](https://github.com/nevware21/ts-utils/pull/569) Add generated-chunk PURE annotation normalization so spaced forms are rewritten to canonical `(/*#__PURE__*/` / `(/*@__PURE__*/` in rollup output + - [#575](https://github.com/nevware21/ts-utils/pull/575) Add packaged artifact validation for PURE annotation spacing and update normalization tolerance, with per-file logging while scanning `lib/bundle` and `lib/dist` + # v0.14.0 May 18th, 2026 ## Changelog diff --git a/lib/rollup.config.js b/lib/rollup.config.js index 9be55b7a..8b6d5b70 100644 --- a/lib/rollup.config.js +++ b/lib/rollup.config.js @@ -91,7 +91,7 @@ export function uglify3(options = {}) { // canonical form with the comment flush against the open paren, which every // bundler accepts. Uses magic-string so the generated sourcemap stays valid. export function fixPureAnnotations() { - const pureRe = /\([ \t]*\/\*[ \t]*([#@])__PURE__[ \t]*\*\//g; + const pureRe = /\(\s{0,5}\/\*\s{0,5}([#@])__PURE__\s{0,5}\*\//g; return { name: "fix-pure-annotations", diff --git a/lib/test/bundle-pure-annotations-check.js b/lib/test/bundle-pure-annotations-check.js new file mode 100644 index 00000000..82dc9777 --- /dev/null +++ b/lib/test/bundle-pure-annotations-check.js @@ -0,0 +1,79 @@ +const fs = require("fs"); +const path = require("path"); + +const outputRoots = [ + path.join(__dirname, "../bundle"), + path.join(__dirname, "../dist") +]; + +const invalidPureAnnotationRe = /\(\s+\/\*\s*([#@])__PURE__\s*\*\//g; + +function collectJsFiles(rootPath, output) { + if (!fs.existsSync(rootPath)) { + return; + } + + fs.readdirSync(rootPath).forEach((name) => { + const fullPath = path.join(rootPath, name); + const stat = fs.statSync(fullPath); + + if (stat.isDirectory()) { + collectJsFiles(fullPath, output); + return; + } + + if (stat.isFile() && path.extname(name) === ".js") { + output.push(fullPath); + } + }); +} + +function getLineNumber(content, index) { + let line = 1; + for (let lp = 0; lp < index; lp++) { + if (content.charCodeAt(lp) === 10) { + line++; + } + } + + return line; +} + +const jsFiles = []; +outputRoots.forEach((rootPath) => collectJsFiles(rootPath, jsFiles)); + +if (jsFiles.length === 0) { + console.error("No generated JavaScript files were found under lib/bundle or lib/dist"); + process.exit(1); +} + +const failures = []; + +console.log("Scanning generated JavaScript files for PURE annotation spacing..."); +console.log("Files discovered: " + jsFiles.length); + +jsFiles.forEach((filePath) => { + const relativeFilePath = path.relative(process.cwd(), filePath).replace(/\\/g, "/"); + console.log(" - Processing " + relativeFilePath); + const content = fs.readFileSync(filePath, "utf8"); + let match; + + invalidPureAnnotationRe.lastIndex = 0; + while ((match = invalidPureAnnotationRe.exec(content))) { + failures.push({ + filePath: relativeFilePath, + line: getLineNumber(content, match.index), + sample: match[0] + }); + } +}); + +if (failures.length > 0) { + console.error("Found invalid PURE annotations with leading whitespace after '(':"); + failures.forEach((failure) => { + console.error(" - " + failure.filePath + ":" + failure.line + " -> " + failure.sample); + }); + process.exit(1); +} + +console.log("PURE annotation spacing check passed for generated bundle/dist JavaScript files."); diff --git a/package.json b/package.json index 81391a21..4dd7a331 100644 --- a/package.json +++ b/package.json @@ -211,7 +211,7 @@ "dtsgen": "api-extractor run --local --verbose && node lib/scripts/setTsReferences.js", "size": "size-limit", "size-save": "size-limit --clean-dir --save-bundle build/size", - "size-check": "node lib/test/bundle-size-check.js", + "size-check": "node lib/test/bundle-size-check.js && node lib/test/bundle-pure-annotations-check.js", "link-check": "node lib/test/readme-links-check.js", "readme-link-check": "npm run docs && npm run link-check" },