@openpolicy/cli 0.0.11 → 0.0.13

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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1 -487
  3. package/package.json +9 -3
  4. package/src/cli.ts +5 -0
  5. package/dist/_cli-BVVbyDQ9.js +0 -49
  6. package/dist/_cli-BjVuFgXe.js +0 -33
  7. package/dist/_cli-C-Vx-Nop.js +0 -58
  8. package/dist/_cli-DrypJgn2.js +0 -247
  9. package/dist/_lib-9AbI1LBo.js +0 -35
  10. package/dist/_lib-9AbI1LBo.js.map +0 -1
  11. package/dist/_lib-D2I-M4OU.js +0 -51
  12. package/dist/_lib-D2I-M4OU.js.map +0 -1
  13. package/dist/_lib-D2LkleUQ.js +0 -60
  14. package/dist/_lib-D2LkleUQ.js.map +0 -1
  15. package/dist/_lib-MI0GKJMR.js +0 -249
  16. package/dist/_lib-MI0GKJMR.js.map +0 -1
  17. package/dist/cli +0 -0
  18. package/dist/cli.d.ts +0 -3
  19. package/dist/cli.d.ts.map +0 -1
  20. package/dist/commands/generate.d.ts +0 -18
  21. package/dist/commands/generate.d.ts.map +0 -1
  22. package/dist/commands/generate.test.d.ts +0 -2
  23. package/dist/commands/generate.test.d.ts.map +0 -1
  24. package/dist/commands/init.d.ts +0 -13
  25. package/dist/commands/init.d.ts.map +0 -1
  26. package/dist/commands/init.test.d.ts +0 -2
  27. package/dist/commands/init.test.d.ts.map +0 -1
  28. package/dist/commands/validate.d.ts +0 -13
  29. package/dist/commands/validate.d.ts.map +0 -1
  30. package/dist/commands/validate.test.d.ts +0 -2
  31. package/dist/commands/validate.test.d.ts.map +0 -1
  32. package/dist/generate-ItFTJ-jj.js +0 -60
  33. package/dist/generate-ItFTJ-jj.js.map +0 -1
  34. package/dist/index.d.ts +0 -8
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.js +0 -22
  37. package/dist/index.js.map +0 -1
  38. package/dist/index.test.d.ts +0 -2
  39. package/dist/index.test.d.ts.map +0 -1
  40. package/dist/init-37NxG-6N.js +0 -249
  41. package/dist/init-37NxG-6N.js.map +0 -1
  42. package/dist/load-config-Bw8yiDkb.js +0 -35
  43. package/dist/load-config-Bw8yiDkb.js.map +0 -1
  44. package/dist/utils/load-config.d.ts +0 -2
  45. package/dist/utils/load-config.d.ts.map +0 -1
  46. package/dist/validate-DPge58Uv.js +0 -51
  47. package/dist/validate-DPge58Uv.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > CLI for generating and validating [OpenPolicy](https://openpolicy.sh) policy documents.
4
4
 
5
- Compile privacy policies and terms of service to Markdown or HTML from the command line — no Vite or Astro required.
5
+ Compile privacy policies and terms of service to Markdown, HTML, or PDF from the command line — no Vite or Astro required.
6
6
 
7
7
  ## Install
8
8
 
@@ -38,7 +38,7 @@ openpolicy generate ./terms.config.ts --format markdown --out ./public/po
38
38
 
39
39
  | Flag | Default | Description |
40
40
  |---|---|---|
41
- | `--format` | `markdown` | Comma-separated output formats: `markdown`, `html` |
41
+ | `--format` | `markdown` | Comma-separated output formats: `markdown`, `html`, `pdf` |
42
42
  | `--out` | `./public/policies` | Output directory |
43
43
  | `--type` | auto-detected | Override policy type: `privacy` or `terms` |
44
44
  | `--watch` | `false` | Watch config files and regenerate on changes |
package/dist/cli.js CHANGED
@@ -1,487 +1 @@
1
- #!/usr/bin/env node
2
- import { defineCommand, runMain } from "citty";
3
- import { join, resolve } from "node:path";
4
- import consola from "consola";
5
- import { existsSync, watch } from "node:fs";
6
- import { mkdir, writeFile } from "node:fs/promises";
7
- import { compilePolicy, expandOpenPolicyConfig, isOpenPolicyConfig, validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
8
- //#region \0rolldown/runtime.js
9
- var __defProp = Object.defineProperty;
10
- var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
11
- var __exportAll = (all, no_symbols) => {
12
- let target = {};
13
- for (var name in all) __defProp(target, name, {
14
- get: all[name],
15
- enumerable: true
16
- });
17
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
18
- return target;
19
- };
20
- //#endregion
21
- //#region package.json
22
- var version = "0.0.11";
23
- //#endregion
24
- //#region src/commands/init.ts
25
- var init_exports = /* @__PURE__ */ __exportAll({ initCommand: () => initCommand });
26
- function toJurisdictions(choice) {
27
- if (choice === "gdpr") return ["eu"];
28
- if (choice === "ccpa") return ["ca"];
29
- if (choice === "both") return ["eu", "ca"];
30
- return ["us"];
31
- }
32
- function toDataCollected(categories) {
33
- const groups = {};
34
- for (const cat of categories) {
35
- const mapping = DATA_CATEGORY_MAP[cat];
36
- if (!mapping) continue;
37
- groups[mapping.group] = [...groups[mapping.group] ?? [], mapping.label];
38
- }
39
- return Object.keys(groups).length > 0 ? groups : { "Personal Information": ["Email address"] };
40
- }
41
- function toUserRights(jurisdictions) {
42
- const rights = new Set(["access", "erasure"]);
43
- if (jurisdictions.includes("eu")) for (const r of [
44
- "rectification",
45
- "portability",
46
- "restriction",
47
- "objection"
48
- ]) rights.add(r);
49
- if (jurisdictions.includes("ca")) for (const r of ["opt_out_sale", "non_discrimination"]) rights.add(r);
50
- return Array.from(rights);
51
- }
52
- function renderPrivacyConfig(values) {
53
- const dataLines = Object.entries(values.dataCollected).map(([k, v]) => ` ${JSON.stringify(k)}: ${JSON.stringify(v)},`).join("\n");
54
- return `import { definePrivacyPolicy } from "@openpolicy/sdk";
55
-
56
- export default definePrivacyPolicy({
57
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
58
- company: {
59
- name: ${JSON.stringify(values.companyName)},
60
- legalName: ${JSON.stringify(values.legalName)},
61
- address: ${JSON.stringify(values.address)},
62
- contact: ${JSON.stringify(values.contact)},
63
- },
64
- dataCollected: {
65
- ${dataLines}
66
- },
67
- legalBasis: ${JSON.stringify(values.legalBasis)},
68
- retention: {
69
- "All personal data": "As long as necessary for the purposes described in this policy",
70
- },
71
- cookies: {
72
- essential: true,
73
- analytics: ${values.hasCookies},
74
- marketing: false,
75
- },
76
- thirdParties: [],
77
- userRights: ${JSON.stringify(values.userRights)},
78
- jurisdictions: ${JSON.stringify(values.jurisdictions)},
79
- });
80
- `;
81
- }
82
- function renderTermsConfig(values) {
83
- return `import { defineTermsOfService } from "@openpolicy/sdk";
84
-
85
- export default defineTermsOfService({
86
- effectiveDate: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}",
87
- company: {
88
- name: ${JSON.stringify(values.companyName)},
89
- legalName: ${JSON.stringify(values.legalName)},
90
- address: ${JSON.stringify(values.address)},
91
- contact: ${JSON.stringify(values.contact)},
92
- },
93
- acceptance: {
94
- methods: ["using the service", "creating an account"],
95
- },
96
- eligibility: {
97
- minimumAge: 13,
98
- },
99
- accounts: {
100
- registrationRequired: false,
101
- userResponsibleForCredentials: true,
102
- companyCanTerminate: true,
103
- },
104
- prohibitedUses: [
105
- "Violating any applicable laws or regulations",
106
- "Infringing on intellectual property rights",
107
- "Transmitting harmful or malicious content",
108
- ],
109
- intellectualProperty: {
110
- companyOwnsService: true,
111
- usersMayNotCopy: true,
112
- },
113
- termination: {
114
- companyCanTerminate: true,
115
- userCanTerminate: true,
116
- },
117
- disclaimers: {
118
- serviceProvidedAsIs: true,
119
- noWarranties: true,
120
- },
121
- limitationOfLiability: {
122
- excludesIndirectDamages: true,
123
- },
124
- governingLaw: {
125
- jurisdiction: ${JSON.stringify(values.jurisdiction)},
126
- },
127
- changesPolicy: {
128
- noticeMethod: "email or prominent notice on our website",
129
- noticePeriodDays: 30,
130
- },
131
- });
132
- `;
133
- }
134
- var DATA_CATEGORY_MAP, initCommand;
135
- var init_init = __esmMin((() => {
136
- DATA_CATEGORY_MAP = {
137
- name: {
138
- group: "Personal Information",
139
- label: "Full name"
140
- },
141
- email: {
142
- group: "Personal Information",
143
- label: "Email address"
144
- },
145
- ip_address: {
146
- group: "Technical Data",
147
- label: "IP address"
148
- },
149
- device_info: {
150
- group: "Technical Data",
151
- label: "Device type and browser"
152
- },
153
- location: {
154
- group: "Location Data",
155
- label: "Approximate location"
156
- },
157
- payment_info: {
158
- group: "Financial Data",
159
- label: "Payment card details"
160
- },
161
- usage_data: {
162
- group: "Usage Data",
163
- label: "Pages visited and features used"
164
- }
165
- };
166
- initCommand = defineCommand({
167
- meta: {
168
- name: "init",
169
- description: "Interactively create a policy config file"
170
- },
171
- args: {
172
- out: {
173
- type: "string",
174
- description: "Output path for generated config",
175
- default: ""
176
- },
177
- yes: {
178
- type: "boolean",
179
- description: "Skip prompts and use defaults (CI mode)",
180
- default: false
181
- },
182
- type: {
183
- type: "string",
184
- description: "Policy type: \"privacy\" or \"terms\"",
185
- default: "privacy"
186
- }
187
- },
188
- async run({ args }) {
189
- const policyType = args.type === "terms" ? "terms" : "privacy";
190
- const defaultOut = policyType === "terms" ? "./terms.config.ts" : "./privacy.config.ts";
191
- consola.start(`OpenPolicy init wizard (${policyType})`);
192
- const companyName = String(await consola.prompt("Company name?", {
193
- type: "text",
194
- cancel: "reject"
195
- }));
196
- const legalName = String(await consola.prompt("Legal entity name?", {
197
- type: "text",
198
- cancel: "reject",
199
- initial: companyName
200
- }));
201
- const address = String(await consola.prompt("Company address?", {
202
- type: "text",
203
- cancel: "reject"
204
- }));
205
- const contact = String(await consola.prompt(policyType === "terms" ? "Legal contact email?" : "Privacy contact email?", {
206
- type: "text",
207
- cancel: "reject"
208
- }));
209
- let source;
210
- if (policyType === "terms") source = renderTermsConfig({
211
- companyName,
212
- legalName,
213
- address,
214
- contact,
215
- jurisdiction: String(await consola.prompt("Governing law jurisdiction? (e.g. Delaware, USA)", {
216
- type: "text",
217
- cancel: "reject",
218
- initial: "Delaware, USA"
219
- }))
220
- });
221
- else {
222
- const jurisdictionChoice = String(await consola.prompt("Jurisdiction?", {
223
- type: "select",
224
- cancel: "reject",
225
- options: [
226
- "gdpr",
227
- "ccpa",
228
- "both"
229
- ]
230
- }));
231
- const dataCategories = await consola.prompt("Data categories collected?", {
232
- type: "multiselect",
233
- cancel: "reject",
234
- options: [
235
- "name",
236
- "email",
237
- "ip_address",
238
- "device_info",
239
- "location",
240
- "payment_info",
241
- "usage_data"
242
- ]
243
- });
244
- const hasCookies = Boolean(await consola.prompt("Does your app use cookies?", {
245
- type: "confirm",
246
- cancel: "reject",
247
- initial: true
248
- }));
249
- const jurisdictions = toJurisdictions(jurisdictionChoice);
250
- const dataCollected = toDataCollected(dataCategories);
251
- const userRights = toUserRights(jurisdictions);
252
- source = renderPrivacyConfig({
253
- companyName,
254
- legalName,
255
- address,
256
- contact,
257
- jurisdictions,
258
- dataCollected,
259
- legalBasis: jurisdictions.includes("eu") ? "Legitimate interests and consent" : "",
260
- hasCookies,
261
- userRights
262
- });
263
- }
264
- const outPath = resolve(args.out || defaultOut);
265
- await Bun.write(outPath, source);
266
- consola.success(`Config written to ${outPath}`);
267
- }
268
- });
269
- }));
270
- //#endregion
271
- //#region src/utils/detect-type.ts
272
- function detectType(explicitType, configPath) {
273
- if (explicitType === "privacy" || explicitType === "terms" || explicitType === "cookie") return explicitType;
274
- const lower = configPath.toLowerCase();
275
- if (lower.includes("cookie")) return "cookie";
276
- if (lower.includes("terms")) return "terms";
277
- return "privacy";
278
- }
279
- var init_detect_type = __esmMin((() => {}));
280
- //#endregion
281
- //#region src/utils/load-config.ts
282
- async function loadConfig(configPath, bustCache = false) {
283
- const absPath = resolve(configPath);
284
- if (!existsSync(absPath)) {
285
- consola.error(`Config file not found: ${absPath}`);
286
- process.exit(1);
287
- }
288
- const importPath = bustCache ? `${absPath}?t=${Date.now()}` : absPath;
289
- let mod;
290
- try {
291
- mod = await import(importPath);
292
- } catch (err) {
293
- consola.error(`Failed to load config: ${absPath}`);
294
- consola.error(err);
295
- process.exit(1);
296
- }
297
- const config = mod["default"] ?? mod["module.exports"] ?? mod;
298
- if (config === null || config === void 0 || typeof config !== "object") {
299
- consola.error(`Config must export a non-null object: ${absPath}`);
300
- process.exit(1);
301
- }
302
- return config;
303
- }
304
- var init_load_config = __esmMin((() => {}));
305
- //#endregion
306
- //#region src/commands/generate.ts
307
- var generate_exports = /* @__PURE__ */ __exportAll({ generateCommand: () => generateCommand });
308
- function toPolicyInput(policyType, config) {
309
- if (policyType === "terms") return {
310
- type: "terms",
311
- ...config
312
- };
313
- if (policyType === "cookie") return {
314
- type: "cookie",
315
- ...config
316
- };
317
- return {
318
- type: "privacy",
319
- ...config
320
- };
321
- }
322
- async function generateFromConfig(configPath, formats, outDir, explicitType, bustCache = false) {
323
- if (!existsSync(configPath)) return false;
324
- const config = await loadConfig(configPath, bustCache);
325
- if (isOpenPolicyConfig(config)) {
326
- const inputs = expandOpenPolicyConfig(config);
327
- if (inputs.length === 0) {
328
- consola.warn(`Unified config has no privacy or terms sections: ${configPath}`);
329
- return true;
330
- }
331
- await mkdir(outDir, { recursive: true });
332
- for (const input of inputs) {
333
- const outputFilename = input.type === "terms" ? "terms-of-service" : input.type === "cookie" ? "cookie-policy" : "privacy-policy";
334
- consola.start(`Generating ${input.type} policy from ${configPath} → formats: ${formats.join(", ")}`);
335
- const results = compilePolicy(input, { formats });
336
- for (const result of results) {
337
- const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
338
- await writeFile(outPath, result.content, "utf-8");
339
- consola.success(`Written: ${outPath}`);
340
- }
341
- }
342
- return true;
343
- }
344
- const policyType = detectType(explicitType, configPath);
345
- consola.start(`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(", ")}`);
346
- const outputFilename = policyType === "terms" ? "terms-of-service" : policyType === "cookie" ? "cookie-policy" : "privacy-policy";
347
- const results = compilePolicy(toPolicyInput(policyType, config), { formats });
348
- await mkdir(outDir, { recursive: true });
349
- for (const result of results) {
350
- const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
351
- await writeFile(outPath, result.content, "utf-8");
352
- consola.success(`Written: ${outPath}`);
353
- }
354
- return true;
355
- }
356
- var generateCommand;
357
- var init_generate = __esmMin((() => {
358
- init_detect_type();
359
- init_load_config();
360
- generateCommand = defineCommand({
361
- meta: {
362
- name: "generate",
363
- description: "Compile a policy config to one or more output formats"
364
- },
365
- args: {
366
- config: {
367
- type: "positional",
368
- description: "Path(s) to policy config file(s), comma-separated",
369
- default: "./openpolicy.ts,./policy.config.ts,./terms.config.ts"
370
- },
371
- format: {
372
- type: "string",
373
- description: "Comma-separated output formats: markdown,pdf,jsx",
374
- default: "markdown"
375
- },
376
- out: {
377
- type: "string",
378
- description: "Output directory",
379
- default: "./output"
380
- },
381
- type: {
382
- type: "string",
383
- description: "Policy type: \"privacy\", \"terms\", or \"cookie\" (auto-detected from filename if omitted)",
384
- default: ""
385
- },
386
- watch: {
387
- type: "boolean",
388
- description: "Watch config files and regenerate on changes",
389
- default: false
390
- }
391
- },
392
- async run({ args }) {
393
- const formats = args.format.split(",").map((f) => f.trim()).filter(Boolean);
394
- const outDir = args.out;
395
- const explicitType = args.type || void 0;
396
- const configPaths = args.config.split(",").map((p) => p.trim()).filter(Boolean);
397
- const hasMultipleConfigs = configPaths.length > 1;
398
- const watchablePaths = [];
399
- for (const configPath of configPaths) if (await generateFromConfig(configPath, formats, outDir, explicitType)) watchablePaths.push(configPath);
400
- else if (hasMultipleConfigs) consola.warn(`Config not found, skipping: ${configPath}`);
401
- else throw new Error(`Config not found: ${configPath}`);
402
- consola.success(`Policy generation complete → ${outDir}`);
403
- if (args.watch && watchablePaths.length > 0) {
404
- consola.info("Watching for changes...");
405
- for (const configPath of watchablePaths) {
406
- let debounceTimer = null;
407
- watch(configPath, () => {
408
- if (debounceTimer) clearTimeout(debounceTimer);
409
- debounceTimer = setTimeout(async () => {
410
- try {
411
- await generateFromConfig(configPath, formats, outDir, explicitType, true);
412
- } catch (err) {
413
- consola.error(`Error regenerating ${configPath}:`, err);
414
- }
415
- }, 100);
416
- });
417
- }
418
- }
419
- }
420
- });
421
- }));
422
- //#endregion
423
- //#region src/commands/validate.ts
424
- var validate_exports = /* @__PURE__ */ __exportAll({ validateCommand: () => validateCommand });
425
- var validateCommand;
426
- var init_validate = __esmMin((() => {
427
- init_detect_type();
428
- init_load_config();
429
- validateCommand = defineCommand({
430
- meta: {
431
- name: "validate",
432
- description: "Validate a policy config for compliance"
433
- },
434
- args: {
435
- config: {
436
- type: "positional",
437
- description: "Path to policy config file",
438
- default: "./policy.config.ts"
439
- },
440
- jurisdiction: {
441
- type: "string",
442
- description: "Jurisdiction to validate against: gdpr, ccpa, or all",
443
- default: "all"
444
- },
445
- type: {
446
- type: "string",
447
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
448
- default: ""
449
- }
450
- },
451
- async run({ args }) {
452
- const configPath = args.config ?? "./policy.config.ts";
453
- const policyType = detectType(args.type || void 0, configPath);
454
- consola.start(`Validating ${policyType} policy: ${configPath}`);
455
- const config = await loadConfig(configPath);
456
- const issues = policyType === "terms" ? validateTermsOfService(config) : validatePrivacyPolicy(config);
457
- if (issues.length === 0) {
458
- consola.success("Config is valid — no issues found.");
459
- return;
460
- }
461
- for (const issue of issues) if (issue.level === "error") consola.error(issue.message);
462
- else consola.warn(issue.message);
463
- const errors = issues.filter((i) => i.level === "error");
464
- if (errors.length > 0) {
465
- consola.fail(`Validation failed with ${errors.length} error(s).`);
466
- process.exit(1);
467
- }
468
- consola.success("Validation passed with warnings.");
469
- }
470
- });
471
- }));
472
- //#endregion
473
- //#region src/cli.ts
474
- runMain(defineCommand({
475
- meta: {
476
- name: "openpolicy",
477
- version,
478
- description: "Generate and validate privacy policy documents"
479
- },
480
- subCommands: {
481
- init: () => Promise.resolve().then(() => (init_init(), init_exports)).then((m) => m.initCommand),
482
- generate: () => Promise.resolve().then(() => (init_generate(), generate_exports)).then((m) => m.generateCommand),
483
- validate: () => Promise.resolve().then(() => (init_validate(), validate_exports)).then((m) => m.validateCommand)
484
- }
485
- }));
486
- //#endregion
487
- export {};
1
+ #!/usr/bin/env bun
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@openpolicy/cli",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "description": "CLI for generating and validating OpenPolicy privacy policy documents",
6
- "license": "MIT",
6
+ "license": "GPL-3.0-only",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/jamiedavenport/openpolicy",
@@ -14,7 +14,12 @@
14
14
  "README.md"
15
15
  ],
16
16
  "bin": {
17
- "openpolicy": "./dist/cli.js"
17
+ "openpolicy": "./src/cli.ts"
18
+ },
19
+ "publishConfig": {
20
+ "bin": {
21
+ "openpolicy": "./dist/cli.js"
22
+ }
18
23
  },
19
24
  "scripts": {
20
25
  "dev": "rolldown -c --watch",
@@ -28,6 +33,7 @@
28
33
  },
29
34
  "devDependencies": {
30
35
  "@openpolicy/core": "workspace:*",
36
+ "@openpolicy/renderers": "workspace:*",
31
37
  "@openpolicy/tooling": "workspace:*"
32
38
  }
33
39
  }
