diff --git a/package.json b/package.json index e8b3f54c..08b3c986 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "eslint-config-qiwi": "^1.13.1", "jest": "^27.0.4", "jest-esm-transformer": "^1.0.0", + "jsdoc": "^3.6.7", "prettier": "^2.3.1", "prettier-config-qiwi": "^1.4.1", "terser": "^5.3.7", @@ -36,7 +37,9 @@ }, "dependencies": { "@11ty/eleventy": "^0.12.1", + "ajv": "^8.6.0", "csv-parse": "^4.12.0", + "find-cache-dir": "^3.3.1", "fs-extra": "^10.0.0", "globby": "^11.0.4", "html-minifier": "^4.0.0", diff --git a/radar data/tech-radar-ios.csv b/radar data/tech-radar-ios.csv new file mode 100644 index 00000000..7abf9589 --- /dev/null +++ b/radar data/tech-radar-ios.csv @@ -0,0 +1,84 @@ +title +QIWI iOS Tech Radar +=== +date +21-06-2021 +=== +name,quadrant,ring,description +Дизайн-система,tech,adopt, +Модульная архитектура,tech,adopt, +Continuous delivery,tech,adopt,"Каждый спринт отправляем сборки в стор, с помощью teamcity и прохождения автоматических автотестов" +Continuous integration,tech,adopt,"Каждый пулл реквест проверяется автоматическими чеками: swiftLint, unit tests, smoke ui tests" +MVVM,tech,adopt,Паттерн проектирования +REST,tech,adopt,REST (от англ. Representational State Transfer — «передача состояния представления») — архитектурный стиль взаимодействия компонентов распределённого приложения в сети. +SOA,tech,adopt,Service-oriented architecture +SOLID,tech,adopt,Мнемонический акроним для 5 основных принципов объектно-ориентированного программирования и проектирования. +UI tests,tech,adopt,Каждая фича покрывается UI тестами +Unit tests,tech,adopt,Каждая фича покрывается unit тестами +GraphQL,tech,ASSESS,A query language for APIs and a runtime for fulfilling those queries with your existing data +Redux,tech,ASSESS,Архитектурный паттерн +Composable architecture,tech,HOLD,Архитектурный паттерн +Appium,Tools,ADOPT,Tool for automation UI tests +Confluence,Tools,ADOPT,Wiki +Fastlane,Tools,ADOPT,"Тул для автоматизации CI/CD и других штук, которые гоняем в Team City" +Figma,Tools,ADOPT,"В ней дизайнеры накидыват интерфейсы, а мы затаскиваем их к себе в проект" +Github,Tools,ADOPT,Система контроля версий исползуемая в основном frontend'ового кода. +Intellij idea,Tools,ADOPT,IDE для разработки на Java/Kotlin +Jira,Tools,ADOPT,Bug tracker +Kaiten,Tools,ADOPT,Система управления задачами +Kibana,Tools,ADOPT,Визуализация логов +SwiftLint,Tools,ADOPT,Linter for Swift code +Tableau,Tools,ADOPT,Решение для построения дашбордов +TeamCity,Tools,ADOPT,Сервер для CI/CD +TestFlight,Tools,ADOPT,Share test builds for testers +Xcode,Tools,ADOPT,IDE для разработки под iOS +Grafana,Tools,TRIAL,Решение для построения дашбордов и мониторинга +Zeplin,Tools,HOLD,"An organized workspace to publish designs, where the entire team can collaborate" +Firebase Crashlytics,Platforms,ADOPT,Креш трекер +Firebase Remote Config,Platforms,ADOPT,"С его помощью делаем фича флаги, раскатываем фичи и проводим A/B тесты" +Google Maps,Platforms,ADOPT,Карта терминалов +Goluber,Platforms,TRIAL,лоток для логов +Yandex AppMetrica,Platforms,TRIAL,Analytics framework +CHIPageControl,Language,ADOPT,A set of cool animated page controls to replace boring UIPageControl +DeviceKit,Language,ADOPT,DeviceKit is a value-type replacement of UIDevice +FormattableTextView,Language,ADOPT,A framework which allows you to format user input according to your mask +InAppProvisioningUtils,Language,ADOPT,Библиотека для работы с Apple Pay в приложении. +KeychainAccess,Language,ADOPT,Keychain framework +Kingfisher,Language,ADOPT,"A powerful, pure-Swift library for downloading and caching images from the web" +MaterialTextView,Language,ADOPT,Реализация текстовых полей по Material Design +Python,Language,ADOPT,Язык программирования +QiwiButtons,Language,ADOPT,Customizable buttons for iOS apps. +SnapKit,Language,ADOPT,DSL to make Auto Layout easy on iOS +SnapshotTesting,Language,ADOPT,Delightful Swift snapshot testing. +Swagger,Language,ADOPT,Фреймворк описания API +Swift,Language,ADOPT,Язык программирования +Swift PM,Language,ADOPT,Менеджер зависимостей +Edna,Language,TRIAL,Фрейморк для чата с пользователями +Kotlin Multiplatform,Language,TRIAL,"Повзоляет писать общий код логики для iOS, Android, JS на едином стеке Kotlin, но пока вдоступна только alfa-версия. На проде одна фича на платформе Android (поиск elasticsearch), в процессе оптимизация под iOs" +SwagGen,Language,TRIAL,OpenAPI/Swagger 3.0 Parser and Swift code generator +XCTAssertNoLeak,Language,TRIAL,Фреймворк для обнаружения утечек памяти +Alamofire,Language,ASSESS,An HTTP networking library written in Swift +Apollo GraphQL,Language,ASSESS,GraphQL framework for Swift +MetricKit,Language,ASSESS,"A framework which aggregates and analyzes per-device reports on exception and crash diagnostics, and on power and performance metrics." +ReactiveCocoa,Language,ASSESS,Фрейморк для реактивного программирования +SwiftUI,Language,ASSESS,UI framework +Swinject,Language,ASSESS,A lightweight dependency injection framework for Swift +Adjust,Language,HOLD,Marketing analytics framework +AFNetworking,Language,HOLD,Network layer framework +Carthage,Language,HOLD,Менеджер зависимостей +CocoaPods,Language,HOLD,Менеджер зависимостей +Combine,Language,HOLD,Reactive framework от Apple +Dwifft,Language,HOLD,"""A small Swift library that tells you what the """"diff"""" is between two collections""" +MBProgressHUD,Language,HOLD,Индикатор загрузки +Objective-C,Language,HOLD,Язык программирования +ReactiveObjc,Language,HOLD,Objective-C фрейморк для реактивного программирования +RxSwift,Language,HOLD,Swift фрейморк для реактивного программирования +SDWebImage,Language,HOLD,Async image downloader with cache support +SwipeCellKit,Language,HOLD,"Swipeable UITableViewCell/UICollectionViewCell based on the stock Mail.app, implemented in Swift" +TTTAttributedLabel,Language,HOLD,"A drop-in replacement for UILabel that supports attributes, data detectors, links, and more" +Typhoon,Language,HOLD,Dependency Injection framework +YapDatabase,Language,HOLD,A collection/key/value store. +=== +quadrant,alias +languages-and-frameworks,Language +Techniques,tech diff --git a/radar data/tech-radar-js.csv b/radar data/tech-radar-js.csv new file mode 100644 index 00000000..56132fa2 --- /dev/null +++ b/radar data/tech-radar-js.csv @@ -0,0 +1,33 @@ +title +QIWI JS Tech Radar +=== +date +21-06-2021 +=== +name,quadrant,ring,description +TypeScript,languages-and-frameworks,Adopt,Статически типизированный ЖС +JavaScript,languages-and-frameworks,Adopt,ЖС +Flow,languages-and-frameworks,Hold,Статически типизированный ЖС +Nestjs,languages-and-frameworks,Trial,Spring для TS +React,languages-and-frameworks,Adopt, +Redux,languages-and-frameworks,Adopt,Стейт-менеджмент провайдер +Rematch,languages-and-frameworks,Trial,Shortcut-flow абстракция над redux +lodash,languages-and-frameworks,Adopt,Стандартаная библиотека +express,languages-and-frameworks,Hold,Мидвары поверх http-server +emotion,languages-and-frameworks,Trial,CSS in JS +jest,languages-and-frameworks,Adopt,Фреймворк для unit автотестов +cypress,languages-and-frameworks,Assess,Фреймворк для e2e тестов +Nodejs,Platforms,Adopt, +Kuber,Platforms,Adopt, +Pijma,Platforms,Trial, +Yarn,Tools,Adopt,Пакетный менеджер вместо npm +semantic-relese,Tools,Trial,"Движение к CD, чтобы катать семантические релизы" +Travis-ci,Tools,Trial,CI для OSS +eslint,Tools,Trial,"Перекатываемся, tslint deprecated скоро" +flp,Tools,Assess,Провайдер клиентских событий +mocha,Tools,Hold,Либа для автотестов +codeclimate,Tools,Trial,Статический анализатор кода +Monorepo,Techniques,Trial,Обобщение кодовой базы на уровне домена продукта +Trunk-based Development,Techniques,Adopt,Фиче-флаги вместо фич-бранчей +Гексагональная архитектура,Techniques,Assess,Унификации контракта интерфейсов различных слоев приложений +OSS,Techniques,Trial,Публичная разработка diff --git a/src/main/js/11ty/.eleventy.cjs b/src/main/js/11ty/.eleventy.cjs index 771d6af4..c276c637 100644 --- a/src/main/js/11ty/.eleventy.cjs +++ b/src/main/js/11ty/.eleventy.cjs @@ -5,8 +5,8 @@ const terser = require('terser') module.exports = (config) => { const pathPrefix = process.env.PATHPREFIX - const tempDir = global._11ty_.temp - const assetsPath = tempDir + '/assets' + const {temp, output, title} = global._11ty_ + const assetsPath = temp + '/assets' config.addPassthroughCopy({ [assetsPath]: '/', }) @@ -27,7 +27,7 @@ module.exports = (config) => { const radarSettings = { ...settings, - title: global._11ty_.title, + title, entries, } @@ -59,8 +59,8 @@ module.exports = (config) => { return { dir: { - input: tempDir, - output: global._11ty_.outDir, + input: temp, + output: output, layouts: '_layouts', }, pathPrefix, diff --git a/src/main/js/constants.js b/src/main/js/constants.js index 8b399964..9a455d27 100644 --- a/src/main/js/constants.js +++ b/src/main/js/constants.js @@ -5,25 +5,34 @@ export const platforms = 'platforms' export const tools = 'tools' export const techniques = 'techniques' -export const quadrantAliases = { - [langAndFw]: langAndFw, - 'languages-and-framework': langAndFw, - language: langAndFw, - lang: langAndFw, - lf: langAndFw, - fw: langAndFw, - framework: langAndFw, - - [platforms]: platforms, - platform: platforms, - pf: platforms, - - [tools]: tools, - tool: tools, +export const tplDir = path.resolve('src/main/tpl') +export const tempDir = 'radar-temp' - [techniques]: techniques, - tech: techniques, +export const radarSchema = { + type: 'object', + properties: { + data: { + type: 'array', + items: { + type: 'object', + properties: { + name: { type: 'string' }, + quadrant: { type: 'string' }, + ring: { type: 'string' }, + description: { type: ['string', 'null'] }, + moved: { type: ['string', 'integer', 'null'] }, + }, + required: ['name', 'quadrant', 'ring', 'description'], + }, + }, + meta: { + type: 'object', + properties: { + title: { type: 'string' }, + date: { type: 'string' }, + legend: { type: ['string', 'null'] }, + }, + required: ['title', 'date'], + }, + }, } - -export const tplDir = path.resolve('src/main/tpl') -export const tempDir = (() => 'temp')() // TODO https://github.com/antongolub/yarn-audit-fix/blob/master/src/main/ts/util.ts#L172 diff --git a/src/main/js/generateMdAssets.js b/src/main/js/generateMdAssets.js index fe01445c..8c2ea5d2 100644 --- a/src/main/js/generateMdAssets.js +++ b/src/main/js/generateMdAssets.js @@ -1,21 +1,28 @@ +import fs from 'fs' import fsExtra from 'fs-extra' import path from 'path' -import { quadrantAliases, tplDir } from './constants.js' +import { tplDir } from './constants.js' +/** + * generate path to .md file + * @param {string} name + * @param {string} quadrant + * @param {string} temp - temp directory + * @returns {string} + */ export function genMdPath({ name, quadrant, temp }) { const entryMdName = name + '.md' - const quadrantAlias = quadrantAliases[quadrant.toLowerCase()] - - if (!quadrantAlias) { - throw new Error( - `Parsing error: invalid quadrant - "${quadrant}" name - "${name}"`, - ) - } - - return path.join(temp, '/entries', quadrantAlias, entryMdName) + return path.join(temp, '/entries', quadrant, entryMdName) } +/** + * generate content .md file + * @param ring + * @param description + * @param moved - optional parameter + * @returns {string} + */ export function genMdContent({ ring, description, moved }) { return `--- ring: ${ring.toLowerCase()} @@ -24,16 +31,29 @@ moved: ${moved || 0} ${description}` } +/** + * generate assets .md files from radarDocument to temp directory + * @param doc - radarDocument + * @param temp - temp directory + */ export const genMdAssets = (doc, temp) => { fsExtra.copySync(tplDir, temp) doc.data.forEach(({ name, quadrant, ring, description, moved }) => { try { - const entryPath = genMdPath({ name, quadrant, temp }) + const quadrantAlias = getQuadrant(quadrant, doc) + const entryPath = genMdPath({ name, quadrant: quadrantAlias, temp }) const content = genMdContent({ ring, description, moved }) - fsExtra.writeFileSync(entryPath, content) + fs.writeFileSync(entryPath, content) } catch (err) { - console.error(err) + console.error('genMdAssets', err) } }) } + +export const getQuadrant = (quadrant, doc) => { + if (!('quadrantAliases' in doc)) return quadrant.toLowerCase() + return doc.quadrantAliases[quadrant.toLowerCase()] + ? doc.quadrantAliases[quadrant.toLowerCase()] + : quadrant.toLowerCase() +} diff --git a/src/main/js/generateStatic.js b/src/main/js/generateStatic.js index 829ee5c6..180fb67a 100644 --- a/src/main/js/generateStatic.js +++ b/src/main/js/generateStatic.js @@ -2,11 +2,22 @@ import Eleventy from '@11ty/eleventy' import fsExtra from 'fs-extra' import path from 'path' -import { tempDir } from './constants.js' +import { radarSchema, tempDir } from './constants.js' import { genMdAssets } from './generateMdAssets.js' +import { validate } from './validator.js' +/** + * generate static sites from array radarDocument + * @param docs + * @param dirs + * @param _output + */ export const genStatics = async (docs, dirs, _output) => docs.reduce(async (r, doc, i) => { + const _m = await r + if (!validate(doc, radarSchema) || Object.keys(doc).length === 0) + return [..._m] + const temp = tempDir const output = dirs[i] ? path.join(_output, dirs[i]) : _output @@ -15,20 +26,24 @@ export const genStatics = async (docs, dirs, _output) => output, temp, } - try { genMdAssets(doc, temp) await genEleventy(temp, output) } catch (err) { - console.error(err) + console.error('genStatics', err) } - return [...(await r), output] + return [..._m, output] }, []) +/** + * generate static site with using 11ty + * @param temp + * @param output + */ export const genEleventy = async (temp, output) => { const elev = new Eleventy(temp, output) elev.setConfigPathOverride('src/main/js/11ty/.eleventy.cjs') await elev.init() await elev.write() - await fsExtra.remove(temp) + fsExtra.removeSync(temp) } diff --git a/src/main/js/index.js b/src/main/js/index.js index 6f4a44fd..7583e2a8 100644 --- a/src/main/js/index.js +++ b/src/main/js/index.js @@ -8,6 +8,12 @@ import { genStatics } from './generateStatic.js' import { read } from './reader.js' import { makeUniq, reverse } from './util.js' +/** + * generate static sites from csv/json/yml files to the output directory + * @param input - globby pattern for input files + * @param output - output directory + * @param cwd - current working directory + */ export const run = async ({ input, output, cwd = process.cwd() } = {}) => { try { // TODO check that `output` is not a dir if exists @@ -18,19 +24,31 @@ export const run = async ({ input, output, cwd = process.cwd() } = {}) => { console.log('statics=', statics) } finally { - await fsExtra.remove(tempDir) + fsExtra.removeSync(tempDir) } } - +/** + * gives array of all file paths matching the globby pattern + * @param input - globby pattern for input files + * @param cwd - current working directory + * @returns {string[]} + */ export const getSources = async (input, cwd) => globby.sync([input], { onlyFiles: true, absolute: true, cwd, }) - +/** + * returns parsed data in radarDocument format + * @param inputs + * @returns {radarDocument[]} + */ export const getDocuments = (inputs) => inputs.map(read) - +/** + * gives unique dirs names for static sites + * @param sources + */ export const getDirs = (sources) => makeUniq(sources.map((s) => s.slice(0, -path.extname(s).length))) .map((s) => reverse(s.split(path.sep)).filter((v) => v)) diff --git a/src/main/js/reader.js b/src/main/js/reader.js index 73704133..908b0566 100644 --- a/src/main/js/reader.js +++ b/src/main/js/reader.js @@ -3,10 +3,24 @@ import fs from 'fs' import yaml from 'js-yaml' import path from 'path' +/** + * read file and generate radarDocument + * @param filePath + * @returns {{data: any[], meta: {}, quadrantAliases?: {}}} radarDocument + */ export const read = (filePath) => { - return getReader(path.extname(filePath))(filePath) + try { + return getReader(path.extname(filePath))(filePath) + } catch (err) { + console.error('filePath:', filePath, err) + return {} + } } - +/** + * selection of the reading function depending on the extension + * @param ext + * @returns {(function(*=): {data: any[], meta: {}})} + */ export const getReader = (ext) => { if (ext === '.csv') { return csvReader @@ -19,13 +33,18 @@ export const getReader = (ext) => { } throw new Error('Unsupported format', ext) } - +/** + * read .csv file and generate radarDocument + * @param csvPath + * @returns {{data: any[], meta: {}, quadrantAliases?: {}}} radarDocument + */ export const csvReader = (csvPath) => { const csvPathResolved = path.resolve(csvPath) const radarContents = fs.readFileSync(csvPathResolved, 'utf8') const radarDocument = { meta: {}, data: [], + quadrantAliases: {}, } radarContents.split('===').forEach((radarChunks) => { const records = parse(radarChunks, { @@ -36,19 +55,33 @@ export const csvReader = (csvPath) => { if (header.includes('name') && header.includes('quadrant')) { radarDocument.data = [...radarDocument.data, ...records] + } else if (header.includes('alias')) { + records.forEach((record) => { + radarDocument.quadrantAliases[record.alias.toLowerCase()] = + record.quadrant.toLowerCase() + }) } else { Object.assign(radarDocument.meta, records[0]) } }) + // console.log('csvPath:', csvPath, radarDocument) return radarDocument } - +/** + * read .json file and generate radarDocument + * @param jsonPath + * @returns {{data: any[], meta: {}}} radarDocument + */ export const jsonReader = (jsonPath) => { const jsonPathResolved = path.resolve(jsonPath) const fileData = fs.readFileSync(jsonPathResolved, 'utf8') return JSON.parse(fileData) } - +/** + * read .yml file and generate radarDocument + * @param yamlPath + * @returns {{data: any[], meta: {}}} radarDocument + */ export const yamlReader = (yamlPath) => { const jsonPathResolved = path.resolve(yamlPath) const yamlData = fs.readFileSync(jsonPathResolved, 'utf8') diff --git a/src/main/js/util.js b/src/main/js/util.js index e47083de..d3092742 100644 --- a/src/main/js/util.js +++ b/src/main/js/util.js @@ -1,3 +1,8 @@ +// import findCacheDir from 'find-cache-dir' +import crypto from 'crypto' +import { ensureDirSync } from 'fs-extra' +import path from 'path' + export const reverse = (arr) => { const _arr = [...arr] _arr.reverse() @@ -15,3 +20,26 @@ export const makeUniq = (arr) => { return count === 1 ? k : `${k}-${count}` }) } + +export const ensureDir = (dir) => { + ensureDirSync(dir) + + return dir +} +/** + * return unique name temp directory + * @param cwd + * @param temp + * @returns {string} + */ +export const getTemp = (cwd, temp) => { + if (temp) { + return ensureDir(path.resolve(temp)) + } + + const id = crypto.randomBytes(16).toString('hex') + // const cacheDir = findCacheDir({ name: '@qiwi__tech-radar', cwd }) + '' + // const tempDir = path.join(cacheDir, id) + const tempDir = id + return ensureDir(tempDir) +} diff --git a/src/main/js/validator.js b/src/main/js/validator.js new file mode 100644 index 00000000..329b987d --- /dev/null +++ b/src/main/js/validator.js @@ -0,0 +1,17 @@ +import Ajv from 'ajv' + +const validators = new Map() +const validate = (target, schema) => { + const validator = validators.get(schema) + if (!validator) { + validators.set(schema, new Ajv().compile(schema)) + return validate(target, schema) + } + + const result = validator(target) + const error = validator.errors + console.error('validator', error) + return result +} + +export { validate } diff --git a/src/test/js/__snapshots__/generateStatic.js.snap b/src/test/js/__snapshots__/generateStatic.js.snap index 65343751..a16996ff 100644 --- a/src/test/js/__snapshots__/generateStatic.js.snap +++ b/src/test/js/__snapshots__/generateStatic.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`generate 11ty app 1`] = ` +exports[`generate 11ty app from .csv file 1`] = ` Array [ "/test/entries/languages-and-frameworks/TypeScript/index.html", "/test/entries/platforms/Nodejs/index.html", @@ -12,3 +12,58 @@ Array [ "/test/radar.js", ] `; + +exports[`generate 11ty app from .json file 1`] = ` +Array [ + "/test/entries/languages-and-frameworks/TypeScript/index.html", + "/test/entries/platforms/Nodejs/index.html", + "/test/entries/techniques/Гексагональная архитектура/index.html", + "/test/entries/tools/codeclimate/index.html", + "/test/favicon.ico", + "/test/index.html", + "/test/radar.css", + "/test/radar.js", +] +`; + +exports[`generate 11ty app from .yml file 1`] = ` +Array [ + "/test/entries/languages-and-frameworks/TypeScript/index.html", + "/test/entries/platforms/Nodejs/index.html", + "/test/entries/techniques/Гексагональная архитектура/index.html", + "/test/entries/tools/codeclimate/index.html", + "/test/favicon.ico", + "/test/index.html", + "/test/radar.css", + "/test/radar.js", +] +`; + +exports[`generate 11ty app from multiple files 1`] = ` +Array [ + "/test/entries/languages-and-frameworks/TypeScript/index.html", + "/test/entries/platforms/Nodejs/index.html", + "/test/entries/techniques/Гексагональная архитектура/index.html", + "/test/entries/tools/codeclimate/index.html", + "/test/favicon.ico", + "/test/index.html", + "/test/radar.css", + "/test/radar.js", + "/test-2/entries/languages-and-frameworks/TypeScript/index.html", + "/test-2/entries/platforms/Nodejs/index.html", + "/test-2/entries/techniques/Гексагональная архитектура/index.html", + "/test-2/entries/tools/codeclimate/index.html", + "/test-2/favicon.ico", + "/test-2/index.html", + "/test-2/radar.css", + "/test-2/radar.js", + "/test-3/entries/languages-and-frameworks/TypeScript/index.html", + "/test-3/entries/platforms/Nodejs/index.html", + "/test-3/entries/techniques/Гексагональная архитектура/index.html", + "/test-3/entries/tools/codeclimate/index.html", + "/test-3/favicon.ico", + "/test-3/index.html", + "/test-3/radar.css", + "/test-3/radar.js", +] +`; diff --git a/src/test/js/__snapshots__/reader.js.snap b/src/test/js/__snapshots__/reader.js.snap index 2c0ef457..3bfbd0bd 100644 --- a/src/test/js/__snapshots__/reader.js.snap +++ b/src/test/js/__snapshots__/reader.js.snap @@ -37,6 +37,9 @@ Object { "legend": "bla bla bla", "title": "work it", }, + "quadrantAliases": Object { + "language": "languages-and-frameworks", + }, } `; @@ -47,7 +50,7 @@ Object { "description": "Статически типизированный ЖС", "moved": "1", "name": "TypeScript", - "quadrant": "language", + "quadrant": "languages-and-frameworks", "ring": "Adopt", }, Object { @@ -117,6 +120,9 @@ Object { "legend": "bla bla bla", "title": "work it", }, + "quadrantAliases": Object { + "language": "languages-and-frameworks", + }, } `; @@ -127,7 +133,7 @@ Object { "description": "Статически типизированный ЖС", "moved": 1, "name": "TypeScript", - "quadrant": "language", + "quadrant": "languages-and-frameworks", "ring": "Adopt", }, Object { @@ -153,7 +159,7 @@ Object { }, ], "meta": Object { - "date": 2021-06-12T00:00:00.000Z, + "date": "2021-06-12", "legend": "bla bla bla", "title": "tech radar js", }, diff --git a/src/test/js/generateStatic.js b/src/test/js/generateStatic.js index 8c46efb7..3f5e20e0 100644 --- a/src/test/js/generateStatic.js +++ b/src/test/js/generateStatic.js @@ -5,32 +5,63 @@ import path from 'path' import { genStatics } from '../../main/js/generateStatic.js' import { getDirs, getDocuments } from '../../main/js/index.js' +export const getFileStruct = (dir, result = []) => { + fs.readdirSync(dir).forEach((elem) => { + const elemPath = dir + '/' + elem + const stat = fs.statSync(elemPath) + if (stat.isDirectory()) { + result = [...getFileStruct(elemPath, result)] + } else { + result.push(elemPath) + } + }) + return result +} + +const genStaticFileStruct = async (input) => { + const docs = getDocuments(input) + const dirs = getDirs(input) + await genStatics(docs, dirs, 'dist') + + const fileStruct = getFileStruct(path.resolve('dist')) + return fileStruct.map((el) => /dist(.+)/.exec(el)[1]) +} + describe('generate 11ty app', () => { - it('', async () => { + it('from .csv file', async () => { const csvPath = path.join(__dirname, '../stub/test.csv') - // const outDir = path.resolve('temp') - const docs = getDocuments([csvPath]) - const dirs = getDirs([csvPath]) - await genStatics(docs, dirs, 'dist') - - const getFileStruct = (dir, result = []) => { - fs.readdirSync(dir).forEach((elem) => { - const elemPath = dir + '/' + elem - const stat = fs.statSync(elemPath) - if (stat.isDirectory()) { - result = [...getFileStruct(elemPath, result)] - } else { - result.push(elemPath) - } - }) - return result - } - const fileStruct = getFileStruct(path.resolve('dist/test')) - const normalizedFileStruct = fileStruct.map((el) => /dist(.+)/.exec(el)[1]) + const normalizedFileStruct = await genStaticFileStruct([csvPath]) expect(normalizedFileStruct).toMatchSnapshot() }) - afterAll(() => { + + afterEach(() => { fsExtra.removeSync(path.resolve('dist')) - fsExtra.removeSync(path.resolve('temp')) + }) + + it('from multiple files', async () => { + const csvPath = path.join(__dirname, '../stub/test.csv') + const jsonPath = path.join(__dirname, '../stub/test.json') + const yamlPath = path.join(__dirname, '../stub/test.yml') + + const normalizedFileStruct = await genStaticFileStruct([ + csvPath, + jsonPath, + yamlPath, + ]) + expect(normalizedFileStruct).toMatchSnapshot() + }) + + it('from .json file', async () => { + const jsonPath = path.join(__dirname, '../stub/test.json') + + const normalizedFileStruct = await genStaticFileStruct([jsonPath]) + expect(normalizedFileStruct).toMatchSnapshot() + }) + + it('from .yml file', async () => { + const yamlPath = path.join(__dirname, '../stub/test.yml') + + const normalizedFileStruct = await genStaticFileStruct([yamlPath]) + expect(normalizedFileStruct).toMatchSnapshot() }) }) diff --git a/src/test/js/index.js b/src/test/js/index.js index b9aceb31..fab2a648 100644 --- a/src/test/js/index.js +++ b/src/test/js/index.js @@ -5,40 +5,62 @@ import { } from '../../main/js/generateMdAssets.js' import { genEleventy, genStatics } from '../../main/js/generateStatic.js' import { getDirs, getDocuments, getSources, run } from '../../main/js/index.js' +import { + csvReader, + getReader, + jsonReader, + read, + yamlReader, +} from '../../main/js/reader.js' import { makeUniq, reverse } from '../../main/js/util.js' describe('has proper exports', () => { it('getSources', function () { - expect(getSources).not.toBeUndefined() + expect(getSources).toBeDefined() }) it('getDocuments', function () { - expect(getDocuments).not.toBeUndefined() + expect(getDocuments).toBeDefined() }) it('getDirs', function () { - expect(getDirs).not.toBeUndefined() + expect(getDirs).toBeDefined() }) it('run', function () { - expect(run).not.toBeUndefined() + expect(run).toBeDefined() }) it('genMdAssets', function () { - expect(genMdAssets).not.toBeUndefined() + expect(genMdAssets).toBeDefined() }) it('genMdContent', function () { - expect(genMdContent).not.toBeUndefined() + expect(genMdContent).toBeDefined() }) it('genMdPath', function () { - expect(genMdPath).not.toBeUndefined() + expect(genMdPath).toBeDefined() }) it('genEleventy', function () { - expect(genEleventy).not.toBeUndefined() + expect(genEleventy).toBeDefined() }) it('genStatics', function () { - expect(genStatics).not.toBeUndefined() + expect(genStatics).toBeDefined() }) it('reverse', function () { - expect(reverse).not.toBeUndefined() + expect(reverse).toBeDefined() }) it('makeUniq', function () { - expect(makeUniq).not.toBeUndefined() + expect(makeUniq).toBeDefined() + }) + it('read', function () { + expect(read).toBeDefined() + }) + it('yamlReader', function () { + expect(yamlReader).toBeDefined() + }) + it('getReader', function () { + expect(getReader).toBeDefined() + }) + it('jsonReader', function () { + expect(jsonReader).toBeDefined() + }) + it('csvReader', function () { + expect(csvReader).toBeDefined() }) }) diff --git a/src/test/js/reader.js b/src/test/js/reader.js index 0e27893a..eb6be7a1 100644 --- a/src/test/js/reader.js +++ b/src/test/js/reader.js @@ -19,9 +19,12 @@ describe('reader.js', () => { it('yamlReader', () => { expect(yamlReader('src/test/stub/test.yml')).toMatchSnapshot() }) - it('getReader ', function () { + it('getReader ', () => { expect(getReader('.csv')).toBe(csvReader) expect(getReader('.json')).toBe(jsonReader) expect(getReader('.yml')).toBe(yamlReader) }) + it('invalid .csv', () => { + expect(read('src/test/stub/invalid.csv')).toStrictEqual({}) + }) }) diff --git a/src/test/js/validator.js b/src/test/js/validator.js new file mode 100644 index 00000000..6a17e8ed --- /dev/null +++ b/src/test/js/validator.js @@ -0,0 +1,44 @@ +import { radarSchema } from '../../main/js/constants.js' +import { validate } from '../../main/js/validator.js' + +describe('validate', () => { + it('validate is not undefined ', () => { + expect(validate).toBeDefined() + }) + it('valid data ', () => { + const obj = { + meta: { + title: '', + date: '', + legend: '', + }, + data: [ + { + name: '', + quadrant: '', + ring: '', + description: '', + moved: '', + }, + ], + } + expect(validate(obj, radarSchema)).toBe(true) + }) + + it('invalid data ', () => { + const obj = { + meta: { + title: '', + }, + data: [ + { + name: '', + quadrant: '', + ring: '', + description: '', + }, + ], + } + expect(validate(obj, radarSchema)).toBe(false) + }) +}) diff --git a/src/test/stub/invalid.csv b/src/test/stub/invalid.csv new file mode 100644 index 00000000..65fb5baa --- /dev/null +++ b/src/test/stub/invalid.csv @@ -0,0 +1,18 @@ +title +not work it +=== +date +2021-06-18 +=== +legend +bla bla bla +=== +name,quadrant,ring,description,moved +TypeScript,language,Adopt,Статически типизированный ЖС,1,,,, +Nodejs,Platforms,Adopt,, +codeclimate,tools,Trial,Статический анализатор кода,0 +Гексагональная архитектура,Techniques,Assess,Унификации контракта интерфейсов различных слоев приложений,-1 +=== +quadrant,alias +languages-and-frameworks,language + diff --git a/src/test/stub/test.csv b/src/test/stub/test.csv index 5861976d..2d4c1993 100644 --- a/src/test/stub/test.csv +++ b/src/test/stub/test.csv @@ -12,4 +12,7 @@ TypeScript,language,Adopt,Статически типизированный ЖС Nodejs,Platforms,Adopt,, codeclimate,tools,Trial,Статический анализатор кода,0 Гексагональная архитектура,Techniques,Assess,Унификации контракта интерфейсов различных слоев приложений,-1 +=== +quadrant,alias +languages-and-frameworks,language diff --git a/src/test/stub/test.json b/src/test/stub/test.json index 801f4030..1cc79595 100644 --- a/src/test/stub/test.json +++ b/src/test/stub/test.json @@ -7,7 +7,7 @@ "data":[ { "name": "TypeScript", - "quadrant": "language", + "quadrant": "languages-and-frameworks", "ring": "Adopt", "description": "Статически типизированный ЖС", "moved": "1" diff --git a/src/test/stub/test.yml b/src/test/stub/test.yml index 2b7c9a18..2410b2f0 100644 --- a/src/test/stub/test.yml +++ b/src/test/stub/test.yml @@ -1,11 +1,11 @@ meta: - "title": tech radar js - "date": 2021-06-12 - "legend": bla bla bla + title: tech radar js + date: "2021-06-12" + legend: bla bla bla data: - name: TypeScript - quadrant: language + quadrant: languages-and-frameworks ring: Adopt description: Статически типизированный ЖС moved: 1 diff --git a/yarn.lock b/yarn.lock index ff5459b7..f818f2b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -228,7 +228,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.7.2": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.7.2", "@babel/parser@^7.9.4": version "7.14.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.7.tgz#6099720c8839ca865a2637e6c85852ead0bdb595" integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA== @@ -900,7 +900,7 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: +ajv@^8.0.1, ajv@^8.6.0: version "8.6.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.0.tgz#60cc45d9c46a477d80d92c48076d972c342e5720" integrity sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ== @@ -1200,6 +1200,11 @@ blob@0.0.5: resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1366,6 +1371,13 @@ caniuse-lite@^1.0.30001219: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz#66e8669985bb2cb84ccb10f68c25ce6dd3e4d2b8" integrity sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ== +catharsis@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.9.0.tgz#40382a168be0e6da308c277d3a2b3eb40c7d2121" + integrity sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A== + dependencies: + lodash "^4.17.15" + chalk@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" @@ -1528,6 +1540,11 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -2413,6 +2430,15 @@ finalhandler@1.1.0: statuses "~1.3.1" unpipe "~1.0.0" +find-cache-dir@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -2599,7 +2625,7 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== @@ -3597,6 +3623,33 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +js2xmlparser@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/js2xmlparser/-/js2xmlparser-4.0.1.tgz#670ef71bc5661f089cc90481b99a05a1227ae3bd" + integrity sha512-KrPTolcw6RocpYjdC7pL7v62e55q7qOMHvLX1UCLc5AAS8qeJ6nukarEJAF2KL2PZxlbGueEbINqZR2bDe/gUw== + dependencies: + xmlcreate "^2.0.3" + +jsdoc@^3.6.7: + version "3.6.7" + resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.7.tgz#00431e376bed7f9de4716c6f15caa80e64492b89" + integrity sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw== + dependencies: + "@babel/parser" "^7.9.4" + bluebird "^3.7.2" + catharsis "^0.9.0" + escape-string-regexp "^2.0.0" + js2xmlparser "^4.0.1" + klaw "^3.0.0" + markdown-it "^10.0.0" + markdown-it-anchor "^5.2.7" + marked "^2.0.3" + mkdirp "^1.0.4" + requizzle "^0.2.3" + strip-json-comments "^3.1.0" + taffydb "2.6.2" + underscore "~1.13.1" + jsdom@^16.6.0: version "16.6.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.6.0.tgz#f79b3786682065492a3da6a60a4695da983805ac" @@ -3730,6 +3783,13 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" + integrity sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g== + dependencies: + graceful-fs "^4.1.9" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -3845,7 +3905,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash@^4.17.10, lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3882,7 +3942,7 @@ luxon@^1.26.0: resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.27.0.tgz#ae10c69113d85dab8f15f5e8390d0cbeddf4f00f" integrity sha512-VKsFsPggTA0DvnxtJdiExAucKdAnwbCCNlMM5ENvHlxubqWd0xhZcdb4XgZ7QFNhaRhilXCFxHuoObP5BNA4PA== -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -3911,6 +3971,11 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== +markdown-it-anchor@^5.2.7: + version "5.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-anchor/-/markdown-it-anchor-5.3.0.tgz#d549acd64856a8ecd1bea58365ef385effbac744" + integrity sha512-/V1MnLL/rgJ3jkMWo84UR+K+jF1cxNG1a+KwqeXqTIJ+jtA8aWSHuigx8lTzauiIjBDbwF3NcWQMotd0Dm39jA== + markdown-it@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-10.0.0.tgz#abfc64f141b1722d663402044e43927f1f50a8dc" @@ -3922,6 +3987,11 @@ markdown-it@^10.0.0: mdurl "^1.0.1" uc.micro "^1.0.5" +marked@^2.0.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-2.1.3.tgz#bd017cef6431724fd4b27e0657f5ceb14bff3753" + integrity sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA== + maximatch@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/maximatch/-/maximatch-0.1.0.tgz#86cd8d6b04c9f307c05a6b9419906d0360fb13a2" @@ -4038,6 +4108,11 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.5" +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + moo@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" @@ -4502,7 +4577,7 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" -pkg-dir@^4.2.0: +pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -4908,6 +4983,13 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +requizzle@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/requizzle/-/requizzle-0.2.3.tgz#4675c90aacafb2c036bd39ba2daa4a1cb777fded" + integrity sha512-YanoyJjykPxGHii0fZP0uUPEXpvqfBDxWV7s6GKAiiOsiqhX6vHNyW3Qzdmqp/iq/ExbhaGbVrjB4ruEVSM4GQ== + dependencies: + lodash "^4.17.14" + reserved-words@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1" @@ -5472,6 +5554,11 @@ table@^6.0.9: string-width "^4.2.0" strip-ansi "^6.0.0" +taffydb@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" + integrity sha1-fLy2S1oUG2ou/CxdLGe04VCyomg= + terminal-link@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" @@ -5687,6 +5774,11 @@ unc-path-regex@^0.1.2: resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= +underscore@~1.13.1: + version "1.13.1" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" + integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== + universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -5899,6 +5991,11 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlcreate@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.3.tgz#df9ecd518fd3890ab3548e1b811d040614993497" + integrity sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ== + xmlhttprequest-ssl@~1.6.2: version "1.6.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"