mirror of
https://github.com/graphql-hive/console
synced 2026-04-21 14:37:17 +00:00
fix(cli): handle escaped single-quoted strings in schema change (#7321)
This commit is contained in:
parent
594b176b74
commit
316859ebcb
6 changed files with 109 additions and 4 deletions
5
.changeset/brave-tigers-dance.md
Normal file
5
.changeset/brave-tigers-dance.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@graphql-hive/cli': patch
|
||||
---
|
||||
|
||||
handle escaped single-quoted strings in schema changes
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
type Query {
|
||||
status: Status
|
||||
}
|
||||
|
||||
enum Status {
|
||||
ACTIVE
|
||||
INACTIVE @deprecated(reason: "Use 'DISABLED' instead, it's clearer")
|
||||
PENDING
|
||||
DISABLED
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
type Query {
|
||||
status: Status
|
||||
}
|
||||
|
||||
enum Status {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
PENDING
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/* eslint-disable no-process-env */
|
||||
import { createHash } from 'node:crypto';
|
||||
import stripAnsi from 'strip-ansi';
|
||||
import { ProjectType, RuleInstanceSeverityLevel } from 'testkit/gql/graphql';
|
||||
import * as GraphQLSchema from 'testkit/gql/graphql';
|
||||
import type { CompositeSchema } from '@hive/api/__generated__/types';
|
||||
|
|
@ -974,3 +975,33 @@ test.concurrent(
|
|||
).rejects.toThrow('Failed to auto-approve: Schema check has schema policy errors');
|
||||
},
|
||||
);
|
||||
|
||||
test.concurrent(
|
||||
'schema:check displays enum deprecation reason with single quotes correctly',
|
||||
async ({ expect }) => {
|
||||
const { createOrg } = await initSeed().createOwner();
|
||||
const { createProject } = await createOrg();
|
||||
const { createTargetAccessToken } = await createProject(ProjectType.Single);
|
||||
const { secret } = await createTargetAccessToken({});
|
||||
|
||||
await schemaPublish([
|
||||
'--registry.accessToken',
|
||||
secret,
|
||||
'--author',
|
||||
'Test',
|
||||
'--commit',
|
||||
'init',
|
||||
'fixtures/enum-with-deprecation-init.graphql',
|
||||
]);
|
||||
|
||||
const result = await schemaCheck([
|
||||
'--registry.accessToken',
|
||||
secret,
|
||||
'fixtures/enum-with-deprecation-change.graphql',
|
||||
]);
|
||||
|
||||
expect(stripAnsi(result)).toContain(
|
||||
"Enum value Status.INACTIVE was deprecated with reason Use 'DISABLED' instead, it's clearer",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
46
integration-tests/tests/cli/texture.spec.ts
Normal file
46
integration-tests/tests/cli/texture.spec.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import colors from 'colors';
|
||||
import { boldQuotedWords } from '../../../packages/libraries/cli/src/helpers/texture/texture';
|
||||
|
||||
describe('boldQuotedWords', () => {
|
||||
test('handles simple single-quoted strings', () => {
|
||||
const input = "Changed value for 'foo'";
|
||||
const expected = `Changed value for ${colors.bold('foo')}`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('handles simple double-quoted strings', () => {
|
||||
const input = 'Changed value for "foo"';
|
||||
const expected = `Changed value for ${colors.bold('foo')}`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('handles multiple quoted strings', () => {
|
||||
const input = "Field 'name' on type 'User' was changed";
|
||||
const expected = `Field ${colors.bold('name')} on type ${colors.bold('User')} was changed`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('handles string with no quotes', () => {
|
||||
const input = 'No quotes here';
|
||||
expect(boldQuotedWords(input)).toBe(input);
|
||||
});
|
||||
|
||||
test('handles escaped single quotes within single-quoted strings', () => {
|
||||
const input =
|
||||
"Enum value 'Status.INACTIVE' has deprecation reason 'Use \\'DISABLED\\' instead'";
|
||||
const expected = `Enum value ${colors.bold('Status.INACTIVE')} has deprecation reason ${colors.bold("Use 'DISABLED' instead")}`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('handles escaped double quotes within double-quoted strings', () => {
|
||||
const input = 'Default value changed from "\\"test\\"" to "other"';
|
||||
const expected = `Default value changed from ${colors.bold('"test"')} to ${colors.bold('other')}`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
|
||||
test('handles apostrophes when quotes are escaped', () => {
|
||||
const input = "Reason 'Use \\'DISABLED\\' instead, it\\'s clearer'";
|
||||
const expected = `Reason ${colors.bold("Use 'DISABLED' instead, it's clearer")}`;
|
||||
expect(boldQuotedWords(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
|
@ -21,11 +21,15 @@ export const trimEnd = (value: string) => value.replace(/\s+$/g, '');
|
|||
* Convert quoted text to bolded text. Quotes are stripped.
|
||||
*/
|
||||
export const boldQuotedWords = (value: string) => {
|
||||
const singleQuotedTextRegex = /'([^']+)'/gim;
|
||||
const doubleQuotedTextRegex = /"([^"]+)"/gim;
|
||||
const singleQuotedTextRegex = /'((?:[^'\\]|\\.)+?)'/g;
|
||||
const doubleQuotedTextRegex = /"((?:[^"\\]|\\.)+?)"/g;
|
||||
return value
|
||||
.replace(singleQuotedTextRegex, (_, capturedValue: string) => colors.bold(capturedValue))
|
||||
.replace(doubleQuotedTextRegex, (_, capturedValue: string) => colors.bold(capturedValue));
|
||||
.replace(singleQuotedTextRegex, (_, capturedValue: string) =>
|
||||
colors.bold(capturedValue.replace(/\\'/g, "'")),
|
||||
)
|
||||
.replace(doubleQuotedTextRegex, (_, capturedValue: string) =>
|
||||
colors.bold(capturedValue.replace(/\\"/g, '"')),
|
||||
);
|
||||
};
|
||||
|
||||
export const prefixedInspect =
|
||||
|
|
|
|||
Loading…
Reference in a new issue