refactor(frontend) : split componentStructure.ts into focused modules
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,36 @@
|
|||||||
import {
|
import {
|
||||||
createEmptyComponentModelStructure,
|
createEmptyComponentModelStructure,
|
||||||
type ComponentModelCustomFieldType,
|
|
||||||
type ComponentModelCustomField,
|
type ComponentModelCustomField,
|
||||||
type ComponentModelPiece,
|
|
||||||
type ComponentModelProduct,
|
|
||||||
type ComponentModelStructure,
|
type ComponentModelStructure,
|
||||||
type ComponentModelStructureNode,
|
type ComponentModelStructureNode,
|
||||||
} from '../types/inventory'
|
} from '../types/inventory'
|
||||||
|
|
||||||
|
// Import for internal use in this file
|
||||||
|
import { sanitizeCustomFields, sanitizePieces, sanitizeProducts, sanitizeSubcomponents } from './componentStructureSanitize'
|
||||||
|
import { hydrateCustomFields, hydratePieces, hydrateProducts, hydrateSubcomponents, mapComponentCustomFields, mapComponentPieces, mapComponentProducts, mapSubcomponents } from './componentStructureHydrate'
|
||||||
|
|
||||||
|
// Re-export sanitize functions so existing imports continue to work
|
||||||
|
export {
|
||||||
|
toStringArray,
|
||||||
|
extractFieldValueObject,
|
||||||
|
sanitizeCustomFields,
|
||||||
|
sanitizePieces,
|
||||||
|
sanitizeProducts,
|
||||||
|
sanitizeSubcomponents,
|
||||||
|
} from './componentStructureSanitize'
|
||||||
|
|
||||||
|
// Re-export hydrate functions so existing imports continue to work
|
||||||
|
export {
|
||||||
|
hydrateCustomFields,
|
||||||
|
hydratePieces,
|
||||||
|
hydrateProducts,
|
||||||
|
hydrateSubcomponents,
|
||||||
|
mapComponentCustomFields,
|
||||||
|
mapComponentPieces,
|
||||||
|
mapComponentProducts,
|
||||||
|
mapSubcomponents,
|
||||||
|
} from './componentStructureHydrate'
|
||||||
|
|
||||||
export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
||||||
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
||||||
}
|
}
|
||||||
@@ -60,440 +83,6 @@ export const cloneStructure = (input: any): ComponentModelStructure => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const toStringArray = (input: unknown): string[] | undefined => {
|
|
||||||
if (!Array.isArray(input)) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const parsed = input
|
|
||||||
.map((value) => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return value.trim()
|
|
||||||
}
|
|
||||||
if (value === null || value === undefined) {
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
return String(value).trim()
|
|
||||||
})
|
|
||||||
.filter((value) => value.length > 0)
|
|
||||||
return parsed.length ? parsed : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
export const extractFieldValueObject = (field: any): Record<string, any> => {
|
|
||||||
if (isPlainObject(field?.value)) {
|
|
||||||
return field.value as Record<string, any>
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sanitizeCustomFields = (fields: any[]): ComponentModelCustomField[] => {
|
|
||||||
if (!Array.isArray(fields)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields
|
|
||||||
.map((field, index) => {
|
|
||||||
const rawName =
|
|
||||||
typeof field?.name === 'string'
|
|
||||||
? field.name
|
|
||||||
: typeof field?.key === 'string'
|
|
||||||
? field.key
|
|
||||||
: ''
|
|
||||||
const name = rawName.trim()
|
|
||||||
if (!name) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueObject = extractFieldValueObject(field)
|
|
||||||
|
|
||||||
const candidateType =
|
|
||||||
typeof field?.type === 'string' && field.type
|
|
||||||
? field.type
|
|
||||||
: typeof valueObject?.type === 'string'
|
|
||||||
? valueObject.type
|
|
||||||
: ''
|
|
||||||
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
|
||||||
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
|
||||||
? (candidateType as ComponentModelCustomFieldType)
|
|
||||||
: 'text'
|
|
||||||
|
|
||||||
const required =
|
|
||||||
typeof valueObject?.required === 'boolean' ? valueObject.required : !!field?.required
|
|
||||||
|
|
||||||
let options: string[] | undefined
|
|
||||||
if (type === 'select') {
|
|
||||||
options =
|
|
||||||
toStringArray(valueObject?.options) ||
|
|
||||||
toStringArray((valueObject as any)?.choices) ||
|
|
||||||
toStringArray(field?.options)
|
|
||||||
|
|
||||||
if (!options && typeof field?.optionsText === 'string') {
|
|
||||||
const parsedFromText = field.optionsText
|
|
||||||
.split(/\r?\n/)
|
|
||||||
.map((option: string) => option.trim())
|
|
||||||
.filter((option: string) => option.length > 0)
|
|
||||||
options = parsedFromText.length ? parsedFromText : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: ComponentModelCustomField = { name, type, required }
|
|
||||||
if (options) {
|
|
||||||
result.options = options
|
|
||||||
}
|
|
||||||
const defaultCandidate =
|
|
||||||
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
|
||||||
const resolvedDefault = (() => {
|
|
||||||
if (defaultCandidate === undefined || defaultCandidate === null) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (typeof defaultCandidate === 'object') {
|
|
||||||
if (defaultCandidate === null) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
|
||||||
return (defaultCandidate as Record<string, any>).defaultValue
|
|
||||||
}
|
|
||||||
if ('value' in (defaultCandidate as Record<string, any>)) {
|
|
||||||
return (defaultCandidate as Record<string, any>).value
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
return defaultCandidate
|
|
||||||
})()
|
|
||||||
if (resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== '') {
|
|
||||||
result.defaultValue = String(resolvedDefault)
|
|
||||||
}
|
|
||||||
const id = typeof field?.id === 'string' ? field.id : undefined
|
|
||||||
if (id) {
|
|
||||||
result.id = id
|
|
||||||
}
|
|
||||||
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
|
||||||
if (customFieldId) {
|
|
||||||
result.customFieldId = customFieldId
|
|
||||||
}
|
|
||||||
const orderIndex = typeof field?.orderIndex === 'number' ? field.orderIndex : index
|
|
||||||
result.orderIndex = orderIndex
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
.filter((field): field is ComponentModelCustomField => !!field)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sanitizePieces = (pieces: any[]): ComponentModelPiece[] => {
|
|
||||||
if (!Array.isArray(pieces)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return pieces
|
|
||||||
.map((piece) => {
|
|
||||||
const rawTypePieceId = typeof piece?.typePieceId === 'string'
|
|
||||||
? piece.typePieceId.trim()
|
|
||||||
: typeof piece?.typePiece?.id === 'string'
|
|
||||||
? piece.typePiece.id.trim()
|
|
||||||
: ''
|
|
||||||
const typePieceId = rawTypePieceId.length > 0 ? rawTypePieceId : undefined
|
|
||||||
|
|
||||||
const rawTypePieceLabel = typeof piece?.typePieceLabel === 'string'
|
|
||||||
? piece.typePieceLabel.trim()
|
|
||||||
: typeof piece?.typePiece?.name === 'string'
|
|
||||||
? piece.typePiece.name.trim()
|
|
||||||
: ''
|
|
||||||
const typePieceLabel = rawTypePieceLabel.length > 0 ? rawTypePieceLabel : undefined
|
|
||||||
|
|
||||||
const reference = typeof piece?.reference === 'string' && piece.reference.trim().length > 0
|
|
||||||
? piece.reference.trim()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const rawFamilyCode = typeof piece?.familyCode === 'string'
|
|
||||||
? piece.familyCode.trim()
|
|
||||||
: typeof piece?.typePiece?.code === 'string'
|
|
||||||
? piece.typePiece.code.trim()
|
|
||||||
: ''
|
|
||||||
const familyCode = rawFamilyCode.length > 0 ? rawFamilyCode : undefined
|
|
||||||
|
|
||||||
const rawRole = typeof piece?.role === 'string' ? piece.role.trim() : ''
|
|
||||||
const role = rawRole.length > 0 ? rawRole : undefined
|
|
||||||
|
|
||||||
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: ComponentModelPiece = {}
|
|
||||||
if (role) {
|
|
||||||
result.role = role
|
|
||||||
}
|
|
||||||
if (familyCode) {
|
|
||||||
result.familyCode = familyCode
|
|
||||||
}
|
|
||||||
if (reference !== undefined) {
|
|
||||||
result.reference = reference
|
|
||||||
}
|
|
||||||
if (typePieceId) {
|
|
||||||
result.typePieceId = typePieceId
|
|
||||||
}
|
|
||||||
if (typePieceLabel) {
|
|
||||||
result.typePieceLabel = typePieceLabel
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
.filter((piece): piece is ComponentModelPiece => !!piece)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sanitizeProducts = (products: any[]): ComponentModelProduct[] => {
|
|
||||||
if (!Array.isArray(products)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return products
|
|
||||||
.map((product) => {
|
|
||||||
const rawTypeProductId = typeof product?.typeProductId === 'string'
|
|
||||||
? product.typeProductId.trim()
|
|
||||||
: typeof product?.typeProduct?.id === 'string'
|
|
||||||
? product.typeProduct.id.trim()
|
|
||||||
: ''
|
|
||||||
const typeProductId = rawTypeProductId.length > 0 ? rawTypeProductId : undefined
|
|
||||||
|
|
||||||
const rawTypeProductLabel = typeof product?.typeProductLabel === 'string'
|
|
||||||
? product.typeProductLabel.trim()
|
|
||||||
: typeof product?.typeProduct?.name === 'string'
|
|
||||||
? product.typeProduct.name.trim()
|
|
||||||
: ''
|
|
||||||
const typeProductLabel = rawTypeProductLabel.length > 0 ? rawTypeProductLabel : undefined
|
|
||||||
|
|
||||||
const reference = typeof product?.reference === 'string' && product.reference.trim().length > 0
|
|
||||||
? product.reference.trim()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const rawFamilyCode = typeof product?.familyCode === 'string'
|
|
||||||
? product.familyCode.trim()
|
|
||||||
: typeof product?.typeProduct?.code === 'string'
|
|
||||||
? product.typeProduct.code.trim()
|
|
||||||
: ''
|
|
||||||
const familyCode = rawFamilyCode.length > 0 ? rawFamilyCode : undefined
|
|
||||||
|
|
||||||
const rawRole = typeof product?.role === 'string' ? product.role.trim() : ''
|
|
||||||
const role = rawRole.length > 0 ? rawRole : undefined
|
|
||||||
|
|
||||||
if (!typeProductId && !typeProductLabel && !reference && !familyCode) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: ComponentModelProduct = {}
|
|
||||||
if (role) {
|
|
||||||
result.role = role
|
|
||||||
}
|
|
||||||
if (familyCode) {
|
|
||||||
result.familyCode = familyCode
|
|
||||||
}
|
|
||||||
if (reference !== undefined) {
|
|
||||||
result.reference = reference
|
|
||||||
}
|
|
||||||
if (typeProductId) {
|
|
||||||
result.typeProductId = typeProductId
|
|
||||||
}
|
|
||||||
if (typeProductLabel) {
|
|
||||||
result.typeProductLabel = typeProductLabel
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
.filter((product): product is ComponentModelProduct => !!product)
|
|
||||||
}
|
|
||||||
|
|
||||||
const sanitizeSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
|
||||||
if (!Array.isArray(components)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return components
|
|
||||||
.map((component) => {
|
|
||||||
const rawTypeComposantId = typeof component?.typeComposantId === 'string'
|
|
||||||
? component.typeComposantId.trim()
|
|
||||||
: typeof component?.typeComposant?.id === 'string'
|
|
||||||
? component.typeComposant.id.trim()
|
|
||||||
: ''
|
|
||||||
const typeComposantId = rawTypeComposantId.length > 0 ? rawTypeComposantId : undefined
|
|
||||||
|
|
||||||
const modelId = typeof component?.modelId === 'string' && component.modelId.trim().length > 0
|
|
||||||
? component.modelId.trim()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const familyCode = typeof component?.familyCode === 'string' && component.familyCode.trim().length > 0
|
|
||||||
? component.familyCode.trim()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
const alias = typeof component?.alias === 'string' && component.alias.trim().length > 0
|
|
||||||
? component.alias.trim()
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
if (!typeComposantId && !modelId && !familyCode) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: ComponentModelStructureNode = {
|
|
||||||
subcomponents: sanitizeSubcomponents(
|
|
||||||
Array.isArray(component?.subcomponents)
|
|
||||||
? component.subcomponents
|
|
||||||
: component?.subComponents,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeComposantId) {
|
|
||||||
result.typeComposantId = typeComposantId
|
|
||||||
}
|
|
||||||
const typeComposantLabel = typeof component?.typeComposantLabel === 'string'
|
|
||||||
? component.typeComposantLabel.trim()
|
|
||||||
: typeof component?.typeComposant?.name === 'string'
|
|
||||||
? component.typeComposant.name.trim()
|
|
||||||
: ''
|
|
||||||
if (typeComposantLabel) {
|
|
||||||
result.typeComposantLabel = typeComposantLabel
|
|
||||||
}
|
|
||||||
if (modelId) {
|
|
||||||
result.modelId = modelId
|
|
||||||
}
|
|
||||||
if (familyCode) {
|
|
||||||
result.familyCode = familyCode
|
|
||||||
}
|
|
||||||
if (alias) {
|
|
||||||
result.alias = alias
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
|
||||||
.filter((component): component is ComponentModelStructureNode => !!component)
|
|
||||||
}
|
|
||||||
|
|
||||||
const hydrateCustomFields = (fields: any[]): any[] => {
|
|
||||||
if (!Array.isArray(fields)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return fields.map((field, index) => {
|
|
||||||
const valueObject = extractFieldValueObject(field)
|
|
||||||
const name = typeof field?.name === 'string'
|
|
||||||
? field.name
|
|
||||||
: typeof field?.key === 'string'
|
|
||||||
? field.key
|
|
||||||
: ''
|
|
||||||
|
|
||||||
const candidateType =
|
|
||||||
typeof field?.type === 'string' && field.type
|
|
||||||
? field.type
|
|
||||||
: typeof valueObject?.type === 'string'
|
|
||||||
? valueObject.type
|
|
||||||
: ''
|
|
||||||
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
|
||||||
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
|
||||||
? (candidateType as ComponentModelCustomFieldType)
|
|
||||||
: 'text'
|
|
||||||
|
|
||||||
const required =
|
|
||||||
typeof field?.required === 'boolean'
|
|
||||||
? field.required
|
|
||||||
: typeof valueObject?.required === 'boolean'
|
|
||||||
? valueObject.required
|
|
||||||
: false
|
|
||||||
|
|
||||||
const options =
|
|
||||||
toStringArray(field?.options) ||
|
|
||||||
toStringArray(valueObject?.options) ||
|
|
||||||
toStringArray((valueObject as any)?.choices) ||
|
|
||||||
[]
|
|
||||||
|
|
||||||
const optionsText = typeof field?.optionsText === 'string'
|
|
||||||
? field.optionsText
|
|
||||||
: options.length
|
|
||||||
? options.join('\n')
|
|
||||||
: ''
|
|
||||||
|
|
||||||
const defaultCandidate =
|
|
||||||
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
|
||||||
const resolvedDefault = (() => {
|
|
||||||
if (defaultCandidate === undefined || defaultCandidate === null) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (typeof defaultCandidate === 'object') {
|
|
||||||
if (defaultCandidate === null) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
|
||||||
return (defaultCandidate as Record<string, any>).defaultValue
|
|
||||||
}
|
|
||||||
if ('value' in (defaultCandidate as Record<string, any>)) {
|
|
||||||
return (defaultCandidate as Record<string, any>).value
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
return defaultCandidate
|
|
||||||
})()
|
|
||||||
const defaultValue =
|
|
||||||
resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== ''
|
|
||||||
? String(resolvedDefault)
|
|
||||||
: ''
|
|
||||||
|
|
||||||
const id = typeof field?.id === 'string' ? field.id : undefined
|
|
||||||
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
|
||||||
const orderIndex = typeof field?.orderIndex === 'number' ? field.orderIndex : index
|
|
||||||
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
type,
|
|
||||||
required,
|
|
||||||
options,
|
|
||||||
optionsText,
|
|
||||||
defaultValue,
|
|
||||||
id,
|
|
||||||
customFieldId,
|
|
||||||
orderIndex,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const hydratePieces = (pieces: any[]): ComponentModelPiece[] => {
|
|
||||||
if (!Array.isArray(pieces)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return pieces.map((piece) => ({
|
|
||||||
typePieceId: piece?.typePieceId ?? piece?.typePiece?.id ?? '',
|
|
||||||
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
|
||||||
reference: piece?.reference ?? '',
|
|
||||||
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
|
||||||
role: piece?.role ?? '',
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const hydrateProducts = (products: any[]): ComponentModelProduct[] => {
|
|
||||||
if (!Array.isArray(products)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return products.map((product) => ({
|
|
||||||
typeProductId: product?.typeProductId ?? product?.typeProduct?.id ?? '',
|
|
||||||
typeProductLabel: product?.typeProductLabel ?? product?.typeProduct?.name ?? '',
|
|
||||||
reference: product?.reference ?? '',
|
|
||||||
familyCode: product?.familyCode ?? product?.typeProduct?.code ?? '',
|
|
||||||
role: product?.role ?? '',
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const hydrateSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
|
||||||
if (!Array.isArray(components)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
return components.map((component) => ({
|
|
||||||
typeComposantId: component?.typeComposantId ?? component?.typeComposant?.id ?? '',
|
|
||||||
typeComposantLabel: component?.typeComposantLabel ?? component?.typeComposant?.name ?? '',
|
|
||||||
modelId: component?.modelId ?? '',
|
|
||||||
familyCode: component?.familyCode ?? component?.typeComposant?.code ?? '',
|
|
||||||
alias: component?.alias ?? component?.name ?? '',
|
|
||||||
subcomponents: hydrateSubcomponents(
|
|
||||||
Array.isArray(component?.subcomponents)
|
|
||||||
? component.subcomponents
|
|
||||||
: component?.subComponents,
|
|
||||||
),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const normalizeStructureForEditor = (input: any): ComponentModelStructure => {
|
export const normalizeStructureForEditor = (input: any): ComponentModelStructure => {
|
||||||
const source = cloneStructure(input)
|
const source = cloneStructure(input)
|
||||||
|
|
||||||
@@ -668,76 +257,6 @@ export const hydrateStructureForEditor = (input: any): ComponentModelStructure =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapComponentCustomFields = (fields: any[]) => {
|
|
||||||
if (!Array.isArray(fields)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return hydrateCustomFields(fields).map((field, index) => {
|
|
||||||
const defaultValue =
|
|
||||||
field?.defaultValue !== undefined && field?.defaultValue !== null && field?.defaultValue !== ''
|
|
||||||
? field.defaultValue
|
|
||||||
: null
|
|
||||||
return {
|
|
||||||
name: typeof field?.name === 'string' ? field.name : '',
|
|
||||||
type: field?.type ?? 'text',
|
|
||||||
required: !!field?.required,
|
|
||||||
options: Array.isArray(field?.options) ? field.options : [],
|
|
||||||
optionsText: typeof field?.optionsText === 'string' ? field.optionsText : '',
|
|
||||||
defaultValue,
|
|
||||||
id: typeof (field as any)?.id === 'string' ? (field as any).id : undefined,
|
|
||||||
customFieldId:
|
|
||||||
typeof (field as any)?.customFieldId === 'string'
|
|
||||||
? (field as any).customFieldId
|
|
||||||
: undefined,
|
|
||||||
orderIndex: typeof field?.orderIndex === 'number' ? field.orderIndex : index,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapComponentPieces = (pieces: any[]): ComponentModelPiece[] => {
|
|
||||||
if (!Array.isArray(pieces)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return pieces.map((piece) => ({
|
|
||||||
reference: piece?.reference ?? '',
|
|
||||||
typePieceId: piece?.typePieceId ?? piece?.typePiece?.id ?? '',
|
|
||||||
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
|
||||||
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
|
||||||
role: piece?.role ?? '',
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapComponentProducts = (products: any[]): ComponentModelProduct[] => {
|
|
||||||
if (!Array.isArray(products)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return products.map((product) => ({
|
|
||||||
reference: product?.reference ?? '',
|
|
||||||
typeProductId: product?.typeProductId ?? product?.typeProduct?.id ?? '',
|
|
||||||
typeProductLabel: product?.typeProductLabel ?? product?.typeProduct?.name ?? '',
|
|
||||||
familyCode: product?.familyCode ?? product?.typeProduct?.code ?? '',
|
|
||||||
role: product?.role ?? '',
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
|
||||||
if (!Array.isArray(components)) {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return components.map((component) => ({
|
|
||||||
typeComposantId: component?.typeComposantId ?? component?.typeComposant?.id ?? '',
|
|
||||||
typeComposantLabel: component?.typeComposantLabel ?? component?.typeComposant?.name ?? '',
|
|
||||||
modelId: component?.modelId ?? '',
|
|
||||||
familyCode: component?.familyCode ?? component?.typeComposant?.code ?? '',
|
|
||||||
alias: component?.alias ?? component?.name ?? '',
|
|
||||||
subcomponents: mapSubcomponents(
|
|
||||||
Array.isArray(component?.subcomponents)
|
|
||||||
? component.subcomponents
|
|
||||||
: component?.subComponents,
|
|
||||||
),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const extractStructureFromComponent = (component: any) => {
|
export const extractStructureFromComponent = (component: any) => {
|
||||||
if (!component) {
|
if (!component) {
|
||||||
return defaultStructure()
|
return defaultStructure()
|
||||||
|
|||||||
210
app/shared/model/componentStructureHydrate.ts
Normal file
210
app/shared/model/componentStructureHydrate.ts
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
import type {
|
||||||
|
ComponentModelCustomFieldType,
|
||||||
|
ComponentModelPiece,
|
||||||
|
ComponentModelProduct,
|
||||||
|
ComponentModelStructureNode,
|
||||||
|
} from '../types/inventory'
|
||||||
|
import { extractFieldValueObject, toStringArray } from './componentStructureSanitize'
|
||||||
|
|
||||||
|
export const hydrateCustomFields = (fields: any[]): any[] => {
|
||||||
|
if (!Array.isArray(fields)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields.map((field, index) => {
|
||||||
|
const valueObject = extractFieldValueObject(field)
|
||||||
|
const name = typeof field?.name === 'string'
|
||||||
|
? field.name
|
||||||
|
: typeof field?.key === 'string'
|
||||||
|
? field.key
|
||||||
|
: ''
|
||||||
|
|
||||||
|
const candidateType =
|
||||||
|
typeof field?.type === 'string' && field.type
|
||||||
|
? field.type
|
||||||
|
: typeof valueObject?.type === 'string'
|
||||||
|
? valueObject.type
|
||||||
|
: ''
|
||||||
|
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
||||||
|
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
||||||
|
? (candidateType as ComponentModelCustomFieldType)
|
||||||
|
: 'text'
|
||||||
|
|
||||||
|
const required =
|
||||||
|
typeof field?.required === 'boolean'
|
||||||
|
? field.required
|
||||||
|
: typeof valueObject?.required === 'boolean'
|
||||||
|
? valueObject.required
|
||||||
|
: false
|
||||||
|
|
||||||
|
const options =
|
||||||
|
toStringArray(field?.options) ||
|
||||||
|
toStringArray(valueObject?.options) ||
|
||||||
|
toStringArray((valueObject as any)?.choices) ||
|
||||||
|
[]
|
||||||
|
|
||||||
|
const optionsText = typeof field?.optionsText === 'string'
|
||||||
|
? field.optionsText
|
||||||
|
: options.length
|
||||||
|
? options.join('\n')
|
||||||
|
: ''
|
||||||
|
|
||||||
|
const defaultCandidate =
|
||||||
|
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
||||||
|
const resolvedDefault = (() => {
|
||||||
|
if (defaultCandidate === undefined || defaultCandidate === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (typeof defaultCandidate === 'object') {
|
||||||
|
if (defaultCandidate === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
||||||
|
return (defaultCandidate as Record<string, any>).defaultValue
|
||||||
|
}
|
||||||
|
if ('value' in (defaultCandidate as Record<string, any>)) {
|
||||||
|
return (defaultCandidate as Record<string, any>).value
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return defaultCandidate
|
||||||
|
})()
|
||||||
|
const defaultValue =
|
||||||
|
resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== ''
|
||||||
|
? String(resolvedDefault)
|
||||||
|
: ''
|
||||||
|
|
||||||
|
const id = typeof field?.id === 'string' ? field.id : undefined
|
||||||
|
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
||||||
|
const orderIndex = typeof field?.orderIndex === 'number' ? field.orderIndex : index
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
required,
|
||||||
|
options,
|
||||||
|
optionsText,
|
||||||
|
defaultValue,
|
||||||
|
id,
|
||||||
|
customFieldId,
|
||||||
|
orderIndex,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hydratePieces = (pieces: any[]): ComponentModelPiece[] => {
|
||||||
|
if (!Array.isArray(pieces)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return pieces.map((piece) => ({
|
||||||
|
typePieceId: piece?.typePieceId ?? piece?.typePiece?.id ?? '',
|
||||||
|
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
||||||
|
reference: piece?.reference ?? '',
|
||||||
|
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
||||||
|
role: piece?.role ?? '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hydrateProducts = (products: any[]): ComponentModelProduct[] => {
|
||||||
|
if (!Array.isArray(products)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return products.map((product) => ({
|
||||||
|
typeProductId: product?.typeProductId ?? product?.typeProduct?.id ?? '',
|
||||||
|
typeProductLabel: product?.typeProductLabel ?? product?.typeProduct?.name ?? '',
|
||||||
|
reference: product?.reference ?? '',
|
||||||
|
familyCode: product?.familyCode ?? product?.typeProduct?.code ?? '',
|
||||||
|
role: product?.role ?? '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const hydrateSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
||||||
|
if (!Array.isArray(components)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return components.map((component) => ({
|
||||||
|
typeComposantId: component?.typeComposantId ?? component?.typeComposant?.id ?? '',
|
||||||
|
typeComposantLabel: component?.typeComposantLabel ?? component?.typeComposant?.name ?? '',
|
||||||
|
modelId: component?.modelId ?? '',
|
||||||
|
familyCode: component?.familyCode ?? component?.typeComposant?.code ?? '',
|
||||||
|
alias: component?.alias ?? component?.name ?? '',
|
||||||
|
subcomponents: hydrateSubcomponents(
|
||||||
|
Array.isArray(component?.subcomponents)
|
||||||
|
? component.subcomponents
|
||||||
|
: component?.subComponents,
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapComponentCustomFields = (fields: any[]) => {
|
||||||
|
if (!Array.isArray(fields)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return hydrateCustomFields(fields).map((field, index) => {
|
||||||
|
const defaultValue =
|
||||||
|
field?.defaultValue !== undefined && field?.defaultValue !== null && field?.defaultValue !== ''
|
||||||
|
? field.defaultValue
|
||||||
|
: null
|
||||||
|
return {
|
||||||
|
name: typeof field?.name === 'string' ? field.name : '',
|
||||||
|
type: field?.type ?? 'text',
|
||||||
|
required: !!field?.required,
|
||||||
|
options: Array.isArray(field?.options) ? field.options : [],
|
||||||
|
optionsText: typeof field?.optionsText === 'string' ? field.optionsText : '',
|
||||||
|
defaultValue,
|
||||||
|
id: typeof (field as any)?.id === 'string' ? (field as any).id : undefined,
|
||||||
|
customFieldId:
|
||||||
|
typeof (field as any)?.customFieldId === 'string'
|
||||||
|
? (field as any).customFieldId
|
||||||
|
: undefined,
|
||||||
|
orderIndex: typeof field?.orderIndex === 'number' ? field.orderIndex : index,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapComponentPieces = (pieces: any[]): ComponentModelPiece[] => {
|
||||||
|
if (!Array.isArray(pieces)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return pieces.map((piece) => ({
|
||||||
|
reference: piece?.reference ?? '',
|
||||||
|
typePieceId: piece?.typePieceId ?? piece?.typePiece?.id ?? '',
|
||||||
|
typePieceLabel: piece?.typePieceLabel ?? piece?.typePiece?.name ?? '',
|
||||||
|
familyCode: piece?.familyCode ?? piece?.typePiece?.code ?? '',
|
||||||
|
role: piece?.role ?? '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapComponentProducts = (products: any[]): ComponentModelProduct[] => {
|
||||||
|
if (!Array.isArray(products)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return products.map((product) => ({
|
||||||
|
reference: product?.reference ?? '',
|
||||||
|
typeProductId: product?.typeProductId ?? product?.typeProduct?.id ?? '',
|
||||||
|
typeProductLabel: product?.typeProductLabel ?? product?.typeProduct?.name ?? '',
|
||||||
|
familyCode: product?.familyCode ?? product?.typeProduct?.code ?? '',
|
||||||
|
role: product?.role ?? '',
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mapSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
||||||
|
if (!Array.isArray(components)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return components.map((component) => ({
|
||||||
|
typeComposantId: component?.typeComposantId ?? component?.typeComposant?.id ?? '',
|
||||||
|
typeComposantLabel: component?.typeComposantLabel ?? component?.typeComposant?.name ?? '',
|
||||||
|
modelId: component?.modelId ?? '',
|
||||||
|
familyCode: component?.familyCode ?? component?.typeComposant?.code ?? '',
|
||||||
|
alias: component?.alias ?? component?.name ?? '',
|
||||||
|
subcomponents: mapSubcomponents(
|
||||||
|
Array.isArray(component?.subcomponents)
|
||||||
|
? component.subcomponents
|
||||||
|
: component?.subComponents,
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
}
|
||||||
312
app/shared/model/componentStructureSanitize.ts
Normal file
312
app/shared/model/componentStructureSanitize.ts
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
import type {
|
||||||
|
ComponentModelCustomField,
|
||||||
|
ComponentModelCustomFieldType,
|
||||||
|
ComponentModelPiece,
|
||||||
|
ComponentModelProduct,
|
||||||
|
ComponentModelStructureNode,
|
||||||
|
} from '../types/inventory'
|
||||||
|
// Inline helper to avoid circular dependency with componentStructure.ts
|
||||||
|
const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
||||||
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toStringArray = (input: unknown): string[] | undefined => {
|
||||||
|
if (!Array.isArray(input)) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const parsed = input
|
||||||
|
.map((value) => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value.trim()
|
||||||
|
}
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return String(value).trim()
|
||||||
|
})
|
||||||
|
.filter((value) => value.length > 0)
|
||||||
|
return parsed.length ? parsed : undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export const extractFieldValueObject = (field: any): Record<string, any> => {
|
||||||
|
if (isPlainObject(field?.value)) {
|
||||||
|
return field.value as Record<string, any>
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sanitizeCustomFields = (fields: any[]): ComponentModelCustomField[] => {
|
||||||
|
if (!Array.isArray(fields)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
.map((field, index) => {
|
||||||
|
const rawName =
|
||||||
|
typeof field?.name === 'string'
|
||||||
|
? field.name
|
||||||
|
: typeof field?.key === 'string'
|
||||||
|
? field.key
|
||||||
|
: ''
|
||||||
|
const name = rawName.trim()
|
||||||
|
if (!name) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueObject = extractFieldValueObject(field)
|
||||||
|
|
||||||
|
const candidateType =
|
||||||
|
typeof field?.type === 'string' && field.type
|
||||||
|
? field.type
|
||||||
|
: typeof valueObject?.type === 'string'
|
||||||
|
? valueObject.type
|
||||||
|
: ''
|
||||||
|
const allowedTypes: ComponentModelCustomFieldType[] = ['text', 'number', 'select', 'boolean', 'date']
|
||||||
|
const type = allowedTypes.includes(candidateType as ComponentModelCustomFieldType)
|
||||||
|
? (candidateType as ComponentModelCustomFieldType)
|
||||||
|
: 'text'
|
||||||
|
|
||||||
|
const required =
|
||||||
|
typeof valueObject?.required === 'boolean' ? valueObject.required : !!field?.required
|
||||||
|
|
||||||
|
let options: string[] | undefined
|
||||||
|
if (type === 'select') {
|
||||||
|
options =
|
||||||
|
toStringArray(valueObject?.options) ||
|
||||||
|
toStringArray((valueObject as any)?.choices) ||
|
||||||
|
toStringArray(field?.options)
|
||||||
|
|
||||||
|
if (!options && typeof field?.optionsText === 'string') {
|
||||||
|
const parsedFromText = field.optionsText
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map((option: string) => option.trim())
|
||||||
|
.filter((option: string) => option.length > 0)
|
||||||
|
options = parsedFromText.length ? parsedFromText : undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ComponentModelCustomField = { name, type, required }
|
||||||
|
if (options) {
|
||||||
|
result.options = options
|
||||||
|
}
|
||||||
|
const defaultCandidate =
|
||||||
|
field?.defaultValue ?? valueObject?.defaultValue ?? field?.value ?? field?.default ?? null
|
||||||
|
const resolvedDefault = (() => {
|
||||||
|
if (defaultCandidate === undefined || defaultCandidate === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if (typeof defaultCandidate === 'object') {
|
||||||
|
if (defaultCandidate === null) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
if ('defaultValue' in (defaultCandidate as Record<string, any>)) {
|
||||||
|
return (defaultCandidate as Record<string, any>).defaultValue
|
||||||
|
}
|
||||||
|
if ('value' in (defaultCandidate as Record<string, any>)) {
|
||||||
|
return (defaultCandidate as Record<string, any>).value
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return defaultCandidate
|
||||||
|
})()
|
||||||
|
if (resolvedDefault !== undefined && resolvedDefault !== null && resolvedDefault !== '') {
|
||||||
|
result.defaultValue = String(resolvedDefault)
|
||||||
|
}
|
||||||
|
const id = typeof field?.id === 'string' ? field.id : undefined
|
||||||
|
if (id) {
|
||||||
|
result.id = id
|
||||||
|
}
|
||||||
|
const customFieldId = typeof field?.customFieldId === 'string' ? field.customFieldId : undefined
|
||||||
|
if (customFieldId) {
|
||||||
|
result.customFieldId = customFieldId
|
||||||
|
}
|
||||||
|
const orderIndex = typeof field?.orderIndex === 'number' ? field.orderIndex : index
|
||||||
|
result.orderIndex = orderIndex
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.filter((field): field is ComponentModelCustomField => !!field)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sanitizePieces = (pieces: any[]): ComponentModelPiece[] => {
|
||||||
|
if (!Array.isArray(pieces)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return pieces
|
||||||
|
.map((piece) => {
|
||||||
|
const rawTypePieceId = typeof piece?.typePieceId === 'string'
|
||||||
|
? piece.typePieceId.trim()
|
||||||
|
: typeof piece?.typePiece?.id === 'string'
|
||||||
|
? piece.typePiece.id.trim()
|
||||||
|
: ''
|
||||||
|
const typePieceId = rawTypePieceId.length > 0 ? rawTypePieceId : undefined
|
||||||
|
|
||||||
|
const rawTypePieceLabel = typeof piece?.typePieceLabel === 'string'
|
||||||
|
? piece.typePieceLabel.trim()
|
||||||
|
: typeof piece?.typePiece?.name === 'string'
|
||||||
|
? piece.typePiece.name.trim()
|
||||||
|
: ''
|
||||||
|
const typePieceLabel = rawTypePieceLabel.length > 0 ? rawTypePieceLabel : undefined
|
||||||
|
|
||||||
|
const reference = typeof piece?.reference === 'string' && piece.reference.trim().length > 0
|
||||||
|
? piece.reference.trim()
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const rawFamilyCode = typeof piece?.familyCode === 'string'
|
||||||
|
? piece.familyCode.trim()
|
||||||
|
: typeof piece?.typePiece?.code === 'string'
|
||||||
|
? piece.typePiece.code.trim()
|
||||||
|
: ''
|
||||||
|
const familyCode = rawFamilyCode.length > 0 ? rawFamilyCode : undefined
|
||||||
|
|
||||||
|
const rawRole = typeof piece?.role === 'string' ? piece.role.trim() : ''
|
||||||
|
const role = rawRole.length > 0 ? rawRole : undefined
|
||||||
|
|
||||||
|
if (!typePieceId && !typePieceLabel && !reference && !familyCode) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ComponentModelPiece = {}
|
||||||
|
if (role) {
|
||||||
|
result.role = role
|
||||||
|
}
|
||||||
|
if (familyCode) {
|
||||||
|
result.familyCode = familyCode
|
||||||
|
}
|
||||||
|
if (reference !== undefined) {
|
||||||
|
result.reference = reference
|
||||||
|
}
|
||||||
|
if (typePieceId) {
|
||||||
|
result.typePieceId = typePieceId
|
||||||
|
}
|
||||||
|
if (typePieceLabel) {
|
||||||
|
result.typePieceLabel = typePieceLabel
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.filter((piece): piece is ComponentModelPiece => !!piece)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sanitizeProducts = (products: any[]): ComponentModelProduct[] => {
|
||||||
|
if (!Array.isArray(products)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return products
|
||||||
|
.map((product) => {
|
||||||
|
const rawTypeProductId = typeof product?.typeProductId === 'string'
|
||||||
|
? product.typeProductId.trim()
|
||||||
|
: typeof product?.typeProduct?.id === 'string'
|
||||||
|
? product.typeProduct.id.trim()
|
||||||
|
: ''
|
||||||
|
const typeProductId = rawTypeProductId.length > 0 ? rawTypeProductId : undefined
|
||||||
|
|
||||||
|
const rawTypeProductLabel = typeof product?.typeProductLabel === 'string'
|
||||||
|
? product.typeProductLabel.trim()
|
||||||
|
: typeof product?.typeProduct?.name === 'string'
|
||||||
|
? product.typeProduct.name.trim()
|
||||||
|
: ''
|
||||||
|
const typeProductLabel = rawTypeProductLabel.length > 0 ? rawTypeProductLabel : undefined
|
||||||
|
|
||||||
|
const reference = typeof product?.reference === 'string' && product.reference.trim().length > 0
|
||||||
|
? product.reference.trim()
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const rawFamilyCode = typeof product?.familyCode === 'string'
|
||||||
|
? product.familyCode.trim()
|
||||||
|
: typeof product?.typeProduct?.code === 'string'
|
||||||
|
? product.typeProduct.code.trim()
|
||||||
|
: ''
|
||||||
|
const familyCode = rawFamilyCode.length > 0 ? rawFamilyCode : undefined
|
||||||
|
|
||||||
|
const rawRole = typeof product?.role === 'string' ? product.role.trim() : ''
|
||||||
|
const role = rawRole.length > 0 ? rawRole : undefined
|
||||||
|
|
||||||
|
if (!typeProductId && !typeProductLabel && !reference && !familyCode) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ComponentModelProduct = {}
|
||||||
|
if (role) {
|
||||||
|
result.role = role
|
||||||
|
}
|
||||||
|
if (familyCode) {
|
||||||
|
result.familyCode = familyCode
|
||||||
|
}
|
||||||
|
if (reference !== undefined) {
|
||||||
|
result.reference = reference
|
||||||
|
}
|
||||||
|
if (typeProductId) {
|
||||||
|
result.typeProductId = typeProductId
|
||||||
|
}
|
||||||
|
if (typeProductLabel) {
|
||||||
|
result.typeProductLabel = typeProductLabel
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.filter((product): product is ComponentModelProduct => !!product)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sanitizeSubcomponents = (components: any[]): ComponentModelStructureNode[] => {
|
||||||
|
if (!Array.isArray(components)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return components
|
||||||
|
.map((component) => {
|
||||||
|
const rawTypeComposantId = typeof component?.typeComposantId === 'string'
|
||||||
|
? component.typeComposantId.trim()
|
||||||
|
: typeof component?.typeComposant?.id === 'string'
|
||||||
|
? component.typeComposant.id.trim()
|
||||||
|
: ''
|
||||||
|
const typeComposantId = rawTypeComposantId.length > 0 ? rawTypeComposantId : undefined
|
||||||
|
|
||||||
|
const modelId = typeof component?.modelId === 'string' && component.modelId.trim().length > 0
|
||||||
|
? component.modelId.trim()
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const familyCode = typeof component?.familyCode === 'string' && component.familyCode.trim().length > 0
|
||||||
|
? component.familyCode.trim()
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
const alias = typeof component?.alias === 'string' && component.alias.trim().length > 0
|
||||||
|
? component.alias.trim()
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
if (!typeComposantId && !modelId && !familyCode) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ComponentModelStructureNode = {
|
||||||
|
subcomponents: sanitizeSubcomponents(
|
||||||
|
Array.isArray(component?.subcomponents)
|
||||||
|
? component.subcomponents
|
||||||
|
: component?.subComponents,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeComposantId) {
|
||||||
|
result.typeComposantId = typeComposantId
|
||||||
|
}
|
||||||
|
const typeComposantLabel = typeof component?.typeComposantLabel === 'string'
|
||||||
|
? component.typeComposantLabel.trim()
|
||||||
|
: typeof component?.typeComposant?.name === 'string'
|
||||||
|
? component.typeComposant.name.trim()
|
||||||
|
: ''
|
||||||
|
if (typeComposantLabel) {
|
||||||
|
result.typeComposantLabel = typeComposantLabel
|
||||||
|
}
|
||||||
|
if (modelId) {
|
||||||
|
result.modelId = modelId
|
||||||
|
}
|
||||||
|
if (familyCode) {
|
||||||
|
result.familyCode = familyCode
|
||||||
|
}
|
||||||
|
if (alias) {
|
||||||
|
result.alias = alias
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
.filter((component): component is ComponentModelStructureNode => !!component)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user