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
7 changes: 7 additions & 0 deletions .changeset/happy-weeks-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@smithy/shared-ini-file-loader": patch
"@smithy/util-endpoints": patch
"@smithy/util-stream": patch
---

remove and ban circular imports
4 changes: 4 additions & 0 deletions packages/shared-ini-file-loader/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* @internal
*/
export const CONFIG_PREFIX_SEPARATOR = ".";
2 changes: 1 addition & 1 deletion packages/shared-ini-file-loader/src/getConfigData.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ParsedIniData } from "@smithy/types";
import { IniSectionType } from "@smithy/types";

import { CONFIG_PREFIX_SEPARATOR } from "./loadSharedConfigFiles";
import { CONFIG_PREFIX_SEPARATOR } from "./constants";

/**
* Returns the config data from parsed ini data.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ export interface SharedConfigInit {

const swallowError = () => ({});

/**
* @internal
*/
export const CONFIG_PREFIX_SEPARATOR = ".";
export { CONFIG_PREFIX_SEPARATOR } from "./constants";

/**
* Loads the config and credentials files.
Expand Down
2 changes: 1 addition & 1 deletion packages/shared-ini-file-loader/src/parseIni.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { ParsedIniData } from "@smithy/types";
import { IniSectionType } from "@smithy/types";

import { CONFIG_PREFIX_SEPARATOR } from "./loadSharedConfigFiles";
import { CONFIG_PREFIX_SEPARATOR } from "./constants";

const prefixKeyRegex = /^([\w-]+)\s(["'])?([\w-@\+\.%:/]+)\2$/;
const profileNameBlockList = ["__proto__", "profile __proto__"];
Expand Down
8 changes: 4 additions & 4 deletions packages/util-endpoints/src/utils/callFunction.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest";

import { callFunction } from "./callFunction";
import { customEndpointFunctions } from "./customEndpointFunctions";
import { endpointFunctions } from "./endpointFunctions";
import { evaluateExpression } from "./evaluateExpression";

vi.mock("./evaluateExpression");
import { callFunction, group } from "./evaluateExpression";

describe(callFunction.name, () => {
vi.spyOn(group, "evaluateExpression").mockImplementation(vi.fn());
const { evaluateExpression } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
19 changes: 2 additions & 17 deletions packages/util-endpoints/src/utils/callFunction.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,2 @@
import type { EvaluateOptions, Expression, FunctionObject, FunctionReturn } from "../types";
import { customEndpointFunctions } from "./customEndpointFunctions";
import { endpointFunctions } from "./endpointFunctions";
import { evaluateExpression } from "./evaluateExpression";

export const callFunction = ({ fn, argv }: FunctionObject, options: EvaluateOptions): FunctionReturn => {
const evaluatedArgs = argv.map((arg) =>
["boolean", "number"].includes(typeof arg) ? arg : evaluateExpression(arg as Expression, "arg", options)
);
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
// @ts-ignore Element implicitly has an 'any' type
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
}
// @ts-ignore Element implicitly has an 'any' type
return endpointFunctions[fn](...evaluatedArgs);
};
// breaks circular import
export { callFunction } from "./evaluateExpression";
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { afterEach, describe, expect, test as it, vi } from "vitest";

import { EndpointError } from "../types";
import { callFunction } from "./callFunction";
import { evaluateExpression } from "./evaluateExpression";
import { evaluateExpression, group } from "./evaluateExpression";
import { evaluateTemplate } from "./evaluateTemplate";
import { getReferenceValue } from "./getReferenceValue";

vi.mock("./callFunction");
vi.mock("./getReferenceValue");
vi.mock("./evaluateTemplate");

describe(evaluateExpression.name, () => {
vi.spyOn(group, "callFunction").mockImplementation(vi.fn());
const { callFunction } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
25 changes: 22 additions & 3 deletions packages/util-endpoints/src/utils/evaluateExpression.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import type { EvaluateOptions, Expression, FunctionObject, ReferenceObject } from "../types";
import type { EvaluateOptions, Expression, FunctionObject, FunctionReturn, ReferenceObject } from "../types";
import { EndpointError } from "../types";
import { callFunction } from "./callFunction";
import { customEndpointFunctions } from "./customEndpointFunctions";
import { endpointFunctions } from "./endpointFunctions";
import { evaluateTemplate } from "./evaluateTemplate";
import { getReferenceValue } from "./getReferenceValue";

export const evaluateExpression = (obj: Expression, keyName: string, options: EvaluateOptions) => {
if (typeof obj === "string") {
return evaluateTemplate(obj, options);
} else if ((obj as FunctionObject)["fn"]) {
return callFunction(obj as FunctionObject, options);
return group.callFunction(obj as FunctionObject, options);
} else if ((obj as ReferenceObject)["ref"]) {
return getReferenceValue(obj as ReferenceObject, options);
}
throw new EndpointError(`'${keyName}': ${String(obj)} is not a string, function or reference.`);
};

export const callFunction = ({ fn, argv }: FunctionObject, options: EvaluateOptions): FunctionReturn => {
const evaluatedArgs = argv.map((arg) =>
["boolean", "number"].includes(typeof arg) ? arg : group.evaluateExpression(arg as Expression, "arg", options)
);
const fnSegments = fn.split(".");
if (fnSegments[0] in customEndpointFunctions && fnSegments[1] != null) {
// @ts-ignore Element implicitly has an 'any' type
return customEndpointFunctions[fnSegments[0]][fnSegments[1]](...evaluatedArgs);
}
// @ts-ignore Element implicitly has an 'any' type
return endpointFunctions[fn](...evaluatedArgs);
};

export const group = {
evaluateExpression,
callFunction,
};
6 changes: 4 additions & 2 deletions packages/util-endpoints/src/utils/evaluateRules.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import type { EndpointRuleObject, ErrorRuleObject, TreeRuleObject } from "../typ
import { EndpointError } from "../types";
import { evaluateEndpointRule } from "./evaluateEndpointRule";
import { evaluateErrorRule } from "./evaluateErrorRule";
import { evaluateRules } from "./evaluateRules";
import { evaluateTreeRule } from "./evaluateTreeRule";
import { evaluateRules, group } from "./evaluateRules";

vi.mock("./evaluateEndpointRule");
vi.mock("./evaluateErrorRule");
vi.mock("./evaluateTreeRule");

describe(evaluateRules.name, () => {
vi.spyOn(group, "evaluateTreeRule").mockImplementation(vi.fn());
const { evaluateTreeRule } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
25 changes: 22 additions & 3 deletions packages/util-endpoints/src/utils/evaluateRules.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { EndpointV2 } from "@smithy/types";

import type { EvaluateOptions, RuleSetRules } from "../types";
import type { EvaluateOptions, RuleSetRules, TreeRuleObject } from "../types";
import { EndpointError } from "../types";
import { evaluateConditions } from "./evaluateConditions";
import { evaluateEndpointRule } from "./evaluateEndpointRule";
import { evaluateErrorRule } from "./evaluateErrorRule";
import { evaluateTreeRule } from "./evaluateTreeRule";

export const evaluateRules = (rules: RuleSetRules, options: EvaluateOptions): EndpointV2 => {
for (const rule of rules) {
Expand All @@ -16,7 +16,7 @@ export const evaluateRules = (rules: RuleSetRules, options: EvaluateOptions): En
} else if (rule.type === "error") {
evaluateErrorRule(rule, options);
} else if (rule.type === "tree") {
const endpointOrUndefined = evaluateTreeRule(rule, options);
const endpointOrUndefined = group.evaluateTreeRule(rule, options);
if (endpointOrUndefined) {
return endpointOrUndefined;
}
Expand All @@ -26,3 +26,22 @@ export const evaluateRules = (rules: RuleSetRules, options: EvaluateOptions): En
}
throw new EndpointError(`Rules evaluation failed`);
};

export const evaluateTreeRule = (treeRule: TreeRuleObject, options: EvaluateOptions): EndpointV2 | undefined => {
const { conditions, rules } = treeRule;

const { result, referenceRecord } = evaluateConditions(conditions, options);
if (!result) {
return;
}

return group.evaluateRules(rules, {
...options,
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
});
};

export const group = {
evaluateRules,
evaluateTreeRule,
};
6 changes: 4 additions & 2 deletions packages/util-endpoints/src/utils/evaluateTreeRule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { describe, expect, test as it, vi } from "vitest";

import type { TreeRuleObject } from "../types";
import { evaluateConditions } from "./evaluateConditions";
import { evaluateRules } from "./evaluateRules";
import { group } from "./evaluateRules";
import { evaluateTreeRule } from "./evaluateTreeRule";

vi.mock("./evaluateConditions");
vi.mock("./evaluateRules");

describe(evaluateTreeRule.name, () => {
vi.spyOn(group, "evaluateRules").mockImplementation(() => ({}) as any);
const { evaluateRules } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
21 changes: 2 additions & 19 deletions packages/util-endpoints/src/utils/evaluateTreeRule.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,2 @@
import type { EndpointV2 } from "@smithy/types";

import type { EvaluateOptions, TreeRuleObject } from "../types";
import { evaluateConditions } from "./evaluateConditions";
import { evaluateRules } from "./evaluateRules";

export const evaluateTreeRule = (treeRule: TreeRuleObject, options: EvaluateOptions): EndpointV2 | undefined => {
const { conditions, rules } = treeRule;

const { result, referenceRecord } = evaluateConditions(conditions, options);
if (!result) {
return;
}

return evaluateRules(rules, {
...options,
referenceRecord: { ...options.referenceRecord, ...referenceRecord },
});
};
// breaks circular import
export { evaluateTreeRule } from "./evaluateRules";
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { afterEach, describe, expect, test as it, vi } from "vitest";

import { getEndpointProperties } from "./getEndpointProperties";
import { getEndpointProperty } from "./getEndpointProperty";

vi.mock("./getEndpointProperty");
import { getEndpointProperties, group } from "./getEndpointProperties";

describe(getEndpointProperties.name, () => {
vi.spyOn(group, "getEndpointProperty");
const { getEndpointProperty } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
34 changes: 32 additions & 2 deletions packages/util-endpoints/src/utils/getEndpointProperties.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
import type { EndpointObjectProperty } from "@smithy/types";

import type { EndpointObjectProperties, EvaluateOptions } from "../types";
import { getEndpointProperty } from "./getEndpointProperty";
import { EndpointError } from "../types";
import { evaluateTemplate } from "./evaluateTemplate";

export const getEndpointProperties = (properties: EndpointObjectProperties, options: EvaluateOptions) =>
Object.entries(properties).reduce(
(acc, [propertyKey, propertyVal]) => ({
...acc,
[propertyKey]: getEndpointProperty(propertyVal, options),
[propertyKey]: group.getEndpointProperty(propertyVal, options),
}),
{}
);

export const getEndpointProperty = (
property: EndpointObjectProperty,
options: EvaluateOptions
): EndpointObjectProperty => {
if (Array.isArray(property)) {
return property.map((propertyEntry) => getEndpointProperty(propertyEntry, options));
}
switch (typeof property) {
case "string":
return evaluateTemplate(property, options);
case "object":
if (property === null) {
throw new EndpointError(`Unexpected endpoint property: ${property}`);
}
return group.getEndpointProperties(property, options);
case "boolean":
return property;
default:
throw new EndpointError(`Unexpected endpoint property type: ${typeof property}`);
}
};

export const group = {
getEndpointProperty,
getEndpointProperties,
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { afterEach, beforeEach, describe, expect, test as it, vi } from "vitest"

import { EndpointError } from "../types";
import { evaluateTemplate } from "./evaluateTemplate";
import { getEndpointProperties } from "./getEndpointProperties";
import { getEndpointProperty } from "./getEndpointProperty";
import { getEndpointProperty, group } from "./getEndpointProperties";

vi.mock("./evaluateTemplate");
vi.mock("./getEndpointProperties");

describe(getEndpointProperty.name, () => {
vi.spyOn(group, "getEndpointProperties").mockImplementation(vi.fn());
const { getEndpointProperties } = group;

const mockOptions = {
endpointParams: {},
referenceRecord: {},
Expand Down
30 changes: 2 additions & 28 deletions packages/util-endpoints/src/utils/getEndpointProperty.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,2 @@
import type { EndpointObjectProperty } from "@smithy/types";

import type { EvaluateOptions } from "../types";
import { EndpointError } from "../types";
import { evaluateTemplate } from "./evaluateTemplate";
import { getEndpointProperties } from "./getEndpointProperties";

export const getEndpointProperty = (
property: EndpointObjectProperty,
options: EvaluateOptions
): EndpointObjectProperty => {
if (Array.isArray(property)) {
return property.map((propertyEntry) => getEndpointProperty(propertyEntry, options));
}
switch (typeof property) {
case "string":
return evaluateTemplate(property, options);
case "object":
if (property === null) {
throw new EndpointError(`Unexpected endpoint property: ${property}`);
}
return getEndpointProperties(property, options);
case "boolean":
return property;
default:
throw new EndpointError(`Unexpected endpoint property type: ${typeof property}`);
}
};
// breaks circular import
export { getEndpointProperty } from "./getEndpointProperties";
13 changes: 10 additions & 3 deletions packages/util-stream/src/blob/Uint8ArrayBlobAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { transformFromString, transformToString } from "./transforms";
import { fromBase64, toBase64 } from "@smithy/util-base64";
import { fromUtf8, toUtf8 } from "@smithy/util-utf8";

/**
* Adapter for conversions of the native Uint8Array type.
Expand All @@ -12,7 +13,10 @@ export class Uint8ArrayBlobAdapter extends Uint8Array {
*/
public static fromString(source: string, encoding = "utf-8"): Uint8ArrayBlobAdapter {
if (typeof source === "string") {
return transformFromString(source, encoding);
if (encoding === "base64") {
return Uint8ArrayBlobAdapter.mutate(fromBase64(source));
}
return Uint8ArrayBlobAdapter.mutate(fromUtf8(source));
}
throw new Error(`Unsupported conversion from ${typeof source} to Uint8ArrayBlobAdapter.`);
}
Expand All @@ -31,6 +35,9 @@ export class Uint8ArrayBlobAdapter extends Uint8Array {
* @returns the blob as string.
*/
public transformToString(encoding = "utf-8"): string {
return transformToString(this, encoding);
if (encoding === "base64") {
return toBase64(this);
}
return toUtf8(this);
}
}
Loading