diff --git a/README.md b/README.md index 0b094b4..d349f00 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ Then pass the interpreter instance and a callback function to this module! ```js const { Machine, interpret } = require("xstate"); -const componentTree = require("xstate-component-tree"); +const ComponentTree = require("xstate-component-tree"); const statechart = Machine({ // ... @@ -68,7 +68,7 @@ const statechart = Machine({ const service = interpret(statechart); -componentTree(service, (tree) => { +new ComponentTree(service, (tree) => { // }); ``` @@ -76,35 +76,29 @@ componentTree(service, (tree) => { The second argument to the function will be called every time the machine transitions. It will pass the callback a new object representing all the views defined on currently active states, all correctly nested to match the structure of the statechart. ```js -componentTree(service, (tree) => { +new ComponentTree(service, (tree) => { /** * * tree will be something like this * * [{ - * id: "machine-id", - * children: [{ - * component: MyComponent, - * children: [], - * props: false - * }], + * component: MyComponent, + * children: [], + * props: false, * }] * * or if there are nested components * * [{ - * id: "machine-id", - * children: [{ - * component: MyComponent, - * props: false - * children : [{ - * component : ChildComponent, - * props: { - * one1 : 1 - * }, - * children: [] - * }] - * }], + * component: MyComponent, + * props: false + * children : [{ + * component : ChildComponent, + * props: { + * one1 : 1 + * }, + * children: [] + * }] * }] * */ diff --git a/package-lock.json b/package-lock.json index d44ba4c..d84413c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,28 +84,84 @@ } }, "@babel/helper-module-imports": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", - "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz", + "integrity": "sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ==", "dev": true, "requires": { - "@babel/types": "^7.0.0" + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "@babel/helper-module-transforms": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.5.5.tgz", - "integrity": "sha512-jBeCvETKuJqeiaCdyaheF40aXnnU1+wkSiUs/IQg3tB85up1LyL8x77ClY8qJpuRJUcXQo+ZtdNESmZl4j56Pw==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", + "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/template": "^7.4.4", - "@babel/types": "^7.5.5", + "@babel/helper-module-imports": "^7.7.4", + "@babel/helper-simple-access": "^7.7.4", + "@babel/helper-split-export-declaration": "^7.7.4", + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4", "lodash": "^4.17.13" }, "dependencies": { + "@babel/helper-split-export-declaration": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz", + "integrity": "sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug==", + "dev": true, + "requires": { + "@babel/types": "^7.7.4" + } + }, + "@babel/parser": { + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", @@ -121,13 +177,49 @@ "dev": true }, "@babel/helper-simple-access": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", - "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.7.4.tgz", + "integrity": "sha512-zK7THeEXfan7UlWsG2A6CI/L9jVnI5+xxKZOdej39Y0YtDYKx9raHk5F2EtK9K8DHRTihYwg20ADt9S36GR78A==", "dev": true, "requires": { - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" + "@babel/template": "^7.7.4", + "@babel/types": "^7.7.4" + }, + "dependencies": { + "@babel/parser": { + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==", + "dev": true + }, + "@babel/template": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.7.4.tgz", + "integrity": "sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.4", + "@babel/types": "^7.7.4" + } + }, + "@babel/types": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.7.4.tgz", + "integrity": "sha512-cz5Ji23KCi4T+YIE/BolWosrJuSmoZeN1EFnRtBwF+KKLi8GG/Z2c2hOJJeCXPk4mwk4QFvTmwIodJowXgttRA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "@babel/helper-split-export-declaration": { @@ -177,14 +269,14 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.6.0.tgz", - "integrity": "sha512-Ma93Ix95PNSEngqomy5LSBMAQvYKVe3dy+JlVJSHEXZR5ASL9lQBedMiCyVtmTLraIDVRE3ZjTZvmXXD2Ozw3g==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", + "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", - "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-simple-access": "^7.7.4", "babel-plugin-dynamic-import-node": "^2.3.0" } }, @@ -501,9 +593,9 @@ } }, "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "version": "0.0.40", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.40.tgz", + "integrity": "sha512-p3KZgMto/JyxosKGmnLDJ/dG5wf+qTRMUjHJcspC2oQKa4jP7mz+tv0ND56lLBu3ojHlhzY33Ol+khLyNmilkA==", "dev": true }, "@types/istanbul-lib-coverage": { @@ -538,11 +630,20 @@ "dev": true }, "@types/node": { - "version": "12.11.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.7.tgz", - "integrity": "sha512-JNbGaHFCLwgHn/iCckiGSOZ1XYHsKFwREtzPwSGCVld1SGhOlmZw2D4ZI94HQCrBHbADzW9m4LER/8olJTRGHA==", + "version": "12.12.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.14.tgz", + "integrity": "sha512-u/SJDyXwuihpwjXy7hOOghagLEV1KdAST6syfnOk6QZAMzZuWZqXy5aYYZbh8Jdpd4escVFP0MvftHNDb9pruA==", "dev": true }, + "@types/resolve": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", + "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", @@ -565,42 +666,49 @@ "dev": true }, "@typescript-eslint/experimental-utils": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-1.13.0.tgz", - "integrity": "sha512-zmpS6SyqG4ZF64ffaJ6uah6tWWWgZ8m+c54XXgwFtUv0jNz8aJAVx8chMCvnk7yl6xwn8d+d96+tWp7fXzTuDg==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.10.0.tgz", + "integrity": "sha512-FZhWq6hWWZBP76aZ7bkrfzTMP31CCefVIImrwP3giPLcoXocmLTmr92NLZxuIcTL4GTEOE33jQMWy9PwelL+yQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "1.13.0", - "eslint-scope": "^4.0.0" - }, - "dependencies": { - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - } + "@typescript-eslint/typescript-estree": "2.10.0", + "eslint-scope": "^5.0.0" } }, "@typescript-eslint/typescript-estree": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz", - "integrity": "sha512-b5rCmd2e6DCC6tCTN9GSUAuxdYwCM/k/2wdjHGrIRGPSJotWMCe/dGpi66u42bhuh8q3QBzqM4TMA1GUUCJvdw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.10.0.tgz", + "integrity": "sha512-oOYnplddQNm/LGVkqbkAwx4TIBuuZ36cAQq9v3nFIU9FmhemHuVzAesMSXNQDdAzCa5bFgCrfD3JWhYVKlRN2g==", "dev": true, "requires": { + "debug": "^4.1.1", + "eslint-visitor-keys": "^1.1.0", + "glob": "^7.1.6", + "is-glob": "^4.0.1", "lodash.unescape": "4.0.1", - "semver": "5.5.0" + "semver": "^6.3.0", + "tsutils": "^3.17.1" }, "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true } } @@ -1350,6 +1458,12 @@ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", "dev": true }, + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -1490,12 +1604,12 @@ } }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-width": { @@ -1572,8 +1686,7 @@ "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true, - "optional": true + "dev": true }, "compare-func": { "version": "1.3.2", @@ -1598,28 +1711,28 @@ "dev": true }, "conventional-changelog": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.12.tgz", - "integrity": "sha512-zyGKwii8Z5zOq1nGFm5jn9Ou1jQ6UBoRT0+nqBIU8fEzh64+AcVxrY97tVuK77Ati0xwpBiFHpDXAW7pkq1jEw==", + "version": "3.1.15", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.15.tgz", + "integrity": "sha512-CoWM+Z9bYyF00QzNpTnxkCLiuLAeRocJz3C/foFjvhsdltdtkJgMChp7GytQNjm4pT7JFBVJTpqLHTpxNtOzaA==", "dev": true, "requires": { - "conventional-changelog-angular": "^5.0.5", + "conventional-changelog-angular": "^5.0.6", "conventional-changelog-atom": "^2.0.3", "conventional-changelog-codemirror": "^2.0.3", - "conventional-changelog-conventionalcommits": "^4.2.1", - "conventional-changelog-core": "^4.0.2", + "conventional-changelog-conventionalcommits": "^4.2.3", + "conventional-changelog-core": "^4.1.1", "conventional-changelog-ember": "^2.0.4", "conventional-changelog-eslint": "^3.0.4", "conventional-changelog-express": "^2.0.1", "conventional-changelog-jquery": "^3.0.6", "conventional-changelog-jshint": "^2.0.3", - "conventional-changelog-preset-loader": "^2.2.0" + "conventional-changelog-preset-loader": "^2.3.0" } }, "conventional-changelog-angular": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.5.tgz", - "integrity": "sha512-RrkdWnL/TVyWV1ayWmSsrWorsTDqjL/VwG5ZSEneBQrd65ONcfeA1cW7FLtNweQyMiKOyriCMTKRSlk18DjTrw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz", + "integrity": "sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -1636,16 +1749,24 @@ } }, "conventional-changelog-cli": { - "version": "2.0.25", - "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.25.tgz", - "integrity": "sha512-b0zNygHrFI4HjNmgPzDLSqoltIwo3pIfilWZFNH/1w6QIZoZHeA4SxojRgih9aCc0Eeg1RH7lXIPaRgHa9cv7A==", + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.28.tgz", + "integrity": "sha512-ioagYxYI4GGs3p5APfEgSqjK21Fwl0mTa05MkIH85R64MqtUvNygtjHZWoXtdpM29OONJzxrebWDSyNHX6Fssg==", "dev": true, "requires": { "add-stream": "^1.0.0", - "conventional-changelog": "^3.1.12", - "lodash": "^4.14.14", - "meow": "^4.0.0", + "conventional-changelog": "^3.1.15", + "lodash": "^4.17.15", + "meow": "^5.0.0", "tempfile": "^3.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "conventional-changelog-codemirror": { @@ -1658,30 +1779,38 @@ } }, "conventional-changelog-conventionalcommits": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.1.tgz", - "integrity": "sha512-vC02KucnkNNap+foDKFm7BVUSDAXktXrUJqGszUuYnt6T0J2azsbYz/w9TDc3VsrW2v6JOtiQWVcgZnporHr4Q==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz", + "integrity": "sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww==", "dev": true, "requires": { "compare-func": "^1.3.1", - "lodash": "^4.2.1", + "lodash": "^4.17.15", "q": "^1.5.1" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "conventional-changelog-core": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.0.2.tgz", - "integrity": "sha512-vQh7J+emZlcIA5alvI2xGikID2/iYKyk39dHmHEyU7/xvB9L9kq+3BzqbCXVstu7SD7isDfem27m/Qzu7R0BRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-4.1.1.tgz", + "integrity": "sha512-fBre5P6U9n914Da6Cj82vIfRU2DhTLGr1eDPXWA7AamxTpd4cd0jgdS7Aieas5Vn5WXOJNFRDNl6PrYLEonImg==", "dev": true, "requires": { - "conventional-changelog-writer": "^4.0.9", - "conventional-commits-parser": "^3.0.5", + "conventional-changelog-writer": "^4.0.11", + "conventional-commits-parser": "^3.0.8", "dateformat": "^3.0.0", "get-pkg-repo": "^1.0.0", "git-raw-commits": "2.0.0", "git-remote-origin-url": "^2.0.0", - "git-semver-tags": "^3.0.0", - "lodash": "^4.2.1", + "git-semver-tags": "^3.0.1", + "lodash": "^4.17.15", "normalize-package-data": "^2.3.5", "q": "^1.5.1", "read-pkg": "^3.0.0", @@ -1708,6 +1837,12 @@ "path-exists": "^3.0.0" } }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -1791,15 +1926,15 @@ } }, "conventional-changelog-preset-loader": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.2.0.tgz", - "integrity": "sha512-zXB+5vF7D5Y3Cb/rJfSyCCvFphCVmF8mFqOdncX3BmjZwAtGAPfYrBcT225udilCKvBbHgyzgxqz2GWDB5xShQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz", + "integrity": "sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ==", "dev": true }, "conventional-changelog-writer": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.9.tgz", - "integrity": "sha512-2Y3QfiAM37WvDMjkVNaRtZgxVzWKj73HE61YQ/95T53yle+CRwTVSl6Gbv/lWVKXeZcM5af9n9TDVf0k7Xh+cw==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz", + "integrity": "sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -1807,13 +1942,19 @@ "dateformat": "^3.0.0", "handlebars": "^4.4.0", "json-stringify-safe": "^5.0.1", - "lodash": "^4.2.1", - "meow": "^4.0.0", + "lodash": "^4.17.15", + "meow": "^5.0.0", "semver": "^6.0.0", "split": "^1.0.0", "through2": "^3.0.0" }, "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -1833,18 +1974,26 @@ } }, "conventional-commits-parser": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.5.tgz", - "integrity": "sha512-qVz9+5JwdJzsbt7JbJ6P7NOXBGt8CyLFJYSjKAuPSgO+5UGfcsbk9EMR+lI8Unlvx6qwIc2YDJlrGIfay2ehNA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz", + "integrity": "sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ==", "dev": true, "requires": { "JSONStream": "^1.0.4", - "is-text-path": "^2.0.0", - "lodash": "^4.2.1", - "meow": "^4.0.0", + "is-text-path": "^1.0.1", + "lodash": "^4.17.15", + "meow": "^5.0.0", "split2": "^2.0.0", "through2": "^3.0.0", "trim-off-newlines": "^1.0.0" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "convert-source-map": { @@ -2206,9 +2355,9 @@ } }, "eslint": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.5.1.tgz", - "integrity": "sha512-32h99BoLYStT1iq1v2P9uwpyznQ4M2jRiFB6acitKz52Gqn+vPaMDUTB1bYi1WN4Nquj2w+t+bimYUG83DC55A==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.7.2.tgz", + "integrity": "sha512-qMlSWJaCSxDFr8fBPvJM9kJwbazrhNcBU3+DszDW1OlEwKBBRWsJc7NJFelvwQpanHCR14cOLD41x8Eqvo3Nng==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -2218,19 +2367,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.2", + "eslint-utils": "^1.4.3", "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.1", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -2239,7 +2388,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -2259,12 +2408,35 @@ "is-glob": "^4.0.1" } }, + "globals": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -2274,12 +2446,12 @@ } }, "eslint-plugin-jest": { - "version": "22.19.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-22.19.0.tgz", - "integrity": "sha512-4zUc3rh36ds0SXdl2LywT4YWA3zRe8sfLhz8bPp8qQPIKvynTTkNGwmSCMpl5d9QiZE2JxSinGF+WD8yU+O0Lg==", + "version": "23.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.1.1.tgz", + "integrity": "sha512-2oPxHKNh4j1zmJ6GaCBuGcb8FVZU7YjFUOJzGOPnl9ic7VA/MGAskArLJiRIlnFUmi1EUxY+UiATAy8dv8s5JA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "^1.13.0" + "@typescript-eslint/experimental-utils": "^2.5.0" } }, "eslint-scope": { @@ -2293,12 +2465,12 @@ } }, "eslint-utils": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz", - "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" } }, "eslint-visitor-keys": { @@ -2308,13 +2480,13 @@ "dev": true }, "espree": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.1.tgz", - "integrity": "sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^7.0.0", - "acorn-jsx": "^5.0.2", + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", "eslint-visitor-keys": "^1.1.0" } }, @@ -2348,6 +2520,12 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", @@ -2582,9 +2760,9 @@ } }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -3488,6 +3666,82 @@ "through2": "^2.0.0" }, "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -3519,12 +3773,12 @@ } }, "git-semver-tags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-3.0.0.tgz", - "integrity": "sha512-T4C/gJ9k2Bnxz+PubtcyiMtUUKrC+Nh9Q4zaECcnmVMwJgPhrNyP/Rf+YpdRqsJbCV/+kYrCH24Xg+IeAmbOPg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-3.0.1.tgz", + "integrity": "sha512-Hzd1MOHXouITfCasrpVJbRDg9uvW7LfABk3GQmXYZByerBDrfrEMP9HXpNT7RxAbieiocP6u+xq20DkvjwxnCA==", "dev": true, "requires": { - "meow": "^4.0.0", + "meow": "^5.0.0", "semver": "^6.0.0" }, "dependencies": { @@ -3758,9 +4012,9 @@ "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -3812,26 +4066,35 @@ "dev": true }, "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.0.tgz", + "integrity": "sha512-rSdC7zelHdRQFkWnhsMu2+2SO41mpv2oF2zy4tMhmiLWkcKbOAs87fWAJhVXttKVwhdZvymvnuM95EyEXg2/tQ==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", + "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", + "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", "run-async": "^2.2.0", "rxjs": "^6.4.0", - "string-width": "^2.1.0", + "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" }, "dependencies": { + "ansi-escapes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, "lodash": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", @@ -3993,6 +4256,12 @@ "is-extglob": "^2.1.1" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -4040,6 +4309,23 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-reference": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz", + "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==", + "dev": true, + "requires": { + "@types/estree": "0.0.39" + }, + "dependencies": { + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + } + } + }, "is-regex": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", @@ -4065,12 +4351,12 @@ } }, "is-text-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz", - "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", + "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", "dev": true, "requires": { - "text-extensions": "^2.0.0" + "text-extensions": "^1.0.0" } }, "is-typedarray": { @@ -4895,6 +5181,15 @@ "signal-exit": "^3.0.0" } }, + "magic-string": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz", + "integrity": "sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.4" + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -4944,22 +5239,28 @@ } }, "meow": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-5.0.0.tgz", + "integrity": "sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", "decamelize-keys": "^1.0.0", "loud-rejection": "^1.0.0", - "minimist": "^1.1.3", "minimist-options": "^3.0.1", "normalize-package-data": "^2.3.4", "read-pkg-up": "^3.0.0", "redent": "^2.0.0", - "trim-newlines": "^2.0.0" + "trim-newlines": "^2.0.0", + "yargs-parser": "^10.0.0" }, "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -4979,12 +5280,6 @@ "path-exists": "^3.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -5018,6 +5313,15 @@ "find-up": "^2.0.0", "read-pkg": "^3.0.0" } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } } } }, @@ -5064,9 +5368,9 @@ } }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimatch": { @@ -5137,9 +5441,9 @@ "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "nan": { @@ -5358,12 +5662,12 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "optimist": { @@ -5410,6 +5714,11 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-cancelable": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.0.0.tgz", + "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==" + }, "p-each-series": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", @@ -5940,12 +6249,12 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -5965,9 +6274,9 @@ } }, "rollup": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.25.2.tgz", - "integrity": "sha512-+7z6Wab/L45QCPcfpuTZKwKiB0tynj05s/+s2U3F2Bi7rOLPr9UcjUwO7/xpjlPNXA/hwnth6jBExFRGyf3tMg==", + "version": "1.27.10", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.10.tgz", + "integrity": "sha512-5PjBSKney8zLu7tTn/y4iVBL3OyK+G9rA/wfkcY78bZ9kAMtgNqb8nOfR5KpoDYyt8Vs5o2o8DyDjf9RpwYbAg==", "dev": true, "requires": { "@types/estree": "*", @@ -5975,6 +6284,54 @@ "acorn": "^7.1.0" } }, + "rollup-plugin-commonjs": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz", + "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1", + "is-reference": "^1.1.2", + "magic-string": "^0.25.2", + "resolve": "^1.11.0", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-node-resolve": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz", + "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==", + "dev": true, + "requires": { + "@types/resolve": "0.0.8", + "builtin-modules": "^3.1.0", + "is-module": "^1.0.0", + "resolve": "^1.11.1", + "rollup-pluginutils": "^2.8.1" + } + }, + "rollup-plugin-terser": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.1.3.tgz", + "integrity": "sha512-FuFuXE5QUJ7snyxHLPp/0LFXJhdomKlIx/aK7Tg88Yubsx/UU/lmInoJafXJ4jwVVNcORJ1wRUC5T9cy5yk0wA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "jest-worker": "^24.6.0", + "rollup-pluginutils": "^2.8.1", + "serialize-javascript": "^2.1.2", + "terser": "^4.1.0" + } + }, + "rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "requires": { + "estree-walker": "^0.6.1" + } + }, "rsvp": { "version": "4.8.5", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", @@ -6057,6 +6414,12 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -6265,9 +6628,9 @@ } }, "snapshot-diff": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/snapshot-diff/-/snapshot-diff-0.5.2.tgz", - "integrity": "sha512-6cKemS91iEZCRRHQUjYBcPMIUz70lqWVoffqx7nhZ2XP/tG+EJKK0O8tANW0zHcmaEOfu00cfzKhsg08QdC9fg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/snapshot-diff/-/snapshot-diff-0.6.1.tgz", + "integrity": "sha512-wWt3x4fb7FJIcV05Ng9NceVSTvQYE493sIqebzUoQbQlRG6rIR03KaRt8o/7W7znaYjUbP0eOq1iK+DfpZXaeQ==", "dev": true, "requires": { "jest-diff": "^24.0.0", @@ -6319,6 +6682,12 @@ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", "dev": true }, + "sourcemap-codec": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz", + "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==", + "dev": true + }, "spdx-correct": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", @@ -6468,22 +6837,41 @@ } }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.0" } } } @@ -6620,6 +7008,25 @@ "uuid": "^3.3.2" } }, + "terser": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.2.tgz", + "integrity": "sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "test-exclude": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", @@ -6633,9 +7040,9 @@ } }, "text-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz", - "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, "text-table": { @@ -6771,6 +7178,15 @@ "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", "dev": true }, + "tsutils": { + "version": "3.17.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", + "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6795,6 +7211,12 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, "uglify-js": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.2.tgz", @@ -7009,6 +7431,12 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -7081,9 +7509,9 @@ "dev": true }, "xstate": { - "version": "4.7.0-rc5", - "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.7.0-rc5.tgz", - "integrity": "sha512-vzVoXii9TJZ3+vBpOFnipBkMpwrRECkplot2wuqkmShgVRbqqV3GxTUfj5UVGiP8lPDmtCz33dlRHacdAQdHtg==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/xstate/-/xstate-4.7.2.tgz", + "integrity": "sha512-vAIEf5CuLPNgH5obVP7WS1U+I91L+vSKLpradVn6AhbyFrccWlNQwFVuYktInafgkvA6z4w9rLkuRKBZ5izkSA==", "dev": true }, "xtend": { diff --git a/package.json b/package.json index fa45b0f..1296ecb 100644 --- a/package.json +++ b/package.json @@ -7,23 +7,26 @@ "module": "dist/treebuilder.mjs", "main": "dist/treebuilder.js", "devDependencies": { - "@babel/plugin-transform-modules-commonjs": "^7.6.0", + "@babel/plugin-transform-modules-commonjs": "^7.7.5", "@tivac/eslint-config": "^2.4.0", "babel-core": "^6.26.3", "babel-eslint": "^10.0.3", "babel-jest": "^24.9.0", "babel-plugin-add-module-exports": "^1.0.2", - "conventional-changelog-cli": "^2.0.25", - "eslint": "^6.5.1", - "eslint-plugin-jest": "^22.19.0", + "conventional-changelog-cli": "^2.0.28", + "eslint": "^6.7.2", + "eslint-plugin-jest": "^23.1.1", "jest": "^24.9.0", "p-wait-for": "^3.1.0", - "rollup": "^1.25.2", - "snapshot-diff": "^0.5.2", - "xstate": "^4.7.0-rc5" + "rollup": "^1.27.10", + "rollup-plugin-commonjs": "^10.1.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-terser": "^5.1.3", + "snapshot-diff": "^0.6.1", + "xstate": "^4.7.2" }, "peerDependencies": { - "xstate": "^4.7.0-rc5" + "xstate": "^4.7.2" }, "scripts": { "build": "rollup --config", @@ -42,5 +45,8 @@ ], "files": [ "dist/" - ] + ], + "dependencies": { + "p-cancelable": "^2.0.0" + } } diff --git a/rollup.config.js b/rollup.config.js index 6307cc1..dd7f8cc 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,5 +1,7 @@ "use strict"; +const { terser } = require("rollup-plugin-terser"); + const pkg = require("./package.json"); const banner = `/*! ${pkg.name}@${pkg.version} !*/`; @@ -10,15 +12,37 @@ const input = "./src/treebuilder.js"; module.exports = { input, + plugins : [ + require("rollup-plugin-node-resolve")(), + require("rollup-plugin-commonjs")(), + ], + output : [{ file : pkg.main, format : "cjs", sourcemap : true, + banner, + }, { + file : pkg.main.replace(".js", "-min.js"), + format : "cjs", + sourcemap : true, + plugins : [ + terser(), + ], + banner, }, { file : pkg.module, format : "es", sourcemap : true, banner, + }, { + file : pkg.module.replace(".mjs", "-min.mjs"), + format : "es", + sourcemap : true, + plugins : [ + terser(), + ], + banner, }], }; diff --git a/src/treebuilder.js b/src/treebuilder.js index 24436cd..a0cfceb 100644 --- a/src/treebuilder.js +++ b/src/treebuilder.js @@ -1,3 +1,5 @@ +import Cancelable from "p-cancelable"; + const loader = async ({ item, key, fn, context, event }) => { item[key] = await fn(context, event); }; @@ -10,11 +12,21 @@ class ComponentTree { this.options = options; // identifier! - this._id = interpreter.id; + this.id = interpreter.id; // path -> meta lookup this._paths = new Map(); + // path -> invoked id + this._invocables = new Map(); + + // invoked id -> child machine + this._children = new Map(); + + // Cancelable version of the walker + this._walking = false; + this._walk = Cancelable.fn(this._walkRaw.bind(this)); + // Get goin this._prep(); this._watch(); @@ -22,6 +34,8 @@ class ComponentTree { teardown() { this._paths.clear(); + this._invocables.clear(); + this._children.clear(); this._unsubscribe(); } @@ -29,29 +43,31 @@ class ComponentTree { // Walk the machine and build up maps of paths to meta info as // well as prepping any load functions for usage later _prep() { - const { _paths } = this; + const { _paths, _invocables } = this; const { idMap : ids } = this.interpreter.machine; // xstate maps ids to state nodes, but the value object only // has paths, so need to create our own path-only map here for(const id in ids) { - const { path, meta = false } = ids[id]; + const { path, meta = false, invoke = false } = ids[id]; const key = path.join("."); - if(!meta) { - continue; - } + if(meta) { + const { component, props, load } = meta; - const { component, props, load } = meta; + _paths.set(key, { + __proto__ : null, - _paths.set(key, { - __proto__ : null, + component, + props, + load, + }); + } - component, - props, - load, - }); + if(invoke) { + invoke.forEach(({ id : invokeid }) => _invocables.set(key, invokeid)); + } } } @@ -71,42 +87,56 @@ class ComponentTree { // Walk a machine via BFS, collecting meta information to build a tree // eslint-disable-next-line max-statements - async _walk({ value, context, event }) { - const { _paths } = this; - + async _walkRaw({ value, context, event }, onCancel) { + const { _paths, _invocables, _children } = this; + const loads = []; - const tree = { + const root = { __proto__ : null, + id : this.id, children : [], - id : this._id, }; // Set up queue for a breadth-first traversal of all active states let queue; + let cancelled; + + // Blank out the queue immediately to force iteration to stop ASAP + onCancel(() => { + queue = []; + cancelled = true; + }); if(typeof value === "string") { - queue = [[ tree, value, false ]]; + queue = [[ root, value, false ]]; } else { queue = Object.entries(value).map(([ child, grandchildren ]) => - [ tree, child, grandchildren ] + [ root, child, grandchildren ] ); } - while(queue.length) { + // eslint-disable-next-line no-unmodified-loop-condition + while(queue.length && !cancelled) { const [ parent, path, values ] = queue.shift(); - // Since it can be assigned if we add a new child + // Using let since it can be reassigned if we add a new child let pointer = parent; if(_paths.has(path)) { - const { component, props, load } = _paths.get(path); + const details = _paths.get(path); + const { component, props, load } = details; + const item = { __proto__ : null, - children : [], component : component || false, props : props || false, + children : [], }; + details.item = item; + + _paths.set(path, details); + // Run load function and assign the response to the component prop if(load) { loads.push(loader({ @@ -134,6 +164,20 @@ class ComponentTree { pointer = item; } + if(_invocables.has(path)) { + const id = _invocables.get(path); + + if(_children.has(id)) { + const { tree : child } = _children.get(id); + + if(child) { + // Will attach to the state itself if it has a component, + // otherwise will attach to the parent + pointer.children.push(...child); + } + } + } + if(!values) { continue; } @@ -149,92 +193,90 @@ class ComponentTree { )); } + if(cancelled) { + return false; + } + // await all the load functions await Promise.all(loads); - - return tree; + + return root.children; } - // eslint-disable-next-line max-statements - async _state(state) { - const { changed, value, context, event } = state; - + // React to statechart transitions, sync up the state of child actors, + // and kick off the _walk + _state({ changed, value, context, event, children }) { // Need to specifically check for false because this value is undefined // when a machine first boots up if(changed === false) { - return; + return false; } - const tree = await this._walk({ value, context, event }); - - this.callback(tree); - } -} - -const treeBuilder = (interpreter, fn) => { - const machines = new Map(); - const trees = new Map(); + const { _children } = this; - const root = interpreter.id; - - const respond = () => { - fn([ ...trees.values() ]); - }; - - machines.set(root, new ComponentTree(interpreter, (tree) => { - trees.set(root, tree); - - respond(); - })); + const run = async () => { + // Cancel any previous walks, we're the captain now + if(this._walking && !this._walking.isCanceled) { + this._walking.cancel(); + } - interpreter.subscribe(({ changed, children }) => { - if(changed === false) { - return; - } + this._walking = this._walk({ value, context, event }); + + try { + const tree = await this._walking; + + this.callback(tree); + } catch(e) { + // Swallow errors from cancelling promises, those are ignored because + // a newer walk was requested + if(e instanceof Cancelable.CancelError) { + return; + } - // BFS Walk child statecharts, attach subscribers for each of them - const queue = Object.entries(children); + // Anything else gets re-thrown + throw e; + } + }; - // Track active ids - const active = new Set(); - - while(queue.length) { - const [ id, machine ] = queue.shift(); - - active.add(id); - - if(machine.initialized && machine.state) { - machines.set(id, new ComponentTree(machine, (tree) => { - trees.set(id, tree); + // Clear out any old children that are no longer being tracked + _children.forEach(({ child }, key) => { + if(key in children) { + return; + } - respond(); - })); + child.teardown(); + _children.delete(key); + }); - queue.push(...Object.entries(machine.state.children)); + // Add any new children to be tracked + Object.entries(children).forEach(([ id, service ]) => { + // Already tracked + if(_children.has(id)) { + return; } - } - // Remove any no-longer active invoked statecharts from being tracked - machines.forEach((cancel, id) => { - if(active.has(id) || id === root) { + // Not a statechart, abort! + if(!service.initialized || !service.state) { return; } - machines.get(id).teardown(); - machines.delete(id); - trees.delete(id); + const child = new ComponentTree(service, (tree) => { + const me = _children.get(id); - respond(); - }); - }); + me.tree = tree; - return () => { - machines.forEach((machine) => machine.teardown()); - machines.clear(); - trees.clear(); - }; -}; + return run(); + }); -treeBuilder.ComponentTree = ComponentTree; + // Setup child service for tracking + _children.set(id, { + child, + tree : false, + }); + }); + + return run(); + } +} -export default treeBuilder; +export default ComponentTree; diff --git a/tests/__snapshots__/basic.test.js.snap b/tests/__snapshots__/basic.test.js.snap index 99feb21..e702b88 100644 --- a/tests/__snapshots__/basic.test.js.snap +++ b/tests/__snapshots__/basic.test.js.snap @@ -5,19 +5,14 @@ Snapshot Diff: - First value + Second value -@@ -1,11 +1,11 @@ Array [ Object { - "children": Array [ - Object { - "children": Array [], -- "component": "one", -+ "component": "two", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], +- "component": "one", ++ "component": "two", + "props": false, }, + ] `; exports[`xstate-component-tree should return a tree of components 1`] = ` @@ -25,18 +20,13 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": false, - }, - ], - "component": "one", + "children": Array [], + "component": "two", "props": false, }, ], - "id": "(machine)", + "component": "one", + "props": false, }, ] `; @@ -46,18 +36,13 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": false, - }, - ], - "component": "one", + "children": Array [], + "component": "two", "props": false, }, ], - "id": "(machine)", + "component": "one", + "props": false, }, ] `; @@ -67,18 +52,13 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "three", - "props": false, - }, - ], - "component": "one", + "children": Array [], + "component": "three", "props": false, }, ], - "id": "(machine)", + "component": "one", + "props": false, }, ] `; @@ -86,19 +66,14 @@ Array [ exports[`xstate-component-tree should support nested parallel states 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": false, - }, - Object { - "children": Array [], - "component": "three", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "two", + "props": false, + }, + Object { + "children": Array [], + "component": "three", + "props": false, }, ] `; @@ -106,34 +81,14 @@ Array [ exports[`xstate-component-tree should support parallel states 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - Object { - "children": Array [], - "component": "two", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": false, }, -] -`; - -exports[`xstate-component-tree should support top-level machine ids in the built tree 1`] = ` -Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "testmachine", + "children": Array [], + "component": "two", + "props": false, }, ] `; diff --git a/tests/__snapshots__/invoked-load.test.js.snap b/tests/__snapshots__/invoked-load.test.js.snap index 94ff41a..08a5613 100644 --- a/tests/__snapshots__/invoked-load.test.js.snap +++ b/tests/__snapshots__/invoked-load.test.js.snap @@ -2,16 +2,6 @@ exports[`xstate-component-tree invoked machines using .load should pass child machine context & events to load fns 1`] = ` Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", - }, Object { "children": Array [ Object { @@ -25,23 +15,14 @@ Array [ "props": false, }, ], - "id": "child", + "component": "one", + "props": false, }, ] `; exports[`xstate-component-tree invoked machines using .load should support async .load 1`] = ` Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", - }, Object { "children": Array [ Object { @@ -50,23 +31,14 @@ Array [ "props": false, }, ], - "id": "child", + "component": "one", + "props": false, }, ] `; exports[`xstate-component-tree invoked machines using .load should support sync .load 1`] = ` Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", - }, Object { "children": Array [ Object { @@ -75,7 +47,8 @@ Array [ "props": false, }, ], - "id": "child", + "component": "one", + "props": false, }, ] `; diff --git a/tests/__snapshots__/invoked.test.js.snap b/tests/__snapshots__/invoked.test.js.snap index da91714..7564697 100644 --- a/tests/__snapshots__/invoked.test.js.snap +++ b/tests/__snapshots__/invoked.test.js.snap @@ -6,12 +6,18 @@ Array [ "children": Array [ Object { "children": Array [], - "component": "one", + "component": "child", "props": false, }, ], - "id": "(machine)", + "component": "one", + "props": false, }, +] +`; + +exports[`xstate-component-tree invoked child machines should be supported in a parallel state 1`] = ` +Array [ Object { "children": Array [ Object { @@ -20,7 +26,13 @@ Array [ "props": false, }, ], - "id": "child", + "component": "one", + "props": false, + }, + Object { + "children": Array [], + "component": "two", + "props": false, }, ] `; @@ -28,14 +40,9 @@ Array [ exports[`xstate-component-tree invoked child machines should ignore non-statechart children (callback) 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": false, }, ] `; @@ -43,56 +50,71 @@ Array [ exports[`xstate-component-tree invoked child machines should ignore non-statechart children (promise) 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": false, }, ] `; -exports[`xstate-component-tree invoked child machines should rebuild on nested invoked machine transitions 1`] = ` +exports[`xstate-component-tree invoked child machines should rebuild on child transitions 1`] = ` Snapshot Diff: - First value + Second value -@@ -21,11 +21,11 @@ - }, +@@ -1,11 +1,11 @@ + Array [ Object { "children": Array [ Object { "children": Array [], -- "component": "grandchild1", -+ "component": "grandchild2", +- "component": "child1", ++ "component": "child2", "props": false, }, ], - "id": "grandchild", - }, + "component": "one", + "props": false, `; -exports[`xstate-component-tree invoked child machines should rebuild on transitions 1`] = ` +exports[`xstate-component-tree invoked child machines should rebuild on nested invoked machine transitions 1`] = ` Snapshot Diff: - First value + Second value -@@ -11,11 +11,11 @@ - }, - Object { +@@ -3,11 +3,11 @@ "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [], +- "component": "grandchild1", ++ "component": "grandchild2", + "props": false, + }, + ], + "component": "child", + "props": false, +`; + +exports[`xstate-component-tree invoked child machines should rebuild on parent transitions 1`] = ` +Snapshot Diff: +- First value ++ Second value + +@@ -6,11 +6,11 @@ + "component": "child1", + "props": false, + }, Object { "children": Array [], -- "component": "child1", -+ "component": "child2", +- "component": "oneone", ++ "component": "onetwo", "props": false, }, ], - "id": "child", - }, + "component": "one", + "props": false, `; exports[`xstate-component-tree invoked child machines should remove data once the invoke is halted 1`] = ` @@ -100,22 +122,19 @@ Snapshot Diff: - First value + Second value -@@ -7,16 +7,6 @@ - "props": false, - }, - ], - "id": "(machine)", - }, -- Object { + Array [ + Object { - "children": Array [ - Object { -- "children": Array [], + "children": Array [], - "component": "child", - "props": false, - }, - ], -- "id": "child", -- }, +- "component": "one", ++ "component": "two", + "props": false, + }, ] `; @@ -124,32 +143,19 @@ Array [ Object { "children": Array [ Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", - }, - Object { - "children": Array [ - Object { - "children": Array [], + "children": Array [ + Object { + "children": Array [], + "component": "grandchild", + "props": false, + }, + ], "component": "child", "props": false, }, ], - "id": "child", - }, - Object { - "children": Array [ - Object { - "children": Array [], - "component": "grandchild", - "props": false, - }, - ], - "id": "grandchild", + "component": "one", + "props": false, }, ] `; diff --git a/tests/__snapshots__/load.test.js.snap b/tests/__snapshots__/load.test.js.snap index 112ee0a..7b8cba2 100644 --- a/tests/__snapshots__/load.test.js.snap +++ b/tests/__snapshots__/load.test.js.snap @@ -3,14 +3,9 @@ exports[`xstate-component-tree should ignore stale trees if component loads hadn't completed 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "two", + "props": false, }, ] `; @@ -18,19 +13,14 @@ Array [ exports[`xstate-component-tree should pass context and event params to .load methods 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": Object { - "ctx": "context", - "event": Object { - "type": "xstate.init", - }, - }, - "props": false, + "children": Array [], + "component": Object { + "ctx": "context", + "event": Object { + "type": "xstate.init", }, - ], - "id": "(machine)", + }, + "props": false, }, ] `; @@ -38,14 +28,9 @@ Array [ exports[`xstate-component-tree should support async .load methods 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": false, }, ] `; @@ -55,18 +40,13 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": false, - }, - ], - "component": "one", + "children": Array [], + "component": "two", "props": false, }, ], - "id": "(machine)", + "component": "one", + "props": false, }, ] `; @@ -74,14 +54,9 @@ Array [ exports[`xstate-component-tree should support sync .load methods 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": false, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": false, }, ] `; diff --git a/tests/__snapshots__/props.test.js.snap b/tests/__snapshots__/props.test.js.snap index 0f03075..aac5b46 100644 --- a/tests/__snapshots__/props.test.js.snap +++ b/tests/__snapshots__/props.test.js.snap @@ -3,19 +3,14 @@ exports[`xstate-component-tree props should pass context & event to dynamic props functions 1`] = ` Array [ Object { - "children": Array [ + "children": Array [], + "component": "one", + "props": Array [ + "context", Object { - "children": Array [], - "component": "one", - "props": Array [ - "context", - Object { - "type": "xstate.init", - }, - ], + "type": "xstate.init", }, ], - "id": "(machine)", }, ] `; @@ -23,17 +18,12 @@ Array [ exports[`xstate-component-tree props should support async dynamic props 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": Object { - "booga": 2, - "fooga": 1, - }, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": Object { + "booga": 2, + "fooga": 1, + }, }, ] `; @@ -43,24 +33,19 @@ Array [ Object { "children": Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "two", - "props": Object { - "tooga": 2, - "wooga": 1, - }, - }, - ], - "component": "one", + "children": Array [], + "component": "two", "props": Object { - "booga": 2, - "fooga": 1, + "tooga": 2, + "wooga": 1, }, }, ], - "id": "(machine)", + "component": "one", + "props": Object { + "booga": 2, + "fooga": 1, + }, }, ] `; @@ -68,17 +53,12 @@ Array [ exports[`xstate-component-tree props should support sync dynamic props 1`] = ` Array [ Object { - "children": Array [ - Object { - "children": Array [], - "component": "one", - "props": Object { - "booga": 2, - "fooga": 1, - }, - }, - ], - "id": "(machine)", + "children": Array [], + "component": "one", + "props": Object { + "booga": 2, + "fooga": 1, + }, }, ] `; diff --git a/tests/basic.test.js b/tests/basic.test.js index b79dbb3..756a6bd 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -1,13 +1,10 @@ "use strict"; const { Machine : createMachine, interpret } = require("xstate"); -const waitFor = require("p-wait-for"); const trees = require("./util/trees.js"); const component = require("./util/component.js"); -const treeBuilder = require("../src/treebuilder.js"); - describe("xstate-component-tree", () => { it("should return a tree of components", async () => { const testMachine = createMachine({ @@ -231,26 +228,6 @@ describe("xstate-component-tree", () => { expect(eventCounter.mock.calls.length).toBe(2); }); - it("should support top-level machine ids in the built tree", async () => { - const testMachine = createMachine({ - id : "testmachine", - initial : "one", - - states : { - one : { - meta : { - component : component("one"), - }, - }, - }, - }); - - const service = interpret(testMachine); - const tree = trees(service); - - expect(await tree()).toMatchSnapshot(); - }); - it("should clean up after itself", async () => { const testMachine = createMachine({ initial : "one", @@ -278,13 +255,11 @@ describe("xstate-component-tree", () => { const callback = jest.fn(); - const cancel = treeBuilder(service, callback); - - service.start(); + const tree = trees(service, callback); - await waitFor(() => callback.mock.calls.length > 0); - - cancel(); + await tree(); + + tree.builder.teardown(); service.send("NEXT"); diff --git a/tests/invoked-load.test.js b/tests/invoked-load.test.js index 43ec270..a009dd1 100644 --- a/tests/invoked-load.test.js +++ b/tests/invoked-load.test.js @@ -80,8 +80,10 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root Built await tree(); + // Child Built expect(await tree()).toMatchSnapshot(); }); diff --git a/tests/invoked.test.js b/tests/invoked.test.js index e544d92..7e4f8c8 100644 --- a/tests/invoked.test.js +++ b/tests/invoked.test.js @@ -1,5 +1,8 @@ "use strict"; +// eslint-disable-next-line no-empty-function +const NOOP = () => {}; + const { Machine : createMachine, interpret } = require("xstate"); const trees = require("./util/trees.js"); const component = require("./util/component.js"); @@ -25,7 +28,48 @@ describe("xstate-component-tree", () => { states : { one : { invoke : { - id : "child", + id : "child-machine", + src : childMachine, + }, + + meta : { + component : component("one"), + }, + }, + }, + }); + + const service = interpret(testMachine); + + const tree = trees(service); + + // Root built + await tree(); + + // Child built + expect(await tree()).toMatchSnapshot(); + }); + + it("should be supported in a parallel state", async () => { + const childMachine = createMachine({ + initial : "child", + + states : { + child : { + meta : { + component : component("child"), + }, + }, + }, + }); + + const testMachine = createMachine({ + type : "parallel", + + states : { + one : { + invoke : { + id : "child-machine", src : childMachine, }, @@ -33,6 +77,12 @@ describe("xstate-component-tree", () => { component : component("one"), }, }, + + two : { + meta : { + component : component("two"), + }, + }, }, }); @@ -40,16 +90,16 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root built await tree(); + // Child built expect(await tree()).toMatchSnapshot(); }); it.each([ - // eslint-disable-next-line no-empty-function - [ "promise", () => new Promise(() => {}) ], - // eslint-disable-next-line no-empty-function - [ "callback", () => () => {} ], + [ "promise", () => new Promise(NOOP) ], + [ "callback", () => NOOP ], ])("should ignore non-statechart children (%s)", async (name, src) => { const testMachine = createMachine({ initial : "one", @@ -72,6 +122,7 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root built expect(await tree()).toMatchSnapshot(); }); @@ -118,17 +169,21 @@ describe("xstate-component-tree", () => { const service = interpret(testMachine); const tree = trees(service); + // Root built await tree(); + + // Child built const before = await tree(); service.send("NEXT"); + // Root rebuilt const after = await tree(); expect(before).toMatchDiffSnapshot(after); }); - it("should rebuild on transitions", async () => { + it("should rebuild on child transitions", async () => { const childMachine = createMachine({ initial : "child1", @@ -174,11 +229,83 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root built await tree(); + + // Child built const before = await tree(); service.send("NEXT"); + // Child rebuilt + const after = await tree(); + + expect(before).toMatchDiffSnapshot(after); + }); + + it("should rebuild on parent transitions", async () => { + const childMachine = createMachine({ + initial : "child", + + states : { + child : { + meta : { + component : component("child1"), + }, + }, + }, + }); + + const testMachine = createMachine({ + initial : "one", + + states : { + one : { + invoke : { + id : "child", + src : childMachine, + }, + + meta : { + component : component("one"), + }, + + initial : "oneone", + + states : { + oneone : { + meta : { + component : component("oneone"), + }, + + on : { + NEXT : "onetwo", + }, + }, + + onetwo : { + meta : { + component : component("onetwo"), + }, + }, + }, + }, + }, + }); + + const service = interpret(testMachine); + + const tree = trees(service); + + // Root built + await tree(); + + // Child built + const before = await tree(); + + service.send("NEXT"); + + // Root rebuilt const after = await tree(); expect(before).toMatchDiffSnapshot(after); @@ -203,7 +330,7 @@ describe("xstate-component-tree", () => { states : { child : { invoke : { - id : "grandchild", + id : "grandchild-machine", src : grandchildMachine, autoForward : true, @@ -222,7 +349,7 @@ describe("xstate-component-tree", () => { states : { one : { invoke : { - id : "child", + id : "child-machine", src : childMachine, autoForward : true, @@ -239,9 +366,13 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root built await tree(); + + // Child built await tree(); - + + // Grandchild built expect(await tree()).toMatchSnapshot(); }); @@ -310,12 +441,18 @@ describe("xstate-component-tree", () => { const tree = trees(service); + // Root built await tree(); + + // Child built await tree(); + + // Grandchild built const before = await tree(); service.send("NEXT"); - + + // Grandchild rebuilt const after = await tree(); expect(before).toMatchDiffSnapshot(after); diff --git a/tests/util/deferred.js b/tests/util/deferred.js new file mode 100644 index 0000000..a510b25 --- /dev/null +++ b/tests/util/deferred.js @@ -0,0 +1,16 @@ +const deferred = () => { + let resolve; + let reject; + + const p = new Promise((ok, no) => { + resolve = ok; + reject = no; + }); + + p.resolve = resolve; + p.reject = reject; + + return p; +}; + +export default deferred; diff --git a/tests/util/trees.js b/tests/util/trees.js index 0bb9dae..3f52f61 100644 --- a/tests/util/trees.js +++ b/tests/util/trees.js @@ -1,57 +1,54 @@ "use strict"; -const treeBuilder = require("../../src/treebuilder.js"); +const ComponentTree = require("../../src/treebuilder.js"); +const deferred = require("./deferred.js"); -const deferred = () => { - let resolve; - let reject; - - const p = new Promise((ok, no) => { - resolve = ok; - reject = no; - }); - - p.resolve = resolve; - p.reject = reject; - - return p; -}; +// eslint-disable-next-line no-empty-function +const noop = () => {}; // Watch for trees to be built, and provide an easy way // to await each value -const trees = (service) => { +const trees = (service, fn = noop) => { const responses = []; + let idx = 0; let p; + let resolved; const respond = () => { - if(!p || !responses.length) { + if(resolved || idx >= responses.length) { return; } - p.resolve(responses.shift()); + p.resolve(responses[idx++]); + }; + + const out = () => { + p = deferred(); + resolved = false; + + respond(); + + return p.then((data) => { + resolved = true; - p = false; + return data; + }); }; - treeBuilder(service, (tree) => { + out.responses = responses; + + // Push new tree states onto array and respond if a request is waiting + out.builder = new ComponentTree(service, (tree) => { responses.push(tree); + fn(tree); + respond(); }); - return () => { - if(!service.initialized) { - service.start(); - } + service.start(); - p = deferred(); - - // Scheduled so promise can be returned before this has a chance - // to run and potentially remove the promise reference - setImmediate(respond); - - return p; - }; + return out; }; module.exports = trees;