readyup 0.0.0 → 0.13.0

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 (91) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +123 -0
  3. package/bin/rdy.js +11 -0
  4. package/dist/esm/.cache +1 -0
  5. package/dist/esm/assertIsPreflightCollection.d.ts +2 -0
  6. package/dist/esm/assertIsPreflightCollection.js +27 -0
  7. package/dist/esm/assertIsRdyKit.d.ts +2 -0
  8. package/dist/esm/assertIsRdyKit.js +27 -0
  9. package/dist/esm/authoring.d.ts +6 -0
  10. package/dist/esm/authoring.js +22 -0
  11. package/dist/esm/bin/preflight.d.ts +1 -0
  12. package/dist/esm/bin/preflight.js +12 -0
  13. package/dist/esm/bin/rdy.d.ts +1 -0
  14. package/dist/esm/bin/rdy.js +12 -0
  15. package/dist/esm/bin/route.d.ts +1 -0
  16. package/dist/esm/bin/route.js +202 -0
  17. package/dist/esm/check-utils/filesystem.d.ts +4 -0
  18. package/dist/esm/check-utils/filesystem.js +26 -0
  19. package/dist/esm/check-utils/index.d.ts +3 -0
  20. package/dist/esm/check-utils/index.js +14 -0
  21. package/dist/esm/check-utils/package-json.d.ts +6 -0
  22. package/dist/esm/check-utils/package-json.js +40 -0
  23. package/dist/esm/check-utils/semver.d.ts +1 -0
  24. package/dist/esm/check-utils/semver.js +12 -0
  25. package/dist/esm/cli.d.ts +36 -0
  26. package/dist/esm/cli.js +285 -0
  27. package/dist/esm/compile/compileCommand.d.ts +1 -0
  28. package/dist/esm/compile/compileCommand.js +121 -0
  29. package/dist/esm/compile/compileConfig.d.ts +5 -0
  30. package/dist/esm/compile/compileConfig.js +52 -0
  31. package/dist/esm/compile/validateCompiledOutput.d.ts +1 -0
  32. package/dist/esm/compile/validateCompiledOutput.js +29 -0
  33. package/dist/esm/config.d.ts +2 -0
  34. package/dist/esm/config.js +28 -0
  35. package/dist/esm/expandGitHubShorthand.d.ts +1 -0
  36. package/dist/esm/expandGitHubShorthand.js +26 -0
  37. package/dist/esm/formatCombinedSummary.d.ts +2 -0
  38. package/dist/esm/formatCombinedSummary.js +40 -0
  39. package/dist/esm/formatJsonError.d.ts +1 -0
  40. package/dist/esm/formatJsonError.js +6 -0
  41. package/dist/esm/formatJsonReport.d.ts +10 -0
  42. package/dist/esm/formatJsonReport.js +90 -0
  43. package/dist/esm/index.d.ts +4 -0
  44. package/dist/esm/index.js +37 -0
  45. package/dist/esm/init/initCommand.d.ts +6 -0
  46. package/dist/esm/init/initCommand.js +33 -0
  47. package/dist/esm/init/scaffold.d.ts +11 -0
  48. package/dist/esm/init/scaffold.js +15 -0
  49. package/dist/esm/init/templates.d.ts +2 -0
  50. package/dist/esm/init/templates.js +37 -0
  51. package/dist/esm/isRecord.d.ts +1 -0
  52. package/dist/esm/isRecord.js +6 -0
  53. package/dist/esm/jitiImport.d.ts +1 -0
  54. package/dist/esm/jitiImport.js +23 -0
  55. package/dist/esm/loadConfig.d.ts +2 -0
  56. package/dist/esm/loadConfig.js +74 -0
  57. package/dist/esm/loadRemoteCollection.d.ts +6 -0
  58. package/dist/esm/loadRemoteCollection.js +40 -0
  59. package/dist/esm/loadRemoteKit.d.ts +6 -0
  60. package/dist/esm/loadRemoteKit.js +40 -0
  61. package/dist/esm/parseArgs.d.ts +15 -0
  62. package/dist/esm/parseArgs.js +93 -0
  63. package/dist/esm/reportPreflight.d.ts +7 -0
  64. package/dist/esm/reportPreflight.js +105 -0
  65. package/dist/esm/reportRdy.d.ts +7 -0
  66. package/dist/esm/reportRdy.js +105 -0
  67. package/dist/esm/resolveCollectionExports.d.ts +1 -0
  68. package/dist/esm/resolveCollectionExports.js +20 -0
  69. package/dist/esm/resolveGitHubToken.d.ts +1 -0
  70. package/dist/esm/resolveGitHubToken.js +22 -0
  71. package/dist/esm/resolveKitExports.d.ts +1 -0
  72. package/dist/esm/resolveKitExports.js +20 -0
  73. package/dist/esm/resolveRequestedNames.d.ts +2 -0
  74. package/dist/esm/resolveRequestedNames.js +38 -0
  75. package/dist/esm/runPreflight.d.ts +7 -0
  76. package/dist/esm/runPreflight.js +157 -0
  77. package/dist/esm/runRdy.d.ts +7 -0
  78. package/dist/esm/runRdy.js +157 -0
  79. package/dist/esm/terminal.d.ts +6 -0
  80. package/dist/esm/terminal.js +55 -0
  81. package/dist/esm/types.d.ts +139 -0
  82. package/dist/esm/types.js +10 -0
  83. package/dist/esm/validateCollection.d.ts +2 -0
  84. package/dist/esm/validateCollection.js +27 -0
  85. package/dist/esm/validateKit.d.ts +2 -0
  86. package/dist/esm/validateKit.js +27 -0
  87. package/dist/esm/version.d.ts +1 -0
  88. package/dist/esm/version.js +4 -0
  89. package/dist/esm/writeFileWithCheck.d.ts +10 -0
  90. package/dist/esm/writeFileWithCheck.js +41 -0
  91. package/package.json +56 -10
