@interchained/portal-cli 0.1.3 → 0.1.4

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.
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Load app.contract.ts from a Portal project.
3
- * Uses a simple regex-based extraction since we can't dynamically import TS at runtime.
4
- * For full evaluation, we'd use jiti/tsx — but for MVP we parse the exported object.
2
+ * Load app.contract from a Portal project.
3
+ *
4
+ * Supported formats (checked in order):
5
+ * 1. app.contract.json — plain JSON, zero parsing ambiguity
6
+ * 2. app.contract.ts / .js — static TS/JS, several export patterns handled
7
+ *
8
+ * The contract file is intentionally kept as static data (no runtime logic).
9
+ * We extract it with a regex rather than executing arbitrary code.
5
10
  */
6
11
  import { type AppContract } from "@interchained/portal-contract";
7
12
  export declare function findContractPath(root: string): Promise<string | null>;
8
- /**
9
- * Load a contract from a Portal project.
10
- * Attempts to read and evaluate the contract file.
11
- * Falls back to a safe empty contract if not found.
12
- */
13
13
  export declare function loadContract(root?: string): Promise<AppContract>;
14
14
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/utils/contract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AASnF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS3E;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,SAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuB7E"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/utils/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAWnF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3E;AAED,wBAAsB,YAAY,CAAC,IAAI,SAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAmC7E"}
@@ -1,14 +1,21 @@
1
1
  /**
2
- * Load app.contract.ts from a Portal project.
3
- * Uses a simple regex-based extraction since we can't dynamically import TS at runtime.
4
- * For full evaluation, we'd use jiti/tsx — but for MVP we parse the exported object.
2
+ * Load app.contract from a Portal project.
3
+ *
4
+ * Supported formats (checked in order):
5
+ * 1. app.contract.json — plain JSON, zero parsing ambiguity
6
+ * 2. app.contract.ts / .js — static TS/JS, several export patterns handled
7
+ *
8
+ * The contract file is intentionally kept as static data (no runtime logic).
9
+ * We extract it with a regex rather than executing arbitrary code.
5
10
  */
6
11
  import { readFile, access } from "node:fs/promises";
7
12
  import { join } from "node:path";
8
13
  import { validateContract } from "@interchained/portal-contract";
9
14
  const CANDIDATE_PATHS = [
15
+ "app.contract.json",
10
16
  "app.contract.ts",
11
17
  "app.contract.js",
18
+ "portal.contract.json",
12
19
  "portal.contract.ts",
13
20
  "portal.contract.js",
14
21
  ];
@@ -19,35 +26,50 @@ export async function findContractPath(root) {
19
26
  await access(full);
20
27
  return full;
21
28
  }
22
- catch { /* continue */ }
29
+ catch { /* next */ }
23
30
  }
24
31
  return null;
25
32
  }
