this zero-dependency package will provide browser-compatible versions of jslint (v2020.7.2) and csslint (v2018.2.25), with working web-demo
npm install jslint-lite
 


| git-branch : | master | beta | alpha|
|--:|:--|:--|:--|
| test-server-github : |  |  | |
| test-server-heroku : |  |  | |
| test-report : |  |  | |
| coverage : |  |  | |
| build-artifacts : |  |  | |


#### cli help
!screenshot
#### changelog 2020.10.27
- jslint - update to v2020.10.21
- jslint - add nullish-coalescing support
- jslint - add optional-chaining support
- jslint - require macro "!!jslint_utility2":true to conditionally-autofix .json file
- none
#### todo
- jslint - unmangle function jslintAutofixLocalFunction
- jslint - improve test-coverage
- jslint - jslint embedded template-strings
- none
#### additional info
- csslint code derived from https://github.com/CSSLint
- jslint code derived from https://github.com/douglascrockford/JSLint
shell
example.sh
this shell script will download and run web-demo of jslint-lite as standalone app
1. download standalone app
curl -O https://kaizhu256.github.io/node-jslint-lite/build..beta..travis-ci.com/app/assets.app.js
2. run standalone app
PORT=8081 node ./assets.app.js
3. open browser to http://127.0.0.1:8081 and play with web-demo
4. edit file assets.app.js to suit your needs
`#### output from browser

#### output from shell
!screenshot
quickstart example.js
#### to run this example, follow instruction in script below
- example.js
`javascript
/*
example.jsthis script will run web-demo of jslint-lite
instruction
1. save this script as example.js
2. run shell-command:
$ npm install jslint-lite && \
PORT=8081 node example.js
3. open browser to http://127.0.0.1:8081 and play with web-demo
4. edit this script to suit your needs
*/
/ istanbul instrument in package jslint /
// assets.utility2.header.js - start
/ jslint utility2:true /
/ istanbul ignore next /
// run shared js-env code - init-local
(function () {
"use strict";
let isBrowser;
let isWebWorker;
let local;
// polyfill globalThis
if (!(typeof globalThis === "object" && globalThis)) {
if (typeof window === "object" && window && window.window === window) {
window.globalThis = window;
}
if (typeof global === "object" && global && global.global === global) {
global.globalThis = global;
}
}
// init debugInline
if (!globalThis.debugInline) {
let consoleError;
consoleError = console.error;
globalThis.debugInline = function (...argList) {
/*
* this function will both print to stderr
* and return [0]
*/
consoleError("\n\ndebugInline");
consoleError(...argList);
consoleError("\n");
return argList[0];
};
}
// init isBrowser
isBrowser = (
typeof globalThis.XMLHttpRequest === "function"
&& globalThis.navigator
&& typeof globalThis.navigator.userAgent === "string"
);
// init isWebWorker
isWebWorker = (
isBrowser && typeof globalThis.importScripts === "function"
);
// init function
function objectDeepCopyWithKeysSorted(obj) {
/*
* this function will recursively deep-copy with keys sorted
*/
let sorted;
if (typeof obj !== "object" || !obj) {
return obj;
}
// recursively deep-copy list with child-keys sorted
if (Array.isArray(obj)) {
return obj.map(objectDeepCopyWithKeysSorted);
}
// recursively deep-copy obj with keys sorted
sorted = {};
Object.keys(obj).sort().forEach(function (key) {
sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
});
return sorted;
}
function assertJsonEqual(aa, bb) {
/*
* this function will assert JSON.stringify() === JSON.stringify()
*/
aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa));
bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb));
if (aa !== bb) {
throw new Error(JSON.stringify(aa) + " !== " + JSON.stringify(bb));
}
}
function assertOrThrow(passed, msg) {
/*
* this function will throw if is falsy
*/
if (passed) {
return;
}
throw (
(
msg
&& typeof msg.message === "string"
&& typeof msg.stack === "string"
)
// if msg is err, then leave as is
? msg
: new Error(
typeof msg === "string"
// if msg is string, then leave as is
? msg
// else JSON.stringify(msg)
: JSON.stringify(msg, undefined, 4)
)
);
}
function coalesce(...argList) {
/*
* this function will coalesce null, undefined, or "" in
*/
let arg;
let ii;
ii = 0;
while (ii < argList.length) {
arg = argList[ii];
if (arg !== undefined && arg !== null && arg !== "") {
return arg;
}
ii += 1;
}
return arg;
}
function identity(val) {
/*
* this function will return
*/
return val;
}
function nop() {
/*
* this function will do nothing
*/
return;
}
function objectAssignDefault(tgt = {}, src = {}, depth = 0) {
/*
* this function will if items from are null, undefined, or "",
* then overwrite them with items from
*/
let recurse;
recurse = function (tgt, src, depth) {
Object.entries(src).forEach(function ([
key, bb
]) {
let aa;
aa = tgt[key];
if (aa === undefined || aa === null || aa === "") {
tgt[key] = bb;
return;
}
if (
depth !== 0
&& typeof aa === "object" && aa && !Array.isArray(aa)
&& typeof bb === "object" && bb && !Array.isArray(bb)
) {
recurse(aa, bb, depth - 1);
}
});
};
recurse(tgt, src, depth | 0);
return tgt;
}
function onErrorThrow(err) {
/*
* this function will throw if exists
*/
if (err) {
throw err;
}
}
// bug-workaround - throw unhandledRejections in node-process
if (
typeof process === "object" && process
&& typeof process.on === "function"
&& process.unhandledRejections !== "strict"
) {
process.unhandledRejections = "strict";
process.on("unhandledRejection", function (err) {
throw err;
});
}
// init local
local = {};
local.local = local;
globalThis.globalLocal = local;
local.assertJsonEqual = assertJsonEqual;
local.assertOrThrow = assertOrThrow;
local.coalesce = coalesce;
local.identity = identity;
local.isBrowser = isBrowser;
local.isWebWorker = isWebWorker;
local.nop = nop;
local.objectAssignDefault = objectAssignDefault;
local.objectDeepCopyWithKeysSorted = objectDeepCopyWithKeysSorted;
local.onErrorThrow = onErrorThrow;
}());
// assets.utility2.header.js - end
/ jslint utility2:true /
(function (local) {
"use strict";
// run shared js-env code - init-before
(function () {
// init local
local = (
globalThis.utility2_rollup
|| globalThis.utility2_jslint
|| require("jslint-lite")
);
// init exports
globalThis.local = local;
}());
/ istanbul ignore next /
// run browser js-env code - init-test
(function () {
if (!local.isBrowser) {
return;
}
// log stderr and stdout to #outputStdout1
["error", "log"].forEach(function (key) {
let elem;
let fnc;
elem = document.querySelector("#outputStdout1");
if (!elem) {
return;
}
fnc = console[key];
console[key] = function (...argList) {
fnc(...argList);
// append text to #outputStdout1
elem.textContent += argList.map(function (arg) {
return (
typeof arg === "string"
? arg
: JSON.stringify(arg, undefined, 4)
);
}).join(" ").replace((
/\u001b\[\d*m/g
), "") + "\n";
// scroll textarea to bottom
elem.scrollTop = elem.scrollHeight;
};
});
local.objectAssignDefault(local, globalThis.domOnEventDelegateDict);
globalThis.domOnEventDelegateDict = local;
}());
/ istanbul ignore next /
// run node js-env code - init-test
(function () {
if (local.isBrowser) {
return;
}
// init exports
module.exports = local;
// init assetsDict
local.assetsDict = local.assetsDict || {};
/ jslint ignore:start /
local.assetsDict["/assets.index.template.html"] = '\
\n\
\n\
\n\
\n\
\n\
\n\
{{env.npm_package_name}} ({{env.npm_package_version}}) \n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
{{env.npm_package_name}} ({{env.npm_package_version}})\n\
\n\
\n\
{{env.npm_package_description}}
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
\n\
[\n\
this app was created with\n\
href="https://github.com/kaizhu256/node-utility2" target="_blank"\n\
>utility2\n\
]\n\
\n\
\n\
\n\
';
/ jslint ignore:end /
local.assetsDict["/assets.jslint.js"] = (
local.assetsDict["/assets.jslint.js"]
|| require("fs").readFileSync(
require("path").resolve(local.__dirname + "/lib.jslint.js"),
"utf8"
).replace((
/^#!\//
), "// ")
);
/ validateLineSortedReset /
local.assetsDict["/"] = local.assetsDict[
"/assets.index.template.html"
].replace((
/\{\{env\.(\w+?)\}\}/g
), function (match0, match1) {
switch (match1) {
case "npm_package_description":
return "the greatest app in the world!";
case "npm_package_name":
return "jslint-lite";
case "npm_package_nameLib":
return "jslint";
case "npm_package_version":
return "0.0.1";
default:
return match0;
}
});
local.assetsDict["/assets.example.html"] = local.assetsDict["/"];
// init cli
if (module !== require.main || globalThis.utility2_rollup) {
return;
}
local.assetsDict["/assets.example.js"] = (
local.assetsDict["/assets.example.js"]
|| require("fs").readFileSync(__filename, "utf8")
);
local.assetsDict["/favicon.ico"] = local.assetsDict["/favicon.ico"] || "";
local.assetsDict["/index.html"] = local.assetsDict["/"];
// if $npm_config_timeout_exit exists,
// then exit this process after $npm_config_timeout_exit ms
if (Number(process.env.npm_config_timeout_exit)) {
setTimeout(process.exit, Number(process.env.npm_config_timeout_exit));
}
// start server
if (globalThis.utility2_serverHttp1) {
return;
}
process.env.PORT = process.env.PORT || "8081";
console.error("http-server listening on port " + process.env.PORT);
require("http").createServer(function (req, res) {
let data;
data = local.assetsDict[require("url").parse(req.url).pathname];
if (data !== undefined) {
res.end(data);
return;
}
res.statusCode = 404;
res.end();
}).listen(process.env.PORT);
}());
}());
`#### output from browser

#### output from shell
!screenshot
extra screenshots
1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.buildCi.browser.%252F.tmp%252Fbuild%252Fapidoc.html.png
1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.buildCi.browser.%252F.tmp%252Fbuild%252Fcoverage.lib.html.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.buildCi.browser.%252F.tmp%252Fbuild%252Ftest-report.html.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.deployGithub.browser.%252Fnode-jslint-lite%252Fbuild%252Fapp.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.deployGithubTest.browser.%252Fnode-jslint-lite%252Fbuild%252Fapp.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.deployHeroku.browser.%252F.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.deployHerokuTest.browser.%252F.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.npmTest.browser.%252F.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.testExampleJs.browser.%252F.png

1. https://kaizhu256.github.io/node-jslint-lite/build/screenshot.testExampleSh.browser.%252F.png

package.json
`json
{
"!!jslint_utility2": true,
"author": "kai zhu ",
"bin": {
"jslint-lite": "lib.jslint.js"
},
"description": "this zero-dependency package will provide browser-compatible versions of jslint (v2020.7.2) and csslint (v2018.2.25), with working web-demo",
"devDependencies": {
"utility2": "kaizhu256/node-utility2#alpha"
},
"engines": {
"node": ">=12.0"
},
"fileCount": 16,
"homepage": "https://github.com/kaizhu256/node-jslint-lite",
"keywords": [
"csslint",
"jslint"
],
"license": "MIT",
"main": "lib.jslint.js",
"name": "jslint-lite",
"nameAliasPublish": "csslint-lite kslint",
"nameLib": "jslint",
"nameOriginal": "jslint-lite",
"repository": {
"type": "git",
"url": "https://github.com/kaizhu256/node-jslint-lite.git"
},
"scripts": {
"build-ci": "./npm_scripts.sh",
"env": "env",
"eval": "./npm_scripts.sh",
"heroku-postbuild": "./npm_scripts.sh",
"postinstall": "./npm_scripts.sh",
"start": "./npm_scripts.sh",
"test": "./npm_scripts.sh",
"utility2": "./npm_scripts.sh"
},
"version": "2020.10.27"
}
`
changelog of last 50 commits

internal build script
- build_ci.sh
`shell
build_ci.sh
this shell script will run build-ci for this package
shBuildCiAfter () {(set -e
# shDeployCustom
shDeployGithub
shDeployHeroku
shReadmeTest example.sh
)}
shBuildCiBefore () {(set -e
shNpmTestPublished
shReadmeTest example.js
)}
run shBuildCi
eval "$(utility2 source)"
shBuildCi
``