From 6338bff01c0dc6d3d45e46ea14a2288a7601a098 Mon Sep 17 00:00:00 2001 From: Sam Carlton Date: Fri, 27 Nov 2020 23:06:04 -0600 Subject: [PATCH 1/6] Install marked and node-html-parser --- package-lock.json | 26 ++++++++++++++++++++------ package.json | 2 ++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 189814a..fd18114 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1367,6 +1367,17 @@ "fs-extra": "^8.1.0", "html-minifier": "^4.0.0", "node-html-parser": "^1.3.1" + }, + "dependencies": { + "node-html-parser": { + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.9.tgz", + "integrity": "sha512-UVcirFD1Bn0O+TSmloHeHqZZCxHjvtIeGdVdGMhyZ8/PWlEiZaZ5iJzR189yKZr8p0FXN58BUeC7RHRkf/KYGw==", + "dev": true, + "requires": { + "he": "1.2.0" + } + } } }, "@nuxt/loading-screen": { @@ -6471,8 +6482,7 @@ "he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, "hex-color-regex": { "version": "1.1.0", @@ -7729,6 +7739,11 @@ "uc.micro": "^1.0.5" } }, + "marked": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/marked/-/marked-1.2.5.tgz", + "integrity": "sha512-2AlqgYnVPOc9WDyWu7S5DJaEZsfk6dNh/neatQ3IHUW4QLutM/VPSH9lG7bif+XjFWc9K9XR3QvR+fXuECmfdA==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -8139,10 +8154,9 @@ "dev": true }, "node-html-parser": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-1.4.3.tgz", - "integrity": "sha512-GXiLAg4ecY8CItLXXd2I8BqScBcIewhxO1erTEJ0A9K+r5HORAUkROZLxDokestkJYxt06t/IK84WaP0+6GyHA==", - "dev": true, + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-2.0.0.tgz", + "integrity": "sha512-3wJdYSxiVIBxuiFm9UtfNWAlBw2P+Vb/RN1nqf40q2JeZDpcJ1HsrWuWV3j15SSJ25TvfnOoac2Q+uDU9iY0sw==", "requires": { "he": "1.2.0" } diff --git a/package.json b/package.json index 120b55c..f5b2b11 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "axios": "^0.21.0", "cross-env": "^5.2.0", "markdown-it": "^11.0.1", + "marked": "^1.2.5", + "node-html-parser": "^2.0.0", "observe-element-in-viewport": "0.0.15", "scroll-into-view-if-needed": "^2.2.26", "slugify": "^1.4.5", From ec7a4eebff3a11463ef77b3dd7260a774a591788 Mon Sep 17 00:00:00 2001 From: Sam Carlton Date: Fri, 27 Nov 2020 23:07:46 -0600 Subject: [PATCH 2/6] Fetch formula status for homebrew --- .gitignore | 1 + helpers/build-homebrew-list.js | 174 +++++++++++++++++++++++++++++++++ helpers/get-list.js | 12 +++ nuxt.config.js | 23 +++-- pages/categories.vue | 11 +-- pages/formula/_slug.vue | 70 +++++++++++++ pages/kind/_slug.vue | 2 + 7 files changed, 273 insertions(+), 20 deletions(-) create mode 100644 helpers/build-homebrew-list.js create mode 100644 helpers/get-list.js create mode 100644 pages/formula/_slug.vue diff --git a/.gitignore b/.gitignore index 1eae457..b1acffc 100644 --- a/.gitignore +++ b/.gitignore @@ -85,5 +85,6 @@ dist /static/app-list.json /README-temp.md /static/game-list.json +/static/homebrew-list.json .DS_Store /commits-data.json diff --git a/helpers/build-homebrew-list.js b/helpers/build-homebrew-list.js new file mode 100644 index 0000000..b128480 --- /dev/null +++ b/helpers/build-homebrew-list.js @@ -0,0 +1,174 @@ + +// import { promises as fs } from 'fs' +// import MarkdownIt from 'markdown-it' +import slugify from 'slugify' +import axios from 'axios' + +// import statuses from './statuses' +// import parseGithubDate from './parse-github-date' + +const marked = require('marked') +const HTMLParser = require(`node-html-parser`) + + + +const statusesTranslations = { + + // brew install -s succeeds on Apple Silicon. The software works well enough natively. + '🥇': 'native', + + // The formula has been updated with depends_on :arch => [:x86_64, :build]. The software works well enough on Rosetta. + '🥈': 'rosetta', + + // The formula has known issues on macOS 11, though most features work. The issues are described in the Comments field. + '🥉': 'rosetta', + + // The formula has been updated with depends_on :arch => :x86_64. The software has been deemed to work on Intel only (for now). + '🚫': 'no', + + // The formula has been found to need more analysis/work. + '⚠️': 'no', + +} + +const statusesMessages = { + '🥇': '✅ Yes, Full Native Apple Silicon Support', + '🥈': '✳️ Yes, works via Rosetta 2', + '🥉': '⏹ Known issues on macOS 11, though most features work', + '⚠️': '⏹ No, not yet, support is still in progress', + '🚫': '🚫 No, not yet supported only works on Intel-based Macs' +} + +function getStatusText(formula) { + // Match status to Sheet Status + return statusesMessages[formula.status] +} + +function parseStatus(formulae) { + // Match status to Sheet Status + return statusesTranslations[formulae.status] +} + + +export default async function () { + + // Fetch Homebrew + const response = await axios.get(process.env.HOMEBREW_SOURCE) + + // Extract commit from response data + const issueMarkdown = response.data.data.repository.issue.body + + // Parse markdown + const issueHTML = marked(issueMarkdown) + + // Parse Markdown HTML into a dom + const dom = HTMLParser.parse(issueHTML) + + + // Map table Headings + // [ 'Formula', 'Works1on 11.0', 'Comments' ] + // const tableHeadings = dom.querySelectorAll('thead th').map(th => th.rawText) + + const headings = [ + 'fullName', + 'status', + 'comments' + ] + + // Map Formulae List within table + const tableRows = dom.querySelectorAll('table tr') + + // Remove the first row (Headings) + tableRows.shift() + + const tableRowData = tableRows.map( tr => { + + // Map Table Cells + + const cellsData = tr.querySelectorAll('td').map((td, i) => { + + const column = headings[i] + + if (td.childNodes.length === 0) return '' + + if (column === 'comments') return td.innerHTML + + return td.rawText + }) + + const formulaeRow = Object.fromEntries(cellsData.map( (cellData, i) => { + return [ headings[i], cellData ] + })) + + formulaeRow.name = formulaeRow.fullName.split(' ')[0] + + formulaeRow.links = tr.querySelectorAll('a').map( a => { + const href = a.getAttribute('href') + return { + href, + label: a.rawText, + // a + } + }) + + // if (formulaeRow.links.length !== 0) console.log('formulaeRow', formulaeRow.links) + + return formulaeRow + }) + + // console.log('dom', dom.length) + // console.log('issueHTML', issueHTML) + // console.log('formulaeWithStatus', formulaeWithStatus) + + + const formulaeList = [] + + + for (const formulae of tableRowData) { + + // If this formulae status is empty + // then skip this formulae + if (formulae.status.length === 0) continue + + // If this formulae emoji status is not in statusesTranslations + // then skip this formulae + if (!statusesTranslations.hasOwnProperty(formulae.status)) continue + + // Generate slug + const slug = formulae.name + + // slugify(formulae.name, { + // lower: true, + // strict: true + // }) + + formulaeList.push({ + name: formulae.name, + status: parseStatus(formulae), + url: `https://formulae.brew.sh/formula/${formulae.name}`, + text: getStatusText(formulae), + slug, + endpoint: `/formula/${slug}`, + section: { + label: 'Homebrew', + slug: 'homebrew' + }, + content: formulae.comments, + relatedLinks: [ + { + href: `https://formulae.brew.sh/formula/${formulae.name}`, + label: formulae.name, + // a + }, + ...formulae.links + ], + // reports: [ + // formulae + // ] + }) + } + + // console.log('formulaeList', formulaeList) + + return formulaeList +} diff --git a/helpers/get-list.js b/helpers/get-list.js new file mode 100644 index 0000000..b241cf4 --- /dev/null +++ b/helpers/get-list.js @@ -0,0 +1,12 @@ +import appList from '~/static/app-list.json' +import gameList from '~/static/game-list.json' +import homebrewList from '~/static/homebrew-list.json' + +import { byTimeThenNull } from '~/helpers/sort-list.js' + + +export const allList = [ + ...appList.sort(byTimeThenNull), + ...homebrewList, + ...gameList, +] diff --git a/nuxt.config.js b/nuxt.config.js index c8578e6..a410fd8 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -1,9 +1,10 @@ import { promises as fs } from 'fs' -import path from 'path' +// import path from 'path' import pkg from './package' import buildAppList from './helpers/build-app-list.js' import buildGamesList from './helpers/build-game-list.js' +import buildHomebrewList from './helpers/build-homebrew-list.js' const listsOptions = [ @@ -14,6 +15,10 @@ const listsOptions = [ { buildMethod: buildGamesList, path: '/static/game-list.json', + }, + { + buildMethod: buildHomebrewList, + path: '/static/homebrew-list.json', } ] @@ -91,21 +96,12 @@ export default { .then(( lists ) => { // console.log('appList', appList) - // const appRoutes = appList.map(app => ({ - // route: '/app/' + app.slug, - // // payload: appList - // })) - - // const gameRoutes = gameList.map(game => ({ - // route: '/game/' + game.slug, - // // payload: appList - // })) - const sectionList = [] const [ appRoutes, - gameRoutes + gameRoutes, + homebrewRoutes ] = lists.map((list, listI) => { return list.map( app => { // Find and store all sections @@ -117,6 +113,8 @@ export default { }) }) + // console.log('homebrewRoutes', homebrewRoutes) + const sectionRoutes = sectionList.map(slug => ({ route: '/kind/' + slug, // payload: appList @@ -125,6 +123,7 @@ export default { return [ ...appRoutes, ...gameRoutes, + ...homebrewRoutes, ...sectionRoutes ] }) diff --git a/pages/categories.vue b/pages/categories.vue index 822317c..4ff08ab 100644 --- a/pages/categories.vue +++ b/pages/categories.vue @@ -38,21 +38,16 @@ import Search from '~/components/search.vue' import LinkButton from '~/components/link-button.vue' -import { byTimeThenNull } from '~/helpers/sort-list.js' - // import appList from '~/static/app-list.json' // import gamelist from '~/static/game-list.json' export default { async asyncData () { - const { default: appList } = await import('~/static/app-list.json') - const { default: gamelist } = await import('~/static/game-list.json') + // const { default: appList } = await import('~/static/app-list.json') + // const { default: gamelist } = await import('~/static/game-list.json') - const allList = [ - ...appList.sort(byTimeThenNull), - ...gamelist, - ] + const { allList } = await import('~/helpers/get-list.js') const sectionList = {} diff --git a/pages/formula/_slug.vue b/pages/formula/_slug.vue new file mode 100644 index 0000000..0a5e40f --- /dev/null +++ b/pages/formula/_slug.vue @@ -0,0 +1,70 @@ + + + diff --git a/pages/kind/_slug.vue b/pages/kind/_slug.vue index c07fc95..7a66a04 100644 --- a/pages/kind/_slug.vue +++ b/pages/kind/_slug.vue @@ -45,9 +45,11 @@ import { byTimeThenNull } from '~/helpers/sort-list.js' import appList from '~/static/app-list.json' import gamelist from '~/static/game-list.json' +import homebrewList from '~/static/homebrew-list.json' const allList = [ ...appList.sort(byTimeThenNull), + ...homebrewList, ...gamelist, ] From 3702254b00051c3896280f0d5c8c341926d2f5d6 Mon Sep 17 00:00:00 2001 From: Sam Carlton Date: Fri, 27 Nov 2020 23:20:02 -0600 Subject: [PATCH 3/6] Enable initial search results to be limited --- components/search.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/components/search.vue b/components/search.vue index 0314579..1b7fafc 100644 --- a/components/search.vue +++ b/components/search.vue @@ -192,6 +192,10 @@ export default { type: Boolean, default: false }, + initialLimit: { + type: Number, + default: null + }, quickButtons: { type: Array, default: () => [ @@ -249,7 +253,9 @@ export default { }, computed: { results () { - if (!this.hasSearchInputText) return this.appList + if (!this.hasSearchInputText) { + return this.initialLimit !== null ? this.appList.slice(0, this.initialLimit) : this.appList + } return [ ...this.titleStartsWithResults, From 6a70d2e0bfe4dd4b48cc954433df24594dc6c95c Mon Sep 17 00:00:00 2001 From: Sam Carlton Date: Fri, 27 Nov 2020 23:21:24 -0600 Subject: [PATCH 4/6] Add Homebrew Formulae to index list --- pages/index.vue | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/pages/index.vue b/pages/index.vue index 1e14be7..36fc033 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -9,7 +9,8 @@ @@ -37,22 +38,17 @@ import Search from '~/components/search.vue' import LinkButton from '~/components/link-button.vue' -import { byTimeThenNull } from '~/helpers/sort-list.js' - -import appList from '~/static/app-list.json' -import gameList from '~/static/game-list.json' - -// console.log('appList.length', appList.length) -// console.log('gameList.length', gameList.length) - -const sortedAppList = appList.sort(byTimeThenNull) - -const mergedList = [ - ...sortedAppList, - ...gameList -] - export default { + async asyncData () { + // const { default: appList } = await import('~/static/app-list.json') + // const { default: gamelist } = await import('~/static/game-list.json') + + const { allList } = await import('~/helpers/get-list.js') + + return { + allList + } + }, components: { Search, LinkButton @@ -61,11 +57,6 @@ export default { return { query: '', } - }, - computed: { - appList() { - return mergedList - } } } From 497b8cde1041bb75e841bd8608bcc2697af47935 Mon Sep 17 00:00:00 2001 From: Sam Carlton Date: Fri, 27 Nov 2020 23:30:50 -0600 Subject: [PATCH 5/6] Add section icons --- components/search.vue | 4 ++-- helpers/build-app-list.js | 3 ++- helpers/build-game-list.js | 3 ++- helpers/build-homebrew-list.js | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components/search.vue b/components/search.vue index 1b7fafc..719b95d 100644 --- a/components/search.vue +++ b/components/search.vue @@ -76,7 +76,7 @@ style="transition-property: border;" >