From 26fcdc97832e28bf5b42db344aa6b4751c858372 Mon Sep 17 00:00:00 2001 From: Rasmus Gustafsson Date: Sat, 27 Jul 2024 15:04:25 +0300 Subject: [PATCH] docs: update README usage examples --- README.md | 149 +++++++++++++++++++++++++++++-------------------- package.json | 1 + pnpm-lock.yaml | 52 +++++++++++++++++ 3 files changed, 142 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 3e4d900..a8e5423 100644 --- a/README.md +++ b/README.md @@ -18,72 +18,101 @@ Inspired by Vercel's [Error design framework](https://vercel.com/design/error#er ## Features -- Create consistent, human-friendly logs throughout your application or library -- Build versatile errors like lego-blocks -- Support for parameters +- Create consistent, helpful logs that help users fix the problem themselves +- Build versatile errors by connecting events, explanations and solutions +- Support for parameters: template variables into the log messages +- Only 193 lines of code ## 💻 Example Usage +We start by defining our `events`, `explanations`, and `solutions`. These will later be used in logs to create user-friendly errors, guiding the users to the right solution. + ```typescript -export const apiLogs = createHumanLogs({ - events: { - project_create_failed: 'Cannot create your project', - team_create_failed: 'Cannot create your team', - }, - explanations: { - api_unreachable: 'because the API cannot be reached.', - team_exists: { - template: 'because a team with ID "{teamId}" already exists.', - params: { - teamId: '' - } - } - }, - solutions: { - check_status_page: { - template: 'You can check the status of our services on our status page.', - params: {}, - actions: [ - { - text: 'Go to status page', - href: 'https://skosh.dev' - } - ] - } - } -}) - -// You can now use `apiLogs` to create user-friendly error logs, by connecting events, explanations and solutions like lego-blocks. -const log = apiLogs({ - event: ['project_create_failed'], - explanation: ['api_unreachable'], - solution: ['check_status_page'] -}) - -console.log(log.message) -// => Cannot create your project because the API cannot be reached. You can check the status of our services on our status page. - -console.log(log.actions) -/* => [{ - text: 'Go to status page', - href: 'https://status.foobar.inc' - }]*/ - -console.log(log.toString()) -// => Cannot create your project because the API cannot be reached. You can check the status of our services on our status page. Go to status page (https://status.foobar.inc) - -// Example with parameters -const logWithParams = apiLogs({ - event: ['team_create_failed'], - explanation: ['team_exists'], - params: { - teamId: 'winning-team' - } -}) -console.log(logWithParams.message) -// => Cannot create your team because a team with ID "winning-team" already exists. +import { createHumanLogs, event, explanation, solution, createTextFormatter } from "human-logs" + +export const notionError = createHumanLogs( + [ + event("fetching_posts_failed", "fetching posts failed", { + params: {}, + }), + explanation( + "missing_params", + "the {paramType} `{paramName}` is missing for post with ID `{postId}`, and no fallback was provided", + { + params: { + paramType: "", + paramName: "", + postId: "", + }, + } + ), + explanation( + "unsupported_blocktype", + "unsupported block type `{blockType}` is is included in this page", + { + params: { + blockType: "", + }, + } + ), + solution( + "add_missing_param", + "add the missing {paramType} on your Notion page", + { + params: {}, + } + ), + solution( + "provide_fallback", + "add a fallback to your parameter definition like this:\n\nurl(`{paramName}`, { fallback: `https://useflytrap.com` })", + { + params: { + paramName: "", + }, + } + ), + solution("open_issue", "open an issue for this on GitHub", { + params: {}, + actions: [ + { + text: "Open an issue", + href: "https://github.com/useflytrap/notion-contentlayer/issues/new", + }, + ], + }), + ], + { + formatter: createTextFormatter({ + eventsPrefix: "🚧 ", + solutionsPrefix: "🛠️ ", + }), + } +) + +// You can now use `notionError` to create user-friendly error logs, by connecting events, explanations and solutions like lego-blocks. +const errorLog = notionError([ + "fetching_posts_failed", + "missing_params", + "add_missing_param", + "add_skip_missing_fields", +], { + // 👇 these are inferred like magic! + paramName: 'image', + paramType: 'Image', + postId: 'abcd-123', +}); + +console.log(errorLog.toString()) +/* => "🚧 Fetching posts failed because the Image `image` is missing for post with ID `abcd-123`, and no fallback was provided. + +🛠️ Solutions: +1) add the missing Image on your Notion page +2) if you want to skip posts that have missing fields, add `skipMissingFields`: true to your `fetchPosts` call like this: `notionSource.fetchPosts({ skipMissingFields: true })`" +*/ ``` +Wow! Look at how helpful those errors are. These are errors developers, product end-users and everyone in between could only DREAM OF. + ## 💻 Development - Clone this repository diff --git a/package.json b/package.json index 5b9f299..509a5b3 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "devDependencies": { "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.2.1", "prettier": "^3.3.3", "typescript": "5", "typescript-eslint": "^7.17.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d14602e..e71a335 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ devDependencies: eslint-config-prettier: specifier: ^9.1.0 version: 9.1.0(eslint@8.57.0) + eslint-plugin-prettier: + specifier: ^5.2.1 + version: 5.2.1(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.3.3) prettier: specifier: ^3.3.3 version: 3.3.3 @@ -970,6 +973,11 @@ packages: fastq: 1.17.1 dev: true + /@pkgr/core@0.1.1: + resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + dev: true + /@rollup/plugin-alias@5.1.0(rollup@3.29.4): resolution: {integrity: sha512-lpA3RZ9PdIG7qqhEfv79tBffNaoDuukFDrmhLqg9ifv99u/ehn+lOg30x2zmhf8AQqQUZaMk/B9fZraQ6/acDQ==} engines: {node: '>=14.0.0'} @@ -1935,6 +1943,27 @@ packages: eslint: 8.57.0 dev: true + /eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0)(eslint@8.57.0)(prettier@3.3.3): + resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '*' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.57.0 + eslint-config-prettier: 9.1.0(eslint@8.57.0) + prettier: 3.3.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.9.1 + dev: true + /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2057,6 +2086,10 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -2996,6 +3029,13 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.3.0 + dev: true + /prettier@3.3.3: resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} @@ -3218,6 +3258,14 @@ packages: picocolors: 1.0.1 dev: true + /synckit@0.9.1: + resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} + engines: {node: ^14.18.0 || >=16.0.0} + dependencies: + '@pkgr/core': 0.1.1 + tslib: 2.6.3 + dev: true + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -3262,6 +3310,10 @@ packages: typescript: 5.5.4 dev: true + /tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + dev: true + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'}