Skip to content

Commit

Permalink
Add preliminary removePrefix and removeSuffix things
Browse files Browse the repository at this point in the history
  • Loading branch information
hyperupcall committed Sep 28, 2023
1 parent 1999218 commit 268cf61
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 55 deletions.
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.{md,yaml,yml}]
indent_style = space
indent_size = 2
86 changes: 80 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,84 @@
# template-for-proposals
# String.prototype.removePrefix / String.prototype.removeSuffix

A repository template for ECMAScript proposals.
ECMAScript proposal, specification, and reference implementation for `String.prototype.remove{Prefix,Suffix}`.

## Status

**Author(s)**: @hyperupcall

**Champion(s)**: TBD

**Stage:** 0

## Motivation

The lack of a built-in way to remove a prefix substring or a suffix substring from a string is a great inconvenience and incompleteness of JavaScript. Fixing this paper-cut will bring JavaScript more in line with the conveniences of other modern-day languages.

Current alternatives to a native method are too slow, verbose, and hard-to-read.

Commonly, [`.slice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice) used:

```js
// removePrefix
let str = 'greninja'
str.slice('gren'.length - 1)
// => ninja

// removeSuffix
let str = 'charizard'
str.slice(0, str.length - 'izard'.length)
// => char
```

This approach is difficult to read (especially when nested/repeated) and not semantic.

Sometimes, regular expressions are used:

```js
let str = 'mudkip'
str.replace(/kip$/, '')
```

This isn't performant [jsPerf](https://jsperf.app/haxumu) and requires knowledge of regular expressions.

## Proposed Solution

We propose adding `String.prototype.removePrefix` and `String.prototype.removeSuffix` to the String prototype.

```js
'greninja'.removePrefix('gren')
// => ninja

'charizard'.removeSuffix('izard')
// => char
```

Fixing this paper-cut will bring JavaScript more in line with the conveniences of other modern-day languages.

## High-level API

The proposed signature is:

```js
String.prototype.removePrefix(prefix: string): string
```

```js
String.prototype.removeSuffix(suffix: string): string
```

## Naming

## Comparison to other languages

- Ruby (since v2.5) has [`.delete_prefix`](https://ruby-doc.org/current/String.html#method-i-delete_prefix) and [`.delete_suffix`](https://ruby-doc.org/current/String.html#method-i-delete_suffix)
- Python (since v3.9) has [`.removeprefix`](https://docs.python.org/3/library/stdtypes.html#str.removeprefix) and [`.removesuffix`](https://docs.python.org/3/library/stdtypes.html#str.removesuffix)
- Rust (since v1.45.0) has [`.strip_prefix`](https://doc.rust-lang.org/std/string/struct.String.html#method.strip_prefix) and [`.strip_suffix`](https://doc.rust-lang.org/std/string/struct.String.html#method.strip_suffix)
- Go (since v1.1) has [`strings.TrimPrefix`](https://pkg.go.dev/strings#TrimPrefix) and [`strings.TrimSuffix`](https://pkg.go.dev/strings#TrimSuffix)

## Credit

[proposal-string-replaceall](https://github.com/tc39/proposal-string-replaceall) and [proposal-string-pad-start-end](https://github.com/tc39/proposal-string-pad-start-end).

## Before creating a proposal

Expand All @@ -12,11 +90,7 @@ Please ensure the following:
## Create your proposal repo

Follow these steps:
1. Click the green [“use this template”](https://github.com/tc39/template-for-proposals/generate) button in the repo header. (Note: Do not fork this repo in GitHub's web interface, as that will later prevent transfer into the TC39 organization)
1. Update ecmarkup and the biblio to the latest version: `npm install --save-dev ecmarkup@latest && npm install --save-dev --save-exact @tc39/ecma262-biblio@latest`.
1. Go to your repo settings page:
1. Under “General”, under “Features”, ensure “Issues” is checked, and disable “Wiki”, and “Projects” (unless you intend to use Projects)
1. Under “Pull Requests”, check “Always suggest updating pull request branches” and “automatically delete head branches”
1. Under the “Pages” section on the left sidebar, and set the source to “deploy from a branch” and check “Enforce HTTPS”
1. Under the “Actions” section on the left sidebar, under “General”, select “Read and write permissions” under “Workflow permissions” and click “Save”
1. [“How to write a good explainer”][explainer] explains how to make a good first impression.
Expand Down
42 changes: 21 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
{
"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.2571",
"ecmarkup": "^17.0.0"
},
"engines": {
"node": ">= 12"
}
"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.2638",
"ecmarkup": "^18.0.0"
},
"engines": {
"node": ">= 12"
}
}
13 changes: 13 additions & 0 deletions polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'
if (!String.prototype.removePrefix) {
String.prototype.removePrefix = function removePrefix() {

}
}

if (!String.prototype.removeSuffix) {
String.prototype.removeSuffix = function removeSuffix() {

}
}

56 changes: 28 additions & 28 deletions spec.emu
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,36 @@
<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: Proposal Title Goes Here
stage: -1
contributors: Your Name(s) Here
title: String.prototype.removePrefix / removeSuffix
stage: 0
contributors: Edwin Kofler
</pre>

<emu-clause id="sec-demo-clause">
<h1>This is an emu-clause</h1>
<p>This is an algorithm:</p>
<emu-alg>
1. Let _proposal_ be *undefined*.
1. If IsAccepted(_proposal_) is *true*, then
1. Let _stage_ be *0*<sub>ℤ</sub>.
1. Else,
1. Let _stage_ be *-1*<sub>ℤ</sub>.
1. Return ? ToString(_stage_).
</emu-alg>
<emu-clause id="sec-startswith" type="abstract operation">
<h1>
StartsWith (
_argument_: an ECMAScript language value,
)
</h1>
<dl class="header">
<dt>description</dt>
<dd>It converts _argument_ to an integer representing its Number value with fractional part truncated, or to +∞ or -∞ when that Number value is infinite.</dd>
</dl>
<emu-alg>
1. Return _argument_.
</emu-alg>
</emu-clause>

<emu-clause id="sec-is-accepted" type="abstract operation">
<h1>
IsAccepted (
_proposal_: an ECMAScript language value
): a Boolean
</h1>
<dl class="header">
<dt>description</dt>
<dd>Tells you if the proposal was accepted</dd>
</dl>
<emu-alg>
1. If _proposal_ is not a String, or is not accepted, return *false*.
1. Return *true*.
</emu-alg>
<emu-clause id="String.prototype.removePrefix">
<h1>String.prototype.removePrefix ( _prefix_ )</h1>
<p>When the `removePrefix` method is called, the following steps are taken:</p>
<emu-alg>
1. Let _O_ be ? RequireObjectCoercible(*this* value).
1. Let _S_ be ? ToString(_O_).
1. Let _isPrefix_ be ? StartsWith(_S_).
1. Let _len_ be the length of _S_.
1. Let _substring_ be the *substring* of _S_ from 0 to _len_.
1. If _isPrefix_ is *true*, return _substring_.
1. Return _S_.
</emu-alg>
</emu-clause>

0 comments on commit 268cf61

Please sign in to comment.