Skip to content

Commit a0fd0af

Browse files
authored
fix: new function quoteKey for object keys with special characters (#485)
- Introduced new utility function `quoteKey` to handle object keys with special characters in JSON utilities. - Enhanced `stringifyTypeAST` to utilize `quoteKey` for key quoting, ensuring proper formatting in output. - Added unit tests for `quoteKey` and updated existing tests to cover new functionality. - Bumped the CLI version in package.json from 1.0.2 to 1.0.3. - Modified test scripts for improved functionality: - Changed "test" to run vitest directly. - Added "test:watch" for continuous testing. - Updated "test:ci" to streamline CI testing with reporters.
1 parent 4f209fd commit a0fd0af

File tree

4 files changed

+58
-12
lines changed

4 files changed

+58
-12
lines changed

packages/cli/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@reflag/cli",
3-
"version": "1.0.2",
3+
"version": "1.0.3",
44
"packageManager": "[email protected]",
55
"description": "CLI for Reflag service",
66
"main": "./dist/index.js",
@@ -31,8 +31,9 @@
3131
"scripts": {
3232
"build": "tsc && shx chmod +x dist/index.js",
3333
"reflag": "yarn build && ./dist/index.js",
34-
"test": "vitest -c vite.config.js",
35-
"test:ci": "vitest run -c vite.config.js --reporter=default --reporter=junit --outputFile=junit.xml",
34+
"test": "vitest run",
35+
"test:watch": "vitest",
36+
"test:ci": "yarn test --reporter=default --reporter=junit --outputFile=junit.xml",
3637
"coverage": "vitest run --coverage",
3738
"lint": "eslint .",
3839
"lint:ci": "eslint --output-file eslint-report.json --format json .",

packages/cli/test/json.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest";
33
import {
44
JSONToType,
55
mergeTypeASTs,
6+
quoteKey,
67
stringifyTypeAST,
78
toTypeAST,
89
TypeAST,
@@ -300,6 +301,37 @@ describe("JSON utilities", () => {
300301
expect(stringifyTypeAST({ kind: "object", properties: [] })).toBe("{}");
301302
});
302303

304+
it("should quote object keys with special characters", () => {
305+
const ast: TypeAST = {
306+
kind: "object",
307+
properties: [
308+
{
309+
key: "my-key",
310+
type: { kind: "primitive", type: "string" },
311+
optional: false,
312+
},
313+
{
314+
key: "my key",
315+
type: { kind: "primitive", type: "string" },
316+
optional: false,
317+
},
318+
{
319+
key: "my.key",
320+
type: { kind: "primitive", type: "string" },
321+
optional: false,
322+
},
323+
{
324+
key: "123key",
325+
type: { kind: "primitive", type: "string" },
326+
optional: false,
327+
},
328+
],
329+
};
330+
331+
const expected = `{\n "my-key": string,\n "my key": string,\n "my.key": string,\n "123key": string\n}`;
332+
expect(stringifyTypeAST(ast)).toBe(expected);
333+
});
334+
303335
it("should stringify union types", () => {
304336
const ast: TypeAST = {
305337
kind: "union",
@@ -422,4 +454,14 @@ describe("JSON utilities", () => {
422454
).toBe(expected);
423455
});
424456
});
457+
458+
describe("quoteKey", () => {
459+
it("should quote keys with special characters", () => {
460+
expect(quoteKey("my-key")).toBe('"my-key"');
461+
expect(quoteKey("my key")).toBe('"my key"');
462+
expect(quoteKey("my.key")).toBe('"my.key"');
463+
expect(quoteKey("123key")).toBe('"123key"');
464+
expect(quoteKey("key")).toBe("key");
465+
});
466+
});
425467
});

packages/cli/utils/gen.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { dirname, isAbsolute, join } from "node:path";
44

55
import { Flag, RemoteConfig } from "../services/flags.js";
66

7-
import { JSONToType } from "./json.js";
7+
import { JSONToType, quoteKey } from "./json.js";
88

99
export type GenFormat = "react" | "node";
1010

@@ -118,7 +118,7 @@ ${flags
118118
.map(({ key }) => {
119119
const config = configDefs.get(key);
120120
return indentLines(
121-
`"${key}": ${config?.definition ? `{ config: { payload: ${config.name} } }` : "boolean"};`,
121+
`${quoteKey(key)}: ${config?.definition ? `{ config: { payload: ${config.name} } }` : "boolean"};`,
122122
4,
123123
);
124124
})

packages/cli/utils/json.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,12 @@ export function stringifyTypeAST(ast: TypeAST, nestLevel = 0): string {
179179
if (ast.properties.length === 0) return "{}";
180180

181181
return `{\n${ast.properties
182-
.map(
183-
({ key, optional, type }) =>
184-
`${nextIndent}${key}${optional ? "?" : ""}: ${stringifyTypeAST(
185-
type,
186-
nestLevel + 1,
187-
)}`,
188-
)
182+
.map(({ key, optional, type }) => {
183+
return `${nextIndent}${quoteKey(key)}${optional ? "?" : ""}: ${stringifyTypeAST(
184+
type,
185+
nestLevel + 1,
186+
)}`;
187+
})
189188
.join(",\n")}\n${indent}}`;
190189

191190
case "union":
@@ -198,6 +197,10 @@ export function stringifyTypeAST(ast: TypeAST, nestLevel = 0): string {
198197
}
199198
}
200199

200+
export function quoteKey(key: string): string {
201+
return /[^a-zA-Z0-9_]/.test(key) || /^[0-9]/.test(key) ? `"${key}"` : key;
202+
}
203+
201204
// Convert JSON array to TypeScript type
202205
export function JSONToType(json: JSONPrimitive[]): string | null {
203206
if (!json.length) return null;

0 commit comments

Comments
 (0)