UNPKG

yandex-market-language

Version:

Your own Yandex Market Language (YML) generator, with blackjack and validation

160 lines (143 loc) 11.4 kB
const t = require('tcomb') const r = require('./refinements') // A validation schemas for Yandex Market Language (YML) const Cpa = t.enums.of([0, 1]) const Adult = t.Boolean const DeliveryOptions = r.Maxlength(5)(t.list(t.interface({ cost: t.Integer, days: t.union([t.enums.of(['']), t.Integer, t.tuple([t.Integer, t.Integer])]), // @todo maxvalue 31, output range as `"2-4"`, max interval 3 days 'order-before': t.maybe(t.Integer) // @todo max 24 }, { name: 'Delivery Options', strict: true }), 'DeliveryOptionsObject')) const PriceObject = t.interface({ from: t.Boolean, // @todo Allowed only for specific categories value: t.Number }, { name: 'PriceObject', strict: true }) // @todo Don't like that part, it involves repetition const Price = t.union([t.Number, PriceObject]) Price.dispatch = (x) => t.Number.is(x) ? t.Number : PriceObject const CurrencyId = t.enums.of(['RUB', 'RUR', 'UAH', 'BYN', 'KZT', 'USD', 'EUR']) const Currencies = t.list(t.interface({ id: CurrencyId, // @todo В качестве основной валюты (для которой установлено rate="1") могут быть использованы только рубль (RUR, RUB), белорусский рубль (BYN), гривна (UAH) или тенге (KZT). rate: t.maybe(t.union([t.Number, t.enums.of(['CBRF', 'NBU', 'NBK', 'СВ'])])), plus: t.maybe(t.Number) }, { name: 'Currency', strict: true }), 'CurrenciesObject') const Categories = t.list(t.interface({ id: r.Maxlength(32)(t.String), // @todo can't be 0 parentId: t.maybe(t.String), // @todo should exist in current list name: t.String }, { name: 'Category', strict: true }), 'CategoriesObject') const BaseOffer = t.interface({ // attributes id: r.Maxlength(20)(t.String), // @todo only number and latin chars, should be unique among other offers available: t.maybe(t.Boolean), // Seems to be not used, when delivery-options specified bid: t.maybe(t.Integer), cbid: t.maybe(t.Integer), fee: t.maybe(t.Integer), group_id: t.maybe(r.Maxlength(9)(t.String)), // end attributes url: t.maybe(r.Maxlength(512)(r.Absoluteurl)), // @todo if contains non-latin chars, should be http, not https, or encoded price: Price, oldprice: t.maybe(t.Number), // @todo Should be higher than `Offer.price` currencyId: CurrencyId, categoryId: r.Maxlength(18)(t.String), // @todo JPEG or PNG only), mandatory for some categories picture: t.maybe(r.Maxlength(10)(t.list(r.Maxlength(512)(t.refinement(r.Absoluteurl, (p) => r.Imagepath.is(p), 'Absoluteurl with Imagepath' ))))), store: t.maybe(t.Boolean), pickup: t.maybe(t.Boolean), delivery: t.maybe(t.Boolean), outlets: t.maybe(t.list(t.interface({ id: t.String, instock: t.maybe(t.Integer), booking: t.maybe(t.Boolean) }, { name: 'OutletsObject', strict: true }))), 'delivery-options': t.maybe(DeliveryOptions), // @todo dissalows words «скидка», «распродажа», «дешевый», «подарок» (кроме подарочных категорий), «бесплатно», «акция», «специальная цена», «только», «новинка», «new», «аналог», «заказ», «хит»; // dissalows urls, emails; // allows only tags <h3>...</h3>, <ul><li>...</li></ul>, <p>...</p>, <br/> encloused into `<![CDATA[Текст с использованием xhtml-разметки]]>`` description: t.maybe(r.Maxlength(3000)(t.String)), sales_notes: t.maybe(r.Maxlength(50)(t.String)), 'min-quantity': t.maybe(t.Integer), 'step-quantity': t.maybe(t.Integer), manufacturer_warranty: t.maybe(t.Boolean), // @see https://cache-mskdataline04.cdn.yandex.net/download.cdn.yandex.net/support/ru/partnermarket/files/countries.pdf country_of_origin: t.maybe(t.enums.of(['Австралия', 'Австрия', 'Азербайджан', 'Албания', 'Алжир', 'Американские Виргинские острова', 'Ангилья', 'Ангола', 'Андорра', 'Антигуа и Барбуда', 'Аргентина', 'Армения', 'Аруба', 'Афганистан', 'Багамские острова', 'Бангладеш', 'Барбадос', 'Бахрейн', 'Беларусь', 'Белиз', 'Бельгия', 'Бенин', 'Бермудские Острова', 'Болгария', 'Боливия', 'Босния и Герцеговина', 'Ботсвана', 'Бразилия', 'Британские Виргинские острова', 'Бруней', 'Буркина-Фасо', 'Бурунди', 'Бутан', 'Вануату', 'Ватикан', 'Великобритания', 'Венгрия', 'Венесуэла', 'Восточный Тимор', 'Вьетнам', 'Габон', 'Гайана', 'Гаити', 'Гамбия', 'Гана', 'Гваделупа', 'Гватемала', 'Гвинея', 'Гвинея-Бисау', 'Германия', 'Гибралтар', 'Гондурас', 'Гонконг', 'Гренада', 'Гренландия', 'Греция', 'Грузия', 'Дания', 'Демократическая Республика Конго', 'Джибути', 'Доминика', 'Доминиканская Республика', 'Египет', 'Замбия', 'Западная Сахара', 'Зимбабве', 'Йемен', 'Израиль', 'Индия', 'Индонезия', 'Иордания', 'Ирак', 'Иран', 'Ирландия', 'Исландия', 'Испания', 'Италия', 'Кабо-Верде', 'Казахстан', 'Каймановы острова', 'Камбоджа', 'Камерун', 'Канада', 'Катар', 'Кения', 'Кипр', 'Киргизия', 'Кирибати', 'Китай', 'Колумбия', 'Коморские острова', 'Коста-Рика', 'Кот-д’Ивуар', 'Куба', 'Кувейт', 'Лаос', 'Латвия', 'Лесото', 'Либерия', 'Ливан', 'Ливия', 'Литва', 'Лихтенштейн', 'Люксембург', 'Маврикий', 'Мавритания', 'Мадагаскар', 'Майотта', 'Макао', 'Македония', 'Малави', 'Малайзия', 'Мали', 'Мальдивы', 'Мальта', 'Марокко', 'Маршалловы острова', 'Мексика', 'Мозамбик', 'Молдова', 'Монако', 'Монголия', 'Мьянма', 'Намибия', 'Науру', 'Непал', 'Нигер', 'Нигерия', 'Нидерланды', 'Никарагуа', 'Новая Зеландия', 'Новая Каледония', 'Норвегия', 'Объединённые Арабские Эмираты', 'Оман', 'Острова Кука', 'Пакистан', 'Палау', 'Панама', 'Папуа - Новая Гвинея', 'Парагвай', 'Перу', 'Польша', 'Португалия', 'Республика Конго', 'Реюньон', 'Россия', 'Руанда', 'Румыния', 'Самоа', 'Сан-Марино', 'Сан-Томе и Принсипи', 'Саудовская Аравия', 'Свазиленд', 'Северная Корея', 'Сейшельские острова', 'Сенегал', 'Сент-Винсент и Гренадины', 'Сент-Китс и Невис', 'Сент-Люсия', 'Сербия', 'Сингапур', 'Сирия', 'Словакия', 'Словения', 'Сомали', 'Судан', 'Суринам', 'США', 'Сьерра-Леоне', 'Таджикистан', 'Таиланд', 'Танзания', 'Тёркс и Кайкос', 'Того', 'Тонга', 'Тринидад и Тобаго', 'Тувалу', 'Тунис', 'Туркменистан', 'Турция', 'Уганда', 'Узбекистан', 'Украина', 'Уругвай', 'Федеративные Штаты Микронезии', 'Фиджи', 'Филиппины', 'Финляндия', 'Франция', 'Французская Гвиана', 'Французская Полинезия', 'Хорватия', 'Центрально-Африканская Республика', 'Чад', 'Черногория', 'Чехия', 'Чили', 'Швейцария', 'Швеция', 'Шри-Ланка', 'Эквадор', 'Экваториальная Гвинея', 'Эритрея', 'Эстония', 'Эфиопия', 'ЮАР', 'Южная Корея', 'Ямайка', 'Япония'])), adult: t.maybe(Adult), age: t.maybe(t.interface({ unit: t.enums.of(['year', 'month']), value: t.enums.of([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) // @todo For unit=year only 0, 6, 12, 16, 18 allowed }, { name: 'AgeObject', strict: true })), barcode: t.maybe(t.list(r.Maxlength(12)(t.String))), // @todo can contains only numbers, without any other chars. Conforms to standards EAN-13, EAN-8, UPC-A, UPC-E cpa: t.maybe(Cpa), // @see https://yandex.ru/support/partnermarket/param.html for recommended params and their units param: t.maybe(t.list(t.interface({ name: t.String, unit: t.maybe(t.String), // @todo mandatory if value numeric value: t.union([t.String, t.Number]) }, { name: 'ParamObject', strict: true }))), expiry: t.maybe(t.String), // @todo should be in ISO8601 weight: t.maybe(t.Number), dimensions: t.maybe(t.tuple([t.Number, t.Number, t.Number])), downloadable: t.maybe(t.Boolean), // @todo only ints and latin chars // ids should be enlisted in that file rec: t.maybe(r.Maxlength(30)(t.list(r.Maxlength(20)(t.String)))), vat: t.maybe(t.enums.of([2, 'VAT_10', 4, 'VAT_10_110', 5, 'VAT_0', 6, 'NO_VAT', 7, 'VAT_20'])) }, { name: 'Offer', strict: true }) // @todo Add support for special types: // https://yandex.ru/support/partnermarket/export/books.html // https://yandex.ru/support/partnermarket/export/audiobooks.html // https://yandex.ru/support/partnermarket/export/music-video.html // https://yandex.ru/support/partnermarket/export/medicine.html // https://yandex.ru/support/partnermarket/export/event-tickets.html // https://yandex.ru/support/partnermarket/export/tours.html const SimplifiedOffer = BaseOffer.extend({ name: r.Maxlength(120)(t.String), model: t.maybe(t.String), vendor: t.maybe(t.String), vendorCode: t.maybe(t.String) }, { name: 'SimplifiedOffer', strict: true }) const FreeOffer = BaseOffer.extend({ // attributes type: t.enums.of(['vendor.model']), // end attributes typePrefix: t.maybe(t.String), model: t.String, vendor: t.String, vendorCode: t.maybe(t.String) }, { name: 'FreeOffer', strict: true }) const Offer = t.union([FreeOffer, SimplifiedOffer], 'Offer') Offer.dispatch = (x) => x.type || x.typePrefix ? FreeOffer : SimplifiedOffer const Offers = t.list(Offer, 'Offers') const YML = t.interface({ name: r.Maxlength(20)(t.String), company: t.String, url: r.Maxlength(50)(r.Absoluteurl), platform: t.maybe(t.String), // mostly not needed version: t.maybe(t.String), // mostly not needed agency: t.maybe(t.String), // mostly not needed email: t.maybe(t.String), // mostly not needed // @todo r.Email currencies: Currencies, categories: Categories, 'delivery-options': DeliveryOptions, cpa: t.maybe(Cpa), adult: t.maybe(Adult), offers: Offers }, { name: 'YML', strict: true }) module.exports = { Cpa, Adult, DeliveryOptions, CurrencyId, Currencies, Categories, Offer, Offers, YML }