package/src/cli.ts ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bun
2
+ import { runMain } from "citty";
3
+ import { mainCommand } from "./index";
4
+
5
+ runMain(mainCommand);
@@ -1,49 +0,0 @@
1
- import { n as detectType, t as loadConfig } from "./_cli-BjVuFgXe.js";
2
- import { defineCommand } from "citty";
3
- import { validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
4
- import consola from "consola";
5
- //#region src/commands/validate.ts
6
- const validateCommand = defineCommand({
7
- meta: {
8
- name: "validate",
9
- description: "Validate a policy config for compliance"
10
- },
11
- args: {
12
- config: {
13
- type: "positional",
14
- description: "Path to policy config file",
15
- default: "./policy.config.ts"
16
- },
17
- jurisdiction: {
18
- type: "string",
19
- description: "Jurisdiction to validate against: gdpr, ccpa, or all",
20
- default: "all"
21
- },
22
- type: {
23
- type: "string",
24
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
25
- default: ""
26
- }
27
- },
28
- async run({ args }) {
29
- const configPath = args.config ?? "./policy.config.ts";
30
- const policyType = detectType(args.type || void 0, configPath);
31
- consola.start(`Validating ${policyType} policy: ${configPath}`);
32
- const config = await loadConfig(configPath);
33
- const issues = policyType === "terms" ? validateTermsOfService(config) : validatePrivacyPolicy(config);
34
- if (issues.length === 0) {
35
- consola.success("Config is valid — no issues found.");
36
- return;
37
- }
38
- for (const issue of issues) if (issue.level === "error") consola.error(issue.message);
39
- else consola.warn(issue.message);
40
- const errors = issues.filter((i) => i.level === "error");
41
- if (errors.length > 0) {
42
- consola.fail(`Validation failed with ${errors.length} error(s).`);
43
- process.exit(1);
44
- }
45
- consola.success("Validation passed with warnings.");
46
- }
47
- });
48
- //#endregion
49
- export { validateCommand };
@@ -1,33 +0,0 @@
1
- import { resolve } from "node:path";
2
- import consola from "consola";
3
- import { existsSync } from "node:fs";
4
- //#region src/utils/detect-type.ts
5
- function detectType(explicitType, configPath) {
6
- if (explicitType === "privacy" || explicitType === "terms") return explicitType;
7
- return configPath.toLowerCase().includes("terms") ? "terms" : "privacy";
8
- }
9
- //#endregion
10
- //#region src/utils/load-config.ts
11
- async function loadConfig(configPath) {
12
- const absPath = resolve(configPath);
13
- if (!existsSync(absPath)) {
14
- consola.error(`Config file not found: ${absPath}`);
15
- process.exit(1);
16
- }
17
- let mod;
18
- try {
19
- mod = await import(absPath);
20
- } catch (err) {
21
- consola.error(`Failed to load config: ${absPath}`);
22
- consola.error(err);
23
- process.exit(1);
24
- }
25
- const config = mod["default"] ?? mod["module.exports"] ?? mod;
26
- if (config === null || config === void 0 || typeof config !== "object") {
27
- consola.error(`Config must export a non-null object: ${absPath}`);
28
- process.exit(1);
29
- }
30
- return config;
31
- }
32
- //#endregion
33
- export { detectType as n, loadConfig as t };
@@ -1,58 +0,0 @@
1
- import { n as detectType, t as loadConfig } from "./_cli-BjVuFgXe.js";
2
- import { defineCommand } from "citty";
3
- import { join } from "node:path";
4
- import { compilePolicy } from "@openpolicy/core";
5
- import consola from "consola";
6
- //#region src/commands/generate.ts
7
- const generateCommand = defineCommand({
8
- meta: {
9
- name: "generate",
10
- description: "Compile a policy config to one or more output formats"
11
- },
12
- args: {
13
- config: {
14
- type: "positional",
15
- description: "Path to policy config file",
16
- default: "./policy.config.ts"
17
- },
18
- format: {
19
- type: "string",
20
- description: "Comma-separated output formats: markdown,pdf,jsx",
21
- default: "markdown"
22
- },
23
- out: {
24
- type: "string",
25
- description: "Output directory",
26
- default: "./output"
27
- },
28
- type: {
29
- type: "string",
30
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
31
- default: ""
32
- }
33
- },
34
- async run({ args }) {
35
- const formats = (args.format ?? "markdown").split(",").map((f) => f.trim()).filter(Boolean);
36
- const outDir = args.out ?? "./output";
37
- const configPath = args.config ?? "./policy.config.ts";
38
- const policyType = detectType(args.type || void 0, configPath);
39
- consola.start(`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(", ")}`);
40
- const config = await loadConfig(configPath);
41
- const outputFilename = policyType === "terms" ? "terms-of-service" : "privacy-policy";
42
- const results = compilePolicy(policyType === "terms" ? {
43
- type: "terms",
44
- ...config
45
- } : {
46
- type: "privacy",
47
- ...config
48
- }, { formats });
49
- for (const result of results) {
50
- const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
51
- await Bun.write(outPath, result.content);
52
- consola.success(`Written: ${outPath}`);
53
- }
54
- consola.success(`Policy generation complete → ${outDir}`);
55
- }
56
- });
57
- //#endregion
58
- export { generateCommand };