Skip to content

Commit

Permalink
Rewrite
Browse files Browse the repository at this point in the history
Rewrite specification. Also remove implementation and change some meta things (per other proposals).
  • Loading branch information
CanadaHonk committed Oct 10, 2024
1 parent fbf4b5a commit 513523e
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 169 deletions.
12 changes: 0 additions & 12 deletions .editorconfig

This file was deleted.

1 change: 0 additions & 1 deletion .gitattributes

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
- run: npm run docs
- uses: actions/upload-pages-artifact@v3
with:
path: "./output"
path: "./build"

deploy:
needs: build
Expand Down
46 changes: 44 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
output/
# Logs
logs
*.log
npm-debug.log*

# Runtime data
pids
*.pid
*.seed

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
package-lock.json
jspm_packages

# Optional npm cache directory
.npm

# Optional REPL history
.node_repl_history

# Only apps should have lockfiles
yarn.lock
package-lock.json
npm-shrinkwrap.json
pnpm-lock.yaml

# Build directory
build
2 changes: 1 addition & 1 deletion license → LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Richie Bendall <[email protected]>
Copyright (c) 2024 ECMA TC39 and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
58 changes: 26 additions & 32 deletions readme.md → README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# `Math.clamp`

ECMAScript proposal and reference implementation for `Math.clamp`.
A TC39 proposal to add `Math.clamp`: a function that constrains a value between an upper and lower bound.

**Author:** Richie Bendall
## Status

**Champion:** None

**Stage:** 0
**Stage:** 0 \
**Champion:** Oliver Medhurst (@canadahonk) \
**Authors:** Oliver Medhurst (@canadahonk), Richie Bendall (@richienb) \
**Last Presented:** (unpresented)

## Overview and motivation

Expand Down Expand Up @@ -54,67 +55,60 @@ We name it the function `clamp`, like how it is in other programming languages..
...and userland implementations:

