@openpolicy/cli 0.0.10 → 0.0.11

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 (3) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +94 -39
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -41,6 +41,7 @@ openpolicy generate ./terms.config.ts --format markdown --out ./public/po
41
41
  | `--format` | `markdown` | Comma-separated output formats: `markdown`, `html` |
42
42
  | `--out` | `./public/policies` | Output directory |
43
43
  | `--type` | auto-detected | Override policy type: `privacy` or `terms` |
44
+ | `--watch` | `false` | Watch config files and regenerate on changes |
44
45
 
45
46
  Policy type is auto-detected from the filename — files containing `"terms"` compile as terms of service.
46
47
 
package/dist/cli.js CHANGED
@@ -2,9 +2,9 @@
2
2
  import { defineCommand, runMain } from "citty";
3
3
  import { join, resolve } from "node:path";
4
4
  import consola from "consola";
5
- import { access, mkdir, writeFile } from "node:fs/promises";
6
- import { compilePolicy, validatePrivacyPolicy, validateTermsOfService } from "@openpolicy/core";
7
- import { existsSync } from "node:fs";
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
8
  //#region \0rolldown/runtime.js
9
9
  var __defProp = Object.defineProperty;
10
10
  var __esmMin = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -18,6 +18,9 @@ var __exportAll = (all, no_symbols) => {
18
18
  return target;
19
19
  };
20
20
  //#endregion
21
+ //#region package.json
22
+ var version = "0.0.11";
23
+ //#endregion
21
24
  //#region src/commands/init.ts
22
25
  var init_exports = /* @__PURE__ */ __exportAll({ initCommand: () => initCommand });
23
26
  function toJurisdictions(choice) {
@@ -267,21 +270,25 @@ var init_init = __esmMin((() => {
267
270
  //#endregion
268
271
  //#region src/utils/detect-type.ts
269
272
  function detectType(explicitType, configPath) {
270
- if (explicitType === "privacy" || explicitType === "terms") return explicitType;
271
- return configPath.toLowerCase().includes("terms") ? "terms" : "privacy";
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";
272
278
  }
273
279
  var init_detect_type = __esmMin((() => {}));
274
280
  //#endregion
275
281
  //#region src/utils/load-config.ts
276
- async function loadConfig(configPath) {
282
+ async function loadConfig(configPath, bustCache = false) {
277
283
  const absPath = resolve(configPath);
278
284
  if (!existsSync(absPath)) {
279
285
  consola.error(`Config file not found: ${absPath}`);
280
286
  process.exit(1);
281
287
  }
288
+ const importPath = bustCache ? `${absPath}?t=${Date.now()}` : absPath;
282
289
  let mod;
283
290
  try {
284
- mod = await import(absPath);
291
+ mod = await import(importPath);
285
292
  } catch (err) {
286
293
  consola.error(`Failed to load config: ${absPath}`);
287
294
  consola.error(err);
@@ -298,6 +305,54 @@ var init_load_config = __esmMin((() => {}));
298
305
  //#endregion
299
306
  //#region src/commands/generate.ts
300
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
+ }
301
356
  var generateCommand;
302
357
  var init_generate = __esmMin((() => {
303
358
  init_detect_type();
@@ -311,7 +366,7 @@ var init_generate = __esmMin((() => {
311
366
  config: {
312
367
  type: "positional",
313
368
  description: "Path(s) to policy config file(s), comma-separated",
314
- default: "./policy.config.ts,./terms.config.ts"
369
+ default: "./openpolicy.ts,./policy.config.ts,./terms.config.ts"
315
370
  },
316
371
  format: {
317
372
  type: "string",
@@ -325,42 +380,42 @@ var init_generate = __esmMin((() => {
325
380
  },
326
381
  type: {
327
382
  type: "string",
328
- description: "Policy type: \"privacy\" or \"terms\" (auto-detected from filename if omitted)",
383
+ description: "Policy type: \"privacy\", \"terms\", or \"cookie\" (auto-detected from filename if omitted)",
329
384
  default: ""
385
+ },
386
+ watch: {
387
+ type: "boolean",
388
+ description: "Watch config files and regenerate on changes",
389
+ default: false
330
390
  }
331
391
  },
332
392
  async run({ args }) {
333
- const formats = (args.format ?? "markdown").split(",").map((f) => f.trim()).filter(Boolean);
334
- const outDir = args.out ?? "./output";
335
- const configPaths = (args.config ?? "./policy.config.ts,./terms.config.ts").split(",").map((p) => p.trim()).filter(Boolean);
336
- const isMulti = configPaths.length > 1;
337
- for (const configPath of configPaths) {
338
- if (!await access(configPath).then(() => true).catch(() => false)) {
339
- if (isMulti) {
340
- consola.warn(`Config not found, skipping: ${configPath}`);
341
- continue;
342
- }
343
- throw new Error(`Config not found: ${configPath}`);
344
- }
345
- const policyType = detectType(args.type || void 0, configPath);
346
- consola.start(`Generating ${policyType} policy from ${configPath} → formats: ${formats.join(", ")}`);
347
- const config = await loadConfig(configPath);
348
- const outputFilename = policyType === "terms" ? "terms-of-service" : "privacy-policy";
349
- const results = compilePolicy(policyType === "terms" ? {
350
- type: "terms",
351
- ...config
352
- } : {
353
- type: "privacy",
354
- ...config
355
- }, { formats });
356
- await mkdir(outDir, { recursive: true });
357
- for (const result of results) {
358
- const outPath = join(outDir, `${outputFilename}.${result.format === "markdown" ? "md" : result.format}`);
359
- await writeFile(outPath, result.content, "utf-8");
360
- consola.success(`Written: ${outPath}`);
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
+ });
361
417
  }
362
418
  }
363
- consola.success(`Policy generation complete → ${outDir}`);
364
419
  }
365
420
  });
366
421
  }));
@@ -419,7 +474,7 @@ var init_validate = __esmMin((() => {
419
474
  runMain(defineCommand({
420
475
  meta: {
421
476
  name: "openpolicy",
422
- version: "0.0.1",
477
+ version,
423
478
  description: "Generate and validate privacy policy documents"
424
479
  },
425
480
  subCommands: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpolicy/cli",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "type": "module",
5
5
  "description": "CLI for generating and validating OpenPolicy privacy policy documents",
6
6
  "license": "MIT",