@@ -0,0 +1,90 @@
1
+ import { meetsThreshold } from "./runRdy.js";
2
+ function formatJsonReport(entries, options) {
3
+ const reportOn = options?.reportOn ?? "recommend";
4
+ let totalPassed = 0;
5
+ let totalFailed = 0;
6
+ let totalSkipped = 0;
7
+ const checklists = entries.map(({ name, report }) => {
8
+ let passed = 0;
9
+ let failed = 0;
10
+ let skipped = 0;
11
+ const visibleResults = report.results.filter((r) => meetsThreshold(r.severity, reportOn));
12
+ for (const result of visibleResults) {
13
+ if (result.status === "passed") passed++;
14
+ else if (result.status === "failed") failed++;
15
+ else skipped++;
16
+ }
17
+ const { entries: checks } = buildCheckEntries(visibleResults, 0, 0);
18
+ totalPassed += passed;
19
+ totalFailed += failed;
20
+ totalSkipped += skipped;
21
+ return {
22
+ name,
23
+ allPassed: report.passed,
24
+ durationMs: report.durationMs,
25
+ passed,
26
+ failed,
27
+ skipped,
28
+ checks
29
+ };
30
+ });
31
+ const totalDurationMs = checklists.reduce((sum, c) => sum + c.durationMs, 0);
32
+ const output = {
33
+ allPassed: entries.every(({ report }) => report.passed),
34
+ passed: totalPassed,
35
+ failed: totalFailed,
36
+ skipped: totalSkipped,
37
+ durationMs: totalDurationMs,
38
+ checklists
39
+ };
40
+ return JSON.stringify(output);
41
+ }
42
+ function buildCheckEntries(results, startIndex, expectedDepth) {
43
+ const entries = [];
44
+ let index = startIndex;
45
+ while (index < results.length) {
46
+ const result = results[index];
47
+ if (result === void 0) break;
48
+ const depth = result.depth;
49
+ if (depth < expectedDepth) break;
50
+ index++;
51
+ const { entries: children, nextIndex } = buildCheckEntries(results, index, depth + 1);
52
+ index = nextIndex;
53
+ entries.push(buildCheckEntry(result, children));
54
+ }
55
+ return { entries, nextIndex: index };
56
+ }
57
+ function buildCheckEntry(result, children = []) {
58
+ const errorString = result.error !== null ? result.error.message : null;
59
+ if (result.status === "skipped") {
60
+ return {
61
+ name: result.name,
62
+ status: result.status,
63
+ ok: result.ok,
64
+ severity: result.severity,
65
+ skipReason: result.skipReason,
66
+ detail: result.detail,
67
+ fix: result.fix,
68
+ error: errorString,
69
+ progress: result.progress,
70
+ durationMs: result.durationMs,
71
+ checks: children
72
+ };
73
+ }
74
+ return {
75
+ name: result.name,
76
+ status: result.status,
77
+ ok: result.ok,
78
+ severity: result.severity,
79
+ skipReason: null,
80
+ detail: result.detail,
81
+ fix: result.fix,
82
+ error: errorString,
83
+ progress: result.progress,
84
+ durationMs: result.durationMs,
85
+ checks: children
86
+ };
87
+ }
88
+ export {
89
+ formatJsonReport
90
+ };
@@ -0,0 +1,4 @@
1
+ export type { ChecklistSummary, CheckOutcome, CheckReturnValue, FailedResult, FixLocation, FractionProgress, JsonCheckEntry, JsonChecklistEntry, JsonReport, PassedResult, PercentProgress, Progress, RdyCheck, RdyChecklist, RdyConfig, RdyKit, RdyReport, RdyResult, RdyStagedChecklist, ResolvedRdyConfig, Severity, SkippedResult, SkipResult, } from './types.ts';
2
+ export { isFlatChecklist, isPercentProgress } from './types.ts';
3
+ export { defineChecklists, defineRdyChecklist, defineRdyConfig, defineRdyKit, defineRdyStagedChecklist, } from './authoring.ts';
4
+ export { compareVersions, fileContains, fileDoesNotContain, fileExists, hasDevDependency, hasMinDevDependencyVersion, hasPackageJsonField, readFile, readPackageJson, } from './check-utils/index.ts';
@@ -0,0 +1,37 @@
1
+ import { isFlatChecklist, isPercentProgress } from "./types.js";
2
+ import {
3
+ defineChecklists,
4
+ defineRdyChecklist,
5
+ defineRdyConfig,
6
+ defineRdyKit,
7
+ defineRdyStagedChecklist
8
+ } from "./authoring.js";
9
+ import {
10
+ compareVersions,
11
+ fileContains,
12
+ fileDoesNotContain,
13
+ fileExists,
14
+ hasDevDependency,
15
+ hasMinDevDependencyVersion,
16
+ hasPackageJsonField,
17
+ readFile,
18
+ readPackageJson
19
+ } from "./check-utils/index.js";
20
+ export {
21
+ compareVersions,
22
+ defineChecklists,
23
+ defineRdyChecklist,
24
+ defineRdyConfig,
25
+ defineRdyKit,
26
+ defineRdyStagedChecklist,
27
+ fileContains,
28
+ fileDoesNotContain,
29
+ fileExists,
30
+ hasDevDependency,
31
+ hasMinDevDependencyVersion,
32
+ hasPackageJsonField,
33
+ isFlatChecklist,
34
+ isPercentProgress,
35
+ readFile,
36
+ readPackageJson
37
+ };
@@ -0,0 +1,6 @@
1
+ interface InitOptions {
2
+ dryRun: boolean;
3
+ force: boolean;
4
+ }
5
+ export declare function initCommand({ dryRun, force }: InitOptions): number;
6
+ export {};
@@ -0,0 +1,33 @@
1
+ import { printError, printStep, reportWriteResult } from "../terminal.js";
2
+ import { scaffoldConfig } from "./scaffold.js";
3
+ function initCommand({ dryRun, force }) {
4
+ if (dryRun) {
5
+ console.info("[dry-run mode]");
6
+ }
7
+ printStep("Scaffolding config");
8
+ let result;
9
+ try {
10
+ result = scaffoldConfig({ dryRun, force });
11
+ } catch (error) {
12
+ printError(`Failed to scaffold config: ${error instanceof Error ? error.message : String(error)}`);
13
+ return 1;
14
+ }
15
+ reportWriteResult(result.configResult, dryRun);
16
+ reportWriteResult(result.kitResult, dryRun);
17
+ if (result.configResult.outcome === "failed" || result.kitResult.outcome === "failed") {
18
+ return 1;
19
+ }
20
+ if (!dryRun) {
21
+ printStep("Next steps");
22
+ console.info(`
23
+ 1. Customize .config/rdy.config.ts with your compile settings.
24
+ 2. Add checklists to .rdy/kits/.
25
+ 3. Test by running: npx readyup run
26
+ 4. Commit the generated files.
27
+ `);
28
+ }
29
+ return 0;
30
+ }
31
+ export {
32
+ initCommand
33
+ };
@@ -0,0 +1,11 @@
1
+ import type { WriteResult } from '../writeFileWithCheck.ts';
2
+ interface ScaffoldOptions {
3
+ dryRun: boolean;
4
+ force: boolean;
5
+ }
6
+ interface ScaffoldResult {
7
+ configResult: WriteResult;
8
+ kitResult: WriteResult;
9
+ }
10
+ export declare function scaffoldConfig({ dryRun, force }: ScaffoldOptions): ScaffoldResult;
11
+ export {};
@@ -0,0 +1,15 @@
1
+ import { writeFileWithCheck } from "../writeFileWithCheck.js";
2
+ import { rdyConfigTemplate, rdyKitTemplate } from "./templates.js";
3
+ const CONFIG_PATH = ".config/rdy.config.ts";
4
+ const KIT_PATH = ".rdy/kits/default.ts";
5
+ function scaffoldConfig({ dryRun, force }) {
6
+ const configResult = writeFileWithCheck(CONFIG_PATH, rdyConfigTemplate, { dryRun, overwrite: force });
7
+ const kitResult = writeFileWithCheck(KIT_PATH, rdyKitTemplate, {
8
+ dryRun,
9
+ overwrite: force
10
+ });
11
+ return { configResult, kitResult };
12
+ }
13
+ export {
14
+ scaffoldConfig
15
+ };
@@ -0,0 +1,2 @@
1
+ export declare const rdyConfigTemplate = "import { defineRdyConfig } from 'readyup';\n\n/** Repo-level readyup settings. */\nexport default defineRdyConfig({\n compile: {\n srcDir: '.rdy/kits',\n outDir: '.rdy/kits',\n },\n});\n";
2
+ export declare const rdyKitTemplate = "import { defineRdyKit } from 'readyup';\n\n/**\n * Default rdy kit.\n *\n * Each checklist contains checks that run before a deployment or other operation.\n * Checks run concurrently within a checklist. Use `fix` to provide remediation hints.\n */\nexport default defineRdyKit({\n checklists: [\n {\n name: 'deploy',\n checks: [\n {\n name: 'environment variables set',\n check: () => Boolean(process.env['NODE_ENV']),\n fix: 'Set NODE_ENV before deploying',\n },\n ],\n },\n ],\n});\n";
@@ -0,0 +1,37 @@
1
+ const rdyConfigTemplate = `import { defineRdyConfig } from 'readyup';
2
+
3
+ /** Repo-level readyup settings. */
4
+ export default defineRdyConfig({
5
+ compile: {
6
+ srcDir: '.rdy/kits',
7
+ outDir: '.rdy/kits',
8
+ },
9
+ });
10
+ `;
11
+ const rdyKitTemplate = `import { defineRdyKit } from 'readyup';
12
+
13
+ /**
14
+ * Default rdy kit.
15
+ *
16
+ * Each checklist contains checks that run before a deployment or other operation.
17
+ * Checks run concurrently within a checklist. Use \`fix\` to provide remediation hints.
18
+ */
19
+ export default defineRdyKit({
20
+ checklists: [
21
+ {
22
+ name: 'deploy',
23
+ checks: [
24
+ {
25
+ name: 'environment variables set',
26
+ check: () => Boolean(process.env['NODE_ENV']),
27
+ fix: 'Set NODE_ENV before deploying',
28
+ },
29
+ ],
30
+ },
31
+ ],
32
+ });
33
+ `;
34
+ export {
35
+ rdyConfigTemplate,
36
+ rdyKitTemplate
37
+ };
@@ -0,0 +1 @@
1
+ export declare function isRecord(value: unknown): value is Record<string, unknown>;
@@ -0,0 +1,6 @@
1
+ function isRecord(value) {
2
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3
+ }
4
+ export {
5
+ isRecord
6
+ };
@@ -0,0 +1 @@
1
+ export declare function jitiImport(resolvedPath: string, moduleErrorDetail: string, exportNoun: string): Promise<Record<string, unknown>>;
@@ -0,0 +1,23 @@
1
+ import { isRecord } from "./isRecord.js";
2
+ async function jitiImport(resolvedPath, moduleErrorDetail, exportNoun) {
3
+ const { createJiti } = await import("jiti");
4
+ const jiti = createJiti(resolvedPath);
5
+ let imported;
6
+ try {
7
+ imported = await jiti.import(resolvedPath);
8
+ } catch (error) {
9
+ if (error instanceof Error && "code" in error && (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_MODULE_NOT_FOUND")) {
10
+ const moduleMatch = error.message.match(/Cannot find (?:module|package) '([^']+)'/);
11
+ const moduleName = moduleMatch?.[1] ?? "unknown module";
12
+ throw new Error(`Cannot resolve '${moduleName}'. ${moduleErrorDetail}`);
13
+ }
14
+ throw error;
15
+ }
16
+ if (!isRecord(imported)) {
17
+ throw new Error(`${exportNoun} must export an object, got ${Array.isArray(imported) ? "array" : typeof imported}`);
18
+ }
19
+ return imported;
20
+ }
21
+ export {
22
+ jitiImport
23
+ };
@@ -0,0 +1,2 @@
1
+ import type { ResolvedRdyConfig } from './types.ts';
2
+ export declare function loadConfig(overridePath?: string): Promise<ResolvedRdyConfig>;
@@ -0,0 +1,74 @@
1
+ import { existsSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { z } from "zod";
4
+ import { isRecord } from "./isRecord.js";
5
+ import { jitiImport } from "./jitiImport.js";
6
+ const DEFAULT_CONFIG = {
7
+ compile: {
8
+ srcDir: ".rdy/kits",
9
+ outDir: ".rdy/kits",
10
+ include: void 0
11
+ },
12
+ internal: {
13
+ dir: ".",
14
+ extension: ".ts"
15
+ }
16
+ };
17
+ const LOOKUP_PATHS = [".config/rdy.config.ts"];
18
+ const RdyConfigSchema = z.looseObject({
19
+ compile: z.looseObject({
20
+ srcDir: z.string().optional(),
21
+ outDir: z.string().optional(),
22
+ include: z.string().optional()
23
+ }).optional(),
24
+ internal: z.looseObject({
25
+ dir: z.string().optional(),
26
+ extension: z.string().optional()
27
+ }).optional()
28
+ });
29
+ function assertIsRdyConfig(raw) {
30
+ RdyConfigSchema.parse(raw);
31
+ }
32
+ async function loadConfig(overridePath) {
33
+ let resolvedPath;
34
+ if (overridePath !== void 0) {
35
+ resolvedPath = path.resolve(process.cwd(), overridePath);
36
+ if (!existsSync(resolvedPath)) {
37
+ throw new Error(`Config not found: ${resolvedPath}`);
38
+ }
39
+ } else {
40
+ for (const lookupPath of LOOKUP_PATHS) {
41
+ const candidate = path.resolve(process.cwd(), lookupPath);
42
+ if (existsSync(candidate)) {
43
+ resolvedPath = candidate;
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ if (resolvedPath === void 0) {
49
+ return { ...DEFAULT_CONFIG };
50
+ }
51
+ const imported = await jitiImport(
52
+ resolvedPath,
53
+ "External packages imported by the config file must be installed in the project.",
54
+ "Config file"
55
+ );
56
+ const raw = imported.default !== void 0 && isRecord(imported.default) ? imported.default : imported;
57
+ assertIsRdyConfig(raw);
58
+ const compile = isRecord(raw.compile) ? raw.compile : void 0;
59
+ const internal = isRecord(raw.internal) ? raw.internal : void 0;
60
+ return {
61
+ compile: {
62
+ srcDir: typeof compile?.srcDir === "string" ? compile.srcDir : DEFAULT_CONFIG.compile.srcDir,
63
+ outDir: typeof compile?.outDir === "string" ? compile.outDir : DEFAULT_CONFIG.compile.outDir,
64
+ include: typeof compile?.include === "string" ? compile.include : void 0
65
+ },
66
+ internal: {
67
+ dir: typeof internal?.dir === "string" ? internal.dir : DEFAULT_CONFIG.internal.dir,
68
+ extension: typeof internal?.extension === "string" ? internal.extension : DEFAULT_CONFIG.internal.extension
69
+ }
70
+ };
71
+ }
72
+ export {
73
+ loadConfig
74
+ };
@@ -0,0 +1,6 @@
1
+ import type { PreflightCollection } from './types.ts';
2
+ export interface LoadRemoteCollectionOptions {
3
+ url: string;
4
+ token?: string;
5
+ }
6
+ export declare function loadRemoteCollection({ url, token }: LoadRemoteCollectionOptions): Promise<PreflightCollection>;
@@ -0,0 +1,40 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { assertIsPreflightCollection } from "./assertIsPreflightCollection.js";
6
+ import { isRecord } from "./isRecord.js";
7
+ import { resolveCollectionExports } from "./resolveCollectionExports.js";
8
+ import { validateCollection } from "./validateCollection.js";
9
+ async function loadRemoteCollection({ url, token }) {
10
+ const headers = {};
11
+ if (token !== void 0) {
12
+ headers.Authorization = `token ${token}`;
13
+ }
14
+ const response = await fetch(url, { headers });
15
+ if (!response.ok) {
16
+ throw new Error(`Failed to fetch remote collection from ${url}: ${response.status} ${response.statusText}`);
17
+ }
18
+ const body = await response.text();
19
+ const trimmedBody = body.trimStart().toLowerCase();
20
+ if (trimmedBody.startsWith("<html") || trimmedBody.startsWith("<!doctype")) {
21
+ throw new Error(`Remote collection URL returned an HTML page instead of JavaScript: ${url}`);
22
+ }
23
+ const tempDir = mkdtempSync(join(tmpdir(), "preflight-"));
24
+ const tempFile = join(tempDir, "collection.js");
25
+ try {
26
+ writeFileSync(tempFile, body, "utf8");
27
+ const fileUrl = `${pathToFileURL(tempFile).href}?t=${Date.now()}`;
28
+ const imported = await import(fileUrl);
29
+ const moduleRecord = isRecord(imported) ? imported : {};
30
+ const resolved = resolveCollectionExports(moduleRecord);
31
+ assertIsPreflightCollection(resolved);
32
+ validateCollection(resolved);
33
+ return resolved;
34
+ } finally {
35
+ rmSync(tempDir, { recursive: true, force: true });
36
+ }
37
+ }
38
+ export {
39
+ loadRemoteCollection
40
+ };
@@ -0,0 +1,6 @@
1
+ import type { RdyKit } from './types.ts';
2
+ export interface LoadRemoteKitOptions {
3
+ url: string;
4
+ token?: string;
5
+ }
6
+ export declare function loadRemoteKit({ url, token }: LoadRemoteKitOptions): Promise<RdyKit>;
@@ -0,0 +1,40 @@
1
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { assertIsRdyKit } from "./assertIsRdyKit.js";
6
+ import { isRecord } from "./isRecord.js";
7
+ import { resolveKitExports } from "./resolveKitExports.js";
8
+ import { validateKit } from "./validateKit.js";
9
+ async function loadRemoteKit({ url, token }) {
10
+ const headers = {};
11
+ if (token !== void 0) {
12
+ headers.Authorization = `token ${token}`;
13
+ }
14
+ const response = await fetch(url, { headers });
15
+ if (!response.ok) {
16
+ throw new Error(`Failed to fetch remote kit from ${url}: ${response.status} ${response.statusText}`);
17
+ }
18
+ const body = await response.text();
19
+ const trimmedBody = body.trimStart().toLowerCase();
20
+ if (trimmedBody.startsWith("<html") || trimmedBody.startsWith("<!doctype")) {
21
+ throw new Error(`Remote kit URL returned an HTML page instead of JavaScript: ${url}`);
22
+ }
23
+ const tempDir = mkdtempSync(join(tmpdir(), "rdy-"));
24
+ const tempFile = join(tempDir, "kit.js");
25
+ try {
26
+ writeFileSync(tempFile, body, "utf8");
27
+ const fileUrl = `${pathToFileURL(tempFile).href}?t=${Date.now()}`;
28
+ const imported = await import(fileUrl);
29
+ const moduleRecord = isRecord(imported) ? imported : {};
30
+ const resolved = resolveKitExports(moduleRecord);
31
+ assertIsRdyKit(resolved);
32
+ validateKit(resolved);
33
+ return resolved;
34
+ } finally {
35
+ rmSync(tempDir, { recursive: true, force: true });
36
+ }
37
+ }
38
+ export {
39
+ loadRemoteKit
40
+ };
@@ -0,0 +1,15 @@
1
+ export interface FlagDefinition {
2
+ long: string;
3
+ type: 'boolean' | 'string';
4
+ short?: string;
5
+ }
6
+ export type FlagSchema = Record<string, FlagDefinition>;
7
+ export type ParsedFlags<S extends FlagSchema> = {
8
+ [K in keyof S]: S[K]['type'] extends 'boolean' ? boolean : string | undefined;
9
+ };
10
+ export interface ParsedArgs<S extends FlagSchema> {
11
+ flags: ParsedFlags<S>;
12
+ positionals: string[];
13
+ }
14
+ export declare function parseArgs<S extends FlagSchema>(argv: string[], schema: S): ParsedArgs<S>;
15
+ export declare function translateParseError(error: unknown): string;
@@ -0,0 +1,93 @@
1
+ function handleEqualsForm(arg, eqIndex, longToKey, definitions) {
2
+ const longFlag = arg.slice(0, eqIndex);
3
+ const key = longToKey.get(longFlag);
4
+ if (key === void 0) {
5
+ throw new Error(`unknown flag '${longFlag}'`);
6
+ }
7
+ const def = definitions.get(key);
8
+ if (def?.type === "boolean") {
9
+ throw new Error(`flag '${longFlag}' does not accept a value`);
10
+ }
11
+ const value = arg.slice(eqIndex + 1);
12
+ if (value === "") {
13
+ throw new Error(`${longFlag} requires a value`);
14
+ }
15
+ return { key, value };
16
+ }
17
+ function handleBareFlag(arg, index, argv, longToKey, shortToKey, definitions) {
18
+ const key = longToKey.get(arg) ?? shortToKey.get(arg);
19
+ if (key === void 0) {
20
+ throw new Error(`unknown flag '${arg}'`);
21
+ }
22
+ const def = definitions.get(key);
23
+ if (def?.type === "boolean") {
24
+ return { key, value: true, advance: 0 };
25
+ }
26
+ const next = argv[index + 1];
27
+ if (next === void 0 || next.startsWith("-") && next !== "-") {
28
+ throw new Error(`${def?.long} requires a value`);
29
+ }
30
+ return { key, value: next, advance: 1 };
31
+ }
32
+ function buildLookupTables(schema) {
33
+ const longToKey = /* @__PURE__ */ new Map();
34
+ const shortToKey = /* @__PURE__ */ new Map();
35
+ const definitions = /* @__PURE__ */ new Map();
36
+ for (const [key, def] of Object.entries(schema)) {
37
+ longToKey.set(def.long, key);
38
+ definitions.set(key, def);
39
+ if (def.short !== void 0) {
40
+ shortToKey.set(def.short, key);
41
+ }
42
+ }
43
+ return { longToKey, shortToKey, definitions };
44
+ }
45
+ function parseArgsInternal(argv, schema) {
46
+ const { longToKey, shortToKey, definitions } = buildLookupTables(schema);
47
+ const flags = {};
48
+ for (const [key, def] of Object.entries(schema)) {
49
+ flags[key] = def.type === "boolean" ? false : void 0;
50
+ }
51
+ const positionals = [];
52
+ let pastDelimiter = false;
53
+ for (let i = 0; i < argv.length; i++) {
54
+ const arg = argv[i] ?? "";
55
+ if (pastDelimiter) {
56
+ positionals.push(arg);
57
+ continue;
58
+ }
59
+ if (arg === "--") {
60
+ pastDelimiter = true;
61
+ continue;
62
+ }
63
+ const eqIndex = arg.indexOf("=");
64
+ if (eqIndex !== -1 && arg.startsWith("--")) {
65
+ const { key, value } = handleEqualsForm(arg, eqIndex, longToKey, definitions);
66
+ flags[key] = value;
67
+ continue;
68
+ }
69
+ if (arg.startsWith("-") && arg !== "-") {
70
+ const { key, value, advance } = handleBareFlag(arg, i, argv, longToKey, shortToKey, definitions);
71
+ flags[key] = value;
72
+ i += advance;
73
+ continue;
74
+ }
75
+ positionals.push(arg);
76
+ }
77
+ return { flags, positionals };
78
+ }
79
+ function parseArgs(argv, schema) {
80
+ return parseArgsInternal(argv, schema);
81
+ }
82
+ function translateParseError(error) {
83
+ const message = error instanceof Error ? error.message : String(error);
84
+ const flagMatch = message.match(/^unknown flag '(.+)'$/);
85
+ if (flagMatch?.[1] !== void 0) {
86
+ return `Unknown option: ${flagMatch[1]}`;
87
+ }
88
+ return message;
89
+ }
90
+ export {
91
+ parseArgs,
92
+ translateParseError
93
+ };
@@ -0,0 +1,7 @@
1
+ import type { FixLocation, PreflightReport, Severity } from './types.ts';
2
+ export interface ReportPreflightOptions {
3
+ fixLocation?: FixLocation;
4
+ reportOn?: Severity;
5
+ }
6
+ export declare function formatSummaryCounts(passed: number, failed: number, skipped: number): string;
7
+ export declare function reportPreflight(report: PreflightReport, options?: ReportPreflightOptions): string;