- [`clamp`](https://github.com/hughsk/clamp/blob/377851f0cca9f3f134b53881e294782cccdae4d8/index.js#L3-L7)
- [`math-clamp`][math-clamp]
- [`math-clamp`](https://github.com/sindresorhus/math-clamp/blob/3897064dd3e9711a2e47e891d0aa7eb66ccdcef8/index.js#L1-L15)
- [`lodash`](https://github.com/lodash/lodash/blob/bb7c95947914d12af5f79e7369dd59ce29bc61a8/clamp.js)
- [`three.js`](https://github.com/mrdoob/three.js/blob/431baa0a0e808637df959aa547c98e0b2380bdbe/src/math/MathUtils.js#L43-L47)
- [`p5.js`](https://github.com/processing/p5.js/blob/098f36ded792fca894fdfd947d3293db5bb35e79/src/math/calculation.js#L111-L114)
- [`ramda`](https://github.com/ramda/ramda/blob/6b6a85d3fe30ac1a41ac05734be9f61bd92325e5/source/clamp.js#L23-L32)
- [`sugar`](https://github.com/andrewplummer/Sugar/blob/3ca57818332473b601434001ac1445552d7753ff/lib/range.js#L164-L178)
- [`phaser`](https://github.com/photonstorm/phaser/blob/29ada646e00ebdd375a31eee871be5b10286ba46/src/math/Clamp.js#L19-L22)

Another motivation is to bring parity with the [CSS function][css-clamp] of the same name, although it will have a different parameter order because of the slightly different use cases in each context (also see [the previous discussion on the order of options for CSS `clamp`](https://github.com/w3c/csswg-drafts/issues/2519#issuecomment-387803089).
Another motivation is to bring parity with the [CSS function][css-clamp] of the same name, although it will have a different parameter order because of the slightly different use cases in each context (see also [the previous discussion on the order of options for CSS `clamp`](https://github.com/w3c/csswg-drafts/issues/2519#issuecomment-387803089).

Recognizing the usefulness and improved readability of only specifying either a `min` or `max` (i.e. `Math.min(number, 5)` vs `Math.clamp(number, undefined, 5)`), we consider also allowing `null` or `undefined` as values for `min` and `max` to semantically mean "no upper/lower bound". We consider this as opposed to `Math.clampMin` and `Math.clampMax`, or an option bag, to remain conventional to the language.
The original proposal intended to have the `min` and `max` arguments optional and allowing `null` or `undefined` as values to mean no upper/lower bound; but following [recent TC39 requirements](https://github.com/tc39/how-we-work/blob/main/normative-conventions.md#when-required-arguments-are-missing-throw), it was agreed among some delegates that it would be best to not do this, especially since `Math.min`/`Math.max` remains available for uses with a single bound.

## Examples

The proposed API allows a developer to clamp numbers like:

```js
Math.clamp(5, 0, 10);
//=> 5

Math.clamp(-5, 0, 10);
//=> 0
Math.clamp(5, 0, 10) // 5
Math.clamp(-5, 0, 10) // 0
Math.clamp(15, 0, 10) // 10
```

Math.clamp(15, 0, 10);
//=> 10
It supports `-Infinity`/`Infinity` to specify when there is no upper or lower bound, although `Math.min`/`Math.max` are also already available to use:
```js
Math.clamp(5, 0, Infinity) === Math.max(5, 0) // 5
Math.clamp(-5, -Infinity, 10) === Math.min(-5, 10) // -5
```

It handles a larger minimum than maximum number, like how the [CSS `clamp()` function][css-clamp-spec] does.
If the minimum bound is larger than the maximum bound, it throws a `RangeError` to avoid possible developer confusion:

```js
// Minimum number is larger than maximum value
Math.clamp(10, 5, 0);
//=> 10
Math.clamp(10, 5, 0) // RangeError
```

It supports `null`/`undefined`/`-Infinity`/`Infinity` to specify when there is no upper or lower bound:
It also correctly respects `-0` if given:

```js
Math.clamp(5, 0, null);
//=> 5

Math.clamp(5, undefined, 10);
//=> 5
Math.clamp(-2, -0, 10) // -0
Math.clamp(-0, -0, 10) // -0
Math.clamp(0, -0, 10) // 0
```

## Specification

- [Ecmarkup source](spec.html)
- [HTML version](https://richienb.github.io/proposal-math-clamp)
- [Ecmarkup source](spec.emu)
- [HTML version](https://canadahonk.github.io/proposal-math-clamp)

## Implementations

- [Reference Polyfill](polyfill.js)

## Acknowledgements

Specification and reference implementation inspired by:
Past work:
- [`Math` Extensions Proposal](https://github.com/rwaldron/proposal-math-extensions)
- [`math-clamp`][math-clamp]

[math-clamp]: https://github.com/sindresorhus/math-clamp/blob/3897064dd3e9711a2e47e891d0aa7eb66ccdcef8/index.js#L1-L15
[math-min]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
[math-max]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
[css-clamp]: https://developer.mozilla.org/en-US/docs/Web/CSS/clamp()
Expand Down
4 changes: 0 additions & 4 deletions implementation.d.ts

This file was deleted.

19 changes: 0 additions & 19 deletions implementation.js

This file was deleted.

58 changes: 21 additions & 37 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,39 +1,23 @@
{
"name": "proposal-math-clamp",
"version": "0.1.0",
"description": "ECMAScript reference implementation for `Math.clamp`.",
"repository": "Richienb/proposal-math-clamp",
"author": {
"name": "Richie Bendall",
"email": "[email protected]"
},
"license": "MIT",
"type": "module",
"exports": {
".": "./implementation.js",
"./polyfill": "./polyfill.js"
},
"files": [
"implementation.js",
"implementation.d.ts",
"polyfill.js"
],
"engines": {
"node": ">=12.20"
},
"scripts": {
"docs": "ecmarkup spec.html output/index.html --lint-spec",
"test": "xo && node ./test-implementation.js"
},
"keywords": [
"math",
"clamp"
],
"dependencies": {
"es-abstract": "^1.20.1"
},
"devDependencies": {
"ecmarkup": "^9.4.1",
"xo": "^0.45.0"
}
"private": true,
"name": "template-for-proposals",
"description": "A repository template for ECMAScript proposals.",
"scripts": {
"start": "npm run build-loose -- --watch",
"build": "npm run build-loose -- --strict",
"build-loose": "node -e 'fs.mkdirSync(\"build\", { recursive: true })' && ecmarkup --load-biblio @tc39/ecma262-biblio --verbose spec.emu build/index.html --lint-spec"
},
"homepage": "https://github.com/tc39/template-for-proposals#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/tc39/template-for-proposals.git"
},
"license": "MIT",
"devDependencies": {
"@tc39/ecma262-biblio": "2.1.2778",
"ecmarkup": "^20.0.0"
},
"engines": {
"node": ">= 12"
}
}
7 changes: 0 additions & 7 deletions polyfill.js

This file was deleted.

36 changes: 36 additions & 0 deletions spec.emu
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!doctype html>
<meta charset="utf8">
<link rel="stylesheet" href="./spec.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/github.min.css">
<script src="./spec.js"></script>
<pre class="metadata">
title: Math.clamp
stage: 0
contributors: Oliver Medhurst, Richie Bendall
</pre>

<emu-intro id="intro">
<h1>Introduction</h1>
<p><a href="https://github.com/CanadaHonk/proposal-math-clamp">`Math.clamp()` constrains a value between an upper and lower bound.</a></p>
</emu-intro>

<emu-clause id="sec-math.clamp">
<h1>Math.clamp ( _value_, _min_, _max_ )</h1>
<p>This function returns the Number value that is the result of constraining _number_ between the bounds defined by _min_ and _max_.</p>
<emu-alg>
1. If _value_ is not a Number, throw a *TypeError* exception.
1. If _min_ is not a Number, throw a *TypeError* exception.
1. If _min_ is *NaN*, throw a *RangeError* exception.
1. If _max_ is not a Number, throw a *TypeError* exception.
1. If _max_ is *NaN*, throw a *RangeError* exception.
1. If _min_ ≥ _max_, throw a *RangeError* exception.
1. If _value_ is *NaN*, return *NaN*.
1. If _value_ is *-0*<sub>𝔽</sub> and _min_ is *+0*<sub>𝔽</sub>, return _min_.
1. If _value_ is *+0*<sub>𝔽</sub> and _min_ is *-0*<sub>𝔽</sub>, return _min_.
1. If _value_ < _min_, return _min_.
1. If _value_ is *-0*<sub>𝔽</sub> and _max_ is *+0*<sub>𝔽</sub>, return _max_.
1. If _value_ is *+0*<sub>𝔽</sub> and _max_ is *-0*<sub>𝔽</sub>, return _max_.
1. If _value_ > _max_, return _max_.
1. Return _value_.
</emu-alg>
</emu-clause>
26 changes: 0 additions & 26 deletions spec.html

This file was deleted.

3 changes: 0 additions & 3 deletions test-implementation.js

This file was deleted.

24 changes: 0 additions & 24 deletions test.js

This file was deleted.

0 comments on commit 513523e

Please sign in to comment.