@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.
- package/README.md +1 -0
- package/dist/cli.js +94 -39
- 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 {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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
|
-
|
|
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(
|
|
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 \"
|
|
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 =
|
|
334
|
-
const outDir = args.out
|
|
335
|
-
const
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
|
477
|
+
version,
|
|
423
478
|
description: "Generate and validate privacy policy documents"
|
|
424
479
|
},
|
|
425
480
|
subCommands: {
|