aboutsummaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
authorLibravatar MCMXC <16797721+mcmxcdev@users.noreply.github.com>2023-07-26 06:29:03 -0600
committerLibravatar GitHub <noreply@github.com>2023-07-26 17:59:03 +0530
commit9b8f01716774a960073e944823ab727cc867a8f6 (patch)
tree732b83770baa78f5cf12776aaa33ce65bebfa418 /scripts
parentAdd Excalidraw recipe (#393) (diff)
downloadferdium-recipes-9b8f01716774a960073e944823ab727cc867a8f6.tar.gz
ferdium-recipes-9b8f01716774a960073e944823ab727cc867a8f6.tar.zst
ferdium-recipes-9b8f01716774a960073e944823ab727cc867a8f6.zip
chore: improve lint setup (#397)
- update eslint config to closely mirror the ones from ferdium-app - add .eslintignore - opt in to eslint `reportUnusedDisableDirectives` config option - remove `trailingComma: all` from `prettier` config which is default in `prettier` v3 - autofix or disable a lot of lint issues throughout codebase - add `volta` configuration to `package.json` to autoload correct `node` and `pnpm` versions - upgrade all `eslint` and `prettier` related dependencies to latest - update lint:fix npm script - reformat touched files with prettier - bumped up minor version for all recipes that have changes - introduced injection of 'service.css' where it was missing in many recipes --------- Co-authored-by: Vijay A <vraravam@users.noreply.github.com>
Diffstat (limited to 'scripts')
-rw-r--r--scripts/create.js31
-rw-r--r--scripts/package.js44
-rw-r--r--scripts/sample_recipe/webview.js4
3 files changed, 41 insertions, 38 deletions
diff --git a/scripts/create.js b/scripts/create.js
index 199a23b..158b2f2 100644
--- a/scripts/create.js
+++ b/scripts/create.js
@@ -1,3 +1,4 @@
1/* eslint-disable no-console */
1/** 2/**
2 * Create a new recipe for your service 3 * Create a new recipe for your service
3 */ 4 */
@@ -18,19 +19,15 @@ pnpm create WhatsApp FerdiumDev
18} 19}
19 20
20const recipeName = process.argv[2]; 21const recipeName = process.argv[2];
21const recipe = recipeName.toLowerCase().replace(/\s/g, '-'); 22const recipe = recipeName.toLowerCase().replaceAll(/\s/g, '-');
22const folderName = process.argv[3] || 'Ferdium'; 23const folderName = process.argv[3] || 'Ferdium';
23const filesThatNeedTextReplace = [ 24const filesThatNeedTextReplace = ['package.json', 'index.js', 'webview.js'];
24 'package.json',
25 'index.js',
26 'webview.js',
27];
28 25
29const toPascalCase = (str) => { 26const toPascalCase = str => {
30 const words = str 27 const words = str
31 .replace(/[^a-z]/g, '') 28 .replaceAll(/[^a-z]/g, '')
32 .split(/\W/) 29 .split(/\W/)
33 .map((word) => { 30 .map(word => {
34 if (word.length === 0) { 31 if (word.length === 0) {
35 return word; 32 return word;
36 } 33 }
@@ -38,16 +35,16 @@ const toPascalCase = (str) => {
38 return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); 35 return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
39 }); 36 });
40 return words.join(''); 37 return words.join('');
41} 38};
42const pascalCasedName = toPascalCase(recipe); // PascalCased recipe ID only containing a-z, for usage as the JavaScript class name 39const pascalCasedName = toPascalCase(recipe); // PascalCased recipe ID only containing a-z, for usage as the JavaScript class name
43 40
44(async () => { 41(async () => {
45 // Folder paths 42 // Folder paths
46 const userData = 43 const userData =
47 process.env.APPDATA || 44 process.env.APPDATA ||
48 (process.platform == 'darwin' 45 (process.platform === 'darwin'
49 ? process.env.HOME + '/Library/Application Support' 46 ? `${process.env.HOME}/Library/Application Support`
50 : process.env.HOME + '/.config'); 47 : `${process.env.HOME}/.config`);
51 const recipesFolder = path.join(userData, folderName, 'recipes'); 48 const recipesFolder = path.join(userData, folderName, 'recipes');
52 const devRecipeFolder = path.join(recipesFolder, 'dev'); 49 const devRecipeFolder = path.join(recipesFolder, 'dev');
53 const newRecipeFolder = path.join(devRecipeFolder, recipe); 50 const newRecipeFolder = path.join(devRecipeFolder, recipe);
@@ -60,7 +57,7 @@ const pascalCasedName = toPascalCase(recipe); // PascalCased recipe ID only cont
60 ); 57 );
61 return; 58 return;
62 } 59 }
63 await fs.ensureDir(devRecipeFolder); 60 fs.ensureDirSync(devRecipeFolder);
64 61
65 if (fs.existsSync(newRecipeFolder)) { 62 if (fs.existsSync(newRecipeFolder)) {
66 console.log('⚠️ Recipe already exists'); 63 console.log('⚠️ Recipe already exists');
@@ -70,17 +67,17 @@ const pascalCasedName = toPascalCase(recipe); // PascalCased recipe ID only cont
70 console.log('[Info] Passed pre-checks'); 67 console.log('[Info] Passed pre-checks');
71 68
72 // Copy sample recipe to recipe folder 69 // Copy sample recipe to recipe folder
73 await fs.copy(sampleRecipe, newRecipeFolder); 70 fs.copySync(sampleRecipe, newRecipeFolder);
74 console.log('[Info] Copied recipe'); 71 console.log('[Info] Copied recipe');
75 72
76 // Replace placeholders with the recipe-specific values 73 // Replace placeholders with the recipe-specific values
77 for (const file of filesThatNeedTextReplace) { 74 for (const file of filesThatNeedTextReplace) {
78 const filePath = path.join(newRecipeFolder, file); 75 const filePath = path.join(newRecipeFolder, file);
79 let contents = await fs.readFile(filePath, 'utf8'); 76 let contents = fs.readFileSync(filePath, 'utf8');
80 contents = contents.replace(/SERVICE/g, recipe); 77 contents = contents.replace(/SERVICE/g, recipe);
81 contents = contents.replace(/SNAME/g, recipeName); 78 contents = contents.replace(/SNAME/g, recipeName);
82 contents = contents.replace(/SPASCAL/g, pascalCasedName); 79 contents = contents.replace(/SPASCAL/g, pascalCasedName);
83 await fs.writeFile(filePath, contents); 80 fs.writeFileSync(filePath, contents);
84 } 81 }
85 console.log('[Info] Prepared new recipe'); 82 console.log('[Info] Prepared new recipe');
86 83
diff --git a/scripts/package.js b/scripts/package.js
index e1e3d5c..0482775 100644
--- a/scripts/package.js
+++ b/scripts/package.js
@@ -1,3 +1,4 @@
1/* eslint-disable no-console */
1/** 2/**
2 * Package all recipes 3 * Package all recipes
3 */ 4 */
@@ -6,7 +7,8 @@ const fs = require('fs-extra');
6const path = require('path'); 7const path = require('path');
7const sizeOf = require('image-size'); 8const sizeOf = require('image-size');
8const simpleGit = require('simple-git'); 9const simpleGit = require('simple-git');
9const pkgVersionChangedMatcher = new RegExp(/\n\+.*version.*/); 10
11const pkgVersionChangedMatcher = /\n\+.*version.*/;
10 12
11// Publicly availible link to this repository's recipe folder 13// Publicly availible link to this repository's recipe folder
12// Used for generating public icon URLs 14// Used for generating public icon URLs
@@ -21,7 +23,7 @@ const compress = (src, dest) =>
21 dest, 23 dest,
22 tar: { 24 tar: {
23 // Don't package .DS_Store files and .md files 25 // Don't package .DS_Store files and .md files
24 ignore: function (name) { 26 ignore(name) {
25 return path.basename(name) === '.DS_Store' || name.endsWith('.md'); 27 return path.basename(name) === '.DS_Store' || name.endsWith('.md');
26 }, 28 },
27 }, 29 },
@@ -63,18 +65,19 @@ const compress = (src, dest) =>
63 .filter(dir => dir.isDirectory()) 65 .filter(dir => dir.isDirectory())
64 .map(dir => dir.name); 66 .map(dir => dir.name);
65 67
66 for (let recipe of availableRecipes) { 68 for (const recipe of availableRecipes) {
67 const recipeSrc = path.join(recipesFolder, recipe); 69 const recipeSrc = path.join(recipesFolder, recipe);
68 const mandatoryFiles = ['package.json', 'icon.svg', 'webview.js']; 70 const mandatoryFiles = ['package.json', 'icon.svg', 'webview.js'];
69 71
70 // Check that each mandatory file exists 72 // Check that each mandatory file exists
71 for (let file of mandatoryFiles) { 73 for (const file of mandatoryFiles) {
72 const filePath = path.join(recipeSrc, file); 74 const filePath = path.join(recipeSrc, file);
75 // eslint-disable-next-line no-await-in-loop
73 if (!(await fs.pathExists(filePath))) { 76 if (!(await fs.pathExists(filePath))) {
74 console.log( 77 console.log(
75 `⚠️ Couldn't package "${recipe}": Folder doesn't contain a "${file}".`, 78 `⚠️ Couldn't package "${recipe}": Folder doesn't contain a "${file}".`,
76 ); 79 );
77 unsuccessful++; 80 unsuccessful += 1;
78 } 81 }
79 } 82 }
80 if (unsuccessful > 0) { 83 if (unsuccessful > 0) {
@@ -89,22 +92,24 @@ const compress = (src, dest) =>
89 console.log( 92 console.log(
90 `⚠️ Couldn't package "${recipe}": Recipe SVG icon isn't a square`, 93 `⚠️ Couldn't package "${recipe}": Recipe SVG icon isn't a square`,
91 ); 94 );
92 unsuccessful++; 95 unsuccessful += 1;
93 continue; 96 continue;
94 } 97 }
95 98
96 // Check that user.js does not exist 99 // Check that user.js does not exist
97 const userJs = path.join(recipeSrc, 'user.js'); 100 const userJs = path.join(recipeSrc, 'user.js');
101 // eslint-disable-next-line no-await-in-loop
98 if (await fs.pathExists(userJs)) { 102 if (await fs.pathExists(userJs)) {
99 console.log( 103 console.log(
100 `⚠️ Couldn't package "${recipe}": Folder contains a "user.js".`, 104 `⚠️ Couldn't package "${recipe}": Folder contains a "user.js".`,
101 ); 105 );
102 unsuccessful++; 106 unsuccessful += 1;
103 continue; 107 continue;
104 } 108 }
105 109
106 // Read package.json 110 // Read package.json
107 const packageJson = path.join(recipeSrc, 'package.json'); 111 const packageJson = path.join(recipeSrc, 'package.json');
112 // eslint-disable-next-line no-await-in-loop
108 const config = await fs.readJson(packageJson); 113 const config = await fs.readJson(packageJson);
109 114
110 // Make sure it contains all required fields 115 // Make sure it contains all required fields
@@ -112,10 +117,10 @@ const compress = (src, dest) =>
112 console.log( 117 console.log(
113 `⚠️ Couldn't package "${recipe}": Could not read or parse "package.json"`, 118 `⚠️ Couldn't package "${recipe}": Could not read or parse "package.json"`,
114 ); 119 );
115 unsuccessful++; 120 unsuccessful += 1;
116 continue; 121 continue;
117 } 122 }
118 let configErrors = []; 123 const configErrors = [];
119 if (!config.id) { 124 if (!config.id) {
120 configErrors.push( 125 configErrors.push(
121 "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 (_)", 126 "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 (_)",
@@ -227,6 +232,7 @@ const compress = (src, dest) =>
227 const relativeRepoSrc = path.relative(repoRoot, recipeSrc); 232 const relativeRepoSrc = path.relative(repoRoot, recipeSrc);
228 233
229 // Check for changes in recipe's directory, and if changes are present, then the changes should contain a version bump 234 // Check for changes in recipe's directory, and if changes are present, then the changes should contain a version bump
235 // eslint-disable-next-line no-await-in-loop
230 await git.diffSummary(relativeRepoSrc, (err, result) => { 236 await git.diffSummary(relativeRepoSrc, (err, result) => {
231 if (err) { 237 if (err) {
232 configErrors.push( 238 configErrors.push(
@@ -239,11 +245,7 @@ const compress = (src, dest) =>
239 result.deletions !== 0) 245 result.deletions !== 0)
240 ) { 246 ) {
241 const pkgJsonRelative = path.relative(repoRoot, packageJson); 247 const pkgJsonRelative = path.relative(repoRoot, packageJson);
242 if (!result.files.some(({ file }) => file === pkgJsonRelative)) { 248 if (result.files.some(({ file }) => file === pkgJsonRelative)) {
243 configErrors.push(
244 `Found changes in '${relativeRepoSrc}' without the corresponding version bump in '${pkgJsonRelative}'`,
245 );
246 } else {
247 git.diff(pkgJsonRelative, (_diffErr, diffResult) => { 249 git.diff(pkgJsonRelative, (_diffErr, diffResult) => {
248 if (diffResult && !pkgVersionChangedMatcher.test(diffResult)) { 250 if (diffResult && !pkgVersionChangedMatcher.test(diffResult)) {
249 configErrors.push( 251 configErrors.push(
@@ -251,6 +253,10 @@ const compress = (src, dest) =>
251 ); 253 );
252 } 254 }
253 }); 255 });
256 } else {
257 configErrors.push(
258 `Found changes in '${relativeRepoSrc}' without the corresponding version bump in '${pkgJsonRelative}'`,
259 );
254 } 260 }
255 } 261 }
256 }); 262 });
@@ -259,14 +265,14 @@ const compress = (src, dest) =>
259 if (configErrors.length > 0) { 265 if (configErrors.length > 0) {
260 console.log(`⚠️ Couldn't package "${recipe}": There were errors in the recipe's package.json: 266 console.log(`⚠️ Couldn't package "${recipe}": There were errors in the recipe's package.json:
261 ${configErrors.reduce((str, err) => `${str}\n${err}`)}`); 267 ${configErrors.reduce((str, err) => `${str}\n${err}`)}`);
262 unsuccessful++; 268 unsuccessful += 1;
263 } 269 }
264 270
265 if (!fs.existsSync(path.join(recipeSrc, 'index.js'))) { 271 if (!fs.existsSync(path.join(recipeSrc, 'index.js'))) {
266 console.log( 272 console.log(
267 `⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "index.js"`, 273 `⚠️ Couldn't package "${recipe}": The recipe doesn't contain a "index.js"`,
268 ); 274 );
269 unsuccessful++; 275 unsuccessful += 1;
270 } 276 }
271 277
272 // Package to .tar.gz 278 // Package to .tar.gz
@@ -289,9 +295,9 @@ const compress = (src, dest) =>
289 295
290 // Sort package list alphabetically 296 // Sort package list alphabetically
291 recipeList = recipeList.sort((a, b) => { 297 recipeList = recipeList.sort((a, b) => {
292 let textA = a.id.toLowerCase(); 298 const textA = a.id.toLowerCase();
293 let textB = b.id.toLowerCase(); 299 const textB = b.id.toLowerCase();
294 return textA < textB ? -1 : (textA > textB ? 1 : 0); 300 return textA < textB ? -1 : textA > textB ? 1 : 0;
295 }); 301 });
296 await fs.writeJson(allJson, recipeList, { 302 await fs.writeJson(allJson, recipeList, {
297 spaces: 2, 303 spaces: 2,
diff --git a/scripts/sample_recipe/webview.js b/scripts/sample_recipe/webview.js
index 86bb422..2a81dec 100644
--- a/scripts/sample_recipe/webview.js
+++ b/scripts/sample_recipe/webview.js
@@ -1,9 +1,9 @@
1const _path = _interopRequireDefault(require('path'));
2
3function _interopRequireDefault(obj) { 1function _interopRequireDefault(obj) {
4 return obj && obj.__esModule ? obj : { default: obj }; 2 return obj && obj.__esModule ? obj : { default: obj };
5} 3}
6 4
5const _path = _interopRequireDefault(require('path'));
6
7module.exports = Ferdium => { 7module.exports = Ferdium => {
8 // TODO: If your SNAME service has unread messages, uncomment these lines to implement the logic for updating the badges 8 // TODO: If your SNAME service has unread messages, uncomment these lines to implement the logic for updating the badges
9 // const getMessages = () => { 9 // const getMessages = () => {