UNPKG

google-ads-api

Version:

Google Ads API Client Library for Node.js

117 lines (116 loc) 4.4 kB
"use strict"; 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); };