├── vercel.json
├── playwright
├── README.md
├── .eslintrc.js
└── ui
│ └── landingPages.play.js
├── static
└── img
│ ├── favicon.ico
│ ├── typescript-error.png
│ ├── relay-new-devtools.png
│ ├── graphql-response-overfetching.png
│ ├── undraw_docusaurus_tree.svg
│ └── logo.svg
├── til
├── 2019-07-18-a-b-vs-ancestry-path.md
├── 2019-01-25-git-changes-last-week.md
├── 2019-02-28-does-it-mutate.md
├── 2022-04-03-list-of-all-packages-installed-using-homebrew.md
├── 2019-07-29-4b825dc642cb6eb9a060e54bf8d69288fbee4904.md
├── 2019-04-17-sleep-sort.md
├── 2021-02-01-asserting-a-specific-enum-variant.md
├── 2019-09-18-beyond-console-log.md
├── 2019-01-28-is-object.md
├── 2019-11-06-flow-spreads-dont-preserve-read-only-ness.md
├── 2019-01-10-clearing-resetting-restoring-jest-mocks.md
├── 2019-09-30-rem-units.md
├── 2021-07-04-high-color-contrast-via-css.md
├── 2019-08-19-nodejs-lts-or-not.md
├── 2019-03-29-yarn-comments-in-package-json.md
├── 2019-06-24-optional-chaining-gotchas.md
├── 2019-07-09-splitting-string.md
├── 2019-12-30-responsive-component-with-hooks.md
├── 2022-02-16-new-relay-flow-type-names.md
├── 2020-01-31-graphql-rate-limiting-cost-computation.md
├── 2022-02-23-macos-monterey-blocking-port-5000.md
├── 2018-12-14-getters-can-be-dangerous.md
├── 2022-03-06-math-imul.md
├── 2022-02-15-using-dev-constant-in-rescript.md
├── 2019-09-30-computing-average-in-a-constant-time.md
├── 2020-07-21-strictequals-without-equals-operators.md
├── 2019-08-19-gitignore.md
├── 2019-05-22-v8-built-in-functions.md
├── 2020-02-10-css-selectors.md
├── 2019-09-26-understanding-git-diff.md
├── 2019-09-30-identify-css-layout-inconsistencies.md
├── 2019-09-26-object-preventextensions-seal-freeze.md
├── 2019-01-28-is-this-thing-a-number.md
├── 2019-09-26-placement-of-catch-before-and-after-then.md
└── 2022-03-12-turbofish.md
├── babel.config.js
├── .eslintrc.js
├── .gitignore
├── README.md
├── src
├── pages
│ ├── index.js
│ └── styles.module.css
└── css
│ └── custom.css
├── package.json
├── playwright.config.js
├── sidebars.js
├── Dockerfile
├── docs
├── relay
│ ├── match-module.md
│ ├── uploadables.md
│ └── local-schema.md
├── flow
│ ├── patterns
│ │ └── exhaustive-checking.md
│ ├── configuration.md
│ ├── unsealed-objects.md
│ ├── shenanigans.md
│ ├── debugging.md
│ └── saved-state.md
├── git.md
├── rust.md
├── graphql.md
├── relay.md
└── flow.md
├── til-articles
├── 2019-10-14-flow-react-restricted-element.md
├── 2020-12-28-understanding-rust-modules.md
└── 2019-10-14-flow-new-spread-model.md
└── docusaurus.config.js
/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "github": {
3 | "silent": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/playwright/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | yarn workspace mrtnzlml-meta playwright test
3 | ```
4 |
--------------------------------------------------------------------------------
/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrtnzlml/meta/HEAD/static/img/favicon.ico
--------------------------------------------------------------------------------
/static/img/typescript-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrtnzlml/meta/HEAD/static/img/typescript-error.png
--------------------------------------------------------------------------------
/static/img/relay-new-devtools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrtnzlml/meta/HEAD/static/img/relay-new-devtools.png
--------------------------------------------------------------------------------
/static/img/graphql-response-overfetching.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mrtnzlml/meta/HEAD/static/img/graphql-response-overfetching.png
--------------------------------------------------------------------------------
/til/2019-07-18-a-b-vs-ancestry-path.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'A..B vs A...B vs --ancestry-path'
3 | tags: ['git']
4 | ---
5 |
6 | See: https://stackoverflow.com/a/36437843
7 |
--------------------------------------------------------------------------------
/til/2019-01-25-git-changes-last-week.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Git: What happened in last week?'
3 | tags: ['git']
4 | ---
5 |
6 | ```bash
7 | git log --since=1.week --oneline --no-merges
8 | ```
9 |
--------------------------------------------------------------------------------
/til/2019-02-28-does-it-mutate.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Does it mutate?
3 | tags: ['javascript']
4 | ---
5 |
6 | Which JavaScript functions mutate and which don't?
7 |
8 | - https://doesitmutate.xyz/
9 | - https://stackoverflow.com/a/9009934/3135248
10 |
--------------------------------------------------------------------------------
/til/2022-04-03-list-of-all-packages-installed-using-homebrew.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: List of all packages installed using Homebrew
3 | ---
4 |
5 | ```text
6 | brew leaves | xargs -n1 brew desc
7 | ```
8 |
9 | Source: https://apple.stackexchange.com/a/154750/436493
10 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable ft-flow/require-valid-file-annotation */
2 |
3 | module.exports = function (api) {
4 | api.assertVersion(7);
5 | api.cache(true);
6 |
7 | return {
8 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
9 | };
10 | };
11 |
--------------------------------------------------------------------------------
/til/2019-07-29-4b825dc642cb6eb9a060e54bf8d69288fbee4904.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
3 | ---
4 |
5 | ```
6 | 4b825dc642cb6eb9a060e54bf8d69288fbee4904
7 | ```
8 |
9 | This hash exists in every Git repository: https://stackoverflow.com/q/9765453/3135248
10 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @flow strict
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'hermes-eslint',
6 | env: {
7 | node: true,
8 | },
9 | extends: [
10 | '@adeira/eslint-config/base',
11 | '@adeira/eslint-config/flowtype',
12 | '@adeira/eslint-config/react',
13 | ],
14 | };
15 |
--------------------------------------------------------------------------------
/til/2019-04-17-sleep-sort.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sleep sort in JavaScript
3 | tags: ['javascript']
4 | ---
5 |
6 | 🤪 🤨 🙃
7 |
8 | ```js
9 | [3, 5, 1, 8, 2, 4, 9, 6, 7].forEach((num) => {
10 | setTimeout(() => console.log(num), num);
11 | });
12 | ```
13 |
14 | https://twitter.com/JavaScriptDaily/status/856267407106682880
15 |
--------------------------------------------------------------------------------
/playwright/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // @flow strict
2 |
3 | /* eslint-disable no-unused-vars */
4 | const OFF = 0;
5 | const WARN = 1;
6 | const ERROR = 2;
7 | /* eslint-enable no-unused-vars */
8 |
9 | module.exports = {
10 | rules: {
11 | // Jest rules incompatible with Playwright:
12 | 'jest/no-disabled-tests': OFF,
13 | 'jest/no-standalone-expect': OFF,
14 | 'jest/valid-title': OFF,
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/til/2021-02-01-asserting-a-specific-enum-variant.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'Asserting a specific enum variant'
3 | tags: ['rust']
4 | ---
5 |
6 | Specifically, asserting that result is a specific variant of an enum of structs when we don't care about the fields (something like "is instance of"):
7 |
8 | ```rust
9 | assert!(matches!(return_with_fields(), MyEnum::WithFields { .. }));
10 | ```
11 |
12 | Source: https://stackoverflow.com/a/51123901/3135248
13 |
--------------------------------------------------------------------------------
/til/2019-09-18-beyond-console-log.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Beyond console.log()
3 | tags: ['javascript']
4 | ---
5 |
6 | There is more than just a simple `console.log`: https://medium.com/@mattburgess/beyond-console-log-2400fdf4a9d8
7 |
8 | - `console.log/warn/error/info` with `%s`, `%o` and `%c`
9 | - `console.dir`
10 | - `console.table`
11 | - `console.assert`
12 | - `console.count/countReset`
13 | - `console.trace`
14 | - `console.time/timeEnd`
15 | - `console.group/groupCollapsed/groupEnd`
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | /node_modules
3 |
4 | # production
5 | /build
6 |
7 | # generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # misc
12 | .DS_Store
13 | .idea
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | # Yarn Berry (without Zero-installs)
24 | .pnp.*
25 | .yarn/*
26 | !.yarn/patches
27 | !.yarn/plugins
28 | !.yarn/releases
29 | !.yarn/sdks
30 | !.yarn/versions
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Hi! 👋 I am Martin Zlámal and this is where I store my knowledge: https://mrtnzlml.com/
2 |
3 | ## Contributing
4 |
5 | Do you want to improve this website? This is how you install it:
6 |
7 | ```text
8 | git clone git@github.com:mrtnzlml/meta.git
9 | cd meta
10 | yarn install
11 | yarn start
12 | ```
13 |
14 | Now, make some changes and send a [pull request](https://help.github.com/en/articles/about-pull-requests). That's it. :)
15 |
16 | 
17 |
--------------------------------------------------------------------------------
/til/2019-01-28-is-object.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: isObject()
3 | tags: ['javascript']
4 | ---
5 |
6 | ```js
7 | function isObject(value): boolean %checks {
8 | return typeof value === 'object' && value !== null && !Array.isArray(value);
9 | }
10 | ```
11 |
12 | Jest [implementation](https://github.com/facebook/jest/blob/d7ca8b23acf2fdd1d070496efb2b2709644a6f4f/packages/jest-snapshot/src/utils.js#L79-L81):
13 |
14 | ```js
15 | function isObject(item) {
16 | return item && typeof item === 'object' && !Array.isArray(item);
17 | }
18 | ```
19 |
--------------------------------------------------------------------------------
/til/2019-11-06-flow-spreads-dont-preserve-read-only-ness.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Flow: spreads don't preserve read-only-ness"
3 | tags: ['javascript', 'flow']
4 | ---
5 |
6 | ```js
7 | type A = {| +readOnlyKey: string |};
8 | type B = {| ...A, +otherKey: string |};
9 |
10 | function test(x: B) {
11 | x.readOnlyKey = 'overwrite'; // no error ?
12 | x.otherKey = 'overwrite'; // no error ??
13 | }
14 | ```
15 |
16 | This applies to value spreads as well since they are creating a new object. It's less understandable for these type spreads where value spread is not involved.
17 |
--------------------------------------------------------------------------------
/til/2019-01-10-clearing-resetting-restoring-jest-mocks.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Clearing/resetting/restoring Jest mocks
3 | tags: ['javascript', 'jest']
4 | ---
5 |
6 | I am never gonna remember this correctly I guess. 🤷
7 |
8 | - `jest.clearAllMocks()` only clears the internal state of the mock
9 | - `jest.resetAllMocks()` does the same + it removes any mocked implementations or return values
10 | - `jest.restoreAllMocks()` does everything above but it restores the original non-mocked implementation (and works only with `jest.spyOn`)
11 |
12 | https://github.com/facebook/jest/issues/5143
13 |
--------------------------------------------------------------------------------
/til/2019-09-30-rem-units.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: REM units
3 | tags: ['css']
4 | ---
5 |
6 | ```css
7 | html {
8 | font-size: 6.25%; /* =1px */
9 | /* Since most browsers have a default value of 16px. Alternatively, people quite often
10 | use 62.5% instead and adjust children REM units accordingly. */
11 | }
12 | body {
13 | font-size: 14rem; /* =14px */
14 | }
15 | h1 {
16 | font-size: 24rem; /* =24px */
17 | }
18 | ```
19 |
20 | Default HTML font size: https://stackoverflow.com/questions/24542508/default-html-font-size
21 |
22 | Even better approach: https://css-tricks.com/rems-ems/
23 |
--------------------------------------------------------------------------------
/til/2021-07-04-high-color-contrast-via-css.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: High color contrast via CSS
3 | tags: ['css']
4 | ---
5 |
6 | See: https://css-tricks.com/css-variables-calc-rgb-enforcing-high-contrast-colors/
7 |
8 | ```css
9 | :root {
10 | --red: 28;
11 | --green: 150;
12 | --blue: 130;
13 |
14 | --accessible-color: calc(
15 | ((((var(--red) * 299) + (var(--green) * 587) + (var(--blue) * 114)) / 1000) - 128) * -1000
16 | );
17 | }
18 |
19 | .button {
20 | color: rgb(var(--accessible-color), var(--accessible-color), var(--accessible-color));
21 | background-color: rgb(var(--red), var(--green), var(--blue));
22 | }
23 | ```
24 |
--------------------------------------------------------------------------------
/til/2019-08-19-nodejs-lts-or-not.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Should you use Node.js LTS or not?
3 | tags: ['javascript']
4 | ---
5 |
6 | > Node LTS is primarily aimed at enterprise use where there may be more resistance to frequent updates, extensive procurement procedures and lengthy test and quality requirements.
7 |
8 | > Generally if you are able to keep up with the latest stable and future Node releases you should do so. These are stable and _production ready_ releases with excellent community support. Unstable and experimental functionality is kept behind build and runtime flags and should not affect your day to day operations.
9 |
10 | https://stackoverflow.com/a/34655149/3135248
11 |
--------------------------------------------------------------------------------
/til/2019-03-29-yarn-comments-in-package-json.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Yarn comments in package.json
3 | tags: ['yarn']
4 | ---
5 |
6 | ```json
7 | {
8 | "private": true,
9 | "devDependencies": {
10 | "//": [
11 | "Please note: `react` dependency here is necessary in order to solve hoisting issues",
12 | "with React Native (Expo) and their locked React version. Yarn hoisted wrong version.",
13 | "It can eventually be removed (try Relay and RN-Expo examples to verify it works)."
14 | ],
15 | "flow-bin": "^0.95.1",
16 | "react": "^16.8.6"
17 | }
18 | }
19 | ```
20 |
21 | https://github.com/yarnpkg/yarn/pull/3829/files (also great example of `test.concurrent` usage ^^)
22 |
--------------------------------------------------------------------------------
/til/2019-06-24-optional-chaining-gotchas.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Optional chaining gotchas
3 | tags: ['javascript']
4 | ---
5 |
6 | Optional chaining != error suppression operator.
7 |
8 | ```js
9 | (function () {
10 | 'use strict';
11 | undeclared_var?.b; // ReferenceError: undeclared_var is not defined
12 | arguments?.callee; // TypeError: 'callee' may not be accessed in strict mode
13 | arguments.callee?.(); // TypeError: 'callee' may not be accessed in strict mode
14 | true?.(); // TypeError: true is not a function
15 | })();
16 | ```
17 |
18 | - https://v8.dev/features/optional-chaining
19 | - https://github.com/tc39/proposal-optional-chaining/commit/87e408d375bd749b21d70e65bd0cbbf57d9bcf82
20 |
--------------------------------------------------------------------------------
/til/2019-07-09-splitting-string.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to split strings in JavaScript
3 | tags: ['javascript']
4 | ---
5 |
6 | ```js
7 | 'I 💖 U'.split(' '); // ✅: [ 'I', '💖', 'U' ]
8 | 'I💖U'.split(''); // ❌: [ 'I', '�', '�', 'U' ]
9 | ```
10 |
11 | Better alternatives:
12 |
13 | ```js
14 | [...'I💖U'];
15 | Array.from('I💖U');
16 | 'I💖U'.split(/(?=[\s\S])/u);
17 | ```
18 |
19 | More info: [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split), [stackoverflow.com](https://stackoverflow.com/a/34717402/3135248)
20 |
21 | Please note - it's still a bit more complicated. Read this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split#reversing_a_string_using_split
22 |
--------------------------------------------------------------------------------
/til/2019-12-30-responsive-component-with-hooks.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Responsive component with hooks
3 | tags: ['react']
4 | ---
5 |
6 | ```js
7 | function MyResponsiveComponent() {
8 | const width = useWindowWidth(); // Our custom Hook
9 | return
Window width is {width}
;
10 | }
11 | ```
12 |
13 | ```js
14 | function useWindowWidth() {
15 | const [width, setWidth] = useState(window.innerWidth);
16 |
17 | useEffect(() => {
18 | const handleResize = () => setWidth(window.innerWidth);
19 | window.addEventListener('resize', handleResize);
20 | return () => {
21 | window.removeEventListener('resize', handleResize);
22 | };
23 | });
24 |
25 | return width;
26 | }
27 | ```
28 |
29 | Source: https://gist.github.com/gaearon/cb5add26336003ed8c0004c4ba820eae
30 |
--------------------------------------------------------------------------------
/src/pages/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | *
7 | * @flow
8 | */
9 |
10 | import React from 'react';
11 | /* $FlowFixMe[cannot-resolve-module] This comment suppresses an error when
12 | * merging two repositories. To see the error delete this comment and run Flow. */
13 | import { Redirect } from '@docusaurus/router'; // eslint-disable-line import/no-unresolved
14 |
15 | /* $FlowFixMe[signature-verification-failure] This comment suppresses an error when
16 | * merging two repositories. To see the error delete this comment and run Flow. */
17 | export default function Home() {
18 | return ;
19 | }
20 |
--------------------------------------------------------------------------------
/til/2022-02-16-new-relay-flow-type-names.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: New Flow types for Relay
3 | tags: ['relay', 'flow']
4 | ---
5 |
6 | Relay version 13 shipped with a new Rust Compiler and requires migration to the new Flow type names. @kassens described the migration path well in this comment: https://github.com/facebook/relay/issues/3792#issuecomment-1033933397
7 |
8 | - `SomeFragment$data` (instead of `SomeFragment` (no suffix))
9 | - `SomeFragment$fragmentType` (instead of `SomeFragment$ref`)
10 | - `SomeQuery$variables` (instead of `SomeQueryVariables`)
11 | - `SomeQuery$data` (instead of `SomeQueryResponse`, as it works like the `$data` for fragments and isn't the full response)
12 | - `$fragmentSpreads` (as a key in generated files instead of `$refs`)
13 |
14 | I also asked about the new Flow types here: https://github.com/facebook/relay/issues/3717
15 |
--------------------------------------------------------------------------------
/til/2020-01-31-graphql-rate-limiting-cost-computation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'GraphQL: Rate Limiting, Cost Computation'
3 | tags: ['graphql']
4 | ---
5 |
6 | So far the best idea I've ever seen is this one: https://github.com/adeira/universe/blob/5d2c15e1767a6e91c5eb82f41abc1e856811d0df/src/graphql-result-size/semantics-and-complexity-of-graphql.pdf (alternative reading: [Result size calculation for Facebook’s GraphQL query language](https://www.diva-portal.org/smash/get/diva2:1237221/FULLTEXT01.pdf))
7 |
8 | Experimental implementation here: https://github.com/adeira/universe/tree/5d2c15e1767a6e91c5eb82f41abc1e856811d0df/src/graphql-result-size
9 |
10 | Alternative approaches:
11 |
12 | - https://developer.github.com/v4/guides/resource-limitations/ (TODO: explain why it's worse and when you should consider it)
13 | - https://twitter.com/__xuorig__/status/1148653318069207041
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mrtnzlml-meta",
3 | "version": "0.0.0",
4 | "private": true,
5 | "license": "UNLICENSED",
6 | "scripts": {
7 | "docusaurus": "docusaurus",
8 | "start": "docusaurus start",
9 | "build": "docusaurus build",
10 | "swizzle": "docusaurus swizzle",
11 | "deploy": "docusaurus deploy"
12 | },
13 | "dependencies": {
14 | "@docusaurus/core": "^3.6.3",
15 | "@docusaurus/preset-classic": "^3.6.3",
16 | "react": "^18.3.1",
17 | "react-dom": "^18.3.1"
18 | },
19 | "devDependencies": {
20 | "@playwright/test": "^1.45.0"
21 | },
22 | "browserslist": {
23 | "production": [
24 | ">0.2%",
25 | "not dead",
26 | "not op_mini all"
27 | ],
28 | "development": [
29 | "last 1 chrome version",
30 | "last 1 firefox version",
31 | "last 1 safari version"
32 | ]
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/pages/styles.module.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2017-present, Facebook, Inc.
3 | *
4 | * This source code is licensed under the MIT license found in the
5 | * LICENSE file in the root directory of this source tree.
6 | */
7 |
8 | /**
9 | * CSS files with the .module.css suffix will be treated as CSS modules
10 | * and scoped locally.
11 | */
12 |
13 | .heroBanner {
14 | padding: 4rem 0;
15 | text-align: center;
16 | position: relative;
17 | overflow: hidden;
18 | }
19 |
20 | @media screen and (max-width: 966px) {
21 | .heroBanner {
22 | padding: 2rem;
23 | }
24 | }
25 |
26 | .buttons {
27 | display: flex;
28 | align-items: center;
29 | justify-content: center;
30 | }
31 |
32 | .features {
33 | display: flex;
34 | align-items: center;
35 | padding: 2rem 0;
36 | width: 100%;
37 | }
38 |
39 | .featureImage {
40 | height: 200px;
41 | width: 200px;
42 | }
43 |
--------------------------------------------------------------------------------
/playwright.config.js:
--------------------------------------------------------------------------------
1 | // eslint-disable-next-line ft-flow/require-valid-file-annotation,import/no-extraneous-dependencies
2 | const { devices, defineConfig } = require('@playwright/test');
3 |
4 | export default defineConfig({
5 | timeout: 60000,
6 | testDir: 'playwright',
7 | outputDir: 'playwright/test-results',
8 | testMatch: '**.play.js',
9 | forbidOnly: !!process.env.CI,
10 | reporter: process.env.CI ? 'github' : 'list',
11 | retries: process.env.CI ? 2 : 0,
12 | webServer: {
13 | command: process.env.CI ? 'yarn build && yarn start' : 'yarn start',
14 | port: 3000,
15 | timeout: 120 * 1000, // milliseconds
16 | reuseExistingServer: !process.env.CI,
17 | },
18 | use: {
19 | trace: 'on-first-retry',
20 | screenshot: 'only-on-failure',
21 | },
22 | projects: [
23 | {
24 | name: 'Desktop Chrome',
25 | use: devices['Desktop Chrome'],
26 | },
27 | ],
28 | });
29 |
--------------------------------------------------------------------------------
/til/2022-02-23-macos-monterey-blocking-port-5000.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: macOS Monterey is blocking port 5000
3 | tags: ['macos']
4 | ---
5 |
6 | This happened today. I couldn't start my Rust server because port 5000 was already occupied. But by whom? 🤔 I did some digging, and I got something like this:
7 |
8 | ```text
9 | $ lsof -i :5000
10 | COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
11 | ControlCe 1677 user 32u IPv4 0x728ff8e52d51c6dd 0t0 TCP *:commplex-main (LISTEN)
12 | ControlCe 1677 user 33u IPv6 0x728ff8e51d98ec65 0t0 TCP *:commplex-main (LISTEN)
13 | ```
14 |
15 | Hmm? I tried to kill the process but that didn't help. It took me a while to research that the culprit is macOS Monterey (I didn't start the server ever since I upgraded to this macOS version): https://stackoverflow.com/q/69868760/3135248
16 |
17 | Solution: Go to System Preference --> Sharing --> uncheck off the "AirPlay Receiver"
18 |
19 | WTF
20 |
--------------------------------------------------------------------------------
/til/2018-12-14-getters-can-be-dangerous.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getters can be dangerous
3 | tags: ['javascript']
4 | ---
5 |
6 | ```js
7 | // @flow
8 |
9 | type x = {
10 | +address: ?{|
11 | +fullAddress: ?string,
12 | |},
13 | };
14 |
15 | class WTF {
16 | _address = {
17 | fullAddress: 'yay',
18 | };
19 |
20 | get address() {
21 | const addr = this._address;
22 | this._address = null;
23 | return addr;
24 | }
25 | }
26 |
27 | const y = new WTF();
28 |
29 | // this is going to explode:
30 | console.warn(y.address?.fullAddress && y.address.fullAddress);
31 |
32 | // here is why:
33 | // console.warn(
34 | // y.address,
35 | // y.address,
36 | // );
37 | ```
38 |
39 | source: https://github.com/facebook/flow/issues/5479#issuecomment-349749477
40 |
41 | Unfortunatelly, Flow cannot uncover this version (which can also explode):
42 |
43 | ```js
44 | {
45 | y.address && y.address.fullAddress && {y.address.fullAddress};
46 | }
47 | ```
48 |
--------------------------------------------------------------------------------
/til/2022-03-06-math-imul.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Math.imul()
3 | tags: ['javascript']
4 | ---
5 |
6 | See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/imul
7 |
8 | ```js
9 | console.log(Math.imul(3, 4));
10 | // expected output: 12
11 |
12 | console.log(Math.imul(-5, 12));
13 | // expected output: -60
14 |
15 | console.log(Math.imul(0xffffffff, 5));
16 | // expected output: -5
17 |
18 | console.log(Math.imul(0xfffffffe, 5));
19 | // expected output: -10
20 | ```
21 |
22 | > The reason imul exists is because it is faster in only one (so far) circumstance: AsmJS. AsmJS allows for JIT-optimizers to more easily implement internal integers in JavaScript. Multiplying two numbers stored internally as integers (which is only possible with AsmJS) with imul is the only potential circumstance where Math.imul may prove performant in current browsers.
23 |
24 | Also: [Why would I use Math.imul()?](https://stackoverflow.com/questions/21052816/why-would-i-use-math-imul)
25 |
--------------------------------------------------------------------------------
/til/2022-02-15-using-dev-constant-in-rescript.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How to use __DEV__ constant in ReScript
3 | tags: ['rescript']
4 | ---
5 |
6 | Global constant `__DEV__` is not part of the ReScript language, but you can use it via `%external`. It is a common pattern that allows you to easily distinguish dev and prod environments. I started using it in my projects [as well](https://github.com/adeira/universe/tree/e769861df645885f9c646416a4855ce944a3839c/src/babel-preset-adeira#__dev__-expression).
7 |
8 | ```reason
9 | switch %external(__DEV__) {
10 | | Some(_) => Js.log("dev mode")
11 | | None => Js.log("production mode")
12 | }
13 | ```
14 |
15 | The code above translates to something like this:
16 |
17 | ```js
18 | var match$1 = typeof __DEV__ === 'undefined' ? undefined : __DEV__;
19 | if (match$1 !== undefined) {
20 | console.log('dev mode');
21 | } else {
22 | console.log('production mode');
23 | }
24 | ```
25 |
26 | Obviously, this code still needs some kind of transpilation (since `__DEV__` doesn't exist in JS either).
27 |
--------------------------------------------------------------------------------
/til/2019-09-30-computing-average-in-a-constant-time.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Computing average in a constant time
3 | tags: ['javascript']
4 | ---
5 |
6 | _Also known as average streaming._
7 |
8 | Source: https://stackoverflow.com/a/22999488/3135248
9 |
10 | > The following function adds a number to an average. average is the current average, size is the current number of values in the average, and value is the number to add to the average:
11 |
12 | ```
13 | double addToAverage(double average, int size, double value)
14 | {
15 | return (size * average + value) / (size + 1);
16 | }
17 | ```
18 |
19 | > Likewise, the following function removes a number from the average:
20 |
21 | ```
22 | double subtractFromAverage(double average, int size, double value)
23 | {
24 | // if (size == 1) return 0; // wrong but then adding a value "works"
25 | // if (size == 1) return NAN; // mathematically proper
26 | // assert(size > 1); // debug-mode check
27 | // if(size < 2) throw(...) // always check
28 | return (size * average - value) / (size - 1);
29 | }
30 | ```
31 |
--------------------------------------------------------------------------------
/til/2020-07-21-strictequals-without-equals-operators.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: strictEquals(a, b) without using "==="
3 | tags: ['javascript']
4 | ---
5 |
6 | > Write a function called `strictEquals(a, b)` that returns the same value as `a === b`. Your implementation must not use the `===` or `!==` operators.
7 |
8 | Solution: https://gist.github.com/gaearon/08a85a33e3d08f3f2ca25fb17bd9d638?ck_subscriber_id=920605104
9 |
10 | ```js
11 | function strictEquals(a, b) {
12 | if (Object.is(a, b)) {
13 | // Same value.
14 | // Is this NaN?
15 | if (Object.is(a, NaN)) {
16 | // We already know a and b are the same, so it's enough to check a.
17 | // Special case #1.
18 | return false;
19 | } else {
20 | // They are equal!
21 | return true;
22 | }
23 | } else {
24 | // Different value.
25 | // Are these 0 and -0?
26 | if ((Object.is(a, 0) && Object.is(b, -0)) || (Object.is(a, -0) && Object.is(b, 0))) {
27 | // Special case #2.
28 | return true;
29 | } else {
30 | // They are not equal!
31 | return false;
32 | }
33 | }
34 | }
35 | ```
36 |
--------------------------------------------------------------------------------
/til/2019-08-19-gitignore.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Gitignore
3 | tags: ['git']
4 | ---
5 |
6 | ```gitignore
7 | # Empty lines are being ignored.
8 | # Trailing spaces are ignored unless they are quoted with backslash ("\").
9 |
10 | \#not_a_comment.xyz
11 | !\#not_a_comment.xyz
12 |
13 | # If there is a separator at the beginning or middle (or both) of the pattern, then the pattern is relative to the directory level of the particular .gitignore file itself.
14 | # Otherwise the pattern may also match at any level below the .gitignore level.
15 |
16 | directory_only/
17 | directory_or_file
18 |
19 | # An asterisk "*" matches anything except a slash.
20 | # The character "?" matches any one character except "/".
21 | # The range notation, e.g. [a-zA-Z], can be used to match one of the characters in a range.
22 |
23 | # Two consecutive asterisks ("**") in patterns matched against full pathname may have special meaning:
24 | **/foo # match in all directories
25 | abc/** # matches all files inside directory "abc"
26 | a/**/b # zero or more directories ("a/b", "a/x/b", "a/x/y/b", ...)
27 | ```
28 |
29 | https://git-scm.com/docs/gitignore
30 |
--------------------------------------------------------------------------------
/til/2019-05-22-v8-built-in-functions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: V8 Built-in functions
3 | tags: ['javascript']
4 | ---
5 |
6 | - https://v8.dev/docs/builtin-functions
7 | - https://github.com/v8/v8/blob/master/src/runtime/runtime.h
8 | - https://v8.dev/docs/memory-leaks
9 |
10 | ```js
11 | function foo() {
12 | const x = { bar: 'bar' };
13 | %DebugTrackRetainingPath(x);
14 | return () => {
15 | return x;
16 | };
17 | }
18 | const closure = foo();
19 | gc();
20 | ```
21 |
22 | vvv
23 |
24 | ```text
25 | 💃 universe [master] node --allow-natives-syntax --track-retaining-path --expose-gc src/test.js
26 |
27 | #################################################
28 | Retaining path for 0x33a90e9bcb89:
29 |
30 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31 | Distance from root 3: 0x33a90e9bcb89