Giter VIP home page Giter VIP logo

jshint-loader's Introduction

npm node deps tests chat

jshint-loader

A JSHint loader module for webpack. Runs JSHint on JavaScript files in a bundle at build-time.

Requirements

This module requires a minimum of Node v6.9.0 and Webpack v4.0.0.

Getting Started

To begin, you'll need to install jshint-loader:

$ npm install jshint-loader --save-dev

Then add the loader to your webpack config. For example:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /.js/,
        enforce: 'pre',
        exclude: /node_modules/,
        use: [
          {
            loader: `jshint-loader`,
            options: {...options}
          }
        ]
      }
    ]
  }
}

And run webpack via your preferred method.

Options

All valid JSHint options are valid on this object, in addition to the custom loader options listed below:

delete options.; delete options.; delete options.;

emitErrors

Type: Boolean Default: undefined

Instructs the loader to emit all JSHint warnings and errors as webpack errors.

failOnHint

Type: Boolean Default: undefined

Instructs the loader to cause the webpack build to fail on all JSHint warnings and errors.

reporter

Type: Function Default: undefined

A function used to format and emit JSHint warnings and errors.

Custom Reporter

By default, jshint-loader will provide a default reporter.

However, if you prefer a custom reporter, pass a function under the reporter property in jshint options. (see usage above)

The reporter function will be passed an array of errors/warnings produced by JSHint with the following structure:

