mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Fix/empty properties (#1764)
* refactor properties utilities with updated ts-matches and allow for a null file * update pacakges
This commit is contained in:
5171
frontend/package-lock.json
generated
5171
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -52,7 +52,7 @@
|
|||||||
"pbkdf2": "^3.1.2",
|
"pbkdf2": "^3.1.2",
|
||||||
"rxjs": "^7.5.6",
|
"rxjs": "^7.5.6",
|
||||||
"swiper": "^8.2.4",
|
"swiper": "^8.2.4",
|
||||||
"ts-matches": "^5.1.7",
|
"ts-matches": "^5.2.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"zone.js": "^0.11.5"
|
"zone.js": "^0.11.5"
|
||||||
|
|||||||
@@ -1,51 +1,59 @@
|
|||||||
import { applyOperation } from 'fast-json-patch'
|
import { applyOperation } from 'fast-json-patch'
|
||||||
import {
|
import matches, {
|
||||||
Parser,
|
Parser,
|
||||||
shape,
|
shape,
|
||||||
string,
|
string,
|
||||||
literal,
|
literal,
|
||||||
boolean,
|
boolean,
|
||||||
object,
|
|
||||||
deferred,
|
deferred,
|
||||||
dictionary,
|
dictionary,
|
||||||
anyOf,
|
anyOf,
|
||||||
|
number,
|
||||||
|
arrayOf,
|
||||||
} from 'ts-matches'
|
} from 'ts-matches'
|
||||||
|
|
||||||
export type ValidVersion = 1 | 2
|
type ValidVersion = 1 | 2
|
||||||
|
|
||||||
function has<Obj extends {}, K extends string>(
|
type PropertiesV1 = typeof matchPropertiesV1._TYPE
|
||||||
obj: Obj,
|
type PackagePropertiesV1 = PropertiesV1[]
|
||||||
key: K,
|
type PackagePropertiesV2 = {
|
||||||
): obj is Obj & { [P in K]: unknown } {
|
[name: string]: PackagePropertyString | PackagePropertyObject
|
||||||
return key in obj
|
|
||||||
}
|
}
|
||||||
|
type PackagePropertiesVersionedData<T extends number> = T extends 1
|
||||||
|
? PackagePropertiesV1
|
||||||
|
: T extends 2
|
||||||
|
? PackagePropertiesV2
|
||||||
|
: never
|
||||||
|
|
||||||
|
type PackagePropertyString = typeof matchPackagePropertyString._TYPE
|
||||||
|
|
||||||
|
export type PackagePropertiesVersioned<T extends number> = {
|
||||||
|
version: T
|
||||||
|
data: PackagePropertiesVersionedData<T>
|
||||||
|
}
|
||||||
|
export type PackageProperties = PackagePropertiesV2
|
||||||
|
|
||||||
const matchPropertiesV1 = shape(
|
const matchPropertiesV1 = shape(
|
||||||
{
|
{
|
||||||
name: string,
|
name: string,
|
||||||
value: string,
|
value: string,
|
||||||
description: string.optional(),
|
description: string,
|
||||||
copyable: boolean.optional(),
|
copyable: boolean,
|
||||||
qr: boolean.optional(),
|
qr: boolean,
|
||||||
},
|
},
|
||||||
['description', 'copyable', 'qr'],
|
['description', 'copyable', 'qr'],
|
||||||
{ copyable: false, qr: false } as const,
|
{ copyable: false, qr: false } as const,
|
||||||
)
|
)
|
||||||
type PropertiesV1 = typeof matchPropertiesV1._TYPE
|
|
||||||
|
|
||||||
type PackagePropertiesV2 = {
|
|
||||||
[name: string]: PackagePropertyString | PackagePropertyObject
|
|
||||||
}
|
|
||||||
|
|
||||||
const [matchPackagePropertiesV2, setPPV2] = deferred<PackagePropertiesV2>()
|
const [matchPackagePropertiesV2, setPPV2] = deferred<PackagePropertiesV2>()
|
||||||
const matchPackagePropertyString = shape(
|
const matchPackagePropertyString = shape(
|
||||||
{
|
{
|
||||||
type: literal('string'),
|
type: literal('string'),
|
||||||
description: string.optional(),
|
description: string,
|
||||||
value: string,
|
value: string,
|
||||||
copyable: boolean.optional(),
|
copyable: boolean,
|
||||||
qr: boolean.optional(),
|
qr: boolean,
|
||||||
masked: boolean.optional(),
|
masked: boolean,
|
||||||
},
|
},
|
||||||
['description', 'copyable', 'qr', 'masked'],
|
['description', 'copyable', 'qr', 'masked'],
|
||||||
{
|
{
|
||||||
@@ -54,16 +62,15 @@ const matchPackagePropertyString = shape(
|
|||||||
masked: false,
|
masked: false,
|
||||||
} as const,
|
} as const,
|
||||||
)
|
)
|
||||||
type PackagePropertyString = typeof matchPackagePropertyString._TYPE
|
|
||||||
const matchPackagePropertyObject = shape(
|
const matchPackagePropertyObject = shape(
|
||||||
{
|
{
|
||||||
type: literal('object'),
|
type: literal('object'),
|
||||||
value: matchPackagePropertiesV2,
|
value: matchPackagePropertiesV2,
|
||||||
description: string.optional(),
|
description: string,
|
||||||
},
|
},
|
||||||
['description'],
|
['description'],
|
||||||
{ description: null as null },
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const matchPropertyV2 = anyOf(
|
const matchPropertyV2 = anyOf(
|
||||||
matchPackagePropertyString,
|
matchPackagePropertyString,
|
||||||
matchPackagePropertyObject,
|
matchPackagePropertyObject,
|
||||||
@@ -71,58 +78,29 @@ const matchPropertyV2 = anyOf(
|
|||||||
type PackagePropertyObject = typeof matchPackagePropertyObject._TYPE
|
type PackagePropertyObject = typeof matchPackagePropertyObject._TYPE
|
||||||
setPPV2(dictionary([string, matchPropertyV2]))
|
setPPV2(dictionary([string, matchPropertyV2]))
|
||||||
|
|
||||||
|
const matchPackagePropertiesVersionedV1 = shape({
|
||||||
|
version: number,
|
||||||
|
data: arrayOf(matchPropertiesV1),
|
||||||
|
})
|
||||||
|
const matchPackagePropertiesVersionedV2 = shape({
|
||||||
|
version: number,
|
||||||
|
data: dictionary([string, matchPropertyV2]),
|
||||||
|
})
|
||||||
|
|
||||||
export function parsePropertiesPermissive(
|
export function parsePropertiesPermissive(
|
||||||
properties: unknown,
|
properties: unknown,
|
||||||
errorCallback: (err: Error) => any = console.warn,
|
errorCallback: (err: Error) => any = console.warn,
|
||||||
): PackageProperties {
|
): PackageProperties {
|
||||||
if (typeof properties !== 'object' || properties === null) {
|
return matches(properties)
|
||||||
errorCallback(new TypeError(`${properties} is not an object`))
|
.when(matchPackagePropertiesVersionedV1, prop =>
|
||||||
return {}
|
parsePropertiesV1Permissive(prop.data, errorCallback),
|
||||||
}
|
)
|
||||||
// @TODO still need this conditional?
|
.when(matchPackagePropertiesVersionedV2, prop => prop.data)
|
||||||
if (
|
.when(matches.nill, {})
|
||||||
!has(properties, 'version') ||
|
.defaultToLazy(() => {
|
||||||
!has(properties, 'data') ||
|
errorCallback(new TypeError(`value is not valid`))
|
||||||
typeof properties.version !== 'number' ||
|
return {}
|
||||||
!properties.data
|
})
|
||||||
) {
|
|
||||||
return Object.entries(properties)
|
|
||||||
.filter(([_, value]) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
errorCallback(new TypeError(`${value} is not a string`))
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(([name, value]) => ({
|
|
||||||
name,
|
|
||||||
value: {
|
|
||||||
value: String(value),
|
|
||||||
copyable: false,
|
|
||||||
qr: false,
|
|
||||||
masked: false,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
.reduce((acc, { name, value }) => {
|
|
||||||
// TODO: Fix type
|
|
||||||
acc[name] = value as any
|
|
||||||
return acc
|
|
||||||
}, {} as PackageProperties)
|
|
||||||
}
|
|
||||||
switch (properties.version) {
|
|
||||||
case 1:
|
|
||||||
return parsePropertiesV1Permissive(properties.data, errorCallback)
|
|
||||||
case 2:
|
|
||||||
return parsePropertiesV2Permissive(properties.data, errorCallback)
|
|
||||||
default:
|
|
||||||
errorCallback(
|
|
||||||
new Error(
|
|
||||||
`unknown properties version ${properties.version}, attempting to parse as v2`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return parsePropertiesV2Permissive(properties.data, errorCallback)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parsePropertiesV1Permissive(
|
function parsePropertiesV1Permissive(
|
||||||
@@ -164,37 +142,6 @@ function parsePropertiesV1Permissive(
|
|||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
function parsePropertiesV2Permissive(
|
|
||||||
properties: unknown,
|
|
||||||
errorCallback: (err: Error) => any,
|
|
||||||
): PackageProperties {
|
|
||||||
if (!object.test(properties)) {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
return Object.entries(properties).reduce(
|
|
||||||
(prev: PackageProperties, [name, value], idx) => {
|
|
||||||
const result = matchPropertyV2.enumParsed(value)
|
|
||||||
if ('value' in result) {
|
|
||||||
prev[name] = result.value
|
|
||||||
} else {
|
|
||||||
const error = result.error
|
|
||||||
const message = Parser.validatorErrorAsString(error)
|
|
||||||
const dataPath = error.keys.map(removeQuotes).join('/')
|
|
||||||
errorCallback(new Error(`/data/${idx}: ${message}`))
|
|
||||||
if (dataPath) {
|
|
||||||
applyOperation(properties, {
|
|
||||||
op: 'replace',
|
|
||||||
path: `/${dataPath}`,
|
|
||||||
value: undefined,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prev
|
|
||||||
},
|
|
||||||
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeRegex = /('|")/
|
const removeRegex = /('|")/
|
||||||
function removeQuotes(x: string) {
|
function removeQuotes(x: string) {
|
||||||
@@ -203,17 +150,3 @@ function removeQuotes(x: string) {
|
|||||||
}
|
}
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackagePropertiesV1 = PropertiesV1[]
|
|
||||||
export type PackageProperties = PackagePropertiesV2
|
|
||||||
|
|
||||||
export type PackagePropertiesVersioned<T extends number> = {
|
|
||||||
version: T
|
|
||||||
data: PackagePropertiesVersionedData<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PackagePropertiesVersionedData<T extends number> = T extends 1
|
|
||||||
? PackagePropertiesV1
|
|
||||||
: T extends 2
|
|
||||||
? PackagePropertiesV2
|
|
||||||
: never
|
|
||||||
|
|||||||
Reference in New Issue
Block a user