diff --git a/.gitignore b/.gitignore index 634c41431..049556560 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ dist examples/.dat static/*.bundle.js* static/*.worker.js* +static/*.ttf test/lib/test-data bin/test-data translations diff --git a/.storybook/__mocks__/fs.js b/.storybook/__mocks__/fs.js index 67501b5b2..a81496a87 100644 --- a/.storybook/__mocks__/fs.js +++ b/.storybook/__mocks__/fs.js @@ -1,4 +1,3 @@ -const { action } = require('@storybook/addon-actions') const through = require('through2') const concat = require('concat-stream') const FileSaver = require('file-saver') @@ -8,18 +7,18 @@ module.exports = { const stream = through() stream.pipe( concat(data => { - action('fs.createWriteStream')(filepath) + console.log('fs.createWriteStream', filepath) }) ) return stream }, writeFile: (filepath, data, cb) => { - action('fs.writeFile')(filepath) + console.log('fs.writeFile', filepath) const blob = new Blob([data], { type: 'application/octet-stream' }) FileSaver.saveAs(blob, filepath) cb() }, readFileSync: filepath => { - action('fs.readFileSync')(filepath) + console.log('fs.readFileSync', filepath) } } diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 000000000..31a570c66 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,15 @@ +const path = require('path') + +module.exports = { + webpackFinal: async (config, { configType }) => { + // Configure worker-loader for PDF renderer + config.module.rules.unshift({ + test: /\.worker\.js$/, + include: path.join(__dirname, '../src'), + use: [{ loader: 'worker-loader' }, { loader: 'babel-loader' }] + }) + + // Return the altered config + return config + } +} diff --git a/flow-typed/npm/@react-pdf/renderer_vx.x.x.js b/flow-typed/npm/@react-pdf/renderer_vx.x.x.js index fe48bac53..f6c81054b 100644 --- a/flow-typed/npm/@react-pdf/renderer_vx.x.x.js +++ b/flow-typed/npm/@react-pdf/renderer_vx.x.x.js @@ -17,7 +17,7 @@ declare module '@react-pdf/renderer' { |} declare type ImagePropTypes = {| wrap?: boolean, - src?: string, + src?: string | Promise<{ data: Buffer, format: 'png' | 'jpg' }>, style?: any, debug?: boolean, fixed?: boolean, diff --git a/package-lock.json b/package-lock.json index f085354fd..c1f14a9e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2690,43 +2690,27 @@ "@react-pdf/types": "^2.0.3", "cross-fetch": "^3.0.4", "is-url": "^1.2.4" + } + }, + "@react-pdf/fontkit": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@react-pdf/fontkit/-/fontkit-2.0.6.tgz", + "integrity": "sha512-9l85jaY8WiyLHMZvh4d08q5TMWPRwqZIwN6uLzqaoMjMqJ1A3I6StE5kaxvEGVxvFvAeExHfFVgKdyeFmLQg4g==", + "requires": { + "@react-pdf/unicode-properties": "^2.4.1", + "brotli": "^1.2.0", + "clone": "^1.0.4", + "deep-equal": "^1.0.0", + "dfa": "1.1.0", + "restructure": "^0.5.3", + "tiny-inflate": "^1.0.2", + "unicode-trie": "^0.3.0" }, "dependencies": { - "@react-pdf/fontkit": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@react-pdf/fontkit/-/fontkit-2.0.6.tgz", - "integrity": "sha512-9l85jaY8WiyLHMZvh4d08q5TMWPRwqZIwN6uLzqaoMjMqJ1A3I6StE5kaxvEGVxvFvAeExHfFVgKdyeFmLQg4g==", - "requires": { - "@react-pdf/unicode-properties": "^2.4.1", - "brotli": "^1.2.0", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "1.1.0", - "restructure": "^0.5.3", - "tiny-inflate": "^1.0.2", - "unicode-trie": "^0.3.0" - } - }, - "@react-pdf/unicode-properties": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@react-pdf/unicode-properties/-/unicode-properties-2.4.1.tgz", - "integrity": "sha512-B6jnyp7KaTcQeWbkk5wlBEWrGrsGAMtcWVHIyUArBK2HXo3CDkCyx3/AiRsZYgBLBJzjmD7Qv6nPK9ksXNQD/Q==", - "requires": { - "unicode-trie": "^0.3.0" - } - }, "clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "dfa": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.1.0.tgz", - "integrity": "sha1-0wIYvRDQMPpCHfPrvIIoVGOjF4E=", - "requires": { - "babel-runtime": "^6.11.6" - } } } }, @@ -2737,13 +2721,6 @@ "requires": { "@react-pdf/png-js": "^2.0.2", "cross-fetch": "^3.0.4" - }, - "dependencies": { - "@react-pdf/png-js": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-2.0.2.tgz", - "integrity": "sha512-hdOxW8JiWKy1JtocfMG6RhNFRLJeJIHOdAPg9CNpg4Az7PrDdtPoEZfQ1rXSuPhX2iHH5Brfb3Epv+VvUl7BKg==" - } } }, "@react-pdf/layout": { @@ -2765,74 +2742,6 @@ "ramda": "^0.26.1" }, "dependencies": { - "@react-pdf/fontkit": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@react-pdf/fontkit/-/fontkit-2.0.6.tgz", - "integrity": "sha512-9l85jaY8WiyLHMZvh4d08q5TMWPRwqZIwN6uLzqaoMjMqJ1A3I6StE5kaxvEGVxvFvAeExHfFVgKdyeFmLQg4g==", - "requires": { - "@react-pdf/unicode-properties": "^2.4.1", - "brotli": "^1.2.0", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "1.1.0", - "restructure": "^0.5.3", - "tiny-inflate": "^1.0.2", - "unicode-trie": "^0.3.0" - } - }, - "@react-pdf/pdfkit": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-2.0.10.tgz", - "integrity": "sha512-D3YjLSLF3ajM+q+y2OWqAc5BF1FyKQvp4SPQiZLXFC7ucRqM5SUbSHZ2bPWtfm7J12pPHYnOPZjaWbIThW/QwA==", - "requires": { - "@react-pdf/fontkit": "^2.0.6", - "@react-pdf/png-js": "^2.0.2", - "crypto-js": "^4.0.0", - "lz-string": "^1.4.4" - } - }, - "@react-pdf/png-js": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-2.0.2.tgz", - "integrity": "sha512-hdOxW8JiWKy1JtocfMG6RhNFRLJeJIHOdAPg9CNpg4Az7PrDdtPoEZfQ1rXSuPhX2iHH5Brfb3Epv+VvUl7BKg==" - }, - "@react-pdf/textkit": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-2.0.5.tgz", - "integrity": "sha512-HWPoEzjULQ7LKTHIdINa6GJKf/30MFrH4pXBqP00+XIl/UvlEjfrmqgnYJLdfZt8JP8M7wAXX6I0DbEeJGuYJw==", - "requires": { - "@babel/runtime": "^7.4.3", - "@react-pdf/unicode-properties": "^2.4.1", - "hyphen": "^1.6.4", - "ramda": "^0.26.1" - } - }, - "@react-pdf/unicode-properties": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@react-pdf/unicode-properties/-/unicode-properties-2.4.1.tgz", - "integrity": "sha512-B6jnyp7KaTcQeWbkk5wlBEWrGrsGAMtcWVHIyUArBK2HXo3CDkCyx3/AiRsZYgBLBJzjmD7Qv6nPK9ksXNQD/Q==", - "requires": { - "unicode-trie": "^0.3.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "dfa": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.1.0.tgz", - "integrity": "sha1-0wIYvRDQMPpCHfPrvIIoVGOjF4E=", - "requires": { - "babel-runtime": "^6.11.6" - } - }, - "hyphen": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.6.4.tgz", - "integrity": "sha512-nWwvXceFMAFIjkiRzqZMZSOa1LVngieSolnYIVKWSwmDwMSmdutjzqImmdbxe2eUCfX693fgrCgtPjbllqx1lA==" - }, "ramda": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", @@ -2840,6 +2749,22 @@ } } }, + "@react-pdf/pdfkit": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-2.0.10.tgz", + "integrity": "sha512-D3YjLSLF3ajM+q+y2OWqAc5BF1FyKQvp4SPQiZLXFC7ucRqM5SUbSHZ2bPWtfm7J12pPHYnOPZjaWbIThW/QwA==", + "requires": { + "@react-pdf/fontkit": "^2.0.6", + "@react-pdf/png-js": "^2.0.2", + "crypto-js": "^4.0.0", + "lz-string": "^1.4.4" + } + }, + "@react-pdf/png-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-2.0.2.tgz", + "integrity": "sha512-hdOxW8JiWKy1JtocfMG6RhNFRLJeJIHOdAPg9CNpg4Az7PrDdtPoEZfQ1rXSuPhX2iHH5Brfb3Epv+VvUl7BKg==" + }, "@react-pdf/primitives": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-pdf/primitives/-/primitives-2.0.0.tgz", @@ -2861,30 +2786,6 @@ "svg-arc-to-cubic-bezier": "^3.2.0" }, "dependencies": { - "@react-pdf/textkit": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-2.0.5.tgz", - "integrity": "sha512-HWPoEzjULQ7LKTHIdINa6GJKf/30MFrH4pXBqP00+XIl/UvlEjfrmqgnYJLdfZt8JP8M7wAXX6I0DbEeJGuYJw==", - "requires": { - "@babel/runtime": "^7.4.3", - "@react-pdf/unicode-properties": "^2.4.1", - "hyphen": "^1.6.4", - "ramda": "^0.26.1" - } - }, - "@react-pdf/unicode-properties": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@react-pdf/unicode-properties/-/unicode-properties-2.4.1.tgz", - "integrity": "sha512-B6jnyp7KaTcQeWbkk5wlBEWrGrsGAMtcWVHIyUArBK2HXo3CDkCyx3/AiRsZYgBLBJzjmD7Qv6nPK9ksXNQD/Q==", - "requires": { - "unicode-trie": "^0.3.0" - } - }, - "hyphen": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.6.4.tgz", - "integrity": "sha512-nWwvXceFMAFIjkiRzqZMZSOa1LVngieSolnYIVKWSwmDwMSmdutjzqImmdbxe2eUCfX693fgrCgtPjbllqx1lA==" - }, "ramda": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", @@ -2911,58 +2812,6 @@ "scheduler": "^0.15.0" }, "dependencies": { - "@react-pdf/fontkit": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@react-pdf/fontkit/-/fontkit-2.0.6.tgz", - "integrity": "sha512-9l85jaY8WiyLHMZvh4d08q5TMWPRwqZIwN6uLzqaoMjMqJ1A3I6StE5kaxvEGVxvFvAeExHfFVgKdyeFmLQg4g==", - "requires": { - "@react-pdf/unicode-properties": "^2.4.1", - "brotli": "^1.2.0", - "clone": "^1.0.4", - "deep-equal": "^1.0.0", - "dfa": "1.1.0", - "restructure": "^0.5.3", - "tiny-inflate": "^1.0.2", - "unicode-trie": "^0.3.0" - } - }, - "@react-pdf/pdfkit": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@react-pdf/pdfkit/-/pdfkit-2.0.10.tgz", - "integrity": "sha512-D3YjLSLF3ajM+q+y2OWqAc5BF1FyKQvp4SPQiZLXFC7ucRqM5SUbSHZ2bPWtfm7J12pPHYnOPZjaWbIThW/QwA==", - "requires": { - "@react-pdf/fontkit": "^2.0.6", - "@react-pdf/png-js": "^2.0.2", - "crypto-js": "^4.0.0", - "lz-string": "^1.4.4" - } - }, - "@react-pdf/png-js": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@react-pdf/png-js/-/png-js-2.0.2.tgz", - "integrity": "sha512-hdOxW8JiWKy1JtocfMG6RhNFRLJeJIHOdAPg9CNpg4Az7PrDdtPoEZfQ1rXSuPhX2iHH5Brfb3Epv+VvUl7BKg==" - }, - "@react-pdf/unicode-properties": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@react-pdf/unicode-properties/-/unicode-properties-2.4.1.tgz", - "integrity": "sha512-B6jnyp7KaTcQeWbkk5wlBEWrGrsGAMtcWVHIyUArBK2HXo3CDkCyx3/AiRsZYgBLBJzjmD7Qv6nPK9ksXNQD/Q==", - "requires": { - "unicode-trie": "^0.3.0" - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" - }, - "dfa": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.1.0.tgz", - "integrity": "sha1-0wIYvRDQMPpCHfPrvIIoVGOjF4E=", - "requires": { - "babel-runtime": "^6.11.6" - } - }, "ramda": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", @@ -2998,24 +2847,43 @@ } } }, + "@react-pdf/textkit": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@react-pdf/textkit/-/textkit-2.0.5.tgz", + "integrity": "sha512-HWPoEzjULQ7LKTHIdINa6GJKf/30MFrH4pXBqP00+XIl/UvlEjfrmqgnYJLdfZt8JP8M7wAXX6I0DbEeJGuYJw==", + "requires": { + "@babel/runtime": "^7.4.3", + "@react-pdf/unicode-properties": "^2.4.1", + "hyphen": "^1.6.4", + "ramda": "^0.26.1" + }, + "dependencies": { + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" + } + } + }, "@react-pdf/types": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@react-pdf/types/-/types-2.0.3.tgz", "integrity": "sha512-yrcq/hkDU7+hcZKf3+NN4sa3gYcOfdPBaJPsaCq7aNI/Wk4FNG+R5qimo5PSiOiaowkkXFZtFadVq0RlbrWXeg==" }, + "@react-pdf/unicode-properties": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@react-pdf/unicode-properties/-/unicode-properties-2.4.1.tgz", + "integrity": "sha512-B6jnyp7KaTcQeWbkk5wlBEWrGrsGAMtcWVHIyUArBK2HXo3CDkCyx3/AiRsZYgBLBJzjmD7Qv6nPK9ksXNQD/Q==", + "requires": { + "unicode-trie": "^0.3.0" + } + }, "@react-pdf/yoga": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@react-pdf/yoga/-/yoga-2.0.2.tgz", "integrity": "sha512-BKEbxIw1XHy3BDYAaOOjrJRLQZUmh+DIv+WIYO6MbwPXP7WLhbggqhC1MOLS3ZyNyBC12VInsYEdpF1l5ia3ng==", "requires": { "@types/yoga-layout": "^1.9.3" - }, - "dependencies": { - "@types/yoga-layout": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.3.tgz", - "integrity": "sha512-tkAtGqt+f8IFNTr1j11znuuYtYtoEeBFFyEDSENKEVw+aUiHz2tdYcE1TTxNcGEAy/9NNrYfIPaeEYEQXy+Y+Q==" - } } }, "@rollup/plugin-commonjs": { @@ -5315,6 +5183,11 @@ "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", "dev": true }, + "@types/yoga-layout": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.3.tgz", + "integrity": "sha512-tkAtGqt+f8IFNTr1j11znuuYtYtoEeBFFyEDSENKEVw+aUiHz2tdYcE1TTxNcGEAy/9NNrYfIPaeEYEQXy+Y+Q==" + }, "@typescript-eslint/eslint-plugin": { "version": "2.34.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz", @@ -10761,9 +10634,9 @@ } }, "cross-fetch": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", - "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.4.tgz", + "integrity": "sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ==", "requires": { "node-fetch": "2.6.1" }, @@ -11798,6 +11671,14 @@ "wrappy": "1" } }, + "dfa": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.1.0.tgz", + "integrity": "sha1-0wIYvRDQMPpCHfPrvIIoVGOjF4E=", + "requires": { + "babel-runtime": "^6.11.6" + } + }, "diacritics": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/diacritics/-/diacritics-1.3.0.tgz", @@ -14216,6 +14097,27 @@ "p-finally": "^1.0.0", "signal-exit": "^3.0.0", "strip-eof": "^1.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "exit": { @@ -16479,23 +16381,9 @@ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "requires": { - "pump": "^3.0.0" - }, - "dependencies": { - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" }, "get-value": { "version": "2.0.6", @@ -17096,6 +16984,27 @@ "p-cancelable": "^1.0.0", "to-readable-stream": "^1.0.0", "url-parse-lax": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "graceful-fs": { @@ -18001,6 +17910,11 @@ } } }, + "hyphen": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.6.4.tgz", + "integrity": "sha512-nWwvXceFMAFIjkiRzqZMZSOa1LVngieSolnYIVKWSwmDwMSmdutjzqImmdbxe2eUCfX693fgrCgtPjbllqx1lA==" + }, "hyphenate-style-name": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", @@ -21575,6 +21489,25 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } } } }, @@ -21606,6 +21539,25 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } } } }, @@ -21626,6 +21578,25 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } } } }, @@ -21652,6 +21623,25 @@ "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -21669,6 +21659,27 @@ "figgy-pudding": "^3.5.1", "get-stream": "^4.0.0", "npm-registry-fetch": "^4.0.0" + }, + "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } } }, "libnpmteam": { @@ -21688,6 +21699,25 @@ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } } } }, @@ -25592,7 +25622,6 @@ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", "is-stream": "^1.1.0", "npm-run-path": "^2.0.0", "p-finally": "^1.0.0", @@ -27281,6 +27310,15 @@ "which": "^1.3.1" }, "dependencies": { + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -27315,6 +27353,16 @@ "minimist": "^1.2.5" } }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -28838,6 +28886,15 @@ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -28916,6 +28973,16 @@ "uniq": "^1.0.1" } }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -29589,9 +29656,9 @@ "dev": true }, "queue": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.1.tgz", - "integrity": "sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "requires": { "inherits": "~2.0.3" } @@ -30353,6 +30420,26 @@ "pdfjs-dist": "2.4.456", "prop-types": "^15.6.2", "worker-loader": "^2.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "worker-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", + "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", + "requires": { + "loader-utils": "^1.0.0", + "schema-utils": "^0.4.0" + } + } } }, "react-popper": { @@ -32125,6 +32212,11 @@ "varint": "~5.0.0" } }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, "simple-html-tokenizer": { "version": "0.5.9", "resolved": "https://registry.npmjs.org/simple-html-tokenizer/-/simple-html-tokenizer-0.5.9.tgz", @@ -35971,6 +36063,11 @@ "punycode": "^2.1.0" } }, + "uri-templates": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/uri-templates/-/uri-templates-0.2.0.tgz", + "integrity": "sha1-K1eEURzJCYaHMekjPCaAl9ELSZ8=" + }, "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", @@ -36921,9 +37018,9 @@ } }, "webpack-bundle-analyzer": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.8.0.tgz", - "integrity": "sha512-PODQhAYVEourCcOuU+NiYI7WdR8QyELZGgPvB1y2tjbUpbmcQOt5Q7jEK+ttd5se0KSBKD9SXHCEozS++Wllmw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz", + "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==", "dev": true, "requires": { "acorn": "^7.1.1", @@ -36935,16 +37032,16 @@ "express": "^4.16.3", "filesize": "^3.6.1", "gzip-size": "^5.0.0", - "lodash": "^4.17.15", + "lodash": "^4.17.19", "mkdirp": "^0.5.1", "opener": "^1.5.1", "ws": "^6.0.0" }, "dependencies": { "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-walk": { @@ -36953,6 +37050,12 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", @@ -36969,9 +37072,9 @@ } }, "ws": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", - "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", "dev": true, "requires": { "async-limiter": "~1.0.0" @@ -37551,21 +37654,80 @@ } }, "worker-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-2.0.0.tgz", - "integrity": "sha512-tnvNp4K3KQOpfRnD20m8xltE3eWh89Ye+5oj7wXEEHKac1P4oZ6p9oTj8/8ExqoSBnk9nu5Pr4nKfQ1hn2APJw==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-3.0.8.tgz", + "integrity": "sha512-XQyQkIFeRVC7f7uRhFdNMe/iJOdO6zxAaR3EWbDp45v3mDhrTi+++oswKNxShUNjPC/1xUp5DB29YKLhFo129g==", + "dev": true, "requires": { - "loader-utils": "^1.0.0", - "schema-utils": "^0.4.0" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "dependencies": { + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" } } } diff --git a/package.json b/package.json index f9d35013f..09847bb47 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,7 @@ "fs-write-stream-atomic": "^1.0.10", "get-port": "^5.1.1", "get-scrollbar-width": "^1.0.4", + "get-stream": "^6.0.0", "hidden-mapbox": "^1.0.1", "html-react-parser": "^0.9.1", "id-mapeo": "^3.4.1", @@ -168,12 +169,14 @@ "sanitize-filename": "^1.6.3", "semver": "^7.3.2", "signal-exit": "^3.0.3", + "simple-concat": "^1.0.1", "styled-components": "^3.4.4", "subleveldown": "^3.0.1", "tar-fs": "^1.16.0", "terminate": "^2.1.2", "through2": "^2.0.5", "tiny-typed-emitter": "^2.0.3", + "uri-templates": "^0.2.0", "utm": "^1.1.1", "winston": "^3.2.1", "winston-daily-rotate-file": "^4.4.2", @@ -259,10 +262,11 @@ "typescript": "^4.2.2", "url-loader": "^4.1.1", "webpack": "^4.40.2", - "webpack-bundle-analyzer": "^3.8.0", + "webpack-bundle-analyzer": "^3.9.0", "webpack-cli": "^3.3.9", "webpack-merge": "^4.2.2", - "webpack-node-externals": "^1.7.2" + "webpack-node-externals": "^1.7.2", + "worker-loader": "^3.0.5" }, "license-check-config": { "src": [ diff --git a/src/main/ipc.js b/src/main/ipc.js index 004848b82..cee8e0bbc 100644 --- a/src/main/ipc.js +++ b/src/main/ipc.js @@ -9,7 +9,6 @@ const i18n = require('./i18n') * Miscellaneous ipcMain calls that don't hit mapeo-core */ module.exports = function (ipcSend) { - console.log('IPC main') function onError (err) { logger.error('[MAIN/IPC] error', err) ipcSend('error', err.message, err.stack) diff --git a/src/main/windows.js b/src/main/windows.js index f9d8966b3..87bf337ef 100644 --- a/src/main/windows.js +++ b/src/main/windows.js @@ -38,6 +38,7 @@ function MainWindow (options) { icon: path.resolve(__dirname, '../../static/mapeo_256x256.png'), webPreferences: { nodeIntegration: true, + nodeIntegrationInWorker: true, preload: path.resolve(__dirname, '../renderer/index-preload.js'), additionalArguments: [JSON.stringify(options)], contextIsolation: false diff --git a/src/renderer/components/MapFilter/ReportView/PDFReport.js b/src/renderer/components/MapFilter/ReportView/PDFReport.js index 481ae8e5a..ddc61e23f 100644 --- a/src/renderer/components/MapFilter/ReportView/PDFReport.js +++ b/src/renderer/components/MapFilter/ReportView/PDFReport.js @@ -1,7 +1,8 @@ // @flow import * as React from 'react' +import { nativeImage } from 'electron' +import ky from 'ky' import { - RawIntlProvider, IntlProvider, defineMessages, useIntl, @@ -9,7 +10,6 @@ import { FormattedMessage } from 'react-intl' import { - pdf, Page, Text as TextOrig, View, @@ -18,9 +18,8 @@ import { StyleSheet, Font } from '@react-pdf/renderer' -import type { Field } from 'mapeo-schema' -import PQueue from 'p-queue' -import pTimeout from 'p-timeout' +import type { Field, Observation } from 'mapeo-schema' +import UriTemplate from 'uri-templates' import { FormattedFieldProp, @@ -31,17 +30,13 @@ import { isEmptyValue } from '../utils/helpers' import { formatId } from '../utils/strings' import { get } from '../utils/get_set' import type { ImageMediaItem } from '../ObservationDialog' -import type { - PresetWithAdditionalFields, - CommonViewContentProps -} from '../types' +import type { PresetWithAdditionalFields } from '../types' import { SettingsContext, defaultSettings, type SettingsContextType } from '../internal/Context' import { type MapViewContentProps } from '../MapView/MapViewContent' -import api from '../../../new-api' import dateIcon from './iconEvent.png' import fallbackCategoryIcon from './iconPlace.png' @@ -66,6 +61,8 @@ import rubikItalic from '../../../../../static/fonts/Rubik-Italic.ttf' import rubikLight from '../../../../../static/fonts/Rubik-Light.ttf' import rubikLightItalic from '../../../../../static/fonts/Rubik-LightItalic.ttf' +import robotoMonoRegular from '../../../../../static/fonts/RobotoMono-Regular.ttf' + Font.register({ family: 'Sarabun', fonts: [ @@ -94,6 +91,11 @@ Font.register({ ] }) +Font.register({ + family: 'Roboto Mono', + fonts: [{ src: robotoMonoRegular, fontStyle: 'normal', fontWeight: 400 }] +}) + const DEFAULT_FONT = 'Rubik' // Our default font (Rubik) does not contain glyphs for all languages. There @@ -117,10 +119,17 @@ const m = defineMessages({ }) export type ReportProps = { - ...$Exact<$Diff>, - /** Rendering a PDF does not inherit context from the parent tree. Get this - * value with useIntl() and provide it as a prop */ - intl?: any, + observationsWithPresets: Array<{| + observation: Observation, + preset: PresetWithAdditionalFields, + iconURL?: string, + mediaSources: { + [id: string]: { src: string, type: 'image' | 'video' | 'audio' } | void + } + |}>, + mapImageTemplateURL: string, + locale?: string, + messages?: any, /** Rendering a PDF does not inherit context from the parent tree. Get this * value with React.useContext(SettingsContext) and provide it as a prop */ settings?: SettingsContextType, @@ -131,7 +140,7 @@ export type ReportProps = { * pdf preview of second observation starts on page 3). Do not use for final * render */ startPage?: number, - ...$Exact + ...$Exact<$Diff> } /* TODO: add frontpage @@ -162,33 +171,6 @@ const FrontPage = ({ bounds }) => { */ -// Only render 1 PDF doc at a time -const queue = new PQueue({ concurrency: 1 }) - -function renderToBlob (doc, timeout?: number) { - return queue.add(() => { - const instance = pdf(doc) - return timeout - ? pTimeout( - instance.toBlob(), - timeout, - `Report render timed out after ${timeout}ms` - ) - : instance.toBlob() - }) -} - -export function renderPDFReport ( - props: ReportProps, - timeout?: number -): Promise<{ blob: Blob, index: Array }> { - let pageIndex: Array = [] - const doc = ( - (pageIndex = index)} /> - ) - return renderToBlob(doc).then(blob => ({ blob, index: pageIndex })) -} - const Text = ({ style, ...otherProps @@ -199,18 +181,20 @@ const Text = ({ } export const PDFReport = ({ - intl, settings = defaultSettings, onPageIndex, - observations, - getPreset, - getMedia, + observationsWithPresets, + mapImageTemplateURL, + locale = 'en', + messages, mapStyle, mapboxAccessToken, startPage = 1 }: ReportProps) => { // **Assumption: Each observation will be max 3 pages** - const sparsePageIndex = new Array(observations.length * 3).fill(undefined) + const sparsePageIndex = new Array(observationsWithPresets.length * 3).fill( + undefined + ) let didCallback = false // This will be called once for each observation without the totalPages, then @@ -228,35 +212,34 @@ export const PDFReport = ({ } } - const children = ( - - - {observations.map(observation => { - const view = new ObservationView({ - observation, - getPreset, - getMedia, - mapStyle, - mapboxAccessToken - }) - return ( - - ) - })} - - - ) - // Need to provide `intl` for dates to format according to language, but will - // fallback to `en` with default intl object - return intl ? ( - {children} - ) : ( - {children} + return ( + + + + {observationsWithPresets.map( + ({ observation, preset, mediaSources, iconURL }) => { + const view = new ObservationView({ + observation, + preset, + mediaSources, + iconURL, + mapStyle, + mapboxAccessToken, + mapImageTemplateURL + }) + return ( + + ) + } + )} + + + ) } @@ -294,7 +277,9 @@ const FeaturePage = ({ }> - }>{formatId(view.id)} + }> + {formatId(view.id)} + @@ -463,10 +448,17 @@ const ObsInsetMap = ({ view }: { view: ObservationView }) => { const ObsImage = ({ src }: { src: string }) => ( - + ) +async function getResizedImage (src: string, width: number) { + const arrayBuffer = await ky.get(src).arrayBuffer() + const image = nativeImage.createFromBuffer(Buffer.from(arrayBuffer)) + const buf = image.resize({ width, quality: 'better' }).toJPEG(70) + return { data: buf, format: 'jpg' } +} + class ObservationView { static DEFAULT_ZOOM_LEVEL = 11 id: string @@ -479,16 +471,22 @@ class ObservationView { preset: PresetWithAdditionalFields mapboxAccessToken: $PropertyType mapStyle: $PropertyType + iconURL: string | void + mapImageTemplate: any constructor ({ observation, - getPreset, - getMedia, + preset, + mediaSources, + iconURL, mapStyle, - mapboxAccessToken + mapboxAccessToken, + mapImageTemplateURL }) { this.mapStyle = mapStyle this.mapboxAccessToken = mapboxAccessToken + this.mapImageTemplate = new UriTemplate(mapImageTemplateURL) + this.iconURL = iconURL this.id = observation.id this.coords = typeof observation.lon === 'number' && typeof observation.lat === 'number' @@ -499,28 +497,24 @@ class ObservationView { : undefined this.createdAt = new Date(observation.created_at) - this.preset = getPreset(observation) + this.preset = preset // $FlowFixMe - need to create Fields type this.fields = this.preset.fields.concat(this.preset.additionalFields) this.tags = observation.tags || {} this.note = this.tags.note || this.tags.notes this.mediaItems = (observation.attachments || []).reduce((acc, cur) => { - const item = getMedia(cur, { width: 800, height: 600 }) + const item = mediaSources[cur.id] if (item && item.type === 'image') acc.push(item.src) return acc }, []) } getIconURL (size?: 'medium') { - if (!api.getBaseUrl()) return // for rendering in storybook - if (!this.preset.icon) return - return api.getIconUrl(this.preset.icon) + return this.iconURL } - getMapImageURL (zoom) { - if (!zoom) zoom = ObservationView.DEFAULT_ZOOM_LEVEL + getMapImageURL (zoom = ObservationView.DEFAULT_ZOOM_LEVEL) { if (!this.coords) return null - var opts = { width: HEADER_HEIGHT * 1.5, height: HEADER_HEIGHT, @@ -531,7 +525,7 @@ class ObservationView { style: this.mapStyle, accessToken: this.mapboxAccessToken } - return api.getMapImageURL(opts) + return this.mapImageTemplate.fillFromObject(opts) } } @@ -593,6 +587,9 @@ const s = StyleSheet.create({ fontWeight: 500, color: 'white' }, + id: { + fontFamily: 'Roboto Mono' + }, categoryIcon: { width: 20 }, diff --git a/src/renderer/components/MapFilter/ReportView/PDFReport.stories.js b/src/renderer/components/MapFilter/ReportView/PDFReport.stories.js index ce124929b..7d739c62f 100644 --- a/src/renderer/components/MapFilter/ReportView/PDFReport.stories.js +++ b/src/renderer/components/MapFilter/ReportView/PDFReport.stories.js @@ -26,6 +26,13 @@ const getMediaUrl = id => { if (id === 'portrait.jpg') return imageBaseUrl + id return imageBaseUrl + ((parseInt(id, 16) % 17) + 1) + '.jpg' } + +const exampleWithPresets = exampleObservations.slice(0, 1).map(o => ({ + observation: o, + preset: defaultGetPreset(o), + mediaSources: o.attachments.map(a => getMedia(a)) +})) + export default { title: 'ReportView/components/PDFReport', component: PDFReport, @@ -53,12 +60,10 @@ export const basic = () => } > diff --git a/src/renderer/components/MapFilter/ReportView/ReportViewContent.js b/src/renderer/components/MapFilter/ReportView/ReportViewContent.js index 1edbf665a..17179acb1 100644 --- a/src/renderer/components/MapFilter/ReportView/ReportViewContent.js +++ b/src/renderer/components/MapFilter/ReportView/ReportViewContent.js @@ -33,7 +33,7 @@ import type { } from '../types' import { type MapViewContentProps } from '../MapView/MapViewContent' import { SettingsContext } from '../internal/Context' -import { renderPDFReport } from './PDFReport' +import renderPDFReport from './renderReport' import ToolbarButton from '../internal/ToolbarButton' export type ReportViewContentProps = { @@ -67,10 +67,12 @@ const hiddenTags = { const ReportViewContent = ({ onClick, observations, + getMedia, getPreset, initialPageNumber = 1, totalObservations, - ...otherProps + mapboxAccessToken, + mapStyle }: ReportViewContentProps) => { const stats = useMemo(() => getStats(observations || []), [observations]) const intl = useIntl() @@ -123,7 +125,9 @@ const ReportViewContent = ({ intl, settings, getPreset: getPresetWithFilteredFields, - ...otherProps + getMedia, + mapboxAccessToken, + mapStyle }) // Prefix filename with date `YYYY-MM-DD` const datePrefix = new Date().toISOString().split('T')[0] @@ -146,7 +150,9 @@ const ReportViewContent = ({ intl, settings, getPreset: getPresetWithFilteredFields, - ...otherProps + getMedia, + mapboxAccessToken, + mapStyle }) // If there is an error generating the PDF preview, try resetting to page 1 diff --git a/src/renderer/components/MapFilter/ReportView/renderReport.js b/src/renderer/components/MapFilter/ReportView/renderReport.js new file mode 100644 index 000000000..3cc1809c2 --- /dev/null +++ b/src/renderer/components/MapFilter/ReportView/renderReport.js @@ -0,0 +1,67 @@ +// @flow +import api from '../../../new-api' +import { type ReportProps } from './PDFReport' +import type { ReportViewContentProps } from './ReportViewContent' + +type ReportData = { + blob: Blob, + index: Array +} + +type Props = {| + ...$Exact< + $Diff + >, + intl: any, + settings: any, + startPage?: number +|} + +const reportWorker = new Worker('./pdfWorker.bundle.js') +let msgId = 1 +const pending = new Map void>() + +// $FlowFixMe +reportWorker.addEventListener('message', msg => { + const { id, buffer, index } = msg.data + if (!id || !pending.has(id)) return + const resolve = pending.get(id) + pending.delete(id) + resolve && + resolve({ blob: new Blob([buffer], { type: 'application/pdf' }), index }) +}) + +export default function renderReport ( + { observations, getPreset, getMedia, intl, ...otherProps }: Props, + timeout?: number +): Promise { + const id = msgId++ + return new Promise((resolve, reject) => { + const props: ReportProps = { + observationsWithPresets: observations.map(obs => { + const preset = getPreset(obs) + return { + observation: obs, + preset, + iconURL: preset && preset.icon && api.getIconUrl(preset.icon), + mediaSources: (obs.attachments || []).reduce((acc, cur) => { + acc[cur.id] = getMedia(cur) + return acc + }, {}) + } + }), + mapImageTemplateURL: api.getMapImageTemplateURL(), + locale: intl.locale, + messages: intl.messages, + ...otherProps + } + reportWorker.postMessage({ props, action: 'RENDER_PDF', id }) + pending.set(id, resolve) + if (!timeout) return + setTimeout(() => { + if (!pending.has(id)) return + pending.delete(id) + reject(new Error('Report generation timeout')) + }, timeout) + }) +} diff --git a/src/renderer/components/MapFilter/ReportView/renderReport.worker.js b/src/renderer/components/MapFilter/ReportView/renderReport.worker.js new file mode 100644 index 000000000..bde03e444 --- /dev/null +++ b/src/renderer/components/MapFilter/ReportView/renderReport.worker.js @@ -0,0 +1,44 @@ +// @flow + +import { pdf } from '@react-pdf/renderer' +import concat from 'simple-concat' +import PQueue from 'p-queue' +import React from 'react' + +import { PDFReport, type ReportProps } from './PDFReport' + +const queue = new PQueue({ concurrency: 1 }) + +function renderToStream (doc) { + return queue.add(() => { + const instance = pdf(doc) + return instance.toBuffer() + }) +} + +async function renderPDF ( + props: $Diff +): Promise<{ buffer: Buffer, index: Array }> { + let pageIndex: Array = [] + const doc = ( + (pageIndex = index)} /> + ) + const outStream = await renderToStream(doc) + return new Promise((resolve, reject) => { + concat(outStream, (err, buffer) => { + if (err) return reject(err) + resolve({ buffer, index: pageIndex }) + }) + }) +} + +self.addEventListener('message', async msg => { + switch (msg.data.action) { + case 'RENDER_PDF': { + const { buffer, index } = await renderPDF(msg.data.props) + self.postMessage({ id: msg.data.id, buffer: buffer.buffer, index }, [ + buffer.buffer + ]) + } + } +}) diff --git a/src/renderer/components/MapFilter/ReportView/usePDFPreview.js b/src/renderer/components/MapFilter/ReportView/usePDFPreview.js index ea9230f78..443e6168e 100644 --- a/src/renderer/components/MapFilter/ReportView/usePDFPreview.js +++ b/src/renderer/components/MapFilter/ReportView/usePDFPreview.js @@ -3,7 +3,7 @@ import React from 'react' import QuickLRU from 'quick-lru' import type { Observation } from 'mapeo-schema' -import { renderPDFReport } from './PDFReport' +import renderPDFReport from './renderReport' import type { ReportViewContentProps } from './ReportViewContent' import logger from '../../../../logger' @@ -103,7 +103,9 @@ export default function usePDFPreview ({ ) pdfCache.set(obs, pdfPromise) // Don't cache if render fails - pdfPromise.catch(() => pdfCache.delete(obs)) + pdfPromise.catch(e => { + pdfCache.delete(obs) + }) return pdfPromise } diff --git a/src/renderer/new-api.js b/src/renderer/new-api.js index 6932cec66..4474fbdc4 100644 --- a/src/renderer/new-api.js +++ b/src/renderer/new-api.js @@ -1,6 +1,7 @@ import 'core-js/es/reflect' import ky from 'ky/umd' import logger from '../logger' +import UriTemplate from 'uri-templates' export default Api({ // globals are set in src/middleware/client-preload.js @@ -216,6 +217,10 @@ function Api ({ baseUrl, mapUrl, ipc }) { ipc.send('zoom-to-data-get-centroid', type, cb) }, + getMapImageTemplateURL: function () { + return `${mapUrl}map/{lon}/{lat}/{zoom}/{width}/{height}/x{dpi}.png{?style,accessToken}` + }, + getMapImageURL: function ({ lon, lat, @@ -226,18 +231,17 @@ function Api ({ baseUrl, mapUrl, ipc }) { style, accessToken }) { - let url = `${mapUrl}map/${lon}/${lat}/${zoom}/${width}/${height}/x${dpi}.png` - const searchParams = [] - if (typeof style === 'string') { - searchParams.push('style=' + style) - } - if (typeof accessToken === 'string') { - searchParams.push('accessToken=' + accessToken) - } - if (searchParams.length) { - url += '?' + searchParams.join('&') - } - return url + const template = new UriTemplate(api.getMapImageTemplateURL()) + return template.fillFromObject({ + lon, + lat, + zoom, + width, + height, + dpi, + style, + accessToken + }) } } diff --git a/static/fonts/RobotoMono-Regular.ttf b/static/fonts/RobotoMono-Regular.ttf new file mode 100644 index 000000000..7c4ce36a4 Binary files /dev/null and b/static/fonts/RobotoMono-Regular.ttf differ diff --git a/webpack.common.js b/webpack.common.js index 58b95bee6..d76334fd6 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -2,7 +2,9 @@ const path = require('path') module.exports = { entry: { - app: './src/renderer/app.js' + app: './src/renderer/app.js', + pdfWorker: + './src/renderer/components/MapFilter/ReportView/renderReport.worker.js' }, target: 'electron-renderer', externals: [ @@ -41,7 +43,7 @@ module.exports = { }, { test: /\.ttf$/i, - loader: 'url-loader' + loader: 'file-loader' }, { test: /\.png$/i,