@intentius/chant 0.18.5 → 0.18.6

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.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * True when the module identified by `importMetaUrl` is the process entry point
3
+ * (`process.argv[1]`) — i.e. run directly, not imported.
4
+ *
5
+ * A naive `import.meta.url === \`file://${process.argv[1]}\`` is a false negative
6
+ * whenever the invocation path crosses a symlink (pnpm, global bins, a symlinked
7
+ * checkout, the npm `.bin` shim, `/tmp`→`/private/tmp`): the loader canonicalises
8
+ * `import.meta.url` to the realpath while `argv[1]` keeps the symlink, so the CLI
9
+ * silently exits 0 having done nothing. Canonicalise both sides so the entry
10
+ * point is detected regardless of how the path was spelled.
11
+ */
12
+ export declare function isEntryPoint(argv1: string | undefined, importMetaUrl: string): boolean;
13
+ //# sourceMappingURL=is-entry-point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"is-entry-point.d.ts","sourceRoot":"","sources":["../../src/cli/is-entry-point.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAOtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAKA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA2LpD"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AAMA,OAAO,EAAmC,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAiB9E;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA2LpD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.18.5",
3
+ "version": "0.18.6",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -0,0 +1,46 @@
1
+ import { describe, test, expect, beforeAll, afterAll } from "vitest";
2
+ import { isEntryPoint } from "./is-entry-point";
3
+ import { mkdtempSync, writeFileSync, symlinkSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+
8
+ describe("isEntryPoint", () => {
9
+ let dir: string;
10
+
11
+ beforeAll(() => {
12
+ dir = mkdtempSync(join(tmpdir(), "chant-entry-"));
13
+ writeFileSync(join(dir, "cli.ts"), "");
14
+ writeFileSync(join(dir, "marker"), "");
15
+ symlinkSync(join(dir, "cli.ts"), join(dir, "cli-link.ts"));
16
+ });
17
+ afterAll(() => rmSync(dir, { recursive: true, force: true }));
18
+
19
+ test("true when argv1 and import.meta.url are the same real file", () => {
20
+ const file = join(dir, "cli.ts");
21
+ expect(isEntryPoint(file, pathToFileURL(file).href)).toBe(true);
22
+ });
23
+
24
+ test("true when argv1 is a symlink to the file import.meta.url resolves to", () => {
25
+ // The regression: import.meta.url is the realpath (real cli.ts); argv1 is the
26
+ // symlink (cli-link.ts). A raw string compare would be false; this must be true.
27
+ const symlinkArg = join(dir, "cli-link.ts");
28
+ const realUrl = pathToFileURL(join(dir, "cli.ts")).href;
29
+ expect(symlinkArg).not.toBe(join(dir, "cli.ts"));
30
+ expect(isEntryPoint(symlinkArg, realUrl)).toBe(true);
31
+ });
32
+
33
+ test("false for a different file (imported, not the entry point)", () => {
34
+ const other = join(dir, "cli.ts");
35
+ const importedUrl = pathToFileURL(join(dir, "marker")).href;
36
+ expect(isEntryPoint(other, importedUrl)).toBe(false);
37
+ });
38
+
39
+ test("false when there is no argv1", () => {
40
+ expect(isEntryPoint(undefined, pathToFileURL(join(dir, "cli.ts")).href)).toBe(false);
41
+ });
42
+
43
+ test("false (not a throw) when a path does not exist", () => {
44
+ expect(isEntryPoint(join(dir, "gone.ts"), pathToFileURL(join(dir, "cli.ts")).href)).toBe(false);
45
+ });
46
+ });
@@ -0,0 +1,22 @@
1
+ import { realpathSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ /**
5
+ * True when the module identified by `importMetaUrl` is the process entry point
6
+ * (`process.argv[1]`) — i.e. run directly, not imported.
7
+ *
8
+ * A naive `import.meta.url === \`file://${process.argv[1]}\`` is a false negative
9
+ * whenever the invocation path crosses a symlink (pnpm, global bins, a symlinked
10
+ * checkout, the npm `.bin` shim, `/tmp`→`/private/tmp`): the loader canonicalises
11
+ * `import.meta.url` to the realpath while `argv[1]` keeps the symlink, so the CLI
12
+ * silently exits 0 having done nothing. Canonicalise both sides so the entry
13
+ * point is detected regardless of how the path was spelled.
14
+ */
15
+ export function isEntryPoint(argv1: string | undefined, importMetaUrl: string): boolean {
16
+ if (!argv1) return false;
17
+ try {
18
+ return realpathSync(argv1) === realpathSync(fileURLToPath(importMetaUrl));
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
package/src/cli/main.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env tsx
2
2
 
3
3
  import { resolve } from "node:path";
4
+ import { isEntryPoint } from "./is-entry-point";
4
5
  import { formatSuccess, formatError } from "./format";
5
6
  import { loadPlugins, resolveProjectLexicons } from "./plugins";
6
7
  import { resolveCommand, type CommandDef, type ParsedArgs } from "./registry";
@@ -536,8 +537,10 @@ async function main(): Promise<void> {
536
537
  process.exit(await match.def.handler(ctx));
537
538
  }
538
539
 
539
- // Only run main when executed directly, not when imported
540
- const isMain = import.meta.url === `file://${process.argv[1]}`;
540
+ // Only run main when executed directly, not when imported. Robust to symlinked
541
+ // invocation paths see isEntryPoint (a raw string compare silently no-ops the
542
+ // whole CLI through the npm .bin shim / a symlinked checkout).
543
+ const isMain = isEntryPoint(process.argv[1], import.meta.url);
541
544
  if (isMain) {
542
545
  main().catch((err) => {
543
546
  const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");