[
{
    id:        [string, usually '(error)'],
    code:      [string, error/warning code],
    reason:    [string, error/warning message],
    evidence:  [string, a piece of code that generated this error]
    line:      [number]
    character: [number]
    scope:     [string, message scope;
                usually '(main)' unless the code was eval'ed]

    [+ a few other legacy fields that you don't need to worry about.]
},
// ...
// more errors/warnings
]

The reporter function will be excuted with the loader context as this. You may emit messages using this.emitWarning(...) or this.emitError(...). See webpack docs on loader context.

Note: JSHint reporters are not compatible with JSHint-loader! This is due to the fact that reporter input is only processed from one file; not multiple files. Error reporting in this manner differs from traditional reporters for JSHint since the loader plugin (i.e. JSHint-loader) is executed for each source file; and thus the reporter is executed for each file.

The output in webpack CLI will usually be:

...
WARNING in ./path/to/file.js
<reporter output>
...

`

Contributing

Please take a moment to read our contributing guidelines if you haven't yet done so.

License

jshint-loader's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jshint-loader's Issues

Request for a new release

Please publish a new release 0.8.5 that includes changes merged on Mar 13th (#38) (plus anything newer if need be). Thanks!

webpack-defaults upgrade

Addition of webpack-defaults & associated refactoring as a part of the next Major release

Issue exists for status tracking across the organization.

Please do not close

.jshintrc "overrides" option causes warning

I just started using jshint-loader with an existing .jshintrc file containing an overrides section:

{
  "curly": true,
  ...
  "devel": true,
  "node": true,
  "overrides": {
    "app/**/*.js": {
      "devel": false,
      "undef": true,
      "globals": {
        "angular": true,
        "module": true,
        "require": true
      }
    },
    "app/**/test/**/*.js": {
      "devel": true,
      "undef": true,
      "jasmine": true,
      "globals": {
        "module": true,
        "inject": true
      }
    }
  }
}

This works fine with jshint itself and many IDEs, but jshint-loader throws this warning:

WARNING in ./app/js/resources/resource.js
jshint results in errors
  Bad option: 'overrides'. @ line 0 char 0

Could this be supported by jshint-loader as well, since it's supported by jshint?

Environment:
webpack 1.13.2
jshint: 2.9.3
jshint-loader: 0.8.3
npm: 3.10.3
node: 6.3.1

Only changed file warnings

Hello everyone.

I have a big project on Webpack. And I trying to integrate jshint-loader. But I encountered some problems.
JSHint generates too many warning messages in the command line. And maybe exists such option in config, that show warnings only in a modified file.

For example, I have two files: index.js and app.js. I made some changes in the index.js file and I want to see only warnings from my index.js file. But I got warnings from both files instead.

Respect .jshintrc

Just wondering if the package can be updated to respect the .jshintrc file if it present.

As per there docs:

There are three main ways to configure your copy of JSHint: you can either specify the configuration file manually via the --config flag, use a special file .jshintrc or put your config into your projects package.json file under the jshintConfig property. In case of .jshintrc, JSHint will start looking for this file in the same directory as the file that's being linted.

This would be nice as other tools (like various IDE linters) look for this file and adjust the running errors accordingly.

Should show filename for JSHint warnings

JSHint via webpack doesn't seem to be showing which file an error occurred in, e.g.:

Running "webpack:desktop_debug" (webpack) task
                         Asset    Size  Chunks  Chunk Names
ripple-client-desktop-debug.js  606748       0  main       

WARNING in jshint results in errors
  Unnecessary semicolon. @ line 408 char 6
        };

Which file has that unnecessary semicolon?

v.0.1.3 dependency error

npm install jshint-loader
npm
ERR!
Error: No compatible version found: loader-utils@'>=0.9.0- <0.10.0-'```

Some globals are being ignored from .jshintrc

Bug Report

I have a project using ES Modules and do not want to support AMD / CommonJS. I can turn this off in the parser settings in Webpack but I want to have JSHint throw an error. If I set the option in my .jshintrc it is ignored.

Example:

// .jshintrc

{
  ...
  "globals": {
    "require": false,
    "define": false,
    "module": false,
    "exports": false
  }
}

// Source file: './index.js'

var myModule = require('my-module');

module.exports = ...

This does not emit an error or warning in the webpack build and I would expect it to.

Not reading my .jshintrc

I'm not sure what changed, but webpack seems to not be applying my .jshintrc anymore. When I change my .jshintrc to end with .json and require it in my webpack config on the jshint property, everything works as expected.

"emitErrors: true" still shows warnings

I am having the same problem as in this stackoverflow question: http://stackoverflow.com/questions/29510309/how-do-i-make-webpack-exit-with-an-error-when-jshint-emits-warnings

I have both "emitErrors" and "failOnHint" options set to true, but still getting only warnings, which results in successful build.

I am using [email protected].

Here is my full config file:

const webpack = require('webpack');
const conf = require('./conf');
const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer = require('autoprefixer');

module.exports = {
    module: {
        preLoaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'jshint'
            }
        ],
        loaders: [
            {
                test: /.json$/,
                loaders: [
                    'json'
                ]
            },
            {
                test: /\.(css|less)$/,
                loader: ExtractTextPlugin.extract({
                    fallbackLoader: 'style',
                    loader: 'css!less!postcss'
                })
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loaders: [
                    'babel',
                    'webpack-strip-block',
                    'ng-annotate',
                ]
            },
            {
                test: /.html$/,
                loaders: [
                    'html'
                ]
            },
            {
                test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
                loader: 'url?limit=10000',
            },
            {
                test: /\.(png|gif)$/,
                loader: "url-loader?limit=10000"
            },
            {
                test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
                loader: 'file',
            }
        ]
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin({name: 'vendor'}),
        new webpack.DefinePlugin({'process.env.ENV': JSON.stringify('prod')}),
        new webpack.ProvidePlugin({'moment': 'moment', 'humanizeDuration': 'humanize-duration'}),
        new webpack.optimize.OccurrenceOrderPlugin(),
        new HtmlWebpackPlugin({
            template: conf.path.src('index.html'),
            inject: true
        }),
        new ExtractTextPlugin('index-[contenthash].css')
    ],
    postcss: () => [autoprefixer],
    output: {
        path: path.join(process.cwd(), conf.paths.dist),
        filename: '[name]-[hash].js'
    },
    entry: {
        app: ['bootstrap-loader/extractStyles', `./${conf.path.src('index')}`],
        vendor: [
            "babel-polyfill",
            "angular",
            "angular-animate",
            "angular-loading-bar",
            "angular-timer",
            "angular-toastr",
            "angular-ui-bootstrap",
            "angular-ui-router",
            "humanize-duration",
            "moment",
            "moment-business",
            "ui-select",
            "underscore",
        ]
    },
    jshint: {
        emitErrors: true,
        failOnHint: true
    },
    failOnError: true,
    bail: true
};

