{"id":13447365,"url":"https://github.com/GeneZharov/introversion","last_synced_at":"2025-03-21T17:31:22.503Z","repository":{"id":57123700,"uuid":"56770165","full_name":"GeneZharov/introversion","owner":"GeneZharov","description":"Swiss army knife for debugging JavaScript expressions and performance measurements","archived":false,"fork":false,"pushed_at":"2020-06-04T19:31:59.000Z","size":503,"stargazers_count":8,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-09T17:36:06.206Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GeneZharov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-21T12:03:29.000Z","updated_at":"2020-06-04T19:32:02.000Z","dependencies_parsed_at":"2022-08-29T02:12:11.527Z","dependency_job_id":null,"html_url":"https://github.com/GeneZharov/introversion","commit_stats":null,"previous_names":["kahless/echolotjs","kahless/echolot"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeneZharov%2Fintroversion","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeneZharov%2Fintroversion/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeneZharov%2Fintroversion/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeneZharov%2Fintroversion/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GeneZharov","download_url":"https://codeload.github.com/GeneZharov/introversion/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221817222,"owners_count":16885478,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T05:01:15.525Z","updated_at":"2024-10-28T10:31:18.790Z","avatar_url":"https://github.com/GeneZharov.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"Introversion.js\n===============\n\nSwiss army knife for debugging JavaScript expressions and performance \nmeasurements. A wrapper around `console.log()`, `performance.now()`, \n`debugger`, etc. with essential benefits:\n\n* works great with functional code (built for [React](https://reactjs.org/), \n  [Redux](https://redux.js.org/), [Ramda](https://ramdajs.com/), \n  [lodash/fp](https://github.com/lodash/lodash/wiki/FP-Guide), etc.)\n* pretty and colorful output\n* easy to use:\n    * automatically chooses the best time source available (`performance.now()` \n      or `console.time()` or `Date.now()`)\n    * logged objects are deeply cloned to prevent confusing results in DevTools\n    * lots of tools for various scenarios\n\n\nTable of Contents\n-----------------\n* [Motivation](#motivation)\n* [Installation](#installation)\n* [Watchers](#watchers)\n    * [`logV()`](#logV)\n    * [`logF()`](#logF)\n* [Timers](#timers)\n    * [`time()`, `timeEnd()`](#time-timeEnd)\n    * [`stopwatch()`, `lap()`](#stopwatch-lap)\n    * [`timeF()`](#timeF)\n    * [`timeV()`](#timeV)\n* [Modes](#modes)\n    * [Quiet mode (`logV_()`, `v_()`...)](#quiet-mode)\n    * [Breakpoint mode (`debV()`, ...)](#breakpoint-mode)\n    * [Guards](#guards)\n    * [Mute mode (`.mute`)](#mute-mode)\n* [Configuration](#configuration)\n    * [Default configuration (`setDefaults()`)](#default-configuration)\n    * [Instance configuration (`instance()`)](#instance-configuration)\n    * [In-place configuration (`.with()`)](#in-place-configuration)\n* [Options](#options)\n    * [General options](#general-options)\n    * [Formatting options](#formatting-options)\n    * [Stack trace options](#stack-trace-options)\n    * [In-place options](#in-place-options)\n* [Advanced installation](#advanced-installation)\n    * [Default import](#default-import)\n    * [Set up in global variable](#set-up-in-global-variable)\n    * [Zero-conf for Node.js](#zero-conf-for-nodejs)\n* [License](#license)\n\n\nMotivation\n----------\n\nSuppose you have an arrow function, and you need to know some value inside:\n\n```js\nconst fn = n =\u003e n + 1; // what's in “n”?\n```\n\nIn order to use `console.log()` you’ll have to rewrite this function into \nmultiple statements:\n\n```js\nconst fn = n =\u003e {\n  console.log(n);\n  return n + 1;\n};\n```\n\nIntroversion allows you to simply wrap the desired value without rewriting:\n\n```js\nconst fn = n =\u003e logV(n) + 1; // log value\n// ...or\nconst fn = logF(n =\u003e n + 1); // log every function call (arguments and return value)\n```\n\n\n### React Component\nA real-world example of a functional React component that makes you hate \n`console.log()`.\n\n```js\n...\nrenderSuggestion={item =\u003e (\n  \u003cMenuItem\n    text={logV(item).name}\n    onClick={_ =\u003e this.toggle(item.id)}\n  /\u003e\n)}\n```\n\n\n### Performance\n\nImagine you need to check if a function call is fast enough to decide whether \nyou need to cache it somewhere. With Introversion you can do it by simply \nwrapping the desired expression in `timeV(() =\u003e \u003cexpr\u003e)` right in JSX:\n\n```js\n// before\n\u003cSelect options={states.map(transform) /* is map() too slow? */} /\u003e\n\n// after\n\u003cSelect options={timeV(() =\u003e states.map(transform)) /* prints 2.73ms */} /\u003e\n```\n\n\n### Functional Programming\n\nSince Introversion is functional, it tries not to interfere in the program’s \nlogic, but to seamlessly proxy input and output values, so it makes it easy to \ndebug functional code. For example, to research a function composition for \nissues.\n\n```js\nimport { pipe, groupBy, omitBy, mapValues } from \"lodash/fp\";\n\nconst build = pipe([\n  groupBy(o =\u003e o.key),\n  logF(omitBy(x =\u003e x.length \u003e 1)), // print what goes on the 2nd step and what comes out\n  mapValues(([o]) =\u003e o.uuid)\n]);\n```\n\n\nInstallation\n------------\n\n```sh\nnpm install introversion --save-dev\n# or\nyarn add introversion --dev\n```\n\n```js\nimport { logV } from \"introversion\";\n\nlogV(val);\n```\n\nAdvanced installation cases are described below ([Default \nimport](#default-import), [Set up in global \nvariable](#set-up-in-global-variable), [Zero-conf for \nNode.js](#zero-conf-for-nodejs))\n\n\nWatchers\n--------\n\n### logV()\n\n*Alias:* `v()` (helpful with default import: `In.v()`)\n\n`logV()` (“v” stands for “value”) merely prints an array of its arguments. The \nmain difference from `console.log()` is that the last argument is returned. \nTherefore it is safe to wrap any expression in `logV()` without breaking your \ncode down.\n\n```js\nimport { logV } from \"introversion\";\n\nconst random = n =\u003e Math.floor(logV(Math.random()) * n) + 10;\nrandom(1); //=\u003e logV() [ 0.5909956243063763 ]\n```\n\nYou can print any other values alongside with the wrapped expression. Just pass \nthem as arguments. Only the last argument is returned so extra arguments \nwon’t affect your code:\n\n```js\nconst random = n =\u003e Math.floor(logV(num, this, \"mystr\", Math.random()) * n) 10;\nrandom(1); //=\u003e logV [ 1, {}, 'mystr', 0.8474771121023132 ]\n```\n\nYou can use extra arguments to distinguish different watchers from each other \nin the log:\n\n```js\nconst fn = n =\u003e n \u003e 0 ? logV(true, n * 1.25) : logV(false, n / 9);\nfn(5);   //=\u003e logV [ true, 6.25 ]\nfn(-81); //=\u003e logV [ false, -9 ]\n```\n\n### logF()\n\n*Alias:* `f()` (helpful with default import: `In.f()`)\n\n`logF()` (“f” stands for “function”) is designed to watch for function \ncalls. When a wrapped function is called, its arguments and a returned value \nare logged. If a wrapped function throws an exception, that exception will be \nlogged and then rethrown again. A wrapped in the `logF()` function can be used \nin the same way as an unwrapped one: all arguments, `this` and a returned value \nwill be proxied.\n\n```js\nimport { logF } from \"introversion\";\n\n[1, 2].map(logF(n =\u003e 2 * n));\n\n//=\u003e logF()\n//=\u003e ... Params: [ 1, 0, [ 1, 2 ] ]\n//=\u003e ... Result: 2\n\n//=\u003e logF()\n//=\u003e ... Params: [ 2, 1, [ 1, 2 ] ]\n//=\u003e ... Result: 4\n```\n\n`logF()` can also accept additional arguments that will be printed just like `logV()` \ndoes:\n\n```js\nlogF(\"foo\", \"bar\", calculate)(1, 2, 3)\n\n// =\u003e logF() [ \"foo\", \"bar\" ] \u003c- extra arguments go here\n// =\u003e ... Params: [ 1, 2, 3 ]\n// =\u003e ... Result: 999\n```\n\nTimers\n------\n\n### time(), timeEnd()\nA replacement for `console.time`/`timeEnd()` that use the most accurate source \nof time available:\n\n1. `performance.now()`\n2. `console.time`/`timeEnd()`\n3. `Date.now()`\n\n```js\nimport { time, timeEnd } from \"introversion\";\n\ntime(); // start the timer\ncalculateSomething();\ntimeEnd(); // stop the timer\n\n//=\u003e timeEnd() 203 ms\n```\n\nJust like console timing methods, these functions accept an optional name for a \nnew timer. `timeEnd()` may also take additional arguments for printing \nalongside with the elapsed time (not available with `format: false` and console \nmethods as a time source).\n\n```js\ntime(\"label\"); // start the timer named \"label\"\ncalculateEverything();\ntimeEnd(\"foo\", \"bar\", \"label\"); // stop the timer named \"label\"\n\n//=\u003e timeEnd() [ 'foo', 'bar', 'label' ] 203 ms\n```\n\n### stopwatch(), lap()\nWhen you have a sequence of actions, it is inconvenient to wrap every action in \n`time()...timeEnd()`. In this case, stopwatch API is more helpful.\n\n* `stopwatch()` — initially starts the timer.\n* `lap([...args])` — prints the elapsed time since the previous \n  `stopwatch`/`lap()`. Also prints optional arguments and starts a new timer \n  for the next lap.\n\u003c/a\u003e\n\n```js\nimport { stopwatch, lap } form \"introversion\";\n\nstopwatch();\n\ncreateTables();\nlap(\"created\"); //=\u003e lap() [ 'created' ] 15 ms\n\nconst rows = queryRows();\nlap(\"foobar\", rows, \"queried\"); //=\u003e lap() [ 'foobar', [], 'queried' ] 107 ms\n\npopulateState(rows);\nlap(\"populated\"); //=\u003e lap() [ 'populated' ] 768 ms\n```\n\n### timeF()\nYou can wrap any function in `timeF()`. The result will be a function with \nthe same behavior as a wrapped one, but additionally, it will print the \nexecution time of its synchronous code.\n\n```js\nimport { timeF } form \"introversion\";\n\narray.map(timeF(iterator));\n\n//=\u003e timeF() 4 ms\n//=\u003e timeF() 9 ms\n//=\u003e timeF() 1 ms\n```\n\nOptionally you can pass any arguments for printing:\n\n```js\narray.map(timeF(\"foo\", \"bar\", iterator));\n\n//=\u003e timeF() [ 'foo', 'bar' ] 4 ms\n//=\u003e timeF() [ 'foo', 'bar' ] 9 ms\n//=\u003e timeF() [ 'foo', 'bar' ] 1 ms\n```\n\n### timeV()\n\nSometimes you may suspect that some expression is calculated for too long. In \nthis case it is convenient to wrap that expression in `timeV(() =\u003e \u003cexpr\u003e)` \nthat will print the elapsed time.\n\n```js\nimport { timeV } form \"introversion\";\n\n// original expression\ndata = [calculate(src), readState()];\n\n// wrapped expression\ndata = timeV(() =\u003e [calculate(src), readState()]);\n\n//=\u003e timeV() 349 ms\n```\n\nOptionally you can pass any arguments for printing:\n\n```js\ndata = timeV(\"data\", src, () =\u003e [calculate(src), readState()]);\n\n//=\u003e timeV() [ 'data', 'DATABASE' ] 349 ms\n```\n\n\nModes\n-----\n\n### Quiet Mode\n\n* `logV_()`, *alias:* `v_()`\n* `logF_()`, *alias:* `f_()`\n\nSometimes you are not interested in a wrapped value itself, but you need to \nknow, if it was calculated. For example, in React Native an attempt to log an \nevent object may hang the application. Or maybe you are interested only in \nprinting additional arguments. For these cases, there are alternative quiet \nmode watchers that don’t log wrapped value itself but log all additional \narguments.\n\n```js\nimport { logF_ } from \"introversion\";\n\nconst fn = logF_(\"Invoked!\", n =\u003e n + 1);\nfn(2); //=\u003e logF_() [ 'Invoked!' ]\n```\n\n### Breakpoint Mode\n\n* `debV()`\n* `debF()`\n\nInstead of printing data, these functions create a breakpoint using `debugger` \nstatement. It can help to look around and walk through the call stack.\n\n### Guards\nSometimes a watcher can produce too many outputs if it is called for too many \ntimes. You may want to suppress excess outputs. Perhaps you need only the first \none or first ten outputs. In this case, the in-place “guard” option may help. \nIt specifies the number of times a watcher will be active. After this amount \nruns out, it will merely proxy values without any side effects. More about the \n[in-place configuration](#in-place-configuration) is described below.\n\n```js\nimport { logV } from \"introversion\";\n\nfor (let i = 0; i \u003c 1000; i++) {\n  logV.with({ guard: 1 })(i); // prints only once\n}\n```\n\nGuards need some way to distinguish one call from another to keep track of the \namount of executed calls. So if you have more than one guard, you need to \nexplicitly identify a call with the “id” option:\n\n```js\nimport { logV } from \"introversion\";\n\nfor (let i = 0; i \u003c 1000; i++) {\n  logV.with({ id: 1, guard: 1 })(i); // prints only once\n  logV.with({ id: 2, guard: 10 })(arr[i]); // prints for the first 10 times\n}\n```\n\n### Mute Mode\n\nImagine, you have a function covered with unit tests. And 1 of 30 tests fails. \nFor debugging reasons, it’s important to know a value deep inside of that \nfunction. But if you log that value each time it is evaluated for every unit \ntest, there would be hundreds of log entries. In this case, the mute mode comes \nto the rescue.\n\nYou can use a muted watcher, that is available for any watcher under the \nproperty called `.mute` (e.g. `logV.mute()`, `logV_.mute()`, `debV.mute()`, \n`logF.mute()`, ...). Muted watcher doesn’t produce any logs or breakpoints \nunless you explicitly unmute it (in the failed unit test for instance).\n\n* `unmuteF(fn)` — unmute everything during this function execution\n* `unmuteV(() =\u003e \u003cexpr\u003e)` — runs passed function and unmutes everything while \n  it is running\n* `unmute()` — unmute all the muted functions\n* `mute()` — mute everything again\n\nExample:\n\n```js\n// module.js\nfunction action(x) {\n  // ... big and complicated function\n  const y = x * 8;\n  return y ^ Math.PI;\n}\n\n// module.spec.js\ndescribe(\"action()\", () =\u003e {\n  // ... lots of unit tests\n  it(\"should perform a complex calculation\", () =\u003e {\n    const res = action(2);\n    expect(res).toBe(16);\n  });\n});\n```\n\nFirst, we need to wrap the desired expression in a muted watcher:\n\n```js\n// module.js\nimport { logV } from \"introversion\";\n\nfunction action(x) {\n  ...\n  return logV.mute(y) ^ Math.PI;\n}\n```\n\nThen we need to unmute a muted watcher at the desired moment (in the failed \nunit test):\n\n```js\n// module.spec.js\nimport { mute, unmute, unmuteF, unmuteV } from \"introversion\";\n\n// unmute a function\nconst res = unmuteF(action)(2);\n\n// or unmute an expression\nconst res = unmuteV(() =\u003e action(2));\n\n// or unmute anything in a low level imperative style\nunmute();\nconst res = action(2);\nmute();\n```\n\n\nConfiguration\n-------------\n\n### Default Configuration\n\nYou can pass any number of default options as object properties:\n\n```js\nimport { setDefaults } from \"introversion\";\n\nsetDefaults({\n  format: false,\n  log: (...xs) =\u003e Reactotron.log(xs),\n  warn: (...xs) =\u003e Reactotron.warn(xs)\n});\n```\n\n### Instance Configuration\n\nYou can have many instances of Introversions with different configurations:\n\n```js\nimport { instance } from \"introversion\";\n\nconst InR = instance({\n  format: false,\n  log: (...xs) =\u003e Reactotron.log(xs),\n  warn: (...xs) =\u003e Reactotron.warn(xs)\n});\n\nconst InX = instance({\n  format: false,\n  log: (...xs) =\u003e xscript.response.write(xs.join(\" \") + \"\\n\"),\n  warn (...xs) =\u003e xscript.response.write(xs.join(\" \") + \"\\n\")\n})\n\nInR.logV(val);\nInX.logV(val);\n```\n\n### In-Place Configuration\n\nMost functions have a method `with()` for setting temporary local configuration \noptions only for this call.\n\n```js\nimport { logV } from \"introversion\";\n\nlogV.with({ depth: Infinity })(myobj);\n```\n\nOptions\n-------\n\n### General Options\n\n* **log**\n\n    A function that accepts any number of any arguments and prints them to the \n    log.\n\n    *Default:* `(...xs) =\u003e console.log(...xs)`\n\n    *Examples:*\n\n    ```js\n    (...xs) =\u003e Reactotron.log(xs)\n    (...xs) =\u003e xscript.response.write(xs.join(\" \") + \"\\n\")\n    ```\n\n* **warn**\n\n    A function that accepts any number of any arguments and prints them as \n    warnings to the log.\n\n    *Default:* `(...xs) =\u003e console.warn(...xs)`\n\n    *Example:*\n\n    ```js\n    (...xs) =\u003e Reactotron.warn(xs)\n    ```\n\n* **timer**\n\n    * `\"auto\"` — use the most accurate source of time available\n    * `\"performance\"` — use `performance.now()`\n    * `\"console\"` — use `console.time`/`timeEnd()`\n    * `\"date\"` — use `Date.now()`\n    * `() =\u003e number` — custom user function that returns time in milliseconds\n\n    To offer protection against timing attacks and fingerprinting, the \n    precision of `Date.now()` might get rounded depending on the environment. \n    So consider the use of “repeat” option to increase preciseness in this \n    case.\n\n    *Default:* `\"auto\"`\n\n* **clone**\n\n    * `\"auto\"` — clone all the values before printing if DevTools are detected\n    * `true`/`false` — whether to deeply clone all values for printing\n\n    *Default:* `\"auto\"`\n\n* **errorHandling**\n\n    * `\"warn\"` — output errors as warnings and try to fall back on the default \n      behavior\n    * `\"throw\"` — always throw an exception on error\n\n    *Default:* `\"warn\"`\n\n* **devTools**\n\n    For some options, it is important if DevTools are connected to the program. \n    Introversion tries to detect DevTools with a test output to the log. To \n    skip it, you can explicitly specify presence of DevTools with this option. \n    Or you can explicitly specify all the options that depend on DevTools \n    (currently these are “clone”, “format”, “formatErrors”).\n\n    * `\"auto\"` — detect DevTools with a test output to the log\n    * `true`/`false` — whether DevTools are connected\n\n    *Default:* `\"auto\"`\n\n* **dev**\n\n    If `true` Introversion utilities additionally print a configuration object \n    they are using and a stack trace including the detected user code position \n    in it that is useful for configuring “stackTraceShift” option.\n\n    *Default:* `false`\n\n### Formatting Options\n\n* **format**\n\n    * `\"auto\"` — detect the environment\n    * `true` — optimized for browsers and sophisticated tools like DevTools\n    * `false` — optimized for text output, e.g., to a terminal by Node.js\n\n    When “format” is enabled:\n\n    * stringifies printed objects in a pretty way\n    * Only a single `log()` call is made with a single formatted string as an \n      argument\n    * empty line after each output\n\n    Not formatted output:\n\n    ```\n    logF() at myfunc (index.js:10:23)\n    ... Params: [ 1, 0, [ 1, 2, 3 ] ]\n    ... Result: 1\n    ```\n\n    Formatted output:\n\n    ```\n    logF() at myfunc (index.js:10:23)\n    --- Params ---\n    [ 1, 0, [ 1, 2, 3 ] ]\n    --- Result ---\n    1\n    ```\n\n    *Default:* `\"auto\"`\n\n* **formatErrors**\n\n    Similar to the “format” option, but for errors and warnings.\n\n    * `\"auto\"` — detect the environment\n    * `true` — optimized for browsers and sophisticated tools like DevTools\n    * `false` — optimized for text output, e.g., to a terminal by Node.js\n\n    Not formatted output:\n\n    ```\n    Introversion Warning\n\n    Unknown option stakcTrace\n    ```\n\n    Formatted output:\n\n    ```\n    ▒  Introversion\n    ▒\n    ▒  Unknown option stakcTrace\n    ▒\n    ▒  at validateConf (introversion.js:780:7)\n    ▒  at (introversion.js:898:31)\n    ▒  at Object.\u003canonymous\u003e (index.js:35:4)\n    ▒  at Module._compile (loader.js:723:30)\n    ▒  at Object.Module._extensions..js (loader.js:734:10)\n    ▒  at Module.load (loader.js:620:32)\n    ▒  at tryModuleLoad (loader.js:560:12)\n    ```\n\n    *Default:* `\"auto\"`\n\n* **highlight**\n\n    If `true`, Introversion will try to highlight the output for terminals.\n\n    *Default:* `\"auto\"`\n\n* **inspectOptions**\n\n    Options that will be proxied to the node’s `util.inspect()`\n\n    *Default:* `\"auto\"`\n\n* **precision**\n\n    Number of digits after the point for the time measured by \n    [timers](#timers).\n\n    *Default:* `2`\n\n### Stack Trace Options\n\n* **stacktrace**\n\n    In order to distinguish one output from another Introversion logs function \n    name, file name, line and column numbers of a line where the user called an \n    Introversion function. What exactly will be printed is configured with this \n    option using an array of keywords.\n\n    * `\"auto\"` — depends on the environment\n    * `Array\u003c\"func\" | \"file\" | \"line\" | \"col\"\u003e`\n    * `true` — print everything, shorthand for `[\"func\", \"file\", \"line\", \"col\"]`\n    * `false` — print nothing, shorthand for `[]`\n\n    *Default:* `\"auto\"`\n\n* **stackTraceAsync**\n\n    * `\"auto\"` — try to log asynchronously if available.\n    * `true` — print to the log asynchronously. It allows the use of source \n      maps and guess anonymous functions but will trigger network requests for \n      source maps.\n    * `false` — synchronous behavior, won’t use source maps or guess anonymous \n      functions.\n\n    *Default:* `\"auto\"`\n\n* **stackTraceShift**\n\n    Introversion knows at what depth in the stack trace the user function call \n    should be located. But on some platforms Introversion module can be wrapped \n    in something. For instance React Native increases stack trace depth by 1. \n    Therefore, Introversion may mistake with the location of the user function \n    call. This option helps to correct this mistake.\n\n    ```js\n    logV.with({ dev: true })\n    // ...\n    // --- Dev: stacktrace ---\n    //  0  — at getTrace (introversion.js:989:21)\n    //  1  — at logVal (introversion.js:1048:3)\n    //  2  — at (introversion.js:1414:12)\n    //  3  — at (introversion.js:869:12)\n    // [4] — at Object.\u003canonymous\u003e (2.js:5:25)\n    //  5  — at Module._compile (loader.js:723:30)\n    //  6  — at Object.Module._extensions..js (loader.js:734:10)\n    //  7  — at Module.load (loader.js:620:32)\n    ```\n\n    You can see that Introversion suppose that user call was in the 4th \n    position, but actually it was in the 5th. So you can set `stackTraceShift: \n    1` to fix it.\n\n    *Default:* `\"auto\"`\n\n### In-Place Options\n\n* **id**\n\n    Makes a watcher/timer unique. It helps Introversion to distinguish \n    watchers/timers from each other. This option is required in order to use \n    “guard” options.\n\n    ID can be of any type, but if you are using the console as a time source, \n    then the value will be internally converted to a string since it is \n    required by the \n    [console spec](https://console.spec.whatwg.org/#timer-table).\n\n* **guard**\n\n    Sets how many times a watcher or a timer will be functional. After the \n    number of calls exceeds, the call will act just like an original \n    value/function/method without any additional behavior like printing or \n    debugging.\n\n    See [guards](#guards) for a complete description.\n\n    *Default:* `Infinity`\n\n    ```js\n    import { logF } from \"introversion\";\n    const fn = logF.with({ id: 0, guard: 1 })(n =\u003e n % 2); // prints only once\n    [1, 2, 3, 4, 5].map(fn);\n\n    //=\u003e logF()\n    //=\u003e ... Params: [ 1, 0, [ 1, 2, 3, 4, 5 ] ]\n    //=\u003e ... Result: 1\n    ```\n\n* **repeat**\n\n    The number of times to repeat the measure in order to increase preciseness. \n    Especially useful with `Date.now()` as a time source, because its precision \n    is rounded.\n\n    The value can be either a number or a string with a special suffix (`\"K\"`, \n    `\"M\"`, `\"G\"`) for big numbers. For example:\n\n    * `\"5K\"` stands for 5,000\n    * `\"1.5M\"` stands for 1,500,000\n    * `\"10G\"` stands for 10,000,000,000\n\n    *Default:* 1\n\n    ```js\n    import { timeV } from \"introversion\";\n\n    timeV.with({ repeat: 5000 })(mergeDatabases);\n    // ...or\n    timeV.with({ repeat: \"5K\" })(mergeDatabases);\n\n    //=\u003e timeV() 0.113 ms\n    ```\n\n\nAdvanced Installation\n---------------------\n\n### Default Import\n\nIntroversion has a default export:\n\n```js\nimport In from \"introversion\";\n\nIn.v(\"foobar\");\n```\n\nIn this case short aliases `v()`, `f()` for `logV()`, `logF()` and their quiet \nalternatives `v_()`, `f_()` are especially helpful.\n\n#### ImportJS\n\nIf you use [ImportJS](https://github.com/Galooshi/import-js) and you want it to \nautomatically add Introversion as a default import, like in the example above, \nthen set the desired alias in the configuration file.\n\n```js\n// .importjs.js\n\nmodule.exports = {\n  aliases: { In: \"introversion\" }\n};\n```\n\n### Set up in Global Variable\n\nSometimes, it is convenient to set up Introversion in the global scope. In \norder to do this you can import the following script in your main file:\n\n```js\n// src/globals.js\n\nimport In from \"introversion\";\n\nIn.setDefaults({...}); // if necessary\nwindow.In = In; // for browser\nglobal.In = In; // for node\n```\n\n#### Jest\n\nTo make a global variable with Introversion’s API available in \n[Jest](https://jestjs.io) unit tests:\n\n```json\n// package.json\n\n\"jest\": {\n  \"setupFiles\": [\"\u003crootDir\u003e/src/globals.js\"]\n}\n```\n\n#### Flow\n\nIf you are using Introversion with [Flow](https://flow.org/), then you’ll have \nto specify the type of the global variable with a libdef file:\n\n```js\n// flow-typed/introversion.js\n\ndeclare var In: any;\n```\n\nIf you want to specify the shape of the API, then you can copypaste it from the \n[libdef \nscript](https://github.com/GeneZharov/introversion/blob/master/introversion.js.flow).\n\n### Zero-Conf for Node.js\n\nIntroversion can work with Node.js with no need to initialize or add imports. \nTo make API available in scripts you need to run `node` with `-r \nintroversion/init` option, that will write API into the global variable `In`.\n\n```sh\nnode -r introversion/init myfile.js\n```\n\n```js\n// myfile.js\nIn.v(\"working without initialization!\");\n```\n\nIntroversion initialized this way can be configured with environment variables:\n\n* `INTROVERSION_NAME` — the name for the global variable (`In` by default)\n* `INTROVERSION_CONF` — js object with the configuration\n* `INTROVERSION_CONF_FILE` — path to the CommonJS module that exports the \n  configuration object\n\nExamples:\n\n```sh\nINTROVERSION_NAME='I' node -r introversion/init myfile.js\nINTROVERSION_CONF='{ stackTrace: false }' node -r introversion/init myfile.js\nINTROVERSION_CONF_FILE=~/.introversion-conf.js node -r introversion/init myfile.js\n```\n\nYou can go further and create an alias for Node with initialized Introversion \nfor debugging small scripts that you don’t want to over bloat with extra code. \nYou can put these commands in `~/.bashrc`, `~/.zshrc`, etc. Introversion should \nbe installed globally in this case.\n\n```sh\nnpm install -g introversion\n\nalias nodein='node -r introversion/init'\nalias babel-nodein='babel-node -r introversion/init'\nalias ts-nodein='ts-node -r introversion/init'\n...\n```\n\n\nLicense\n-------\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGeneZharov%2Fintroversion","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGeneZharov%2Fintroversion","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGeneZharov%2Fintroversion/lists"}