Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 2x 2x 2x 2x 55x 5x 2x 52x 2x 20x 2x 18x 1x 17x 17x 16x 1x 2x 25x 1x 24x 24x 1x 23x 2x 23x 6x 5x 5x 1x 4x 1x 21x 2x 60x 60x 12x 9x 60x 125x 120x 24x 26x 26x 26x 25x 25x 25x 25x 100x 25x 25x 25x 25x 23x 23x 21x 21x 20x 20x 21x 20x 20x 21x 20x 21x 20x 20x 21x 20x 20x 21x 2x | import { ValueType, ObjectType, StringType } from 'yaschva'
import { map } from 'microtil'
import { validate, isValidationError } from './jsonSchema.js'
import {
CrudContract, CrudAuthAll, CrudAuthSome, OutputSuccess, Output, ManageableFields
} from './types.js'
import {
HttpMethods,
SearchTypes
} from 'declarapi-runtime'
import { loadJSON, baseSchemaLocation } from '../util.js'
const contractOptions = (input: ValueType | ValueType[]): ValueType[] => {
if (Array.isArray(input)) {
if (input.some(x => x === '?')) { return input }
return input.concat(['?'])
}
return [input, '?']
}
const searchToType =
(idType: 'string'| StringType, dataType: ObjectType, search?: SearchTypes): ObjectType => {
if (search === 'idOnly') {
return { id: [idType, { $array: idType }, '?'] }
} else if (search === 'textSearch') {
return { search: ['string', '?'], id: [idType, { $array: idType }, '?'] }
} else Iif (search === 'full') {
return map(dataType, value => contractOptions(value))
} else if (!search) {
return {}
}
return search
}
const checkIdField = (contract:CrudContract) :Output | false => {
if (contract.dataType.id === undefined) {
return {
type: 'error',
errors: 'id field does not exist in the data declaration'
}
}
const idType: any = contract.dataType.id
if (!(idType === 'string' || idType.$string)) {
return {
type: 'error',
errors: 'Type of id field must be string'
}
}
return false
}
const checkManageFields = (contract: CrudContract): Output|false => {
for (const [key, value] of Object.entries(contract.manageFields || {})) {
if (value) {
const fieldType: any = contract.dataType[key]
if (fieldType === undefined) {
return {
type: 'error',
errors: `managed field "${key}" is not present on data type`
}
}
if (!(fieldType === 'string' || fieldType.$string)) {
return {
type: 'error',
errors: `managed field "${key}" must be a string, current type :${fieldType}`
}
}
}
}
return false
}
const removeManaged = (args: ObjectType, manageFields?: ManageableFields):ObjectType => {
const result = { ...args }
for (const [key, value] of Object.entries(manageFields || {})) {
if (value) {
delete result[key]
}
}
return result
}
const isCrudAuth = (tbd: any): tbd is CrudAuthAll => tbd.post !== undefined
const isCrudAuthSome = (tbd: any): tbd is CrudAuthSome => tbd.modify !== undefined
const transformForPost = (tbd: any) => Array.isArray(tbd) && tbd.find(x => x.createdBy) ? true : tbd
export const transform = async (data:CrudContract | any): Promise<Output> => {
const valid = await validate(await loadJSON(`${await baseSchemaLocation()}crudContractSchema.json`), data)
if (isValidationError(valid)) return valid
const contractData: CrudContract = data
const au = contractData.authentication
const auth = {
GET: isCrudAuth(au) ? au.get : (isCrudAuthSome(au) ? au.get : au),
POST: isCrudAuth(au) ? au.post : transformForPost((isCrudAuthSome(au) ? au.modify : au)),
PUT: isCrudAuth(au) ? au.put : (isCrudAuthSome(au) ? au.modify : au),
PATCH: isCrudAuth(au) ? au.put : (isCrudAuthSome(au) ? au.modify : au),
DELETE: isCrudAuth(au) ? au.delete : (isCrudAuthSome(au) ? au.delete || au.modify : au)
}
const createOutput = (method: HttpMethods, args: ObjectType,
returns: ObjectType = contractData.dataType): OutputSuccess => ({
method,
name: contractData.name,
authentication: auth[method],
manageFields: contractData.manageFields || {},
search: contractData.search,
preferredImplementation: contractData.preferredImplementation,
arguments: args,
returns
})
const returnArray = { $array: contractData.dataType }
const output: OutputSuccess[] = []
const errorWithId = checkIdField(contractData)
if (errorWithId) return errorWithId
const errorWithManageFields = checkManageFields(contractData)
if (errorWithManageFields) return errorWithManageFields
const idType: any = contractData.dataType.id
if (contractData.methods?.get !== false) {
const search = contractData.search
output.push(createOutput('GET',
searchToType(idType, contractData.dataType, search), returnArray))
}
if (contractData.methods?.post !== false) {
const post = { ...contractData.dataType, id: [idType, '?'] }
output.push(createOutput('POST', removeManaged(post, contractData.manageFields)))
}
if (contractData.methods?.put !== false) {
output.push(createOutput('PUT', removeManaged(contractData.dataType, contractData.manageFields)))
}
if (contractData.methods?.patch !== false) {
const patch: {[s: string]: ValueType | ValueType[];} =
{ ...map(contractData.dataType, contractOptions), id: idType }
output.push(createOutput('PATCH', removeManaged(patch, contractData.manageFields)))
}
if (contractData.methods?.delete !== false) {
const deleteIds: {[s: string]: ValueType[];} = { id: [idType, { $array: idType }] }
output.push(createOutput('DELETE', deleteIds, returnArray))
}
return { type: 'result', key: contractData.name, results: output }
}
export default transform
|