And here is console log:

WARNING in ./src/app/components/common/navigation/Navigation.js
jshint results in errors
  Identifier 'test_asd' is not in camel case. @ line 16 char 25
                var test_asd = '123'

  Missing semicolon. @ line 16 char 33
                var test_asd = '123'
 @ ./src/app/components ^\.\/((?!components).)*\.js$
 @ ./src/app/components/components.js
 @ ./src/index.js
 @ multi app

WARNING in ./src/app/components/common/navigation/Navigation.js
Module build failed: Error: Module failed in cause of jshint error.
  at Object.jsHint (C:\www\enviam-esales\node_modules\jshint-loader\index.js:127:9)
  at Object.<anonymous> (C:\www\enviam-esales\node_modules\jshint-loader\index.js:146:11)
  at Object.<anonymous> (C:\www\enviam-esales\node_modules\jshint-loader\index.js:37:12)
  at respond (C:\www\enviam-esales\node_modules\rcloader\index.js:68:7)
  at respond (C:\www\enviam-esales\node_modules\rcfinder\index.js:140:7)
  at next (C:\www\enviam-esales\node_modules\rcfinder\index.js:167:16)
  at _combinedTickCallback (internal/process/next_tick.js:67:7)
  at process._tickCallback (internal/process/next_tick.js:98:9)

 @ ./src/app/components ^\.\/((?!components).)*\.js$
 @ ./src/app/components/components.js
 @ ./src/index.js
 @ multi app
Child html-webpack-plugin for "index.html":
         Asset     Size  Chunks       Chunk Names
    index.html  2.69 kB       0       
Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:

Child extract-text-webpack-plugin:
                                     Asset     Size  Chunks       Chunk Names
      f4769f9bdb7466be65088239c12046d1.eot  20.1 kB               
      89889688147bd7575d6327160d64e760.svg   109 kB               
      e18bbf611f2a2e43afc071aa2f4e1512.ttf  45.4 kB               
     fa2772327f55d8198301fdb8bcfc8158.woff  23.4 kB               
    448c34a56d699c29117adc64c43affeb.woff2    18 kB               

Done.

Process finished with exit code 0

Does not work on Node < 4.0.0

What kind of issue are you submitting?

  • Bug Report

  • jshint-loader version 0.8.4

#37 updated loader-utils to ^1.0.2. However, from v0.2.17 (webpack/loader-utils@4130dff) loader-utils started using ES6 features from node >= 4.0.0.

