import * as path from 'path' import { z } from "zod" import normalizeUrl from 'normalize-url' import { isInvalidMarketplaceComponent, isValidLibraryComponent, isValidMarketplaceComponent, PFilterInvalid, PFilterValid } from './filter.js' import { forward_slash, pathInfoEx } from './fs/_glob.js' import { resolve } from './variables.js' import { readOSRConfig } from './config.js' const IMAGES_GLOB = '*.+(JPG|jpg|png|PNG|gif)' export const find_items = (nodes: string[], options) => { nodes = nodes.filter(options.filter) return nodes.map((c) => { const root = resolve(options.root, false, {}) return { rel: forward_slash(`${path.relative(root, path.parse(c).dir)}`), path: forward_slash(`${options.root}/${path.relative(root, c)}`), config: readOSRConfig(c) } }) } export const get = (src, root, type): IComponentNode[] => { const srcInfo = pathInfoEx(src, false, { absolute: true }) switch (type) { case PFilterValid.marketplace_component: { const options = { filter: isValidMarketplaceComponent, root } return find_items(srcInfo.FILES, options) } case PFilterValid.library_component: { const options = { filter: isValidLibraryComponent, root } return find_items(srcInfo.FILES, options) } case PFilterInvalid.marketplace_component: { const options = { filter: isInvalidMarketplaceComponent, root } return find_items(srcInfo.FILES, options) } } } export const UrlSchema = z.string().url().transform((arg) => normalizeUrl(arg)) export const ExifSchema = z.object({ file: z.any(), // Assuming File is another schema or any type jfif: z.any(), // Assuming Jfif is another schema or any type exif: z.any(), // Assuming Exif2 is another schema or any type gps: z.any() // Assuming Gps is another schema or any type }); export const ImageMetaSchema = z.object({ format: z.string(), width: z.number(), height: z.number(), space: z.string(), channels: z.number(), depth: z.string(), density: z.number(), chromaSubsampling: z.string(), isProgressive: z.boolean(), resolutionUnit: z.string(), hasProfile: z.boolean(), hasAlpha: z.boolean(), orientation: z.number(), exif: z.any() // Assuming Exif is another schema or any type }); export const CADMetaSchema = z.object({ file: z.string(), name: z.string(), configuration: z.string(), // solidworks map step: z.string().optional(), model: z.string().optional(), html: z.string().optional(), }) export const ShippingSchema = z.object({ price: z.number().optional(), transit: z.number().optional(), handling: z.number().optional() }) export const ManufacturingSchema = z.object({ lead_time: z.number().optional() }) export const ResourceSchema = z.object({ name: z.string(), url: z.string(), type: z.string() }) export const AssetImageSchema = z.object({ name: z.string().optional(), url: z.string(), thumb: z.string().optional(), responsive: z.string().optional(), meta: z.any().optional(), keywords: z.array(z.string()).optional(), description: z.string().optional(), alt: z.string().optional(), title: z.string().optional(), height: z.number().optional(), width: z.number().optional(), order: z.number().optional(), exif: ExifSchema.optional(), }) export const GalleryConfig = z.object({ glob: z.array(z.string()) }) export const GalleryConfigsSchema = z.record(GalleryConfig) export const AuthorSchema = z.object({ name: z.string(), url: z.string(), }) export const ContentSchema = z.object({ body: z.string().optional(), features: z.string().optional(), highlights: z.string().optional(), specs: z.string().optional(), license: z.string().optional(), resources: z.string().optional(), readme: z.string().optional(), shared: z.string().optional() }) export const VersionSchema = z.object({ version: z.string().optional(), up: z.string().optional(), down: z.string().optional(), family: z.string().optional(), sheet: z.string().optional() }) export const AssetsSchema = z.object({ gallery: z.array(AssetImageSchema).optional(), renderings: z.array(AssetImageSchema).optional(), components: z.array(AssetImageSchema).optional(), configurations: z.array(AssetImageSchema).optional(), showcase: z.array(AssetImageSchema).optional(), samples: z.array(AssetImageSchema).optional() }) export const ProductionSchema = z.object({ "fusion-folder": z.string(), "nc-folder": z.string(), cam: z.array(AuthorSchema) }) export const ComponentConfigSchema = z.object({ // shop cart_id: z.string().optional(), code: z.string(), price: z.number().optional(), cscartCats: z.array(z.number()).optional(), cscartId: z.number().optional(), vendorId: z.number().optional(), shipping: ShippingSchema.optional().default({ price: 0, transit: 12, handling: 2 }), // references replaced_by: z.string().optional(), alternatives: z.array(ResourceSchema).optional(), used_by: z.array(ResourceSchema).optional(), image: AssetImageSchema.optional(), name: z.string(), // cad edrawings: z.string().optional(), cad: z.array(CADMetaSchema).default([]), manufacturing: ManufacturingSchema, // settings showDimensions: z.boolean().optional(), showParts: z.boolean().optional(), Preview3d: z.boolean().optional(), flags: z.number().optional().default(0), // meta slug: z.string(), keywords: z.string().optional(), meta_keywords: z.string().optional(), version: z.string().optional(), versions: VersionSchema.optional(), status: z.string().optional(), authors: z.array(AuthorSchema).optional(), // content assets: AssetsSchema.default({ gallery: [], renderings: [], components: [], configurations: [], showcase: [], samples: [] }), resources: z.array(ResourceSchema).default([]), tests: z.array(ResourceSchema).default([]), download: z.boolean().optional(), // galleries gallery: GalleryConfigsSchema.default({}).default(Object.fromEntries( ["renderings", "gallery", "components", "configurations", "showcase", "samples"].map(key => [key, { glob: [IMAGES_GLOB] }]) )), // nesting components: z.array(z.lazy(() => ComponentConfigSchema)).optional().default([]), // @deprecated howto_categories: z.union([z.string(), z.array(z.string())]).optional(), steps: z.any().optional(), sourceLanguage: z.string().optional(), category: z.string(), product_dimensions: z.string().optional(), production: ProductionSchema.optional(), score: z.number().optional() }).merge(ContentSchema).passthrough() export type IComponentConfig = z.infer export type ICADNodeSchema = z.infer export interface IComponentNode { rel: string path: string config: IComponentConfig }