aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/package.js
diff options
context:
space:
mode:
authorLibravatar Bennett <hello@vantezzen.io>2020-09-22 20:56:48 +0200
committerLibravatar GitHub <noreply@github.com>2020-09-22 19:56:48 +0100
commit6f5e4a00588aefdda7a5a1cfe70935870e7e234a (patch)
tree9e29aa7aa0620a1a4a968ff8739b4b8ba96791a9 /scripts/package.js
parentUpdated logos for Outlook/OWA (diff)
downloadferdium-recipes-6f5e4a00588aefdda7a5a1cfe70935870e7e234a.tar.gz
ferdium-recipes-6f5e4a00588aefdda7a5a1cfe70935870e7e234a.tar.zst
ferdium-recipes-6f5e4a00588aefdda7a5a1cfe70935870e7e234a.zip
Unpack recipes and update recipes icons (#292)
Co-authored-by: Amine Mouafik <amine@mouafik.fr>
Diffstat (limited to 'scripts/package.js')
-rw-r--r--scripts/package.js177
1 files changed, 173 insertions, 4 deletions
diff --git a/scripts/package.js b/scripts/package.js
index d650121..82dfc81 100644
--- a/scripts/package.js
+++ b/scripts/package.js
@@ -1,8 +1,177 @@
1/** 1/**
2 * Package recipe into tar.gz file 2 * Package all recipes
3 */ 3 */
4require('./api/require-depts')(); 4const targz = require('targz');
5const fs = require('fs-extra');
6const path = require('path');
7const sizeOf = require('image-size');
5 8
6const packageRecipe = require('./api/package'); 9// Publicly availible link to this repository's recipe folder
10// Used for generating public icon URLs
11const repo = 'https://cdn.jsdelivr.net/gh/getferdi/recipes/recipes/';
7 12
8packageRecipe(); \ No newline at end of file 13// Helper: Compress src folder into dest file
14const compress = (src, dest) => new Promise((resolve, reject) => {
15 targz.compress({
16 src,
17 dest,
18 tar: {
19 // Don't package .DS_Store files
20 ignore: function(name) {
21 return path.basename(name) === '.DS_Store'
22 }
23 },
24 }, (err) => {
25 if (err) {
26 reject(err);
27 } else {
28 resolve(dest);
29 }
30 });
31});
32
33// Let us work in an async environment
34(async () => {
35 // Create paths to important files
36 const recipesFolder = path.join(__dirname, '../recipes');
37 const outputFolder = path.join(__dirname, '../archives');
38 const allJson = path.join(__dirname, '../all.json');
39 const featuredFile = path.join(__dirname, '../featured.json');
40 const featuredRecipes = await fs.readJSON(featuredFile);
41 let recipeList = [];
42 let unsuccessful = 0;
43
44 await fs.ensureDir(outputFolder);
45 await fs.emptyDir(outputFolder);
46 await fs.remove(allJson);
47
48 const availableRecipes = fs.readdirSync(recipesFolder, { withFileTypes: true })
49 .filter(dir => dir.isDirectory())
50 .map(dir => dir.name);
51
52 for(let recipe of availableRecipes) {
53 const recipeSrc = path.join(recipesFolder, recipe);
54 const packageJson = path.join(recipeSrc, 'package.json');
55 const svgIcon = path.join(recipeSrc, 'icon.svg');
56 const pngIcon = path.join(recipeSrc, 'icon.png');
57
58 // Check that package.json exists
59 if (!await fs.pathExists(packageJson)) {
60 console.log(`⚠️ Couldn't package "${recipe}": Folder doesn't contain a "package.json".`);
61 unsuccessful++;
62 continue;
63 }
64
65 // Check that icons exist
66 const hasSvg = await fs.pathExists(svgIcon);
67 const hasPng = await fs.pathExists(pngIcon);
68 if (!hasSvg && !hasPng) {
69 console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon SVG and PNG`);
70 unsuccessful++;
71 } else if (!hasSvg) {
72 console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon SVG`);
73 unsuccessful++;
74 continue;
75 } else if (!hasPng) {
76 console.log(`⚠️ Couldn't package "${recipe}": Recipe doesn't contain an icon PNG`);
77 unsuccessful++;
78 continue;
79 }
80
81 // Check icons sizes
82 const svgSize = sizeOf(svgIcon);
83 const svgHasRightSize = svgSize.width === svgSize.height;
84 if (!svgHasRightSize) {
85 console.log(`⚠️ Couldn't package "${recipe}": Recipe SVG icon isn't a square`);
86 unsuccessful++;
87 continue;
88 }
89
90 const pngSize = sizeOf(pngIcon);
91 const pngHasRightSize = pngSize.width === 1024 && pngSize.height === 1024;
92 if (!pngHasRightSize) {
93 console.log(`⚠️ Couldn't package "${recipe}": Recipe PNG icon dimensions should be 1024x1024`);
94 unsuccessful++;
95 continue;
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(`⚠️ Couldn't package "${recipe}": Could not read or parse "package.json"`);
104 unsuccessful++;
105 continue;
106 }
107 let configErrors = [];
108 if (!config.id) {
109 configErrors.push("The recipe's package.json contains no 'id' field. This field should contain a unique ID made of lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_)");
110 } else if (!/^[a-zA-Z0-9._\-]+$/.test(config.id)) {
111 configErrors.push("The recipe's package.json defines an invalid recipe ID. Please make sure the 'id' field only contains lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_)");
112 }
113 if (!config.name) {
114 configErrors.push("The recipe's package.json contains no 'name' field. This field should contain the name of the service (e.g. 'Google Keep')");
115 }
116 if (!config.version) {
117 configErrors.push("The recipe's package.json contains no 'version' field. This field should contain the a semver-compatible version number for your recipe (e.g. '1.0.0')");
118 }
119 if (!config.config || typeof config.config !== "object") {
120 configErrors.push("The recipe's package.json contains no 'config' object. This field should contain a configuration for your service.");
121 }
122
123 if (configErrors.length > 0) {
124 console.log(`⚠️ Couldn't package "${recipe}": There were errors in the recipe's package.json:
125 ${configErrors.reduce((str, err) => `${str}\n${err}`)}`);
126 unsuccessful++;
127 continue;
128 }
129
130 if (!await fs.exists(path.join(recipeSrc, 'webview.js'))) {
131 console.log(`⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "webview.js"`);
132 unsuccessful++;
133 continue;
134 }
135 if (!await fs.exists(path.join(recipeSrc, 'index.js'))) {
136 console.log(`⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "index.js"`);
137 unsuccessful++;
138 continue;
139 }
140
141 // Package to .tar.gz
142 compress(recipeSrc, path.join(outputFolder, `${config.id}.tar.gz`));
143
144 // Add recipe to all.json
145 const isFeatured = featuredRecipes.includes(config.id);
146 const packageInfo = {
147 "author": config.author || '',
148 "featured": isFeatured,
149 "id": config.id,
150 "name": config.name,
151 "version": config.version || '1.0.0',
152 "icons": {
153 "png": `${repo}${config.id}/icon.png`,
154 "svg": `${repo}${config.id}/icon.svg`,
155 },
156 };
157 recipeList.push(packageInfo);
158 }
159
160
161 // Sort package list alphabetically
162 recipeList = recipeList.sort((a, b) => {
163 var textA = a.id.toLowerCase();
164 var textB = b.id.toLowerCase();
165 return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
166 });
167 await fs.writeJson(allJson, recipeList, {
168 spaces: 2,
169 EOL: '\n',
170 });
171
172 console.log(`✅ Successfully packaged and added ${recipeList.length} recipes (${unsuccessful} unsuccessful recipes)`);
173
174 if (unsuccessful > 0) {
175 process.exit(1);
176 }
177})();