ERROR in /node_modules/jshint-loader/node_modules/loader-utils/lib/parseQuery.js:24
	queryArgs.forEach(arg => {
	                      ^^
Unexpected token =>

I believe this is a breaking change for everyone using Node < 4 (including iojs).

npm3+ error

I am getting the following warning from npm 2.14.1 when installing jshint-loader as a dependency:

npm WARN peerDependencies The peer dependency jshint@^2.5.0 included from jshint-loader will no
npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency 
npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.

rcloader.for outputting object instead of string

hi there. the loader didn't respect my .jshintrc, so i debugged it.
it appears, that the rcloader.for function does output an object instead of a string:

// console.log(this.resourcePath);
C:\xampp\htdocs\_www\frontend-webpack\src\js\main.js
// line 34
// var path = rcLoader.for(this.resourcePath);
// console.log(path);
{ '0': 'C',
  '1': ':',
  '2': '\\',
  '3': 'x',
  '4': 'a',
  '5': 'm',
  '6': 'p',
  '7': 'p',
  '8': '\\',
  '9': 'h',
  '10': 't',
  '11': 'd',
  '12': 'o',
  '13': 'c',
  '14': 's',
  '15': '\\',
  '16': '_',
  '17': 'w',
  '18': 'w',
  '19': 'w',
  '20': '\\',
  '21': 'f',
  '22': 'r',
  '23': 'o',
  '24': 'n',
  '25': 't',
  '26': 'e',
  '27': 'n',
  '28': 'd',
  '29': '-',
  '30': 'w',
  '31': 'e',
  '32': 'b',
  '33': 'p',
  '34': 'a',
  '35': 'c',
  '36': 'k',
  '37': '\\',
  '38': '.',
  '39': 'j',
  '40': 's',
  '41': 'h',
  '42': 'i',
  '43': 'n',
  '44': 't',
  '45': 'r',
  '46': 'c' }

anyone experiencing a similar issue?
my system:
win7 x64, nodejs 0.10.33
package.json:
"jshint-loader": "^0.8.1",

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.output.path: The provided value "./build/" is not an absolute path! -> The output directory as **absolute path** (required).

My webpack.config.js file

module.exports={
entry:['./app/index.js'],
output:{
path:'./build/',
filename:'bundle.js'
}
}

And getting this error

C:\Users\Hafiz Musaddiq Babar\Desktop\es6>npm run build

[email protected] build C:\Users\Hafiz Musaddiq Babar\Desktop\es6
webpack

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.

  • configuration.output.path: The provided value "./build/" is not an absolute path!
    -> The output directory as absolute path (required).
    npm ERR! code ELIFECYCLE
    npm ERR! errno 1
    npm ERR! [email protected] build: webpack
    npm ERR! Exit status 1
    npm ERR!
    npm ERR! Failed at the [email protected] build script.
    npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Hafiz Musaddiq Babar\AppData\Roaming\npm-cache_logs\2018-09-12T02_45_23_508Z-debug.log

Pass a path to .jshintrc

Hi guys,

Is there a way to pass a path to .jshintrc?

The structure of my app has recently changed so i'm now requiring files in sibling folders to the initial project. Webpack is respecting this setup with some resolve options, but it seems that the jshint-loader is always looking for .jshintrc in the root of the project it's importing from at the time.

| - A
| |- node_modules
| |- app
| |- .jshintrc
|
| - B
| |- app
| 
| - C
| |- app

In this instance as the jshint-loader goes to bundle a dependency in B it'll look for a .jshintrc in the root of B and not resolve back to A's .jshintrc

Ideally I don't want to duplicate the same .jshintrc file across multiple projects.

Any suggestions appreciated!

jshint-loader not working with webpack 4

In webpack 4 in the presence of packages jslint and jshint-loader error on the similarity of such:

ERROR in ./src/js/index.js
Module build failed: TypeError: Cannot read property 'jshint' of undefined
    at Object.jsHint (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\jshint-loader\index.js:63:18)
    at Object.<anonymous> (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\jshint-loader\index.js:149:11)
    at Object.<anonymous> (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\jshint-loader\index.js:40:12)
    at respond (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\rcloader\index.js:68:7)
    at respond (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\rcfinder\index.js:140:7)
    at next (D:\Harrix\GitHub\Harrix-HTML-Template\node_modules\rcfinder\index.js:164:16)
    at process._tickCallback (internal/process/next_tick.js:112:11)

Example of rule:

{ // this is both for prod and dev environments
      enforce: 'pre',
      test: /\.js$/,
      include: path.resolve(__dirname, 'src'),
      use: [{ loader: 'jshint-loader' }]
    },

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.

I believe the documentation is incorrect, as the code example gives an error.

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration has an unknown property 'jshint'. These properties are valid:
   object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
   For typos: please correct them.
   For loader options: webpack 2 no longer allows custom properties in configuration.
     Loaders should be updated to allow passing options via loader options in module.rules.
     Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
     plugins: [
       new webpack.LoaderOptionsPlugin({
         // test: /\.xxx$/, // may apply this only for some modules
         options: {
           jshint: ...
         }
       })
     ]

What kind of issue are you submitting?
Bug Report

Please tell us your

  • Webpack version 3.8.1
  • jshint-loader version 0.8.4
  • jshint version Whichever jshint-loader installs
  • OS OSX

Use this configuration and run webpack:

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: './js/init.js',
  watch: true,
  output: {
    path: path.resolve(__dirname, 'js'),
    filename: 'init.min.js'
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: [/node_modules/],
        query: {
          presets: ['es2015'],
          plugins: ["transform-object-assign", "transform-runtime"]
        }
      }
    ],
    rules: [
      {
        test: /\.js$/, // include .js files
        enforce: "pre", // preload the jshint loader
        exclude: /node_modules/, // exclude any and all files in the node_modules folder
        use: [
          {
            loader: "jshint-loader"
          }
        ],
      }
    ]
  },
  jshint: {
    // any jshint option http://www.jshint.com/docs/options/
    // i. e.
    camelcase: true,

    // jshint errors are displayed by default as warnings
    // set emitErrors to true to display them as errors
    emitErrors: false,

    // jshint to not interrupt the compilation
    // if you want any file with jshint errors to fail
    // set failOnHint to true
    failOnHint: false,

    // custom reporter function
    reporter: function(errors) { }
  },
  stats: {
    colors: true
  },
  //devtool: 'source-map'
};

