├── mock
├── tls.js
├── empty.js
├── tty.js
├── net.js
├── buffer.js
├── punycode.js
├── console.js
├── dns.js
└── process.js
├── example
├── esm
│ ├── browserify.mjs
│ ├── rollup.html
│ ├── esbuild.html
│ ├── webpack.html
│ ├── browserify.html
│ ├── vite
│ │ ├── index.html
│ │ └── vite.config.mjs
│ ├── esbuild.mjs
│ ├── webpack.config.mjs
│ ├── rollup.config.mjs
│ └── index.mjs
├── cjs
│ ├── esbuild.html
│ ├── rollup.html
│ ├── webpack.html
│ ├── browserify.html
│ ├── vite
│ │ ├── index.html
│ │ └── vite.config.js
│ ├── webpack.config.js
│ ├── browserify.js
│ ├── esbuild.js
│ ├── rollup.config.js
│ └── index.js
├── README.md
└── package.json
├── .npmrc
├── .browserslistrc
├── test
├── .eslintrc
└── index.js
├── .huskyrc
├── proxy
├── process
│ └── browser.js
├── querystring.js
├── process.js
└── url.js
├── .nycrc
├── helpers
├── esbuild
│ ├── shim.src.js
│ └── plugin.js
├── webpack
│ └── plugin.js
└── rollup
│ └── plugin.js
├── .lintstagedrc
├── types
└── lib.d.ts
├── .editorconfig
├── .gitignore
├── .babelrc
├── .prettierrc
├── tsconfig.json
├── .github
└── workflows
│ └── ci.yml
├── LICENSE.md
├── .eslintrc
├── CHANGELOG.md
├── index.js
├── rollup.config.js
├── package.json
└── README.md
/mock/tls.js:
--------------------------------------------------------------------------------
1 | // Todo
2 |
--------------------------------------------------------------------------------
/example/esm/browserify.mjs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/mock/empty.js:
--------------------------------------------------------------------------------
1 | export default null;
2 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | last 3 major versions
2 | since 2019
3 | not ie <= 10
4 |
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["eslint-config-niksy/tests"]
3 | }
4 |
--------------------------------------------------------------------------------
/.huskyrc:
--------------------------------------------------------------------------------
1 | {
2 | "hooks": {
3 | "pre-commit": "lint-staged"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/mock/tty.js:
--------------------------------------------------------------------------------
1 | function noop() {}
2 |
3 | export { noop as isatty, noop as setRawMode };
4 |
--------------------------------------------------------------------------------
/proxy/process/browser.js:
--------------------------------------------------------------------------------
1 | import api from '../process.js';
2 |
3 | export default api;
4 |
5 | export * from '../process.js';
6 |
--------------------------------------------------------------------------------
/.nycrc:
--------------------------------------------------------------------------------
1 | {
2 | "statements": 80,
3 | "lines": 0,
4 | "reporter": ["html", "text"],
5 | "sourceMap": false,
6 | "instrument": false
7 | }
8 |
--------------------------------------------------------------------------------
/helpers/esbuild/shim.src.js:
--------------------------------------------------------------------------------
1 | import { Buffer } from 'buffer';
2 | import process from 'process';
3 |
4 | const _global = globalThis;
5 |
6 | export { Buffer, process, _global as global };
7 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.js": ["eslint --fix"],
3 | "*.(md|json|yml)": ["prettier --ignore-path .gitignore --write"],
4 | ".!(npm|browserslist)*rc": [
5 | "prettier --ignore-path .gitignore --parser json --write"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/mock/net.js:
--------------------------------------------------------------------------------
1 | function noop() {}
2 | function bool() {
3 | return true;
4 | }
5 |
6 | export {
7 | noop as createServer,
8 | noop as createConnection,
9 | noop as connect,
10 | bool as isIP,
11 | bool as isIPv4,
12 | bool as isIPv6
13 | };
14 |
--------------------------------------------------------------------------------
/mock/buffer.js:
--------------------------------------------------------------------------------
1 | function Buffer() {
2 | throw new Error('Buffer is not included.');
3 | }
4 | Buffer.isBuffer = function () {
5 | return false;
6 | };
7 |
8 | const INSPECT_MAX_BYTES = 50;
9 |
10 | export { INSPECT_MAX_BYTES, Buffer as SlowBuffer, Buffer };
11 |
--------------------------------------------------------------------------------
/types/lib.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'querystring-es3' {
2 | import { decode, encode, parse, stringify } from 'querystring';
3 | export { decode, encode, parse, stringify };
4 | };
5 |
6 | declare module 'process/browser.js' {
7 | const process: NodeJS.Process;
8 | export = process;
9 | };
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [{package.json,*.yml}]
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | package-lock.json
4 | yarn.lock
5 | npm-debug.log
6 | .nyc_output/
7 | coverage/
8 | cjs/
9 | esm/
10 | !test/fixtures/node_modules/
11 | !example/cjs
12 | !example/esm
13 | example/cjs/*.dist.js
14 | example/cjs/vite/dist
15 | example/esm/*.dist.js
16 | example/esm/vite/dist
17 | helpers/esbuild/shim.js
18 |
--------------------------------------------------------------------------------
/example/cjs/esbuild.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | esbuild, CommonJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/cjs/rollup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Rollup, CommonJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/cjs/webpack.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Webpack, CommonJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/esm/rollup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Rollup, ES Modules
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/esm/esbuild.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | esbuild, ES Modules
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/esm/webpack.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Webpack, ES Modules
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/cjs/browserify.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Browserify, CommonJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/esm/browserify.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Browserify, ES Modules
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/esm/vite/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite, ES Modules
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/cjs/vite/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Vite, CommonJS
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/mock/punycode.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {string} s
3 | */
4 | function passthrough(s) {
5 | return s;
6 | }
7 |
8 | const ucs2 = {
9 | encode: passthrough,
10 | decode: passthrough
11 | };
12 |
13 | const version = '0.0.0';
14 |
15 | export {
16 | ucs2,
17 | version,
18 | passthrough as encode,
19 | passthrough as decode,
20 | passthrough as toUnicode,
21 | passthrough as toASCII
22 | };
23 |
--------------------------------------------------------------------------------
/helpers/webpack/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const webpack = require('webpack');
4 |
5 | const nodeProtocolRegex = /^node:/;
6 |
7 | function NodeProtocolUrlPlugin() {
8 | return new webpack.NormalModuleReplacementPlugin(
9 | nodeProtocolRegex,
10 | (resource) => {
11 | resource.request = resource.request.replace(nodeProtocolRegex, '');
12 | }
13 | );
14 | }
15 |
16 | module.exports.NodeProtocolUrlPlugin = NodeProtocolUrlPlugin;
17 |
--------------------------------------------------------------------------------
/mock/console.js:
--------------------------------------------------------------------------------
1 | const _console = globalThis.console ?? {};
2 |
3 | const consoleApi = {
4 | log: 1,
5 | info: 1,
6 | error: 1,
7 | warn: 1,
8 | dir: 1,
9 | trace: 1,
10 | assert: 1,
11 | time: 1,
12 | timeEnd: 1
13 | };
14 |
15 | /** @typedef {keyof consoleApi} ConsoleApi */
16 |
17 | for (const property in consoleApi) {
18 | if (!_console[/** @type {ConsoleApi} */ (property)]) {
19 | _console[/** @type {ConsoleApi} */ (property)] = function () {};
20 | }
21 | }
22 |
23 | export default _console;
24 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false,
7 | "loose": true
8 | }
9 | ]
10 | ],
11 | "plugins": ["babel-plugin-transform-globalthis"],
12 | "overrides": [
13 | {
14 | "test": ["./index.js", "./test/index.js"],
15 | "presets": [
16 | [
17 | "@babel/preset-env",
18 | {
19 | "modules": false,
20 | "loose": true,
21 | "targets": {
22 | "node": "10"
23 | }
24 | }
25 | ]
26 | ]
27 | }
28 | ],
29 | "env": {
30 | "test": {
31 | "plugins": ["babel-plugin-istanbul"]
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/mock/dns.js:
--------------------------------------------------------------------------------
1 | /* globals unknown */
2 |
3 | /**
4 | * @param {unknown[]} arguments_
5 | */
6 | const api = function (...arguments_) {
7 | if (arguments_.length === 0) {
8 | return;
9 | }
10 | const callback = arguments_[arguments_.length - 1];
11 | if (typeof callback === 'function') {
12 | callback(null, '0.0.0.0');
13 | }
14 | };
15 |
16 | export {
17 | api as lookup,
18 | api as resolve4,
19 | api as resolve6,
20 | api as resolveCname,
21 | api as resolveMx,
22 | api as resolveNs,
23 | api as resolveTxt,
24 | api as resolveSrv,
25 | api as resolveNaptr,
26 | api as reverse,
27 | api as resolve
28 | };
29 |
--------------------------------------------------------------------------------
/example/esm/vite/vite.config.mjs:
--------------------------------------------------------------------------------
1 | import { createRequire } from 'module';
2 | import inject from '@rollup/plugin-inject';
3 | import stdLibBrowser from '../../../esm/index.js';
4 |
5 | const require = createRequire(import.meta.url);
6 | const esbuildShim = require.resolve('../../../helpers/esbuild/shim');
7 |
8 | export default {
9 | resolve: {
10 | alias: stdLibBrowser
11 | },
12 | optimizeDeps: {
13 | include: ['buffer', 'process']
14 | },
15 | plugins: [
16 | {
17 | ...inject({
18 | global: [esbuildShim, 'global'],
19 | process: [esbuildShim, 'process'],
20 | Buffer: [esbuildShim, 'Buffer']
21 | }),
22 | enforce: 'post'
23 | }
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 80,
3 | "tabWidth": 4,
4 | "useTabs": true,
5 | "semi": true,
6 | "singleQuote": true,
7 | "quoteProps": "preserve",
8 | "jsxSingleQuote": true,
9 | "trailingComma": "none",
10 | "bracketSpacing": true,
11 | "bracketSameLine": false,
12 | "arrowParens": "always",
13 | "requirePragma": false,
14 | "insertPragma": false,
15 | "proseWrap": "always",
16 | "htmlWhitespaceSensitivity": "css",
17 | "vueIndentScriptAndStyle": false,
18 | "endOfLine": "lf",
19 | "embeddedLanguageFormatting": "auto",
20 | "overrides": [
21 | {
22 | "files": ["package.json", "*.yml"],
23 | "options": {
24 | "useTabs": false,
25 | "tabWidth": 2
26 | }
27 | }
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/example/cjs/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const { NodeProtocolUrlPlugin } = require('../../helpers/webpack/plugin.js');
4 | const stdLibraryBrowser = require('../../cjs/index.js');
5 |
6 | module.exports = {
7 | mode: 'none',
8 | entry: './cjs/index.js',
9 | output: {
10 | library: 'stdLibBrowser',
11 | libraryTarget: 'umd',
12 | filename: 'webpack.dist.js',
13 | path: __dirname
14 | },
15 | resolve: {
16 | alias: stdLibraryBrowser
17 | },
18 | plugins: [
19 | new NodeProtocolUrlPlugin(),
20 | new webpack.ProvidePlugin({
21 | process: stdLibraryBrowser.process,
22 | Buffer: stdLibraryBrowser.buffer
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/example/cjs/browserify.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const browserify = require('browserify');
4 | const aliasify = require('aliasify');
5 | const stdLibBrowser = require('../../cjs/index.js');
6 |
7 | const b = browserify([path.resolve(__dirname, 'index.js')], {
8 | standalone: 'stdLibBrowser',
9 | transform: [[aliasify, { aliases: stdLibBrowser }]],
10 | insertGlobalVars: {
11 | process: () => {
12 | return `require('${stdLibBrowser.process}')`;
13 | },
14 | Buffer: () => {
15 | return `require('${stdLibBrowser.buffer}').Buffer`;
16 | }
17 | }
18 | });
19 |
20 | b.bundle().pipe(
21 | fs.createWriteStream(path.resolve(__dirname, 'browserify.dist.js'))
22 | );
23 |
--------------------------------------------------------------------------------
/example/cjs/vite/vite.config.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/dynamic-import-chunkname */
2 |
3 | const inject = require('@rollup/plugin-inject');
4 |
5 | const esbuildShim = require.resolve('../../../helpers/esbuild/shim');
6 |
7 | module.exports = async () => {
8 | const { default: stdLibBrowser } = await import('../../../esm/index.js');
9 | return {
10 | resolve: {
11 | alias: stdLibBrowser
12 | },
13 | optimizeDeps: {
14 | include: ['buffer', 'process']
15 | },
16 | plugins: [
17 | {
18 | ...inject({
19 | global: [esbuildShim, 'global'],
20 | process: [esbuildShim, 'process'],
21 | Buffer: [esbuildShim, 'Buffer']
22 | }),
23 | enforce: 'post'
24 | }
25 | ]
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "lib": ["ESNext", "DOM"],
6 | "moduleResolution": "node",
7 | "allowSyntheticDefaultImports": true,
8 | "esModuleInterop": true,
9 | "resolveJsonModule": true,
10 | "noEmit": true,
11 | "newLine": "lf",
12 | "strict": true,
13 | "noPropertyAccessFromIndexSignature": true,
14 | "noEmitOnError": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "allowJs": true,
17 | "checkJs": true,
18 | "skipLibCheck": true
19 | },
20 | "include": [
21 | "index.js",
22 | "lib/**/*.js",
23 | "proxy/**/*.js",
24 | "mock/**/*.js",
25 | "test/**/*.js",
26 | "types/**/*.ts",
27 | "helpers/**/plugin.js"
28 | ]
29 | }
30 |
--------------------------------------------------------------------------------
/example/cjs/esbuild.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const esbuild = require('esbuild');
3 | const plugin = require('../../helpers/esbuild/plugin.js');
4 | const stdLibBrowser = require('../../cjs/index.js');
5 |
6 | (async () => {
7 | try {
8 | await esbuild.build({
9 | entryPoints: [path.resolve(__dirname, 'index.js')],
10 | outfile: path.resolve(__dirname, 'esbuild.dist.js'),
11 | bundle: true,
12 | format: 'iife',
13 | globalName: 'stdLibBrowser',
14 | inject: [path.resolve(__dirname, '../../helpers/esbuild/shim.js')],
15 | define: {
16 | global: 'global',
17 | process: 'process',
18 | Buffer: 'Buffer'
19 | },
20 | plugins: [plugin(stdLibBrowser)]
21 | });
22 | } catch (error) {
23 | // Handled
24 | }
25 | })();
26 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | - push
4 | - pull_request
5 | jobs:
6 | Test:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node-version:
11 | - 10
12 | - 12
13 | - 16
14 | steps:
15 | - name: Clone repository
16 | uses: actions/checkout@v2
17 |
18 | - name: Use Node ${{ matrix.node-version }}
19 | uses: actions/setup-node@v2
20 | with:
21 | node-version: ${{ matrix.node-version }}
22 |
23 | - name: Install dependencies
24 | run: npm install
25 |
26 | - name: Lint
27 | run: npm run lint
28 |
29 | - name: Check types
30 | run: npm run lint:types
31 |
32 | - name: Test
33 | run: npm test
34 |
--------------------------------------------------------------------------------
/proxy/querystring.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @typedef {import('querystring').escape} qsEscape
3 | * @typedef {import('querystring').unescape} qsUnescape
4 | */
5 |
6 | import { decode, encode, parse, stringify } from 'querystring-es3';
7 |
8 | /**
9 | * @type {qsEscape}
10 | */
11 | function qsEscape(string) {
12 | return encodeURIComponent(string);
13 | }
14 |
15 | /**
16 | * @type {qsUnescape}
17 | */
18 | function qsUnescape(string) {
19 | return decodeURIComponent(string);
20 | }
21 |
22 | const api = {
23 | decode,
24 | encode,
25 | parse,
26 | stringify,
27 | escape: qsEscape,
28 | unescape: qsUnescape
29 | };
30 |
31 | export default api;
32 |
33 | export {
34 | decode,
35 | encode,
36 | parse,
37 | stringify,
38 | qsEscape as escape,
39 | qsUnescape as unescape
40 | };
41 |
--------------------------------------------------------------------------------
/example/esm/esbuild.mjs:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { fileURLToPath } from 'url';
3 | import esbuild from 'esbuild';
4 | import plugin from '../../helpers/esbuild/plugin.js';
5 | import stdLibBrowser from '../../esm/index.js';
6 |
7 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
8 |
9 | (async () => {
10 | try {
11 | await esbuild.build({
12 | entryPoints: [path.resolve(__dirname, 'index.mjs')],
13 | outfile: path.resolve(__dirname, 'esbuild.dist.js'),
14 | bundle: true,
15 | format: 'iife',
16 | globalName: 'stdLibBrowser',
17 | inject: [path.resolve(__dirname, '../../helpers/esbuild/shim.js')],
18 | define: {
19 | global: 'global',
20 | process: 'process',
21 | Buffer: 'Buffer'
22 | },
23 | plugins: [plugin(stdLibBrowser)]
24 | });
25 | } catch (error) {
26 | // Handled
27 | }
28 | })();
29 |
--------------------------------------------------------------------------------
/example/esm/webpack.config.mjs:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { fileURLToPath } from 'url';
3 | import webpack from 'webpack';
4 | import { NodeProtocolUrlPlugin } from '../../helpers/webpack/plugin.js';
5 | import stdLibBrowser from '../../esm/index.js';
6 |
7 | export default {
8 | mode: 'none',
9 | entry: './esm/index.mjs',
10 | output: {
11 | library: 'stdLibBrowser',
12 | libraryTarget: 'umd',
13 | filename: 'webpack.dist.js',
14 | path: path.dirname(fileURLToPath(import.meta.url))
15 | },
16 | resolve: {
17 | alias: stdLibBrowser
18 | },
19 | module: {
20 | rules: [
21 | {
22 | test: /\.m?js$/,
23 | resolve: {
24 | fullySpecified: false
25 | }
26 | }
27 | ]
28 | },
29 | plugins: [
30 | new NodeProtocolUrlPlugin(),
31 | new webpack.ProvidePlugin({
32 | process: stdLibBrowser.process,
33 | Buffer: stdLibBrowser.buffer
34 | })
35 | ]
36 | };
37 |
--------------------------------------------------------------------------------
/helpers/rollup/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('rollup')} rollup
5 | * @typedef {import('rollup').WarningHandlerWithDefault} rollup.WarningHandlerWithDefault
6 | */
7 |
8 | /**
9 | * @type {rollup.WarningHandlerWithDefault}
10 | */
11 | function handleCircularDependancyWarning(warning, warningHandler) {
12 | const packagesWithCircularDependencies = [
13 | 'util/',
14 | 'assert/',
15 | 'readable-stream/',
16 | 'crypto-browserify/'
17 | ];
18 | if (
19 | !(
20 | warning.code === 'CIRCULAR_DEPENDENCY' &&
21 | packagesWithCircularDependencies.some((modulePath) => {
22 | if (typeof warning.importer !== 'string') {
23 | return false;
24 | }
25 | return warning.importer.includes(modulePath);
26 | })
27 | )
28 | ) {
29 | warningHandler(warning);
30 | }
31 | }
32 |
33 | module.exports.handleCircularDependancyWarning =
34 | handleCircularDependancyWarning;
35 |
--------------------------------------------------------------------------------
/example/esm/rollup.config.mjs:
--------------------------------------------------------------------------------
1 | import resolve from '@rollup/plugin-node-resolve';
2 | import commonjs from '@rollup/plugin-commonjs';
3 | import json from '@rollup/plugin-json';
4 | import alias from '@rollup/plugin-alias';
5 | import inject from '@rollup/plugin-inject';
6 | import stdLibBrowser from '../../esm/index.js';
7 | import { handleCircularDependancyWarning } from '../../helpers/rollup/plugin.js';
8 |
9 | export default {
10 | input: './esm/index.mjs',
11 | output: [
12 | {
13 | file: 'esm/rollup.dist.js',
14 | format: 'umd',
15 | name: 'stdLibBrowser',
16 | exports: 'auto',
17 | sourcemap: 'inline'
18 | }
19 | ],
20 | plugins: [
21 | alias({
22 | entries: stdLibBrowser
23 | }),
24 | resolve({
25 | browser: true
26 | }),
27 | commonjs(),
28 | json(),
29 | inject({
30 | process: stdLibBrowser.process,
31 | Buffer: [stdLibBrowser.buffer, 'Buffer']
32 | })
33 | ],
34 | onwarn: (warning, rollupWarn) => {
35 | handleCircularDependancyWarning(warning, rollupWarn);
36 | }
37 | };
38 |
--------------------------------------------------------------------------------
/example/cjs/rollup.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { default: resolve } = require('@rollup/plugin-node-resolve');
4 | const commonjs = require('@rollup/plugin-commonjs');
5 | const json = require('@rollup/plugin-json');
6 | const alias = require('@rollup/plugin-alias');
7 | const inject = require('@rollup/plugin-inject');
8 | const stdLibBrowser = require('../../cjs/index.js');
9 | const {
10 | handleCircularDependancyWarning
11 | } = require('../../helpers/rollup/plugin.js');
12 |
13 | module.exports = {
14 | input: './cjs/index.js',
15 | output: [
16 | {
17 | file: 'cjs/rollup.dist.js',
18 | format: 'umd',
19 | name: 'stdLibBrowser',
20 | exports: 'auto',
21 | sourcemap: 'inline'
22 | }
23 | ],
24 | plugins: [
25 | alias({
26 | entries: stdLibBrowser
27 | }),
28 | resolve({
29 | browser: true
30 | }),
31 | commonjs(),
32 | json(),
33 | inject({
34 | process: stdLibBrowser.process,
35 | Buffer: [stdLibBrowser.buffer, 'Buffer']
36 | })
37 | ],
38 | onwarn: (warning, rollupWarn) => {
39 | handleCircularDependancyWarning(warning, rollupWarn);
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/helpers/esbuild/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * @typedef {import('../../')} Packages
5 | * @typedef {import('esbuild').Plugin} esbuild.Plugin
6 | */
7 |
8 | const { promisify } = require('util');
9 | const browserResolve = require('browser-resolve');
10 |
11 | const pBrowserResolve = promisify(browserResolve);
12 |
13 | const plugin = (
14 | /** @type {Packages | {[key: string]: string}} */ stdLibBrowser
15 | ) => {
16 | /** @type {esbuild.Plugin} */
17 | const main = {
18 | name: 'node-stdlib-browser-alias',
19 | async setup(build) {
20 | const map = new Map();
21 | const promises = Object.entries(stdLibBrowser).map(
22 | async ([name, path]) => {
23 | // @ts-ignore
24 | const resolvedPath = await pBrowserResolve(path, {});
25 | map.set(name, resolvedPath);
26 | }
27 | );
28 | await Promise.all(promises);
29 |
30 | map.forEach((path, name) => {
31 | build.onResolve({ filter: new RegExp(`^${name}$`) }, () => {
32 | return {
33 | path
34 | };
35 | });
36 | });
37 | }
38 | };
39 | return main;
40 | };
41 |
42 | module.exports = plugin;
43 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) Ivan Nikolić Copyright (c) Tobias Koppers
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7 | the Software, and to permit persons to whom the Software is furnished to do so,
8 | subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": [
4 | "eslint-config-niksy",
5 | "eslint-config-niksy/typescript",
6 | "eslint-config-niksy/next",
7 | "eslint-config-prettier"
8 | ],
9 | "plugins": ["eslint-plugin-prettier", "eslint-plugin-unicorn"],
10 | "globals": {
11 | "globalThis": false
12 | },
13 | "settings": {
14 | "jsdoc": {
15 | "preferredTypes": ["esbuild"]
16 | }
17 | },
18 | "rules": {
19 | "prettier/prettier": 1,
20 | "camelcase": 0,
21 | "unicorn/prefer-flat-map": 0,
22 | "unicorn/prevent-abbreviations": [
23 | 1,
24 | {
25 | "allowList": {
26 | "stdLibBrowser": true
27 | }
28 | }
29 | ]
30 | },
31 | "ignorePatterns": ["helpers/esbuild/shim.js", "example/**/*"],
32 | "overrides": [
33 | {
34 | "files": "mock/*.js",
35 | "env": {
36 | "browser": true
37 | }
38 | },
39 | {
40 | "files": ["rollup.config.js", "helpers/**/plugin.js"],
41 | "parserOptions": {
42 | "sourceType": "script"
43 | },
44 | "rules": {
45 | "no-console": 0
46 | }
47 | },
48 | {
49 | "files": ["rollup.config.js", "test/index.js"],
50 | "plugins": ["eslint-plugin-unicorn"],
51 | "rules": {
52 | "unicorn/numeric-separators-style": 0
53 | }
54 | }
55 | ]
56 | }
57 |
--------------------------------------------------------------------------------
/mock/process.js:
--------------------------------------------------------------------------------
1 | /* globals unknown */
2 |
3 | import path from 'path';
4 |
5 | function noop() {}
6 | /**
7 | * @param {unknown[]} arguments_
8 | */
9 | function nextTick(...arguments_) {
10 | const [function_] = arguments_;
11 | arguments_.shift();
12 | setTimeout(function () {
13 | if (typeof function_ === 'function') {
14 | function_.apply(null, arguments_);
15 | }
16 | }, 0);
17 | }
18 |
19 | /**
20 | * @param {unknown} name
21 | */
22 | function binding(name) {
23 | throw new Error('No such module. (Possibly not yet loaded)');
24 | }
25 |
26 | const features = {};
27 | const platformName = 'browser';
28 | const pid = 1;
29 | const browser = true;
30 | const environment = {};
31 | /** @type {string[]} */
32 | const argv = [];
33 |
34 | let cwd = '/';
35 | function getCwd() {
36 | return cwd;
37 | }
38 | /**
39 | * @param {string} dir
40 | */
41 | function getChdir(dir) {
42 | cwd = path.resolve(dir, cwd);
43 | }
44 |
45 | export {
46 | features,
47 | nextTick,
48 | pid,
49 | browser,
50 | environment as env,
51 | argv,
52 | binding,
53 | getCwd as cwd,
54 | getChdir as chdir,
55 | noop as exit,
56 | noop as kill,
57 | noop as umask,
58 | noop as dlopen,
59 | noop as uptime,
60 | noop as memoryUsage,
61 | noop as uvCounters,
62 | platformName as platform,
63 | platformName as arch,
64 | platformName as execPath,
65 | platformName as title
66 | };
67 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # Bundler output test
2 |
3 | This directory servers as minimal reproducible configuration for build with
4 | various bundlers.
5 |
6 | Run `npm install && npm run build`, and then:
7 |
8 | - `npm run build:webpack:cjs` - Run Webpack config as CommonJS module
9 | - `npm run build:rollup:cjs` - Run Rollup config as CommonJS module
10 | - `npm run build:esbuild:cjs` - Run esbuild build as CommonJS module
11 | - `npm run build:browserify:cjs` - Run Browserify build as CommonJS module
12 | - `npm run build:webpack:esm` - Run Rollup config as ES module
13 | - `npm run build:rollup:esm` - Run Rollup config as ES module
14 | - `npm run build:esbuild:esm` - Run esbuild build as ES module
15 | - `npm run build:browserify:esm` - Run Browserify build as ES module
16 | - `npm run open:webpack:cjs` - Open generated bundle from Webpack CommonJS
17 | configuration
18 | - `npm run open:rollup:cjs` - Open generated bundle from Rollup CommonJS
19 | configuration
20 | - `npm run open:esbuild:cjs` - Open generated bundle from esbuild CommonJS
21 | build
22 | - `npm run open:browserify:cjs` - Open generated bundle from Browserify
23 | CommonJS build
24 | - `npm run open:webpack:esm` - Open generated bundle from Webpack ES module
25 | configuration
26 | - `npm run open:rollup:esm` - Open generated bundle from Rollup ES module
27 | configuration
28 | - `npm run open:esbuild:esm` - Open generated bundle from esbuild ES module
29 | build
30 | - `npm run open:browserify:esm` - Open generated bundle from Browserify ES
31 | module build
32 |
33 | In each opened HTML file you can see each module output inside browser console.
34 | Each module is accessible from `stdLibBrowser` global property.
35 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## [Unreleased][]
4 |
5 | ## [1.3.1][] - 2025-02-04
6 |
7 | ### Changed
8 |
9 | - Update `crypto-browserify`
10 | ([#41](https://github.com/niksy/node-stdlib-browser/pull/41))
11 |
12 | ## [1.3.0][] - 2024-11-21
13 |
14 | ### Changed
15 |
16 | - Pin `domain-browser` to 4.22.0
17 | - Add `require` check for path resolver
18 | - Proxy `process` with additional exports
19 | ([#34](https://github.com/niksy/node-stdlib-browser/pull/34))
20 |
21 | ## [1.2.1][] - 2024-09-16
22 |
23 | ### Added
24 |
25 | - Support information and instructions for Vite
26 | - Update dependencies
27 |
28 | ## [1.2.0][] - 2021-12-08
29 |
30 | ### Added
31 |
32 | - Support for `node:` protocol in Webpack
33 | ([#12](https://github.com/niksy/node-stdlib-browser/issues/12))
34 | - Rollup warning helper function
35 |
36 | ## [1.1.0][] - 2021-11-16
37 |
38 | ### Added
39 |
40 | - Note regarding `URL` and `URLSearchParams` polyfilling
41 | - Support for esbuild
42 |
43 | ### Changed
44 |
45 | - Improve Rollup global variable injecting
46 | - Use `path.resolve` for URL methods
47 |
48 | ### Fixed
49 |
50 | - `url.format` to handle `URL`
51 |
52 | ## [1.0.0][] - 2021-11-13
53 |
54 | ### Added
55 |
56 | - Initial implementation
57 |
58 | [1.0.0]: https://github.com/niksy/node-stdlib-browser/tree/v1.0.0
59 | [1.1.0]: https://github.com/niksy/node-stdlib-browser/tree/v1.1.0
60 | [1.2.0]: https://github.com/niksy/node-stdlib-browser/tree/v1.2.0
61 | [Unreleased]: https://github.com/niksy/node-stdlib-browser/compare/v1.3.1...HEAD
62 | [1.3.1]: https://github.com/niksy/node-stdlib-browser/compare/v1.3.0...v1.3.1
63 | [1.3.0]: https://github.com/niksy/node-stdlib-browser/compare/v1.2.1...v1.3.0
64 | [1.2.1]: https://github.com/niksy/node-stdlib-browser/tree/v1.2.1
65 |
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "build": "cd .. && npm run build",
4 | "build:webpack:cjs": "webpack --config ./cjs/webpack.config.js",
5 | "build:webpack:esm": "webpack --config ./esm/webpack.config.mjs",
6 | "build:rollup:cjs": "rollup --config ./cjs/rollup.config.js",
7 | "build:rollup:esm": "rollup --config ./esm/rollup.config.mjs",
8 | "build:esbuild:cjs": "node ./cjs/esbuild.js",
9 | "build:esbuild:esm": "node ./esm/esbuild.mjs",
10 | "build:browserify:cjs": "node ./cjs/browserify.js",
11 | "build:browserify:esm": "node ./esm/browserify.mjs",
12 | "build:vite:cjs": "vite build ./cjs/vite",
13 | "build:vite:esm": "vite build ./esm/vite",
14 | "open:webpack:cjs": "open ./cjs/webpack.html",
15 | "open:webpack:esm": "open ./esm/webpack.html",
16 | "open:rollup:cjs": "open ./cjs/rollup.html",
17 | "open:rollup:esm": "open ./esm/rollup.html",
18 | "open:esbuild:cjs": "open ./cjs/esbuild.html",
19 | "open:esbuild:esm": "open ./esm/esbuild.html",
20 | "open:browserify:cjs": "open ./cjs/browserify.html",
21 | "open:browserify:esm": "open ./esm/browserify.html",
22 | "open:vite:cjs": "vite preview ./cjs/vite --open",
23 | "open:vite:esm": "vite preview ./esm/vite --open"
24 | },
25 | "devDependencies": {
26 | "@chialab/esbuild-plugin-alias": "^0.12.31",
27 | "@rollup/plugin-alias": "^3.1.5",
28 | "@rollup/plugin-commonjs": "^20.0.0",
29 | "@rollup/plugin-inject": "^4.0.3",
30 | "@rollup/plugin-json": "^4.1.0",
31 | "@rollup/plugin-node-resolve": "^13.0.5",
32 | "aliasify": "^2.1.0",
33 | "browserify": "^17.0.0",
34 | "esbuild": "^0.13.14",
35 | "esbuild-plugin-path-alias": "^1.0.3",
36 | "rollup": "^2.57.0",
37 | "vite": "^2.7.13",
38 | "webpack": "^5.54.0",
39 | "webpack-cli": "^4.8.0"
40 | },
41 | "dependencies": {
42 | "browser-resolve": "^2.0.0"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/proxy/process.js:
--------------------------------------------------------------------------------
1 | import {
2 | nextTick,
3 | title,
4 | env as environment,
5 | argv,
6 | version,
7 | versions,
8 | on,
9 | addListener,
10 | once,
11 | off,
12 | removeListener,
13 | removeAllListeners,
14 | emit,
15 | prependListener,
16 | prependOnceListener,
17 | listeners,
18 | cwd,
19 | chdir,
20 | umask,
21 | // @ts-ignore
22 | browser as _browser,
23 | // @ts-ignore
24 | binding as _binding
25 | } from 'process/browser.js';
26 |
27 | function noop() {}
28 |
29 | const browser = /** @type {boolean} */ (_browser);
30 | const emitWarning = noop;
31 | const binding = /** @type {Function} */ (_binding);
32 | const exit = noop;
33 | const pid = 1;
34 | const features = {};
35 | const kill = noop;
36 | const dlopen = noop;
37 | const uptime = noop;
38 | const memoryUsage = noop;
39 | const uvCounters = noop;
40 | const platform = 'browser';
41 | const arch = 'browser';
42 | const execPath = 'browser';
43 | const execArgv = /** @type {string[]} */ ([]);
44 |
45 | const api = {
46 | nextTick,
47 | title,
48 | browser,
49 | env: environment,
50 | argv,
51 | version,
52 | versions,
53 | on,
54 | addListener,
55 | once,
56 | off,
57 | removeListener,
58 | removeAllListeners,
59 | emit,
60 | emitWarning,
61 | prependListener,
62 | prependOnceListener,
63 | listeners,
64 | binding,
65 | cwd,
66 | chdir,
67 | umask,
68 | exit,
69 | pid,
70 | features,
71 | kill,
72 | dlopen,
73 | uptime,
74 | memoryUsage,
75 | uvCounters,
76 | platform,
77 | arch,
78 | execPath,
79 | execArgv
80 | };
81 |
82 | export default api;
83 |
84 | export {
85 | nextTick,
86 | title,
87 | browser,
88 | environment as env,
89 | argv,
90 | version,
91 | versions,
92 | on,
93 | addListener,
94 | once,
95 | off,
96 | removeListener,
97 | removeAllListeners,
98 | emit,
99 | emitWarning,
100 | prependListener,
101 | prependOnceListener,
102 | listeners,
103 | binding,
104 | cwd,
105 | chdir,
106 | umask,
107 | exit,
108 | pid,
109 | features,
110 | kill,
111 | dlopen,
112 | uptime,
113 | memoryUsage,
114 | uvCounters,
115 | platform,
116 | arch,
117 | execPath,
118 | execArgv
119 | };
120 |
--------------------------------------------------------------------------------
/example/esm/index.mjs:
--------------------------------------------------------------------------------
1 | import assert from 'assert';
2 | import buffer from 'buffer';
3 | import child_process from 'child_process';
4 | import cluster from 'cluster';
5 | import _console from 'console';
6 | import constants from 'constants';
7 | import crypto from 'crypto';
8 | import dgram from 'dgram';
9 | import dns from 'dns';
10 | import domain from 'domain';
11 | import events from 'events';
12 | import fs from 'fs';
13 | import http from 'http';
14 | import https from 'https';
15 | import http2 from 'http2';
16 | import _module from 'module';
17 | import net from 'net';
18 | import os from 'os';
19 | import path from 'path';
20 | import punycode from 'punycode';
21 | import _process from 'process';
22 | import querystring from 'querystring';
23 | import readline from 'readline';
24 | import repl from 'repl';
25 | import stream from 'stream';
26 | import _stream_duplex from '_stream_duplex';
27 | import _stream_passthrough from '_stream_passthrough';
28 | import _stream_readable from '_stream_readable';
29 | import _stream_transform from '_stream_transform';
30 | import _stream_writable from '_stream_writable';
31 | import string_decoder from 'string_decoder';
32 | import sys from 'sys';
33 | import timersPromises from 'timers/promises';
34 | import timers from 'timers';
35 | import tls from 'tls';
36 | import tty from 'tty';
37 | import url from 'url';
38 | import util from 'util';
39 | import vm from 'vm';
40 | import zlib from 'zlib';
41 | import nodeAssert from 'node:assert';
42 |
43 | console.log('assert', assert);
44 | console.log('buffer', buffer);
45 | console.log('child_process', child_process);
46 | console.log('cluster', cluster);
47 | console.log('console', _console);
48 | console.log('constants', constants);
49 | console.log('crypto', crypto);
50 | console.log('dgram', dgram);
51 | console.log('dns', dns);
52 | console.log('domain', domain);
53 | console.log('events', events);
54 | console.log('fs', fs);
55 | console.log('http', http);
56 | console.log('https', https);
57 | console.log('http2', http2);
58 | console.log('module', _module);
59 | console.log('net', net);
60 | console.log('os', os);
61 | console.log('path', path);
62 | console.log('punycode', punycode);
63 | console.log('process', _process);
64 | console.log('querystring', querystring);
65 | console.log('readline', readline);
66 | console.log('repl', repl);
67 | console.log('stream', stream);
68 | console.log('_stream_duplex', _stream_duplex);
69 | console.log('_stream_passthrough', _stream_passthrough);
70 | console.log('_stream_readable', _stream_readable);
71 | console.log('_stream_transform', _stream_transform);
72 | console.log('_stream_writable', _stream_writable);
73 | console.log('string_decoder', string_decoder);
74 | console.log('sys', sys);
75 | console.log('timers/promises', timersPromises);
76 | console.log('timers', timers);
77 | console.log('tls', tls);
78 | console.log('tty', tty);
79 | console.log('url', url);
80 | console.log('util', util);
81 | console.log('vm', vm);
82 | console.log('zlib', zlib);
83 | console.log('global Buffer', Buffer);
84 | console.log('global process', process);
85 | console.log('node:assert', nodeAssert);
86 |
87 | export default {
88 | assert,
89 | buffer,
90 | child_process,
91 | cluster,
92 | console: _console,
93 | constants,
94 | crypto,
95 | dgram,
96 | dns,
97 | domain,
98 | events,
99 | fs,
100 | http,
101 | https,
102 | http2,
103 | module: _module,
104 | net,
105 | os,
106 | path,
107 | punycode,
108 | process: _process,
109 | querystring,
110 | readline,
111 | repl,
112 | stream,
113 | _stream_duplex,
114 | _stream_passthrough,
115 | _stream_readable,
116 | _stream_transform,
117 | _stream_writable,
118 | string_decoder,
119 | sys,
120 | 'timers/promises': timersPromises,
121 | timers,
122 | tls,
123 | tty,
124 | url,
125 | util,
126 | vm,
127 | zlib,
128 | __Buffer: Buffer,
129 | __process: process,
130 | __assert: nodeAssert
131 | };
132 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import createRequire from 'create-require';
2 | import pkgDir from 'pkg-dir';
3 |
4 | /**
5 | * @param {string} path
6 | */
7 | const resolvePath = (path) => {
8 | let resolvedPath;
9 | try {
10 | resolvedPath = require.resolve(path);
11 | } catch {
12 | resolvedPath = (
13 | globalThis.require ?? createRequire(import.meta.url)
14 | ).resolve(path);
15 | }
16 | if (!path.includes('./')) {
17 | const directory = pkgDir.sync(resolvedPath) ?? '';
18 | return directory;
19 | }
20 | return resolvedPath;
21 | };
22 |
23 | const assert = resolvePath('assert/');
24 | const buffer = resolvePath('buffer/');
25 | const child_process = resolvePath('./mock/empty.js');
26 | const cluster = resolvePath('./mock/empty.js');
27 | const _console = resolvePath('console-browserify');
28 | const constants = resolvePath('constants-browserify');
29 | const crypto = resolvePath('crypto-browserify');
30 | const dgram = resolvePath('./mock/empty.js');
31 | const dns = resolvePath('./mock/empty.js');
32 | const domain = resolvePath('domain-browser');
33 | const events = resolvePath('events/');
34 | const fs = resolvePath('./mock/empty.js');
35 | const http = resolvePath('stream-http');
36 | const https = resolvePath('https-browserify');
37 | const http2 = resolvePath('./mock/empty.js');
38 | const _module = resolvePath('./mock/empty.js');
39 | const net = resolvePath('./mock/empty.js');
40 | const os = resolvePath('os-browserify/browser.js');
41 | const path = resolvePath('path-browserify');
42 | const punycode = resolvePath('punycode/');
43 | const _process = resolvePath('./proxy/process').replace('.js', '');
44 | const querystring = resolvePath('./proxy/querystring.js');
45 | const readline = resolvePath('./mock/empty.js');
46 | const repl = resolvePath('./mock/empty.js');
47 | const stream = resolvePath('stream-browserify');
48 | const _stream_duplex = resolvePath('readable-stream/lib/_stream_duplex.js');
49 | const _stream_passthrough = resolvePath(
50 | 'readable-stream/lib/_stream_passthrough.js'
51 | );
52 | const _stream_readable = resolvePath('readable-stream/lib/_stream_readable.js');
53 | const _stream_transform = resolvePath(
54 | 'readable-stream/lib/_stream_transform.js'
55 | );
56 | const _stream_writable = resolvePath('readable-stream/lib/_stream_writable.js');
57 | const string_decoder = resolvePath('string_decoder/');
58 | const sys = resolvePath('util/util.js');
59 | const timers = resolvePath('timers-browserify');
60 | const timersPromises = resolvePath('isomorphic-timers-promises');
61 | const tls = resolvePath('./mock/empty.js');
62 | const tty = resolvePath('tty-browserify');
63 | const url = resolvePath('./proxy/url.js');
64 | const util = resolvePath('util/util.js');
65 | const vm = resolvePath('vm-browserify');
66 | const zlib = resolvePath('browserify-zlib');
67 |
68 | const packages = {
69 | assert,
70 | buffer,
71 | child_process,
72 | cluster,
73 | console: _console,
74 | constants,
75 | crypto,
76 | dgram,
77 | dns,
78 | domain,
79 | events,
80 | fs,
81 | http,
82 | https,
83 | http2,
84 | module: _module,
85 | net,
86 | os,
87 | path,
88 | punycode,
89 | process: _process,
90 | querystring,
91 | readline,
92 | repl,
93 | stream,
94 | _stream_duplex,
95 | _stream_passthrough,
96 | _stream_readable,
97 | _stream_transform,
98 | _stream_writable,
99 | string_decoder,
100 | sys,
101 | 'timers/promises': timersPromises,
102 | timers,
103 | tls,
104 | tty,
105 | url,
106 | util,
107 | vm,
108 | zlib
109 | };
110 |
111 | /** @typedef {typeof packages} Packages */
112 | /** @typedef {keyof Packages} PackageNames */
113 | /** @typedef {{ [Property in PackageNames as `node:${Property}`]: Packages[Property] }} NodeProtocolPackages */
114 |
115 | const packagesWithNodeProtocol = /** @type NodeProtocolPackages */ ({});
116 | for (const [packageName, packagePath] of Object.entries(packages)) {
117 | packagesWithNodeProtocol[
118 | `node:${/** @type PackageNames */ (packageName)}`
119 | ] = /** @type PackageNames */ packagePath;
120 | }
121 |
122 | export default {
123 | ...packages,
124 | ...packagesWithNodeProtocol
125 | };
126 |
--------------------------------------------------------------------------------
/example/cjs/index.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const buffer = require('buffer');
3 | const child_process = require('child_process');
4 | const cluster = require('cluster');
5 | const _console = require('console');
6 | const constants = require('constants');
7 | const crypto = require('crypto');
8 | const dgram = require('dgram');
9 | const dns = require('dns');
10 | const domain = require('domain');
11 | const events = require('events');
12 | const fs = require('fs');
13 | const http = require('http');
14 | const https = require('https');
15 | const http2 = require('http2');
16 | const _module = require('module');
17 | const net = require('net');
18 | const os = require('os');
19 | const path = require('path');
20 | const punycode = require('punycode');
21 | const _process = require('process');
22 | const querystring = require('querystring');
23 | const readline = require('readline');
24 | const repl = require('repl');
25 | const stream = require('stream');
26 | const _stream_duplex = require('_stream_duplex');
27 | const _stream_passthrough = require('_stream_passthrough');
28 | const _stream_readable = require('_stream_readable');
29 | const _stream_transform = require('_stream_transform');
30 | const _stream_writable = require('_stream_writable');
31 | const string_decoder = require('string_decoder');
32 | const sys = require('sys');
33 | const timersPromises = require('timers/promises');
34 | const timers = require('timers');
35 | const tls = require('tls');
36 | const tty = require('tty');
37 | const url = require('url');
38 | const util = require('util');
39 | const vm = require('vm');
40 | const zlib = require('zlib');
41 | const nodeAssert = require('node:assert');
42 |
43 | console.log('assert', assert);
44 | console.log('buffer', buffer);
45 | console.log('child_process', child_process);
46 | console.log('cluster', cluster);
47 | console.log('console', _console);
48 | console.log('constants', constants);
49 | console.log('crypto', crypto);
50 | console.log('dgram', dgram);
51 | console.log('dns', dns);
52 | console.log('domain', domain);
53 | console.log('events', events);
54 | console.log('fs', fs);
55 | console.log('http', http);
56 | console.log('https', https);
57 | console.log('http2', http2);
58 | console.log('module', _module);
59 | console.log('net', net);
60 | console.log('os', os);
61 | console.log('path', path);
62 | console.log('punycode', punycode);
63 | console.log('process', _process);
64 | console.log('querystring', querystring);
65 | console.log('readline', readline);
66 | console.log('repl', repl);
67 | console.log('stream', stream);
68 | console.log('_stream_duplex', _stream_duplex);
69 | console.log('_stream_passthrough', _stream_passthrough);
70 | console.log('_stream_readable', _stream_readable);
71 | console.log('_stream_transform', _stream_transform);
72 | console.log('_stream_writable', _stream_writable);
73 | console.log('string_decoder', string_decoder);
74 | console.log('sys', sys);
75 | console.log('timers/promises', timersPromises);
76 | console.log('timers', timers);
77 | console.log('tls', tls);
78 | console.log('tty', tty);
79 | console.log('url', url);
80 | console.log('util', util);
81 | console.log('vm', vm);
82 | console.log('zlib', zlib);
83 | console.log('global Buffer', Buffer);
84 | console.log('global process', process);
85 | console.log('node:assert', nodeAssert);
86 |
87 | module.exports = {
88 | assert,
89 | buffer,
90 | child_process,
91 | cluster,
92 | console: _console,
93 | constants,
94 | crypto,
95 | dgram,
96 | dns,
97 | domain,
98 | events,
99 | fs,
100 | http,
101 | https,
102 | http2,
103 | module: _module,
104 | net,
105 | os,
106 | path,
107 | punycode,
108 | process: _process,
109 | querystring,
110 | readline,
111 | repl,
112 | stream,
113 | _stream_duplex,
114 | _stream_passthrough,
115 | _stream_readable,
116 | _stream_transform,
117 | _stream_writable,
118 | string_decoder,
119 | sys,
120 | 'timers/promises': timersPromises,
121 | timers,
122 | tls,
123 | tty,
124 | url,
125 | util,
126 | vm,
127 | zlib,
128 | __Buffer: Buffer,
129 | __process: process,
130 | __assert: nodeAssert
131 | };
132 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const { promises: fs } = require('fs');
5 | const { default: babel } = require('@rollup/plugin-babel');
6 | const commonjs = require('@rollup/plugin-commonjs');
7 | const execa = require('execa');
8 | const cpy = require('cpy');
9 | const del = require('del');
10 |
11 | function getConfig(filename, options = {}) {
12 | const { cjsOutro = '', cjsExports = 'auto' } = options;
13 | return {
14 | input: filename,
15 | output: [
16 | {
17 | file: `cjs/${filename}`,
18 | format: 'cjs',
19 | exports: cjsExports,
20 | sourcemap: true,
21 | outro: cjsOutro
22 | },
23 | {
24 | file: `esm/${filename}`,
25 | format: 'esm',
26 | sourcemap: true
27 | }
28 | ],
29 | plugins: [
30 | (() => {
31 | return {
32 | name: 'resolve-id',
33 | async resolveId(source, importer) {
34 | if (source === 'url') {
35 | return require.resolve('url/');
36 | }
37 | if (source === 'process/browser.js') {
38 | return require.resolve('process/browser.js');
39 | }
40 | if (
41 | source === 'path' &&
42 | importer.includes('proxy/url.js')
43 | ) {
44 | return require.resolve(
45 | 'rollup-plugin-node-builtins/src/es6/path.js'
46 | );
47 | }
48 | return null;
49 | }
50 | };
51 | })(),
52 | (() => {
53 | return {
54 | name: 'types',
55 | async writeBundle(output) {
56 | let prefix;
57 | if (output.file.includes('cjs/')) {
58 | prefix = 'cjs';
59 | } else if (output.file.includes('esm/')) {
60 | prefix = 'esm';
61 | }
62 | if (typeof prefix !== 'undefined') {
63 | const tsconfig = {
64 | extends: './tsconfig',
65 | exclude: [
66 | 'test/**/*.js',
67 | 'types/**/*-test*',
68 | 'helpers/**/*.js'
69 | ],
70 | compilerOptions: {
71 | declaration: true,
72 | declarationMap: true,
73 | declarationDir: prefix,
74 | emitDeclarationOnly: true,
75 | noEmit: false,
76 | listEmittedFiles: true
77 | }
78 | };
79 | const file = `.${prefix}.tsconfig.json`;
80 | try {
81 | try {
82 | await cpy('types/**/*.d.ts', 'types', {
83 | rename: (basename) =>
84 | basename.replace('.d.ts', '.ts')
85 | });
86 | } catch (error) {}
87 | await fs.writeFile(
88 | file,
89 | JSON.stringify(tsconfig),
90 | 'utf-8'
91 | );
92 | const { stdout } = await execa(
93 | 'tsc',
94 | ['-p', file],
95 | {
96 | preferLocal: true
97 | }
98 | );
99 | try {
100 | await del([
101 | 'types/**/*.ts',
102 | '!types/**/*.d.ts'
103 | ]);
104 | } catch (error) {}
105 | console.log(stdout);
106 | } finally {
107 | await fs.unlink(file);
108 | }
109 | }
110 | }
111 | };
112 | })(),
113 | (() => {
114 | return {
115 | name: 'package-type',
116 | async writeBundle(output) {
117 | let prefix, type;
118 | if (output.file.includes('index.js')) {
119 | return;
120 | }
121 | if (output.file.includes('cjs/')) {
122 | prefix = 'cjs';
123 | type = 'commonjs';
124 | } else if (output.file.includes('esm/')) {
125 | prefix = 'esm';
126 | type = 'module';
127 | }
128 | if (typeof prefix !== 'undefined') {
129 | const package_ = path.join(prefix, 'package.json');
130 | try {
131 | await fs.unlink(package_);
132 | } catch (error) {}
133 | await fs.writeFile(
134 | package_,
135 | JSON.stringify({ type }),
136 | 'utf8'
137 | );
138 | }
139 | }
140 | };
141 | })(),
142 | commonjs(),
143 | babel({
144 | babelHelpers: 'bundled',
145 | exclude: 'node_modules/**'
146 | })
147 | ]
148 | };
149 | }
150 |
151 | module.exports = [
152 | 'index.js',
153 | 'mock/buffer.js',
154 | 'mock/console.js',
155 | 'mock/dns.js',
156 | 'mock/empty.js',
157 | 'mock/net.js',
158 | 'mock/process.js',
159 | 'mock/punycode.js',
160 | 'mock/tls.js',
161 | 'mock/tty.js',
162 | [
163 | 'proxy/url.js',
164 | { cjsOutro: 'exports = module.exports = api;', cjsExports: 'named' }
165 | ],
166 | [
167 | 'proxy/querystring.js',
168 | { cjsOutro: 'exports = module.exports = api;', cjsExports: 'named' }
169 | ],
170 | [
171 | 'proxy/process.js',
172 | { cjsOutro: 'exports = module.exports = api;', cjsExports: 'named' }
173 | ],
174 | [
175 | 'proxy/process/browser.js',
176 | { cjsOutro: 'exports = module.exports = api;', cjsExports: 'named' }
177 | ]
178 | ].map((entry) => {
179 | const [filename, options = {}] = [].concat(entry);
180 | return getConfig(filename, options);
181 | });
182 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-stdlib-browser",
3 | "version": "1.3.1",
4 | "description": "Node standard library for browser.",
5 | "license": "MIT",
6 | "author": "Ivan Nikolić (http://ivannikolic.com)",
7 | "sideEffects": false,
8 | "exports": {
9 | ".": {
10 | "import": "./esm/index.js",
11 | "require": "./cjs/index.js"
12 | },
13 | "./mock/*": {
14 | "import": "./esm/mock/*.js",
15 | "require": "./cjs/mock/*.js"
16 | },
17 | "./helpers/esbuild/*": "./helpers/esbuild/*.js",
18 | "./helpers/webpack/*": "./helpers/webpack/*.js",
19 | "./helpers/rollup/*": "./helpers/rollup/*.js",
20 | "./package.json": "./package.json"
21 | },
22 | "main": "cjs/index.js",
23 | "module": "esm/index.js",
24 | "types": "esm/index.d.ts",
25 | "directories": {
26 | "test": "test"
27 | },
28 | "files": [
29 | "cjs/",
30 | "esm/",
31 | "helpers/esbuild/{plugin,shim}.js",
32 | "helpers/webpack/plugin.js",
33 | "helpers/rollup/plugin.js",
34 | "CHANGELOG.md",
35 | "LICENSE.md",
36 | "README.md"
37 | ],
38 | "scripts": {
39 | "build": "del '{esm/,cjs/}' && rollup --config rollup.config.js && babel helpers/esbuild/shim.src.js --out-file=helpers/esbuild/shim.js",
40 | "lint": "eslint '{index,lib/**/*,test/**/*,helpers/**/*,example/**/*}.{js,mjs}'",
41 | "lint:types": "tsc",
42 | "module-check": "node -e 'require(\"node-stdlib-browser\"); require(\"node-stdlib-browser/helpers/esbuild/plugin\");' && node --input-type=module -e 'import \"node-stdlib-browser\"; import \"node-stdlib-browser/helpers/esbuild/plugin\";'",
43 | "prepublishOnly": "npm run build",
44 | "postpublish": "GITHUB_TOKEN=$GITHUB_RELEASE_TOKEN github-release-from-changelog",
45 | "prerelease": "npm run lint && npm run lint:types && npm run build && npm run module-check",
46 | "release": "np --no-release-draft",
47 | "test": "BABEL_ENV=test nyc mocha --require @babel/register --require esm 'test/**/*.js' && nyc check-coverage",
48 | "test:watch": "nodemon --exec npm test",
49 | "version": "if [ $(git rev-parse --abbrev-ref HEAD) == 'master' ]; then sed -i '' '/\\[unreleased\\]:/d' CHANGELOG.md && version-changelog CHANGELOG.md && changelog-verify CHANGELOG.md && git add CHANGELOG.md; else echo; fi"
50 | },
51 | "dependencies": {
52 | "assert": "^2.0.0",
53 | "browser-resolve": "^2.0.0",
54 | "browserify-zlib": "^0.2.0",
55 | "buffer": "^5.7.1",
56 | "console-browserify": "^1.1.0",
57 | "constants-browserify": "^1.0.0",
58 | "create-require": "^1.1.1",
59 | "crypto-browserify": "^3.12.1",
60 | "domain-browser": "4.22.0",
61 | "events": "^3.0.0",
62 | "https-browserify": "^1.0.0",
63 | "isomorphic-timers-promises": "^1.0.1",
64 | "os-browserify": "^0.3.0",
65 | "path-browserify": "^1.0.1",
66 | "pkg-dir": "^5.0.0",
67 | "process": "^0.11.10",
68 | "punycode": "^1.4.1",
69 | "querystring-es3": "^0.2.1",
70 | "readable-stream": "^3.6.0",
71 | "stream-browserify": "^3.0.0",
72 | "stream-http": "^3.2.0",
73 | "string_decoder": "^1.0.0",
74 | "timers-browserify": "^2.0.4",
75 | "tty-browserify": "0.0.1",
76 | "url": "^0.11.4",
77 | "util": "^0.12.4",
78 | "vm-browserify": "^1.0.1"
79 | },
80 | "devDependencies": {
81 | "@babel/cli": "^7.2.3",
82 | "@babel/core": "^7.2.2",
83 | "@babel/preset-env": "^7.12.1",
84 | "@babel/register": "^7.0.0",
85 | "@rollup/plugin-babel": "^5.2.1",
86 | "@rollup/plugin-commonjs": "^20.0.0",
87 | "@types/browser-resolve": "^2.0.1",
88 | "@types/mocha": "^8.2.3",
89 | "@types/node": "^16.3.0",
90 | "@types/parse-node-version": "^1.0.0",
91 | "babel-plugin-istanbul": "^6.0.0",
92 | "babel-plugin-transform-globalthis": "^1.0.0",
93 | "changelog-verify": "^1.1.2",
94 | "core-js": "^2.6.5",
95 | "cpy": "^8.1.2",
96 | "del": "^6.0.0",
97 | "del-cli": "^3.0.1",
98 | "esbuild": "^0.13.14",
99 | "eslint": "^7.31.0",
100 | "eslint-config-niksy": "^10.0.0",
101 | "eslint-config-prettier": "^8.3.0",
102 | "eslint-plugin-import": "^2.23.4",
103 | "eslint-plugin-jsdoc": "^33.3.0",
104 | "eslint-plugin-mocha": "^8.0.0",
105 | "eslint-plugin-node": "^11.1.0",
106 | "eslint-plugin-prettier": "^3.4.0",
107 | "eslint-plugin-promise": "^5.1.0",
108 | "eslint-plugin-unicorn": "^31.0.0",
109 | "esm": "^3.0.51",
110 | "execa": "^5.1.1",
111 | "github-release-from-changelog": "^2.1.1",
112 | "husky": "^4.3.0",
113 | "lint-staged": "^10.4.2",
114 | "mocha": "^8.2.0",
115 | "nodemon": "^2.0.6",
116 | "np": "^7.6.0",
117 | "nyc": "^15.1.0",
118 | "parse-node-version": "^1.0.1",
119 | "prettier": "^2.4.0",
120 | "rollup": "^2.32.1",
121 | "rollup-plugin-node-builtins": "^2.1.2",
122 | "typescript": "^4.3.5",
123 | "version-changelog": "^3.1.1",
124 | "webpack": "^5.65.0"
125 | },
126 | "engines": {
127 | "node": ">=10"
128 | },
129 | "keywords": [
130 | "node",
131 | "std",
132 | "browser",
133 | "api"
134 | ],
135 | "repository": {
136 | "type": "git",
137 | "url": "git+https://github.com/niksy/node-stdlib-browser.git"
138 | },
139 | "bugs": {
140 | "url": "https://github.com/niksy/node-stdlib-browser/issues"
141 | },
142 | "homepage": "https://github.com/niksy/node-stdlib-browser#readme"
143 | }
144 |
--------------------------------------------------------------------------------
/proxy/url.js:
--------------------------------------------------------------------------------
1 | /* globals unknown */
2 |
3 | /**
4 | * @typedef {import('url').URLFormatOptions} URLFormatOptions
5 | * @typedef {import('url').UrlObject} UrlObject
6 | * @typedef {import('url').format} formatImport
7 | * @typedef {import('url').parse} parseImport
8 | * @typedef {import('url').resolve} resolveImport
9 | * @typedef {import('url').Url} UrlImport
10 | * @typedef {import('url').fileURLToPath} fileURLToPath
11 | * @typedef {import('url').pathToFileURL} pathToFileURL
12 | * @typedef {import('url').domainToUnicode} domainToUnicode
13 | * @typedef {import('url').domainToASCII} domainToASCII
14 | */
15 |
16 | // @ts-ignore
17 | import { format, parse, resolve, resolveObject, Url } from 'url';
18 | import { resolve as pathResolve } from 'path';
19 |
20 | const formatImport = /** @type {formatImport}*/ (format);
21 | const parseImport = /** @type {parseImport}*/ (parse);
22 | const resolveImport = /** @type {resolveImport}*/ (resolve);
23 | // @ts-ignore
24 | const UrlImport = /** @type {UrlImport}*/ (Url);
25 |
26 | const URL = globalThis.URL;
27 | /* eslint-disable-next-line unicorn/prevent-abbreviations */
28 | const URLSearchParams = globalThis.URLSearchParams;
29 |
30 | const percentRegEx = /%/g;
31 | const backslashRegEx = /\\/g;
32 | const newlineRegEx = /\n/g;
33 | const carriageReturnRegEx = /\r/g;
34 | const tabRegEx = /\t/g;
35 | const CHAR_FORWARD_SLASH = 47;
36 |
37 | /**
38 | * @param {unknown} instance
39 | */
40 | function isURLInstance(instance) {
41 | const resolved = /** @type {URL|null} */ (instance ?? null);
42 | return Boolean(resolved !== null && resolved?.href && resolved?.origin);
43 | }
44 |
45 | /**
46 | * @param {URL} url
47 | */
48 | function getPathFromURLPosix(url) {
49 | if (url.hostname !== '') {
50 | throw new TypeError(
51 | `File URL host must be "localhost" or empty on browser`
52 | );
53 | }
54 | const pathname = url.pathname;
55 | for (let n = 0; n < pathname.length; n++) {
56 | if (pathname[n] === '%') {
57 | // @ts-ignore
58 | const third = pathname.codePointAt(n + 2) | 0x20;
59 | if (pathname[n + 1] === '2' && third === 102) {
60 | throw new TypeError(
61 | 'File URL path must not include encoded / characters'
62 | );
63 | }
64 | }
65 | }
66 | return decodeURIComponent(pathname);
67 | }
68 |
69 | /**
70 | * @param {string} filepath
71 | */
72 | function encodePathChars(filepath) {
73 | if (filepath.includes('%')) {
74 | filepath = filepath.replace(percentRegEx, '%25');
75 | }
76 | if (filepath.includes('\\')) {
77 | filepath = filepath.replace(backslashRegEx, '%5C');
78 | }
79 | if (filepath.includes('\n')) {
80 | filepath = filepath.replace(newlineRegEx, '%0A');
81 | }
82 | if (filepath.includes('\r')) {
83 | filepath = filepath.replace(carriageReturnRegEx, '%0D');
84 | }
85 | if (filepath.includes('\t')) {
86 | filepath = filepath.replace(tabRegEx, '%09');
87 | }
88 | return filepath;
89 | }
90 |
91 | const domainToASCII =
92 | /**
93 | * @type {domainToASCII}
94 | */
95 | function (domain) {
96 | if (typeof domain === 'undefined') {
97 | throw new TypeError('The "domain" argument must be specified');
98 | }
99 | return new URL(`http://${domain}`).hostname;
100 | };
101 |
102 | const domainToUnicode =
103 | /**
104 | * @type {domainToUnicode}
105 | */
106 | function (domain) {
107 | if (typeof domain === 'undefined') {
108 | throw new TypeError('The "domain" argument must be specified');
109 | }
110 | return new URL(`http://${domain}`).hostname;
111 | };
112 |
113 | const pathToFileURL =
114 | /**
115 | * @type {(url: string) => URL}
116 | */
117 | function (filepath) {
118 | const outURL = new URL('file://');
119 | let resolved = pathResolve(filepath);
120 | const filePathLast = filepath.charCodeAt(filepath.length - 1);
121 | if (
122 | filePathLast === CHAR_FORWARD_SLASH &&
123 | resolved[resolved.length - 1] !== '/'
124 | ) {
125 | resolved += '/';
126 | }
127 | outURL.pathname = encodePathChars(resolved);
128 | return outURL;
129 | };
130 |
131 | const fileURLToPath =
132 | /**
133 | * @type {fileURLToPath & ((path: string | URL) => string)}
134 | */
135 | function (path) {
136 | if (!isURLInstance(path) && typeof path !== 'string') {
137 | throw new TypeError(
138 | `The "path" argument must be of type string or an instance of URL. Received type ${typeof path} (${path})`
139 | );
140 | }
141 | const resolved = new URL(path);
142 | if (resolved.protocol !== 'file:') {
143 | throw new TypeError('The URL must be of scheme file');
144 | }
145 | return getPathFromURLPosix(resolved);
146 | };
147 |
148 | const formatImportWithOverloads =
149 | /**
150 | * @type {(
151 | * ((urlObject: URL, options?: URLFormatOptions) => string) &
152 | * ((urlObject: UrlObject | string, options?: never) => string)
153 | * )}
154 | */
155 | function (urlObject, options = {}) {
156 | if (!(urlObject instanceof URL)) {
157 | return formatImport(urlObject);
158 | }
159 |
160 | if (typeof options !== 'object' || options === null) {
161 | throw new TypeError(
162 | 'The "options" argument must be of type object.'
163 | );
164 | }
165 |
166 | const auth = options.auth ?? true;
167 | const fragment = options.fragment ?? true;
168 | const search = options.search ?? true;
169 | const unicode = options.unicode ?? false;
170 |
171 | const parsed = new URL(urlObject.toString());
172 |
173 | if (!auth) {
174 | parsed.username = '';
175 | parsed.password = '';
176 | }
177 |
178 | if (!fragment) {
179 | parsed.hash = '';
180 | }
181 |
182 | if (!search) {
183 | parsed.search = '';
184 | }
185 |
186 | if (unicode) {
187 | // Not implemented
188 | }
189 |
190 | return parsed.toString();
191 | };
192 |
193 | const api = {
194 | format: formatImportWithOverloads,
195 | parse: parseImport,
196 | resolve: resolveImport,
197 | resolveObject,
198 | Url: UrlImport,
199 | URL,
200 | URLSearchParams,
201 | domainToASCII,
202 | domainToUnicode,
203 | pathToFileURL,
204 | fileURLToPath
205 | };
206 |
207 | export default api;
208 |
209 | export {
210 | formatImportWithOverloads as format,
211 | parseImport as parse,
212 | resolveImport as resolve,
213 | resolveObject,
214 | UrlImport as Url,
215 | URL,
216 | URLSearchParams,
217 | domainToASCII,
218 | domainToUnicode,
219 | pathToFileURL,
220 | fileURLToPath
221 | };
222 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-stdlib-browser
2 |
3 | [![Build Status][ci-img]][ci]
4 |
5 | [Node standard library](https://nodejs.org/docs/latest/api/) for browser.
6 |
7 | Features:
8 |
9 | - Based on [`node-libs-browser`](https://github.com/webpack/node-libs-browser)
10 | for Webpack
11 | - Maintained with newer versions and modern implementations
12 | - Works with Webpack, Rollup, Vite, esbuild and Browserify, but should also
13 | work with other bundlers
14 | - Exports implementation with [`node:` protocol][node-protocol-imports] which
15 | allows for builtin modules to be referenced by valid absolute URL strings
16 |
17 | Check [example](/example) to see how modules work in browser environment.
18 |
19 | ## Install
20 |
21 | ```sh
22 | npm install node-stdlib-browser --save-dev
23 | ```
24 |
25 | ## Usage
26 |
27 | ### Webpack
28 |
29 |
30 |
31 | Show me
32 |
33 | As of Webpack 5, aliases and globals provider need to be explicitly configured.
34 | If you want to handle [`node:` protocol][node-protocol-imports] imports, you
35 | need to provide helper plugin.
36 |
37 | ```js
38 | // webpack.config.js
39 | const stdLibBrowser = require('node-stdlib-browser');
40 | const {
41 | NodeProtocolUrlPlugin
42 | } = require('node-stdlib-browser/helpers/webpack/plugin');
43 | const webpack = require('webpack');
44 |
45 | module.exports = {
46 | // ...
47 | resolve: {
48 | alias: stdLibBrowser
49 | },
50 | plugins: [
51 | new NodeProtocolUrlPlugin(),
52 | new webpack.ProvidePlugin({
53 | process: stdLibBrowser.process,
54 | Buffer: [stdLibBrowser.buffer, 'Buffer']
55 | })
56 | ]
57 | };
58 | ```
59 |
60 | If you’re using ESM config, additional configuration is needed to handle
61 | unspecified extensions:
62 |
63 | ```js
64 | // webpack.config.js
65 | module.exports = {
66 | // ...
67 | module: {
68 | rules: [
69 | {
70 | test: /\.m?js$/,
71 | resolve: {
72 | fullySpecified: false
73 | }
74 | }
75 | ]
76 | }
77 | };
78 | ```
79 |
80 |
81 |
82 | ### Rollup
83 |
84 |
85 |
86 | Show me
87 |
88 | Since many packages expose only CommonJS implementation, you need to apply
89 | plugins to handle CommonJS exports. Those packages could have dependencies
90 | installed with npm so they need to be properly resolved (taking into account
91 | browser-specific implementations).
92 |
93 | Some dependencies can have circular dependencies and Rollup will warn you about
94 | that. You can ignore these warnings with helper function
95 | ([reference](<(https://github.com/rollup/rollup/issues/1089#issuecomment-635564942)>)).
96 |
97 | ```js
98 | // rollup.config.js
99 | const stdLibBrowser = require('node-stdlib-browser');
100 | const {
101 | handleCircularDependancyWarning
102 | } = require('node-stdlib-browser/helpers/rollup/plugin');
103 | const { default: resolve } = require('@rollup/plugin-node-resolve');
104 | const commonjs = require('@rollup/plugin-commonjs');
105 | const json = require('@rollup/plugin-json');
106 | const alias = require('@rollup/plugin-alias');
107 | const inject = require('@rollup/plugin-inject');
108 |
109 | module.exports = {
110 | // ...
111 | plugins: [
112 | alias({
113 | entries: stdLibBrowser
114 | }),
115 | resolve({
116 | browser: true
117 | }),
118 | commonjs(),
119 | json(),
120 | inject({
121 | process: stdLibBrowser.process,
122 | Buffer: [stdLibBrowser.buffer, 'Buffer']
123 | })
124 | ],
125 | onwarn: (warning, rollupWarn) => {
126 | handleCircularDependancyWarning(warning, rollupWarn);
127 | }
128 | };
129 | ```
130 |
131 |
132 |
133 | ### Vite
134 |
135 |
136 |
137 | Show me
138 |
139 | Vite config uses combination of Rollup and esbuild plugins. It’s **important**
140 | to use dynamic import when using CommonJS configuration so ESM version of
141 | modules is picked up. This allows Vite bundling to use our mocking
142 | implementation and implement heuristics such as proper tree-shaking and dead
143 | code removal marking.
144 |
145 | ```js
146 | const inject = require('@rollup/plugin-inject');
147 |
148 | const esbuildShim = require.resolve('node-stdlib-browser/helpers/esbuild/shim');
149 |
150 | module.exports = async () => {
151 | const { default: stdLibBrowser } = await import('node-stdlib-browser');
152 | return {
153 | resolve: {
154 | alias: stdLibBrowser
155 | },
156 | optimizeDeps: {
157 | include: ['buffer', 'process']
158 | },
159 | plugins: [
160 | {
161 | ...inject({
162 | global: [esbuildShim, 'global'],
163 | process: [esbuildShim, 'process'],
164 | Buffer: [esbuildShim, 'Buffer']
165 | }),
166 | enforce: 'post'
167 | }
168 | ]
169 | };
170 | };
171 | ```
172 |
173 | #### Vite plugins
174 |
175 | If you wish to use simpler configuration, you can use one of the available Vite
176 | plugins which use this package under the hood:
177 |
178 | - https://github.com/sodatea/vite-plugin-node-stdlib-browser
179 | - https://github.com/davidmyersdev/vite-plugin-node-polyfills
180 |
181 |
182 |
183 | ### esbuild
184 |
185 |
186 |
187 | Show me
188 |
189 | Using esbuild requires you to use helper utilities and plugins.
190 |
191 | ```js
192 | const path = require('path');
193 | const esbuild = require('esbuild');
194 | const plugin = require('node-stdlib-browser/helpers/esbuild/plugin');
195 | const stdLibBrowser = require('node-stdlib-browser');
196 |
197 | (async () => {
198 | await esbuild.build({
199 | // ...
200 | inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
201 | define: {
202 | global: 'global',
203 | process: 'process',
204 | Buffer: 'Buffer'
205 | },
206 | plugins: [plugin(stdLibBrowser)]
207 | });
208 | })();
209 | ```
210 |
211 |
212 |
213 | ### Browserify
214 |
215 |
216 |
217 | Show me
218 |
219 | Bundling ES modules is currently not supported natively in Browserify, but you
220 | can try using [esmify](https://github.com/mattdesl/esmify) or
221 | [babelify](https://github.com/babel/babelify) for transforming to CommonJS
222 | first.
223 |
224 | ```js
225 | const fs = require('fs');
226 | const path = require('path');
227 | const browserify = require('browserify');
228 | const aliasify = require('aliasify');
229 | const stdLibBrowser = require('node-stdlib-browser');
230 |
231 | const b = browserify(
232 | [
233 | /* ... */
234 | ],
235 | {
236 | // ...
237 | transform: [[aliasify, { aliases: stdLibBrowser }]],
238 | insertGlobalVars: {
239 | process: () => {
240 | return `require('${stdLibBrowser.process}')`;
241 | },
242 | Buffer: () => {
243 | return `require('${stdLibBrowser.buffer}').Buffer`;
244 | }
245 | }
246 | }
247 | );
248 | ```
249 |
250 |
251 |
252 | ## Package contents
253 |
254 | | Module | Browser implementation | Mock implementation | Notes |
255 | | --------------------- | --------------------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------- |
256 | | `assert` | [assert](https://github.com/browserify/commonjs-assert) | |
257 | | `buffer` | [buffer](https://github.com/feross/buffer) | [buffer](mock/buffer.js) | `buffer@5` for IE 11 support |
258 | | `child_process` | | |
259 | | `cluster` | | |
260 | | `console` | [console-browserify](https://github.com/browserify/console-browserify) | [console](mock/console.js) |
261 | | `constants` | [constants-browserify](https://github.com/juliangruber/constants-browserify) | |
262 | | `crypto` | [crypto-browserify](https://github.com/crypto-browserify/crypto-browserify) | |
263 | | `dgram` | | |
264 | | `dns` | | [dns](mock/dns.js) |
265 | | `domain` | [domain-browser](https://github.com/bevry/domain-browser) | |
266 | | `events` | [events](https://github.com/browserify/events) | |
267 | | `fs` | | | [Mocking `fs`](#mocking-fs) |
268 | | `http` | [stream-http](https://github.com/jhiesey/stream-http) | |
269 | | `https` | [https-browserify](https://github.com/substack/https-browserify) | |
270 | | `module` | | |
271 | | `net` | | [net](mock/net.js) |
272 | | `os` | [os-browserify](https://github.com/CoderPuppy/os-browserify) | |
273 | | `path` | [path-browserify](https://github.com/browserify/path-browserify) | |
274 | | `process` | [process](https://github.com/defunctzombie/node-process) | [process](mock/process.js) | Contains additional exports from newer Node |
275 | | `punycode` | [punycode](https://github.com/bestiejs/punycode.js) | | `punycode@1` for browser support |
276 | | `querystring` | [querystring-es3](https://github.com/mike-spainhower/querystring) | | Contains additional exports from newer Node versions |
277 | | `readline` | | |
278 | | `repl` | | |
279 | | `stream` | [stream-browserify](https://github.com/browserify/stream-browserify) | |
280 | | `string_decoder` | [string_decoder](https://github.com/nodejs/string_decoder) | |
281 | | `sys` | [util](https://github.com/browserify/node-util) | |
282 | | `timers` | [timers-browserify](https://github.com/browserify/timers-browserify) | |
283 | | `timers/promises` | [isomorphic-timers-promises](https://github.com/niksy/isomorphic-timers-promises) | |
284 | | `tls` | | [tls](mock/tls.js) |
285 | | `tty` | [tty-browserify](https://github.com/browserify/tty-browserify) | [tty](mock/tty.js) |
286 | | `url` | [node-url](https://github.com/defunctzombie/node-url) | | Contains additional exports from newer Node versions (`URL` and `URLSearchParams` are not polyfilled) |
287 | | `util` | [util](https://github.com/browserify/node-util) | |
288 | | `vm` | [vm-browserify](https://github.com/browserify/vm-browserify) | |
289 | | `zlib` | [browserify-zlib](https://github.com/browserify/browserify-zlib) | |
290 | | `_stream_duplex` | [readable-stream](https://github.com/nodejs/readable-stream) | |
291 | | `_stream_passthrough` | [readable-stream](https://github.com/nodejs/readable-stream) | |
292 | | `_stream_readable` | [readable-stream](https://github.com/nodejs/readable-stream) | |
293 | | `_stream_transform` | [readable-stream](https://github.com/nodejs/readable-stream) | |
294 | | `_stream_writable` | [readable-stream](https://github.com/nodejs/readable-stream) | |
295 |
296 | ## API
297 |
298 | ### packages
299 |
300 | Returns: `object`
301 |
302 | Exports absolute paths to each module directory (where `package.json` is
303 | located), keyed by module names. Modules without browser replacements return
304 | module with default export `null`.
305 |
306 | Some modules have mocks in the mock directory. These are replacements with
307 | minimal functionality.
308 |
309 | ## Tips
310 |
311 | ### Mocking `fs`
312 |
313 | `fs` package doesn’t return anything since there are many different ways you can
314 | implement file system functionality in browser.
315 |
316 | Examples of implementations:
317 |
318 | - [`BrowserFS`](https://github.com/jvilk/BrowserFS)
319 | - [`fs-web`](https://github.com/matthewp/fs)
320 | - [`browserify-fs`](https://github.com/mafintosh/browserify-fs)
321 | - [`mock-fs`](https://github.com/tschaub/mock-fs)
322 | - [`memfs`](https://github.com/streamich/memfs)
323 |
324 | ## Node support
325 |
326 | Minimum supported version should be Node 10.
327 |
328 | If you’re using ESM in Node < 12.20, note that
329 | [subpath patterns](https://nodejs.org/api/packages.html#packages_subpath_patterns)
330 | are not supported so mocks can’t be handled. In that case, it’s recommended to
331 | use CommonJS implementation.
332 |
333 | ## Browser support
334 |
335 | Minimum supported version should be Internet Explorer 11, but most modules
336 | support even Internet Explorer 9.
337 |
338 | ## Types
339 |
340 | You can use default `@types/node` types.
341 |
342 | ## License
343 |
344 | MIT © [Ivan Nikolić](http://ivannikolic.com)
345 |
346 |
347 |
348 | [ci]: https://github.com/niksy/node-stdlib-browser/actions?query=workflow%3ACI
349 | [ci-img]: https://github.com/niksy/node-stdlib-browser/workflows/CI/badge.svg?branch=master
350 | [node-protocol-imports]: https://nodejs.org/api/esm.html#node-imports
351 |
352 |
353 |
--------------------------------------------------------------------------------
/test/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-namespace */
2 |
3 | import assert from 'assert';
4 | import path from 'path';
5 | import execa from 'execa';
6 | import parseNodeVersion from 'parse-node-version';
7 | import api from '../index';
8 | import url from '../proxy/url';
9 | import qs from '../proxy/querystring';
10 | import _process from '../proxy/process';
11 |
12 | /** @typedef {import('../index').PackageNames} PackageNames */
13 |
14 | const context = path.resolve(__dirname, '../');
15 |
16 | const packages = {
17 | _stream_duplex: 'node_modules/readable-stream',
18 | _stream_passthrough: 'node_modules/readable-stream',
19 | _stream_readable: 'node_modules/readable-stream',
20 | _stream_transform: 'node_modules/readable-stream',
21 | _stream_writable: 'node_modules/readable-stream',
22 | assert: 'node_modules/assert',
23 | buffer: 'node_modules/buffer',
24 | child_process: 'mock/empty.js',
25 | cluster: 'mock/empty.js',
26 | console: 'node_modules/console-browserify',
27 | constants: 'node_modules/constants-browserify',
28 | crypto: 'node_modules/crypto-browserify',
29 | dgram: 'mock/empty.js',
30 | dns: 'mock/empty.js',
31 | domain: 'node_modules/domain-browser',
32 | events: 'node_modules/events',
33 | fs: 'mock/empty.js',
34 | http: 'node_modules/stream-http',
35 | https: 'node_modules/https-browserify',
36 | http2: 'mock/empty.js',
37 | module: 'mock/empty.js',
38 | net: 'mock/empty.js',
39 | os: 'node_modules/os-browserify',
40 | path: 'node_modules/path-browserify',
41 | process: 'proxy/process',
42 | punycode: 'node_modules/punycode',
43 | querystring: 'proxy/querystring.js',
44 | readline: 'mock/empty.js',
45 | repl: 'mock/empty.js',
46 | stream: 'node_modules/stream-browserify',
47 | string_decoder: 'node_modules/string_decoder',
48 | sys: 'node_modules/util',
49 | timers: 'node_modules/timers-browserify',
50 | 'timers/promises': 'node_modules/isomorphic-timers-promises/cjs',
51 | tls: 'mock/empty.js',
52 | tty: 'node_modules/tty-browserify',
53 | url: 'proxy/url.js',
54 | util: 'node_modules/util',
55 | vm: 'node_modules/vm-browserify',
56 | zlib: 'node_modules/browserify-zlib'
57 | };
58 |
59 | describe('Exports', function () {
60 | it('should properly resolve package paths', function () {
61 | Object.entries(packages).forEach(([packageName, packagePath]) => {
62 | const resolvedPath =
63 | typeof packagePath === 'string'
64 | ? path.resolve(context, packagePath)
65 | : packagePath;
66 | assert.ok(
67 | api[/** @type PackageNames */ (packageName)] === resolvedPath,
68 | `Package path not valid for "${packageName}", got "${
69 | api[/** @type PackageNames */ (packageName)]
70 | }"`
71 | );
72 | });
73 | });
74 |
75 | it('should properly resolve package paths for `node:` protocol', function () {
76 | Object.entries(packages).forEach(([packageName, packagePath]) => {
77 | const resolvedPath =
78 | typeof packagePath === 'string'
79 | ? path.resolve(context, packagePath)
80 | : packagePath;
81 | assert.ok(
82 | api[/** @type PackageNames */ (packageName)] === resolvedPath,
83 | `Package path not valid for "node:${packageName}", got "${
84 | api[`node:${/** @type PackageNames */ (packageName)}`]
85 | }"`
86 | );
87 | });
88 | });
89 | });
90 |
91 | describe('`url` additional exports', function () {
92 | it('url.domainToASCII', function () {
93 | const domainWithASCII = [
94 | ['ıíd', 'xn--d-iga7r'],
95 | ['يٴ', 'xn--mhb8f'],
96 | ['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'],
97 | ['новини.com', 'xn--b1amarcd.com'],
98 | ['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'],
99 | ['افغانستا.icom.museum', 'xn--mgbaal8b0b9b2b.icom.museum'],
100 | ['الجزائر.icom.fake', 'xn--lgbbat1ad8j.icom.fake'],
101 | ['भारत.org', 'xn--h2brj9c.org']
102 | ];
103 |
104 | domainWithASCII.forEach((pair) => {
105 | const domain = pair[0];
106 | const ascii = pair[1];
107 | const domainConvertedToASCII = url.domainToASCII(domain);
108 | assert.strictEqual(domainConvertedToASCII, ascii);
109 | });
110 | });
111 |
112 | it('url.domainToUnicode', function () {
113 | const domainWithASCII = [
114 | ['ıíd', 'xn--d-iga7r'],
115 | ['يٴ', 'xn--mhb8f'],
116 | ['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'],
117 | ['новини.com', 'xn--b1amarcd.com'],
118 | ['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'],
119 | ['افغانستا.icom.museum', 'xn--mgbaal8b0b9b2b.icom.museum'],
120 | ['الجزائر.icom.fake', 'xn--lgbbat1ad8j.icom.fake'],
121 | ['भारत.org', 'xn--h2brj9c.org']
122 | ];
123 |
124 | domainWithASCII.forEach((pair) => {
125 | const domain = pair[0];
126 | const ascii = pair[1];
127 | const domainConvertedToASCII = url.domainToUnicode(domain);
128 | assert.strictEqual(domainConvertedToASCII, ascii);
129 | });
130 | });
131 |
132 | it('url.pathToFileURL', function () {
133 | {
134 | const fileURL = url.pathToFileURL('test/').href;
135 | assert.ok(fileURL.startsWith('file:///'));
136 | assert.ok(fileURL.endsWith('/'));
137 | }
138 | {
139 | const fileURL = url.pathToFileURL('test\\').href;
140 | assert.ok(fileURL.startsWith('file:///'));
141 | assert.ok(fileURL.endsWith('%5C'));
142 | }
143 | {
144 | const fileURL = url.pathToFileURL('test/%').href;
145 | assert.ok(fileURL.includes('%25'));
146 | }
147 | {
148 | const fileURL = url.pathToFileURL('\\\\nas\\share\\path.txt').href;
149 | assert.ok(
150 | /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/.test(fileURL)
151 | );
152 | }
153 | {
154 | const testCases = [
155 | { path: '/foo', expected: 'file:///foo' },
156 | { path: '/FOO', expected: 'file:///FOO' },
157 | { path: '/dir/foo', expected: 'file:///dir/foo' },
158 | { path: '/dir/', expected: 'file:///dir/' },
159 | { path: '/foo.mjs', expected: 'file:///foo.mjs' },
160 | { path: '/foo bar', expected: 'file:///foo%20bar' },
161 | { path: '/foo?bar', expected: 'file:///foo%3Fbar' },
162 | { path: '/foo#bar', expected: 'file:///foo%23bar' },
163 | { path: '/foo&bar', expected: 'file:///foo&bar' },
164 | { path: '/foo=bar', expected: 'file:///foo=bar' },
165 | { path: '/foo:bar', expected: 'file:///foo:bar' },
166 | { path: '/foo;bar', expected: 'file:///foo;bar' },
167 | { path: '/foo%bar', expected: 'file:///foo%25bar' },
168 | { path: '/foo\\bar', expected: 'file:///foo%5Cbar' },
169 | { path: '/foo\bbar', expected: 'file:///foo%08bar' },
170 | { path: '/foo\tbar', expected: 'file:///foo%09bar' },
171 | { path: '/foo\nbar', expected: 'file:///foo%0Abar' },
172 | { path: '/foo\rbar', expected: 'file:///foo%0Dbar' },
173 | { path: '/fóóbàr', expected: 'file:///f%C3%B3%C3%B3b%C3%A0r' },
174 | { path: '/€', expected: 'file:///%E2%82%AC' },
175 | { path: '/🚀', expected: 'file:///%F0%9F%9A%80' }
176 | ];
177 |
178 | for (const { path, expected } of testCases) {
179 | const actual = url.pathToFileURL(path).href;
180 | assert.strictEqual(actual, expected);
181 | }
182 | }
183 | });
184 |
185 | it('url.fileURLToPath', function () {
186 | assert.throws(() => url.fileURLToPath('https://a/b/c'), /TypeError/);
187 | {
188 | const withHost = new URL('file://host/a');
189 | // @ts-ignore
190 | assert.throws(() => url.fileURLToPath(withHost), /TypeError/);
191 | }
192 | assert.throws(() => url.fileURLToPath('file:///a%2F/'), /TypeError/);
193 | {
194 | const testCases = [
195 | { path: '/foo', fileURL: 'file:///foo' },
196 | { path: '/FOO', fileURL: 'file:///FOO' },
197 | { path: '/dir/foo', fileURL: 'file:///dir/foo' },
198 | { path: '/dir/', fileURL: 'file:///dir/' },
199 | { path: '/foo.mjs', fileURL: 'file:///foo.mjs' },
200 | { path: '/foo bar', fileURL: 'file:///foo%20bar' },
201 | { path: '/foo?bar', fileURL: 'file:///foo%3Fbar' },
202 | { path: '/foo#bar', fileURL: 'file:///foo%23bar' },
203 | { path: '/foo&bar', fileURL: 'file:///foo&bar' },
204 | { path: '/foo=bar', fileURL: 'file:///foo=bar' },
205 | { path: '/foo:bar', fileURL: 'file:///foo:bar' },
206 | { path: '/foo;bar', fileURL: 'file:///foo;bar' },
207 | { path: '/foo%bar', fileURL: 'file:///foo%25bar' },
208 | { path: '/foo\\bar', fileURL: 'file:///foo%5Cbar' },
209 | { path: '/foo\bbar', fileURL: 'file:///foo%08bar' },
210 | { path: '/foo\tbar', fileURL: 'file:///foo%09bar' },
211 | { path: '/foo\nbar', fileURL: 'file:///foo%0Abar' },
212 | { path: '/foo\rbar', fileURL: 'file:///foo%0Dbar' },
213 | { path: '/fóóbàr', fileURL: 'file:///f%C3%B3%C3%B3b%C3%A0r' },
214 | { path: '/€', fileURL: 'file:///%E2%82%AC' },
215 | { path: '/🚀', fileURL: 'file:///%F0%9F%9A%80' }
216 | ];
217 |
218 | for (const { path, fileURL } of testCases) {
219 | const fromString = url.fileURLToPath(fileURL);
220 | assert.strictEqual(fromString, path);
221 | const fromURL = url.fileURLToPath(new URL(fileURL));
222 | assert.strictEqual(fromURL, path);
223 | }
224 | }
225 | });
226 |
227 | it('url.format, URL instance passed as first argument', function () {
228 | const myURL = new URL('http://xn--lck1c3crb1723bpq4a.com/a?a=b#c');
229 |
230 | assert.strictEqual(
231 | url.format(myURL),
232 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
233 | );
234 |
235 | assert.strictEqual(
236 | url.format(myURL, {}),
237 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
238 | );
239 |
240 | [true, 1, 'test', Infinity].forEach((value) => {
241 | // @ts-ignore
242 | assert.throws(() => url.format(myURL, value), TypeError);
243 | });
244 |
245 | /*
246 | * Any falsy value other than undefined will be treated as false.
247 | * Any truthy value will be treated as true.
248 | */
249 |
250 | assert.strictEqual(
251 | url.format(myURL, { fragment: false }),
252 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
253 | );
254 |
255 | assert.strictEqual(
256 | // @ts-ignore
257 | url.format(myURL, { fragment: '' }),
258 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
259 | );
260 |
261 | assert.strictEqual(
262 | // @ts-ignore
263 | url.format(myURL, { fragment: 0 }),
264 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b'
265 | );
266 |
267 | assert.strictEqual(
268 | // @ts-ignore
269 | url.format(myURL, { fragment: 1 }),
270 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
271 | );
272 |
273 | assert.strictEqual(
274 | // @ts-ignore
275 | url.format(myURL, { fragment: {} }),
276 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
277 | );
278 |
279 | assert.strictEqual(
280 | // @ts-ignore
281 | url.format(myURL, { search: false }),
282 | 'http://xn--lck1c3crb1723bpq4a.com/a#c'
283 | );
284 |
285 | assert.strictEqual(
286 | // @ts-ignore
287 | url.format(myURL, { search: '' }),
288 | 'http://xn--lck1c3crb1723bpq4a.com/a#c'
289 | );
290 |
291 | assert.strictEqual(
292 | // @ts-ignore
293 | url.format(myURL, { search: 0 }),
294 | 'http://xn--lck1c3crb1723bpq4a.com/a#c'
295 | );
296 |
297 | assert.strictEqual(
298 | // @ts-ignore
299 | url.format(myURL, { search: 1 }),
300 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
301 | );
302 |
303 | assert.strictEqual(
304 | // @ts-ignore
305 | url.format(myURL, { search: {} }),
306 | 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c'
307 | );
308 | });
309 | });
310 |
311 | describe('`querystring` additional exports', function () {
312 | describe('escape', function () {
313 | it('does basic escaping', function () {
314 | // @ts-ignore
315 | assert.deepEqual(qs.escape(5), '5');
316 | assert.deepEqual(qs.escape('test'), 'test');
317 | // @ts-ignore
318 | assert.deepEqual(qs.escape({}), '%5Bobject%20Object%5D');
319 | // @ts-ignore
320 | assert.deepEqual(qs.escape([5, 10]), '5%2C10');
321 | assert.deepEqual(qs.escape('Ŋōđĕ'), '%C5%8A%C5%8D%C4%91%C4%95');
322 | assert.deepEqual(
323 | qs.escape('testŊōđĕ'),
324 | 'test%C5%8A%C5%8D%C4%91%C4%95'
325 | );
326 | assert.deepEqual(qs.escape('�test'), '%EF%BF%BDtest');
327 | });
328 |
329 | it('using toString for objects', function () {
330 | assert.strictEqual(
331 | // @ts-ignore
332 | qs.escape({
333 | test: 5,
334 | toString: () => 'test',
335 | valueOf: () => 10
336 | }),
337 | 'test'
338 | );
339 | });
340 |
341 | it('toString is not callable, must throw an error', function () {
342 | // @ts-ignore
343 | assert.throws(() => qs.escape({ toString: 5 }));
344 | });
345 |
346 | it('should use valueOf instead of non-callable toString', function () {
347 | assert.strictEqual(
348 | // @ts-ignore
349 | qs.escape({ toString: 5, valueOf: () => 'test' }),
350 | 'test'
351 | );
352 | });
353 |
354 | it('throws when given Symbol', function () {
355 | try {
356 | // @ts-ignore
357 | qs.escape(Symbol('test'));
358 | } catch (error) {
359 | if (
360 | error instanceof TypeError &&
361 | /[Ss]ymbol.+string/.test(error.message)
362 | ) {
363 | assert.ok(true);
364 | } else {
365 | throw error;
366 | }
367 | }
368 | });
369 | });
370 |
371 | describe('unescape', function () {
372 | it('does basic unescaping', function () {
373 | assert.deepEqual(qs.unescape('5'), '5');
374 | assert.deepEqual(qs.unescape('test'), 'test');
375 | assert.deepEqual(
376 | qs.unescape('%5Bobject%20Object%5D'),
377 | '[object Object]'
378 | );
379 | assert.deepEqual(qs.unescape('5%2C10'), '5,10');
380 | assert.deepEqual(qs.unescape('%C5%8A%C5%8D%C4%91%C4%95'), 'Ŋōđĕ');
381 | assert.deepEqual(
382 | qs.unescape('test%C5%8A%C5%8D%C4%91%C4%95'),
383 | 'testŊōđĕ'
384 | );
385 | assert.deepEqual(qs.unescape('%EF%BF%BDtest'), '�test');
386 | });
387 |
388 | it('using JSON objects', function () {
389 | assert.strictEqual(
390 | qs.unescape(
391 | JSON.stringify({
392 | test: 5,
393 | toString: () => 'test',
394 | valueOf: () => 10
395 | })
396 | ),
397 | '{"test":5}'
398 | );
399 | });
400 |
401 | it('throws when given Symbol', function () {
402 | try {
403 | // @ts-ignore
404 | qs.unescape(Symbol('test'));
405 | } catch (error) {
406 | if (
407 | error instanceof TypeError &&
408 | /[Ss]ymbol.+string/.test(error.message)
409 | ) {
410 | assert.ok(true);
411 | } else {
412 | throw error;
413 | }
414 | }
415 | });
416 | });
417 | });
418 |
419 | describe('`process` additional exports', function () {
420 | it('has exports for browser environment', function () {
421 | assert.equal(_process.title, 'browser');
422 | assert.equal(_process.browser, true);
423 | assert.equal(_process.arch, 'browser');
424 | assert.equal(_process.platform, 'browser');
425 | assert.ok(Array.isArray(_process.execArgv));
426 | assert.ok(typeof _process.emitWarning !== 'undefined');
427 | });
428 | });
429 |
430 | const nodeVersion = parseNodeVersion(process.version);
431 | const shouldBundle = nodeVersion.major >= 12;
432 | const shouldBundleESM = nodeVersion.major >= 16;
433 |
434 | describe('Bundling', function () {
435 | this.timeout(60000 * 2);
436 |
437 | const cwd = path.resolve(__dirname, '../example');
438 |
439 | before(async function () {
440 | if (shouldBundle) {
441 | await execa('npm', ['install'], { cwd });
442 | await execa('npm', ['run', 'build'], { cwd });
443 | }
444 | });
445 |
446 | it('bundles for Webpack', async function () {
447 | const bundles = [];
448 | if (shouldBundle) {
449 | bundles.push(execa('npm', ['run', 'build:webpack:cjs'], { cwd }));
450 | }
451 | if (shouldBundleESM) {
452 | /* Bundles.push(execa('npm', ['run', 'build:webpack:esm'], { cwd }));*/
453 | }
454 | await Promise.all(bundles);
455 | assert.ok(true);
456 | });
457 |
458 | it('bundles for Rollup', async function () {
459 | const bundles = [];
460 | if (shouldBundle) {
461 | bundles.push(execa('npm', ['run', 'build:rollup:cjs'], { cwd }));
462 | }
463 | if (shouldBundleESM) {
464 | bundles.push(execa('npm', ['run', 'build:rollup:esm'], { cwd }));
465 | }
466 | await Promise.all(bundles);
467 | assert.ok(true);
468 | });
469 |
470 | it('bundles for Vite', async function () {
471 | const bundles = [];
472 | if (shouldBundle) {
473 | bundles.push(execa('npm', ['run', 'build:vite:cjs'], { cwd }));
474 | }
475 | if (shouldBundleESM) {
476 | bundles.push(execa('npm', ['run', 'build:vite:esm'], { cwd }));
477 | }
478 | await Promise.all(bundles);
479 | assert.ok(true);
480 | });
481 |
482 | it('bundles for esbuild', async function () {
483 | const bundles = [];
484 | if (shouldBundle) {
485 | bundles.push(execa('npm', ['run', 'build:esbuild:cjs'], { cwd }));
486 | }
487 | if (shouldBundleESM) {
488 | bundles.push(execa('npm', ['run', 'build:esbuild:esm'], { cwd }));
489 | }
490 | await Promise.all(bundles);
491 | assert.ok(true);
492 | });
493 |
494 | it('bundles for Browserify', async function () {
495 | const bundles = [];
496 | if (shouldBundle) {
497 | bundles.push(
498 | execa('npm', ['run', 'build:browserify:cjs'], { cwd })
499 | );
500 | }
501 | if (shouldBundleESM) {
502 | bundles.push(
503 | execa('npm', ['run', 'build:browserify:esm'], { cwd })
504 | );
505 | }
506 | await Promise.all(bundles);
507 | assert.ok(true);
508 | });
509 | });
510 |
--------------------------------------------------------------------------------