Skip to content

Commit

Permalink
Provide a stateless API (#1130)
Browse files Browse the repository at this point in the history
Add a separate module which provides a stateless version of the shescape
API. It exposes the same API as an instance of the `Shescape` class,
allowing usage without instantiating a class. This is mostly useful for
use cases where escaping only needs to be done once, e.g. CLI tools.
  • Loading branch information
ericcornelissen authored Dec 20, 2023
1 parent 88af241 commit 3722970
Show file tree
Hide file tree
Showing 22 changed files with 735 additions and 8 deletions.
3 changes: 3 additions & 0 deletions .github/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,21 @@ flags:
paths:
- src/
- index.js
- stateless.js
- testing.js
integration-Ubuntu:
carryforward: true
paths:
- src/
- index.js
- stateless.js
- testing.js
integration-Windows:
carryforward: true
paths:
- src/
- index.js
- stateless.js
- testing.js
unit:
carryforward: true
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ checksums.txt
crash-*
index.cjs
index.d.cts
stateless.cjs
stateless.d.cts
testing.cjs
testing.d.cts

Expand Down
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
!LICENSE
!README.md
!SECURITY.md
!stateless.cjs
!stateless.d.cts
!stateless.d.ts
!stateless.js
!testing.cjs
!testing.d.cts
!testing.d.ts
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Versioning].

## [Unreleased]

