Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/reference/path-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Inside `${...}` template substitutions, methods transform the captured value:
| `${name.toCamelCase()}` | `my-thing` → `myThing` |
| `${name.toKebabCase()}` | `MyThing` → `my-thing` |
| `${name.toSnakeCase()}` | `MyThing` → `my_thing` |
| `${name.toConstantCase()}` | `my-thing` → `MY_THING` (uppercase snake case) |
| `${name.toFlatCase()}` | `my-thing` → `mything` |
| `${name.toNthSegment(0)}` | `my-thing` → `my` (split by `-`, return nth segment) |
| `${name.toNthSegmentPascalCase(1)}` | `my-thing` → `Thing` |
Expand Down
3 changes: 2 additions & 1 deletion e2e/fixtures/case-maps-broken/konsistent.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"exportFunctions": [
{ "name": "create${providerId.toPascalCase()}Provider" }
],
"exportTypes": ["${providerId.toPascalCase()}ProviderConfig"]
"exportTypes": ["${providerId.toPascalCase()}ProviderConfig"],
"exportConstants": ["${providerId.toConstantCase()}_PROVIDER_ID"]
}
}
]
Expand Down
3 changes: 2 additions & 1 deletion e2e/fixtures/case-maps/konsistent.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"exportFunctions": [
{ "name": "create${providerId.toPascalCase()}Provider" }
],
"exportTypes": ["${providerId.toPascalCase()}ProviderConfig"]
"exportTypes": ["${providerId.toPascalCase()}ProviderConfig"],
"exportConstants": ["${providerId.toConstantCase()}_PROVIDER_ID"]
}
}
]
Expand Down
2 changes: 2 additions & 0 deletions e2e/fixtures/case-maps/providers/graphql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export type GraphQLProviderConfig = {
endpoint: string;
};

export const GRAPHQL_PROVIDER_ID = "graphql";

export function createGraphQLProvider(config: GraphQLProviderConfig): unknown {
return config;
}
2 changes: 2 additions & 0 deletions e2e/fixtures/case-maps/providers/openai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export type OpenAIProviderConfig = {
apiKey: string;
};

export const OPENAI_PROVIDER_ID = "openai";

export function createOpenAIProvider(config: OpenAIProviderConfig): unknown {
return config;
}
3 changes: 3 additions & 0 deletions e2e/placeholder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1049,6 +1049,9 @@ describe("case-maps-broken fixture", () => {
expect(error.stdout).toContain(
'Missing export type "OpenAIProviderConfig"'
);
expect(error.stdout).toContain(
'Missing export constant "OPENAI_PROVIDER_ID"'
);
}
});
});
Expand Down
15 changes: 15 additions & 0 deletions packages/konsistent/src/core/case-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
splitWords,
toCamelCase,
toConstantCase,
toKebabCase,
toPascalCase,
toSnakeCase,
Expand Down Expand Up @@ -76,3 +77,17 @@ describe("toSnakeCase", () => {
expect(toSnakeCase("testUtils")).toBe("test_utils");
});
});

describe("toConstantCase", () => {
it("converts hyphenated", () => {
expect(toConstantCase("test-utils")).toBe("TEST_UTILS");
});

it("converts snake_case", () => {
expect(toConstantCase("test_utils")).toBe("TEST_UTILS");
});

it("converts camelCase", () => {
expect(toConstantCase("testUtils")).toBe("TEST_UTILS");
});
});
6 changes: 6 additions & 0 deletions packages/konsistent/src/core/case-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ export function toSnakeCase(value: string): string {
.map((w) => w.toLowerCase())
.join("_");
}

export function toConstantCase(value: string): string {
return splitWords(value)
.map((w) => w.toUpperCase())
.join("_");
}
53 changes: 53 additions & 0 deletions packages/konsistent/src/core/placeholder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,59 @@ describe("PlaceholderValue", () => {
});
});

describe("toConstantCase", () => {
it("uppercases single word", () => {
expect(new PlaceholderValue({ value: "Openai" }).toConstantCase()).toBe(
"OPENAI"
);
});

it("converts hyphens", () => {
expect(
new PlaceholderValue({ value: "test-utils" }).toConstantCase()
).toBe("TEST_UTILS");
});

it("converts snake_case", () => {
expect(
new PlaceholderValue({ value: "test_utils" }).toConstantCase()
).toBe("TEST_UTILS");
});

it("converts camelCase", () => {
expect(
new PlaceholderValue({ value: "testUtils" }).toConstantCase()
).toBe("TEST_UTILS");
});

it("uses pascalToKebabMap when entry exists", () => {
expect(
new PlaceholderValue({
value: "GraphQL",
pascalToKebabMap: { GraphQL: "graphql" },
}).toConstantCase()
).toBe("GRAPHQL");
});

it("uses camelToKebabMap when entry exists", () => {
expect(
new PlaceholderValue({
value: "graphQL",
camelToKebabMap: { graphQL: "graphql" },
}).toConstantCase()
).toBe("GRAPHQL");
});

it("converts hyphens in mapped value to underscores", () => {
expect(
new PlaceholderValue({
value: "GraphQL",
pascalToKebabMap: { GraphQL: "graph-ql" },
}).toConstantCase()
).toBe("GRAPH_QL");
});
});

describe("extract", () => {
it("returns first capture group when regex has subgroups", () => {
expect(
Expand Down
13 changes: 13 additions & 0 deletions packages/konsistent/src/core/placeholder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
toCamelCase,
toConstantCase,
toKebabCase,
toPascalCase,
toSnakeCase,
Expand Down Expand Up @@ -76,6 +77,18 @@ export class PlaceholderValue {
return toSnakeCase(this.raw);
}

/**
* Transform the value to CONSTANT_CASE, also known as uppercase snake case.
*/
toConstantCase(): string {
const mapped =
this.pascalToKebabMap?.[this.raw] ?? this.camelToKebabMap?.[this.raw];
if (mapped) {
return mapped.replace(/-/g, "_").toUpperCase();
}
return toConstantCase(this.raw);
}

toFlatCase(): string {
return this.raw.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
Expand Down
8 changes: 8 additions & 0 deletions packages/konsistent/src/core/template.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,14 @@ describe("resolveTemplate", () => {
expect(result).toBe("test_utils_config.ts");
});

it("resolves ${name.toConstantCase()}", () => {
const result = resolveTemplate({
template: "${name.toConstantCase()}_CONFIG.ts",
placeholders: makePlaceholders({ map: { name: "test-utils" } }),
});
expect(result).toBe("TEST_UTILS_CONFIG.ts");
});

it("resolves ${name.toFlatCase()}", () => {
const result = resolveTemplate({
template: "${name.toFlatCase()}-config.ts",
Expand Down
2 changes: 2 additions & 0 deletions packages/konsistent/src/core/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export function resolveTemplate(opts: {
return placeholder.toKebabCase();
case "toSnakeCase":
return placeholder.toSnakeCase();
case "toConstantCase":
return placeholder.toConstantCase();
case "toFlatCase":
return placeholder.toFlatCase();
case "toNthSegment":
Expand Down