Giter Club home page Giter Club logo

fixclosure's Introduction

fixclosure

fixclosure is JavaScript dependency checker/fixer for Closure Library based on ECMAScript AST. It finds namespaces used in a JavaScript file and insert/remove goog.provide, goog.require, goog.requireType and goog.forwardDeclare automatically.

npm version Node.js Version Support Build Status License

Install

$ npm install fixclosure

Usage

The following code goog.require()s an unused namespace goog.unused, also goog.missing is used but not goog.require()d.

// foo.js (before)
goog.provide("goog.foo.Bar");

goog.require("goog.foo");
goog.require("goog.unused");

goog.foo.Bar = function () {
  goog.foo.baz();
  goog.missing.require();
};

Fix it !

$ npx fixclosure --fix-in-place --namespaces=goog.foo,goog.missing foo.js
File: foo.js

Provided:
- goog.foo.Bar

Required:
- goog.foo
- goog.unused

Missing Require:
- goog.missing

Unnecessary Require:
- goog.unused

FIXED!

Total: 1 files
Passed: 0 files
Fixed: 1 files

goog.require('goog.unused') is removed and goog.require('goog.missing') is inserted.

// foo.js (fixed)
goog.provide("goog.foo.Bar");

goog.require("goog.foo");
goog.require("goog.missing");

goog.foo.Bar = function () {
  goog.foo.baz();
  goog.missing.require();
};

Rules fixclosure checked

fixclosure checks and fixes:

  • Duplicated provide/require/requireType/forwardDeclare
  • Missing provide/require/requireType/forwardDeclare
  • Unnecessary provide/require/requireType/forwardDeclare

Globbing

The arguments are globbed by globby. Directories are expanded as **/*.js.

$ fixclosure path/to/dir "foo/bar-*.js"

Use with Grunt

Use grunt-fixclosure plugin.

Configuration file

fixclosure loads options from .fixclosurerc config file like:

--provideRoots foo,bar
--replaceMap foo.foobar:foo.foo
--useForwardDeclare

fixclosure will find the file in the current directory and, if not found, will move one level up the directory tree all the way up to the filesystem root.

Options

-f or --fix-in-place

If an invalid file is found, fixclosure fixes the file in place.

--config <file>

.fixclosurerc file path.
Specify if your file is not in the search path. Default: ${process.cwd()}/.fixclosurerc

--provideRoots <roots>

Specify your root namespaces to provide. Default is goog. Comma separated list.

--namespaces <namespaces>

Specify method or property exported as a namespace itself like goog.dispose.
Comma separated list.

--replaceMap <map>

Replace method or property to namespace mapping like goog.disposeAll:goog.dispose.
Comma separated list of colon separated pairs like foo.bar1:foo.bar2,foo.bar3:foo.bar4.

--useForwardDeclare

Use goog.forwardDeclare() instead of goog.requireType() for types used only in JSDoc. Default: false

--depsJs <files>

Load namespace methods from deps.js files separated by comma. You can generate deps.js with google-closure-deps or duck.

--showSuccess

Show not only failed files but also passed files.

--no-color

Disable color output.

Inline hint

fixclosure reads "hint" for lint from special comments in your code.

ignore

fixclosure doesn't remove any goog.provide and goog.require with this hint.

goog.provide("goog.foo"); // fixclosure: ignore

goog.require("goog.bar"); // fixclosure: ignore

In the above, goog.provide('goog.foo') will not removed by fixclosure even if it isn't provided in the file. Also goog.require('goog.bar') will not removed if it isn't used. The hint affects only same line. Useful in module declaration.

suppressRequire

Suppress goog.require auto insertion.

// fixclosure: suppressRequire
goog.foo.bar();

In the above, goog.require('goog.foo') will not inserted. The hint affects only next line. This is useful to workaround cyclic reference.

suppressProvide

Suppress goog.provide auto insertion.

// fixclosure: suppressProvide
goog.Foo = function () {};

In the above, goog.provide('goog.Foo') will not inserted. The hint affects only next line.

Migration from v1 to v2

  • Old Node.js versions were no longer supported, use Node.js v10 or higher.
  • --namespaceMethods was deprecated, use --namespaces.
  • Deprecated --roots was removed, use --provideRoots.
  • --requireRoots was removed because fixclosure v2 no longer detects required namespaces heuristically. Use --namespaces or --depsJs to detect them. They can detect the namespaces correctly.
  • Types used only in JSDoc are reported as errors, while previously only types of @extends in @interface are reported. Add goog.requireType() or goog.fowardDeclare().

License

MIT License: Teppei Sato [email protected]

fixclosure's People

Stargazers

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

Watchers

 avatar  avatar  avatar

fixclosure's Issues

A comment below an `@extends` tag invalidates requires

/**
 * @interface
 * @extends {goog.Foo}
 * I am a comment
 */

