diff options
Diffstat (limited to 'scripts/api/package.js')
-rw-r--r-- | scripts/api/package.js | 207 |
1 files changed, 0 insertions, 207 deletions
diff --git a/scripts/api/package.js b/scripts/api/package.js deleted file mode 100644 index c64132f..0000000 --- a/scripts/api/package.js +++ /dev/null | |||
@@ -1,207 +0,0 @@ | |||
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 | let errorMessages = [] | ||
44 | |||
45 | // Check that package.json exists | ||
46 | if (!await fs.pathExists(packageJson)) { | ||
47 | errorMessages.push(`⚠️ It looks like your recipe is missing the "package.json" file. | ||
48 | ↪ Please add your recipe to ${recipeSrc} and make sure that folder contains a "package.json". | ||
49 | ℹ For more information on how to add your recipe visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md`); | ||
50 | } | ||
51 | |||
52 | // Check that icons exist | ||
53 | const hasSvg = await fs.pathExists(svgIcon); | ||
54 | if (!hasSvg) { | ||
55 | errorMessages.push(`⚠️ It looks like your recipe is missing the "icon.svg" file. | ||
56 | ↪ Please make sure your recipe contains an icon.svg file. | ||
57 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
58 | } | ||
59 | |||
60 | const hasPng = await fs.pathExists(pngIcon); | ||
61 | if (!hasPng) { | ||
62 | errorMessages.push(`⚠️ It looks like your recipe is missing the "icon.png" file. | ||
63 | ↪ Please make sure your recipe contains an icon.png file. | ||
64 | ↪ Please also make sure that your PNG icon is 1024x1024px in size. | ||
65 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
66 | } | ||
67 | |||
68 | // Check that icons have the right dimensions | ||
69 | if (hasSvg) { | ||
70 | const svgSize = sizeOf(svgIcon); | ||
71 | const svgHasRightSize = svgSize.width === svgSize.height; | ||
72 | if (!svgHasRightSize) { | ||
73 | errorMessages.push(`⚠️ It looks like your "icon.svg" is not a square. | ||
74 | ↪ Please make sure that your "icon.svg" has the right dimensions to make a square- width and height should be the same. | ||
75 | ℹ You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
76 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if (hasPng) { | ||
81 | const pngSize = sizeOf(pngIcon); | ||
82 | const pngHasRightSize = pngSize.width === 1024 && pngSize.height === 1024; | ||
83 | if (hasPng && !pngHasRightSize) { | ||
84 | errorMessages.push(`⚠️ it looks like your "icon.png" is not 1024x1024 in size. | ||
85 | ↪ Please make sure that your "icon.png" has the right dimeensions of 1024x1024px. | ||
86 | ℹ You can use software like Photoshop, GIMP or Photopea (https://www.photopea.com/) to resize your icons. | ||
87 | ℹ For more information about recipe icons visit: https://github.com/getferdi/recipes/blob/master/docs/integration.md#icons`); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | // Read package.json | ||
92 | const config = await fs.readJson(packageJson) | ||
93 | |||
94 | // Make sure it contains all required fields | ||
95 | if (!config) { | ||
96 | errorMessages.push(`⚠️ It looks like your "package.json" file could not read or parsed. | ||
97 | ↪ Please make sure your "package.json" contains valid JSON. | ||
98 | ℹ You can use a JSON Validator like JSONLint: https://jsonlint.com/ | ||
99 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
100 | } | ||
101 | |||
102 | if (!config.id) { | ||
103 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain an "id" field. | ||
104 | ↪ Please make sure the "id" field contains a unique ID made of lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_) | ||
105 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
106 | } else if (!/^[a-z._\-]+$/.test(config.id)) { | ||
107 | errorMessages.push(`⚠️ It looks like your "package.json" defines an invalid recipe ID. | ||
108 | ↪ Please make sure the "id" field only contains lowercase letters (a-z), numbers (0-9), hyphens (-), periods (.), and underscores (_) | ||
109 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
110 | } | ||
111 | if (!config.name) { | ||
112 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "name" field. | ||
113 | ↪ Please make sure the "name" field contains the name of the service (e.g. "Google Keep") | ||
114 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
115 | } | ||
116 | if (!config.version) { | ||
117 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "version" field. | ||
118 | ↪ Please make sure the "version" field contains a semver-compatible version number for your recipe (e.g. "1.0.0") | ||
119 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
120 | } | ||
121 | if (!config.config || typeof config.config !== "object") { | ||
122 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "config" object. | ||
123 | ↪ Please make sure the "config" object contains a configuration for your service. | ||
124 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
125 | } else if (!config.config.serviceURL) { | ||
126 | errorMessages.push(`⚠️ It looks like your "package.json" does not contain a "config" object without a "serviceURL" field. | ||
127 | ↪ Please make sure the "serviceURL" contains the URL of your service. | ||
128 | ℹ For more information about the package.json file visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md`); | ||
129 | } | ||
130 | |||
131 | // Index of the current recipe in all.json | ||
132 | const packageIndex = all.findIndex(e => e.id === config.id) | ||
133 | |||
134 | if (packageIndex !== -1) { | ||
135 | const currentVersion = config.version; | ||
136 | const repoVersion = all[packageIndex].version; | ||
137 | |||
138 | if (semver.gte(repoVersion, currentVersion)) { | ||
139 | errorMessages.push(`⚠️ It looks like your recipe is using the same version number as the current recipe. | ||
140 | ↪ 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'). | ||
141 | ↪ If you don't increase your version number, Ferdi cannot detect that you have made changes to the recipe. | ||
142 | ℹ For more information about versioning of recipes visit: https://github.com/getferdi/recipes/blob/master/docs/configuration.md#config-flags`); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if (!await fs.exists(path.join(recipeSrc, 'webview.js'))) { | ||
147 | errorMessages.push(`⚠️ It looks like your recipe doesn't contain a "webview.js" file. | ||
148 | ↪ Please make sure to create that file and add your features to it. | ||
149 | ℹ 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`); | ||
150 | } | ||
151 | if (!await fs.exists(path.join(recipeSrc, 'index.js'))) { | ||
152 | errorMessages.push(`⚠️ It looks like your recipe doesn't contain a "index.js" file. | ||
153 | ↪ 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 | ||
154 | ℹ 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`); | ||
155 | } | ||
156 | |||
157 | if (errorMessages.length > 0) { | ||
158 | console.log(`❌ Could not add your recipe, the following ${errorMessages.length} error(s) were found: | ||
159 | ${errorMessages.reduce((str, err) => `${str}\n${err}`)} | ||
160 | ℹ For more information, visit: https://github.com/getferdi/recipes/tree/master/docs`); | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | // Package to .tar.gz | ||
165 | console.log(`[Info] Packaging ${config.id}...`); | ||
166 | compress(recipeSrc, path.join(__dirname, '../../', 'archives', `${config.id}.tar.gz`)); | ||
167 | |||
168 | // Copy recipe src folder to /uncompressed/:id folder | ||
169 | console.log('[Info] Copying to uncompressed recipes'); | ||
170 | await fs.copy('recipe_src', path.join(__dirname, '../../', 'uncompressed', `${config.id}`)); | ||
171 | |||
172 | // Add recipe to all.json | ||
173 | console.log('[Info] Adding to all.json'); | ||
174 | const isFeatured = packageIndex !== -1 ? all[packageIndex].featured : false; | ||
175 | const packageInfo = { | ||
176 | "author": config.author || '', | ||
177 | "featured": isFeatured, | ||
178 | "id": config.id, | ||
179 | "name": config.name, | ||
180 | "version": config.version || '1.0.0', | ||
181 | "icons": { | ||
182 | "png": `${repo}${config.id}/icon.png`, | ||
183 | "svg": `${repo}${config.id}/icon.svg`, | ||
184 | }, | ||
185 | }; | ||
186 | // Check if package ID already exists | ||
187 | if (packageIndex !== -1) { | ||
188 | console.log('[Info] Recipe with ID already exists - overwriting'); | ||
189 | all[packageIndex] = packageInfo; | ||
190 | } else { | ||
191 | console.log('[Info] No recipe with ID found - creating new.'); | ||
192 | all.push(packageInfo); | ||
193 | } | ||
194 | |||
195 | // Sort package list alphabetically | ||
196 | all = all.sort((a, b) => { | ||
197 | var textA = a.id.toLowerCase(); | ||
198 | var textB = b.id.toLowerCase(); | ||
199 | return (textA < textB) ? -1 : (textA > textB) ? 1 : 0; | ||
200 | }); | ||
201 | await fs.writeJson(allJson, all, { | ||
202 | spaces: 2, | ||
203 | EOL: '\n', | ||
204 | }); | ||
205 | |||
206 | console.log(`✅ Successfully packaged and added new recipe "${config.id}"`); | ||
207 | }; | ||