support loading jshint rules from package.json

jshint supports loading config from package.json. This however, does not work with jshint-loader.

A workaround in webpack.config can be used as below:

jshint: require('./package.json').jshintConfig

Any change this can be supported in loader itself?

Hints are not visible with failOnHint == true

Hi, thanks for the great package!

The failOnHint option is very handy for me, because it prevents people from shipping production builds with errors. Although, when the build fails due to a hint, I am unable to see the hint (not very convenient for solving the problem :)

10% 0/1 build modulesModuleBuildError: Module build failed: Error: Module failed in cause of jshint error.
    at Object.jsHint (/var/app/node_modules/jshint-loader/index.js:127:9)
    at Object.<anonymous> (/var/app/node_modules/jshint-loader/index.js:146:11)
    at /var/app/node_modules/jshint-loader/index.js:52:5
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)
    at DependenciesBlock.onModuleBuildFailed (/var/app/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:315:19)
    at nextLoader (/var/app/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:270:31)
    at /var/app/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:292:15
    at context.callback (/var/app/node_modules/webpack/node_modules/webpack-core/lib/NormalModuleMixin.js:148:14)
    at Object.<anonymous> (/var/app/node_modules/jshint-loader/index.js:149:11)
    at /var/app/node_modules/jshint-loader/index.js:52:5
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:380:3)

Am I missing any config options?
Thanks!

loader exclude not working with resolve config?

I can't seem to get exclude loader option to work. Perhaps I'm not doing it right?

My webpack config is the following:

    resolve: {

        root: __dirname + "/client/",

        modulesDirectories: ["node_modules", "bower_components"],

        alias: {
            jquery: 'jquery/dist/jquery.js'
        }
    },

    module: {
        loaders: [
            // Used for reactjs
            { test: /\.jsx$/, loader: "jsx-loader" }
        ],

        postLoaders: [
            {
                // test: "\\.js$",
                test: /\.js$/, // include .js files
                exclude: ["bower_components", "node_modules"], // exclude more files
                loader: "jshint-loader"
            }
        ]
    },
//...

Output:

Hash: eb15878a99f7ada4bab9
Version: webpack 1.3.1-beta4
Time: 2350ms
 Asset    Size  Chunks             Chunk Names
app.js  257615       0  [emitted]  main
   [0] ./client/app.js 791 {0} [built]
   [1] ./bower_components/jquery/dist/jquery.js 247351 {0} [built] [1 warning]
       cjs require jquery [0] ./client/app.js 10:4-21

WARNING in ./bower_components/jquery/dist/jquery.js
jshint results in errors
...

I'd like to ignore ./bower_components/jquery/dist/jquery.js for jshinting.

Add tests & setup travis

Need add tests and setup travis. We should probably look into what other loaders are using and keep it consistent. html-loader looks like a nice example.

Module build failed: Error: Cannot find module 'jshint'

Hello,
I use webpack 3.8, and i can't use the given configuration as I have error "Module build failed: Error: Cannot find module 'jshint'".
Nevertheless, the directory "jshint-loader" is in node_modules... Any ideas ? :)

The code I use:

module: {
rules: [
{
test: /.(jsx|js)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
options: {
presets: ["es2017", "stage-0", "react", ],
plugins: ["transform-decorators-legacy"]
}
}, {
loader: 'jshint-loader'
}]
}
Thanks,
Dorian

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.