Skip to content

Commit 8f6f83b

Browse files
- use node 24
- add yaml parser for cli - add support for domain-availability checking
1 parent 3ae90d0 commit 8f6f83b

12 files changed

Lines changed: 1770 additions & 61 deletions

File tree

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,8 @@ yarn-error.*
6464
# vites
6565
coverage
6666

67-
js/coverage
67+
js/coverage
68+
69+
# results outputs
70+
./**/domain-results.*
71+
js/domain-results.*

.pnp.cjs

Lines changed: 569 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import { describe, it, expect, vi, beforeEach } from "vitest";
2+
import fs from "node:fs";
3+
import {
4+
readNamesFromInputs,
5+
readTldsFromInputs,
6+
readYamlConfig,
7+
inferAvailability,
8+
summarizeParsed,
9+
} from "../commands/domain-availability-checker/domain-availability-checker";
10+
11+
// Mock only readFileSync
12+
const mockReadFileSync = vi.fn();
13+
vi.spyOn(fs, "readFileSync").mockImplementation(mockReadFileSync);
14+
15+
describe("Domain Availability Checker", () => {
16+
beforeEach(() => {
17+
vi.clearAllMocks();
18+
});
19+
20+
describe("readYamlConfig", () => {
21+
it("should parse valid YAML config", () => {
22+
const yamlContent = `
23+
names:
24+
- test1
25+
- test2
26+
tlds:
27+
- com
28+
- dev
29+
`;
30+
mockReadFileSync.mockReturnValue(yamlContent);
31+
32+
const result = readYamlConfig("test.yaml");
33+
34+
expect(result).toEqual({
35+
names: ["test1", "test2"],
36+
tlds: ["com", "dev"],
37+
});
38+
});
39+
40+
it("should return null for invalid YAML", () => {
41+
mockReadFileSync.mockImplementation(() => {
42+
throw new Error("Invalid YAML");
43+
});
44+
45+
const result = readYamlConfig("test.yaml");
46+
47+
expect(result).toBeNull();
48+
});
49+
50+
it("should return null for empty file", () => {
51+
mockReadFileSync.mockReturnValue("");
52+
53+
const result = readYamlConfig("test.yaml");
54+
55+
expect(result).toBeNull();
56+
});
57+
});
58+
59+
describe("readNamesFromInputs", () => {
60+
it("should read names from array", () => {
61+
const result = readNamesFromInputs(["test1", "test2"]);
62+
63+
expect(result).toEqual(["test1", "test2"]);
64+
});
65+
66+
it("should read names from YAML file", () => {
67+
const yamlContent = "names:\n - yamlname1\n - yamlname2";
68+
mockReadFileSync.mockReturnValue(yamlContent);
69+
70+
const result = readNamesFromInputs(undefined, "test.yaml");
71+
72+
expect(result).toEqual(["yamlname1", "yamlname2"]);
73+
});
74+
75+
it("should read names from plain text file when YAML fails", () => {
76+
mockReadFileSync.mockReturnValue("name1\nname2\n\nname3");
77+
78+
const result = readNamesFromInputs(undefined, "test.txt");
79+
80+
expect(result).toEqual(["name1", "name2", "name3"]);
81+
});
82+
83+
it("should combine array and file names", () => {
84+
const yamlContent = "names:\n - file1\n - file2";
85+
mockReadFileSync.mockReturnValue(yamlContent);
86+
87+
const result = readNamesFromInputs(["arg1", "arg2"], "test.yaml");
88+
89+
expect(result).toEqual(["arg1", "arg2", "file1", "file2"]);
90+
});
91+
92+
it("should deduplicate names", () => {
93+
const result = readNamesFromInputs(["test", "test", "other"]);
94+
95+
expect(result).toEqual(["test", "other"]);
96+
});
97+
98+
it("should trim and lowercase names", () => {
99+
const result = readNamesFromInputs([" TEST ", " Other "]);
100+
101+
expect(result).toEqual(["test", "other"]);
102+
});
103+
});
104+
105+
describe("readTldsFromInputs", () => {
106+
it("should read TLDs from array", () => {
107+
const result = readTldsFromInputs(["com", "dev"]);
108+
109+
expect(result).toEqual(["com", "dev"]);
110+
});
111+
112+
it("should read TLDs from YAML file", () => {
113+
const yamlContent = "tlds:\n - com\n - dev";
114+
mockReadFileSync.mockReturnValue(yamlContent);
115+
116+
const result = readTldsFromInputs(["net"], "test.yaml");
117+
118+
expect(result).toEqual(["net", "com", "dev"]);
119+
});
120+
121+
it("should remove dots and lowercase TLDs", () => {
122+
const result = readTldsFromInputs([".COM", "DEV"]);
123+
124+
expect(result).toEqual(["com", "dev"]);
125+
});
126+
127+
it("should deduplicate TLDs", () => {
128+
const result = readTldsFromInputs(["com", "com", "dev"]);
129+
130+
expect(result).toEqual(["com", "dev"]);
131+
});
132+
});
133+
134+
describe("inferAvailability", () => {
135+
it("should return likely-available for empty/null results", () => {
136+
expect(inferAvailability(null)).toBe("likely-available");
137+
expect(inferAvailability({})).toBe("likely-available");
138+
});
139+
140+
it("should return registered for domains with domain name", () => {
141+
const result = inferAvailability({
142+
"Domain Name": "example.com",
143+
registrar: "Test Registrar",
144+
});
145+
146+
expect(result).toBe("registered");
147+
});
148+
149+
it("should return likely-available for 'not found' phrases", () => {
150+
expect(inferAvailability({}, "No match for domain")).toBe("likely-available");
151+
expect(inferAvailability({}, "Domain not found")).toBe("likely-available");
152+
expect(inferAvailability({}, "Available")).toBe("likely-available");
153+
});
154+
155+
it("should return registered for registrar indicators", () => {
156+
const result = inferAvailability({
157+
registrar: "Test Registrar",
158+
"Creation Date": "2020-01-01",
159+
});
160+
161+
expect(result).toBe("registered");
162+
});
163+
164+
it("should return unknown for unrecognized results", () => {
165+
const result = inferAvailability({
166+
someField: "someValue",
167+
});
168+
169+
expect(result).toBe("unknown");
170+
});
171+
});
172+
173+
describe("summarizeParsed", () => {
174+
it("should return empty string for null/undefined", () => {
175+
expect(summarizeParsed(null)).toBe("");
176+
expect(summarizeParsed(undefined)).toBe("");
177+
});
178+
179+
it("should summarize WHOIS data", () => {
180+
const parsed = {
181+
domainName: "example.com",
182+
registrar: "Test Registrar",
183+
creationDate: "2020-01-01T00:00:00.000Z",
184+
status: "active",
185+
};
186+
187+
const result = summarizeParsed(parsed);
188+
189+
expect(result).toContain("domainName:example.com");
190+
expect(result).toContain("registrar:Test Registrar");
191+
expect(result).toContain("creationDate:2020-01-01T00:00:00.000Z");
192+
expect(result).toContain("status:active");
193+
});
194+
195+
it("should handle multiple domain name fields", () => {
196+
const parsed = {
197+
"Domain Name": "EXAMPLE.COM",
198+
domainName: "example.com",
199+
};
200+
201+
const result = summarizeParsed(parsed);
202+
203+
expect(result).toContain("domainName:example.com");
204+
expect(result).toContain("Domain Name:EXAMPLE.COM");
205+
});
206+
207+
it("should truncate long values", () => {
208+
const longValue = "a".repeat(100);
209+
const parsed = {
210+
domainName: longValue,
211+
};
212+
213+
const result = summarizeParsed(parsed);
214+
215+
expect(result.length).toBeLessThan(100);
216+
expect(result).toContain("...");
217+
});
218+
});
219+
});

js/cli.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { execSync } from "child_process";
33
import { Command } from "commander";
44
import { auditAutoApprove } from "./commands/copilot/audit-auto-approve.ts";
5+
import { makeCheckDomainsCommand } from "./commands/domain-availability-checker/domain-availability-checker.ts";
56

67
const packageJson = await import("./package.json", {
78
with: { type: "json" },
@@ -21,6 +22,8 @@ const copilot = program
2122
.command("copilot")
2223
.description("GitHub Copilot helpers");
2324

25+
program.addCommand(makeCheckDomainsCommand());
26+
2427
// Subcommand: copilot audit-auto-approve
2528
copilot
2629
.command("audit-auto-approve")

0 commit comments

Comments
 (0)