google-ads-api
Version:
Google Ads API Client Library for Node.js
117 lines (116 loc) • 4.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.decamelizeKeys = void 0;
const circ_json_1 = require("circ-json");
const utils_1 = require("./utils");
const fields_1 = require("./protos/autogen/fields");
const enums_1 = require("./protos/autogen/enums");
const fieldDataTypes = (0, circ_json_1.parse)(fields_1.fieldDataTypes);
const decamelizeCache = new Map();
const fieldTypeCache = new Map();
const isObject = (value) => typeof value === "object" && value !== null;
const decamelizeKeys = (input) => {
if (!isObject(input)) {
return input;
}
return transform(input);
function transform(value, parentPath) {
if (!isObject(value)) {
return value;
}
if (Array.isArray(value)) {
const length = value.length;
const result = new Array(length);
for (let i = 0; i < length; i += 1) {
const item = value[i];
result[i] = isObject(item) ? transformObject(item, parentPath) : item;
}
return result;
}
return transformObject(value, parentPath);
}
function transformObject(obj, parentPath) {
const output = {};
for (const key of Object.keys(obj)) {
const rawValue = obj[key];
const newKey = cachedDecamelize(key);
if (isObject(rawValue)) {
const nextParentPath = parentPath === undefined ? newKey : `${parentPath}.${newKey}`;
output[newKey] = transform(rawValue, nextParentPath);
}
else {
output[newKey] = cachedValueParser(newKey, parentPath, rawValue);
}
}
return output;
}
};
exports.decamelizeKeys = decamelizeKeys;
const cachedDecamelize = (key) => {
const cachedResult = decamelizeCache.get(key);
if (cachedResult) {
return cachedResult;
}
const newKey = (0, utils_1.toSnakeCase)(key);
decamelizeCache.set(key, newKey);
return newKey;
};
const cachedValueParser = (key, parentPath, value) => {
let newValue = value;
const fullPath = parentPath ? `${parentPath}.${key}` : key;
const megaDataType = getTypeFromPath(fullPath);
if (megaDataType === undefined && !fullPath.startsWith("@")) {
console.warn(`No data type found for ${fullPath}`);
}
else if (typeof megaDataType === "object") {
// Special handling for FieldMask types - REST API returns them as comma-separated strings
if (megaDataType.paths === "STRING" && typeof value === "string") {
// This is a FieldMask field, convert the comma-separated string to the expected format
// Also convert each path from camelCase to snake_case
newValue = {
paths: value.split(",").map((p) => {
// Handle nested paths like "ipBlock.ipAddress"
return p
.trim()
.split(".")
.map((segment) => (0, utils_1.toSnakeCase)(segment))
.join(".");
}),
};
}
else {
// Normal enum handling
newValue = megaDataType[value];
}
}
else if (megaDataType === "INT64") {
newValue = Number(value);
}
else if (megaDataType === "ENUM") {
// Some enums aren't embedded in megaDataType, so we need this fallback.
// @ts-expect-error typescript doesn't like accessing items in a namespace with a string
newValue = enums_1.enums[fields_1.fields.enumFields[fullPath]][value]; // e.g. enums['CampaignStatus'][ENABLED] = "2"
}
return newValue;
};
const getTypeFromPath = (path) => {
const cachedResult = fieldTypeCache.get(path);
if (cachedResult) {
return cachedResult;
}
const t = get(fieldDataTypes, path);
fieldTypeCache.set(path, t);
return t;
};
// Copied from youmightnotneed.com
const get = (obj, path) => {
if (!path)
return undefined;
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
// Regex explained: https://regexr.com/58j0k
const pathArray = path.match(/([^[.\]])+/g);
if (!pathArray)
return undefined;
// Find value
return pathArray.reduce((prevObj, key) => prevObj && prevObj[key], obj);
};