Skip to content

Instantly share code, notes, and snippets.

@icecream17
Last active March 9, 2023 18:44
Show Gist options
  • Save icecream17/674c8567f9a2dae9ca65e4059e519b65 to your computer and use it in GitHub Desktop.
Save icecream17/674c8567f9a2dae9ca65e4059e519b65 to your computer and use it in GitHub Desktop.
Proposals for ranges in Svelte at https://github.com/sveltejs/svelte/issues/2968

Svelte range proposals

This file shows all syntax alternatives suggested here: sveltejs/svelte#2968

Possible right now

Recommended: sveltejs/svelte#4401 (comment)

{#each { length: n } as _, i}
{#each Array(n) as _, i}

Range keyword / function

Judging sveltejs/svelte#2968 (comment) to be:

{#each range(begin, end, stop) as n}

sveltejs/svelte#2968 (comment) gives

export default function range(from, to) {
	if (!(to > from)) throw ("first argument must be smaller then second one");
	if (from !== parseInt(from) || to !== parseInt(to)) throw ("arguments must be of type integer");
	if (from < 0 || to < 0) throw ("arguments must be positive");

	var elements = to - from + 1;
	return [...Array(elements)].map((_, i) => i += from);
}

// I couldn't help but edit this
export default function range(from, to) {
	if (from > to) throw Error("first argument must be smaller then second one");
	if (!Number.isInteger(to) || !Number.isInteger(from)) throw Error("arguments must be integers");
	if (from < 0 || to < 0) throw Error("arguments must be positive");

	var elements = to - from + 1;
	return [...Array(elements)].map((_, i) => i + from);
}
  

// But of course I should've scrolled down
function range(from, to, includeFrom = true) {
  let isString = false

  // Number.isInteger?
  if (from !== parseInt(from) || to !== parseInt(to)) {
    if (typeof from === 'string' && typeof to === 'string') {
      isString = true
      from = from[0].charCodeAt(0)
      to = to[0].charCodeAt(0)
    } else {
      throw (`'range' arguments must be of type integer or string`);
    }
  }

  const distance = Math.abs(to - from)
  const length = distance + ((includeFrom || distance > 0) ? 1 : 0)

  const elements = [...Array(length)]

  if (isString) {
    if (from > to) {
      return elements.map( (_, i) => String.fromCharCode(from - i) )
    }
    return elements.map( (_, i) => String.fromCharCode(from + i) )
  } else {
    if (from > to) {
      return elements.map( (_, i) => from - i)
    }
    return elements.map( (_, i) => from + i)
  }
}

Extensions to existing syntax

Some of these can be combined with other proposals

#each but omit as

<!-- Default variable is "_": -->
{#each Array(n) i}

{/each}

{#each { length: n } i }

{/each}

<!-- Special syntax -->
{#each n i}

{/each}

Comma arguments

<!-- index is optional -->
{#range from, to (index)}

{/range}

Ex:

{#range 1, 100}

{/range}

{#range 1, 100 (i)}
	<p>{i}</p>
{/range}

Number as a shorthand

{#range 5 as n} // [0, 5)

Can't use each because the static compiler can't tell if this is a number or array:

{#each v as n} // [0, v) or element of v?

Each block

But see sveltejs/svelte#2968 (comment) and later comments

{#each 1..5 as n}

Probably not what was meant

{#each Array in range 1 to 10 as i}

Support iterable

sveltejs/svelte#2968 (comment)

export function* range(start: number, end: number, step: number = 1) {
    for (let i = start; i <= end; i += step) {
        yield i;
    }
}
{#each range(1, 5) as num}

<!-- If you don't need `num` -->
{#each range(1, 5)}

Iterate-for keyword

{#iterate-for i in range(begin,end,step)}

<!-- unrelated? -->
{#iterate-while (condition)}

For keyword

{{#for key in object}}
  {{object[key]}}
{{/for}}

{{#for thing of iterable}}
  {{thing}}
{{/for}}

{{#for [key, value] of map}}
  {{key}}: {{value}}
{{/for}}

And in this case

{#for 1 to 10 as n}
  {n}
{/for}

// optionally have a step clause
{#for 1 to 10 step 2 as n}
  {n}
{/for}

Or maybe even

{#for thing, index of iterable}
  {index}:{thing}
{/for}

{#for [key, value], index of map}
  {index}:{key}:{value}
{/for}

Replace dots with To, Until

{#range 1 to 5 as n}    // closed: 1,2,3,4,5
{#range 1 until 5 as n} //   open: 1,2,3,4

Repeat keyword

{#repeat 10} // [1, 10]
{#repeat 10 i} // Same but puts current value in variable "i"
{#repeat n i} // Unambiguous [1, n] --> "i"

Other languages

Using range here, but each could apply as well

Again, combinations can happen

Coffeescript

Original submission

{#range [0..4] as n}

Actual coffeescript

{#range [0..4] as n} // Inclusive
{#range [0...4] as n} // Exclusive
{#range [0..4] by 2 as n}

F#

regarding step:

0..10..100  // 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100

Haskell

{#range 7, 5..50 as n} <!-- use comma to denote step and use .. for range specification  -->

Nim, Swift

{#range 1..5 as n}  // closed: 1,2,3,4,5
{#range 1..<5 as n} //   open: 1,2,3,4

Ruby

Ruby supports chars as well

{#range 1..5 as n}  // closed: 1,2,3,4,5
{#range 1...5 as n} //   open: 1,2,3,4
{#range (1..5).step(2) as n} // Not originally mentioned

Rust

{#range 1..5 as n} // 1 2 3 4
{#range 1..=5 as n} // 1 2 3 4 5

Sass

{#range 1 to 5 as n}      // Exclusive
{#range 1 through 5 as n} // Inclusive

Vue

<span v-for="n in 10">{{ n }}</span>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment