@williamthorsen/nmr 0.17.0 → 0.17.1

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/README.md CHANGED
@@ -3,13 +3,13 @@
3
3
  Context-aware script runner for PNPM monorepos. Ships an `nmr` (node-monorepo run) binary that provides centralized, consistent script execution across workspace packages and the monorepo root.
4
4
 
5
5
  <!-- section:release-notes -->
6
- ## Release notes — v0.17.0 (2026-07-01)
6
+ ## Release notes — v0.17.1 (2026-07-01)
7
7
 
8
- ### 🎉 Features
8
+ ### 🐛 Bug fixes
9
9
 
10
- - 🚨 **Breaking:** Rebuild nmr-compile on a unified tsc emit (#455)
10
+ - Relocate nmr-compile's build cache out of the published dist (#457)
11
11
 
12
- `nmr` now compiles a package's JavaScript and type declarations in one step, rewriting every import form — static, re-export, dynamic `import()`, bare side-effect, and tsconfig `paths` aliases — to runnable `.js` in both outputs. It now requires TypeScript 5.7 or newer as a peer dependency.
12
+ Fixes an issue where packages built with nmr-compile shipped an internal build-cache file inside their published npm tarball.
13
13
  <!-- /section:release-notes -->
14
14
 
15
15
  ## Installation
@@ -345,7 +345,7 @@ nmr sync-pnpm-version
345
345
 
346
346
  ### `nmr-compile`
347
347
 
348
- Compile a single package's `src` tree to `dist/esm` with the TypeScript compiler API, emitting `.js` and `.d.ts` in one pass. Because the compiler parses each source file, every relative import form — static, re-export, dynamic `import()`, and bare side-effect — is rewritten from `.ts` to `.js` in both outputs, and `.ts` occurrences inside strings and comments are left intact. tsconfig `paths` aliases are resolved to runnable relative `.js` specifiers in both outputs, sourced from the package's tsconfig. The build is skipped when no input has changed (a content-and-path hash is cached in `dist/esm/.cache`). This is the default `compile` script — run it from a package directory.
348
+ Compile a single package's `src` tree to `dist/esm` with the TypeScript compiler API, emitting `.js` and `.d.ts` in one pass. Because the compiler parses each source file, every relative import form — static, re-export, dynamic `import()`, and bare side-effect — is rewritten from `.ts` to `.js` in both outputs, and `.ts` occurrences inside strings and comments are left intact. tsconfig `paths` aliases are resolved to runnable relative `.js` specifiers in both outputs, sourced from the package's tsconfig. The build is skipped when no input has changed (a content-and-path hash is cached under `node_modules/.cache/nmr-compile/`, outside the published output). This is the default `compile` script — run it from a package directory.
349
349
 
350
350
  `typescript` is a peer dependency (`>=5.7.0`, required for `rewriteRelativeImportExtensions`); the consuming repo provides it. Relative imports in source must carry explicit `.ts` extensions for them to be rewritten.
351
351
 
@@ -2,8 +2,8 @@ export interface BuildOptions {
2
2
  entryGlobs?: string[];
3
3
  ignore?: string[];
4
4
  outdir?: string;
5
- cacheFile?: string;
6
5
  }
7
6
  export declare function buildPackage(packageDir: string, options?: BuildOptions): Promise<void>;
8
7
  export declare function computeBuildHash(packageDir: string, files: string[], emitConfig: object): Promise<string>;
9
8
  export declare function resolveTsconfigChain(packageDir: string, configFileName?: string): string[];
9
+ export declare function resolveBuildCachePath(packageDir: string): string;
@@ -9,7 +9,6 @@ const SKIPPED_ICON = '⏭️';
9
9
  const DEFAULT_ENTRY_GLOBS = ['src/**/*.ts'];
10
10
  const DEFAULT_IGNORE = ['**/__tests__/**'];
11
11
  const DEFAULT_OUTDIR = 'dist/esm/';
12
- const DEFAULT_CACHE_FILE = 'dist/esm/.cache';
13
12
  const SOURCE_ROOT = 'src';
14
13
  const MINIMUM_TYPESCRIPT_MAJOR = 5;
15
14
  const MINIMUM_TYPESCRIPT_MINOR = 7;
@@ -17,7 +16,7 @@ const TS_EXTENSION = '.ts';
17
16
  const JS_EXTENSION = '.js';
18
17
  export async function buildPackage(packageDir, options = {}) {
19
18
  assertSupportedTypeScript();
20
- const cacheFile = options.cacheFile ?? DEFAULT_CACHE_FILE;
19
+ const cachePath = resolveBuildCachePath(packageDir);
21
20
  const outdir = options.outdir ?? DEFAULT_OUTDIR;
22
21
  const emitConfig = { outdir, declaration: true, rewriteRelativeImportExtensions: true };
23
22
  const entryPoints = await glob(options.entryGlobs ?? DEFAULT_ENTRY_GLOBS, {
@@ -25,12 +24,12 @@ export async function buildPackage(packageDir, options = {}) {
25
24
  ignore: options.ignore ?? DEFAULT_IGNORE,
26
25
  });
27
26
  const dependencies = ['package.json', ...resolveTsconfigChain(packageDir)];
28
- const { changed, currentHash } = await detectBuildChanges(packageDir, [...entryPoints, ...dependencies], emitConfig, cacheFile);
27
+ const { changed, currentHash } = await detectBuildChanges(packageDir, [...entryPoints, ...dependencies], emitConfig, cachePath);
29
28
  if (!changed) {
30
29
  return;
31
30
  }
32
31
  emitPackage(packageDir, entryPoints, outdir);
33
- await writeBuildCache(packageDir, cacheFile, currentHash);
32
+ await writeBuildCache(cachePath, currentHash);
34
33
  }
35
34
  export async function computeBuildHash(packageDir, files, emitConfig) {
36
35
  const hash = createHash('sha256');
@@ -181,9 +180,27 @@ function getModuleSpecifier(node) {
181
180
  }
182
181
  return undefined;
183
182
  }
184
- async function detectBuildChanges(packageDir, files, emitConfig, cacheFile) {
183
+ export function resolveBuildCachePath(packageDir) {
184
+ const absolutePackageDir = path.resolve(packageDir);
185
+ const home = findNearestNodeModulesHost(absolutePackageDir) ?? absolutePackageDir;
186
+ const digest = createHash('sha256').update(absolutePackageDir).digest('hex').slice(0, 8);
187
+ const key = `${path.basename(absolutePackageDir)}-${digest}.hash`;
188
+ return path.join(home, 'node_modules', '.cache', 'nmr-compile', key);
189
+ }
190
+ function findNearestNodeModulesHost(startDir) {
191
+ let current = startDir;
192
+ let parent = path.dirname(current);
193
+ while (!existsSync(path.join(current, 'node_modules'))) {
194
+ if (parent === current) {
195
+ return undefined;
196
+ }
197
+ current = parent;
198
+ parent = path.dirname(current);
199
+ }
200
+ return current;
201
+ }
202
+ async function detectBuildChanges(packageDir, files, emitConfig, cachePath) {
185
203
  const packageName = path.basename(packageDir);
186
- const cachePath = path.join(packageDir, cacheFile);
187
204
  const previousHash = existsSync(cachePath) ? readFileSync(cachePath, 'utf8') : undefined;
188
205
  const currentHash = await computeBuildHash(packageDir, files, emitConfig);
189
206
  if (previousHash === currentHash) {
@@ -193,8 +210,7 @@ async function detectBuildChanges(packageDir, files, emitConfig, cacheFile) {
193
210
  console.info(`${PACKAGE_ICON} ${packageName}: Changes detected.`);
194
211
  return { changed: true, currentHash };
195
212
  }
196
- async function writeBuildCache(packageDir, cacheFile, hash) {
197
- const cachePath = path.join(packageDir, cacheFile);
213
+ async function writeBuildCache(cachePath, hash) {
198
214
  await mkdir(path.dirname(cachePath), { recursive: true });
199
215
  await writeFile(cachePath, hash);
200
216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@williamthorsen/nmr",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "private": false,
5
5
  "description": "Context-aware script runner for PNPM monorepos",
6
6
  "keywords": [
package/dist/esm/.cache DELETED
@@ -1 +0,0 @@
1
- 49f79592247d14646b1445473aa445a8bcbeafb478c6dc9949eb31cee8e2a627