Detect copy-pasted and structurally similar code

Overview

jsinspect

Detect copy-pasted and structurally similar JavaScript code. Requires Node.js 6.0+, and supports ES6, JSX as well as Flow. Note: the project has been mostly rewritten for the 0.10 release and saw several breaking changes.

Build Status

Overview

We've all had to deal with code smell, and duplicate code is a common source. While some instances are easy to spot, this type of searching is the perfect use-case for a helpful CLI tool.

Existing solutions do exist for this purpose, but some struggle with code that has wildly varying identifiers or literals, and others have lackluster support for the JS ecosystem: ES6, JSX, Flow, ignoring module declarations and imports, etc.

And copy-pasted code is but one type of code duplication. Common boilerplate and repeated logic can be identified as well using jsinspect, since it doesn't operate directly on tokens - it uses the ASTs of the parsed code.

You have the freedom to specify a threshold determining the smallest subset of nodes to analyze. This will identify code with a similar structure, based on the AST node types, e.g. BlockStatement, VariableDeclaration, ObjectExpression, etc. By default, it searches nodes with matching identifiers and literals for copy-paste oriented detection, but this can be disabled. For context, identifiers include the names of variables, methods, properties, etc, while literals are strings, numbers, etc.

The tool accepts a list of paths to parse and prints any found matches. Any directories among the paths are walked recursively, and only .js and .jsx files are analyzed. You can explicitly pass file paths that include a different extension as well. Any node_modules and bower_components dirs are also ignored.

screenshot

Installation

It can be installed via npm using:

npm install -g jsinspect

Usage

Usage: jsinspect [options] <paths ...>


Detect copy-pasted and structurally similar JavaScript code
Example use: jsinspect -I -L -t 20 --ignore "test" ./path/to/src


Options:

  -h, --help                         output usage information
  -V, --version                      output the version number
  -t, --threshold <number>           number of nodes (default: 30)
  -m, --min-instances <number>       min instances for a match (default: 2)
  -c, --config [config]              path to config file (default: .jsinspectrc)
  -r, --reporter [default|json|pmd]  specify the reporter to use
  -I, --no-identifiers               do not match identifiers
  -L, --no-literals                  do not match literals
  -C, --no-color                     disable colors
  --ignore <pattern>                 ignore paths matching a regex
  --truncate <number>                length to truncate lines (default: 100, off: 0)
  --debug                            print debug information

If a .jsinspectrc file is located in the project directory, its values will be used in place of the defaults listed above. For example:

{
  "threshold":     30,
  "identifiers":   true,
  "literals":      true,
  "color":         true,
  "minInstances":  2,
  "ignore":        "test|spec|mock",
  "reporter":      "json",
  "truncate":      100,
}

On first use with a project, you may want to run the tool with the following options, while running explicitly on the lib/src directories, and not the test/spec dir.

jsinspect -t 50 --ignore "test" ./path/to/src

From there, feel free to try decreasing the threshold, ignoring identifiers using the -I flag and ignoring literals with -L. A lower threshold may lead you to discover new areas of interest for refactoring or cleanup.

Integration

It's simple to run jsinspect on your library source as part of a build process. It will exit with an error code of 0 when no matches are found, resulting in a passing step, and a positive error code corresponding to its failure. For example, with Travis CI, you could add the following entries to your .travis.yml:

before_script:
  - "npm install -g jsinspect"

script:
  - "jsinspect ./path/to/src"

Note that in the above example, we're using a threshold of 30 for detecting structurally similar code. A higher threshold may be appropriate as well.

To have jsinspect run with each job, but not block or fail the build, you can use something like the following:

script:
  - "jsinspect ./path/to/src || true"

Reporters

Aside from the default reporter, both JSON and PMD CPD-style XML reporters are available. Note that in the JSON example below, indentation and formatting has been applied. Furthermore, the id property available in these reporters is useful for parsing by automatic scripts to determine whether or not duplicate code has changed between builds.

JSON

[{
  "id":"6ceb36d5891732db3835c4954d48d1b90368a475",
  "instances":[
    {
      "path":"spec/fixtures/intersection.js",
      "lines":[1,5],
      "code":"function intersectionA(array1, array2) {\n  array1.filter(function(n) {\n    return array2.indexOf(n) != -1;\n  });\n}"
    },
    {
      "path":"spec/fixtures/intersection.js",
      "lines":[7,11],
      "code":"function intersectionB(arrayA, arrayB) {\n  arrayA.filter(function(n) {\n    return arrayB.indexOf(n) != -1;\n  });\n}"
    }
  ]
}]

