Skip to content

Commit

Permalink
fix: add helper functions for dealing with AnyXmlValue and export them
Browse files Browse the repository at this point in the history
  • Loading branch information
nytamin committed Oct 15, 2024
1 parent a43c217 commit e4a5f48
Show file tree
Hide file tree
Showing 12 changed files with 225 additions and 161 deletions.
34 changes: 34 additions & 0 deletions packages/helper/src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,38 @@ describe('Index', () => {
expect(MOS.MosModel.XMLMosItem.toXML).toBeTruthy()
expect(MOS.pad).toBeTruthy()
})
test('manipulate xml data', () => {
// The ensure* methods are useful when reading the XML data

const testTypes = (anyData: MOS.AnyXMLObject) => {
// ensureString
testType<string>(MOS.ensureString(anyData.strValue, true))

testType<object>(MOS.ensureXMLObject(anyData.objA, true))
// @ts-expect-error wrong return type
testType<string>(MOS.ensureObject(anyData.objA, true))

testType<string>(MOS.ensureString(MOS.ensureXMLObject(anyData.objA, true).strValue, true))

testType<string>(MOS.ensureString(MOS.ensureXMLObjectArray(anyData.arrayA, true)[0].strValue, true))

expect(1).toBeTruthy()
}

const testType = <T>(_a: T) => {
return
}

testTypes({
strValue: 'test',
objA: {
strValue: 'test',
},
arrayA: [
{
strValue: 'test',
},
],
})
})
})
1 change: 1 addition & 0 deletions packages/helper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export {
export * as MosModel from './mosModel'
export * from './stringify/stringifyMosObject'
export * from './utils/Errors'
export * from './utils/ensureMethods'
3 changes: 2 additions & 1 deletion packages/helper/src/mosModel/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export * from './profile2'
export * from './profile3'
export * from './profile4'
export * from './parseMosTypes'
export { ensureArray, literal, omitUndefined, flattenXMLText } from './lib'
export { literal, omitUndefined, flattenXMLText } from './lib'
export * from '../utils/ensureMethods'
export * from './ParseError'

import { AnyXMLObject } from '@mos-connection/model'
Expand Down
41 changes: 0 additions & 41 deletions packages/helper/src/mosModel/lib.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { AnyXMLValue } from '@mos-connection/model'
import { ensureSingular } from './parseMosTypes'

export function isEmpty(obj: unknown): boolean {
if (typeof obj === 'object') {
Expand All @@ -21,16 +20,6 @@ export function has(obj: unknown, property: string): boolean {
return Object.hasOwnProperty.call(obj, property)
}

/**
* Ensures that the returned value is an array.
* If the input is not an array, it will be wrapped in an array.
*/
export function ensureArray<A, B>(v: A | B | B[]): (A | B)[]
export function ensureArray<T>(v: T | T[]): T[]
export function ensureArray<T>(v: T | T[]): T[] {
if (typeof v === 'object' && Array.isArray(v)) return v
else return [v]
}
/**
* Asserts that a string type is of a certain literal.
* Example usage: const str = assertStringLiteral('foo', ['foo', 'bar']) // str is of type 'foo' | 'bar'
Expand All @@ -39,36 +28,6 @@ export function assertStringLiteral<T extends string>(value: string, options: T[
return options.includes(value as T)
}

export function ensureStringLiteral<T extends string>(
xmlValue: AnyXMLValue,
options: T[],
fallback: T,
strict: boolean
): T {
const value = ensureSingular(xmlValue, strict)

if (!value) {
if (strict) {
throw new Error(`Expected a string, got: "${value}"`)
} else {
return fallback
}
}

if (assertStringLiteral(value, options)) {
return value
} else if (strict) {
throw new Error(`Invalid literal value: "${value}" (valid values: ${options.join(', ')})`)
} else {
return fallback
}
}
export function ensureString(value: AnyXMLValue, strict: boolean): string {
if (typeof value === 'string') {
return value
} else if (strict) throw new Error(`Expected a string, got: ${JSON.stringify(value)}`)
else return ''
}
/** Type assertion */
export function literal<T>(o: T): T {
return o
Expand Down
95 changes: 2 additions & 93 deletions packages/helper/src/mosModel/parseMosTypes.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { MosTypes, getMosTypes, MosType, AnyXMLObject } from '@mos-connection/model'
import { AnyXMLValue, AnyXMLValueSingular, ensureArray, isEmpty } from './lib'
import { AnyXMLValue } from './lib'
import { ParseError } from './ParseError'
import { ensureSingular } from '../utils/ensureMethods'

export function getParseMosTypes(strict: boolean): MosParseTypes {
const mosTypes = getMosTypes(strict)
Expand Down Expand Up @@ -127,85 +128,6 @@ export function parseRequired<V, R>(
}
}

export function ensureSingular(value: AnyXMLValue, strict: boolean): AnyXMLValueSingular {
// Quick-fix if it is in a xml element:
if (isXMLTextElement(value)) value = value.text
// Quick-fix for empty object
if (isEmpty(value)) value = ''

if (typeof value === 'object') {
if (Array.isArray(value)) {
if (value.length === 0) return undefined
if (value.length > 1) {
if (strict)
throw new Error(`Expected only one value, got ${value.length} values: ${JSON.stringify(value)}`)
else return undefined
}
return ensureSingular(value[0], strict)
} else if (strict) throw new Error(`Expected only one value, got object: ${JSON.stringify(value)}`)
else return undefined
} else {
return value
}
}
export function ensureSingularArray(value: AnyXMLValue, strict: boolean): AnyXMLValueSingular[] {
if (typeof value === 'object' && Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
value[i] = ensureSingular(value[i], strict)
}
return value as AnyXMLValueSingular[]
} else if (strict) throw new Error(`Expected an Array, got: ${JSON.stringify(value)}`)
else return []
}
export function ensureXMLObject(value: AnyXMLValue, strict: boolean): AnyXMLObject {
if (typeof value === 'object') {
if (Array.isArray(value)) {
if (value.length === 0) return {}
if (value.length > 1) {
if (strict)
throw new Error(`Expected only one value, got ${value.length} values: ${JSON.stringify(value)}`)
else return {}
}
return ensureXMLObject(value[0], strict)
} else {
return value
}
} else if (strict) throw new Error(`Expected an object, got: ${value}`)
else return {}
}

export function ensureXMLObjectArray(value: AnyXMLValue, strict: boolean): AnyXMLObject[] {
const objs: AnyXMLObject[] = []
for (const obj of ensureArray(value)) {
objs.push(ensureXMLObject(obj, strict))
}
return objs
}
export function isSingular(value: AnyXMLValue): value is AnyXMLValueSingular {
try {
ensureSingular(value, true)
return true
} catch {
return false
}
}
export function isSingularArray(value: AnyXMLValue): value is AnyXMLValueSingular[] {
try {
ensureSingularArray(value, true)
return true
} catch {
return false
}
}
export function isXMLObject(value: AnyXMLValue): value is AnyXMLObject {
try {
ensureXMLObject(value, true)
return true
} catch {
return false
}
}

function getSpecialMosTypes(strict: boolean) {
const string: MosType<string, string, AnyXMLValue> = {
create: (anyValue: AnyXMLValue) => {
Expand Down Expand Up @@ -263,16 +185,3 @@ export function getXMLAttributes(obj: AnyXMLObject): { [key: string]: string } {
return obj.attributes as any
else return {}
}

interface TextElement {
$type: 'text'
$name: string
text: string
}
function isXMLTextElement(xml: any): xml is TextElement {
return (
typeof xml === 'object' &&
(xml as TextElement).$type === 'text' &&
typeof (xml as TextElement).text === 'string'
)
}
7 changes: 4 additions & 3 deletions packages/helper/src/mosModel/profile0/xmlConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import {
IMOSListMachInfoDefaultActiveXMode,
IMOSString128,
} from '@mos-connection/model'
import { ensureArray, ensureStringLiteral, has, omitUndefined } from '../lib'
import { has, omitUndefined } from '../lib'
import { ensureArray, ensureStringLiteral, ensureXMLObject } from '../../utils/ensureMethods'
import { addTextElementInternal } from '../../utils/Utils'
import { ensureXMLObject, getParseMosTypes, getXMLAttributes } from '../parseMosTypes'
import { getParseMosTypes, getXMLAttributes } from '../parseMosTypes'
import { XMLMosExternalMetaData } from '../profile1'
import { ParseError } from '../ParseError'

Expand Down Expand Up @@ -93,7 +94,7 @@ export namespace XMLSupportedProfiles {
)

const parsed: IMOSListMachInfo['supportedProfiles'] = {
deviceType: ensureStringLiteral(xmlSupportedProfiles.deviceType, ['NCS', 'MOS', 'N/A'], 'N/A', strict),
deviceType: ensureStringLiteral(xmlSupportedProfiles.deviceType, ['NCS', 'MOS', 'N/A'], strict, 'N/A'),
// Note: .profiles are added below
}

Expand Down
5 changes: 3 additions & 2 deletions packages/helper/src/mosModel/profile1/xmlConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
IMOSObjectAirStatus,
IMOSScope,
} from '@mos-connection/model'
import { AnyXMLObject, ensureArray, flattenXMLText, has, isEmpty, literal, omitUndefined } from '../lib'
import { AnyXMLObject, flattenXMLText, has, isEmpty, literal, omitUndefined } from '../lib'
import { ensureArray, ensureXMLObject, ensureXMLObjectArray, isXMLObject } from '../../utils/ensureMethods'
import { addTextElementInternal } from '../../utils/Utils'
import { ensureXMLObject, ensureXMLObjectArray, getParseMosTypes, isXMLObject } from '../parseMosTypes'
import { getParseMosTypes } from '../parseMosTypes'
import { ParseError } from '../ParseError'

/* eslint-disable @typescript-eslint/no-namespace */
Expand Down
5 changes: 3 additions & 2 deletions packages/helper/src/mosModel/profile2/xmlConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import {
IMOSROAckObject,
AnyXMLValue,
} from '@mos-connection/model'
import { ensureArray, has, omitUndefined } from '../lib'
import { has, omitUndefined } from '../lib'
import { ensureArray, ensureXMLObject } from '../../utils/ensureMethods'
import { ROAck } from './ROAck'
import { XMLMosExternalMetaData, XMLMosObjects, XMLObjectPaths } from '../profile1/xmlConversion'
import { addTextElementInternal } from '../../utils/Utils'
import { ensureXMLObject, getParseMosTypes } from '../parseMosTypes'
import { getParseMosTypes } from '../parseMosTypes'
import { ParseError } from '../ParseError'
/* eslint-disable @typescript-eslint/no-namespace */

Expand Down
9 changes: 2 additions & 7 deletions packages/helper/src/mosModel/profile3/xmlConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,11 @@ import {
IMOSSearchField,
} from '@mos-connection/model'
import { omitUndefined } from '../lib'
import {
getParseMosTypes,
ensureXMLObject,
getXMLAttributes,
isXMLObject,
ensureXMLObjectArray,
} from '../parseMosTypes'
import { getParseMosTypes, getXMLAttributes } from '../parseMosTypes'
import { addTextElementInternal } from '../../utils/Utils'
import { XMLMosObjects } from '../profile1'
import { ParseError } from '../ParseError'
import { ensureXMLObject, ensureXMLObjectArray, isXMLObject } from '../../utils/ensureMethods'
/* eslint-disable @typescript-eslint/no-namespace */

export namespace XMLMosRequestObjectList {
Expand Down
3 changes: 2 additions & 1 deletion packages/helper/src/mosModel/profile4/xmlConversion.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { IMOSROFullStoryBodyItem, IMOSROFullStory, AnyXMLValue } from '@mos-connection/model'
import { XMLROStory, XMLMosItem } from '../profile2/xmlConversion'
import { omitUndefined } from '../lib'
import { ensureXMLObject, ensureXMLObjectArray, getParseMosTypes } from '../parseMosTypes'
import { getParseMosTypes } from '../parseMosTypes'
import { ParseError } from '../ParseError'
import { ensureXMLObject, ensureXMLObjectArray } from '../../utils/ensureMethods'

/* eslint-disable @typescript-eslint/no-namespace */
export namespace XMLROFullStory {
Expand Down
Loading

0 comments on commit e4a5f48

Please sign in to comment.