fix(schematics): pin prerelease installs to the exact version#3709
fix(schematics): pin prerelease installs to the exact version#3709armando-navarro wants to merge 1 commit into
Conversation
ng add records the installed package with npm's default caret prefix. For a stable release that only drifts to reviewed patch releases, but a prerelease range like ^21.0.0-rc.0 also matches the canary build published for every merge to main — so a later fresh install could silently replace the version the user chose with an unreviewed snapshot. After install, if the workspace's @angular/fire entry is a caret or tilde range around a prerelease, rewrite it to the exact installed version (only when that version already satisfies the range). Stable ranges and hand-authored range expressions are left untouched.
| try { | ||
| return JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json')).toString()).version; | ||
| } catch { | ||
| return undefined; |
There was a problem hiding this comment.
Minor: if the file read fails for any reason, readInstalledVersion returns undefined with no log output, so the user gets no indication the pin was skipped. A context.logger.warn in the catch would help debuggability.
| if (!host.exists('package.json')) { return; } | ||
| const packageJson = safeReadJSON('package.json', host); | ||
|
|
||
| const declaredAngularFireVersion = packageJson.dependencies?.['@angular/fire']; |
There was a problem hiding this comment.
The function only reads from packageJson.dependencies. If @angular/fire somehow ends up in devDependencies, the pin is silently skipped. Unlikely via ng add, but worth a follow-up.
| * directories up. Returns undefined when that layout doesn't hold (e.g. running from source), | ||
| * so callers skip pinning instead of failing the schematic. | ||
| */ | ||
| const readInstalledVersion = () => { |
There was a problem hiding this comment.
Optional/nit, design suggestion: tools/build.ts already stamps values into versions.json at build time, and add/index.ts already imports from it. Adding angularFireVersion there would let you replace the readFileSync/__dirname traversal with a plain JSON import, same pattern already in use and no filesystem-path assumptions.
ng add @angular/fire@nextrecords the install with npm's default caret (^21.0.0-rc.0). A prerelease range like that also matches the-canary.<sha>builds published for every merge to main — they sort higher than the RC — so any later fresh install silently replaces the version the user chose with an unreviewed snapshot.After install, the schematic now pins the workspace's
@angular/fireentry to the exact installed version when the recorded spec is a caret or tilde range around a prerelease (and only when the installed version already satisfies that range). Stable ranges, exact versions, and hand-authored range expressions are left untouched. Includes unit specs for the pinning and all leave-alone cases.Fixes #3708