- Add `shescape/stateless` module with v1-like API. ([#1130])
- Re-export `Shescape` as `Stubscape` from `shescape/testing`. ([#1308])

## [2.0.2] - 2023-11-19
Expand Down Expand Up @@ -321,6 +322,7 @@ Versioning].
[#1082]: https://github.com/ericcornelissen/shescape/pull/1082
[#1083]: https://github.com/ericcornelissen/shescape/pull/1083
[#1094]: https://github.com/ericcornelissen/shescape/pull/1094
[#1130]: https://github.com/ericcornelissen/shescape/pull/1130
[#1137]: https://github.com/ericcornelissen/shescape/pull/1137
[#1142]: https://github.com/ericcornelissen/shescape/pull/1142
[#1149]: https://github.com/ericcornelissen/shescape/pull/1149
Expand Down
2 changes: 1 addition & 1 deletion config/c8/breakage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"all": true,
"include": ["src/", "index.js", "testing.js"],
"include": ["src/", "index.js", "stateless.js", "testing.js"],
"exclude": [],
"check-coverage": false,
"reports-dir": "_reports/coverage/breakage",
Expand Down
2 changes: 1 addition & 1 deletion config/c8/compat.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"all": true,
"include": ["src/", "index.js", "testing.js"],
"include": ["src/", "index.js", "stateless.js", "testing.js"],
"exclude": [],
"check-coverage": false,
"reports-dir": "_reports/coverage/compat",
Expand Down
2 changes: 1 addition & 1 deletion config/c8/integration-unix.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"all": true,
"include": ["src/", "index.js", "testing.js"],
"include": ["src/", "index.js", "stateless.js", "testing.js"],
"exclude": ["src/win/", "src/win.js"],
"check-coverage": false,
"reports-dir": "_reports/coverage/integration",
Expand Down
2 changes: 1 addition & 1 deletion config/c8/integration-win.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"all": true,
"include": ["src/", "index.js", "testing.js"],
"include": ["src/", "index.js", "stateless.js", "testing.js"],
"exclude": ["src/unix/", "src/unix.js"],
"check-coverage": false,
"reports-dir": "_reports/coverage/integration",
Expand Down
2 changes: 2 additions & 0 deletions config/eslint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -755,5 +755,7 @@ ignorePatterns:
- script/maybe-run.js
- index.cjs
- index.d.cts
- stateless.cjs
- stateless.d.cts
- testing.cjs
- testing.d.cts
8 changes: 8 additions & 0 deletions config/rollup.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ export default [
},
external,
},
{
input: "stateless.js",
output: {
file: "stateless.cjs",
format: "cjs",
},
external,
},
{
input: "testing.js",
output: {
Expand Down
2 changes: 1 addition & 1 deletion config/stryker/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export default {
coverageAnalysis: "perTest",
inPlace: false,
mutate: ["index.js", "testing.js"],
mutate: ["index.js", "stateless.js", "testing.js"],
testRunner: "tap",
tap: {
testFiles: ["test/integration/**/*.test.js"],
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*
* @since 2.0.0
*/
interface ShescapeOptions {
export interface ShescapeOptions {
/**
* Whether or not to protect against flag and option (such as `--verbose`)
* injection
Expand Down
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
"default": "./index.cjs"
}
},
"./stateless": {
"import": {
"types": "./stateless.d.ts",
"default": "./stateless.js"
},
"require": {
"types": "./stateless.d.cts",
"default": "./stateless.cjs"
}
},
"./testing": {
"import": {
"types": "./testing.d.ts",
Expand Down
9 changes: 8 additions & 1 deletion script/clean.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ import path from "node:path";

import { common } from "./_.js";

const files = ["index.cjs", "index.d.cts", "testing.cjs", "testing.d.cts"];
const files = [
"index.cjs",
"index.d.cts",
"stateless.cjs",
"stateless.d.cts",
"testing.cjs",
"testing.d.cts",
];
const folders = [".corpus/", ".nyc_output/", ".temp/", "_reports/"];

for (const file of files) {
Expand Down
2 changes: 1 addition & 1 deletion script/create-d-cts.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import path from "node:path";

import { common } from "./_.js";

const files = ["index.d.ts", "testing.d.ts"];
const files = ["index.d.ts", "stateless.d.ts", "testing.d.ts"];

for (const file of files) {
const copy = file.replace(".d.ts", ".d.cts");
Expand Down
108 changes: 108 additions & 0 deletions stateless.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* @overview Contains TypeScript type definitions for Shescape's stateless
* alternative.
* @license MPL-2.0
*/

import type { ShescapeOptions } from "shescape";

/**
* Take a single value, the argument, and escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* spawn(
* "echo",
* ["Hello", shescape.escape(userInput, { shell: false })],
* null // `options.shell` MUST be falsy
* );
* @param {string} arg The argument to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean | string} [options.shell=true] The shell to escape for.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @throws {Error} The shell is not supported or could not be found.
* @since 2.1.0
*/
export function escape(arg: string, options?: ShescapeOptions): string;

/**
* Take an array of values, the arguments, and escape any dangerous characters
* in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string values
* will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* spawn(
* "echo",
* shescape.escapeAll(["Hello", userInput], { shell: false }),
* null // `options.shell` MUST be falsy
* );
* @param {string[]} args The arguments to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean | string} [options.shell=true] The shell to escape for.
* @returns {string[]} The escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @throws {Error} The shell is not supported or could not be found.
* @since 2.1.0
*/
export function escapeAll(args: string[], options?: ShescapeOptions): string[];

/**
* Take a single value, the argument, put shell-specific quotes around it and
* escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* spawn(
* "echo",
* ["Hello", shescape.quote(userInput, { shell: spawnOptions.shell })],
* spawnOptions
* );
* @param {string} arg The argument to quote and escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean | string} [options.shell=true] The shell to escape for.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument is not stringable.
* @throws {Error} The shell is not supported or could not be found.
* @throws {Error} Quoting is not supported with `shell: false`.
* @since 2.1.0
*/
export function quote(arg: string, options?: ShescapeOptions): string;

/**
* Take an array of values, the arguments, put shell-specific quotes around
* every argument and escape any dangerous characters in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string
* values will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* spawn(
* "echo",
* shescape.quoteAll(["Hello", userInput], { shell: spawnOptions.shell }),
* spawnOptions
* );
* @param {string[]} args The arguments to quote and escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean | string} [options.shell=true] The shell to escape for.
* @returns {string[]} The quoted and escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @throws {Error} The shell is not supported or could not be found.
* @throws {Error} Quoting is not supported with `shell: false`.
* @since 2.1.0
*/
export function quoteAll(args: string[], options?: ShescapeOptions): string[];
Loading

0 comments on commit 3722970

Please sign in to comment.