PMD CPD XML

<?xml version="1.0" encoding="utf-8"?>
<pmd-cpd>
<duplication lines="10" id="6ceb36d5891732db3835c4954d48d1b90368a475">
<file path="/jsinspect/spec/fixtures/intersection.js" line="1"/>
<file path="/jsinspect/spec/fixtures/intersection.js" line="7"/>
<codefragment>
spec/fixtures/intersection.js:1,5
function intersectionA(array1, array2) {
  array1.filter(function(n) {
    return array2.indexOf(n) != -1;
  });
}

spec/fixtures/intersection.js:7,11
function intersectionB(arrayA, arrayB) {
  arrayA.filter(function(n) {
    return arrayB.indexOf(n) != -1;
  });
}
</codefragment>
</duplication>
</pmd-cpd>
Comments
  • pmd-cpd report

    pmd-cpd report

    A pmd-cpd reporter would be nice. I could hook this up to Jenkins and have it create graphs overtime of violations.

    Looking at a few outputs from other tools that I use, it looks like it needs to be in the format: <?xml version="1.0" encoding="utf-8"?> <pmd-cpd> <duplication lines="2" tokens="38"> <file path="file/path1.js" line="1373"/> <file path="file/path2.js" line="1389"/> <codefragment> XML Escaped Code Fragment </codefragment> </duplication> </pmd-cpd>

    opened by trichins 18
  • False positives when matching identifiers is not set

    False positives when matching identifiers is not set

    Hi, jsinspect produces false positives for a check with the linked 2 files, when the -i parameter is NOT set. I used the node level 30, 40 Looks like for function arguments that are callback functions the function code is not checked. best regards Armin

    https://github.com/agienger/issue_files/blob/master/jsinspect/callBack1.js https://github.com/agienger/issue_files/blob/master/jsinspect/callBack2.js

    opened by agienger 10
  • SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

    SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

    Hi, Daniel,

    I have just tried this on 2 projects, got identical error block like this:

    /usr/local/lib/node_modules/jsinspect/lib/inspector.js:10 class Inspector extends EventEmitter { ^^^^^

    SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode at exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:374:25) at Object.Module._extensions..js (module.js:417:10) at Module.load (module.js:344:32) at Function.Module._load (module.js:301:12) at Module.require (module.js:354:17) at require (internal/module.js:12:17) at Object. (/usr/local/lib/node_modules/jsinspect/bin/jsinspect:9:17) at Module._compile (module.js:410:26) at Object.Module._extensions..js (module.js:417:10)

    Not sure if this rule is over-enforced here. I have worked on 2 large existing ES6 projects. ES6 modules and classes are strict by default. Any chance you can take a look at this? Do you have a configuration entry that will suppress this error? Or a workaround?

    Thanks! William

    opened by williamku 8
  • Expose module additionally to binary

    Expose module additionally to binary

    Hey hey,

    just had a look on how to wrap jsinspect with a grunt task.

    In my mind, it would be much cleaner (and easier) if jsinspect would expose a binary and additionally a module, which makes it easier for other projects to use.

    Usually the binary is only for parsing arguments and handing it over to the module.

    E.g. a grunt task could spawn and child process using the binary, but an implemented module would be great.

    Please let me know, what you think of this.

    opened by stefanjudis 8
  • 0.11.4 false positive

    0.11.4 false positive

    0.11.4 is reporting the following duplication even though our threshold is set to 40 in the jsinspectrc. It wasn't reporting this false positive in 0.9:

    Match - 2 instances
    
    ./App/Containers/GuestJoinLayout.js:168,168
    </Animatable.View>
    
    ./App/Containers/SignInLayout.js:160,160
    </Animatable.View>
    
    ------------------------------------------------------------
    

    The relevant part of GuestJoinLayout.js:

     render () {
        return (
          <View style={Styles.container}>
            <View style={Styles.content}>
              <Animatable.View ref='content' animation='fadeInUp' duration={2000} ease='ease-in'>
                <LinearGradient
                  start={{x: 0.0, y: 0.0}} end={{x: 0.0, y: 1.0}}
                  locations={[0, 1]}
                  colors={['#074595', '#6589A4']}
                  style={Styles.signInContainer}
                >
                  {this.renderTitle()}
                  {this.renderMeetingId()}
                  {this.renderPasscode()}
                  {this.renderUsernameInput()}
                  {this.renderDropdown()}
                  {this.renderJoinButton()}
                  {/* this.renderSignIn() */}
                </LinearGradient>
              </Animatable.View>
            </View>
          </View>
        )
      }
    

    and SignInLayout.js:

    render () {
        return (
          <Animatable.View ref='container' style={Styles.container} easing='ease-in'>
            <LinearGradient
              start={{x: 0.0, y: 0.0}} end={{x: 0.0, y: 1.0}}
              locations={[0, 1]}
              colors={['#074595', '#6589A4']}
              style={Styles.blurOverlay}>
              <View style={Styles.content}>
                {this.renderLogo()}
                {this.renderErrorMessage()}
                {this.renderUsernameInput()}
                {this.renderPasswordInput()}
                {this.renderNextButton()}
                {this.renderSignInOptions()}
                {this.renderSignUp()}
              </View>
            </LinearGradient>
          </Animatable.View>
        )
      }
    
    opened by matthargett 6
  • Reexporting is not supported

    Reexporting is not supported

    I have this code:

    export * as util from './util';
    

    Checking of this files throws the type of null error I fixed it by refactoring:

    import * as util from './util';
    export { util };
    

    Anyway it will be great to fix it

    opened by timbset 6
  • Alternative parser

    Alternative parser

    I plan in creating a Vscode extension that provides in editor feedback for copy pasted code. The only problem i have is that i need to process code with Flowtype type annotations in it. I have been using flowparser package with great success previously since it produces output compatible with most of the other parsers and also works fine with tools such as Recast, Jscodeshift etc. Wondering if there is an easy way to make the parser configurable via options ? thanks.

    opened by gcazaciuc 5
  • GNU message format

    GNU message format

    Came across it at https://github.com/anandthakker/doiuse/issues/1

    Seems rather trivial in comparison to the current default format, to add support for this format style. Format specified https://www.gnu.org/prep/standards/html_node/Errors.html

    opened by paazmaya 5
  • ignore files in .gitignore ?

    ignore files in .gitignore ?

    is a good feature ignore the files and directories in .gitignore file ?

    normally .gitignore have files/directories like coverage, lib-cov, results, etc

    opened by juanpabloaj 4
  • throws error if run as npm script

    throws error if run as npm script

    When I run $ jsinspect <path> directly from the command line, it works as expected. However when I run it as an npm script ($ npm run jsinspect)

    "scripts": {
      "jsinspect": "jsinspect src/"
    },
    

    and matches are found, error is thrown:

     1 match found across 2 files
    
    npm ERR! Darwin 15.5.0
    npm ERR! argv "/Users/aborowski/.nvm/versions/node/v6.3.1/bin/node" "/Users/aborowski/.nvm/versions/node/v6.3.1/bin/npm" "run" "jsinspect"
    npm ERR! node v6.3.1
    npm ERR! npm  v3.10.3
    npm ERR! code ELIFECYCLE
    npm ERR! [email protected] jsinspect: `jsinspect src/`
    npm ERR! Exit status 1
    
    opened by adekbadek 3
  • Process out of memory

    Process out of memory

    I have a Windows 10 machine with 8 gb of RAM. First time I run jsinspect in one of my projects and I get this:

    $ jsinspect
    [
    <--- Last few GCs --->
    
      208383 ms: Scavenge 1402.4 (1457.2) -> 1402.4 (1457.2) MB, 15.8 / 0 ms (+ 2.0 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep].
      210220 ms: Mark-sweep 1402.4 (1457.2) -> 1401.4 (1456.2) MB, 1836.9 / 0 ms (+ 4.0 ms in 2 steps since start of marking, biggest step 2.0 ms) [last resort gc].
      211992 ms: Mark-sweep 1401.4 (1456.2) -> 1400.9 (1457.2) MB, 1771.8 / 0 ms [last resort gc].
    
    
    <--- JS stacktrace --->
    
    ==== JS stack trace =========================================
    
    Security context: 000003A02DCB4639 <JS Object>
        1: finishNode [C:\Users\miparnisari\AppData\Roaming\npm\node_modules\jsinspect\node_modules\acorn\dist\acorn_loose.js:~647] [pc=00000259F86AE55F] (this=000001850C2CBAB1 <a LooseParser with map 0000035629E4CA89>,node=0000010720CDDF69 <a Node with map 0000035629E4D6E9>,type=000000B68F9CC089 <String[16]: MemberExpression>)
        2: parseSubscripts [C:\Users\miparnisari\AppData\Roaming\npm\node...
    
    FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
    

    I am using these settings:

    {
      "threshold":     30,
      "identifiers":   true,
      "matches":       3,
      "ignore":        "Test.js|Spec.js",
      "jsx":           false,
      "reporter":      "json",
      "suppress":      100
    }
    

    EDIT: I used WindDirStat to know how many JS files there are: 23,540. It's a lot but I'm assuming that we are not scanning the files within .git or node_modules, right?

    opened by miparnisari 3
  • Is this project still maintained?

    Is this project still maintained?

    I really like this project and I'm an active user of jsinspect, it helps me improve my code quality, but I can not use it with newer JS and JSX features. As I see no changes were merged into the master branch already 2 years and some PRs with some updates to support new features are still waiting to be reviewed for at least one year. @danielstjules is this repo still maintained or you'd like to give to somebody else to take care of it?

    opened by micnic 3
  • Single line match reported when there is no match

    Single line match reported when there is no match

    Hi! Thanks for the awesome tool!

    The following blocks of code

    const query = new Query()
    // q (Keyword query)
      .addParam('q', queryToString(params.searchText, '+'))
    

    and

    const query = JobQueries.manageableQuery()
      .includeCompany()
    

    Together reported by jsinspect

    ------------------------------------------------------------
    Match - 2 instances
    
    ./service1.js:78,78
    const query = new Query()
    
    ./service2.js:316,316
    const query = JobQueries.manageableQuery()
    ------------------------------------------------------------
    

    Which apparently shouldn't happen.

    opened by elmeister 0
  • [feature request] support suffix other than .js or .jsx

    [feature request] support suffix other than .js or .jsx

    Hi Thanks for creating this brilliant tool. Our project is trying to use this tool, however we want to apply it to a script language defined by our own. It's syntax is a subset of JavaScript so the tool works well on the texts. The only problem is that we are using a suffix defined by ourself. Is it possible to let JsInspect accept an argument to include certain type of files? Thanks

    opened by JillShu 2
  • FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

    FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

    When i run the command jsinspect ./myfolder/ it results in out of memory issue.

    <--- Last few GCs --->

    [79346:0x103801600] 27292 ms: Mark-sweep 1369.3 (1445.8) -> 1358.1 (1447.3) MB, 959.0 / 0.2 ms (average mu = 0.122, current mu = 0.068) allocation failure scavenge might not succeed [79346:0x103801600] 28349 ms: Mark-sweep 1372.3 (1447.8) -> 1361.1 (1449.3) MB, 989.9 / 0.2 ms (average mu = 0.093, current mu = 0.063) allocation failure scavenge might not succeed

    <--- JS stacktrace --->

    ==== JS stack trace =========================================

    0: ExitFrame [pc: 0x3f21725be3d]
    

    Security context: 0x145d8079e6e1 1: _insert [0x145d574a83e1] [/usr/local/lib/node_modules/jsinspect/lib/inspector.js:~142] [pc=0x3f21791c0ad](this=0x145d9c582271 ,nodes=0x145d017f2309 <JSArray[30]>) 2: /* anonymous /(aka / anonymous */) [0x145d017ee941] [/usr/local/lib/node_modules/jsinspect/lib/inspector.js:64] [bytecode=0x145dabc68fb1 offset=11]...

    FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory 1: 0x10003ae75 node::Abort() [/usr/local/bin/node] 2: 0x10003b07f node::OnFatalError(char const*, char const*) [/usr/local/bin/node] 3: 0x1001a7ae5 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node] 4: 0x100572ef2 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/usr/local/bin/node] 5: 0x1005759c5 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/usr/local/bin/node] 6: 0x10057186f v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node] 7: 0x10056fa44 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node] 8: 0x10057c2dc v8::internal::Heap::AllocateRawWithLigthRetry(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node] 9: 0x10057c35f v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/usr/local/bin/node] 10: 0x10054b6f6 v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::Heap::RootListIndex, int, v8::internal::Object*, v8::internal::PretenureFlag) [/usr/local/bin/node] 11: 0x100690ffc v8::internal::DescriptorArray::Allocate(v8::internal::Isolate*, int, int, v8::internal::PretenureFlag) [/usr/local/bin/node] 12: 0x10068ba3e v8::internal::Map::EnsureDescriptorSlack(v8::internal::Handlev8::internal::Map, int) [/usr/local/bin/node] 13: 0x100697f09 v8::internal::Map::ShareDescriptor(v8::internal::Handlev8::internal::Map, v8::internal::Handlev8::internal::DescriptorArray, v8::internal::Descriptor*) [/usr/local/bin/node] 14: 0x1006838c4 v8::internal::Map::CopyAddDescriptor(v8::internal::Handlev8::internal::Map, v8::internal::Descriptor*, v8::internal::TransitionFlag) [/usr/local/bin/node] 15: 0x1006836e2 v8::internal::Map::CopyWithField(v8::internal::Handlev8::internal::Map, v8::internal::Handlev8::internal::Name, v8::internal::Handlev8::internal::FieldType, v8::internal::PropertyAttributes, v8::internal::PropertyConstness, v8::internal::Representation, v8::internal::TransitionFlag) [/usr/local/bin/node] 16: 0x100699f32 v8::internal::Map::TransitionToDataProperty(v8::internal::Handlev8::internal::Map, v8::internal::Handlev8::internal::Name, v8::internal::Handlev8::internal::Object, v8::internal::PropertyAttributes, v8::internal::PropertyConstness, v8::internal::Object::StoreFromKeyed) [/usr/local/bin/node] 17: 0x100664b38 v8::internal::LookupIterator::PrepareTransitionToDataProperty(v8::internal::Handlev8::internal::JSReceiver, v8::internal::Handlev8::internal::Object, v8::internal::PropertyAttributes, v8::internal::Object::StoreFromKeyed) [/usr/local/bin/node] 18: 0x10068a394 v8::internal::Object::AddDataProperty(v8::internal::LookupIterator*, v8::internal::Handlev8::internal::Object, v8::internal::PropertyAttributes, v8::internal::ShouldThrow, v8::internal::Object::StoreFromKeyed) [/usr/local/bin/node] 19: 0x1007f1459 v8::internal::Runtime::SetObjectProperty(v8::internal::Isolate*, v8::internal::Handlev8::internal::Object, v8::internal::Handlev8::internal::Object, v8::internal::Handlev8::internal::Object, v8::internal::LanguageMode) [/usr/local/bin/node] 20: 0x1007f4ca3 v8::internal::Runtime_SetProperty(int, v8::internal::Object**, v8::internal::Isolate*) [/usr/local/bin/node] 21: 0x3f21725be3d Abort trap: 6

    How to resolve this issue?

    opened by tonystark93 0
  • Consider different font colour for showing matching code blocks

    Consider different font colour for showing matching code blocks

    Just found jsinspect, and it's really cool. Great work. I wanted to mention one issue I found while using it. In my terminal (iTerm2) I use Solarized Dark for the colour theme (pretty common), and here is what the matching code blocks look like, (i.e., invisible):

    screen shot 2018-12-09 at 2 43 53 pm

    It might be good to consider just using the same colour you already use for the file/lines, since that shows up perfectly.

    opened by humphd 1
