diff options
-rw-r--r-- | scripts/add_github.js | 44 | ||||
-rw-r--r-- | scripts/api/package.js | 204 | ||||
-rw-r--r-- | scripts/package.js | 106 | ||||
-rw-r--r-- | scripts/package.json | 1 | ||||
-rw-r--r-- | scripts/yarn.lock | 14 |
5 files changed, 247 insertions, 122 deletions
diff --git a/scripts/add_github.js b/scripts/add_github.js index 543e347..4a5cfce 100644 --- a/scripts/add_github.js +++ b/scripts/add_github.js | |||
@@ -6,6 +6,7 @@ const targz = require('targz'); | |||
6 | const fs = require('fs-extra'); | 6 | const fs = require('fs-extra'); |
7 | const path = require('path'); | 7 | const path = require('path'); |
8 | const GitUrlParse = require("git-url-parse"); | 8 | const GitUrlParse = require("git-url-parse"); |
9 | const packageRecipe = require('./api/package'); | ||
9 | 10 | ||
10 | // Helper: Download file to filesystem | 11 | // Helper: Download file to filesystem |
11 | const downloadFile = (async (url, path) => { | 12 | const downloadFile = (async (url, path) => { |
@@ -30,7 +31,7 @@ const decompress = (src, dest) => { | |||
30 | dest | 31 | dest |
31 | }, function (err) { | 32 | }, function (err) { |
32 | if (err) { | 33 | if (err) { |
33 | console.log('Error while decompressing recipe:', err); | 34 | console.log('⚠️ Could not add your recipe: There was an error while decompressing your GitHub repository file: ', err); |
34 | } | 35 | } |
35 | resolve(); | 36 | resolve(); |
36 | }); | 37 | }); |
@@ -40,7 +41,11 @@ const decompress = (src, dest) => { | |||
40 | const repo = process.argv[2]; | 41 | const repo = process.argv[2]; |
41 | 42 | ||
42 | if (!repo || !/https:\/\/github\.com\/[^\/]+\/[^\/]+\/?/gi.test(repo)) { | 43 | if (!repo || !/https:\/\/github\.com\/[^\/]+\/[^\/]+\/?/gi.test(repo)) { |
43 | console.log("Please provide a valid repository URL"); | 44 | console.log(`⚠️ Could not add your recipe: The GitHub URL you provided doesn't seem to be valid. |
45 | You should use this command like "yarn github https://github.com/user/repo". | ||
46 | Please make sure you provide a URL in the format "https://github.com/user/repo" | ||
47 | For more information about this script visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#publishing | ||
48 | If you want to package a local recipe, please use "yarn package" instead.`); | ||
44 | return; | 49 | return; |
45 | } | 50 | } |
46 | 51 | ||
@@ -54,24 +59,24 @@ const compressed = path.join(__dirname, 'tmp.tar.gz'); | |||
54 | 59 | ||
55 | // Let us work in an async environment | 60 | // Let us work in an async environment |
56 | (async () => { | 61 | (async () => { |
57 | console.log("Creating temporary directory"); | 62 | console.log("[Info] Creating temporary directory"); |
58 | 63 | ||
59 | await fs.ensureDir(tempDir); | 64 | await fs.ensureDir(tempDir); |
60 | await fs.ensureDir(recipeSrc); | 65 | await fs.ensureDir(recipeSrc); |
61 | await fs.ensureDir(recipeSrcTmp); | 66 | await fs.ensureDir(recipeSrcTmp); |
62 | 67 | ||
63 | console.log("Downloading " + repo); | 68 | console.log("[Info] Downloading " + repo); |
64 | 69 | ||
65 | await downloadFile( | 70 | await downloadFile( |
66 | `https://github.com/${repoInfo.owner}/${repoInfo.name}/archive/master.tar.gz`, | 71 | `https://github.com/${repoInfo.owner}/${repoInfo.name}/archive/master.tar.gz`, |
67 | compressed | 72 | compressed |
68 | ); | 73 | ); |
69 | 74 | ||
70 | console.log("Decompressing tarball"); | 75 | console.log("[Info] Decompressing repository"); |
71 | 76 | ||
72 | await decompress(compressed, tempDir); | 77 | await decompress(compressed, tempDir); |
73 | 78 | ||
74 | console.log("Moving directories"); | 79 | console.log("[Info] Moving 'recipe_src' to 'recipe_src_tmp'"); |
75 | 80 | ||
76 | await fs.move(recipeSrc, recipeSrcTmp, {overwrite: true}); | 81 | await fs.move(recipeSrc, recipeSrcTmp, {overwrite: true}); |
77 | await fs.move( | 82 | await fs.move( |
@@ -80,18 +85,21 @@ const compressed = path.join(__dirname, 'tmp.tar.gz'); | |||
80 | {overwrite: true} | 85 | {overwrite: true} |
81 | ); | 86 | ); |
82 | 87 | ||
83 | console.log("Adding to repository"); | 88 | console.log("[Info] Packaging your recipe"); |
84 | require('./package.js'); | 89 | try { |
85 | console.log("Continuing in 1.5 seconds"); | 90 | await packageRecipe(); |
91 | } catch(e) { | ||
92 | return; | ||
93 | } | ||
86 | 94 | ||
87 | setTimeout(async () => { | 95 | console.log("[Info] Deleting temporarydownloaded repository"); |
88 | console.log("Deleting downloaded files"); | ||
89 | 96 | ||
90 | await fs.remove(compressed); | 97 | await fs.remove(compressed); |
91 | await fs.remove(recipeSrc); | 98 | await fs.remove(recipeSrc); |
92 | 99 | ||
93 | console.log("Moving back recipe folder"); | 100 | console.log("[Info] Moving back 'recipe_src_tmp' to 'recipe_src'"); |
94 | 101 | ||
95 | await fs.move(recipeSrcTmp, recipeSrc); | 102 | await fs.move(recipeSrcTmp, recipeSrc); |
96 | }, 1500); | 103 | |
104 | console.log(`✅ Successfully packaged the recipe from your GitHub repository`); | ||
97 | })(); \ No newline at end of file | 105 | })(); \ No newline at end of file |
diff --git a/scripts/api/package.js b/scripts/api/package.js new file mode 100644 index 0000000..2d265f6 --- /dev/null +++ b/scripts/api/package.js | |||
@@ -0,0 +1,204 @@ | |||
1 | /** | ||
2 | * Package recipe into tar.gz file | ||
3 | */ | ||
4 | const targz = require('targz'); | ||
5 | const fs = require('fs-extra'); | ||
6 | const path = require('path'); | ||
7 | const sizeOf = require('image-size'); | ||
8 | const semver = require('semver'); | ||
9 | |||
10 | // Publicly availible link to this repository's uncompressed folder | ||
11 | // Used for generating public icon URLs | ||
12 | const repo = 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/'; | ||
13 | |||
14 | // Helper: Compress src folder into dest file | ||
15 | const compress = (src, dest) => new Promise((resolve, reject) => { | ||
16 | targz.compress({ | ||
17 | src, | ||
18 | dest, | ||
19 | tar: { | ||
20 | // Don't package .DS_Store files | ||
21 | ignore: function(name) { | ||
22 | return path.basename(name) === '.DS_Store' | ||
23 | } | ||
24 | }, | ||
25 | }, (err) => { | ||
26 | if (err) { | ||
27 | reject(err); | ||
28 | } else { | ||
29 | resolve(dest); | ||
30 | } | ||
31 | }); | ||
32 | }); | ||
33 | // Let us work in an async environment | ||
34 | module.exports = async () => { | ||
35 | // Create paths to important files | ||
36 | const recipeSrc = path.join(__dirname, '../recipe_src'); | ||
37 | const packageJson = path.join(recipeSrc, 'package.json'); | ||
38 | const svgIcon = path.join(recipeSrc, 'icon.svg'); | ||
39 | const pngIcon = path.join(recipeSrc, 'icon.png'); | ||
40 | const allJson = path.join(__dirname, '../../', 'all.json'); | ||
41 | let all = await fs.readJson(allJson); | ||
42 | |||
43 | // Check that package.json exists | ||
44 | if (!await fs.pathExists(packageJson)) { | ||
45 | console.log(`⚠️ Could not add your recipe: Please add your recipe to ${recipeSrc} and make sure that folder contains a "package.json". | ||
46 | For more information on how to add your recipe visit https://github.com/getferdi/recipes/blob/master/docs/integration.md`); | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | // Check that icons exist | ||
51 | const hasSvg = await fs.pathExists(svgIcon); | ||
52 | const hasPng = await fs.pathExists(pngIcon); | ||
53 | if (!hasSvg && !hasPng) { | ||
54 | console.log(`⚠️ Could not add your recipe: Please make sure your recipe contains an icon.png and an icon.svg file. | ||
55 | Those icons should be the logo of the recipe you are trying to add. | ||
56 | Please also make sure that your icons are 1024x1024px in size. | ||
57 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
58 | return; | ||
59 | } else if (!hasSvg) { | ||
60 | console.log(`⚠️ Could not add your recipe: Please make sure your recipe contains an icon.svg file. | ||
61 | Your recipe already contains an "icon.png" but it also requires an "icon.svg" to display properly. | ||
62 | Please also make sure that your icons are 1024x1024px in size. | ||
63 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
64 | return; | ||
65 | } else if (!hasPng) { | ||
66 | console.log(`⚠️ Could not add your recipe: Please make sure your recipe contains an icon.png file. | ||
67 | Your recipe already contains an "icon.svg" but it also requires an "icon.png" to display properly. | ||
68 | Please also make sure that your icons are 1024x1024px in size. | ||
69 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | // Check that icons have the right dimensions | ||
74 | const pngSize = sizeOf(pngIcon); | ||
75 | const pngHasRightSize = pngSize.width === 1024 && pngSize.height === 1024; | ||
76 | const svgSize = sizeOf(svgIcon); | ||
77 | const svgHasRightSize = svgSize.width === 1024 && svgSize.height === 1024; | ||
78 | if (!pngHasRightSize && !svgHasRightSize) { | ||
79 | console.log(`⚠️ Could not add your recipe: Icons require to be 1024x1024px in size. | ||
80 | Both your "icon.png" and "icon.svg" don't seem to have the right size. | ||
81 | You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
82 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
83 | return; | ||
84 | } else if (!pngHasRightSize) { | ||
85 | console.log(`⚠️ Could not add your recipe: "icon.png" should be to be 1024x1024px in size. | ||
86 | Please make sure that your "icon.png" has the right size of 1024x1024px in size. | ||
87 | You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
88 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
89 | return; | ||
90 | } else if (!svgHasRightSize) { | ||
91 | console.log(`⚠️ Could not add your recipe: "icon.svg" should be to be 1024x1024px in size. | ||
92 | Please make sure that your "icon.svg" has the right size of 1024x1024px in size. | ||
93 | You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
94 | For more information about recipe icons visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | // Read package.json | ||
99 | const config = await fs.readJson(packageJson) | ||
100 | |||
101 | // Make sure it contains all required fields | ||
102 | if (!config) { | ||
103 | console.log(`⚠️ Could not add your recipe: We could not read or parse your "package.json" configuration. | ||
104 | Please make sure your "package.json" contains valid JSON. | ||
105 | For more information about the package.json file visit https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
106 | return; | ||
107 | } | ||
108 | let configErrors = []; | ||
109 | if (!config.id) { | ||
110 | configErrors.push("Your package.json contains no 'id' field. This field should contain a unique ID made of lowercase letters (a-z) and hyphens (-)"); | ||
111 | } else if (!/^[a-z._\-]+$/.test(config.id)) { | ||
112 | configErrors.push("Your package.json defines an invalid recipe ID. Please make sure the 'id' field only contains lowercase letters (a-z) and hyphens (-)"); | ||
113 | } | ||
114 | if (!config.name) { | ||
115 | configErrors.push("Your package.json contains no 'name' field. This field should contain the name of the service (e.g. 'Google Keep')"); | ||
116 | } | ||
117 | if (!config.version) { | ||
118 | configErrors.push("Your package.json contains no 'version' field. This field should contain the a semver-compatible version number for your recipe (e.g. '1.0.0')"); | ||
119 | } | ||
120 | if (!config.config || typeof config.config !== "object") { | ||
121 | configErrors.push("Your package.json contains no 'config' object. This field should contain a configuration for your service."); | ||
122 | } else if (!config.config.serviceURL) { | ||
123 | configErrors.push("Your package.json contains a 'config' object with no 'serviceURL' field. This field should contain the URL of your service."); | ||
124 | } | ||
125 | |||
126 | if (configErrors.length > 0) { | ||
127 | console.log(`⚠️ Could not add your recipe: There were errors in your package.json: | ||
128 | ${configErrors.reduce((str, err) => `${str}\n${err}`)} | ||
129 | For more information about the package.json file visit https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | // Index of the current recipe in all.json | ||
134 | const packageIndex = all.findIndex(e => e.id === config.id) | ||
135 | |||
136 | if (packageIndex !== -1) { | ||
137 | const currentVersion = config.version; | ||
138 | const repoVersion = all[packageIndex].version; | ||
139 | |||
140 | if (semver.gte(repoVersion, currentVersion)) { | ||
141 | console.log(`⚠️ Could not add your recipe: It looks like your recipe is using the same version number as the current recipe. | ||
142 | Please make sure to increase the version number inside your "package.json" everytime you want to repackage (e.g. '1.0.0' to '1.0.1'). | ||
143 | If you don't increase your version number, Ferdi cannot detect that you have made changes to the recipe. | ||
144 | For more information about versioning of recipes visit https://github.com/getferdi/recipes/blob/master/docs/configuration.md#config-flags`); | ||
145 | return; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (!await fs.exists(path.join(recipeSrc, 'webview.js'))) { | ||
150 | console.log(`⚠️ Could not add your recipe: It looks like your recipe doesn't contain a "webview.js" file. | ||
151 | Please make sure to create that file and add your features to it. | ||
152 | For more information about the webview.js file visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#webviewjs and https://github.com/getferdi/recipes/blob/master/docs/frontend_api.md`); | ||
153 | return; | ||
154 | } | ||
155 | if (!await fs.exists(path.join(recipeSrc, 'index.js'))) { | ||
156 | console.log(`⚠️ Could not add your recipe: It looks like your recipe doesn't contain a "index.js" file. | ||
157 | Please make sure to create that file and add your features to it. For most recipes it is enough to simply add the basic template found at https://github.com/getferdi/recipes/blob/master/docs/integration.md#indexjs | ||
158 | For more information about the webview.js file visit https://github.com/getferdi/recipes/blob/master/docs/integration.md#indexjs and https://github.com/getferdi/recipes/blob/master/docs/backend_api.md`); | ||
159 | return; | ||
160 | } | ||
161 | |||
162 | // Package to .tar.gz | ||
163 | console.log(`[Info] Packaging ${config.id}...`); | ||
164 | compress(recipeSrc, path.join(__dirname, '../../', 'archives', `${config.id}.tar.gz`)); | ||
165 | |||
166 | // Copy recipe src folder to /uncompressed/:id folder | ||
167 | console.log('[Info] Copying to uncompressed recipes'); | ||
168 | await fs.copy('recipe_src', path.join(__dirname, '../../', 'uncompressed', `${config.id}`)); | ||
169 | |||
170 | // Add recipe to all.json | ||
171 | console.log('[Info] Adding to all.json'); | ||
172 | const packageInfo = { | ||
173 | "author": config.author || '', | ||
174 | "featured": false, | ||
175 | "id": config.id, | ||
176 | "name": config.name, | ||
177 | "version": config.version || '1.0.0', | ||
178 | "icons": { | ||
179 | "png": `${repo}${config.id}/icon.png`, | ||
180 | "svg": `${repo}${config.id}/icon.svg`, | ||
181 | }, | ||
182 | }; | ||
183 | // Check if package ID already exists | ||
184 | if (packageIndex !== -1) { | ||
185 | console.log('[Info] Recipe with ID already exists - overwriting'); | ||
186 | all[packageIndex] = packageInfo; | ||
187 | } else { | ||
188 | console.log('[Info] No recipe with ID found - creating new.'); | ||
189 | all.push(packageInfo); | ||
190 | } | ||
191 | |||
192 | // Sort package list alphabetically | ||
193 | all = all.sort((a, b) => { | ||
194 | var textA = a.id.toLowerCase(); | ||
195 | var textB = b.id.toLowerCase(); | ||
196 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; | ||
197 | }); | ||
198 | await fs.writeJson(allJson, all, { | ||
199 | spaces: 2, | ||
200 | EOL: '\n', | ||
201 | }); | ||
202 | |||
203 | console.log(`✅ Successfully packaged and added new recipe "${config.id}"`); | ||
204 | }; \ No newline at end of file | ||
diff --git a/scripts/package.js b/scripts/package.js index a241edc..3726407 100644 --- a/scripts/package.js +++ b/scripts/package.js | |||
@@ -1,108 +1,6 @@ | |||
1 | /** | 1 | /** |
2 | * Package recipe into tar.gz file | 2 | * Package recipe into tar.gz file |
3 | */ | 3 | */ |
4 | const targz = require('targz'); | 4 | const packageRecipe = require('./api/package'); |
5 | const fs = require('fs-extra'); | ||
6 | const path = require('path'); | ||
7 | 5 | ||
8 | console.log('Ferdi Recipe Packager v1.0.0'); | 6 | packageRecipe(); \ No newline at end of file |
9 | |||
10 | // Publicly availible link to this repository's uncompressed folder | ||
11 | // Used for generating public icon URLs | ||
12 | const repo = 'https://cdn.jsdelivr.net/gh/getferdi/recipes/uncompressed/'; | ||
13 | |||
14 | // Helper: Compress src folder into dest file | ||
15 | const compress = (src, dest) => new Promise((resolve, reject) => { | ||
16 | targz.compress({ | ||
17 | src, | ||
18 | dest, | ||
19 | tar: { | ||
20 | // Don't package .DS_Store files | ||
21 | ignore: function(name) { | ||
22 | return path.basename(name) === '.DS_Store' | ||
23 | } | ||
24 | }, | ||
25 | }, (err) => { | ||
26 | if (err) { | ||
27 | reject(err); | ||
28 | } else { | ||
29 | resolve(dest); | ||
30 | } | ||
31 | }); | ||
32 | }); | ||
33 | |||
34 | // Create paths to important files | ||
35 | const recipeSrc = path.join(__dirname, 'recipe_src'); | ||
36 | const packageJson = path.join(recipeSrc, 'package.json'); | ||
37 | const svgIcon = path.join(recipeSrc, 'icon.svg'); | ||
38 | const pngIcon = path.join(recipeSrc, 'icon.png'); | ||
39 | const allJson = path.join('../', 'all.json'); | ||
40 | |||
41 | // Let us work in an async environment | ||
42 | (async () => { | ||
43 | // Check that package.json exists | ||
44 | if (!await fs.pathExists(packageJson)) { | ||
45 | console.log(`Error: Please add your recipe to ${recipeSrc}. (package.json not found)`); | ||
46 | return; | ||
47 | } | ||
48 | // Check that icons exist | ||
49 | if (!await fs.pathExists(svgIcon) || !await fs.pathExists(pngIcon)) { | ||
50 | console.log(`Error: Please make sure your recipe contains an icon.png and an icon.svg file.`); | ||
51 | return; | ||
52 | } | ||
53 | |||
54 | // Read package.json | ||
55 | const config = await fs.readJson(packageJson) | ||
56 | |||
57 | // Make sure it contains all required fields | ||
58 | if (!config || !config.id || !config.name || !config.config) { | ||
59 | console.log(`Error: Your package.json does not contain all required fields. | ||
60 | Please make sure it contains: id, name, config`); | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | // Package to .tar.gz | ||
65 | console.log(`Packaging ${config.id}...`); | ||
66 | compress(recipeSrc, path.join('../', 'archives', `${config.id}.tar.gz`)); | ||
67 | |||
68 | // Copy recipe src folder to /uncompressed/:id folder | ||
69 | console.log('Copying to uncompressed recipes'); | ||
70 | await fs.copy('recipe_src', path.join('../', 'uncompressed', `${config.id}`)); | ||
71 | |||
72 | // Add recipe to all.json | ||
73 | console.log('Adding to all.json'); | ||
74 | const packageInfo = { | ||
75 | "author": config.author || '', | ||
76 | "featured": false, | ||
77 | "id": config.id, | ||
78 | "name": config.name, | ||
79 | "version": config.version || '1.0.0', | ||
80 | "icons": { | ||
81 | "png": `${repo}${config.id}/icon.png`, | ||
82 | "svg": `${repo}${config.id}/icon.svg`, | ||
83 | }, | ||
84 | }; | ||
85 | let all = await fs.readJson(allJson); | ||
86 | // Check if package ID already exists | ||
87 | const packageIndex = all.findIndex(e => e.id === config.id) | ||
88 | if (packageIndex !== -1) { | ||
89 | console.log('Package with ID already exists - overwriting'); | ||
90 | all[packageIndex] = packageInfo; | ||
91 | } else { | ||
92 | console.log('No package with ID found - creating new.'); | ||
93 | all.push(packageInfo); | ||
94 | } | ||
95 | |||
96 | // Sort package list alphabetically | ||
97 | all = all.sort((a, b) => { | ||
98 | var textA = a.id.toLowerCase(); | ||
99 | var textB = b.id.toLowerCase(); | ||
100 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; | ||
101 | }); | ||
102 | await fs.writeJson(allJson, all, { | ||
103 | spaces: 2, | ||
104 | EOL: '\n', | ||
105 | }); | ||
106 | |||
107 | console.log(`Successfully packaged and added new package ${config.id}`); | ||
108 | })(); \ No newline at end of file | ||
diff --git a/scripts/package.json b/scripts/package.json index b82f946..77d5f2f 100644 --- a/scripts/package.json +++ b/scripts/package.json | |||
@@ -10,6 +10,7 @@ | |||
10 | "dir-compare": "^1.7.3", | 10 | "dir-compare": "^1.7.3", |
11 | "fs-extra": "^8.1.0", | 11 | "fs-extra": "^8.1.0", |
12 | "git-url-parse": "^11.1.2", | 12 | "git-url-parse": "^11.1.2", |
13 | "image-size": "^0.8.3", | ||
13 | "node-fetch": "^2.6.0", | 14 | "node-fetch": "^2.6.0", |
14 | "semver": "^6.3.0", | 15 | "semver": "^6.3.0", |
15 | "targz": "^1.0.1" | 16 | "targz": "^1.0.1" |
diff --git a/scripts/yarn.lock b/scripts/yarn.lock index 5f3a5c8..8007f08 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock | |||
@@ -141,6 +141,13 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0: | |||
141 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" | 141 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" |
142 | integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= | 142 | integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= |
143 | 143 | ||
144 | image-size@^0.8.3: | ||
145 | version "0.8.3" | ||
146 | resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.8.3.tgz#f0b568857e034f29baffd37013587f2c0cad8b46" | ||
147 | integrity sha512-SMtq1AJ+aqHB45c3FsB4ERK0UCiA2d3H1uq8s+8T0Pf8A3W4teyBQyaFaktH6xvZqh+npwlKU7i4fJo0r7TYTg== | ||
148 | dependencies: | ||
149 | queue "6.0.1" | ||
150 | |||
144 | inherits@~2.0.3: | 151 | inherits@~2.0.3: |
145 | version "2.0.4" | 152 | version "2.0.4" |
146 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" | 153 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" |
@@ -237,6 +244,13 @@ pump@^1.0.0: | |||
237 | end-of-stream "^1.1.0" | 244 | end-of-stream "^1.1.0" |
238 | once "^1.3.1" | 245 | once "^1.3.1" |
239 | 246 | ||
247 | queue@6.0.1: | ||
248 | version "6.0.1" | ||
249 | resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.1.tgz#abd5a5b0376912f070a25729e0b6a7d565683791" | ||
250 | integrity sha512-AJBQabRCCNr9ANq8v77RJEv73DPbn55cdTb+Giq4X0AVnNVZvMHlYp7XlQiN+1npCZj1DuSmaA2hYVUUDgxFDg== | ||
251 | dependencies: | ||
252 | inherits "~2.0.3" | ||
253 | |||
240 | readable-stream@^2.3.0, readable-stream@^2.3.5: | 254 | readable-stream@^2.3.0, readable-stream@^2.3.5: |
241 | version "2.3.6" | 255 | version "2.3.6" |
242 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" | 256 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" |