UNPKG

@unito/integration-debugger

Version:

The Unito Integration Debugger

125 lines (124 loc) 5.64 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const integration_api_1 = require("@unito/integration-api"); const CrawlerDriver = __importStar(require("../crawlerDriver")); const helpers_1 = require("./helpers"); /** * Returns only the fields with semantic for a given Step's schemaPath */ function getFieldsWithSemantics(step, crawlerDriver) { return crawlerDriver.getFieldSchemas(step.schemaPath)?.filter(field => field.semantic) ?? []; } /** * Check: Select fields of item summaries having a semantic. * * We only care about fields with semantics in this test. * The rationale behind this is that: * 1. They have a semantic so they have a special meaning for the Unito platform. * 2. Therefore, the Unito platform may select those fields when fetching the collection. * * For example, if the item "foo" (collection at "/foos") has multiple fields, * including "bar" and "spam" having a semantic, * the following step is produced: * * GetCollection /foos?select=bar,spam * * The result of this step must contain item summaries having the fields "bar" and "spam". */ const check = { label: 'Select fields - Semantics', prepareOnPreparedSteps: false, validateOnError: false, activatedByDefault: true, prepare: async (stepResult, crawlerDriver) => { const step = stepResult.step; // To perform this operation, we need to know the schema of the items in the collection. if (step.operation !== CrawlerDriver.Operation.GetCollection || !step.schemaPath) { return []; } // We only care about fields with semantics. const fieldsWithSemantics = getFieldsWithSemantics(step, crawlerDriver).filter( // Hack: Confluence has to fetch every item to get the description (body). // I'm skipping this for now until we have a better solution. // TODO: remove this hack when https://app.asana.com/0/1204988207007911/1206117191812124 is done. field => field.semantic !== integration_api_1.Semantics.DESCRIPTION); if (fieldsWithSemantics.length === 0) { return []; } // A path may already have a "select" query params. const queryParams = (0, helpers_1.extractQueryParams)(step.path); const existingSelects = queryParams.get('select')?.split(',') ?? []; const newSelects = fieldsWithSemantics.map(field => field.name); // If the incoming path already test all the selects we want to test, don't produce an additional step. if (existingSelects.length && existingSelects.every(select => newSelects.includes(select))) { return []; } const selects = Array.from(new Set(existingSelects.concat(newSelects))); queryParams.set('select', selects.join(',')); step.path = [step.path.split('?').at(0), queryParams.toString()].join('?'); return [step]; }, validate: (step, _crawlerDriver) => { // The validation part is a little bit more generic and validates any requested selected, not only semantics. if (step.operation !== CrawlerDriver.Operation.GetCollection) { return; } const queryParams = (0, helpers_1.extractQueryParams)(step.path); const selects = Array.from(new Set(queryParams.get('select')?.split(',') ?? [])); if (selects.length === 0) { return; } const items = step.payloadOut.data; for (const [index, item] of items.entries()) { const itemKeys = Object.keys(item.fields ?? {}); for (const select of selects) { if (!itemKeys.includes(select)) { step.errors.push({ keyword: 'unito', message: 'Some requested fields are missing', detailedMessage: `The field '${select}' is missing but requested in '${step.path}'`, instancePath: `/data/${index}/fields`, schemaPath: step.schemaPath ?? '', params: { code: 'REQUESTED_SELECT_FIELD_MISSING', }, }); } } } }, }; exports.default = check;