Releases(0.12.7)
Owner
Daniel St. Jules
Daniel St. Jules
Find and fix problems in your JavaScript code.

ESLint Website | Configuring | Rules | Contributing | Reporting Bugs | Code of Conduct | Twitter | Mailing List | Chat Room ESLint is a tool for ident

ESLint 21.9k Dec 31, 2022
Prettier is an opinionated code formatter.

Opinionated Code Formatter JavaScript · TypeScript · Flow · JSX · JSON CSS · SCSS · Less HTML · Vue · Angular GraphQL · Markdown · YAML Your favorite

Prettier 44.5k Dec 30, 2022
The JavaScript Code Quality Tool

JSLint, The JavaScript Code Quality Tool Douglas Crockford [email protected] 2019-03-15 jslint.js contains the jslint function. It parses and a

Douglas Crockford 3.5k Jan 6, 2023
🌟 JavaScript Style Guide, with linter & automatic code fixer

JavaScript Standard Style Sponsored by English • Español (Latinoamérica) • Français • Bahasa Indonesia • Italiano (Italian) • 日本語 (Japanese) • 한국어 (Ko

Standard JS 27.8k Dec 31, 2022
Pre-evaluate code at build-time with babel-macros

preval.macro This is a babel-plugin-macros macro for babel-plugin-preval. Please see those projects for more information. Installation This module is

Kent C. Dodds 118 Dec 16, 2022
For formatting, searching, and rewriting JavaScript.

jsfmt For formatting, searching, and rewriting JavaScript. Analogous to gofmt. Installation npm install -g jsfmt Usage $ jsfmt --help Usage: jsfmt [

Rdio 1.7k Dec 9, 2022
Detect copy-pasted and structurally similar code

Detect copy-pasted and structurally similar JavaScript code. Requires Node.js 6.0+, and supports ES6, JSX as well as Flow. Note: the project has been

Daniel St. Jules 3.5k Dec 26, 2022
A style export tool that live edits and exports code ready to copy / paste

Awesome Title Generator A style export tool that live edits and exports code ready to copy / paste. Features Edits text and live previews it CSS and R

Crhistian de Oliveira 19 Oct 7, 2022
Copy/paste detecting GitHub Action for programming source code (jscpd)

dry-code Copy/paste detecting GitHub Action for programming source code with jscpd Action inputs Action input Description Default Value Required optio

null 5 Dec 14, 2022
JSHint is a tool that helps to detect errors and potential problems in your JavaScript code

JSHint, A Static Code Analysis Tool for JavaScript [ Use it online • Docs • FAQ • Install • Contribute • Blog • Twitter ] JSHint is a community-driven

JSHint 8.8k Jan 2, 2023
blog with angular made in sass and firebase auth with google, facebook and github also you can copy to clipboard

BlogAngular This project was generated with Angular CLI version 14.1.2. Development server Run ng serve for a dev server. Navigate to http://localhost

John Gualteros 1 Oct 2, 2022
Lightweight library to copy PNG and JPG images to clipboard

Copy Image Clipboard Created with ❤️ by Luan Eduardo da Costa | Follow me on Linkedin ?? About This library allows you to copy JPG and PNG images (onl

Luan Eduardo da Costa 34 Nov 29, 2022
A collection of scripts to build offline documentation for your favourite frameworks/libraries. Simply search, copy/paste the commands and enjoy.

Offline-docs A collection of scripts to build offline documentation for your favourite frameworks/libraries. Simply search, copy/paste the commands an

Naveen Namani 37 Dec 24, 2022
Browser extension to copy the page title and URL as rich text.

Copy Rich Link Browser extension to copy the page title and URL as rich text. Useful for pasting links to Slack, Google Docs, etc. Usage Install Insta

Ryo Nakamura 19 Dec 17, 2022
Detect webpage updates and notify user to reload. support vite and umijs

English | 简体中文 plugin-web-update-notification Detect webpage updates and notify user to reload. support vite and umijs. Take the git commit hash as th

Utopia 57 Dec 26, 2022
mutate a copy of data without changing the original source

immutability-helper Mutate a copy of data without changing the original source Setup via NPM npm install immutability-helper --save This is a drop-in

Moshe Kolodny 5.1k Dec 29, 2022
Copy files

cpy Copy files Why Fast by using streams. Resilient by using graceful-fs. User-friendly by accepting globs and creating non-existent destination direc

Sindre Sorhus 380 Nov 15, 2022
Minecraft-classic - A working copy of the original classic.minecraft.net website.

minecraft-classic Just a copy of https://classic.minecraft.net/ (or at least as much as I could). This is a working copy of the Minecraft Classic webs

null 4 Oct 19, 2022
Emoji - Use emoji names instead of Unicode strings. Copy-pasting emoji sucks.

Grammy Emoji Adds emoji parsing for grammY. Check out the official documentation for this plugin. While this draft is working, we still do not recomme

null 8 Sep 5, 2022
NoPrint.js - Disable Print, Screenshot, Copy & Paste in HTML by JavaScript.

NoPrint.js Disable Print, Screenshot, Copy & Paste in HTML by JavaScript. NoPrint.js is a small and neat open source JS library that disables print, s

null 33 Dec 26, 2022