├── .nvmrc ├── .npmignore ├── .gitignore ├── src ├── repeatingFractions.ts ├── petra │ ├── petra-parser.ts │ ├── petra-convert.ts │ └── petra-keywords.ts ├── numbers.ts ├── convert.ts ├── units.ts └── index.ts ├── test ├── tsconfig.json ├── petra │ └── index.test.ts └── index.test.ts ├── next.config.js ├── .vscode └── settings.json ├── .editorconfig ├── .eslintrc.json ├── tsconfig.json ├── tslint.json ├── package.json ├── README.md ├── yarn-error.log └── yarn.lock /.nvmrc: -------------------------------------------------------------------------------- 1 | 8.9.4 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | lib 4 | testDist 5 | -------------------------------------------------------------------------------- /src/repeatingFractions.ts: -------------------------------------------------------------------------------- 1 | export const repeatingFractions = { 2 | [333]: '1/3', 3 | [666]: '2/3', 4 | [111]: '1/9', 5 | [166]: '1/6', 6 | [833]: '5/6' 7 | } as { [key: string]: string }; 8 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../testDist", 5 | "rootDir": "../" 6 | }, 7 | "include": [ 8 | "./test-typings.d.ts", 9 | "./**/*.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | webpack: (config, { isServer }) => { 3 | // Fixes npm packages that depend on `fs` module 4 | if (!isServer) { 5 | config.node = { 6 | fs: "empty", 7 | }; 8 | } 9 | 10 | return config; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.exclude": { 4 | "**/.git": true, 5 | "**/.svn": true, 6 | "**/.hg": true, 7 | "**/CVS": true, 8 | "**/.DS_Store": true, 9 | "node_modules": true, 10 | "lib": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | 17 | [COMMIT_EDITMSG] 18 | max_line_length = 0 19 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "es6": true, 6 | "mocha": true 7 | }, 8 | "parserOptions": { 9 | "ecmaVersion": 6, 10 | "sourceType": "module" 11 | }, 12 | "plugins": [ 13 | "mocha" 14 | ], 15 | "rules": { 16 | "semi": "error", 17 | "no-extra-boolean-cast": "off", 18 | "no-useless-escape": "off" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "lib": ["es5","es6", "dom", "es2019"], 6 | "sourceMap": true, 7 | "outDir": "./lib", 8 | "rootDir": "./src", 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "noUnusedLocals": true, 15 | "noUnusedParameters": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "baseUrl": "./", 18 | "paths": { 19 | "*": [ 20 | "node_modules/@types/*" 21 | ] 22 | } 23 | }, 24 | "include": [ 25 | "src/**/*.ts" 26 | ], 27 | "exclude": [ 28 | "node_modules" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "arrow-parens": false, 5 | "ban": [true, ["describe", "only"], ["it", "only"]], 6 | "interface-name": [false], 7 | "max-classes-per-file": [false], 8 | "max-line-length": [false], 9 | "member-access": [false], 10 | "member-ordering": [false], 11 | "no-console": [true, "log", "error"], 12 | "no-empty": false, 13 | "no-trailing-whitespace": false, 14 | "no-unused-expression": false, 15 | "no-var-requires": false, 16 | "only-arrow-functions": [false], 17 | "quotemark": [true, "single"], 18 | "trailing-comma": [false], 19 | "variable-name": [false], 20 | "radix": false, 21 | "object-literal-sort-keys": [false], 22 | "ordered-imports": [false] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/petra/petra-parser.ts: -------------------------------------------------------------------------------- 1 | // Petra version to be used in petra application 2 | // Wrapper for the parse method 3 | 4 | import { petraPostprocessing, petraPreprocessing } from "./petra-convert"; 5 | import { parse } from "../"; 6 | import { extractAllUnits } from "../units"; 7 | 8 | export function petraParse( 9 | recipeString: string, 10 | language: string, 11 | keywords?: string[] 12 | ) { 13 | // the unitsMap is a map of language to units. It contains an arar 14 | const unitsArray = extractAllUnits(language); 15 | 16 | recipeString = petraPreprocessing(recipeString, unitsArray, keywords); 17 | const result = parse(recipeString, language); 18 | 19 | result.ingredient = petraPostprocessing(result.ingredient); 20 | return result; 21 | } 22 | 23 | export function petraMultiLineParse(recipeString: string, language: string) { 24 | let ingredients = recipeString.split(/,|👉🏻|👉|\r|\n|-|;/g); 25 | ingredients = ingredients.filter((line) => { 26 | // Verifica se la riga contiene una qualsiasi delle varianti della parola "ingredienti" 27 | if (/ingredient[ei]/i.test(line)) { 28 | return false; 29 | } 30 | // Verifica se la riga contiene solo numeri 31 | if (/^\d+$/.test(line)) { 32 | return false; 33 | } 34 | // Verifica se la riga contiene solo spazi bianchi o è vuota 35 | if (/^\s*$/.test(line)) { 36 | return false; 37 | } 38 | return true; 39 | }); 40 | let result = []; 41 | let i; 42 | for (var ingredient of ingredients) { 43 | i = petraParse(ingredient, language); 44 | if (i["ingredient"]) { 45 | result.push(i); 46 | } 47 | } 48 | return result; 49 | } 50 | -------------------------------------------------------------------------------- /src/petra/petra-convert.ts: -------------------------------------------------------------------------------- 1 | import { getPetraKeywords } from "./petra-keywords"; 2 | 3 | /** 4 | * Process a product string by “underscoring” a product name (a keyword) 5 | * when needed. In our domain the product name might include a number. 6 | * 7 | * In particular, consider these two cases: 8 | * 9 | * 1. "Farina Petra 10 g" 10 | * → No change because the only number ("10") belongs to the quantity. 11 | * 12 | * 2. "Farina Petra 10 10 g" 13 | * → The first "10" is meant to be part of the name. 14 | * The function returns "Farina_Petra_10 10 g". 15 | * 16 | * If no quantity is detected at the end, the function falls back on 17 | * replacing any found keyword (from a predefined list) with its underscored version, 18 | * without changing the order of the words. 19 | * 20 | * @param str The input product string. 21 | * @param units An array of valid unit strings (e.g. ["g", "kg", "ml", "l"]). 22 | * @returns The processed string. 23 | */ 24 | export function petraPreprocessing( 25 | str: string, 26 | units: string[], 27 | _keywords?: string[] 28 | ): string { 29 | // Get keywords list 30 | const keywords = _keywords || getPetraKeywords(); 31 | 32 | units; 33 | 34 | str = str.trim().replace(/^(-)/, "").toLowerCase(); 35 | 36 | // Replace any matching keyword with its underscored version 37 | for (const keyword of keywords) { 38 | if (str.includes(keyword)) { 39 | str = str.replace(keyword, keyword.replace(/ /g, "_")); 40 | break; 41 | } 42 | } 43 | 44 | return str; 45 | } 46 | 47 | export function petraPostprocessing(str: string): string { 48 | return str.replace(/_/g, " "); 49 | } 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recipe-ingredient-parser-v3", 3 | "version": "1.5.0", 4 | "description": "Natural language parser for recipes and ingredient lists, incl. combining ingredients", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "scripts": { 8 | "build": "rm -rf lib && tsc", 9 | "build:test": "rm -rf testDist && tsc -p test/tsconfig.json", 10 | "lint": "tslint \"{./**/*.ts,./**/*.tsx}\" --exclude \"{./node_modules/**,./**/*.d.ts}\"", 11 | "prepublish": "npm run build", 12 | "test": "npm run build:test && NODE_ENV=test mocha testDist/test/**/*.js", 13 | "test:petra": "npm run build:test && NODE_ENV=test mocha testDist/test/petra/**/*.js", 14 | "test:watch": "nodemon --ignore lib --ignore testDist -e ts,tsx -x 'npm run test --silent || true'", 15 | "test:ci": "npm run lint && npm test", 16 | "watch": "nodemon --watch src -e ts,tsx -x 'npm run build'" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/suprmat95/recipe-parser/" 21 | }, 22 | "author": "Matteo D'Ospina ", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/suprmat95/recipe-parser/issues" 26 | }, 27 | "homepage": "https://github.com/suprmat95/recipe-parser#readme", 28 | "devDependencies": { 29 | "@types/chai": "^4.1.4", 30 | "@types/mocha": "^5.2.4", 31 | "chai": "^4.1.0", 32 | "mocha": "^5.2.0", 33 | "ts-node-dev": "^2.0.0", 34 | "tslint": "^5.10.0", 35 | "typescript": "^4.2.3" 36 | }, 37 | "dependencies": { 38 | "@types/node": "^10.5.1" 39 | }, 40 | "keywords": [ 41 | "recipe", 42 | "parser", 43 | "ingredient", 44 | "combine", 45 | "units" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /src/petra/petra-keywords.ts: -------------------------------------------------------------------------------- 1 | // Example keywords (order matters: longer keywords must be first) 2 | 3 | const petraKeywords = [ 4 | "petra 00", 5 | "petra 1", 6 | "petra 3", 7 | "petra 5", 8 | "petra 9", 9 | "petra 1 hp", 10 | "petra 3 hp", 11 | "petra 9 hp", 12 | "petra 8610 hp", 13 | "petra 0101 hp", 14 | "petra 0103 hp", 15 | "petra 0104 hp", 16 | "petra 0105 hp", 17 | "petra 0106 hp", 18 | "petra 0 hp", 19 | "petra 0107 hp", 20 | "petra 1110", 21 | "petra 1111", 22 | "petra 1119", 23 | "petra 0415", 24 | "petra evolutiva 0201", 25 | "petra maiorca 0202", 26 | "petra 5046", 27 | "petra 5063", 28 | "petra 5037", 29 | "petra 5020", 30 | "petra 5078", 31 | "petra 5072", 32 | "petra 5010", 33 | "petra 5009", 34 | "petra 0102 hp", 35 | "petra 0001 - zero glutine 1", 36 | "petra 0003 - zero glutine 3", 37 | "petra 0005 - zero glutine 5", 38 | "petra 0006", 39 | "zero peso 0008", 40 | "petra 0009 - zero glutine 9", 41 | "petra 6379", 42 | "petra 6320", 43 | "petra 6388", 44 | "petra 6390", 45 | "petra 6384", 46 | "petra 6305", 47 | "petra 0007", 48 | "petra 7210", 49 | "petra 7230", 50 | "petra 7220", 51 | "petra 7250", 52 | "petra 8612", 53 | "petra 8610", 54 | "petra 5009", 55 | "petra 1", 56 | "petra 3", 57 | "petra 5", 58 | "petra 9", 59 | "petra 6384", 60 | "petra 6390", 61 | "petra 1111", 62 | "petra 1119", 63 | "petra 5063", 64 | "petra 0101 hp", 65 | "petra 0102 hp", 66 | "petra 1110", 67 | "241 brick", 68 | "0000 genesis", 69 | "601 brick", 70 | "52 brick", 71 | "3220 brick", 72 | "3400 brick", 73 | "430 brick", 74 | "3130 brick", 75 | "25 brick", 76 | "0115 brick", 77 | ]; 78 | // push "farina " to each keyword along side current strings 79 | petraKeywords.push(...petraKeywords.map((keyword) => "farina " + keyword)); 80 | 81 | petraKeywords.sort((a, b) => b.length - a.length); 82 | export function getPetraKeywords() { 83 | return petraKeywords; 84 | } 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # recipe-ingredient-parser-v3 2 | 3 | Natural language parser for recipes and lists of ingredients. Can parse a string into an object and also combine an array of these ingredient objects. 4 | 5 | ## About 6 | 7 | This project was built on top of code written by [nsafai](https://github.com/nsafai/recipe-parser). 8 | 9 | What's different from the original? 10 | 11 | - added support for the Italian language. 12 | - added support for numbers written in words (for example `six cups milk`) 13 | - added support for preposition before name of ingredient (for example `six cups of milk` or `sei tazze di latte`) 14 | 15 | ## To install 16 | 17 | `npm install recipe-ingredient-parser-v3` or `yarn add recipe-ingredient-parser-v3` 18 | 19 | ## To use 20 | 21 | `import { parse } from 'recipe-ingredient-parser-v3';` 22 | 23 | And then use on a string, for example: 24 | `parse('1 teaspoon basil', 'eng');` 25 | or 26 | `parse('1 grammo di zucchero', 'ita');` 27 | 28 | 29 | Will return an object: 30 | 31 | ``` 32 | { 33 | quantity: 1, 34 | unit: 'teaspoon', 35 | ingredient: 'basil', 36 | minQty: 1, 37 | maxQty: 1 38 | }; 39 | ``` 40 | 41 | ### Combine ingredient objects 42 | 43 | ``` 44 | combine([{ 45 | quantity: 1, 46 | unit: 'teaspoon', 47 | ingredient: 'basil', 48 | minQty: 1, 49 | maxQty: 2, 50 | }, 51 | { 52 | quantity: 2, 53 | unit: 'teaspoon', 54 | ingredient: 'basil', 55 | minQty: 2, 56 | maxQty: 2 57 | }]); 58 | ``` 59 | 60 | Will return 61 | 62 | ``` 63 | [{ 64 | quantity: 3, 65 | unit: 'teaspoon', 66 | ingredient: 'basil', 67 | minQty: 3, 68 | maxQty: 4 69 | }] 70 | ``` 71 | 72 | ### Languages supported 73 | 74 | Languages currently supported: 75 | 76 | - English `eng` 77 | - Italian `ita` 78 | 79 | ### Unicode Fractions 80 | 81 | Will also correctly parse unicode fractions into the proper amount 82 | 83 | ### Development 84 | 85 | Clone the repo and `yarn` to install packages. If `yarn test` comes back good after your code changes, give yourself a pat on the back. 86 | 87 | ## Natural Language Parsing 88 | 89 | This project uses Natural, for more information, see https://dzone.com/articles/using-natural-nlp-module 90 | 91 | ### Publishing 92 | 93 | Checkout https://docs.npmjs.com/getting-started/publishing-npm-packages for more info 94 | -------------------------------------------------------------------------------- /src/numbers.ts: -------------------------------------------------------------------------------- 1 | export const engSmall: { [key: string]: number } = { 2 | 'zero': 0, 3 | 'one': 1, 4 | 'two': 2, 5 | 'three': 3, 6 | 'four': 4, 7 | 'five': 5, 8 | 'six': 6, 9 | 'seven': 7, 10 | 'eight': 8, 11 | 'nine': 9, 12 | 'ten': 10, 13 | 'eleven': 11, 14 | 'twelve': 12, 15 | 'thirteen': 13, 16 | 'fourteen': 14, 17 | 'fifteen': 15, 18 | 'sixteen': 16, 19 | 'seventeen': 17, 20 | 'eighteen': 18, 21 | 'nineteen': 19, 22 | 'twenty': 20, 23 | 'thirty': 30, 24 | 'forty': 40, 25 | 'fifty': 50, 26 | 'sixty': 60, 27 | 'seventy': 70, 28 | 'eighty': 80, 29 | 'ninety': 90 30 | }; 31 | 32 | export const engMagnitude: { [key: string]: number } = { 33 | 'hundred': 100, 34 | 'thousand': 1000, 35 | 'million': 1000000, 36 | 'billion': 1000000000, 37 | 'trillion': 1000000000000, 38 | }; 39 | 40 | export const itaSmall: { [key: string]: number } = { 41 | 'zero': 0, 42 | 'mezzo': 0.5, 43 | 'mezza': 0.5, 44 | 'metà': 0.5, 45 | 'meta': 0.5, 46 | 'uno': 1, 47 | 'una': 1, 48 | 'un': 1, 49 | 'due': 2, 50 | 'tre': 3, 51 | 'quattro': 4, 52 | 'cinque': 5, 53 | 'sei': 6, 54 | 'sette': 7, 55 | 'otto': 8, 56 | 'nove': 9, 57 | 'dieci': 10, 58 | 'undici': 11, 59 | 'dodici': 12, 60 | 'dozzina': 12, 61 | 'tredici': 13, 62 | 'quattordici': 14, 63 | 'quindici': 15, 64 | 'sedici': 16, 65 | 'diciassette': 17, 66 | 'diciotto': 18, 67 | 'diciannove': 19, 68 | 'venti': 20, 69 | 'ventuno': 21, 70 | 'trenta': 30, 71 | 'trentuno': 31, 72 | 'quaranta': 40, 73 | 'quarantuno': 41, 74 | 'cinquanta': 50, 75 | 'cinquantuno': 51, 76 | 'sessasanta': 60, 77 | 'sessasantuno': 61, 78 | 'settanta': 70, 79 | 'settantuno': 71, 80 | 'ottanta': 80, 81 | 'ottantuno': 81, 82 | 'novanta': 90, 83 | 'novantuno': 91 84 | 85 | }; 86 | 87 | export const itaMagnitude: { [key: string]: number } = { 88 | 'cento': 100, 89 | 'etto': 100, 90 | 'mille': 1000, 91 | 'mila': 1000, 92 | 'millione': 1000000, 93 | 'milliardo': 1000000000, 94 | 'trilliardo': 1000000000000, 95 | }; 96 | export const toTasteMap: {[key:string]: string } = { 97 | 'eng': 'to taste', 98 | 'ita': 'quanto basta', 99 | }; 100 | export const numbersMap = new Map(); 101 | numbersMap.set("eng",[engSmall, engMagnitude]); 102 | numbersMap.set("ita",[itaSmall, itaMagnitude]); 103 | 104 | -------------------------------------------------------------------------------- /src/convert.ts: -------------------------------------------------------------------------------- 1 | import { numbersMap } from './numbers'; 2 | 3 | export function convertFromFraction(value: string) { 4 | // number comes in, for example: 1 1/3 5 | if (value && value.split(' ').length > 1) { 6 | const [whole, fraction] = value.split(' '); 7 | const [a, b] = fraction.split('/'); 8 | const remainder = parseFloat(a) / parseFloat(b); 9 | const wholeAndFraction = parseInt(whole) ? parseInt(whole) + remainder : remainder; 10 | return keepTwoDecimals(wholeAndFraction); 11 | } else if (!value || value.split('-').length > 1) { 12 | return value; 13 | } else { 14 | const [a, b] = value.split('/'); 15 | return b ? keepTwoDecimals(parseFloat(a) / parseFloat(b)) : a; 16 | } 17 | } 18 | 19 | export function getFirstMatch(line: string, regex: RegExp) { 20 | const match = line.match(regex); 21 | return (match && match[0]) || ''; 22 | } 23 | 24 | const unicodeObj: { [key: string]: string } = { 25 | '½': '1/2', 26 | '⅓': '1/3', 27 | '⅔': '2/3', 28 | '¼': '1/4', 29 | '¾': '3/4', 30 | '⅕': '1/5', 31 | '⅖': '2/5', 32 | '⅗': '3/5', 33 | '⅘': '4/5', 34 | '⅙': '1/6', 35 | '⅚': '5/6', 36 | '⅐': '1/7', 37 | '⅛': '1/8', 38 | '⅜': '3/8', 39 | '⅝': '5/8', 40 | '⅞': '7/8', 41 | '⅑': '1/9', 42 | '⅒': '1/10' 43 | }; 44 | export function text2num(s: string, language: string) { 45 | const a = s.toString().split(/[\s-]+/); 46 | let values: number[] = [0, 0]; 47 | a.forEach(x => { 48 | values = feach(x, values[0], values[1], language) 49 | }); 50 | if (values[0] + values[1] < 0) 51 | return null 52 | else 53 | return values[0] + values[1]; 54 | } 55 | 56 | export function feach(w: string, g: number, n: number, language: string) { 57 | let number = numbersMap.get(language) 58 | let small = number[0] 59 | let magnitude = number[1] 60 | var x = small[w]; 61 | if (x != null) { 62 | g = g + x; 63 | } 64 | else if (100 == magnitude[w]) { 65 | if (g > 0) 66 | g = g * 100; 67 | else 68 | g = 100 69 | } 70 | else { 71 | x = magnitude[w]; 72 | if (x != null) { 73 | n = n + g * x 74 | g = 0; 75 | } 76 | else 77 | return [-1, -1] 78 | 79 | } 80 | return [g, n] 81 | } 82 | 83 | export function findQuantityAndConvertIfUnicode(ingredientLine: string, language: string) { 84 | const numericAndFractionRegex = /\b(\d+\/\d+|\d+\s\d+\/\d+|\d+\.\d+|\d+)\b/g; // consider only the numbers that have space and not those attached to words, such as "petra9" 85 | //const numericRangeWithSpaceRegex = /^(\d+\-\d+)|^(\d+\s\-\s\d+)|^(\d+\sto\s\d+)/g; // for ex: "1 to 2" or "1 - 2" 86 | const unicodeFractionRegex = /\d*[^\u0000-\u007F]+/g; 87 | const onlyUnicodeFraction = /[^\u0000-\u007F]+/g; 88 | const wordUntilSpace = /[^\s]+/g; 89 | 90 | // found a unicode quantity inside our regex, for ex: '⅝' 91 | if (ingredientLine.match(unicodeFractionRegex)) { 92 | const numericPart = getFirstMatch(ingredientLine, numericAndFractionRegex); 93 | const unicodePart = getFirstMatch(ingredientLine, numericPart ? onlyUnicodeFraction : unicodeFractionRegex); 94 | 95 | // If there's a match for the unicodePart in our dictionary above 96 | if (unicodeObj[unicodePart]) { 97 | return [`${numericPart} ${unicodeObj[unicodePart]}`, ingredientLine.replace(getFirstMatch(ingredientLine, unicodeFractionRegex), '').trim()]; 98 | } 99 | } 100 | 101 | // found a quantity range, for ex: "2 to 3" 102 | // if (ingredientLine.match(numericRangeWithSpaceRegex)) { 103 | // const quantity = getFirstMatch(ingredientLine, numericRangeWithSpaceRegex).replace('to', '-').split(' ').join(''); 104 | // const restOfIngredient = ingredientLine.replace(getFirstMatch(ingredientLine, numericRangeWithSpaceRegex), '').trim(); 105 | // return [ingredientLine.match(numericRangeWithSpaceRegex) && quantity, restOfIngredient]; 106 | // } 107 | 108 | // found a numeric/fraction quantity, for example: "1 1/3" 109 | if (ingredientLine.match(numericAndFractionRegex)) { 110 | const quantity = getFirstMatch(ingredientLine, numericAndFractionRegex); 111 | const restOfIngredient = ingredientLine.replace(getFirstMatch(ingredientLine, numericAndFractionRegex), '').trim() 112 | return [ingredientLine.match(numericAndFractionRegex) && quantity, restOfIngredient]; 113 | } 114 | else if (ingredientLine.match(wordUntilSpace)) { 115 | const quantity = getFirstMatch(ingredientLine, wordUntilSpace); 116 | const quantityNumber = text2num(quantity.toLowerCase(), language) 117 | if (quantityNumber) { 118 | const restOfIngredient = ingredientLine.replace(getFirstMatch(ingredientLine, wordUntilSpace), '').trim() 119 | return [ingredientLine.match(wordUntilSpace) && quantityNumber + '', restOfIngredient]; 120 | } 121 | else 122 | return [null, ingredientLine]; 123 | 124 | } 125 | 126 | // no parse-able quantity found 127 | else { 128 | return [null, ingredientLine]; 129 | } 130 | } 131 | 132 | function keepTwoDecimals(val: number) { 133 | const strVal = val.toString(); 134 | return strVal.split('.')[0] + '.' + strVal.split('.')[1].substring(0, 2); 135 | } 136 | -------------------------------------------------------------------------------- /src/units.ts: -------------------------------------------------------------------------------- 1 | export const engUnits = { 2 | bag: ['bag', 'bags'], 3 | box: ['box'], 4 | can: ['can'], 5 | cup: ['cup', 'c', 'c.', 'C', 'Cups'], 6 | clove: ['clove'], 7 | gallon: ['gallon', 'gal'], 8 | ounce: ['ounce', 'oz', 'oz.'], 9 | pint: ['pint', 'pt', 'pts', 'pt.'], 10 | pound: ['pound', 'lb', 'lb.', 'lbs', 'lbs.', 'Lb', 'Lbs'], 11 | quart: ['quart', 'qt', 'qt.', 'qts', 'qts.'], 12 | tablespoon: ['tbs', 'tbsp', 'tbspn', 'T', 'T.', 'Tablespoons', 'Tablespoon'], 13 | teaspoon: ['teaspoon', 'tsp', 'tspn', 't', 't.'], 14 | gram: ['gram', 'g', 'g.'], 15 | kilogram: ['kilogram', 'kg', 'kg.', 'Kg', 'Kg.'], 16 | liter: ['liter', 'l', 'l.', 'lt', 'Lt', 'LT', 'L', 'L.'], 17 | milligram: ['milligram', 'mg', 'mg.'], 18 | milliliter: ['milliliter', 'ml', 'ml.', 'mL', 'mL.'], 19 | package: ['package', 'pkg', 'pkgs'], 20 | stick: ['stick', 'sticks'], 21 | piece: ['piece', 'pcs', 'pcs.'], 22 | pinch: ['pinch'], 23 | small: ['Small'], 24 | slice: ['slice'], 25 | medium: ['Medium'], 26 | large: ['large', 'Large'], 27 | } as { [key: string]: string[] }; 28 | 29 | export const engPluralUnits = { 30 | cup: 'cups', 31 | gallon: 'gallons', 32 | ounce: 'ounces', 33 | pint: 'pints', 34 | pound: 'pounds', 35 | quart: 'quarts', 36 | tablespoon: 'tablespoons', 37 | teaspoon: 'teaspoons', 38 | gram: 'grams', 39 | kilogram: 'kilograms', 40 | liter: 'liters', 41 | milligram: 'milligrams', 42 | milliliter: 'milliliters', 43 | clove: 'cloves', 44 | bag: 'bags', 45 | box: 'boxes', 46 | pinch: 'pinches', 47 | can: 'cans', 48 | slice: 'slices', 49 | piece: 'pieces' 50 | } as { [key: string]: string }; 51 | 52 | export const engNameToSymbol = { 53 | cup: 'c', 54 | gallon: 'gal', 55 | ounce: 'oz', 56 | pint: 'pt', 57 | pound: 'lb', 58 | quart: 'qt', 59 | tablespoon: 'tbs', 60 | teaspoon: 'tsp', 61 | gram: 'g', 62 | kilogram: 'kg', 63 | liter: 'lt', 64 | milligram: 'mg', 65 | milliliter: 'ml', 66 | clove: '', 67 | bag: '', 68 | box: '', 69 | pinch: '', 70 | can: '', 71 | slice: '', 72 | piece: '' 73 | } as { [key: string]: string }; 74 | 75 | export const engPreposition = ['of']; 76 | 77 | 78 | export const itaUnits = { 79 | barattolo: ['barattolo', 'barattoli'], 80 | bicchiere: ['bicchiere'], 81 | bottiglia: ['bottiglie', 'bottiglia'], 82 | bustina: ['bustina', 'bustine'], 83 | cubetto: ['cubetto', 'cubetti'], 84 | cucchiaio: ['cucchiai', 'cucchiaio'], 85 | cucchiaino: ['cucchiaini', 'cucchiaino'], 86 | confezione: ['confezioni', 'confezione'], 87 | grammo: ['g', 'g\\.', 'gr\\.', 'gr', 'grammi', 'grammo'], 88 | chilogrammo: ['kg.', 'kg', 'kilogrammo', 'chilogrammi', 'kilogrammo', 'chilogrammo'], 89 | fetta: ['fetta', 'fette'], 90 | fettina: ['fettina', 'fettine'], 91 | fogliolina: ['fogliolina', 'foglioline'], 92 | foglia: ['foglie', 'foglia'], 93 | foglio: ['fogli', 'foglio'], 94 | gambo: ['gambo', 'gambi'], 95 | litro: ['l\\.', 'l', 'lt', 'litro'], 96 | mazzo: ['mazzo', 'mazzi'], 97 | mazzetto: ['Mazzetto', 'mazzetti', 'mazzetto'], 98 | lattina: ['Lattina', 'lattina'], 99 | milligrammo: ['mg.', 'mg', 'milligrammo'], 100 | millilitro: ['ml', 'ml\\.', 'millilitro'], 101 | panetto: ['Panetto', 'panetti', 'panetto'], 102 | pacco: ['pkg', 'pkgs', 'pacchetto', 'pacco'], 103 | pezzo: ['pezzo', 'pcs', 'pcs.', 'pezzi'], 104 | pizzico: ['pizzico', 'pizzichi'], 105 | tazza: ['tazza', 'tazzina', 'tazzine'], 106 | sacco: ['sacco', 'sacchi'], 107 | spicchio: ['spicchio', 'spicchi'], 108 | scatola: ['scatola', 'scatole'], 109 | vasetto: ['vasetto', 'vasetti'], 110 | filo: ['filo'], 111 | ciuffo: ['ciuffo'], 112 | scatoletta: ['scatoletta'], 113 | manciata: ['manciata'], 114 | rametto: ['rametto', 'rametti'], 115 | rotolo: ['rotolo'], 116 | pugno: ['pugno', 'pugni'], 117 | bicchierino: ['bicchierino'], 118 | 119 | //noce: ['noce'], 120 | } as { [key: string]: string[] }; 121 | 122 | export const itaPluralUnits = { 123 | barattolo: 'barattoli', 124 | bicchiere: 'bicchieri', 125 | bustina: 'bustine', 126 | bottiglia: 'bottiglie', 127 | cubetto: 'cubetti', 128 | gambo: 'gambi', 129 | tazza: 'tazze', 130 | quarto: 'quarti', 131 | cucchiaio: 'cucchiai', 132 | cucchiaino: 'cucchiaini', 133 | confezione: 'confezioni', 134 | grammo: 'grammi', 135 | chilogrammo: 'chilogrammi', 136 | litro: 'litri', 137 | milligrammo: 'milligrammi', 138 | millilitro: 'millilitri', 139 | spicchio: 'spicchi', 140 | scatola: 'scatole', 141 | pizzico: 'pizzichi', 142 | lattina: 'lattine', 143 | fetta: 'fette', 144 | fettina: 'fettine', 145 | pezzo: 'pezzi', 146 | panetto: 'panetti', 147 | foglio: 'fogli', 148 | fogliolina: 'foglioline', 149 | foglia: 'foglie', 150 | mazzo: 'mazzi', 151 | mazzetto: 'mazzetti', 152 | vasetto: 'vasetti', 153 | filo: 'fili', 154 | ciuffo: 'ciuffi', 155 | sacco: 'sacchi', 156 | scatoletta: 'scatolette', 157 | manciata: 'manciate', 158 | rametto: 'rametti', 159 | rotolo: 'rotoli', 160 | bicchierino: 'bicchierini', 161 | pugno: 'pugni' 162 | //noce: 'noci' 163 | } as { [key: string]: string }; 164 | 165 | export const itaNameToSymbol = { 166 | bicchiere: '', 167 | bustina: '', 168 | cubetto: '', 169 | gambo: '', 170 | tazza: '', 171 | quarto: '', 172 | cucchiaio: '', 173 | spicchio: '', 174 | scatola: '', 175 | pizzico: '', 176 | lattina: '', 177 | fetta: '', 178 | pezzo: '', 179 | panetto: '', 180 | foglia: '', 181 | mazzetto: '', 182 | manciata: '', 183 | vasetto: '', 184 | grammo: 'g', 185 | cucchiaino: 'cc', 186 | chilogrammo: 'kg', 187 | litro: 'lt', 188 | milligrammo: 'mg', 189 | millilitro: 'ml', 190 | } as { [key: string]: string }; 191 | 192 | export const itaPreposition = ['di', 'd\'']; 193 | 194 | export const unitsMap = new Map(); 195 | unitsMap.set("eng", [engUnits, engPluralUnits, engPreposition, engNameToSymbol]); 196 | unitsMap.set("ita", [itaUnits, itaPluralUnits, itaPreposition, itaNameToSymbol]); 197 | 198 | export function extractAllUnits(language: string): string[] { 199 | const unitData = unitsMap.get(language); 200 | if (!unitData) return []; 201 | 202 | const flattenedUnits = new Set(); 203 | 204 | for (const data of unitData) { 205 | if (Array.isArray(data)) { 206 | // If it's already an array, add all its elements 207 | data.forEach((unit) => flattenedUnits.add(unit)); 208 | } else if (typeof data === "object") { 209 | // If it's an object (dictionary), extract all values 210 | Object.values(data).forEach((value: any) => { 211 | if (Array.isArray(value)) { 212 | value.forEach((unit) => flattenedUnits.add(unit)); 213 | } else { 214 | flattenedUnits.add(value); 215 | } 216 | }); 217 | } 218 | } 219 | 220 | return Array.from(flattenedUnits); 221 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import * as convert from "./convert"; 2 | import { unitsMap } from "./units"; 3 | import { repeatingFractions } from "./repeatingFractions"; 4 | import { toTasteMap } from "./numbers"; 5 | 6 | //import * as Natural from 'natural'; 7 | 8 | //const nounInflector = new Natural.NounInflector(); 9 | 10 | export interface Ingredient { 11 | ingredient: string; 12 | quantity: string | null; 13 | unit: string | null; 14 | minQty: string | null; 15 | maxQty: string | null; 16 | } 17 | 18 | export function toTasteRecognize(input: string, language: string) { 19 | const toTaste = toTasteMap[language]; 20 | const firstLetter = toTaste.match(/\b(\w)/g); 21 | //componing first two word 22 | //const word = firstWord.concat(' ').concat(secondWord) 23 | 24 | if (firstLetter) { 25 | //checking the extended version 26 | let regEx = new RegExp("\\b" + toTaste + "\\b", "gi"); 27 | if (input.match(regEx)) { 28 | return [ 29 | (firstLetter.join(".") + ".").toLocaleLowerCase(), 30 | convert.getFirstMatch(input, regEx), 31 | true, 32 | ] as [string, string, boolean]; 33 | } 34 | const regExString = firstLetter.join("[.]?") + "[.]?"; 35 | regEx = new RegExp("\\b" + regExString + "\\b", "gi"); 36 | //const a = input.toString().split(/[\s-]+/); 37 | if (input.match(regEx)) { 38 | return [ 39 | (firstLetter.join(".") + ".").toLocaleLowerCase(), 40 | convert.getFirstMatch(input, regEx), 41 | false, 42 | ] as [string, string, boolean]; 43 | } 44 | } 45 | return ["", "", false] as [string, string, boolean]; 46 | } 47 | 48 | function getUnit(input: string, language: string) { 49 | // const word = input.concat(' ').concat(secondWord) 50 | let unit = unitsMap.get(language); 51 | let units = unit[0]; 52 | let pluralUnits = unit[1]; 53 | let symbolUnits = unit[3]; 54 | let response = [] as string[]; 55 | const [toTaste, match, extFlag] = toTasteRecognize(input, language); 56 | // If there is already a unit found for the ingredient, don't add toTaste. Fixes t.t. bug from words with two t's 57 | if (toTaste && !unit) { 58 | if (extFlag) { 59 | response = [toTaste, toTaste, match]; 60 | } else { 61 | response = [toTaste, toTaste, match]; 62 | } 63 | } else { 64 | if (units[input] || pluralUnits[input]) { 65 | response = [input, pluralUnits[input], input]; 66 | } 67 | for (const unit of Object.keys(units)) { 68 | for (const shorthand of units[unit]) { 69 | const regex = new RegExp("(?=\\b" + shorthand + "\\b)", "gi"); 70 | if (input.match(regex)) { 71 | response = [unit, pluralUnits[unit], shorthand]; 72 | } 73 | } 74 | } 75 | for (const pluralUnit of Object.keys(pluralUnits)) { 76 | const regex = new RegExp( 77 | "(?=\\b" + pluralUnits[pluralUnit] + "\\b)", 78 | "gi" 79 | ); 80 | if (input.match(regex)) { 81 | response = [ 82 | pluralUnit, 83 | pluralUnits[pluralUnit], 84 | pluralUnits[pluralUnit], 85 | ]; 86 | } 87 | } 88 | } 89 | let symbol = symbolUnits[response[0]]; 90 | response.splice(2, 0, symbol); 91 | 92 | return response; 93 | } 94 | 95 | /* return the proposition if it's used before of the name of 96 | the ingredient */ 97 | function getPreposition(input: string, language: string) { 98 | let prepositionMap = unitsMap.get(language); 99 | let prepositions = prepositionMap[2]; 100 | for (const preposition of prepositions) { 101 | let regex = new RegExp("^" + preposition); 102 | if (convert.getFirstMatch(input, regex)) return preposition; 103 | } 104 | 105 | return null; 106 | } 107 | 108 | export function parse(recipeString: string, language: string) { 109 | let ingredientLine = recipeString.trim().replace(/^(-)/, "").toLowerCase(); // removes leading and trailing whitespace 110 | /* restOfIngredient represents rest of ingredient line. 111 | For example: "1 pinch salt" --> quantity: 1, restOfIngredient: pinch salt */ 112 | let [quantity, restOfIngredient] = convert.findQuantityAndConvertIfUnicode( 113 | ingredientLine, 114 | language 115 | ) as string[]; 116 | quantity = convert.convertFromFraction(quantity); 117 | /* extraInfo will be any info in parantheses. We'll place it at the end of the ingredient. 118 | For example: "sugar (or other sweetener)" --> extraInfo: "(or other sweetener)" */ 119 | let extraInfo; 120 | if (convert.getFirstMatch(restOfIngredient, /\(([^\)]+)\)/)) { 121 | extraInfo = convert.getFirstMatch(restOfIngredient, /\(([^\)]+)\)/); 122 | restOfIngredient = restOfIngredient.replace(extraInfo, "").trim(); 123 | } 124 | // grab unit and turn it into non-plural version, for ex: "Tablespoons" OR "Tsbp." --> "tablespoon" 125 | let [unit, unitPlural, symbol, originalUnit] = getUnit( 126 | restOfIngredient, 127 | language 128 | ) as string[]; 129 | // remove unit from the ingredient if one was found and trim leading and trailing whitespace 130 | let regex_originalunit = RegExp("\\b" + originalUnit + "\\b", "gi"); 131 | let regex_unit = RegExp("\\b" + unit + "\\b", "gi"); 132 | 133 | let ingredient = !!originalUnit 134 | ? restOfIngredient.replace(regex_originalunit, "").trim() 135 | : restOfIngredient.replace(regex_unit, "").trim(); 136 | ingredient = ingredient.split(".").join("").trim(); 137 | let preposition = getPreposition(ingredient.split(" ")[0], language); 138 | 139 | if (preposition) { 140 | let regex = new RegExp("^" + preposition); 141 | ingredient = ingredient.replace(regex, "").trim(); 142 | } 143 | 144 | let minQty = quantity; // default to quantity 145 | let maxQty = quantity; // default to quantity 146 | 147 | // if quantity is non-nil and is a range, for ex: "1-2", we want to get minQty and maxQty 148 | if (quantity && quantity.includes("-")) { 149 | [minQty, maxQty] = quantity.split("-"); 150 | } 151 | if ((!quantity || quantity == "0") && !unit) { 152 | unit = "q.b."; 153 | unitPlural = "q.b."; 154 | } 155 | return { 156 | quantity: +quantity, 157 | unit: !!unit ? unit : null, 158 | unitPlural: !!unitPlural ? unitPlural : null, 159 | symbol: !!symbol ? symbol : null, 160 | ingredient: extraInfo 161 | ? `${ingredient} ${extraInfo}` 162 | : ingredient.replace(/( )*\.( )*/g, ""), 163 | minQty: +minQty, 164 | maxQty: +maxQty, 165 | }; 166 | } 167 | 168 | export function multiLineParse(recipeString: string, language: string) { 169 | let ingredients = recipeString.split(/,|👉🏻|👉|\r|\n|-|;/g); 170 | ingredients = ingredients.filter((line) => { 171 | // Verifica se la riga contiene una qualsiasi delle varianti della parola "ingredienti" 172 | if (/ingredient[ei]/i.test(line)) { 173 | return false; 174 | } 175 | // Verifica se la riga contiene solo numeri 176 | if (/^\d+$/.test(line)) { 177 | return false; 178 | } 179 | // Verifica se la riga contiene solo spazi bianchi o è vuota 180 | if (/^\s*$/.test(line)) { 181 | return false; 182 | } 183 | return true; 184 | }); 185 | let result = []; 186 | let i; 187 | for (var ingredient of ingredients) { 188 | i = parse(ingredient, language); 189 | if (i["ingredient"]) { 190 | result.push(i); 191 | } 192 | } 193 | return result; 194 | } 195 | 196 | export function combine(ingredientArray: Ingredient[]) { 197 | const combinedIngredients = ingredientArray.reduce((acc, ingredient) => { 198 | const key = ingredient.ingredient + ingredient.unit; // when combining different units, remove this from the key and just use the name 199 | const existingIngredient = acc[key]; 200 | 201 | if (existingIngredient) { 202 | return Object.assign(acc, { 203 | [key]: combineTwoIngredients(existingIngredient, ingredient), 204 | }); 205 | } else { 206 | return Object.assign(acc, { [key]: ingredient }); 207 | } 208 | }, {} as { [key: string]: Ingredient }); 209 | 210 | return Object.keys(combinedIngredients) 211 | .reduce((acc, key) => { 212 | const ingredient = combinedIngredients[key]; 213 | return acc.concat(ingredient); 214 | }, [] as Ingredient[]) 215 | .sort(compareIngredients); 216 | } 217 | 218 | export function prettyPrintingPress(ingredient: Ingredient) { 219 | let quantity = ""; 220 | let unit = ingredient.unit; 221 | if (ingredient.quantity) { 222 | const [whole, remainder] = ingredient.quantity.split("."); 223 | if (+whole !== 0 && typeof whole !== "undefined") { 224 | quantity = whole; 225 | } 226 | if (+remainder !== 0 && typeof remainder !== "undefined") { 227 | let fractional; 228 | if (repeatingFractions[remainder]) { 229 | fractional = repeatingFractions[remainder]; 230 | } else { 231 | const fraction = "0." + remainder; 232 | const len = fraction.length - 2; 233 | let denominator = Math.pow(10, len); 234 | let numerator = +fraction * denominator; 235 | 236 | const divisor = gcd(numerator, denominator); 237 | 238 | numerator /= divisor; 239 | denominator /= divisor; 240 | fractional = Math.floor(numerator) + "/" + Math.floor(denominator); 241 | } 242 | 243 | quantity += quantity ? " " + fractional : fractional; 244 | } 245 | /* if (((+whole !== 0 && typeof remainder !== 'undefined') || +whole > 1) && unit) { 246 | unit = nounInflector.pluralize(unit); 247 | }*/ 248 | } else { 249 | return ingredient.ingredient; 250 | } 251 | 252 | return `${quantity}${unit ? " " + unit : ""} ${ingredient.ingredient}`; 253 | } 254 | 255 | function gcd(a: number, b: number): number { 256 | if (b < 0.0000001) { 257 | return a; 258 | } 259 | 260 | return gcd(b, Math.floor(a % b)); 261 | } 262 | 263 | // TODO: Maybe change this to existingIngredients: Ingredient | Ingredient[] 264 | function combineTwoIngredients( 265 | existingIngredients: Ingredient, 266 | ingredient: Ingredient 267 | ): Ingredient { 268 | const quantity = 269 | existingIngredients.quantity && ingredient.quantity 270 | ? ( 271 | Number(existingIngredients.quantity) + Number(ingredient.quantity) 272 | ).toString() 273 | : null; 274 | const minQty = 275 | existingIngredients.minQty && ingredient.minQty 276 | ? ( 277 | Number(existingIngredients.minQty) + Number(ingredient.minQty) 278 | ).toString() 279 | : null; 280 | const maxQty = 281 | existingIngredients.maxQty && ingredient.maxQty 282 | ? ( 283 | Number(existingIngredients.maxQty) + Number(ingredient.maxQty) 284 | ).toString() 285 | : null; 286 | return Object.assign({}, existingIngredients, { quantity, minQty, maxQty }); 287 | } 288 | 289 | function compareIngredients(a: Ingredient, b: Ingredient) { 290 | if (a.ingredient === b.ingredient) { 291 | return 0; 292 | } 293 | return a.ingredient < b.ingredient ? -1 : 1; 294 | } 295 | -------------------------------------------------------------------------------- /yarn-error.log: -------------------------------------------------------------------------------- 1 | Arguments: 2 | /Users/matteodospina/.nvm/versions/node/v11.10.1/bin/node /usr/local/Cellar/yarn/1.22.10/libexec/bin/yarn.js 3 | 4 | PATH: 5 | /Users/matteodospina/.nvm/versions/node/v11.10.1/bin:/Users/matteodospina/.composer/vendor/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:Users/matteodospina/.composer/vendor/bin:/usr/local/go/bin:/Library/Apple/usr/bin:/Applications/Postgres.app/Contents/Versions/latest/bin:/Users/matteodospina/.nvm/versions/node/v11.10.1/bin:/Users/matteodospina/.composer/vendor/bin 6 | 7 | Yarn version: 8 | 1.22.10 9 | 10 | Node version: 11 | 11.10.1 12 | 13 | Platform: 14 | darwin x64 15 | 16 | Trace: 17 | SyntaxError: /Users/matteodospina/Documents/parser/recipe-parser-matteo/recipe-parser/package.json: Unexpected token } in JSON at position 1390 18 | at JSON.parse () 19 | at /usr/local/Cellar/yarn/1.22.10/libexec/lib/cli.js:1625:59 20 | at Generator.next () 21 | at step (/usr/local/Cellar/yarn/1.22.10/libexec/lib/cli.js:310:30) 22 | at /usr/local/Cellar/yarn/1.22.10/libexec/lib/cli.js:321:13 23 | 24 | npm manifest: 25 | { 26 | "name": "recipe-ingredient-parser-v3", 27 | "version": "1.1.14", 28 | "description": "Natural language parser for recipes and ingredient lists, incl. combining ingredients", 29 | "main": "lib/index.js", 30 | "types": "lib/index.d.ts", 31 | "scripts": { 32 | "build": "rm -rf lib && tsc", 33 | "build:test": "rm -rf testDist && tsc -p test/tsconfig.json", 34 | "lint": "tslint \"{./**/*.ts,./**/*.tsx}\" --exclude \"{./node_modules/**,./**/*.d.ts}\"", 35 | "prepublish": "npm run build", 36 | "test": "npm run build:test && NODE_ENV=test mocha testDist/test/**/*.js", 37 | "test:watch": "nodemon --ignore lib --ignore testDist -e ts,tsx -x 'npm run test --silent || true'", 38 | "test:ci": "npm run lint && npm test", 39 | "watch": "nodemon --watch src -e ts,tsx -x 'npm run build'" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/suprmat95/recipe-parser/" 44 | }, 45 | "author": "Matteo D'Ospina ", 46 | "license": "MIT", 47 | "bugs": { 48 | "url": "https://github.com/suprmat95/recipe-parser/issues" 49 | }, 50 | "homepage": "https://github.com/suprmat95/recipe-parser#readme", 51 | "devDependencies": { 52 | "@types/chai": "^4.1.4", 53 | "@types/mocha": "^5.2.4", 54 | "chai": "^4.1.0", 55 | "mocha": "^5.2.0", 56 | "tslint": "^5.10.0", 57 | "typescript": "^4.2.3" 58 | }, 59 | "dependencies": { 60 | "@types/natural": "^2.1.1", 61 | "@types/node": "^14.14.37", 62 | "natural": "^5.0.1", 63 | }, 64 | "keywords": [ 65 | "recipe", 66 | "parser", 67 | "ingredient", 68 | "combine", 69 | "units" 70 | ] 71 | } 72 | 73 | yarn manifest: 74 | No manifest 75 | 76 | Lockfile: 77 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 78 | # yarn lockfile v1 79 | 80 | 81 | "@babel/code-frame@^7.0.0": 82 | version "7.12.13" 83 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 84 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 85 | dependencies: 86 | "@babel/highlight" "^7.12.13" 87 | 88 | "@babel/helper-validator-identifier@^7.12.11": 89 | version "7.12.11" 90 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 91 | integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== 92 | 93 | "@babel/highlight@^7.12.13": 94 | version "7.13.10" 95 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" 96 | integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== 97 | dependencies: 98 | "@babel/helper-validator-identifier" "^7.12.11" 99 | chalk "^2.0.0" 100 | js-tokens "^4.0.0" 101 | 102 | "@types/chai@^4.1.4": 103 | version "4.2.15" 104 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.15.tgz#b7a6d263c2cecf44b6de9a051cf496249b154553" 105 | integrity sha512-rYff6FI+ZTKAPkJUoyz7Udq3GaoDZnxYDEvdEdFZASiA7PoErltHezDishqQiSDWrGxvxmplH304jyzQmjp0AQ== 106 | 107 | "@types/mocha@^5.2.4": 108 | version "5.2.7" 109 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" 110 | integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== 111 | 112 | "@types/natural@^2.1.1": 113 | version "2.1.1" 114 | resolved "https://registry.yarnpkg.com/@types/natural/-/natural-2.1.1.tgz#761232e1518d7ecb551af63c53e65709de09d8d3" 115 | integrity sha512-FsDESOG70ni89e6DFZHMVvqRWrQWB8H2ad8+10qUAIGA5JX1td0NfSM/qyO4KQVkqOne/8+tNeLTDiDZsH9Dkg== 116 | dependencies: 117 | "@types/node" "*" 118 | 119 | "@types/node@*", "@types/node@^14.14.37": 120 | version "14.14.37" 121 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e" 122 | integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw== 123 | 124 | afinn-165@^1.0.2: 125 | version "1.0.4" 126 | resolved "https://registry.yarnpkg.com/afinn-165/-/afinn-165-1.0.4.tgz#3abf6b8922dd5db84d84e0abd155924381dd73a4" 127 | integrity sha512-7+Wlx3BImrK0HiG6y3lU4xX7SpBPSSu8T9iguPMlaueRFxjbYwAQrp9lqZUuFikqKbd/en8lVREILvP2J80uJA== 128 | 129 | ansi-styles@^3.2.1: 130 | version "3.2.1" 131 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 132 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 133 | dependencies: 134 | color-convert "^1.9.0" 135 | 136 | apparatus@^0.0.10: 137 | version "0.0.10" 138 | resolved "https://registry.yarnpkg.com/apparatus/-/apparatus-0.0.10.tgz#81ea756772ada77863db54ceee8202c109bdca3e" 139 | integrity sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg== 140 | dependencies: 141 | sylvester ">= 0.0.8" 142 | 143 | argparse@^1.0.7: 144 | version "1.0.10" 145 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 146 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 147 | dependencies: 148 | sprintf-js "~1.0.2" 149 | 150 | assertion-error@^1.1.0: 151 | version "1.1.0" 152 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 153 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 154 | 155 | balanced-match@^1.0.0: 156 | version "1.0.0" 157 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 158 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 159 | 160 | brace-expansion@^1.1.7: 161 | version "1.1.11" 162 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 163 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 164 | dependencies: 165 | balanced-match "^1.0.0" 166 | concat-map "0.0.1" 167 | 168 | browser-stdout@1.3.1: 169 | version "1.3.1" 170 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 171 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 172 | 173 | builtin-modules@^1.1.1: 174 | version "1.1.1" 175 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 176 | integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= 177 | 178 | chai@^4.1.0: 179 | version "4.3.4" 180 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" 181 | integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== 182 | dependencies: 183 | assertion-error "^1.1.0" 184 | check-error "^1.0.2" 185 | deep-eql "^3.0.1" 186 | get-func-name "^2.0.0" 187 | pathval "^1.1.1" 188 | type-detect "^4.0.5" 189 | 190 | chalk@^2.0.0, chalk@^2.3.0: 191 | version "2.4.2" 192 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 193 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 194 | dependencies: 195 | ansi-styles "^3.2.1" 196 | escape-string-regexp "^1.0.5" 197 | supports-color "^5.3.0" 198 | 199 | check-error@^1.0.2: 200 | version "1.0.2" 201 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 202 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 203 | 204 | cli@~1.0.0: 205 | version "1.0.1" 206 | resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" 207 | integrity sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ= 208 | dependencies: 209 | exit "0.1.2" 210 | glob "^7.1.1" 211 | 212 | color-convert@^1.9.0: 213 | version "1.9.3" 214 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 215 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 216 | dependencies: 217 | color-name "1.1.3" 218 | 219 | color-name@1.1.3: 220 | version "1.1.3" 221 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 222 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 223 | 224 | commander@2.15.1: 225 | version "2.15.1" 226 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 227 | integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== 228 | 229 | commander@^2.12.1: 230 | version "2.20.3" 231 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 232 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 233 | 234 | concat-map@0.0.1: 235 | version "0.0.1" 236 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 237 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 238 | 239 | console-browserify@1.1.x: 240 | version "1.1.0" 241 | resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" 242 | integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= 243 | dependencies: 244 | date-now "^0.1.4" 245 | 246 | core-util-is@~1.0.0: 247 | version "1.0.2" 248 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 249 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 250 | 251 | date-now@^0.1.4: 252 | version "0.1.4" 253 | resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" 254 | integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= 255 | 256 | debug@3.1.0: 257 | version "3.1.0" 258 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 259 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 260 | dependencies: 261 | ms "2.0.0" 262 | 263 | deep-eql@^3.0.1: 264 | version "3.0.1" 265 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 266 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 267 | dependencies: 268 | type-detect "^4.0.0" 269 | 270 | diff@3.5.0: 271 | version "3.5.0" 272 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 273 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 274 | 275 | diff@^4.0.1: 276 | version "4.0.2" 277 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 278 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 279 | 280 | dom-serializer@0: 281 | version "0.2.2" 282 | resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" 283 | integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== 284 | dependencies: 285 | domelementtype "^2.0.1" 286 | entities "^2.0.0" 287 | 288 | domelementtype@1: 289 | version "1.3.1" 290 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" 291 | integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== 292 | 293 | domelementtype@^2.0.1: 294 | version "2.1.0" 295 | resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.1.0.tgz#a851c080a6d1c3d94344aed151d99f669edf585e" 296 | integrity sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w== 297 | 298 | domhandler@2.3: 299 | version "2.3.0" 300 | resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" 301 | integrity sha1-LeWaCCLVAn+r/28DLCsloqir5zg= 302 | dependencies: 303 | domelementtype "1" 304 | 305 | domutils@1.5: 306 | version "1.5.1" 307 | resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" 308 | integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= 309 | dependencies: 310 | dom-serializer "0" 311 | domelementtype "1" 312 | 313 | entities@1.0: 314 | version "1.0.0" 315 | resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" 316 | integrity sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY= 317 | 318 | entities@^2.0.0: 319 | version "2.2.0" 320 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" 321 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 322 | 323 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 324 | version "1.0.5" 325 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 326 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 327 | 328 | esprima@^4.0.0: 329 | version "4.0.1" 330 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 331 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 332 | 333 | exit@0.1.2, exit@0.1.x: 334 | version "0.1.2" 335 | resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" 336 | integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= 337 | 338 | fs.realpath@^1.0.0: 339 | version "1.0.0" 340 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 341 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 342 | 343 | function-bind@^1.1.1: 344 | version "1.1.1" 345 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 346 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 347 | 348 | get-func-name@^2.0.0: 349 | version "2.0.0" 350 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 351 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 352 | 353 | glob@7.1.2: 354 | version "7.1.2" 355 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 356 | integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== 357 | dependencies: 358 | fs.realpath "^1.0.0" 359 | inflight "^1.0.4" 360 | inherits "2" 361 | minimatch "^3.0.4" 362 | once "^1.3.0" 363 | path-is-absolute "^1.0.0" 364 | 365 | glob@^7.1.1: 366 | version "7.1.6" 367 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 368 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 369 | dependencies: 370 | fs.realpath "^1.0.0" 371 | inflight "^1.0.4" 372 | inherits "2" 373 | minimatch "^3.0.4" 374 | once "^1.3.0" 375 | path-is-absolute "^1.0.0" 376 | 377 | growl@1.10.5: 378 | version "1.10.5" 379 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 380 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 381 | 382 | has-flag@^3.0.0: 383 | version "3.0.0" 384 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 385 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 386 | 387 | has@^1.0.3: 388 | version "1.0.3" 389 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 390 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 391 | dependencies: 392 | function-bind "^1.1.1" 393 | 394 | he@1.1.1: 395 | version "1.1.1" 396 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 397 | integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= 398 | 399 | htmlparser2@3.8.x: 400 | version "3.8.3" 401 | resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" 402 | integrity sha1-mWwosZFRaovoZQGn15dX5ccMEGg= 403 | dependencies: 404 | domelementtype "1" 405 | domhandler "2.3" 406 | domutils "1.5" 407 | entities "1.0" 408 | readable-stream "1.1" 409 | 410 | inflight@^1.0.4: 411 | version "1.0.6" 412 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 413 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 414 | dependencies: 415 | once "^1.3.0" 416 | wrappy "1" 417 | 418 | inherits@2, inherits@~2.0.1: 419 | version "2.0.4" 420 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 421 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 422 | 423 | is-core-module@^2.2.0: 424 | version "2.2.0" 425 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" 426 | integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== 427 | dependencies: 428 | has "^1.0.3" 429 | 430 | isarray@0.0.1: 431 | version "0.0.1" 432 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 433 | integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= 434 | 435 | js-tokens@^4.0.0: 436 | version "4.0.0" 437 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 438 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 439 | 440 | js-yaml@^3.13.1: 441 | version "3.14.1" 442 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" 443 | integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 444 | dependencies: 445 | argparse "^1.0.7" 446 | esprima "^4.0.0" 447 | 448 | jshint@^2.12.0: 449 | version "2.12.0" 450 | resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.12.0.tgz#52e75bd058d587ef81a0e2f95e5cf18eb5dc5c37" 451 | integrity sha512-TwuuaUDmra0JMkuqvqy+WGo2xGHSNjv1BA1nTIgtH2K5z1jHuAEeAgp7laaR+hLRmajRjcrM71+vByBDanCyYA== 452 | dependencies: 453 | cli "~1.0.0" 454 | console-browserify "1.1.x" 455 | exit "0.1.x" 456 | htmlparser2 "3.8.x" 457 | lodash "~4.17.19" 458 | minimatch "~3.0.2" 459 | shelljs "0.3.x" 460 | strip-json-comments "1.0.x" 461 | 462 | json-stable-stringify@^1.0.1: 463 | version "1.0.1" 464 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 465 | integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= 466 | dependencies: 467 | jsonify "~0.0.0" 468 | 469 | jsonify@~0.0.0: 470 | version "0.0.0" 471 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 472 | integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= 473 | 474 | lodash@~4.17.19: 475 | version "4.17.21" 476 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 477 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 478 | 479 | minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: 480 | version "3.0.4" 481 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 482 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 483 | dependencies: 484 | brace-expansion "^1.1.7" 485 | 486 | minimist@0.0.8: 487 | version "0.0.8" 488 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 489 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 490 | 491 | minimist@^1.2.5: 492 | version "1.2.5" 493 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 494 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 495 | 496 | mkdirp@0.5.1: 497 | version "0.5.1" 498 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 499 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 500 | dependencies: 501 | minimist "0.0.8" 502 | 503 | mkdirp@^0.5.1: 504 | version "0.5.5" 505 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 506 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 507 | dependencies: 508 | minimist "^1.2.5" 509 | 510 | mocha@^5.2.0: 511 | version "5.2.0" 512 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" 513 | integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== 514 | dependencies: 515 | browser-stdout "1.3.1" 516 | commander "2.15.1" 517 | debug "3.1.0" 518 | diff "3.5.0" 519 | escape-string-regexp "1.0.5" 520 | glob "7.1.2" 521 | growl "1.10.5" 522 | he "1.1.1" 523 | minimatch "3.0.4" 524 | mkdirp "0.5.1" 525 | supports-color "5.4.0" 526 | 527 | ms@2.0.0: 528 | version "2.0.0" 529 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 530 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 531 | 532 | natural@^5.0.1: 533 | version "5.0.1" 534 | resolved "https://registry.yarnpkg.com/natural/-/natural-5.0.1.tgz#6f21524eeb67cb09f604537cacc44b35c81a784d" 535 | integrity sha512-f/KYLldfYuBlxnSs0r2ROBlxltfgduO7iXKn2/xGL/U+XuKZm75+ph3LENuW0yHw5Rdnl4Wl+0EScc/jvnnlRA== 536 | dependencies: 537 | afinn-165 "^1.0.2" 538 | apparatus "^0.0.10" 539 | jshint "^2.12.0" 540 | json-stable-stringify "^1.0.1" 541 | sylvester "^0.0.12" 542 | underscore "^1.9.1" 543 | wordnet-db "^3.1.11" 544 | 545 | once@^1.3.0: 546 | version "1.4.0" 547 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 548 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 549 | dependencies: 550 | wrappy "1" 551 | 552 | path-is-absolute@^1.0.0: 553 | version "1.0.1" 554 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 555 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 556 | 557 | path-parse@^1.0.6: 558 | version "1.0.6" 559 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 560 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 561 | 562 | pathval@^1.1.1: 563 | version "1.1.1" 564 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 565 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 566 | 567 | readable-stream@1.1: 568 | version "1.1.13" 569 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" 570 | integrity sha1-9u73ZPUUyJ4rniMUanW6EGdW0j4= 571 | dependencies: 572 | core-util-is "~1.0.0" 573 | inherits "~2.0.1" 574 | isarray "0.0.1" 575 | string_decoder "~0.10.x" 576 | 577 | resolve@^1.3.2: 578 | version "1.20.0" 579 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 580 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 581 | dependencies: 582 | is-core-module "^2.2.0" 583 | path-parse "^1.0.6" 584 | 585 | semver@^5.3.0: 586 | version "5.7.1" 587 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 588 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 589 | 590 | shelljs@0.3.x: 591 | version "0.3.0" 592 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" 593 | integrity sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E= 594 | 595 | sprintf-js@~1.0.2: 596 | version "1.0.3" 597 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 598 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 599 | 600 | string_decoder@~0.10.x: 601 | version "0.10.31" 602 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 603 | integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= 604 | 605 | strip-json-comments@1.0.x: 606 | version "1.0.4" 607 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" 608 | integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E= 609 | 610 | supports-color@5.4.0: 611 | version "5.4.0" 612 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 613 | integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== 614 | dependencies: 615 | has-flag "^3.0.0" 616 | 617 | supports-color@^5.3.0: 618 | version "5.5.0" 619 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 620 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 621 | dependencies: 622 | has-flag "^3.0.0" 623 | 624 | "sylvester@>= 0.0.8": 625 | version "0.0.21" 626 | resolved "https://registry.yarnpkg.com/sylvester/-/sylvester-0.0.21.tgz#2987b1ce2bd2f38b0dce2a34388884bfa4400ea7" 627 | integrity sha1-KYexzivS84sNzio0OIiEv6RADqc= 628 | 629 | sylvester@^0.0.12: 630 | version "0.0.12" 631 | resolved "https://registry.yarnpkg.com/sylvester/-/sylvester-0.0.12.tgz#5a884415cd2d002c57e7a3aac99462a75ce9fdb4" 632 | integrity sha1-WohEFc0tACxX56OqyZRip1zp/bQ= 633 | 634 | tslib@^1.8.0, tslib@^1.8.1: 635 | version "1.14.1" 636 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 637 | integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 638 | 639 | tslint@^5.10.0: 640 | version "5.20.1" 641 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" 642 | integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== 643 | dependencies: 644 | "@babel/code-frame" "^7.0.0" 645 | builtin-modules "^1.1.1" 646 | chalk "^2.3.0" 647 | commander "^2.12.1" 648 | diff "^4.0.1" 649 | glob "^7.1.1" 650 | js-yaml "^3.13.1" 651 | minimatch "^3.0.4" 652 | mkdirp "^0.5.1" 653 | resolve "^1.3.2" 654 | semver "^5.3.0" 655 | tslib "^1.8.0" 656 | tsutils "^2.29.0" 657 | 658 | tsutils@^2.29.0: 659 | version "2.29.0" 660 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" 661 | integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== 662 | dependencies: 663 | tslib "^1.8.1" 664 | 665 | type-detect@^4.0.0, type-detect@^4.0.5: 666 | version "4.0.8" 667 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 668 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 669 | 670 | typescript@^4.2.3: 671 | version "4.2.3" 672 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" 673 | integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== 674 | 675 | underscore@^1.9.1: 676 | version "1.12.1" 677 | resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" 678 | integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== 679 | 680 | wordnet-db@^3.1.11: 681 | version "3.1.14" 682 | resolved "https://registry.yarnpkg.com/wordnet-db/-/wordnet-db-3.1.14.tgz#7ba1ec2cb5730393f0856efcc738a60085426199" 683 | integrity sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag== 684 | 685 | wrappy@1: 686 | version "1.0.2" 687 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 688 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 689 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@^7.0.0": 6 | version "7.12.13" 7 | resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" 8 | integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== 9 | dependencies: 10 | "@babel/highlight" "^7.12.13" 11 | 12 | "@babel/helper-validator-identifier@^7.12.11": 13 | version "7.12.11" 14 | resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" 15 | integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== 16 | 17 | "@babel/highlight@^7.12.13": 18 | version "7.13.10" 19 | resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.13.10.tgz#a8b2a66148f5b27d666b15d81774347a731d52d1" 20 | integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg== 21 | dependencies: 22 | "@babel/helper-validator-identifier" "^7.12.11" 23 | chalk "^2.0.0" 24 | js-tokens "^4.0.0" 25 | 26 | "@cspotcode/source-map-support@^0.8.0": 27 | version "0.8.1" 28 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" 29 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== 30 | dependencies: 31 | "@jridgewell/trace-mapping" "0.3.9" 32 | 33 | "@jridgewell/resolve-uri@^3.0.3": 34 | version "3.1.2" 35 | resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" 36 | integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== 37 | 38 | "@jridgewell/sourcemap-codec@^1.4.10": 39 | version "1.5.0" 40 | resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" 41 | integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== 42 | 43 | "@jridgewell/trace-mapping@0.3.9": 44 | version "0.3.9" 45 | resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" 46 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== 47 | dependencies: 48 | "@jridgewell/resolve-uri" "^3.0.3" 49 | "@jridgewell/sourcemap-codec" "^1.4.10" 50 | 51 | "@tsconfig/node10@^1.0.7": 52 | version "1.0.11" 53 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" 54 | integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== 55 | 56 | "@tsconfig/node12@^1.0.7": 57 | version "1.0.11" 58 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" 59 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== 60 | 61 | "@tsconfig/node14@^1.0.0": 62 | version "1.0.3" 63 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" 64 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== 65 | 66 | "@tsconfig/node16@^1.0.2": 67 | version "1.0.4" 68 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" 69 | integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== 70 | 71 | "@types/chai@^4.1.4": 72 | version "4.2.15" 73 | resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.15.tgz#b7a6d263c2cecf44b6de9a051cf496249b154553" 74 | integrity sha512-rYff6FI+ZTKAPkJUoyz7Udq3GaoDZnxYDEvdEdFZASiA7PoErltHezDishqQiSDWrGxvxmplH304jyzQmjp0AQ== 75 | 76 | "@types/mocha@^5.2.4": 77 | version "5.2.7" 78 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" 79 | integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== 80 | 81 | "@types/node@^10.5.1": 82 | version "10.17.56" 83 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.56.tgz#010c9e047c3ff09ddcd11cbb6cf5912725cdc2b3" 84 | integrity sha512-LuAa6t1t0Bfw4CuSR0UITsm1hP17YL+u82kfHGrHUWdhlBtH7sa7jGY5z7glGaIj/WDYDkRtgGd+KCjCzxBW1w== 85 | 86 | "@types/strip-bom@^3.0.0": 87 | version "3.0.0" 88 | resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" 89 | integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== 90 | 91 | "@types/strip-json-comments@0.0.30": 92 | version "0.0.30" 93 | resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" 94 | integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== 95 | 96 | acorn-walk@^8.1.1: 97 | version "8.3.4" 98 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" 99 | integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== 100 | dependencies: 101 | acorn "^8.11.0" 102 | 103 | acorn@^8.11.0, acorn@^8.4.1: 104 | version "8.14.0" 105 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" 106 | integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== 107 | 108 | ansi-styles@^3.2.1: 109 | version "3.2.1" 110 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 111 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 112 | dependencies: 113 | color-convert "^1.9.0" 114 | 115 | anymatch@~3.1.2: 116 | version "3.1.3" 117 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" 118 | integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== 119 | dependencies: 120 | normalize-path "^3.0.0" 121 | picomatch "^2.0.4" 122 | 123 | arg@^4.1.0: 124 | version "4.1.3" 125 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 126 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 127 | 128 | argparse@^1.0.7: 129 | version "1.0.10" 130 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 131 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 132 | dependencies: 133 | sprintf-js "~1.0.2" 134 | 135 | assertion-error@^1.1.0: 136 | version "1.1.0" 137 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" 138 | integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== 139 | 140 | balanced-match@^1.0.0: 141 | version "1.0.0" 142 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 143 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 144 | 145 | binary-extensions@^2.0.0: 146 | version "2.3.0" 147 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" 148 | integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== 149 | 150 | brace-expansion@^1.1.7: 151 | version "1.1.11" 152 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 153 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 154 | dependencies: 155 | balanced-match "^1.0.0" 156 | concat-map "0.0.1" 157 | 158 | braces@~3.0.2: 159 | version "3.0.3" 160 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" 161 | integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== 162 | dependencies: 163 | fill-range "^7.1.1" 164 | 165 | browser-stdout@1.3.1: 166 | version "1.3.1" 167 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 168 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 169 | 170 | buffer-from@^1.0.0: 171 | version "1.1.2" 172 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 173 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 174 | 175 | builtin-modules@^1.1.1: 176 | version "1.1.1" 177 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 178 | integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= 179 | 180 | chai@^4.1.0: 181 | version "4.3.4" 182 | resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" 183 | integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== 184 | dependencies: 185 | assertion-error "^1.1.0" 186 | check-error "^1.0.2" 187 | deep-eql "^3.0.1" 188 | get-func-name "^2.0.0" 189 | pathval "^1.1.1" 190 | type-detect "^4.0.5" 191 | 192 | chalk@^2.0.0, chalk@^2.3.0: 193 | version "2.4.2" 194 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 195 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 196 | dependencies: 197 | ansi-styles "^3.2.1" 198 | escape-string-regexp "^1.0.5" 199 | supports-color "^5.3.0" 200 | 201 | check-error@^1.0.2: 202 | version "1.0.2" 203 | resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" 204 | integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= 205 | 206 | chokidar@^3.5.1: 207 | version "3.6.0" 208 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" 209 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 210 | dependencies: 211 | anymatch "~3.1.2" 212 | braces "~3.0.2" 213 | glob-parent "~5.1.2" 214 | is-binary-path "~2.1.0" 215 | is-glob "~4.0.1" 216 | normalize-path "~3.0.0" 217 | readdirp "~3.6.0" 218 | optionalDependencies: 219 | fsevents "~2.3.2" 220 | 221 | color-convert@^1.9.0: 222 | version "1.9.3" 223 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 224 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 225 | dependencies: 226 | color-name "1.1.3" 227 | 228 | color-name@1.1.3: 229 | version "1.1.3" 230 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 231 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 232 | 233 | commander@2.15.1: 234 | version "2.15.1" 235 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 236 | integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== 237 | 238 | commander@^2.12.1: 239 | version "2.20.3" 240 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 241 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 242 | 243 | concat-map@0.0.1: 244 | version "0.0.1" 245 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 246 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 247 | 248 | create-require@^1.1.0: 249 | version "1.1.1" 250 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 251 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 252 | 253 | debug@3.1.0: 254 | version "3.1.0" 255 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 256 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 257 | dependencies: 258 | ms "2.0.0" 259 | 260 | deep-eql@^3.0.1: 261 | version "3.0.1" 262 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" 263 | integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== 264 | dependencies: 265 | type-detect "^4.0.0" 266 | 267 | diff@3.5.0: 268 | version "3.5.0" 269 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 270 | integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== 271 | 272 | diff@^4.0.1: 273 | version "4.0.2" 274 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 275 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 276 | 277 | dynamic-dedupe@^0.3.0: 278 | version "0.3.0" 279 | resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" 280 | integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== 281 | dependencies: 282 | xtend "^4.0.0" 283 | 284 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 285 | version "1.0.5" 286 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 287 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 288 | 289 | esprima@^4.0.0: 290 | version "4.0.1" 291 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 292 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 293 | 294 | fill-range@^7.1.1: 295 | version "7.1.1" 296 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" 297 | integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== 298 | dependencies: 299 | to-regex-range "^5.0.1" 300 | 301 | fs.realpath@^1.0.0: 302 | version "1.0.0" 303 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 304 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 305 | 306 | fsevents@~2.3.2: 307 | version "2.3.3" 308 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 309 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 310 | 311 | function-bind@^1.1.1: 312 | version "1.1.1" 313 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 314 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 315 | 316 | function-bind@^1.1.2: 317 | version "1.1.2" 318 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 319 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 320 | 321 | get-func-name@^2.0.0: 322 | version "2.0.0" 323 | resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" 324 | integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= 325 | 326 | glob-parent@~5.1.2: 327 | version "5.1.2" 328 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 329 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 330 | dependencies: 331 | is-glob "^4.0.1" 332 | 333 | glob@7.1.2: 334 | version "7.1.2" 335 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 336 | integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== 337 | dependencies: 338 | fs.realpath "^1.0.0" 339 | inflight "^1.0.4" 340 | inherits "2" 341 | minimatch "^3.0.4" 342 | once "^1.3.0" 343 | path-is-absolute "^1.0.0" 344 | 345 | glob@^7.1.1: 346 | version "7.1.6" 347 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 348 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 349 | dependencies: 350 | fs.realpath "^1.0.0" 351 | inflight "^1.0.4" 352 | inherits "2" 353 | minimatch "^3.0.4" 354 | once "^1.3.0" 355 | path-is-absolute "^1.0.0" 356 | 357 | glob@^7.1.3: 358 | version "7.2.3" 359 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 360 | integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== 361 | dependencies: 362 | fs.realpath "^1.0.0" 363 | inflight "^1.0.4" 364 | inherits "2" 365 | minimatch "^3.1.1" 366 | once "^1.3.0" 367 | path-is-absolute "^1.0.0" 368 | 369 | growl@1.10.5: 370 | version "1.10.5" 371 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 372 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 373 | 374 | has-flag@^3.0.0: 375 | version "3.0.0" 376 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 377 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 378 | 379 | has@^1.0.3: 380 | version "1.0.3" 381 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 382 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 383 | dependencies: 384 | function-bind "^1.1.1" 385 | 386 | hasown@^2.0.2: 387 | version "2.0.2" 388 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" 389 | integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== 390 | dependencies: 391 | function-bind "^1.1.2" 392 | 393 | he@1.1.1: 394 | version "1.1.1" 395 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 396 | integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= 397 | 398 | inflight@^1.0.4: 399 | version "1.0.6" 400 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 401 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 402 | dependencies: 403 | once "^1.3.0" 404 | wrappy "1" 405 | 406 | inherits@2: 407 | version "2.0.4" 408 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 409 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 410 | 411 | is-binary-path@~2.1.0: 412 | version "2.1.0" 413 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 414 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 415 | dependencies: 416 | binary-extensions "^2.0.0" 417 | 418 | is-core-module@^2.16.0: 419 | version "2.16.1" 420 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" 421 | integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== 422 | dependencies: 423 | hasown "^2.0.2" 424 | 425 | is-core-module@^2.2.0: 426 | version "2.2.0" 427 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" 428 | integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== 429 | dependencies: 430 | has "^1.0.3" 431 | 432 | is-extglob@^2.1.1: 433 | version "2.1.1" 434 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 435 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 436 | 437 | is-glob@^4.0.1, is-glob@~4.0.1: 438 | version "4.0.3" 439 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 440 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 441 | dependencies: 442 | is-extglob "^2.1.1" 443 | 444 | is-number@^7.0.0: 445 | version "7.0.0" 446 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 447 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 448 | 449 | js-tokens@^4.0.0: 450 | version "4.0.0" 451 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 452 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 453 | 454 | js-yaml@^3.13.1: 455 | version "3.14.1" 456 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" 457 | integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== 458 | dependencies: 459 | argparse "^1.0.7" 460 | esprima "^4.0.0" 461 | 462 | make-error@^1.1.1: 463 | version "1.3.6" 464 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 465 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 466 | 467 | minimatch@3.0.4, minimatch@^3.0.4: 468 | version "3.0.4" 469 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 470 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 471 | dependencies: 472 | brace-expansion "^1.1.7" 473 | 474 | minimatch@^3.1.1: 475 | version "3.1.2" 476 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" 477 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 478 | dependencies: 479 | brace-expansion "^1.1.7" 480 | 481 | minimist@0.0.8: 482 | version "0.0.8" 483 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 484 | integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= 485 | 486 | minimist@^1.2.5: 487 | version "1.2.5" 488 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 489 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 490 | 491 | minimist@^1.2.6: 492 | version "1.2.8" 493 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" 494 | integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== 495 | 496 | mkdirp@0.5.1: 497 | version "0.5.1" 498 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 499 | integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= 500 | dependencies: 501 | minimist "0.0.8" 502 | 503 | mkdirp@^0.5.1: 504 | version "0.5.5" 505 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 506 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 507 | dependencies: 508 | minimist "^1.2.5" 509 | 510 | mkdirp@^1.0.4: 511 | version "1.0.4" 512 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 513 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 514 | 515 | mocha@^5.2.0: 516 | version "5.2.0" 517 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" 518 | integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== 519 | dependencies: 520 | browser-stdout "1.3.1" 521 | commander "2.15.1" 522 | debug "3.1.0" 523 | diff "3.5.0" 524 | escape-string-regexp "1.0.5" 525 | glob "7.1.2" 526 | growl "1.10.5" 527 | he "1.1.1" 528 | minimatch "3.0.4" 529 | mkdirp "0.5.1" 530 | supports-color "5.4.0" 531 | 532 | ms@2.0.0: 533 | version "2.0.0" 534 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 535 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 536 | 537 | normalize-path@^3.0.0, normalize-path@~3.0.0: 538 | version "3.0.0" 539 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 540 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 541 | 542 | once@^1.3.0: 543 | version "1.4.0" 544 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 545 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 546 | dependencies: 547 | wrappy "1" 548 | 549 | path-is-absolute@^1.0.0: 550 | version "1.0.1" 551 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 552 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 553 | 554 | path-parse@^1.0.6: 555 | version "1.0.6" 556 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 557 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 558 | 559 | path-parse@^1.0.7: 560 | version "1.0.7" 561 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 562 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 563 | 564 | pathval@^1.1.1: 565 | version "1.1.1" 566 | resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" 567 | integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== 568 | 569 | picomatch@^2.0.4, picomatch@^2.2.1: 570 | version "2.3.1" 571 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 572 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 573 | 574 | readdirp@~3.6.0: 575 | version "3.6.0" 576 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 577 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 578 | dependencies: 579 | picomatch "^2.2.1" 580 | 581 | resolve@^1.0.0: 582 | version "1.22.10" 583 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" 584 | integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== 585 | dependencies: 586 | is-core-module "^2.16.0" 587 | path-parse "^1.0.7" 588 | supports-preserve-symlinks-flag "^1.0.0" 589 | 590 | resolve@^1.3.2: 591 | version "1.20.0" 592 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 593 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 594 | dependencies: 595 | is-core-module "^2.2.0" 596 | path-parse "^1.0.6" 597 | 598 | rimraf@^2.6.1: 599 | version "2.7.1" 600 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 601 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 602 | dependencies: 603 | glob "^7.1.3" 604 | 605 | semver@^5.3.0: 606 | version "5.7.1" 607 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 608 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 609 | 610 | source-map-support@^0.5.12: 611 | version "0.5.21" 612 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" 613 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 614 | dependencies: 615 | buffer-from "^1.0.0" 616 | source-map "^0.6.0" 617 | 618 | source-map@^0.6.0: 619 | version "0.6.1" 620 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 621 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 622 | 623 | sprintf-js@~1.0.2: 624 | version "1.0.3" 625 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 626 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 627 | 628 | strip-bom@^3.0.0: 629 | version "3.0.0" 630 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 631 | integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== 632 | 633 | strip-json-comments@^2.0.0: 634 | version "2.0.1" 635 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 636 | integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== 637 | 638 | supports-color@5.4.0: 639 | version "5.4.0" 640 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 641 | integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== 642 | dependencies: 643 | has-flag "^3.0.0" 644 | 645 | supports-color@^5.3.0: 646 | version "5.5.0" 647 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 648 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 649 | dependencies: 650 | has-flag "^3.0.0" 651 | 652 | supports-preserve-symlinks-flag@^1.0.0: 653 | version "1.0.0" 654 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 655 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 656 | 657 | to-regex-range@^5.0.1: 658 | version "5.0.1" 659 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 660 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 661 | dependencies: 662 | is-number "^7.0.0" 663 | 664 | tree-kill@^1.2.2: 665 | version "1.2.2" 666 | resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" 667 | integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== 668 | 669 | ts-node-dev@^2.0.0: 670 | version "2.0.0" 671 | resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-2.0.0.tgz#bdd53e17ab3b5d822ef519928dc6b4a7e0f13065" 672 | integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== 673 | dependencies: 674 | chokidar "^3.5.1" 675 | dynamic-dedupe "^0.3.0" 676 | minimist "^1.2.6" 677 | mkdirp "^1.0.4" 678 | resolve "^1.0.0" 679 | rimraf "^2.6.1" 680 | source-map-support "^0.5.12" 681 | tree-kill "^1.2.2" 682 | ts-node "^10.4.0" 683 | tsconfig "^7.0.0" 684 | 685 | ts-node@^10.4.0: 686 | version "10.9.2" 687 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" 688 | integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== 689 | dependencies: 690 | "@cspotcode/source-map-support" "^0.8.0" 691 | "@tsconfig/node10" "^1.0.7" 692 | "@tsconfig/node12" "^1.0.7" 693 | "@tsconfig/node14" "^1.0.0" 694 | "@tsconfig/node16" "^1.0.2" 695 | acorn "^8.4.1" 696 | acorn-walk "^8.1.1" 697 | arg "^4.1.0" 698 | create-require "^1.1.0" 699 | diff "^4.0.1" 700 | make-error "^1.1.1" 701 | v8-compile-cache-lib "^3.0.1" 702 | yn "3.1.1" 703 | 704 | tsconfig@^7.0.0: 705 | version "7.0.0" 706 | resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" 707 | integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== 708 | dependencies: 709 | "@types/strip-bom" "^3.0.0" 710 | "@types/strip-json-comments" "0.0.30" 711 | strip-bom "^3.0.0" 712 | strip-json-comments "^2.0.0" 713 | 714 | tslib@^1.8.0, tslib@^1.8.1: 715 | version "1.14.1" 716 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 717 | integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 718 | 719 | tslint@^5.10.0: 720 | version "5.20.1" 721 | resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" 722 | integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== 723 | dependencies: 724 | "@babel/code-frame" "^7.0.0" 725 | builtin-modules "^1.1.1" 726 | chalk "^2.3.0" 727 | commander "^2.12.1" 728 | diff "^4.0.1" 729 | glob "^7.1.1" 730 | js-yaml "^3.13.1" 731 | minimatch "^3.0.4" 732 | mkdirp "^0.5.1" 733 | resolve "^1.3.2" 734 | semver "^5.3.0" 735 | tslib "^1.8.0" 736 | tsutils "^2.29.0" 737 | 738 | tsutils@^2.29.0: 739 | version "2.29.0" 740 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" 741 | integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== 742 | dependencies: 743 | tslib "^1.8.1" 744 | 745 | type-detect@^4.0.0, type-detect@^4.0.5: 746 | version "4.0.8" 747 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" 748 | integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== 749 | 750 | typescript@^4.2.3: 751 | version "4.2.3" 752 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" 753 | integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== 754 | 755 | v8-compile-cache-lib@^3.0.1: 756 | version "3.0.1" 757 | resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" 758 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== 759 | 760 | wrappy@1: 761 | version "1.0.2" 762 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 763 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 764 | 765 | xtend@^4.0.0: 766 | version "4.0.2" 767 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 768 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 769 | 770 | yn@3.1.1: 771 | version "3.1.1" 772 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 773 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 774 | -------------------------------------------------------------------------------- /test/petra/index.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from "chai"; 2 | 3 | // use petra parser 4 | import { 5 | petraParse as parse, 6 | petraMultiLineParse as multiLineParse, 7 | } from "../../src/petra/petra-parser"; 8 | import { petraPreprocessing } from "../../src/petra/petra-convert"; 9 | 10 | describe("split on separator", () => { 11 | it('"3-4 noci - quattro noci - quattro noci"', () => { 12 | expect( 13 | multiLineParse("12-3 noci - quattro noci - quattro noci", "ita")[0] 14 | ).to.deep.equal({ 15 | unit: null, 16 | unitPlural: null, 17 | symbol: null, 18 | ingredient: "noci", 19 | quantity: 3, 20 | minQty: 3, 21 | maxQty: 3, 22 | }); 23 | }), 24 | it('"INGREDIENTI per 4 persone - quattro noci - quattro noci"', () => { 25 | expect( 26 | multiLineParse( 27 | "INGREDIENTI per 4 persone - quattro noci - quattro noci", 28 | "ita" 29 | )[0] 30 | ).to.deep.equal({ 31 | unit: null, 32 | unitPlural: null, 33 | symbol: null, 34 | ingredient: "noci", 35 | quantity: 4, 36 | minQty: 4, 37 | maxQty: 4, 38 | }); 39 | }), 40 | it('"ingredienti per 4 persone - quattro noci - quattro noci"', () => { 41 | expect( 42 | multiLineParse( 43 | "ingredienti per 4 persone - quattro noci - quattro noci", 44 | "ita" 45 | )[0] 46 | ).to.deep.equal({ 47 | unit: null, 48 | unitPlural: null, 49 | symbol: null, 50 | ingredient: "noci", 51 | quantity: 4, 52 | minQty: 4, 53 | maxQty: 4, 54 | }); 55 | }), 56 | it('"- quattro noci - quattro noci"', () => { 57 | expect( 58 | multiLineParse("- quattro noci - quattro noci", "ita")[0] 59 | ).to.deep.equal({ 60 | unit: null, 61 | unitPlural: null, 62 | symbol: null, 63 | ingredient: "noci", 64 | quantity: 4, 65 | minQty: 4, 66 | maxQty: 4, 67 | }); 68 | }), 69 | it('"quattro noci - quattro noci e cinque mele"', () => { 70 | expect( 71 | multiLineParse("quattro noci - quattro noci e cinque mele", "ita")[2] 72 | ).to.deep.equal({ 73 | unit: null, 74 | unitPlural: null, 75 | symbol: null, 76 | ingredient: "mele", 77 | quantity: 5, 78 | minQty: 5, 79 | maxQty: 5, 80 | }); 81 | }), 82 | it('"quattro noci - quattro noci"', () => { 83 | expect( 84 | multiLineParse("quattro noci - quattro noci", "ita")[0] 85 | ).to.deep.equal({ 86 | unit: null, 87 | unitPlural: null, 88 | symbol: null, 89 | ingredient: "noci", 90 | quantity: 4, 91 | minQty: 4, 92 | maxQty: 4, 93 | }); 94 | }), 95 | it('"tre noci - 8 noci"', () => { 96 | expect(multiLineParse("tre noci - quattro noci", "ita")[0]).to.deep.equal( 97 | { 98 | unit: null, 99 | unitPlural: null, 100 | symbol: null, 101 | ingredient: "noci", 102 | quantity: 3, 103 | minQty: 3, 104 | maxQty: 3, 105 | } 106 | ); 107 | }); 108 | it('"👉 tre noci 👉 8 noci"', () => { 109 | expect( 110 | multiLineParse("👉 tre noci 👉 quattro noci", "ita")[0] 111 | ).to.deep.equal({ 112 | unit: null, 113 | unitPlural: null, 114 | symbol: null, 115 | ingredient: "noci", 116 | quantity: 3, 117 | minQty: 3, 118 | maxQty: 3, 119 | }); 120 | }); 121 | it('"👉🏻 tre noci 👉 8 noci"', () => { 122 | expect( 123 | multiLineParse("👉🏻 tre noci 👉 quattro noci", "ita")[0] 124 | ).to.deep.equal({ 125 | unit: null, 126 | unitPlural: null, 127 | symbol: null, 128 | ingredient: "noci", 129 | quantity: 3, 130 | minQty: 3, 131 | maxQty: 3, 132 | }); 133 | }); 134 | }); 135 | describe("recipe parser ita", () => { 136 | it("returns an object", () => { 137 | expect(typeof parse("1 tazza acqua", "ita")).to.equal("object"); 138 | }); 139 | describe("translates the unit", () => { 140 | it('of "qb di acqua"', () => { 141 | expect(parse("qb di acqua", "ita").unit).to.equal("q.b."); 142 | expect(parse("qb di acqua", "ita").quantity).to.equal(0); 143 | }); 144 | it('of "quanto basta acqua"', () => { 145 | expect(parse("quanto basta di acqua", "ita").unit).to.equal("q.b."); 146 | }); 147 | it('of "Quanto basta acqua"', () => { 148 | expect(parse("Quanto basta di acqua", "ita").unit).to.equal("q.b."); 149 | }); 150 | it('of "Quanto Basta acqua"', () => { 151 | expect(parse("Quanto Basta di acqua", "ita").unit).to.equal("q.b."); 152 | }); 153 | it('of "q.b. di farina"', () => { 154 | expect(parse("q.b. di farina", "ita").ingredient).to.equal("farina"); 155 | }); 156 | it('of "q.b. di farina"', () => { 157 | expect(parse("q.b. di farina", "ita").unit).to.equal("q.b."); 158 | }); 159 | it('of "q.b. farina"', () => { 160 | expect(parse("q.b. farina", "ita").ingredient).to.equal("farina"); 161 | }); 162 | it('of "grammi farina"', () => { 163 | expect(parse("grammi farina", "ita").unit).to.equal("grammo"); 164 | }); 165 | it('of "grammi farina"', () => { 166 | expect(parse("grammi farina", "ita").ingredient).to.equal("farina"); 167 | }); 168 | it('of "Q.B. di acqua"', () => { 169 | expect(parse("Q.B. di acqua", "ita").unit).to.equal("q.b."); 170 | }); 171 | it('of "acqua quanto basta"', () => { 172 | expect(parse("acqua quanto basta", "ita").unit).to.equal("q.b."); 173 | }); 174 | 175 | it('of "QB di acqua"', () => { 176 | expect(parse("QB di acqua", "ita").unit).to.equal("q.b."); 177 | }); 178 | it('of "QB. di acqua"', () => { 179 | expect(parse("QB. di acqua", "ita").unit).to.equal("q.b."); 180 | }); 181 | it('of "Q.B di acqua"', () => { 182 | expect(parse("Q.b di acqua", "ita").unit).to.equal("q.b."); 183 | }); 184 | it('of "1 cucchiao acqua"', () => { 185 | expect(parse("1 cucchiao acqua", "ita").quantity).to.equal(1); 186 | }); 187 | it('of "1.5 cucchiao acqua"', () => { 188 | expect(parse("1.5 cucchiao acqua", "ita").quantity).to.equal(1.5); 189 | }); 190 | it('of "1 1/2 cucchiao acqua"', () => { 191 | expect(parse("1 1/2 cucchiao acqua", "ita").quantity).to.equal(1.5); 192 | }); 193 | it('of "1/3 cucchiao acqua"', () => { 194 | expect(parse("1/3 cucchiao acqua", "ita").quantity).to.equal(0.33); 195 | }); 196 | it('of "1/2 cucchiao acqua"', () => { 197 | expect(parse("1/2 cucchiao acqua", "ita").quantity).to.equal(0.5); 198 | }); 199 | it('of "10 1/2 cucchiao acqua"', () => { 200 | expect(parse("10 1/2 cucchiao acqua", "ita").quantity).to.equal(10.5); 201 | }); 202 | it('of "about 1/2 cucchiao acqua"', () => { 203 | expect(parse("about 1/2 cucchiao acqua", "ita").quantity).to.equal(0.5); 204 | }); 205 | 206 | describe("translates the quantity from string to number", () => { 207 | it("Un cucchiaio d'acqua", () => { 208 | expect(parse("Un cucchiaio d'acqua", "ita").quantity).to.equal(1); 209 | }); 210 | it("Un cucchiaio d'acqua", () => { 211 | expect(parse("Un cucchiaio d'acqua", "ita").quantity).to.equal(1); 212 | }); 213 | it("mezzo cucchiaio d'acqua", () => { 214 | expect(parse("mezzo cucchiaio d'acqua", "ita").quantity).to.equal(0.5); 215 | }); 216 | it("meta cucchiaio d'acqua", () => { 217 | expect(parse("meta cucchiaio d'acqua", "ita").quantity).to.equal(0.5); 218 | }); 219 | it("Venti cucchiai d'acqua\"", () => { 220 | expect(parse("Venti cucchiai d'acqua", "ita").quantity).to.equal(20); 221 | }); 222 | it("cinque cucchiai d'acqua\"", () => { 223 | expect(parse("cinque cucchiai d'acqua", "ita").quantity).to.equal(5); 224 | }); 225 | it("ventuno cucchiai d'acqua\"", () => { 226 | expect(parse("ventuno cucchiai d'acqua", "ita").quantity).to.equal(21); 227 | }); 228 | it("mezzo spicchio d'aglio\"", () => { 229 | expect(parse("mezzo spicchio d'aglio", "ita").quantity).to.equal(0.5); 230 | }); 231 | it("cento grammi d'aglio\"", () => { 232 | expect(parse("cento grammi d'aglio", "ita").quantity).to.equal(100); 233 | }); 234 | it("cento-due grammi d'aglio\"", () => { 235 | expect(parse("cento-due grammi d'aglio", "ita").quantity).to.equal(102); 236 | }); 237 | it("due-cento grammi d'aglio\"", () => { 238 | expect(parse("due-cento grammi d'aglio", "ita").quantity).to.equal(200); 239 | }); 240 | it("due-mila grammi d'aglio\"", () => { 241 | expect(parse("due-mila grammi d'aglio", "ita").quantity).to.equal(2000); 242 | }); 243 | it('due grammi farina"', () => { 244 | expect(parse("due grammi farina", "ita").quantity).to.equal(2); 245 | }); 246 | }); 247 | 248 | // describe('translates the quantity range', () => { 249 | // it('of "10-20 cucchiao acqua"', () => { 250 | // expect(parse('10-20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 251 | // }); 252 | // it('of "10 - 20 cucchiao acqua"', () => { 253 | // expect(parse('10 - 20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 254 | // }); 255 | // it('of "10 to 20 cucchiao acqua"', () => { 256 | // expect(parse('10 to 20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 257 | // }); 258 | // }); 259 | 260 | describe("of unicode fractions", () => { 261 | const unicodeAmounts = [ 262 | "¼", 263 | "½", 264 | "¾", 265 | "⅐", 266 | "⅑", 267 | "⅒", 268 | "⅓", 269 | "⅔", 270 | "⅕", 271 | "⅖", 272 | "⅗", 273 | "⅘", 274 | "⅙", 275 | "⅚", 276 | "⅛", 277 | "⅜", 278 | "⅝", 279 | "⅞", 280 | ]; 281 | const unicodeExpectedAmounts = [ 282 | 0.25, 0.5, 0.75, 0.14, 0.11, 0.1, 0.33, 0.66, 0.2, 0.4, 0.6, 0.8, 0.16, 283 | 0.83, 0.12, 0.37, 0.62, 0.87, 284 | ]; 285 | 286 | for (let u = 0; u < unicodeAmounts.length; u++) { 287 | const element = unicodeAmounts[u]; 288 | const expectedAmount = unicodeExpectedAmounts[u]; 289 | it(`${element} to ${expectedAmount}`, () => { 290 | expect(parse(`${element} cucchiao acqua`, "ita").quantity).to.equal( 291 | expectedAmount 292 | ); 293 | }); 294 | } 295 | 296 | const mixedValues = [ 297 | "1¼", 298 | "2½", 299 | "3¾", 300 | "4⅐", 301 | "5⅑", 302 | "6⅒", 303 | "7⅓", 304 | "8⅔", 305 | "9⅕", 306 | "10⅖", 307 | "11⅗", 308 | "12⅘", 309 | "13⅙", 310 | "14⅚", 311 | "15⅛", 312 | "16⅜", 313 | "17⅝", 314 | "18⅞", 315 | ]; 316 | const mixedExpectedValues = [ 317 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 318 | ]; 319 | 320 | for (let u = 0; u < mixedValues.length; u++) { 321 | const element = mixedValues[u]; 322 | const expectedAmount = 323 | Number(mixedExpectedValues[u]) + Number(unicodeExpectedAmounts[u]); 324 | it(`${element} to ${expectedAmount}`, () => { 325 | expect(parse(`${element} cucchiao acqua`, "ita").quantity).to.equal( 326 | expectedAmount 327 | ); 328 | }); 329 | } 330 | }); 331 | 332 | it("doesn't freak out if a strange unicode character is present", () => { 333 | expect(parse("1/3 tazza zucchero a velo", "ita")).to.deep.equal({ 334 | quantity: 0.33, 335 | unit: "tazza", 336 | unitPlural: "tazze", 337 | symbol: null, 338 | ingredient: "zucchero a velo", 339 | minQty: 0.33, 340 | maxQty: 0.33, 341 | }); 342 | }); 343 | }); 344 | 345 | describe("translates the literal units", () => { 346 | it('of "1 tazza acqua"', () => { 347 | expect(parse("1 tazza acqua", "ita").unit).to.equal("tazza"); 348 | }); 349 | it('of "1 litro acqua"', () => { 350 | expect(parse("1 litro acqua", "ita").unit).to.equal("litro"); 351 | }); 352 | it('of "1 lt acqua"', () => { 353 | expect(parse("1 lt acqua", "ita").unit).to.equal("litro"); 354 | }); 355 | it('of "1 kg acqua"', () => { 356 | expect(parse("1 kg acqua", "ita").unit).to.equal("chilogrammo"); 357 | }); 358 | it('of "1 L acqua"', () => { 359 | expect(parse("1 L acqua", "ita").unit).to.equal("litro"); 360 | }); 361 | it('of "1 L. acqua"', () => { 362 | expect(parse("1 L. acqua", "ita").unit).to.equal("litro"); 363 | }); 364 | it('of "1 cucchiaio acqua"', () => { 365 | expect(parse("1 cucchiaio acqua", "ita").unit).to.equal("cucchiaio"); 366 | }); 367 | it('of "1 cucchiaio acqua"', () => { 368 | expect(parse("1 cucchiaio acqua", "ita").unit).to.equal("cucchiaio"); 369 | }); 370 | it('of "1 grammo acqua"', () => { 371 | expect(parse("1 grammo acqua", "ita").unit).to.equal("grammo"); 372 | }); 373 | it('of "1 chilogrammo acqua"', () => { 374 | expect(parse("1 chilogrammo acqua", "ita").unit).to.equal("chilogrammo"); 375 | }); 376 | it('of "1 litro acqua"', () => { 377 | expect(parse("1 litro acqua", "ita").unit).to.equal("litro"); 378 | }); 379 | it('of "1 milligrammo acqua"', () => { 380 | expect(parse("1 milligrammo acqua", "ita").unit).to.equal("milligrammo"); 381 | }); 382 | it('of "1 millilitro acqua"', () => { 383 | expect(parse("1 millilitro acqua", "ita").unit).to.equal("millilitro"); 384 | }); 385 | it('of "1 l cipolla"', () => { 386 | expect(parse("1 l cipolla", "ita").unit).to.equal("litro"); 387 | }); 388 | it('of "1 cipolla intera"', () => { 389 | expect(parse("1 cipolla intera", "ita").unit).to.equal(null); 390 | }); 391 | it('of "1 spicchio agilio"', () => { 392 | expect(parse("1 spicchio agilio", "ita").unit).to.equal("spicchio"); 393 | }); 394 | it('of "1 bustina aglio"', () => { 395 | expect(parse("1 bustina aglio", "ita").unit).to.equal("bustina"); 396 | }); 397 | it('of "1 pacco salsicce"', () => { 398 | expect(parse("1 pacco salsicce", "ita").unit).to.equal("pacco"); 399 | }); 400 | it('"1 pizzico sale"', () => { 401 | expect(parse("1 pizzico sale", "ita").unit).to.equal("pizzico"); 402 | }); 403 | it('"1 foglia prezzemolo"', () => { 404 | expect(parse("1 foglia prezzemolo", "ita").unit).to.equal("foglia"); 405 | }); 406 | it('"1 mazzetto prezzemolo"', () => { 407 | expect(parse("1 mazzetto prezzemolo", "ita").unit).to.equal("mazzetto"); 408 | }); 409 | it('"1 vasetto yogurt"', () => { 410 | expect(parse("1 vasetto yogurt", "ita").unit).to.equal("vasetto"); 411 | }); 412 | it('"1 (14.5 oz) lattina pommodori"', () => { 413 | expect(parse("1 (14.5 oz) lattina pommodori", "ita")).to.deep.equal({ 414 | unit: "lattina", 415 | unitPlural: "lattine", 416 | symbol: null, 417 | quantity: 1, 418 | ingredient: "pommodori (14.5 oz)", 419 | minQty: 1, 420 | maxQty: 1, 421 | }); 422 | }); 423 | // it('"parses ingredient with range: 1 to 2 petto di pollo"', () => { 424 | // expect(parse('1 to 2 petto di pollo', 'ita')).to.deep.equal({ 425 | // unit: null, 426 | // unitPlural: null, 427 | // symbol: null, 428 | // quantity: '1-2', 429 | // ingredient: 'petto di pollo', 430 | // minQty: '1', 431 | // maxQty: '2', 432 | // }); 433 | // }); 434 | // it('"parses ingredient with range: 1 - 2 petto di pollo"', () => { 435 | // expect(parse('1 - 2 petto di pollo', 'ita')).to.deep.equal({ 436 | // unit: null, 437 | // unitPlural: null, 438 | // symbol: null, 439 | // quantity: '1-2', 440 | // ingredient: 'petto di pollo', 441 | // minQty: '1', 442 | // maxQty: '2', 443 | // }); 444 | // }); 445 | // it('"parses ingredient with range: 1-2 petto di pollo"', () => { 446 | // expect(parse('1-2 petto di pollo', 'ita')).to.deep.equal({ 447 | // unit: null, 448 | // unitPlural: null, 449 | // symbol: null, 450 | // quantity: '1-2', 451 | // ingredient: 'petto di pollo', 452 | // minQty: 1, 453 | // maxQty: 2, 454 | // }); 455 | // }); 456 | it('"1 (16 oz) scatola pasta"', () => { 457 | expect(parse("1 (16 oz) scatola pasta", "ita")).to.deep.equal({ 458 | unit: "scatola", 459 | unitPlural: "scatole", 460 | symbol: null, 461 | quantity: 1, 462 | ingredient: "pasta (16 oz)", 463 | minQty: 1, 464 | maxQty: 1, 465 | }); 466 | }); 467 | it('"1 fetta di formaggio"', () => { 468 | expect(parse("1 fetta di formaggio", "ita")).to.deep.equal({ 469 | unit: "fetta", 470 | unitPlural: "fette", 471 | quantity: 1, 472 | symbol: null, 473 | ingredient: "formaggio", 474 | minQty: 1, 475 | maxQty: 1, 476 | }); 477 | }); 478 | it('"1 spicchio d\'aglio"', () => { 479 | expect(parse("1 spicchio d'aglio", "ita")).to.deep.equal({ 480 | unit: "spicchio", 481 | unitPlural: "spicchi", 482 | quantity: 1, 483 | symbol: null, 484 | ingredient: "aglio", 485 | minQty: 1, 486 | maxQty: 1, 487 | }); 488 | }); 489 | describe('" check the correct symbol"', () => { 490 | it('"grammi di farina"', () => { 491 | expect(parse("grammi di farina", "ita")).to.deep.equal({ 492 | unit: "grammo", 493 | unitPlural: "grammi", 494 | quantity: 0, 495 | symbol: "g", 496 | ingredient: "farina", 497 | minQty: 0, 498 | maxQty: 0, 499 | }); 500 | }); 501 | it('"100 grammi di farina"', () => { 502 | expect(parse("100 grammi di farina", "ita")).to.deep.equal({ 503 | unit: "grammo", 504 | unitPlural: "grammi", 505 | quantity: 100, 506 | symbol: "g", 507 | ingredient: "farina", 508 | minQty: 100, 509 | maxQty: 100, 510 | }); 511 | }); 512 | it('"1 spicchio d\'aglio"', () => { 513 | expect(parse("1 spicchio d'aglio", "ita")).to.deep.equal({ 514 | unit: "spicchio", 515 | unitPlural: "spicchi", 516 | quantity: 1, 517 | symbol: null, 518 | ingredient: "aglio", 519 | minQty: 1, 520 | maxQty: 1, 521 | }); 522 | }); 523 | it('"1 kilogrammo d\'aglio"', () => { 524 | expect(parse("1 kilogrammo d'aglio", "ita")).to.deep.equal({ 525 | unit: "chilogrammo", 526 | unitPlural: "chilogrammi", 527 | quantity: 1, 528 | symbol: "kg", 529 | ingredient: "aglio", 530 | minQty: 1, 531 | maxQty: 1, 532 | }); 533 | }); 534 | it('"1 cucchiaino riso"', () => { 535 | expect(parse("1 cucchiaino riso", "ita")).to.deep.equal({ 536 | unit: "cucchiaino", 537 | unitPlural: "cucchiaini", 538 | quantity: 1, 539 | symbol: "cc", 540 | ingredient: "riso", 541 | minQty: 1, 542 | maxQty: 1, 543 | }); 544 | }); 545 | it('"100 litri di latte"', () => { 546 | expect(parse("100 litri di latte", "ita")).to.deep.equal({ 547 | unit: "litro", 548 | unitPlural: "litri", 549 | quantity: 100, 550 | symbol: "lt", 551 | ingredient: "latte", 552 | minQty: 100, 553 | maxQty: 100, 554 | }); 555 | }); 556 | it('"100 milligrammi di olio"', () => { 557 | expect(parse("100 milligrammi di olio", "ita")).to.deep.equal({ 558 | unit: "milligrammo", 559 | unitPlural: "milligrammi", 560 | quantity: 100, 561 | symbol: "mg", 562 | ingredient: "olio", 563 | minQty: 100, 564 | maxQty: 100, 565 | }); 566 | }); 567 | it('"100 rotoli di olio"', () => { 568 | expect(parse("100 rotoli di olio", "ita")).to.deep.equal({ 569 | unit: "rotolo", 570 | unitPlural: "rotoli", 571 | quantity: 100, 572 | symbol: null, 573 | ingredient: "olio", 574 | minQty: 100, 575 | maxQty: 100, 576 | }); 577 | }); 578 | it('"100 bicchierini di olio"', () => { 579 | expect(parse("100 bicchierino di olio", "ita")).to.deep.equal({ 580 | unit: "bicchierino", 581 | unitPlural: "bicchierini", 582 | quantity: 100, 583 | symbol: null, 584 | ingredient: "olio", 585 | minQty: 100, 586 | maxQty: 100, 587 | }); 588 | }); 589 | it('"Un filo d\'olio"', () => { 590 | expect(parse("Un filo d'olio", "ita")).to.deep.equal({ 591 | unit: "filo", 592 | unitPlural: "fili", 593 | quantity: 1, 594 | symbol: null, 595 | ingredient: "olio", 596 | minQty: 1, 597 | maxQty: 1, 598 | }); 599 | }); 600 | it('"Un ciuffo di prezzemolo"', () => { 601 | expect(parse("Un ciuffo di prezzemolo", "ita")).to.deep.equal({ 602 | unit: "ciuffo", 603 | unitPlural: "ciuffi", 604 | quantity: 1, 605 | symbol: null, 606 | ingredient: "prezzemolo", 607 | minQty: 1, 608 | maxQty: 1, 609 | }); 610 | }); 611 | it('"100 millilitri di latte"', () => { 612 | expect(parse("100 millilitri di latte", "ita")).to.deep.equal({ 613 | unit: "millilitro", 614 | unitPlural: "millilitri", 615 | quantity: 100, 616 | symbol: "ml", 617 | ingredient: "latte", 618 | minQty: 100, 619 | maxQty: 100, 620 | }); 621 | }); 622 | it('"quanto basta di latte"', () => { 623 | expect(parse("quanto basta di latte", "ita")).to.deep.equal({ 624 | unit: "q.b.", 625 | unitPlural: "q.b.", 626 | quantity: 0, 627 | symbol: null, 628 | ingredient: "latte", 629 | minQty: 0, 630 | maxQty: 0, 631 | }); 632 | }); 633 | it('"Quanto Basta di latte"', () => { 634 | expect(parse("quanto basta di latte", "ita")).to.deep.equal({ 635 | unit: "q.b.", 636 | unitPlural: "q.b.", 637 | quantity: 0, 638 | symbol: null, 639 | ingredient: "latte", 640 | minQty: 0, 641 | maxQty: 0, 642 | }); 643 | }); 644 | it('"qb di latte"', () => { 645 | expect(parse("quanto basta di latte", "ita")).to.deep.equal({ 646 | unit: "q.b.", 647 | unitPlural: "q.b.", 648 | quantity: 0, 649 | symbol: null, 650 | ingredient: "latte", 651 | minQty: 0, 652 | maxQty: 0, 653 | }); 654 | }); 655 | it('"q.b. di latte"', () => { 656 | expect(parse("q.b. di latte", "ita")).to.deep.equal({ 657 | unit: "q.b.", 658 | unitPlural: "q.b.", 659 | quantity: 0, 660 | symbol: null, 661 | ingredient: "latte", 662 | minQty: 0, 663 | maxQty: 0, 664 | }); 665 | }); 666 | it('"q.b. latte"', () => { 667 | expect(parse("q.b. latte", "ita")).to.deep.equal({ 668 | unit: "q.b.", 669 | unitPlural: "q.b.", 670 | quantity: 0, 671 | symbol: null, 672 | ingredient: "latte", 673 | minQty: 0, 674 | maxQty: 0, 675 | }); 676 | }); 677 | }); 678 | }); 679 | 680 | it("translates unit when no unit provided", () => { 681 | expect(parse("1 tortilla", "ita")).to.deep.equal({ 682 | unit: null, 683 | unitPlural: null, 684 | symbol: null, 685 | ingredient: "tortilla", 686 | quantity: 1, 687 | minQty: 1, 688 | maxQty: 1, 689 | }); 690 | }); 691 | it("test order and case sensitive", () => { 692 | expect(parse("100 ml. tortilla ", "ita")).to.deep.equal({ 693 | unit: "millilitro", 694 | unitPlural: "millilitri", 695 | symbol: "ml", 696 | ingredient: "tortilla", 697 | quantity: 100, 698 | minQty: 100, 699 | maxQty: 100, 700 | }); 701 | expect(parse("100 mg. tortilla ", "ita")).to.deep.equal({ 702 | unit: "milligrammo", 703 | unitPlural: "milligrammi", 704 | symbol: "mg", 705 | ingredient: "tortilla", 706 | quantity: 100, 707 | minQty: 100, 708 | maxQty: 100, 709 | }); 710 | expect(parse("100 g. tortilla ", "ita")).to.deep.equal({ 711 | unit: "grammo", 712 | unitPlural: "grammi", 713 | symbol: "g", 714 | ingredient: "tortilla", 715 | quantity: 100, 716 | minQty: 100, 717 | maxQty: 100, 718 | }); 719 | expect(parse("1 g. d' acqua", "ita")).to.deep.equal({ 720 | unit: "grammo", 721 | unitPlural: "grammi", 722 | symbol: "g", 723 | ingredient: "acqua", 724 | quantity: 1, 725 | minQty: 1, 726 | maxQty: 1, 727 | }); 728 | expect(parse("100 g. di tortilla ", "ita")).to.deep.equal({ 729 | unit: "grammo", 730 | unitPlural: "grammi", 731 | symbol: "g", 732 | ingredient: "tortilla", 733 | quantity: 100, 734 | minQty: 100, 735 | maxQty: 100, 736 | }); 737 | expect(parse("100 G. di tortilla ", "ita")).to.deep.equal({ 738 | unit: "grammo", 739 | unitPlural: "grammi", 740 | symbol: "g", 741 | ingredient: "tortilla", 742 | quantity: 100, 743 | minQty: 100, 744 | maxQty: 100, 745 | }); 746 | expect(parse("100 G di tortilla ", "ita")).to.deep.equal({ 747 | unit: "grammo", 748 | unitPlural: "grammi", 749 | symbol: "g", 750 | ingredient: "tortilla", 751 | quantity: 100, 752 | minQty: 100, 753 | maxQty: 100, 754 | }); 755 | expect(parse("q.b. di sale", "ita")).to.deep.equal({ 756 | unit: "q.b.", 757 | unitPlural: "q.b.", 758 | symbol: null, 759 | ingredient: "sale", 760 | quantity: 0, 761 | minQty: 0, 762 | maxQty: 0, 763 | }); 764 | expect(parse("100 gr. tortilla ", "ita")).to.deep.equal({ 765 | unit: "grammo", 766 | unitPlural: "grammi", 767 | symbol: "g", 768 | ingredient: "tortilla", 769 | quantity: 100, 770 | minQty: 100, 771 | maxQty: 100, 772 | }); 773 | expect(parse("tortilla 100 gr", "ita")).to.deep.equal({ 774 | unit: "grammo", 775 | unitPlural: "grammi", 776 | symbol: "g", 777 | ingredient: "tortilla", 778 | quantity: 100, 779 | minQty: 100, 780 | maxQty: 100, 781 | }); 782 | expect(parse("basilico quanto basta", "ita")).to.deep.equal({ 783 | unit: "q.b.", 784 | unitPlural: "q.b.", 785 | symbol: null, 786 | ingredient: "basilico", 787 | quantity: 0, 788 | minQty: 0, 789 | maxQty: 0, 790 | }); 791 | expect(parse("basilico q.b.", "ita")).to.deep.equal({ 792 | unit: "q.b.", 793 | unitPlural: "q.b.", 794 | symbol: null, 795 | ingredient: "basilico", 796 | quantity: 0, 797 | minQty: 0, 798 | maxQty: 0, 799 | }); 800 | expect(parse("basilico QB", "ita")).to.deep.equal({ 801 | unit: "q.b.", 802 | unitPlural: "q.b.", 803 | symbol: null, 804 | ingredient: "basilico", 805 | quantity: 0, 806 | minQty: 0, 807 | maxQty: 0, 808 | }); 809 | expect(parse("basilico millilitri 100", "ita")).to.deep.equal({ 810 | unit: "millilitro", 811 | unitPlural: "millilitri", 812 | symbol: "ml", 813 | ingredient: "basilico", 814 | quantity: 100, 815 | minQty: 100, 816 | maxQty: 100, 817 | }); 818 | }); 819 | it("doesn't explode when no unit and no quantity provided", () => { 820 | expect(parse("zucchero a velo", "ita")).to.deep.equal({ 821 | unit: "q.b.", 822 | unitPlural: "q.b.", 823 | symbol: null, 824 | ingredient: "zucchero a velo", 825 | quantity: 0, 826 | minQty: 0, 827 | maxQty: 0, 828 | }); 829 | }); 830 | it("test noci", () => { 831 | expect(parse("quattro noci", "ita")).to.deep.equal({ 832 | unit: null, 833 | unitPlural: null, 834 | symbol: null, 835 | ingredient: "noci", 836 | quantity: 4, 837 | minQty: 4, 838 | maxQty: 4, 839 | }); 840 | expect(parse("una noce", "ita")).to.deep.equal({ 841 | unit: null, 842 | unitPlural: null, 843 | symbol: null, 844 | ingredient: "noce", 845 | quantity: 1, 846 | minQty: 1, 847 | maxQty: 1, 848 | }); 849 | expect(parse("100 gr di noci", "ita")).to.deep.equal({ 850 | unit: "grammo", 851 | unitPlural: "grammi", 852 | symbol: "g", 853 | ingredient: "noci", 854 | quantity: 100, 855 | minQty: 100, 856 | maxQty: 100, 857 | }); 858 | }); 859 | describe("translates the abbreviated units of", () => { 860 | it('"1 tazza acqua"', () => { 861 | expect(parse("1 tazza acqua", "ita").unit).to.equal("tazza"); 862 | expect(parse("2 tazzine acqua", "ita").unit).to.equal("tazza"); 863 | expect(parse("2 tazze acqua", "ita").unit).to.equal("tazza"); 864 | }); 865 | it('"1 litro acqua"', () => { 866 | expect(parse("1 l acqua", "ita").unit).to.equal("litro"); 867 | expect(parse("1 litri acqua", "ita").unit).to.equal("litro"); 868 | }); 869 | it('"1 grammo acqua"', () => { 870 | expect(parse("1 gr acqua", "ita").unit).to.equal("grammo"); 871 | expect(parse("2 g acqua", "ita").unit).to.equal("grammo"); 872 | expect(parse("2 g. acqua", "ita").ingredient).to.equal("acqua"); 873 | }); 874 | it('"1 chilogrammo acqua"', () => { 875 | expect(parse("1 kg acqua", "ita").unit).to.equal("chilogrammo"); 876 | expect(parse("2 KG acqua", "ita").unit).to.equal("chilogrammo"); 877 | expect(parse("1 kilogrammo acqua", "ita").unit).to.equal("chilogrammo"); 878 | expect(parse("2 Kilogrammo acqua", "ita").unit).to.equal("chilogrammo"); 879 | expect(parse("acqua KILOGRAMMO 2", "ita").unit).to.equal("chilogrammo"); 880 | expect(parse("acqua KILOGRAMMO due", "ita").unit).to.equal("chilogrammo"); 881 | }); 882 | it('"1 tazza acqua"', () => { 883 | expect(parse("1 tazza acqua", "ita").unit).to.equal("tazza"); 884 | expect(parse("1 tazzina acqua", "ita").unit).to.equal("tazza"); 885 | expect(parse("2 tazzine acqua", "ita").unit).to.equal("tazza"); 886 | expect(parse("2 Tazza acqua", "ita").unit).to.equal("tazza"); 887 | }); 888 | it('"1 millilitro acqua"', () => { 889 | expect(parse("1 ml acqua", "ita").unit).to.equal("millilitro"); 890 | expect(parse("1 ml. acqua", "ita").unit).to.equal("millilitro"); 891 | expect(parse("1 millilitro acqua", "ita").unit).to.equal("millilitro"); 892 | expect(parse("1 Millilitro acqua", "ita").unit).to.equal("millilitro"); 893 | }); 894 | it('"1 cucchiaio acqua"', () => { 895 | expect(parse("2 cucchiai acqua", "ita").unit).to.equal("cucchiaio"); 896 | expect(parse("1 Cucchiaio acqua", "ita").unit).to.equal("cucchiaio"); 897 | expect(parse("2 cucchiai acqua", "ita").unit).to.equal("cucchiaio"); 898 | }); 899 | it('"1 cucchiaino acqua"', () => { 900 | expect(parse("1 Cucchiaino acqua", "ita").unit).to.equal("cucchiaino"); 901 | expect(parse("1 cucchiaino acqua", "ita").unit).to.equal("cucchiaino"); 902 | expect(parse("2 Cucchiaini acqua", "ita").unit).to.equal("cucchiaino"); 903 | expect(parse("2 cucchiaini acqua", "ita").unit).to.equal("cucchiaino"); 904 | }); 905 | it('"1 grammo acqua"', () => { 906 | expect(parse("1 g acqua", "ita").unit).to.equal("grammo"); 907 | expect(parse("1 g. acqua", "ita").unit).to.equal("grammo"); 908 | expect(parse("2 grammi acqua", "ita").unit).to.equal("grammo"); 909 | }); 910 | it('"1 chilogrammo acqua"', () => { 911 | expect(parse("1 kg acqua", "ita").unit).to.equal("chilogrammo"); 912 | expect(parse("1 kg. acqua", "ita").unit).to.equal("chilogrammo"); 913 | expect(parse("2 chilogrammi acqua", "ita").unit).to.equal("chilogrammo"); 914 | }); 915 | it('"1 litro acqua"', () => { 916 | expect(parse("1 l acqua", "ita").unit).to.equal("litro"); 917 | expect(parse("1 l. acqua", "ita").unit).to.equal("litro"); 918 | expect(parse("2 litri acqua", "ita").unit).to.equal("litro"); 919 | }); 920 | it('"1 milligrammo acqua"', () => { 921 | expect(parse("1 mg acqua", "ita").unit).to.equal("milligrammo"); 922 | expect(parse("1 mg. acqua", "ita").unit).to.equal("milligrammo"); 923 | expect(parse("1 milligrammo acqua", "ita").unit).to.equal("milligrammo"); 924 | }); 925 | it('"1 millilitro acqua"', () => { 926 | expect(parse("1 ml acqua", "ita").unit).to.equal("millilitro"); 927 | expect(parse("1 ml. acqua", "ita").unit).to.equal("millilitro"); 928 | expect(parse("1 millilitro acqua", "ita").unit).to.equal("millilitro"); 929 | }); 930 | it('"1 pizzico acqua"', () => { 931 | expect(parse("2 pizzichi sale", "ita").unit).to.equal("pizzico"); 932 | }); 933 | it('"1 cubetto di ghiaccio"', () => { 934 | expect(parse("2 cubetto di ghiaccio", "ita").unit).to.equal("cubetto"); 935 | }); 936 | }); 937 | 938 | describe("translates the ingredient of", () => { 939 | it('"1 cucchiaio d\'acqua"', () => { 940 | expect(parse("1 cucchiaio d'acqua", "ita").ingredient).to.equal("acqua"); 941 | }); 942 | it('"1 spicchio d\'aglio"', () => { 943 | expect(parse("1 cucchiaio d'acqua", "ita").ingredient).to.equal("acqua"); 944 | }); 945 | it('"1 cucchiaio di latte"', () => { 946 | expect(parse("1 cucchiaio di latte", "ita").ingredient).to.equal("latte"); 947 | }); 948 | it('"1 cucchiaio acqua"', () => { 949 | expect(parse("1 cucchiaio acqua", "ita").ingredient).to.equal("acqua"); 950 | }); 951 | it('"1 cucchiaio latte"', () => { 952 | expect(parse("1 cucchiaio latte", "ita").ingredient).to.equal("latte"); 953 | }); 954 | }); 955 | 956 | describe("translates the ingredient of", () => { 957 | it('"1 g di latte"', () => { 958 | expect(parse("1 g di latte", "ita").ingredient).to.equal("latte"); 959 | }); 960 | it('"1 kg di latte"', () => { 961 | expect(parse("1 kg di latte", "ita").ingredient).to.equal("latte"); 962 | }); 963 | it('"250 kg di farina"', () => { 964 | expect(parse("250 kg di farina", "ita").ingredient).to.equal("farina"); 965 | }); 966 | it('"dieci kg farina"', () => { 967 | expect(parse("dieci kg farina", "ita").ingredient).to.equal("farina"); 968 | }); 969 | it('"dieci kg farina"', () => { 970 | expect(parse("dieci kg farina", "ita").ingredient).to.equal("farina"); 971 | }); 972 | it('"3 g spaghetti"', () => { 973 | expect(parse("3 g spaghetti", "ita").ingredient).to.equal("spaghetti"); 974 | }); 975 | it('"3 mg spamghetti"', () => { 976 | expect(parse("3 mg spamghetti", "ita").ingredient).to.equal("spamghetti"); 977 | }); 978 | }); 979 | describe("translates q.b. without quantity of", () => { 980 | it('"latte"', () => { 981 | expect(parse("latte", "ita").unit).to.equal("q.b."); 982 | }); 983 | it('"farina"', () => { 984 | expect(parse("farina", "ita").unit).to.equal("q.b."); 985 | }); 986 | it('"250 kg di farina"', () => { 987 | expect(parse("250 kg di farina", "ita").quantity).to.equal(250); 988 | }); 989 | }); 990 | describe("translates bug with g", () => { 991 | it('"sgombro 300 g"', () => { 992 | expect(parse("sgombro 300 g", "ita").ingredient).to.equal("sgombro"); 993 | }); 994 | it('"lamle 300 ml"', () => { 995 | expect(parse("lamle 300 ml", "ita").ingredient).to.equal("lamle"); 996 | }); 997 | it('"lamge 300 mg"', () => { 998 | expect(parse("lamge 300 mg", "ita").ingredient).to.equal("lamge"); 999 | }); 1000 | it('"lamge 1/3 mg"', () => { 1001 | expect(parse("lamge 1/3 mg", "ita").quantity).to.equal(0.33); 1002 | }); 1003 | it('"guanciale 100 g"', () => { 1004 | expect(parse("guanciale 100 g", "ita").ingredient).to.equal("guanciale"); 1005 | }); 1006 | it('"Guanciale 100 g"', () => { 1007 | expect(parse("Guanciale 100 g", "ita").ingredient).to.equal("guanciale"); 1008 | }); 1009 | it('"cuangiale 100 g"', () => { 1010 | expect(parse("cuangiale 100 g", "ita").ingredient).to.equal("cuangiale"); 1011 | }); 1012 | }); 1013 | }); 1014 | 1015 | describe('handles special "Farina" and "Petra" numeric references in real-world examples', () => { 1016 | it('parses "farina petra 8610 500g" correctly', () => { 1017 | expect(parse("farina petra 8610 500 g", "ita")).to.deep.equal({ 1018 | quantity: 500, 1019 | unit: "grammo", 1020 | unitPlural: "grammi", 1021 | symbol: "g", 1022 | ingredient: "farina petra 8610", 1023 | minQty: 500, 1024 | maxQty: 500, 1025 | }); 1026 | }); 1027 | 1028 | it('parses "farina petra 00 1kg" correctly', () => { 1029 | expect(parse("farina petra 00 1 kg", "ita")).to.deep.equal({ 1030 | quantity: 1, 1031 | unit: "chilogrammo", 1032 | unitPlural: "chilogrammi", 1033 | symbol: "kg", 1034 | ingredient: "farina petra 00", 1035 | minQty: 1, 1036 | maxQty: 1, 1037 | }); 1038 | }); 1039 | 1040 | it('parses "petra 9 250ml" correctly', () => { 1041 | expect(parse("petra 9 250 ml", "ita")).to.deep.equal({ 1042 | quantity: 250, 1043 | unit: "millilitro", 1044 | unitPlural: "millilitri", 1045 | symbol: "ml", 1046 | ingredient: "petra 9", 1047 | minQty: 250, 1048 | maxQty: 250, 1049 | }); 1050 | }); 1051 | 1052 | it('parses "farina petra 1 100g" correctly', () => { 1053 | expect(parse("farina petra 1 100 g", "ita")).to.deep.equal({ 1054 | quantity: 100, 1055 | unit: "grammo", 1056 | unitPlural: "grammi", 1057 | symbol: "g", 1058 | ingredient: "farina petra 1", 1059 | minQty: 100, 1060 | maxQty: 100, 1061 | }); 1062 | }); 1063 | 1064 | it('parses "petra 8610 2 barattoli" correctly', () => { 1065 | expect(parse("petra 8610 2 barattoli", "ita")).to.deep.equal({ 1066 | quantity: 2, 1067 | unit: "barattolo", 1068 | unitPlural: "barattoli", 1069 | symbol: null, 1070 | ingredient: "petra 8610", 1071 | minQty: 2, 1072 | maxQty: 2, 1073 | }); 1074 | }); 1075 | 1076 | it('parses "farina petra 00 750g" correctly', () => { 1077 | expect(parse("farina petra 00 750 g", "ita")).to.deep.equal({ 1078 | quantity: 750, 1079 | unit: "grammo", 1080 | unitPlural: "grammi", 1081 | symbol: "g", 1082 | ingredient: "farina petra 00", 1083 | minQty: 750, 1084 | maxQty: 750, 1085 | }); 1086 | }); 1087 | 1088 | it('parses "petra 00 4 pezzi" correctly', () => { 1089 | expect(parse("petra 00 4 pezzi", "ita")).to.deep.equal({ 1090 | quantity: 4, 1091 | unit: "pezzo", 1092 | unitPlural: "pezzi", 1093 | symbol: null, 1094 | ingredient: "petra 00", 1095 | minQty: 4, 1096 | maxQty: 4, 1097 | }); 1098 | }); 1099 | 1100 | it('parses "farina petra 9 5 litri" correctly', () => { 1101 | expect(parse("farina petra 9 5 litri", "ita")).to.deep.equal({ 1102 | quantity: 5, 1103 | unit: "litro", 1104 | unitPlural: "litri", 1105 | symbol: "lt", 1106 | ingredient: "farina petra 9", 1107 | minQty: 5, 1108 | maxQty: 5, 1109 | }); 1110 | }); 1111 | 1112 | it('parses "petra 1 20g" correctly', () => { 1113 | expect(parse("petra 1 20 g", "ita")).to.deep.equal({ 1114 | quantity: 20, 1115 | unit: "grammo", 1116 | unitPlural: "grammi", 1117 | symbol: "g", 1118 | ingredient: "petra 1", 1119 | minQty: 20, 1120 | maxQty: 20, 1121 | }); 1122 | }); 1123 | it('parses "farina petra 5063 500g" correctly', () => { 1124 | expect(parse("farina petra 5063 500 g", "ita")).to.deep.equal({ 1125 | quantity: 500, 1126 | unit: "grammo", 1127 | unitPlural: "grammi", 1128 | symbol: "g", 1129 | ingredient: "farina petra 5063", 1130 | minQty: 500, 1131 | maxQty: 500, 1132 | }); 1133 | }); 1134 | 1135 | it('parses "petra 8612 1kg" correctly', () => { 1136 | expect(parse("petra 8612 9 kg", "ita")).to.deep.equal({ 1137 | quantity: 9, 1138 | unit: "chilogrammo", 1139 | unitPlural: "chilogrammi", 1140 | symbol: "kg", 1141 | ingredient: "petra 8612", 1142 | minQty: 9, 1143 | maxQty: 9, 1144 | }); 1145 | }); 1146 | 1147 | it('parses "petra 0102 hp 2 barattoli" correctly', () => { 1148 | console.log(petraPreprocessing("petra 0102 hp 2 barattoli", [])); 1149 | expect(parse("petra 0102 hp 3 barattoli", "ita")).to.deep.equal({ 1150 | quantity: 3, 1151 | unit: "barattolo", 1152 | unitPlural: "barattoli", 1153 | symbol: null, 1154 | ingredient: "petra 0102 hp", 1155 | minQty: 3, 1156 | maxQty: 3, 1157 | }); 1158 | }); 1159 | 1160 | it('parses "farina petra 0005 - zero glutine 250ml" correctly', () => { 1161 | expect( 1162 | parse("farina petra 0005 - zero glutine 250 ml", "ita") 1163 | ).to.deep.equal({ 1164 | quantity: 250, 1165 | unit: "millilitro", 1166 | unitPlural: "millilitri", 1167 | symbol: "ml", 1168 | ingredient: "farina petra 0005 - zero glutine", 1169 | minQty: 250, 1170 | maxQty: 250, 1171 | }); 1172 | }); 1173 | 1174 | it('parses "petra 0003 - zero glutine 3 cucchiai" correctly', () => { 1175 | expect(parse("petra 0003 - zero glutine 4 cucchiai", "ita")).to.deep.equal({ 1176 | quantity: 4, 1177 | unit: "cucchiaio", 1178 | unitPlural: "cucchiai", 1179 | symbol: null, 1180 | ingredient: "petra 0003 - zero glutine", 1181 | minQty: 4, 1182 | maxQty: 4, 1183 | }); 1184 | }); 1185 | 1186 | it('parses "petra 5046 5 litri" correctly', () => { 1187 | expect(parse("petra 5046 8 litri", "ita")).to.deep.equal({ 1188 | quantity: 8, 1189 | unit: "litro", 1190 | unitPlural: "litri", 1191 | symbol: "lt", 1192 | ingredient: "petra 5046", 1193 | minQty: 8, 1194 | maxQty: 8, 1195 | }); 1196 | }); 1197 | 1198 | it('parses "farina petra 1110 750g" correctly', () => { 1199 | expect(parse("farina petra 1110 750 g", "ita")).to.deep.equal({ 1200 | quantity: 750, 1201 | unit: "grammo", 1202 | unitPlural: "grammi", 1203 | symbol: "g", 1204 | ingredient: "farina petra 1110", 1205 | minQty: 750, 1206 | maxQty: 750, 1207 | }); 1208 | }); 1209 | 1210 | it('parses "petra 5078 4 pezzi" correctly', () => { 1211 | expect(parse("petra 5078 4 pezzi", "ita")).to.deep.equal({ 1212 | quantity: 4, 1213 | unit: "pezzo", 1214 | unitPlural: "pezzi", 1215 | symbol: null, 1216 | ingredient: "petra 5078", 1217 | minQty: 4, 1218 | maxQty: 4, 1219 | }); 1220 | }); 1221 | 1222 | it('parses "petra 7210 200g" correctly', () => { 1223 | expect(parse("petra 7210 200 g", "ita")).to.deep.equal({ 1224 | quantity: 200, 1225 | unit: "grammo", 1226 | unitPlural: "grammi", 1227 | symbol: "g", 1228 | ingredient: "petra 7210", 1229 | minQty: 200, 1230 | maxQty: 200, 1231 | }); 1232 | }); 1233 | 1234 | it('parses "petra 0104 hp 12 barattoli" correctly', () => { 1235 | expect(parse("petra 0104 hp 12 barattoli", "ita")).to.deep.equal({ 1236 | quantity: 12, 1237 | unit: "barattolo", 1238 | unitPlural: "barattoli", 1239 | symbol: null, 1240 | ingredient: "petra 0104 hp", 1241 | minQty: 12, 1242 | maxQty: 12, 1243 | }); 1244 | }); 1245 | 1246 | it('parses "petra 0006 500ml" correctly', () => { 1247 | expect(parse("petra 0006 500 ml", "ita")).to.deep.equal({ 1248 | quantity: 500, 1249 | unit: "millilitro", 1250 | unitPlural: "millilitri", 1251 | symbol: "ml", 1252 | ingredient: "petra 0006", 1253 | minQty: 500, 1254 | maxQty: 500, 1255 | }); 1256 | }); 1257 | 1258 | it('parses "farina petra 5063 1.5kg" correctly', () => { 1259 | expect(parse("farina petra 5063 1.5 kg", "ita")).to.deep.equal({ 1260 | quantity: 1.5, 1261 | unit: "chilogrammo", 1262 | unitPlural: "chilogrammi", 1263 | symbol: "kg", 1264 | ingredient: "farina petra 5063", 1265 | minQty: 1.5, 1266 | maxQty: 1.5, 1267 | }); 1268 | }); 1269 | 1270 | it('parses "petra 0101 hp 300g" correctly', () => { 1271 | expect(parse("petra 0101 hp 300 g", "ita")).to.deep.equal({ 1272 | quantity: 300, 1273 | unit: "grammo", 1274 | unitPlural: "grammi", 1275 | symbol: "g", 1276 | ingredient: "petra 0101 hp", 1277 | minQty: 300, 1278 | maxQty: 300, 1279 | }); 1280 | }); 1281 | 1282 | it('parses "petra 6388 2 bottiglie" correctly', () => { 1283 | expect(parse("petra 6388 2 bottiglie", "ita")).to.deep.equal({ 1284 | quantity: 2, 1285 | unit: "bottiglia", 1286 | unitPlural: "bottiglie", 1287 | symbol: null, 1288 | ingredient: "petra 6388", 1289 | minQty: 2, 1290 | maxQty: 2, 1291 | }); 1292 | }); 1293 | 1294 | it('parses "petra 5009 2,5kg" correctly', () => { 1295 | expect(parse("petra 5009 2.5 kg", "ita")).to.deep.equal({ 1296 | quantity: 2.5, 1297 | unit: "chilogrammo", 1298 | unitPlural: "chilogrammi", 1299 | symbol: "kg", 1300 | ingredient: "petra 5009", 1301 | minQty: 2.5, 1302 | maxQty: 2.5, 1303 | }); 1304 | }); 1305 | }); 1306 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import { parse, multiLineParse } from '../src/index'; 3 | /* 4 | describe('recipe parser eng', () => { 5 | it('returns an object', () => { 6 | expect(typeof parse('1 cup water', 'eng')).to.equal('object'); 7 | }); 8 | 9 | describe('translates the quantity', () => { 10 | it('of "to taste of water"', () => { 11 | expect(parse('to taste of water', 'eng').unit).to.equal('t.t.'); 12 | }); 13 | it('of "To taste of water"', () => { 14 | expect(parse('To taste of water', 'eng').unit).to.equal('t.t.'); 15 | }); 16 | it('of "t.t. of water"', () => { 17 | expect(parse('t.t. of water', 'eng').unit).to.equal('t.t.'); 18 | }); 19 | it('of "t.t. of water"', () => { 20 | expect(parse('t.t. of water', 'eng').unit).to.equal('t.t.'); 21 | }); 22 | it('of "TT of water"', () => { 23 | expect(parse('TT of water', 'eng').unit).to.equal('t.t.'); 24 | }); 25 | it('of "TT. of water"', () => { 26 | expect(parse('TT. of water', 'eng').unit).to.equal('t.t.'); 27 | }); 28 | it('of "T.t of water"', () => { 29 | expect(parse('T.t of water', 'eng').unit).to.equal('t.t.'); 30 | }); 31 | it('of "1 teaspoon water"', () => { 32 | expect(parse('1 teaspoon water', 'eng').quantity).to.equal(1); 33 | }); 34 | it('of "1.5 teaspoon water"', () => { 35 | expect(parse('1.5 teaspoon water', 'eng').quantity).to.equal(1.5); 36 | }); 37 | it('of "1 1/2 teaspoon water"', () => { 38 | expect(parse('1 1/2 teaspoon water', 'eng').quantity).to.equal(1.5); 39 | }); 40 | it('of "1/3 teaspoon water"', () => { 41 | expect(parse('1/3 cup water', 'eng').quantity).to.equal(0.333); 42 | }); 43 | it('of "1/2 teaspoon water"', () => { 44 | expect(parse('1/2 teaspoon water', 'eng').quantity).to.equal(0.5); 45 | }); 46 | it('of "10 1/2 teaspoon water"', () => { 47 | expect(parse('10 1/2 teaspoon water', 'eng').quantity).to.equal(10.5); 48 | }); 49 | it('of "about 1/2 teaspoon water"', () => { 50 | expect(parse('about 1/2 teaspoon water', 'eng').quantity).to.equal(0.5); 51 | }); 52 | 53 | describe('translates the quantity from string to number', () => { 54 | it('one teaspoon water"', () => { 55 | expect(parse('one teaspoon water', 'eng').quantity).to.equal(1); 56 | }); 57 | it('twenty-one teaspoon water"', () => { 58 | expect(parse('twenty-one teaspoon water', 'eng').quantity).to.equal(21); 59 | }); 60 | it('five teaspoon water"', () => { 61 | expect(parse('five teaspoon water', 'eng').quantity).to.equal(5); 62 | }); 63 | }); 64 | 65 | // describe('translates the quantity range', () => { 66 | // it('of "10-20 teaspoon water"', () => { 67 | // expect(parse('10-20 teaspoon water', 'eng').quantity).to.equal('10-20'); 68 | // }); 69 | // it('of "10 - 20 teaspoon water"', () => { 70 | // expect(parse('10 - 20 teaspoon water', 'eng').quantity).to.equal('10-20'); 71 | // }); 72 | // it('of "10 to 20 teaspoon water"', () => { 73 | // expect(parse('10 to 20 teaspoon water', 'eng').quantity).to.equal('10-20'); 74 | // }); 75 | // }); 76 | 77 | describe('of unicode fractions', () => { 78 | const unicodeAmounts = ['¼', '½', '¾', '⅐', '⅑', '⅒', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞']; 79 | const unicodeExpectedAmounts = [0.25, 0.5, 0.75, 0.142, 0.111, 0.1, 0.333, 0.666, 0.2, 0.4, 0.6, 0.8, 0.166, 0.833, 0.125, 0.375, 0.625, 0.875]; 80 | 81 | for (let u = 0; u < unicodeAmounts.length; u++) { 82 | const element = unicodeAmounts[u]; 83 | const expectedAmount = unicodeExpectedAmounts[u]; 84 | it(`${element} to ${expectedAmount}`, () => { 85 | expect(parse(`${element} teaspoon water`, 'eng').quantity).to.equal(expectedAmount); 86 | }); 87 | } 88 | 89 | const mixedValues = ['1¼', '2½', '3¾', '4⅐', '5⅑', '6⅒', '7⅓', '8⅔', '9⅕', '10⅖', '11⅗', '12⅘', '13⅙', '14⅚', '15⅛', '16⅜', '17⅝', '18⅞']; 90 | const mixedExpectedValues = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18']; 91 | 92 | for (let u = 0; u < mixedValues.length; u++) { 93 | const element = mixedValues[u]; 94 | const expectedAmount = (Number(mixedExpectedValues[u]) + Number(unicodeExpectedAmounts[u])); 95 | it(`${element} to ${expectedAmount}`, () => { 96 | expect(parse(`${element} teaspoon water`, 'eng').quantity).to.equal(expectedAmount); 97 | }); 98 | } 99 | }); 100 | 101 | it('doesn\'t freak out if a strange unicode character is present', () => { 102 | expect(parse('1/3 cup confectioners’ sugar', 'eng')).to.deep.equal({ 103 | quantity: 0.333, 104 | unit: 'cup', 105 | unitPlural: 'cups', 106 | symbol: 'c', 107 | ingredient: 'confectioners’ sugar', 108 | minQty: 0.333, 109 | maxQty: 0.333, 110 | }); 111 | }); 112 | }); 113 | 114 | describe('translates the literal units', () => { 115 | it('of "1 cup water"', () => { 116 | expect(parse('1 cup water', 'eng').unit).to.equal('cup'); 117 | }); 118 | it('of "1 gallon water"', () => { 119 | expect(parse('1 gallon water', 'eng').unit).to.equal('gallon'); 120 | }); 121 | it('of "1 ounce water"', () => { 122 | expect(parse('1 ounce water', 'eng').unit).to.equal('ounce'); 123 | }); 124 | it('of "1 pint water"', () => { 125 | expect(parse('1 pint water', 'eng').unit).to.equal('pint'); 126 | }); 127 | it('of "1 pound water"', () => { 128 | expect(parse('1 pound water', 'eng').unit).to.equal('pound'); 129 | }); 130 | it('of "1 quart water"', () => { 131 | expect(parse('1 quart water', 'eng').unit).to.equal('quart'); 132 | }); 133 | it('of "1 tablespoon water"', () => { 134 | expect(parse('1 tablespoon water', 'eng').unit).to.equal('tablespoon'); 135 | }); 136 | it('of "1 teaspoon water"', () => { 137 | expect(parse('1 teaspoon water', 'eng').unit).to.equal('teaspoon'); 138 | }); 139 | it('of "1 gram water"', () => { 140 | expect(parse('1 gram water', 'eng').unit).to.equal('gram'); 141 | }); 142 | it('of "1 kilogram water"', () => { 143 | expect(parse('1 kilogram water', 'eng').unit).to.equal('kilogram'); 144 | }); 145 | it('of "1 liter water"', () => { 146 | expect(parse('1 liter water', 'eng').unit).to.equal('liter'); 147 | }); 148 | it('of "1 milligram water"', () => { 149 | expect(parse('1 milligram water', 'eng').unit).to.equal('milligram'); 150 | }); 151 | it('of "1 milliliter water"', () => { 152 | expect(parse('1 milliliter water', 'eng').unit).to.equal('milliliter'); 153 | }); 154 | it('of "1 large onion"', () => { 155 | expect(parse('1 large onion', 'eng').unit).to.equal("large"); 156 | }); 157 | it('of "1 whole onion"', () => { 158 | expect(parse('1 whole onion', 'eng').unit).to.equal(null); 159 | }); 160 | it('of "1 clove garlic"', () => { 161 | expect(parse('1 clove garlic', 'eng').unit).to.equal('clove'); 162 | }); 163 | it('of "1 bag garlic"', () => { 164 | expect(parse('1 bag garlic', 'eng').unit).to.equal('bag'); 165 | }); 166 | it('of "1 package sausage"', () => { 167 | expect(parse('1 package sausage', 'eng').unit).to.equal('package'); 168 | }); 169 | it('"1 pinch water"', () => { 170 | expect(parse('1 pinch salt', 'eng').unit).to.equal('pinch'); 171 | }); 172 | it('"1 (14.5 oz) can tomatoes"', () => { 173 | expect(parse('1 (14.5 oz) can tomatoes', 'eng')).to.deep.equal({ 174 | unit: 'can', 175 | unitPlural: 'cans', 176 | symbol: null, 177 | quantity: 1, 178 | ingredient: 'tomatoes (14.5 oz)', 179 | minQty: 1, 180 | maxQty: 1, 181 | }); 182 | }); 183 | it('"25 lb beef stew chunks (or buy a roast and chop into small cubes)"', () => { 184 | expect(parse('25 lb beef stew chunks (or buy a roast and chop into small cubes)', 'eng')).to.deep.equal({ 185 | unit: 'pound', 186 | unitPlural: 'pounds', 187 | symbol: 'lb', 188 | quantity: 25, 189 | ingredient: 'beef stew chunks (or buy a roast and chop into small cubes)', 190 | minQty: 25, 191 | maxQty: 25, 192 | }); 193 | }); 194 | // it('"parses ingredient with range: 1 to 2 chicken breasts"', () => { 195 | // expect(parse('1 to 2 chicken breasts', 'eng')).to.deep.equal({ 196 | // unit: null, 197 | // unitPlural: null, 198 | // symbol: null, 199 | // quantity: '1-2', 200 | // ingredient: 'chicken breasts', 201 | // minQty: '1', 202 | // maxQty: '2', 203 | // }); 204 | // }); 205 | // it('"parses ingredient with range: 1 - 2 chicken breasts"', () => { 206 | // expect(parse('1 - 2 chicken breasts', 'eng')).to.deep.equal({ 207 | // unit: null, 208 | // unitPlural: null, 209 | // symbol: null, 210 | // quantity: '1-2', 211 | // ingredient: 'chicken breasts', 212 | // minQty: '1', 213 | // maxQty: '2', 214 | // }); 215 | // }); 216 | // it('"parses ingredient with range: 1-2 chicken breasts"', () => { 217 | // expect(parse('1-2 chicken breasts', 'eng')).to.deep.equal({ 218 | // unit: null, 219 | // unitPlural: null, 220 | // symbol: null, 221 | // quantity: '1-2', 222 | // ingredient: 'chicken breasts', 223 | // minQty: '1', 224 | // maxQty: '2', 225 | // }); 226 | // }); 227 | it('"1 (16 oz) box pasta"', () => { 228 | expect(parse('1 (16 oz) box pasta', 'eng')).to.deep.equal({ 229 | unit: 'box', 230 | unitPlural: 'boxes', 231 | symbol: null, 232 | quantity: 1, 233 | ingredient: 'pasta (16 oz)', 234 | minQty: 1, 235 | maxQty: 1, 236 | }); 237 | }); 238 | it('"1 slice cheese"', () => { 239 | expect(parse('1 slice cheese', 'eng')).to.deep.equal({ 240 | unit: 'slice', 241 | unitPlural: 'slices', 242 | symbol: null, 243 | quantity: 1, 244 | ingredient: 'cheese', 245 | minQty: 1, 246 | maxQty: 1, 247 | }); 248 | }); 249 | }); 250 | 251 | it('translates unit when no unit provided', () => { 252 | expect(parse('1 tortilla', 'eng')).to.deep.equal({ 253 | unit: null, 254 | unitPlural: null, 255 | symbol: null, 256 | ingredient: 'tortilla', 257 | quantity: 1, 258 | minQty: 1, 259 | maxQty: 1, 260 | }); 261 | }); 262 | 263 | it('doesn\'t explode when no unit and no quantity provided', () => { 264 | expect(parse('Powdered Sugar', 'eng')).to.deep.equal({ 265 | ingredient: 'Powdered Sugar', 266 | quantity: 0, 267 | unit: null, 268 | unitPlural: null, 269 | symbol: null, 270 | minQty: 0, 271 | maxQty: 0, 272 | }); 273 | }); 274 | 275 | describe('translates the abbreviated units of', () => { 276 | it('"1 cup water"', () => { 277 | expect(parse('1 c water', 'eng').unit).to.equal('cup'); 278 | expect(parse('2 c. water', 'eng').unit).to.equal('cup'); 279 | expect(parse('2 cups water', 'eng').unit).to.equal('cup'); 280 | }); 281 | it('"1 gallon water"', () => { 282 | expect(parse('1 gal water', 'eng').unit).to.equal('gallon'); 283 | expect(parse('1 gallons water', 'eng').unit).to.equal('gallon'); 284 | }); 285 | it('"1 ounce water"', () => { 286 | expect(parse('1 oz water', 'eng').unit).to.equal('ounce'); 287 | expect(parse('1 oz. water', 'eng').unit).to.equal('ounce'); 288 | expect(parse('2 ounces water', 'eng').unit).to.equal('ounce'); 289 | }); 290 | it('"1 pint water"', () => { 291 | expect(parse('1 pt water', 'eng').unit).to.equal('pint'); 292 | expect(parse('2 pts water', 'eng').unit).to.equal('pint'); 293 | expect(parse('1 pt. water', 'eng').unit).to.equal('pint'); 294 | expect(parse('2 pints water', 'eng').unit).to.equal('pint'); 295 | }); 296 | it('"1 pound water"', () => { 297 | expect(parse('1 lb water', 'eng').unit).to.equal('pound'); 298 | expect(parse('1 lb. water', 'eng').unit).to.equal('pound'); 299 | expect(parse('2 lbs water', 'eng').unit).to.equal('pound'); 300 | expect(parse('2 pounds water', 'eng').unit).to.equal('pound'); 301 | }); 302 | it('"1 quart water"', () => { 303 | expect(parse('1 qt water', 'eng').unit).to.equal('quart'); 304 | expect(parse('1 qt. water', 'eng').unit).to.equal('quart'); 305 | expect(parse('1 qts water', 'eng').unit).to.equal('quart'); 306 | expect(parse('1 quarts water', 'eng').unit).to.equal('quart'); 307 | }); 308 | it('"1 tablespoon water"', () => { 309 | expect(parse('1 T water', 'eng').unit).to.equal('tablespoon'); 310 | expect(parse('1 T. water', 'eng').unit).to.equal('tablespoon'); 311 | expect(parse('1 tbs water', 'eng').unit).to.equal('tablespoon'); 312 | expect(parse('1 tbsp water', 'eng').unit).to.equal('tablespoon'); 313 | expect(parse('1 tbspn water', 'eng').unit).to.equal('tablespoon'); 314 | expect(parse('2 tablespoons water', 'eng').unit).to.equal('tablespoon'); 315 | expect(parse('1 Tablespoon water', 'eng').unit).to.equal('tablespoon'); 316 | expect(parse('2 Tablespoons water', 'eng').unit).to.equal('tablespoon'); 317 | }); 318 | it('"1 teaspoon water"', () => { 319 | expect(parse('1 tsp water', 'eng').unit).to.equal('teaspoon'); 320 | expect(parse('1 tspn water', 'eng').unit).to.equal('teaspoon'); 321 | expect(parse('1 t water', 'eng').unit).to.equal('teaspoon'); 322 | expect(parse('1 t. water', 'eng').unit).to.equal('teaspoon'); 323 | expect(parse('2 teaspoons water', 'eng').unit).to.equal('teaspoon'); 324 | }); 325 | it('"1 gram water"', () => { 326 | expect(parse('1 g water', 'eng').unit).to.equal('gram'); 327 | expect(parse('1 g. water', 'eng').unit).to.equal('gram'); 328 | expect(parse('2 grams water', 'eng').unit).to.equal('gram'); 329 | }); 330 | it('"1 kilogram water"', () => { 331 | expect(parse('1 kg water', 'eng').unit).to.equal('kilogram'); 332 | expect(parse('1 kg. water', 'eng').unit).to.equal('kilogram'); 333 | expect(parse('2 kilograms water', 'eng').unit).to.equal('kilogram'); 334 | }); 335 | it('"1 liter water"', () => { 336 | expect(parse('1 l water', 'eng').unit).to.equal('liter'); 337 | expect(parse('1 l. water', 'eng').unit).to.equal('liter'); 338 | expect(parse('2 liters water', 'eng').unit).to.equal('liter'); 339 | }); 340 | it('"1 milligram water"', () => { 341 | expect(parse('1 mg water', 'eng').unit).to.equal('milligram'); 342 | expect(parse('1 mg. water', 'eng').unit).to.equal('milligram'); 343 | expect(parse('1 milligrams water', 'eng').unit).to.equal('milligram'); 344 | }); 345 | it('"1 milliliter water"', () => { 346 | expect(parse('1 ml water', 'eng').unit).to.equal('milliliter'); 347 | expect(parse('1 ml. water', 'eng').unit).to.equal('milliliter'); 348 | expect(parse('1 milliliters water', 'eng').unit).to.equal('milliliter'); 349 | }); 350 | it('"1 pinch water"', () => { 351 | expect(parse('2 pinches salt', 'eng').unit).to.equal('pinch'); 352 | }); 353 | }); 354 | 355 | describe('translates the ingredient of', () => { 356 | it('"1 teaspoon water"', () => { 357 | expect(parse('1 teaspoon of water', 'eng').ingredient).to.equal('water'); 358 | }); 359 | it('"1 teaspoon milk"', () => { 360 | expect(parse('1 teaspoon of milk', 'eng').ingredient).to.equal('milk'); 361 | }); 362 | it('"1 teaspoon of milk"', () => { 363 | expect(parse('1 teaspoon of milk', 'eng').ingredient).to.equal('milk'); 364 | }); 365 | it('"1 teaspoon of milk"', () => { 366 | expect(parse('1 teaspoon of powdered sugar', 'eng').ingredient).to.equal('powdered sugar'); 367 | }); 368 | }); 369 | }); 370 | */ 371 | /////ITALIAN TEST 372 | describe('split on separator', () => { 373 | it('"3-4 noci - quattro noci - quattro noci"', () => { 374 | expect(multiLineParse('12-3 noci - quattro noci - quattro noci', 'ita')[0]).to.deep.equal({ 375 | unit: null, 376 | unitPlural: null, 377 | symbol: null, 378 | ingredient: 'noci', 379 | quantity: 3, 380 | minQty: 3, 381 | maxQty: 3, 382 | }); 383 | }), 384 | it('"INGREDIENTI per 4 persone - quattro noci - quattro noci"', () => { 385 | expect(multiLineParse('INGREDIENTI per 4 persone - quattro noci - quattro noci', 'ita')[0]).to.deep.equal({ 386 | unit: null, 387 | unitPlural: null, 388 | symbol: null, 389 | ingredient: 'noci', 390 | quantity: 4, 391 | minQty: 4, 392 | maxQty: 4, 393 | }); 394 | }), 395 | it('"ingredienti per 4 persone - quattro noci - quattro noci"', () => { 396 | expect(multiLineParse('ingredienti per 4 persone - quattro noci - quattro noci', 'ita')[0]).to.deep.equal({ 397 | unit: null, 398 | unitPlural: null, 399 | symbol: null, 400 | ingredient: 'noci', 401 | quantity: 4, 402 | minQty: 4, 403 | maxQty: 4, 404 | }); 405 | }), 406 | it('"- quattro noci - quattro noci"', () => { 407 | expect(multiLineParse('- quattro noci - quattro noci', 'ita')[0]).to.deep.equal({ 408 | unit: null, 409 | unitPlural: null, 410 | symbol: null, 411 | ingredient: 'noci', 412 | quantity: 4, 413 | minQty: 4, 414 | maxQty: 4, 415 | }); 416 | }), 417 | it('"quattro noci - quattro noci e cinque mele"', () => { 418 | expect(multiLineParse('quattro noci - quattro noci e cinque mele', 'ita')[2]).to.deep.equal({ 419 | unit: null, 420 | unitPlural: null, 421 | symbol: null, 422 | ingredient: 'mele', 423 | quantity: 5, 424 | minQty: 5, 425 | maxQty: 5, 426 | }); 427 | }), 428 | it('"quattro noci - quattro noci"', () => { 429 | expect(multiLineParse('quattro noci - quattro noci', 'ita')[0]).to.deep.equal({ 430 | unit: null, 431 | unitPlural: null, 432 | symbol: null, 433 | ingredient: 'noci', 434 | quantity: 4, 435 | minQty: 4, 436 | maxQty: 4, 437 | }); 438 | }), 439 | it('"tre noci - 8 noci"', () => { 440 | expect(multiLineParse('tre noci - quattro noci', 'ita')[0]).to.deep.equal({ 441 | unit: null, 442 | unitPlural: null, 443 | symbol: null, 444 | ingredient: 'noci', 445 | quantity: 3, 446 | minQty: 3, 447 | maxQty: 3, 448 | }); 449 | }); 450 | it('"👉 tre noci 👉 8 noci"', () => { 451 | expect(multiLineParse('👉 tre noci 👉 quattro noci', 'ita')[0]).to.deep.equal({ 452 | unit: null, 453 | unitPlural: null, 454 | symbol: null, 455 | ingredient: 'noci', 456 | quantity: 3, 457 | minQty: 3, 458 | maxQty: 3, 459 | }); 460 | }); 461 | it('"👉🏻 tre noci 👉 8 noci"', () => { 462 | expect(multiLineParse('👉🏻 tre noci 👉 quattro noci', 'ita')[0]).to.deep.equal({ 463 | unit: null, 464 | unitPlural: null, 465 | symbol: null, 466 | ingredient: 'noci', 467 | quantity: 3, 468 | minQty: 3, 469 | maxQty: 3, 470 | }); 471 | }); 472 | }); 473 | describe('recipe parser ita', () => { 474 | it('returns an object', () => { 475 | expect(typeof parse('1 tazza acqua', 'ita')).to.equal('object'); 476 | }); 477 | describe('translates the unit', () => { 478 | it('of "qb di acqua"', () => { 479 | expect(parse('qb di acqua', 'ita').unit).to.equal('q.b.'); 480 | expect(parse('qb di acqua', 'ita').quantity).to.equal(0); 481 | 482 | }); 483 | it('of "quanto basta acqua"', () => { 484 | expect(parse('quanto basta di acqua', 'ita').unit).to.equal('q.b.'); 485 | }); 486 | it('of "Quanto basta acqua"', () => { 487 | expect(parse('Quanto basta di acqua', 'ita').unit).to.equal('q.b.'); 488 | }); 489 | it('of "Quanto Basta acqua"', () => { 490 | expect(parse('Quanto Basta di acqua', 'ita').unit).to.equal('q.b.'); 491 | }); 492 | it('of "q.b. di farina"', () => { 493 | expect(parse('q.b. di farina', 'ita').ingredient).to.equal('farina'); 494 | }); 495 | it('of "q.b. di farina"', () => { 496 | expect(parse('q.b. di farina', 'ita').unit).to.equal('q.b.'); 497 | }); 498 | it('of "q.b. farina"', () => { 499 | expect(parse('q.b. farina', 'ita').ingredient).to.equal('farina'); 500 | }); 501 | it('of "grammi farina"', () => { 502 | expect(parse('grammi farina', 'ita').unit).to.equal('grammo'); 503 | }); 504 | it('of "grammi farina"', () => { 505 | expect(parse('grammi farina', 'ita').ingredient).to.equal('farina'); 506 | }); 507 | it('of "Q.B. di acqua"', () => { 508 | expect(parse('Q.B. di acqua', 'ita').unit).to.equal('q.b.'); 509 | }); 510 | it('of "acqua quanto basta"', () => { 511 | expect(parse('acqua quanto basta', 'ita').unit).to.equal('q.b.'); 512 | }); 513 | 514 | it('of "QB di acqua"', () => { 515 | expect(parse('QB di acqua', 'ita').unit).to.equal('q.b.'); 516 | }); 517 | it('of "QB. di acqua"', () => { 518 | expect(parse('QB. di acqua', 'ita').unit).to.equal('q.b.'); 519 | }); 520 | it('of "Q.B di acqua"', () => { 521 | expect(parse('Q.b di acqua', 'ita').unit).to.equal('q.b.'); 522 | }); 523 | it('of "1 cucchiao acqua"', () => { 524 | expect(parse('1 cucchiao acqua', 'ita').quantity).to.equal(1); 525 | }); 526 | it('of "1.5 cucchiao acqua"', () => { 527 | expect(parse('1.5 cucchiao acqua', 'ita').quantity).to.equal(1.5); 528 | }); 529 | it('of "1 1/2 cucchiao acqua"', () => { 530 | expect(parse('1 1/2 cucchiao acqua', 'ita').quantity).to.equal(1.5); 531 | }); 532 | it('of "1/3 cucchiao acqua"', () => { 533 | expect(parse('1/3 cucchiao acqua', 'ita').quantity).to.equal(0.33); 534 | }); 535 | it('of "1/2 cucchiao acqua"', () => { 536 | expect(parse('1/2 cucchiao acqua', 'ita').quantity).to.equal(0.5); 537 | }); 538 | it('of "10 1/2 cucchiao acqua"', () => { 539 | expect(parse('10 1/2 cucchiao acqua', 'ita').quantity).to.equal(10.5); 540 | }); 541 | it('of "about 1/2 cucchiao acqua"', () => { 542 | expect(parse('about 1/2 cucchiao acqua', 'ita').quantity).to.equal(0.5); 543 | }); 544 | 545 | describe('translates the quantity from string to number', () => { 546 | it('Un cucchiaio d\'acqua', () => { 547 | expect(parse('Un cucchiaio d\'acqua', 'ita').quantity).to.equal(1); 548 | }); 549 | it('Un cucchiaio d\'acqua', () => { 550 | expect(parse('Un cucchiaio d\'acqua', 'ita').quantity).to.equal(1); 551 | }); 552 | it('mezzo cucchiaio d\'acqua', () => { 553 | expect(parse('mezzo cucchiaio d\'acqua', 'ita').quantity).to.equal(0.5); 554 | }); 555 | it('meta cucchiaio d\'acqua', () => { 556 | expect(parse('meta cucchiaio d\'acqua', 'ita').quantity).to.equal(0.5); 557 | }); 558 | it('Venti cucchiai d\'acqua"', () => { 559 | expect(parse('Venti cucchiai d\'acqua', 'ita').quantity).to.equal(20); 560 | }); 561 | it('cinque cucchiai d\'acqua"', () => { 562 | expect(parse('cinque cucchiai d\'acqua', 'ita').quantity).to.equal(5); 563 | }); 564 | it('ventuno cucchiai d\'acqua"', () => { 565 | expect(parse('ventuno cucchiai d\'acqua', 'ita').quantity).to.equal(21); 566 | }); 567 | it('mezzo spicchio d\'aglio"', () => { 568 | expect(parse('mezzo spicchio d\'aglio', 'ita').quantity).to.equal(0.5); 569 | }); 570 | it('cento grammi d\'aglio"', () => { 571 | expect(parse('cento grammi d\'aglio', 'ita').quantity).to.equal(100); 572 | }); 573 | it('cento-due grammi d\'aglio"', () => { 574 | expect(parse('cento-due grammi d\'aglio', 'ita').quantity).to.equal(102); 575 | }); 576 | it('due-cento grammi d\'aglio"', () => { 577 | expect(parse('due-cento grammi d\'aglio', 'ita').quantity).to.equal(200); 578 | }); 579 | it('due-mila grammi d\'aglio"', () => { 580 | expect(parse('due-mila grammi d\'aglio', 'ita').quantity).to.equal(2000); 581 | }); 582 | it('due grammi farina"', () => { 583 | expect(parse('due grammi farina', 'ita').quantity).to.equal(2); 584 | }); 585 | }); 586 | 587 | // describe('translates the quantity range', () => { 588 | // it('of "10-20 cucchiao acqua"', () => { 589 | // expect(parse('10-20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 590 | // }); 591 | // it('of "10 - 20 cucchiao acqua"', () => { 592 | // expect(parse('10 - 20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 593 | // }); 594 | // it('of "10 to 20 cucchiao acqua"', () => { 595 | // expect(parse('10 to 20 cucchiao acqua', 'ita').quantity).to.equal('10-20'); 596 | // }); 597 | // }); 598 | 599 | 600 | describe('of unicode fractions', () => { 601 | const unicodeAmounts = ['¼', '½', '¾', '⅐', '⅑', '⅒', '⅓', '⅔', '⅕', '⅖', '⅗', '⅘', '⅙', '⅚', '⅛', '⅜', '⅝', '⅞']; 602 | const unicodeExpectedAmounts = [0.25, 0.5, 0.75, 0.14, 0.11, 0.1, 0.33, 0.66, 0.2, 0.4, 0.6, 0.8, 0.16, 0.83, 0.12, 0.37, 0.62, 0.87]; 603 | 604 | for (let u = 0; u < unicodeAmounts.length; u++) { 605 | const element = unicodeAmounts[u]; 606 | const expectedAmount = unicodeExpectedAmounts[u]; 607 | it(`${element} to ${expectedAmount}`, () => { 608 | expect(parse(`${element} cucchiao acqua`, 'ita').quantity).to.equal(expectedAmount); 609 | }); 610 | } 611 | 612 | const mixedValues = ['1¼', '2½', '3¾', '4⅐', '5⅑', '6⅒', '7⅓', '8⅔', '9⅕', '10⅖', '11⅗', '12⅘', '13⅙', '14⅚', '15⅛', '16⅜', '17⅝', '18⅞']; 613 | const mixedExpectedValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; 614 | 615 | for (let u = 0; u < mixedValues.length; u++) { 616 | const element = mixedValues[u]; 617 | const expectedAmount = (Number(mixedExpectedValues[u]) + Number(unicodeExpectedAmounts[u])); 618 | it(`${element} to ${expectedAmount}`, () => { 619 | expect(parse(`${element} cucchiao acqua`, 'ita').quantity).to.equal(expectedAmount); 620 | }); 621 | } 622 | }); 623 | 624 | it('doesn\'t freak out if a strange unicode character is present', () => { 625 | expect(parse('1/3 tazza zucchero a velo', 'ita')).to.deep.equal({ 626 | quantity: 0.33, 627 | unit: 'tazza', 628 | unitPlural: 'tazze', 629 | symbol: null, 630 | ingredient: 'zucchero a velo', 631 | minQty: 0.33, 632 | maxQty: 0.33, 633 | }); 634 | }); 635 | }); 636 | 637 | describe('translates the literal units', () => { 638 | it('of "1 tazza acqua"', () => { 639 | expect(parse('1 tazza acqua', 'ita').unit).to.equal('tazza'); 640 | }); 641 | it('of "1 litro acqua"', () => { 642 | expect(parse('1 litro acqua', 'ita').unit).to.equal('litro'); 643 | }); 644 | it('of "1 lt acqua"', () => { 645 | expect(parse('1 lt acqua', 'ita').unit).to.equal('litro'); 646 | }); 647 | it('of "1 kg acqua"', () => { 648 | expect(parse('1 kg acqua', 'ita').unit).to.equal('chilogrammo'); 649 | }); 650 | it('of "1 L acqua"', () => { 651 | expect(parse('1 L acqua', 'ita').unit).to.equal('litro'); 652 | }); 653 | it('of "1 L. acqua"', () => { 654 | expect(parse('1 L. acqua', 'ita').unit).to.equal('litro'); 655 | }); 656 | it('of "1 cucchiaio acqua"', () => { 657 | expect(parse('1 cucchiaio acqua', 'ita').unit).to.equal('cucchiaio'); 658 | }); 659 | it('of "1 cucchiaio acqua"', () => { 660 | expect(parse('1 cucchiaio acqua', 'ita').unit).to.equal('cucchiaio'); 661 | }); 662 | it('of "1 grammo acqua"', () => { 663 | expect(parse('1 grammo acqua', 'ita').unit).to.equal('grammo'); 664 | }); 665 | it('of "1 chilogrammo acqua"', () => { 666 | expect(parse('1 chilogrammo acqua', 'ita').unit).to.equal('chilogrammo'); 667 | }); 668 | it('of "1 litro acqua"', () => { 669 | expect(parse('1 litro acqua', 'ita').unit).to.equal('litro'); 670 | }); 671 | it('of "1 milligrammo acqua"', () => { 672 | expect(parse('1 milligrammo acqua', 'ita').unit).to.equal('milligrammo'); 673 | }); 674 | it('of "1 millilitro acqua"', () => { 675 | expect(parse('1 millilitro acqua', 'ita').unit).to.equal('millilitro'); 676 | }); 677 | it('of "1 l cipolla"', () => { 678 | expect(parse('1 l cipolla', 'ita').unit).to.equal("litro"); 679 | }); 680 | it('of "1 cipolla intera"', () => { 681 | expect(parse('1 cipolla intera', 'ita').unit).to.equal(null); 682 | }); 683 | it('of "1 spicchio agilio"', () => { 684 | expect(parse('1 spicchio agilio', 'ita').unit).to.equal('spicchio'); 685 | }); 686 | it('of "1 bustina aglio"', () => { 687 | expect(parse('1 bustina aglio', 'ita').unit).to.equal('bustina'); 688 | }); 689 | it('of "1 pacco salsicce"', () => { 690 | expect(parse('1 pacco salsicce', 'ita').unit).to.equal('pacco'); 691 | }); 692 | it('"1 pizzico sale"', () => { 693 | expect(parse('1 pizzico sale', 'ita').unit).to.equal('pizzico'); 694 | }); 695 | it('"1 foglia prezzemolo"', () => { 696 | expect(parse('1 foglia prezzemolo', 'ita').unit).to.equal('foglia'); 697 | }); 698 | it('"1 mazzetto prezzemolo"', () => { 699 | expect(parse('1 mazzetto prezzemolo', 'ita').unit).to.equal('mazzetto'); 700 | }); 701 | it('"1 vasetto yogurt"', () => { 702 | expect(parse('1 vasetto yogurt', 'ita').unit).to.equal('vasetto'); 703 | }); 704 | it('"1 (14.5 oz) lattina pommodori"', () => { 705 | expect(parse('1 (14.5 oz) lattina pommodori', 'ita')).to.deep.equal({ 706 | unit: 'lattina', 707 | unitPlural: 'lattine', 708 | symbol: null, 709 | quantity: 1, 710 | ingredient: 'pommodori (14.5 oz)', 711 | minQty: 1, 712 | maxQty: 1, 713 | }); 714 | }); 715 | // it('"parses ingredient with range: 1 to 2 petto di pollo"', () => { 716 | // expect(parse('1 to 2 petto di pollo', 'ita')).to.deep.equal({ 717 | // unit: null, 718 | // unitPlural: null, 719 | // symbol: null, 720 | // quantity: '1-2', 721 | // ingredient: 'petto di pollo', 722 | // minQty: '1', 723 | // maxQty: '2', 724 | // }); 725 | // }); 726 | // it('"parses ingredient with range: 1 - 2 petto di pollo"', () => { 727 | // expect(parse('1 - 2 petto di pollo', 'ita')).to.deep.equal({ 728 | // unit: null, 729 | // unitPlural: null, 730 | // symbol: null, 731 | // quantity: '1-2', 732 | // ingredient: 'petto di pollo', 733 | // minQty: '1', 734 | // maxQty: '2', 735 | // }); 736 | // }); 737 | // it('"parses ingredient with range: 1-2 petto di pollo"', () => { 738 | // expect(parse('1-2 petto di pollo', 'ita')).to.deep.equal({ 739 | // unit: null, 740 | // unitPlural: null, 741 | // symbol: null, 742 | // quantity: '1-2', 743 | // ingredient: 'petto di pollo', 744 | // minQty: 1, 745 | // maxQty: 2, 746 | // }); 747 | // }); 748 | it('"1 (16 oz) scatola pasta"', () => { 749 | expect(parse('1 (16 oz) scatola pasta', 'ita')).to.deep.equal({ 750 | unit: 'scatola', 751 | unitPlural: 'scatole', 752 | symbol: null, 753 | quantity: 1, 754 | ingredient: 'pasta (16 oz)', 755 | minQty: 1, 756 | maxQty: 1, 757 | }); 758 | }); 759 | it('"1 fetta di formaggio"', () => { 760 | expect(parse('1 fetta di formaggio', 'ita')).to.deep.equal({ 761 | unit: 'fetta', 762 | unitPlural: 'fette', 763 | quantity: 1, 764 | symbol: null, 765 | ingredient: 'formaggio', 766 | minQty: 1, 767 | maxQty: 1, 768 | }); 769 | }); 770 | it('"1 spicchio d\'aglio"', () => { 771 | expect(parse('1 spicchio d\'aglio', 'ita')).to.deep.equal({ 772 | unit: 'spicchio', 773 | unitPlural: 'spicchi', 774 | quantity: 1, 775 | symbol: null, 776 | ingredient: 'aglio', 777 | minQty: 1, 778 | maxQty: 1, 779 | }); 780 | }); 781 | describe('" check the correct symbol"', () => { 782 | it('"grammi di farina"', () => { 783 | expect(parse('grammi di farina', 'ita')).to.deep.equal({ 784 | unit: 'grammo', 785 | unitPlural: 'grammi', 786 | quantity: 0, 787 | symbol: 'g', 788 | ingredient: 'farina', 789 | minQty: 0, 790 | maxQty: 0, 791 | }); 792 | }); 793 | it('"100 grammi di farina"', () => { 794 | expect(parse('100 grammi di farina', 'ita')).to.deep.equal({ 795 | unit: 'grammo', 796 | unitPlural: 'grammi', 797 | quantity: 100, 798 | symbol: 'g', 799 | ingredient: 'farina', 800 | minQty: 100, 801 | maxQty: 100, 802 | }); 803 | }); 804 | it('"1 spicchio d\'aglio"', () => { 805 | expect(parse('1 spicchio d\'aglio', 'ita')).to.deep.equal({ 806 | unit: 'spicchio', 807 | unitPlural: 'spicchi', 808 | quantity: 1, 809 | symbol: null, 810 | ingredient: 'aglio', 811 | minQty: 1, 812 | maxQty: 1, 813 | }); 814 | }); 815 | it('"1 kilogrammo d\'aglio"', () => { 816 | expect(parse('1 kilogrammo d\'aglio', 'ita')).to.deep.equal({ 817 | unit: 'chilogrammo', 818 | unitPlural: 'chilogrammi', 819 | quantity: 1, 820 | symbol: 'kg', 821 | ingredient: 'aglio', 822 | minQty: 1, 823 | maxQty: 1, 824 | }); 825 | }); 826 | it('"1 cucchiaino riso"', () => { 827 | expect(parse('1 cucchiaino riso', 'ita')).to.deep.equal({ 828 | unit: 'cucchiaino', 829 | unitPlural: 'cucchiaini', 830 | quantity: 1, 831 | symbol: 'cc', 832 | ingredient: 'riso', 833 | minQty: 1, 834 | maxQty: 1, 835 | }); 836 | }); 837 | it('"100 litri di latte"', () => { 838 | expect(parse('100 litri di latte', 'ita')).to.deep.equal({ 839 | unit: 'litro', 840 | unitPlural: 'litri', 841 | quantity: 100, 842 | symbol: 'lt', 843 | ingredient: 'latte', 844 | minQty: 100, 845 | maxQty: 100, 846 | }); 847 | }); 848 | it('"100 milligrammi di olio"', () => { 849 | expect(parse('100 milligrammi di olio', 'ita')).to.deep.equal({ 850 | unit: 'milligrammo', 851 | unitPlural: 'milligrammi', 852 | quantity: 100, 853 | symbol: 'mg', 854 | ingredient: 'olio', 855 | minQty: 100, 856 | maxQty: 100, 857 | }); 858 | }); 859 | it('"100 rotoli di olio"', () => { 860 | expect(parse('100 rotoli di olio', 'ita')).to.deep.equal({ 861 | unit: 'rotolo', 862 | unitPlural: 'rotoli', 863 | quantity: 100, 864 | symbol: null, 865 | ingredient: 'olio', 866 | minQty: 100, 867 | maxQty: 100, 868 | }); 869 | }); 870 | it('"100 bicchierini di olio"', () => { 871 | expect(parse('100 bicchierino di olio', 'ita')).to.deep.equal({ 872 | unit: 'bicchierino', 873 | unitPlural: 'bicchierini', 874 | quantity: 100, 875 | symbol: null, 876 | ingredient: 'olio', 877 | minQty: 100, 878 | maxQty: 100, 879 | }); 880 | }); 881 | it('"Un filo d\'olio"', () => { 882 | expect(parse('Un filo d\'olio', 'ita')).to.deep.equal({ 883 | unit: 'filo', 884 | unitPlural: 'fili', 885 | quantity: 1, 886 | symbol: null, 887 | ingredient: 'olio', 888 | minQty: 1, 889 | maxQty: 1, 890 | }); 891 | }); 892 | it('"Un ciuffo di prezzemolo"', () => { 893 | expect(parse('Un ciuffo di prezzemolo', 'ita')).to.deep.equal({ 894 | unit: 'ciuffo', 895 | unitPlural: 'ciuffi', 896 | quantity: 1, 897 | symbol: null, 898 | ingredient: 'prezzemolo', 899 | minQty: 1, 900 | maxQty: 1, 901 | }); 902 | }); 903 | it('"100 millilitri di latte"', () => { 904 | expect(parse('100 millilitri di latte', 'ita')).to.deep.equal({ 905 | unit: 'millilitro', 906 | unitPlural: 'millilitri', 907 | quantity: 100, 908 | symbol: 'ml', 909 | ingredient: 'latte', 910 | minQty: 100, 911 | maxQty: 100, 912 | }); 913 | }); 914 | it('"quanto basta di latte"', () => { 915 | expect(parse('quanto basta di latte', 'ita')).to.deep.equal({ 916 | unit: "q.b.", 917 | unitPlural: "q.b.", 918 | quantity: 0, 919 | symbol: null, 920 | ingredient: 'latte', 921 | minQty: 0, 922 | maxQty: 0, 923 | }); 924 | }); 925 | it('"Quanto Basta di latte"', () => { 926 | expect(parse('quanto basta di latte', 'ita')).to.deep.equal({ 927 | unit: "q.b.", 928 | unitPlural: "q.b.", 929 | quantity: 0, 930 | symbol: null, 931 | ingredient: 'latte', 932 | minQty: 0, 933 | maxQty: 0, 934 | }); 935 | }); 936 | it('"qb di latte"', () => { 937 | expect(parse('quanto basta di latte', 'ita')).to.deep.equal({ 938 | unit: "q.b.", 939 | unitPlural: "q.b.", 940 | quantity: 0, 941 | symbol: null, 942 | ingredient: 'latte', 943 | minQty: 0, 944 | maxQty: 0, 945 | }); 946 | }); 947 | it('"q.b. di latte"', () => { 948 | expect(parse('q.b. di latte', 'ita')).to.deep.equal({ 949 | unit: "q.b.", 950 | unitPlural: "q.b.", 951 | quantity: 0, 952 | symbol: null, 953 | ingredient: 'latte', 954 | minQty: 0, 955 | maxQty: 0, 956 | }); 957 | }); 958 | it('"q.b. latte"', () => { 959 | expect(parse('q.b. latte', 'ita')).to.deep.equal({ 960 | unit: "q.b.", 961 | unitPlural: "q.b.", 962 | quantity: 0, 963 | symbol: null, 964 | ingredient: 'latte', 965 | minQty: 0, 966 | maxQty: 0, 967 | }); 968 | }); 969 | }); 970 | }); 971 | 972 | it('translates unit when no unit provided', () => { 973 | expect(parse('1 tortilla', 'ita')).to.deep.equal({ 974 | unit: null, 975 | unitPlural: null, 976 | symbol: null, 977 | ingredient: 'tortilla', 978 | quantity: 1, 979 | minQty: 1, 980 | maxQty: 1, 981 | }); 982 | }); 983 | it('test order and case sensitive', () => { 984 | expect(parse('100 ml. tortilla ', 'ita')).to.deep.equal({ 985 | unit: 'millilitro', 986 | unitPlural: 'millilitri', 987 | symbol: 'ml', 988 | ingredient: 'tortilla', 989 | quantity: 100, 990 | minQty: 100, 991 | maxQty: 100, 992 | }); 993 | expect(parse('100 mg. tortilla ', 'ita')).to.deep.equal({ 994 | unit: 'milligrammo', 995 | unitPlural: 'milligrammi', 996 | symbol: 'mg', 997 | ingredient: 'tortilla', 998 | quantity: 100, 999 | minQty: 100, 1000 | maxQty: 100, 1001 | }); 1002 | expect(parse('100 g. tortilla ', 'ita')).to.deep.equal({ 1003 | unit: 'grammo', 1004 | unitPlural: 'grammi', 1005 | symbol: 'g', 1006 | ingredient: 'tortilla', 1007 | quantity: 100, 1008 | minQty: 100, 1009 | maxQty: 100, 1010 | }); 1011 | expect(parse('1 g. d\' acqua', 'ita')).to.deep.equal({ 1012 | unit: 'grammo', 1013 | unitPlural: 'grammi', 1014 | symbol: 'g', 1015 | ingredient: 'acqua', 1016 | quantity: 1, 1017 | minQty: 1, 1018 | maxQty: 1, 1019 | }); 1020 | expect(parse('100 g. di tortilla ', 'ita')).to.deep.equal({ 1021 | unit: 'grammo', 1022 | unitPlural: 'grammi', 1023 | symbol: 'g', 1024 | ingredient: 'tortilla', 1025 | quantity: 100, 1026 | minQty: 100, 1027 | maxQty: 100, 1028 | }); 1029 | expect(parse('100 G. di tortilla ', 'ita')).to.deep.equal({ 1030 | unit: 'grammo', 1031 | unitPlural: 'grammi', 1032 | symbol: 'g', 1033 | ingredient: 'tortilla', 1034 | quantity: 100, 1035 | minQty: 100, 1036 | maxQty: 100, 1037 | }); 1038 | expect(parse('100 G di tortilla ', 'ita')).to.deep.equal({ 1039 | unit: 'grammo', 1040 | unitPlural: 'grammi', 1041 | symbol: 'g', 1042 | ingredient: 'tortilla', 1043 | quantity: 100, 1044 | minQty: 100, 1045 | maxQty: 100, 1046 | }); 1047 | expect(parse('q.b. di sale', 'ita')).to.deep.equal({ 1048 | unit: 'q.b.', 1049 | unitPlural: "q.b.", 1050 | symbol: null, 1051 | ingredient: 'sale', 1052 | quantity: 0, 1053 | minQty: 0, 1054 | maxQty: 0, 1055 | }); 1056 | expect(parse('100 gr. tortilla ', 'ita')).to.deep.equal({ 1057 | unit: 'grammo', 1058 | unitPlural: 'grammi', 1059 | symbol: 'g', 1060 | ingredient: 'tortilla', 1061 | quantity: 100, 1062 | minQty: 100, 1063 | maxQty: 100, 1064 | }); 1065 | expect(parse('tortilla 100 gr', 'ita')).to.deep.equal({ 1066 | unit: 'grammo', 1067 | unitPlural: 'grammi', 1068 | symbol: 'g', 1069 | ingredient: 'tortilla', 1070 | quantity: 100, 1071 | minQty: 100, 1072 | maxQty: 100, 1073 | }); 1074 | expect(parse('basilico quanto basta', 'ita')).to.deep.equal({ 1075 | unit: 'q.b.', 1076 | unitPlural: "q.b.", 1077 | symbol: null, 1078 | ingredient: 'basilico', 1079 | quantity: 0, 1080 | minQty: 0, 1081 | maxQty: 0, 1082 | }); 1083 | expect(parse('basilico q.b.', 'ita')).to.deep.equal({ 1084 | unit: 'q.b.', 1085 | unitPlural: "q.b.", 1086 | symbol: null, 1087 | ingredient: 'basilico', 1088 | quantity: 0, 1089 | minQty: 0, 1090 | maxQty: 0, 1091 | }); 1092 | expect(parse('basilico QB', 'ita')).to.deep.equal({ 1093 | unit: 'q.b.', 1094 | unitPlural: "q.b.", 1095 | symbol: null, 1096 | ingredient: 'basilico', 1097 | quantity: 0, 1098 | minQty: 0, 1099 | maxQty: 0, 1100 | }); 1101 | expect(parse('basilico millilitri 100', 'ita')).to.deep.equal({ 1102 | unit: 'millilitro', 1103 | unitPlural: 'millilitri', 1104 | symbol: 'ml', 1105 | ingredient: 'basilico', 1106 | quantity: 100, 1107 | minQty: 100, 1108 | maxQty: 100, 1109 | }); 1110 | }); 1111 | it('doesn\'t explode when no unit and no quantity provided', () => { 1112 | expect(parse('zucchero a velo', 'ita')).to.deep.equal({ 1113 | unit: 'q.b.', 1114 | unitPlural: 'q.b.', 1115 | symbol: null, 1116 | ingredient: 'zucchero a velo', 1117 | quantity: 0, 1118 | minQty: 0, 1119 | maxQty: 0, 1120 | }); 1121 | }); 1122 | it('test noci', () => { 1123 | expect(parse('quattro noci', 'ita')).to.deep.equal({ 1124 | unit: null, 1125 | unitPlural: null, 1126 | symbol: null, 1127 | ingredient: 'noci', 1128 | quantity: 4, 1129 | minQty: 4, 1130 | maxQty: 4, 1131 | }); 1132 | expect(parse('una noce', 'ita')).to.deep.equal({ 1133 | unit: null, 1134 | unitPlural: null, 1135 | symbol: null, 1136 | ingredient: 'noce', 1137 | quantity: 1, 1138 | minQty: 1, 1139 | maxQty: 1, 1140 | }); 1141 | expect(parse('100 gr di noci', 'ita')).to.deep.equal({ 1142 | unit: 'grammo', 1143 | unitPlural: 'grammi', 1144 | symbol: 'g', 1145 | ingredient: 'noci', 1146 | quantity: 100, 1147 | minQty: 100, 1148 | maxQty: 100, 1149 | }); 1150 | }); 1151 | describe('translates the abbreviated units of', () => { 1152 | it('"1 tazza acqua"', () => { 1153 | expect(parse('1 tazza acqua', 'ita').unit).to.equal('tazza'); 1154 | expect(parse('2 tazzine acqua', 'ita').unit).to.equal('tazza'); 1155 | expect(parse('2 tazze acqua', 'ita').unit).to.equal('tazza'); 1156 | }); 1157 | it('"1 litro acqua"', () => { 1158 | expect(parse('1 l acqua', 'ita').unit).to.equal('litro'); 1159 | expect(parse('1 litri acqua', 'ita').unit).to.equal('litro'); 1160 | }); 1161 | it('"1 grammo acqua"', () => { 1162 | expect(parse('1 gr acqua', 'ita').unit).to.equal('grammo'); 1163 | expect(parse('2 g acqua', 'ita').unit).to.equal('grammo'); 1164 | expect(parse('2 g. acqua', 'ita').ingredient).to.equal('acqua'); 1165 | 1166 | }); 1167 | it('"1 chilogrammo acqua"', () => { 1168 | expect(parse('1 kg acqua', 'ita').unit).to.equal('chilogrammo'); 1169 | expect(parse('2 KG acqua', 'ita').unit).to.equal('chilogrammo'); 1170 | expect(parse('1 kilogrammo acqua', 'ita').unit).to.equal('chilogrammo'); 1171 | expect(parse('2 Kilogrammo acqua', 'ita').unit).to.equal('chilogrammo'); 1172 | expect(parse('acqua KILOGRAMMO 2', 'ita').unit).to.equal('chilogrammo'); 1173 | expect(parse('acqua KILOGRAMMO due', 'ita').unit).to.equal('chilogrammo'); 1174 | 1175 | }); 1176 | it('"1 tazza acqua"', () => { 1177 | expect(parse('1 tazza acqua', 'ita').unit).to.equal('tazza'); 1178 | expect(parse('1 tazzina acqua', 'ita').unit).to.equal('tazza'); 1179 | expect(parse('2 tazzine acqua', 'ita').unit).to.equal('tazza'); 1180 | expect(parse('2 Tazza acqua', 'ita').unit).to.equal('tazza'); 1181 | }); 1182 | it('"1 millilitro acqua"', () => { 1183 | expect(parse('1 ml acqua', 'ita').unit).to.equal('millilitro'); 1184 | expect(parse('1 ml. acqua', 'ita').unit).to.equal('millilitro'); 1185 | expect(parse('1 millilitro acqua', 'ita').unit).to.equal('millilitro'); 1186 | expect(parse('1 Millilitro acqua', 'ita').unit).to.equal('millilitro'); 1187 | }); 1188 | it('"1 cucchiaio acqua"', () => { 1189 | expect(parse('2 cucchiai acqua', 'ita').unit).to.equal('cucchiaio'); 1190 | expect(parse('1 Cucchiaio acqua', 'ita').unit).to.equal('cucchiaio'); 1191 | expect(parse('2 cucchiai acqua', 'ita').unit).to.equal('cucchiaio'); 1192 | }); 1193 | it('"1 cucchiaino acqua"', () => { 1194 | expect(parse('1 Cucchiaino acqua', 'ita').unit).to.equal('cucchiaino'); 1195 | expect(parse('1 cucchiaino acqua', 'ita').unit).to.equal('cucchiaino'); 1196 | expect(parse('2 Cucchiaini acqua', 'ita').unit).to.equal('cucchiaino'); 1197 | expect(parse('2 cucchiaini acqua', 'ita').unit).to.equal('cucchiaino'); 1198 | }); 1199 | it('"1 grammo acqua"', () => { 1200 | expect(parse('1 g acqua', 'ita').unit).to.equal('grammo'); 1201 | expect(parse('1 g. acqua', 'ita').unit).to.equal('grammo'); 1202 | expect(parse('2 grammi acqua', 'ita').unit).to.equal('grammo'); 1203 | }); 1204 | it('"1 chilogrammo acqua"', () => { 1205 | expect(parse('1 kg acqua', 'ita').unit).to.equal('chilogrammo'); 1206 | expect(parse('1 kg. acqua', 'ita').unit).to.equal('chilogrammo'); 1207 | expect(parse('2 chilogrammi acqua', 'ita').unit).to.equal('chilogrammo'); 1208 | }); 1209 | it('"1 litro acqua"', () => { 1210 | expect(parse('1 l acqua', 'ita').unit).to.equal('litro'); 1211 | expect(parse('1 l. acqua', 'ita').unit).to.equal('litro'); 1212 | expect(parse('2 litri acqua', 'ita').unit).to.equal('litro'); 1213 | }); 1214 | it('"1 milligrammo acqua"', () => { 1215 | expect(parse('1 mg acqua', 'ita').unit).to.equal('milligrammo'); 1216 | expect(parse('1 mg. acqua', 'ita').unit).to.equal('milligrammo'); 1217 | expect(parse('1 milligrammo acqua', 'ita').unit).to.equal('milligrammo'); 1218 | }); 1219 | it('"1 millilitro acqua"', () => { 1220 | expect(parse('1 ml acqua', 'ita').unit).to.equal('millilitro'); 1221 | expect(parse('1 ml. acqua', 'ita').unit).to.equal('millilitro'); 1222 | expect(parse('1 millilitro acqua', 'ita').unit).to.equal('millilitro'); 1223 | }); 1224 | it('"1 pizzico acqua"', () => { 1225 | expect(parse('2 pizzichi sale', 'ita').unit).to.equal('pizzico'); 1226 | }); 1227 | it('"1 cubetto di ghiaccio"', () => { 1228 | expect(parse('2 cubetto di ghiaccio', 'ita').unit).to.equal('cubetto'); 1229 | }); 1230 | }); 1231 | 1232 | describe('translates the ingredient of', () => { 1233 | it('"1 cucchiaio d\'acqua"', () => { 1234 | expect(parse('1 cucchiaio d\'acqua', 'ita').ingredient).to.equal('acqua'); 1235 | }); 1236 | it('"1 spicchio d\'aglio"', () => { 1237 | expect(parse('1 cucchiaio d\'acqua', 'ita').ingredient).to.equal('acqua'); 1238 | }); 1239 | it('"1 cucchiaio di latte"', () => { 1240 | expect(parse('1 cucchiaio di latte', 'ita').ingredient).to.equal('latte'); 1241 | }); 1242 | it('"1 cucchiaio acqua"', () => { 1243 | expect(parse('1 cucchiaio acqua', 'ita').ingredient).to.equal('acqua'); 1244 | }); 1245 | it('"1 cucchiaio latte"', () => { 1246 | expect(parse('1 cucchiaio latte', 'ita').ingredient).to.equal('latte'); 1247 | }); 1248 | }); 1249 | 1250 | describe('translates the ingredient of', () => { 1251 | it('"1 g di latte"', () => { 1252 | expect(parse('1 g di latte', 'ita').ingredient).to.equal('latte'); 1253 | }); 1254 | it('"1 kg di latte"', () => { 1255 | expect(parse('1 kg di latte', 'ita').ingredient).to.equal('latte'); 1256 | }); 1257 | it('"250 kg di farina"', () => { 1258 | expect(parse('250 kg di farina', 'ita').ingredient).to.equal('farina'); 1259 | }); 1260 | it('"dieci kg farina"', () => { 1261 | expect(parse('dieci kg farina', 'ita').ingredient).to.equal('farina'); 1262 | }); 1263 | it('"dieci kg farina"', () => { 1264 | expect(parse('dieci kg farina', 'ita').ingredient).to.equal('farina'); 1265 | }); 1266 | it('"3 g spaghetti"', () => { 1267 | expect(parse('3 g spaghetti', 'ita').ingredient).to.equal('spaghetti'); 1268 | }); 1269 | it('"3 mg spamghetti"', () => { 1270 | expect(parse('3 mg spamghetti', 'ita').ingredient).to.equal('spamghetti'); 1271 | }); 1272 | }); 1273 | describe('translates q.b. without quantity of', () => { 1274 | it('"latte"', () => { 1275 | expect(parse('latte', 'ita').unit).to.equal('q.b.'); 1276 | }); 1277 | it('"farina"', () => { 1278 | expect(parse('farina', 'ita').unit).to.equal('q.b.'); 1279 | }); 1280 | it('"250 kg di farina"', () => { 1281 | expect(parse('250 kg di farina', 'ita').quantity).to.equal(250); 1282 | }); 1283 | 1284 | }); 1285 | describe('translates bug with g', () => { 1286 | it('"sgombro 300 g"', () => { 1287 | expect(parse('sgombro 300 g', 'ita').ingredient).to.equal('sgombro'); 1288 | }); 1289 | it('"lamle 300 ml"', () => { 1290 | expect(parse('lamle 300 ml', 'ita').ingredient).to.equal('lamle'); 1291 | }); 1292 | it('"lamge 300 mg"', () => { 1293 | expect(parse('lamge 300 mg', 'ita').ingredient).to.equal('lamge'); 1294 | }); 1295 | it('"lamge 1/3 mg"', () => { 1296 | expect(parse('lamge 1/3 mg', 'ita').quantity).to.equal(0.33); 1297 | }); 1298 | it('"guanciale 100 g"', () => { 1299 | expect(parse('guanciale 100 g', 'ita').ingredient).to.equal('guanciale'); 1300 | }); 1301 | it('"Guanciale 100 g"', () => { 1302 | expect(parse('Guanciale 100 g', 'ita').ingredient).to.equal('guanciale'); 1303 | }); 1304 | it('"cuangiale 100 g"', () => { 1305 | expect(parse('cuangiale 100 g', 'ita').ingredient).to.equal('cuangiale'); 1306 | }); 1307 | }); 1308 | }); 1309 | 1310 | ///// 1311 | 1312 | //describe('combine ingredients', () => { 1313 | // it('accepts an empty array', () => { 1314 | // expect(combine([])).to.deep.equal([]); 1315 | // }); 1316 | // 1317 | // it('returns sorted ingredients', () => { 1318 | // const ingredientArray = [ 1319 | // { 1320 | // ingredient: 'butter', 1321 | // quantity: 2, 1322 | // unit: 'tablespoon', 1323 | // symbol: 'tbs', 1324 | // minQty: 2, 1325 | //// maxQty: 2, 1326 | //// }, 1327 | //// { 1328 | //// ingredient: 'apples', 1329 | //// quantity: 2, 1330 | //// unit: 'pound', 1331 | //// symbol: 'lb', 1332 | //// minQty: 2, 1333 | //// maxQty: 2, 1334 | //// } 1335 | //// ]; 1336 | //// expect(combine(ingredientArray)).to.deep.equal([ 1337 | //// { 1338 | //// ingredient: 'apples', 1339 | //// quantity: 2, 1340 | //// unit: 'pound', 1341 | //// symbol: 'lb', 1342 | // minQty: 2, 1343 | // maxQty: 2, 1344 | // }, 1345 | // { 1346 | // ingredient: 'butter', 1347 | // quantity: 2, 1348 | // unit: 'tablespoon', 1349 | // symbol: 'tbs', 1350 | // minQty: 2, 1351 | // maxQty: 2, 1352 | // } 1353 | // ]); 1354 | // }); 1355 | 1356 | // it('combines two ingredient objects into one', () => { 1357 | // const ingredientArray = [ 1358 | // { 1359 | // ingredient: 'butter', 1360 | // quantity: '2', 1361 | // unit: 'tablespoon', 1362 | // symbol: 'tbs', 1363 | // minQty: '2', 1364 | // maxQty: '2', 1365 | // }, 1366 | // { 1367 | // ingredient: 'butter', 1368 | // quantity: '2', 1369 | // unit: 'tablespoon', 1370 | // symbol: 'tbs', 1371 | // minQty: '2', 1372 | // maxQty: '2', 1373 | // } 1374 | // ]; 1375 | // expect(combine(ingredientArray)).to.deep.equal([ 1376 | // { 1377 | // ingredient: 'butter', 1378 | // quantity: '4', 1379 | // unit: 'tablespoon', 1380 | // symbol: 'tbs', 1381 | // minQty: '4', 1382 | // maxQty: '4', 1383 | // } 1384 | // ]); 1385 | // }); 1386 | 1387 | // it('combines three ingredient objects into one', () => { 1388 | // const ingredientArray = [ 1389 | // { 1390 | // ingredient: 'butter', 1391 | // quantity: '2', 1392 | // unit: 'tablespoon', 1393 | // symbol: 'tbs', 1394 | // minQty: '2', 1395 | // maxQty: '2', 1396 | // }, 1397 | // { 1398 | // ingredient: 'butter', 1399 | // quantity: '2', 1400 | // unit: 'tablespoon', 1401 | // symbol: 'tbs', 1402 | // minQty: '2', 1403 | // maxQty: '2', 1404 | // }, 1405 | // { 1406 | // ingredient: 'butter', 1407 | // quantity: '2', 1408 | // unit: 'tablespoon', 1409 | // symbol: 'tbs', 1410 | // minQty: '2', 1411 | // maxQty: '2', 1412 | // } 1413 | // ]; 1414 | // expect(combine(ingredientArray)).to.deep.equal([ 1415 | // { 1416 | // ingredient: 'butter', 1417 | // quantity: '6', 1418 | // unit: 'tablespoon', 1419 | // symbol: 'tbs', 1420 | // minQty: '6', 1421 | // maxQty: '6', 1422 | // } 1423 | // ]); 1424 | // }); 1425 | 1426 | // it('combines four ingredient objects into two', () => { 1427 | // const ingredientArray = [ 1428 | // { 1429 | // ingredient: 'butter', 1430 | // quantity: '2', 1431 | // unit: 'tablespoon', 1432 | // minQty: '2', 1433 | // maxQty: '2', 1434 | // }, 1435 | // { 1436 | // ingredient: 'butter', 1437 | // quantity: '2', 1438 | // unit: 'tablespoon', 1439 | // minQty: '2', 1440 | // maxQty: '2', 1441 | // }, 1442 | // { 1443 | // ingredient: 'butter', 1444 | // quantity: '2', 1445 | // unit: 'tablespoon', 1446 | // minQty: '2', 1447 | // maxQty: '2', 1448 | // }, 1449 | // { 1450 | // ingredient: 'apple', 1451 | // quantity: '2', 1452 | // unit: 'pound', 1453 | // minQty: '2', 1454 | // maxQty: '2', 1455 | // } 1456 | // ]; 1457 | // expect(combine(ingredientArray)).to.deep.equal([ 1458 | // { 1459 | // ingredient: 'apple', 1460 | // quantity: '2', 1461 | // unit: 'pound', 1462 | // minQty: '2', 1463 | // maxQty: '2', 1464 | // }, 1465 | // { 1466 | // ingredient: 'butter', 1467 | // quantity: '6', 1468 | // unit: 'tablespoon', 1469 | // minQty: '6', 1470 | // maxQty: '6', 1471 | // } 1472 | // ]); 1473 | // }); 1474 | 1475 | // it('combines 2 ingredients that have a quantity range', () => { 1476 | // const ingredientArray = [ 1477 | // { 1478 | // ingredient: 'butter', 1479 | // quantity: '2', 1480 | // unit: 'tablespoon', 1481 | // minQty: '2', 1482 | // maxQty: '3', 1483 | // }, 1484 | // { 1485 | // ingredient: 'butter', 1486 | // quantity: '2', 1487 | // unit: 'tablespoon', 1488 | // minQty: '1', 1489 | // maxQty: '2', 1490 | // } 1491 | // ]; 1492 | // expect(combine(ingredientArray)).to.deep.equal([ 1493 | // { 1494 | // ingredient: 'butter', 1495 | // quantity: '4', 1496 | // unit: 'tablespoon', 1497 | // minQty: '3', 1498 | // maxQty: '5', 1499 | // } 1500 | // ]); 1501 | // }); 1502 | 1503 | // it('combines 1 ingredient with no range, and 1 with a range', () => { 1504 | // const ingredientArray = [ 1505 | // { 1506 | // ingredient: 'butter', 1507 | // quantity: '10', 1508 | // unit: 'tablespoon', 1509 | //// minQty: '1', 1510 | // maxQty: '10', 1511 | // }, 1512 | // { 1513 | // ingredient: 'butter', 1514 | // quantity: '2', 1515 | // unit: 'tablespoon', 1516 | // minQty: '2', 1517 | // maxQty: '2', 1518 | // } 1519 | // ]; 1520 | // expect(combine(ingredientArray)).to.deep.equal([ 1521 | // { 1522 | // ingredient: 'butter', 1523 | // quantity: '12', 1524 | // unit: 'tablespoon', 1525 | // minQty: '3', 1526 | // maxQty: '12', 1527 | // } 1528 | // ]); 1529 | // }); 1530 | 1531 | // it('combines 2 ingredient with a range, and 1 different ingredient without a range', () => { 1532 | // const ingredientArray = [ 1533 | // { 1534 | // ingredient: 'butter', 1535 | // quantity: '10', 1536 | // unit: 'tablespoon', 1537 | // minQty: '1', 1538 | // maxQty: '10', 1539 | // }, 1540 | // { 1541 | // ingredient: 'butter', 1542 | // quantity: '2', 1543 | // unit: 'tablespoon', 1544 | // minQty: '2', 1545 | // maxQty: '2', 1546 | // }, 1547 | // { 1548 | // ingredient: 'apple', 1549 | // quantity: '2', 1550 | // unit: null, 1551 | // minQty: '2', 1552 | // maxQty: '2', 1553 | // } 1554 | // ]; 1555 | // expect(combine(ingredientArray)).to.deep.equal([ 1556 | // { 1557 | // ingredient: 'apple', 1558 | // quantity: '2', 1559 | // unit: null, 1560 | // minQty: '2', 1561 | // maxQty: '2', 1562 | // }, 1563 | // { 1564 | // ingredient: 'butter', 1565 | // quantity: '12', 1566 | // unit: 'tablespoon', 1567 | // minQty: '3', 1568 | // maxQty: '12', 1569 | // } 1570 | // ]); 1571 | // }); 1572 | 1573 | // it('does not combine if ingredients have different units (for now)', () => { 1574 | //// const ingredientArray = [ 1575 | //// { 1576 | //// ingredient: 'butter', 1577 | //// quantity: '2', 1578 | //// unit: 'tablespoon', 1579 | //// minQty: '2', 1580 | //// maxQty: '2', 1581 | //// }, 1582 | //// { 1583 | //// ingredient: 'butter', 1584 | //// quantity: '2', 1585 | //// unit: 'tablespoon', 1586 | //// minQty: '2', 1587 | //// maxQty: '2', 1588 | // }, 1589 | // { 1590 | // ingredient: 'butter', 1591 | // quantity: '1', 1592 | // unit: 'stick', 1593 | // minQty: '1', 1594 | // maxQty: '1', 1595 | // }, 1596 | // { 1597 | // ingredient: 'apple', 1598 | // quantity: '2', 1599 | // unit: 'pound', 1600 | // minQty: '2', 1601 | // maxQty: '2', 1602 | // } 1603 | // ]; 1604 | // expect(combine(ingredientArray)).to.deep.equal([ 1605 | // { 1606 | // ingredient: 'apple', 1607 | // quantity: '2', 1608 | // unit: 'pound', 1609 | // minQty: '2', 1610 | // maxQty: '2', 1611 | // }, 1612 | // { 1613 | // ingredient: 'butter', 1614 | // quantity: '4', 1615 | // unit: 'tablespoon', 1616 | // minQty: '4', 1617 | // maxQty: '4', 1618 | // }, 1619 | // { 1620 | // ingredient: 'butter', 1621 | // quantity: '1', 1622 | // unit: 'stick', 1623 | // minQty: '1', 1624 | // maxQty: '1', 1625 | // } 1626 | // ]); 1627 | // }); 1628 | // 1629 | // it('handles the no-unit case', () => { 1630 | // const ingredientArray = [ 1631 | // { 1632 | // ingredient: 'tortilla', 1633 | // quantity: '10', 1634 | // unit: null, 1635 | // symbol: null, 1636 | // minQty: '10', 1637 | // maxQty: '10', 1638 | // }, 1639 | // { 1640 | // ingredient: 'tortilla', 1641 | // quantity: 5, 1642 | // unit: null, 1643 | // symbol: null, 1644 | // minQty: 5, 1645 | // maxQty: 5, 1646 | // } 1647 | // ]; 1648 | // expect(combine(ingredientArray)).to.deep.equal([ 1649 | // { 1650 | // ingredient: 'tortilla', 1651 | // quantity: 15, 1652 | // unit: null, 1653 | // symbol: null, 1654 | // minQty: 15, 1655 | // maxQty: 15, 1656 | // } 1657 | // ]); 1658 | // }); 1659 | // 1660 | // it('handles the no-unit and no-quantity case', () => { 1661 | // const ingredientArray = [ 1662 | // { 1663 | // ingredient: 'Powdered Sugar', 1664 | // quantity: 0, 1665 | // unit: null, 1666 | // symbol: null, 1667 | // minQty: 0, 1668 | // maxQty: 0, 1669 | // }, 1670 | // { 1671 | // ingredient: 'Powdered Sugar', 1672 | // quantity: 0, 1673 | // unit: null, 1674 | // symbol: null, 1675 | // minQty: 0, 1676 | // maxQty: 0, 1677 | // } 1678 | // ]; 1679 | // expect(combine(ingredientArray)).to.deep.equal([ 1680 | // { 1681 | // ingredient: 'Powdered Sugar', 1682 | // quantity: 0, 1683 | // unit: null, 1684 | // symbol: null, 1685 | // minQty: 0, 1686 | // maxQty: 0, 1687 | // } 1688 | // ]); 1689 | // }); 1690 | //}); 1691 | /* 1692 | describe('pretty printing press', () => { 1693 | const ingredients = [{ 1694 | ingredient: 'milk', 1695 | unit: 'cup', 1696 | quantity: '1.5', 1697 | minQty: '1.5', 1698 | maxQty: '1.5', 1699 | }, { 1700 | ingredient: 'milk', 1701 | unit: 'cup', 1702 | quantity: '0.25', 1703 | minQty: '0.25', 1704 | maxQty: '0.25', 1705 | }, { 1706 | ingredient: 'milk', 1707 | unit: 'cup', 1708 | quantity: '1', 1709 | minQty: '1', 1710 | maxQty: '1', 1711 | }, { 1712 | ingredient: 'something', 1713 | unit: 'box', 1714 | quantity: '2', 1715 | minQty: '2', 1716 | maxQty: '2', 1717 | }, { 1718 | ingredient: 'milk', 1719 | unit: 'teaspoon', 1720 | quantity: '1.333', 1721 | minQty: '1.333', 1722 | maxQty: '1.333', 1723 | }, { 1724 | ingredient: 'milk', 1725 | unit: 'teaspoon', 1726 | quantity: '1.666', 1727 | minQty: '1.666', 1728 | maxQty: '1.666', 1729 | }, { 1730 | ingredient: 'milk', 1731 | unit: 'teaspoon', 1732 | quantity: '1.111', 1733 | minQty: '1.111', 1734 | maxQty: '1.111', 1735 | }, { 1736 | ingredient: 'milk', 1737 | unit: 'teaspoon', 1738 | quantity: '1.166', 1739 | minQty: '1.166', 1740 | maxQty: '1.166', 1741 | }, { 1742 | ingredient: 'milk', 1743 | unit: 'teaspoon', 1744 | quantity: '1.833', 1745 | minQty: '1.1833', 1746 | maxQty: '1.1833', 1747 | }, { 1748 | ingredient: 'powdered sugar', 1749 | unit: null, 1750 | quantity: null, 1751 | minQty: null, 1752 | maxQty: null, 1753 | }, { 1754 | ingredient: 'eggs', 1755 | unit: null, 1756 | quantity: '18', 1757 | minQty: '18', 1758 | maxQty: '18', 1759 | }, { 1760 | ingredient: 'large eggs', 1761 | unit: null, 1762 | quantity: '18', 1763 | minQty: '18', 1764 | maxQty: '18', 1765 | }]; 1766 | const expectedOutcome = [ 1767 | '1 1/2 cups milk', 1768 | '1/4 cup milk', 1769 | '1 cup milk', 1770 | '2 boxes something', 1771 | '1 1/3 teaspoons milk', 1772 | '1 2/3 teaspoons milk', 1773 | '1 1/9 teaspoons milk', 1774 | '1 1/6 teaspoons milk', 1775 | '1 5/6 teaspoons milk', 1776 | 'powdered sugar', 1777 | '18 eggs', 1778 | '18 large eggs' 1779 | ]; 1780 | for (let i = 0; i < ingredients.length; i++) { 1781 | it(`returns expected outcome ${expectedOutcome[i]}`, () => { 1782 | expect(prettyPrintingPress(ingredients[i])).to.equal(expectedOutcome[i]); 1783 | }); 1784 | } 1785 | });*/ 1786 | --------------------------------------------------------------------------------