diff options
author | MCMXC <16797721+mcmxcdev@users.noreply.github.com> | 2023-07-26 06:29:03 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-26 17:59:03 +0530 |
commit | 9b8f01716774a960073e944823ab727cc867a8f6 (patch) | |
tree | 732b83770baa78f5cf12776aaa33ce65bebfa418 /scripts | |
parent | Add Excalidraw recipe (#393) (diff) | |
download | ferdium-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.js | 31 | ||||
-rw-r--r-- | scripts/package.js | 44 | ||||
-rw-r--r-- | scripts/sample_recipe/webview.js | 4 |
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 | ||
20 | const recipeName = process.argv[2]; | 21 | const recipeName = process.argv[2]; |
21 | const recipe = recipeName.toLowerCase().replace(/\s/g, '-'); | 22 | const recipe = recipeName.toLowerCase().replaceAll(/\s/g, '-'); |
22 | const folderName = process.argv[3] || 'Ferdium'; | 23 | const folderName = process.argv[3] || 'Ferdium'; |
23 | const filesThatNeedTextReplace = [ | 24 | const filesThatNeedTextReplace = ['package.json', 'index.js', 'webview.js']; |
24 | 'package.json', | ||
25 | 'index.js', | ||
26 | 'webview.js', | ||
27 | ]; | ||
28 | 25 | ||
29 | const toPascalCase = (str) => { | 26 | const 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 | }; |
42 | const pascalCasedName = toPascalCase(recipe); // PascalCased recipe ID only containing a-z, for usage as the JavaScript class name | 39 | const 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'); | |||
6 | const path = require('path'); | 7 | const path = require('path'); |
7 | const sizeOf = require('image-size'); | 8 | const sizeOf = require('image-size'); |
8 | const simpleGit = require('simple-git'); | 9 | const simpleGit = require('simple-git'); |
9 | const pkgVersionChangedMatcher = new RegExp(/\n\+.*version.*/); | 10 | |
11 | const 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 @@ | |||
1 | const _path = _interopRequireDefault(require('path')); | ||
2 | |||
3 | function _interopRequireDefault(obj) { | 1 | function _interopRequireDefault(obj) { |
4 | return obj && obj.__esModule ? obj : { default: obj }; | 2 | return obj && obj.__esModule ? obj : { default: obj }; |
5 | } | 3 | } |
6 | 4 | ||
5 | const _path = _interopRequireDefault(require('path')); | ||
6 | |||
7 | module.exports = Ferdium => { | 7 | module.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 = () => { |