26
- /**
27
- * Load a contract from a Portal project.
28
- * Attempts to read and evaluate the contract file.
29
- * Falls back to a safe empty contract if not found.
30
- */
31
33
  export async function loadContract(root = process.cwd()) {
32
34
  const contractPath = await findContractPath(root);
33
- if (!contractPath) {
35
+ if (!contractPath)
34
36
  return { name: "Portal App", goals: [] };
35
- }
36
37
  try {
37
38
  const src = await readFile(contractPath, "utf-8");
38
- // Extract the object passed to defineApp() using a simple heuristic.
39
- // This is intentionally dumb — the contract file should be static data, not logic.
40
- const match = src.match(/defineApp\(\s*(\{[\s\S]*?\})\s*\)/);
41
- if (!match) {
42
- return { name: "Portal App", goals: [] };
39
+ // ── JSON file ─────────────────────────────────────────────────────────────
40
+ if (contractPath.endsWith(".json")) {
41
+ return validateContract(JSON.parse(src));
43
42
  }
44
- // Safe eval via Function constructor (no side effects in contract files)
45
- const fn = new Function(`return (${match[1]})`);
46
- const raw = fn();
47
- return validateContract(raw);
43
+ // ── TS/JS patterns ────────────────────────────────────────────────────────
44
+ // We try several common shapes, in order of specificity.
45
+ // 1. defineApp({ ... })
46
+ const defineMatch = src.match(/defineApp\s*\(\s*(\{[\s\S]*?\})\s*\)/);
47
+ if (defineMatch)
48
+ return evalObject(defineMatch[1]);
49
+ // 2. export default { ... } (inline object literal)
50
+ const exportDefaultInline = src.match(/export\s+default\s+(\{[\s\S]*\})\s*;?\s*$/);
51
+ if (exportDefaultInline)
52
+ return evalObject(exportDefaultInline[1]);
53
+ // 3. const <name>: AppContract = { ... }
54
+ const constTyped = src.match(/const\s+\w+\s*:\s*AppContract\s*=\s*(\{[\s\S]*?\});\s*$/m);
55
+ if (constTyped)
56
+ return evalObject(constTyped[1]);
57
+ // 4. const <name> = { ... } (no type annotation)
58
+ const constPlain = src.match(/const\s+\w+\s*=\s*(\{[\s\S]*?\});\s*$/m);
59
+ if (constPlain)
60
+ return evalObject(constPlain[1]);
61
+ return { name: "Portal App", goals: [] };
48
62
  }
49
63
  catch {
50
64
  return { name: "Portal App", goals: [] };
51
65
  }
52
66
  }
67
+ function evalObject(src) {
68
+ // Strip TypeScript casts and `as const` before evaluating
69
+ const cleaned = src
70
+ .replace(/\s+as\s+\w[\w.]*(\[\])?/g, "")
71
+ .replace(/\s+satisfies\s+\w[\w.]*/g, "");
72
+ const fn = new Function(`return (${cleaned})`);
73
+ return validateContract(fn());
74
+ }
53
75
  //# sourceMappingURL=contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/utils/contract.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAoB,MAAM,+BAA+B,CAAC;AAEnF,MAAM,eAAe,GAAG;IACtB,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,KAAK,MAAM,SAAS,IAAI,eAAe,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;IACrD,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAElD,qEAAqE;QACrE,mFAAmF;QACnF,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAC3C,CAAC;QAED,yEAAyE;QACzE,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAChD,MAAM,GAAG,GAAG,EAAE,EAAa,CAAC;QAC5B,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/utils/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAoB,MAAM,+BAA+B,CAAC;AAEnF,MAAM,eAAe,GAAG;IACtB,mBAAmB;IACnB,iBAAiB;IACjB,iBAAiB;IACjB,sBAAsB;IACtB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,KAAK,MAAM,SAAS,IAAI,eAAe,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACnC,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAAC,OAAO,IAAI,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;IACrD,MAAM,YAAY,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAE5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QAElD,6EAA6E;QAC7E,IAAI,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACnC,OAAO,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QAC3C,CAAC;QAED,6EAA6E;QAC7E,yDAAyD;QAEzD,wBAAwB;QACxB,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACtE,IAAI,WAAW;YAAE,OAAO,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnD,sDAAsD;QACtD,MAAM,mBAAmB,GAAG,GAAG,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC;QACnF,IAAI,mBAAmB;YAAE,OAAO,UAAU,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnE,yCAAyC;QACzC,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QACzF,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjD,mDAAmD;QACnD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;QACvE,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAEjD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,0DAA0D;IAC1D,MAAM,OAAO,GAAG,GAAG;SAChB,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC;SACvC,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,WAAW,OAAO,GAAG,CAAC,CAAC;IAC/C,OAAO,gBAAgB,CAAC,EAAE,EAAa,CAAC,CAAC;AAC3C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interchained/portal-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Portal CLI — dev, build, audit, improve, generate, guard",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "author": "Interchained <dev@interchained.org>",