diff --git a/.gitignore b/.gitignore index ad46b30..02bf73d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,61 +1,8 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories +coverage/ +index-es5.js +index-es5.js.map node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env - -# next.js build output -.next +.nyc_output/ +package-lock.json +temp.js +temp.js.map diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7818ff3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - 10 + - 12 + - node +script: npm run ci diff --git a/README.md b/README.md index bddfeda..68deaa1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,43 @@ -# is-dom-element2 -Determine if an object is an HTMLElement (from any Realm). +# is-dom-element [![NPM Version][npm-image]][npm-url] ![File Size][filesize-image] [![Build Status][travis-image]][travis-url] [![Coverage Status][coveralls-image]][coveralls-url] [![Dependency Monitor][greenkeeper-image]][greenkeeper-url] + +> Determine if an object is an `HTMLElement` (from any `Realm`). + + +## Installation + +[Node.js](http://nodejs.org) `>= 10` is required. To install, type this at the command line: +```shell +npm install is-dom-element +``` + + +## Importing + +ES Module: +```js +import isDOMElement from 'is-dom-element'; +``` + +CommonJS Module: +```js +const isDOMElement = require('is-dom-element'); +``` + + +## Usage + +```js +isDOMElement(document.createElement('div')); //-> true +isDOMElement(document.createTextNode('content')); //-> false +```` + + +[npm-image]: https://img.shields.io/npm/v/is-dom-element.svg +[npm-url]: https://npmjs.com/package/is-dom-element +[filesize-image]: https://img.shields.io/badge/size-390B%20gzipped-blue.svg +[travis-image]: https://img.shields.io/travis/stevenvachon/is-dom-element2.svg +[travis-url]: https://travis-ci.org/stevenvachon/is-dom-element2 +[coveralls-image]: https://img.shields.io/coveralls/stevenvachon/is-dom-element2.svg +[coveralls-url]: https://coveralls.io/github/stevenvachon/is-dom-element2 +[greenkeeper-image]: https://badges.greenkeeper.io/stevenvachon/is-dom-element2.svg +[greenkeeper-url]: https://greenkeeper.io/ diff --git a/index.js b/index.js new file mode 100644 index 0000000..f665e9d --- /dev/null +++ b/index.js @@ -0,0 +1,5 @@ +import isDOMNode from "is-dom"; + +const ELEMENT_NODE = 1; // https://mdn.io/Node/nodeType + +export default element => isDOMNode(element) && element.nodeType===ELEMENT_NODE; diff --git a/package.json b/package.json new file mode 100644 index 0000000..6a0fe92 --- /dev/null +++ b/package.json @@ -0,0 +1,69 @@ +{ + "name": "is-dom-element", + "description": "Determine if an object is an HTMLElement (from any Realm).", + "version": "1.0.0", + "license": "MIT", + "author": "Steven Vachon (https://svachon.com)", + "repository": "github:stevenvachon/is-dom-element2", + "main": "index-es5.js", + "dependencies": { + "is-dom": "^1.1.0" + }, + "devDependencies": { + "@babel/cli": "^7.5.0", + "@babel/core": "^7.5.0", + "@babel/preset-env": "^7.5.0", + "babel-plugin-add-module-exports": "^1.0.2", + "chai": "^4.2.0", + "coveralls": "^3.0.4", + "gzip-size-cli": "^3.0.0", + "mocha": "^6.1.4", + "npm-watch": "~0.6.0", + "nyc": "^14.1.1", + "parcel": "^1.12.3", + "puppeteer": "^1.18.1", + "puppeteer-to-istanbul": "^1.2.2", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">= 10" + }, + "scripts": { + "build": "npm run build-release && npm run build-size && npm run build-test", + "build-release": "babel index.js --out-file=index-es5.js --plugins=add-module-exports --presets=@babel/env --source-maps", + "build-size": "parcel build index-es5.js --experimental-scope-hoisting --global=isDOMElement --log-level=1 --no-cache --out-dir='.' --out-file=temp.js --public-url='.' && gzip-size temp.js && rimraf temp.js", + "build-test": "parcel build index-es5.js --global=isDOMElement --log-level=1 --no-cache --out-dir='.' --out-file=temp.js --public-url='.'", + "build:watch": "npm-watch build", + "ci": "npm run test && nyc report --reporter=text-lcov | coveralls", + "posttest": "nyc report --reporter=text-summary --reporter=html && rimraf temp.js temp.js.map", + "prepublishOnly": "npm test", + "pretest": "npm run build", + "test": "nyc --silent mocha test.js --bail --check-leaks --timeout=5000", + "test:watch": "npm-watch test" + }, + "watch": { + "build": { + "inherit": true, + "patterns": [ + "index.js" + ] + }, + "test": { + "inherit": true, + "patterns": [ + "index.js", + "test.js" + ] + } + }, + "files": [ + "index.js", + "index-es5.js", + "index-es5.js.map" + ], + "keywords": [ + "dom", + "element", + "node" + ] +} diff --git a/test.js b/test.js new file mode 100644 index 0000000..bdc94b9 --- /dev/null +++ b/test.js @@ -0,0 +1,113 @@ +"use strict"; +const {after, before, it} = require("mocha"); +const puppeteer = require("puppeteer"); +const puppeteerCoverage = require("puppeteer-to-istanbul"); + +const runInBrowser = func => () => page.evaluate(func); + +let browser, page; + + + +// @todo also use npmjs.com/puppeteer-firefox +before(async () => +{ + browser = await puppeteer.launch({ args: ["--no-sandbox"] }); + page = await browser.newPage(); + + page.on("console", async msg => console[msg._type](...await Promise.all(msg.args().map(arg => arg.jsonValue())))); + page.on("pageerror", console.error); + + await Promise.all( + [ + page.addScriptTag({ path: "node_modules/chai/chai.js" }), + page.addScriptTag({ path: "temp.js" }), + + // @todo https://github.com/istanbuljs/puppeteer-to-istanbul/issues/18 + // @todo https://github.com/GoogleChrome/puppeteer/issues/3570 + page.coverage.startJSCoverage({ reportAnonymousScripts: true }) + ]); + + await page.evaluate(() => + { + const iframe = document.createElement("iframe"); + document.body.append(iframe); + window.anotherRealm = iframe.contentWindow; + window.anotherDocument = anotherRealm.document; + + window.expect = chai.expect; + delete window.chai; // cleanup + }); +}); + + + +after(async () => +{ + let coverage = await page.coverage.stopJSCoverage(); + + // Exclude tools + coverage = coverage.filter(({url}) => !url.includes("chai")); + + puppeteerCoverage.write(coverage); + + browser.close(); +}); + + + +it("is a (bundled) function", runInBrowser(() => +{ + expect(window.isDOMElement).to.be.a("function"); +})); + + + +it("returns false for a non-HTMLElement", runInBrowser(() => +{ + const fixtures = + [ + "Node", + Symbol("Node"), + {}, + [], + /regex/, + true, + 1, + null, + undefined, + window, + anotherRealm, + document, + document.createComment("data"), + document.createDocumentFragment(), + document.createProcessingInstruction("target", "data"), + document.createTextNode("data"), + document.implementation.createDocument("namespaceURI", "qualifiedNameStr"), + document.implementation.createDocument("namespaceURI", "qualifiedNameStr").createCDATASection("data"), + document.implementation.createDocumentType("qualifiedNameStr", "publicId", "systemId"), + document.implementation.createHTMLDocument("title"), + anotherDocument, + anotherDocument.createComment("data"), + anotherDocument.createDocumentFragment(), + anotherDocument.createProcessingInstruction("target", "data"), + anotherDocument.createTextNode("data"), + anotherDocument.implementation.createDocument("namespaceURI", "qualifiedNameStr"), + anotherDocument.implementation.createDocument("namespaceURI", "qualifiedNameStr").createCDATASection("data"), + anotherDocument.implementation.createDocumentType("qualifiedNameStr", "publicId", "systemId"), + anotherDocument.implementation.createHTMLDocument("title") + ]; + + fixtures.forEach(fixture => expect(isDOMElement(fixture)).to.be.false); +})); + + + +it("returns true for an HTMLElement", runInBrowser(() => +{ + ["a", "b", "div"].forEach(tagName => + { + expect(isDOMElement(document.createElement(tagName))).to.be.true; + expect(isDOMElement(anotherDocument.createElement(tagName))).to.be.true; + }); +}));