goog.Foo should be required, but it is not.

Likewise:

/**
 * @interface
 * @extends {goog.Foo}
 * @extends {goog.Foo2}
 * I am a comment
 * @extends {goog.Foo3}
 * @extends {goog.Foo4}
 */

Here goog.Foo is required, but none of the others are.

node-version

We are currently restricted to using a node version <10 since we are using gulp v3. Specifically, we are using node 8. We are currently using our own private fork of fixclosure to validate requires, and in that fork the node version is set to >=8, and it seems to work without any issues. Is there a specific reason you have set "node": ">=10"? Would you be ok with downgrading to "node": ">=8"?

Inline hint "fixclosure: ignore"

goog.provide('goog.undefined.in.this.file'); // fixclosure: ignore
goog.require('goog.unused.in.this.file'); // fixclosure: ignore

Merge with suppressUnused

fixclosure sometimes counts an object as 'toRequire'.

This test fails.

/**
 * @param {Element} e An click event.
 */
goog.Foo1.prototype.handleClick = function(e) {
  if (e.target && e.target.id == 'XX') { }
};

// toProvide: goog.Foo1

fixclosure reports Missing Require: e.target but we never want.

Don't require resources defined in the same file

This goog.dom.SavedRange.logger_ should not be goog.required.

goog.dom.SavedRange.logger_ =
    goog.debug.Logger.getLogger('goog.dom.SavedRange');

goog.dom.SavedRange.prototype.restore = function(opt_stayAlive) {
  goog.dom.SavedRange.logger_.severe(
      'Disposed SavedRange objects cannot be restored.');
  // ...
};

replaceMap contains wrong default values

The replaceMap contains a value from goog.disposeAll to goog.dispose. However, goog.disposable provides goog.disposeAll so it should not be changed to something different. Is the replaceMap relevant at all if you are using a deps file? I think it is a similar case to providedNamespaces which is now deprecated in favor of --depsJs.

Add option to ignore provides

Currently, we are not interested in changing provides. Fx, whether an enum on a class should be provided varies by case. Having an option to leave provides as they are would be nice.

.fixclosurerc merged incorrectly

When the command line options is merged with the config options, the argsOptions will have default values even if they are not set. So if I call fixclosure path/to/file, the argsOptions will have default values for --useForwardDeclare so it cannot be overridden from the .fixclosurerc file.
The --depsJs argument is parsed in a different way. It creates an array of namespaces based on the passed deps file. However, when the merged options object is created it will always use the one created from the argsOptions object even if that list is empty and the rcOptions contains correct namespaces.

Inconsistent output with README.md

I’ve tried fixclosure with a file that is the same as an example in README.md.
But the result was unexpected for me.
Am I missing something?

  • Input File
// foo.js (before)
goog.provide('goog.foo.Bar');

goog.require('goog.foo');
goog.require('goog.unused');

goog.foo.Bar = function() {
  goog.foo.baz();
  goog.missing.require();
};
  • Expected
File: foo.js

Provided:
- goog.foo.Bar

Required:
- goog.foo
- goog.unused

Missing Require:
- goog.missing

Unnecessary Require:
- goog.unused

FAIL!

Total: 1 files
Passed: 0 files
Failed: 1 files
  • Actual
File: foo.js

Provided:
- goog.foo.Bar

Required:
- goog.foo
- goog.unused

Unnecessary Require:
- goog.foo
- goog.unused

FAIL!

Total: 1 files
Passed: 0 files
Failed: 1 files

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.