Skip to content

Commit

Permalink
refactor: stringify values before using encodeDisallowedCharacters
Browse files Browse the repository at this point in the history
  • Loading branch information
glowcloud committed Apr 4, 2024
1 parent e80049d commit a560dd3
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 37 deletions.
62 changes: 27 additions & 35 deletions src/execute/oas3/style-serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ export function encodeDisallowedCharacters(str, { escape } = {}, parse) {
str = str.toString();
}

if (str !== null && typeof str === 'object' && !Array.isArray(str)) {
str = JSON.stringify(str);
}

if (typeof str !== 'string' || !str.length) {
return str;
}
Expand Down Expand Up @@ -60,23 +56,29 @@ export default function stylize(config) {
return encodePrimitive(config);
}

function encodeArray({ key, value, style, explode, escape }) {
const valueEncoder = (str) =>
encodeDisallowedCharacters(str, {
escape,
});
function valueEncoder(value, escape) {
if (value !== null && typeof value === 'object') {
value = JSON.stringify(value);
} else if (typeof val === 'number') {
value = value.toString();
}
return encodeDisallowedCharacters(value, {
escape,
});
}

function encodeArray({ key, value, style, explode, escape }) {
if (style === 'simple') {
return value.map((val) => valueEncoder(val)).join(',');
return value.map((val) => valueEncoder(val, escape)).join(',');
}

if (style === 'label') {
return `.${value.map((val) => valueEncoder(val)).join('.')}`;
return `.${value.map((val) => valueEncoder(val, escape)).join('.')}`;
}

if (style === 'matrix') {
return value
.map((val) => valueEncoder(val))
.map((val) => valueEncoder(val, escape))
.reduce((prev, curr) => {
if (!prev || explode) {
return `${prev || ''};${key}=${curr}`;
Expand All @@ -87,33 +89,28 @@ function encodeArray({ key, value, style, explode, escape }) {

if (style === 'form') {
const after = explode ? `&${key}=` : ',';
return value.map((val) => valueEncoder(val)).join(after);
return value.map((val) => valueEncoder(val, escape)).join(after);
}

if (style === 'spaceDelimited') {
const after = explode ? `${key}=` : '';
return value.map((val) => valueEncoder(val)).join(` ${after}`);
return value.map((val) => valueEncoder(val, escape)).join(` ${after}`);
}

if (style === 'pipeDelimited') {
const after = explode ? `${key}=` : '';
return value.map((val) => valueEncoder(val)).join(`|${after}`);
return value.map((val) => valueEncoder(val, escape)).join(`|${after}`);
}

return undefined;
}

function encodeObject({ key, value, style, explode, escape }) {
const valueEncoder = (str) =>
encodeDisallowedCharacters(str, {
escape,
});

const valueKeys = Object.keys(value);

if (style === 'simple') {
return valueKeys.reduce((prev, curr) => {
const val = valueEncoder(value[curr]);
const val = valueEncoder(value[curr], escape);
const middleChar = explode ? '=' : ',';
const prefix = prev ? `${prev},` : '';

Expand All @@ -123,7 +120,7 @@ function encodeObject({ key, value, style, explode, escape }) {

if (style === 'label') {
return valueKeys.reduce((prev, curr) => {
const val = valueEncoder(value[curr]);
const val = valueEncoder(value[curr], escape);
const middleChar = explode ? '=' : '.';
const prefix = prev ? `${prev}.` : '.';

Expand All @@ -133,7 +130,7 @@ function encodeObject({ key, value, style, explode, escape }) {

if (style === 'matrix' && explode) {
return valueKeys.reduce((prev, curr) => {
const val = valueEncoder(value[curr]);
const val = valueEncoder(value[curr], escape);
const prefix = prev ? `${prev};` : ';';

return `${prefix}${curr}=${val}`;
Expand All @@ -143,7 +140,7 @@ function encodeObject({ key, value, style, explode, escape }) {
if (style === 'matrix') {
// no explode
return valueKeys.reduce((prev, curr) => {
const val = valueEncoder(value[curr]);
const val = valueEncoder(value[curr], escape);
const prefix = prev ? `${prev},` : `;${key}=`;

return `${prefix}${curr},${val}`;
Expand All @@ -152,7 +149,7 @@ function encodeObject({ key, value, style, explode, escape }) {

if (style === 'form') {
return valueKeys.reduce((prev, curr) => {
const val = valueEncoder(value[curr]);
const val = valueEncoder(value[curr], escape);
const prefix = prev ? `${prev}${explode ? '&' : ','}` : '';
const separator = explode ? '=' : ',';

Expand All @@ -164,29 +161,24 @@ function encodeObject({ key, value, style, explode, escape }) {
}

function encodePrimitive({ key, value, style, escape }) {
const valueEncoder = (str) =>
encodeDisallowedCharacters(str, {
escape,
});

if (style === 'simple') {
return valueEncoder(value);
return valueEncoder(value, escape);
}

if (style === 'label') {
return `.${valueEncoder(value)}`;
return `.${valueEncoder(value, escape)}`;
}

if (style === 'matrix') {
return `;${key}=${valueEncoder(value)}`;
return `;${key}=${valueEncoder(value, escape)}`;
}

if (style === 'form') {
return valueEncoder(value);
return valueEncoder(value, escape);
}

if (style === 'deepObject') {
return valueEncoder(value, {}, true);
return valueEncoder(value, escape);
}

return undefined;
Expand Down
15 changes: 13 additions & 2 deletions src/http/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,19 @@ function formatKeyValueBySerializationOption(key, value, skipEncoding, serializa
: serializationOption && serializationOption.allowReserved
? 'unsafe'
: 'reserved';
const encodeFn = (v) => encodeDisallowedCharacters(v, { escape });
const encodeKeyFn = skipEncoding ? (k) => k : (k) => encodeDisallowedCharacters(k, { escape });

const encodeFn = (v) => {
if (v !== null && typeof v === 'object') {
v = JSON.stringify(v);
} else if (typeof val === 'number') {
v = v.toString();
}
return encodeDisallowedCharacters(v, {
escape,
});
};

const encodeKeyFn = skipEncoding ? (k) => k : (k) => encodeFn(k);

// Primitive
if (typeof value !== 'object') {
Expand Down
127 changes: 127 additions & 0 deletions test/oas3/execute/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,133 @@ describe('buildRequest - OpenAPI Specification 3.0', () => {
},
});
});

it('should encode arrays of arrays and objects', () => {
const req = buildRequest({
spec: {
openapi: '3.0.0',
paths: {
'/': {
post: {
operationId: 'myOp',
parameters: [
{
name: 'arrayOfObjects',
in: 'query',
schema: {
type: 'array',
items: {
type: 'object',
},
},
explode: false,
},
{
name: 'arrayOfArrays',
in: 'query',
schema: {
type: 'array',
items: {
type: 'array',
items: {
type: 'object',
},
},
},
explode: false,
},
{
name: 'headerArrayOfObjects',
in: 'header',
schema: {
type: 'array',
items: {
type: 'object',
},
},
},
{
name: 'headerArrayOfArrays',
in: 'header',
schema: {
type: 'array',
items: {
type: 'array',
items: {
type: 'object',
},
},
},
},
],
},
},
},
},
operationId: 'myOp',
parameters: {
arrayOfObjects: [
{
a: {
b: 'c',
},
},
{
d: {
e: 'f',
},
},
],
arrayOfArrays: [
[
{
a: {
b: 'c',
},
},
],
],
headerArrayOfObjects: [
{
a: {
b: 'c',
},
},
{
d: {
e: 'f',
},
},
],
headerArrayOfArrays: [
[
{
a: {
b: 'c',
},
},
],
[
{
d: {
e: 'f',
},
},
],
],
},
});

expect(req).toEqual({
method: 'POST',
url: `/?arrayOfObjects=${escape('{"a":{"b":"c"}}')},${escape('{"d":{"e":"f"}}')}&arrayOfArrays=${escape('[{"a":{"b":"c"}}]')}`,
credentials: 'same-origin',
headers: {
headerArrayOfObjects: '{"a":{"b":"c"}},{"d":{"e":"f"}}',
headerArrayOfArrays: '[{"a":{"b":"c"}}],[{"d":{"e":"f"}}]',
},
});
});
});

describe('`content` parameters', () => {
Expand Down

0 comments on commit a560dd3

Please sign in to comment.