Skip to content

Instantly share code, notes, and snippets.

@tommycoppers
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tommycoppers/f761a41296eda2a8577c to your computer and use it in GitHub Desktop.
Save tommycoppers/f761a41296eda2a8577c to your computer and use it in GitHub Desktop.
Map Functions - To add support to native List and Map functions in Sass
// ========================================
// ===== Collections (Maps and Lists) =====
// ========================================
// ------------------------------------------------
// Create and return a new list between a start and end point within provided list
//
// @param {List} $list - List to slice
// @param {Num} $start - Index to start the slice at
// @param {Num} $end - Index to end slice at
//
// @requires _slice-tests()
@function slice($list, $start: 1, $end: length($list)) {
$errors: _slice-tests($list, $start, $end);
@if not $errors {
$result: ();
@for $i from $start through $end {
$result: append($result, nth($list, $i), comma);
}
@return $result;
}
@else {
@return $list;
}
}
@function _slice-tests ($list, $start, $end) {
$errors: false;
@if type-of($start) != number or type-of($end) != number {
@warn "Either $start or $end are not a number for `slice`.";
$errors: true;
}
@else if $start > $end {
@warn "The start index has to be lesser than or equals to the end index for `slice`.";
$errors: true;
}
@else if $start < 1 or $end < 1 {
@warn "List indexes must be non-zero integers for `slice`.";
$errors: true;
}
@else if $start > length($list) {
@warn "List index is #{$start} but list is only #{length($list)} item long for `slice`.";
$errors: true;
}
@else if $end > length($list) {
@warn "List index is #{$end} but list is only #{length($list)} item long for `slice`.";
$errors: true;
}
@return $errors;
}
// ------------------------------------------------
// Shorthand for map-get() which allows for nested value lookup and error handling
//
// @param {Map} $map - Map to parse
// @param {Argslist} $map-chain... - Path to the key (property) of the desired value
//
// @requires _get-initialize-test()
// @requires _get-map-keys-test()
@function get ($map, $map-chain...) {
$initialize-errors: _get-initialize-test($map, $map-chain);
$map-key-errors: false !default;
@if not $initialize-errors {
$key: nth($map-chain, 1);
$map-key-errors: _get-map-keys-test($map, $key);
@if not $map-key-errors {
$result: map-get($map, $key);
@if length($map-chain) > 1 {
$remainder: slice($map-chain, $start: 2);
@return get($result, $remainder...);
}
@return $result;
}
@return $map-chain; // Return if $map-key-errors == true
}
@return $map-chain; // Return if $initialize-errors == true
}
@function _get-initialize-test ($map, $map-chain) {
$errors: false;
@if type-of($map) != map {
@warn "$map needs to be a map. Currently it's a #{type-of($map)}";
$errors: true;
}
@return $errors;
}
@function _get-map-keys-test ($map, $key) {
$errors: false;
@if type-of($map) != map {
@warn "_get-map-keys-test(): $map is not a map";
$errors: true;
}
@if not map-has-key($map, $key) {
@warn "Map doesn't have a key named '#{$key}'!! Available keys include: '#{map-keys($map)}'";
$errors: true;
}
@return $errors;
}
// ------------------------------------------------
// Get the first key or value from a list or map
//
// @param {List|Map} $collection - List or Map
// @param {String} $return - What to return: key or value
//
// @requires _get-in-collection-unit-tests()
@function get-first ($collection, $return: key) {
$return: to-lower_case($return);
$errors: _get-in-collection-unit-tests($collection, $return);
@if not $errors {
@if type-of($collection) == list {
@return nth($collection, 1)
}
@else {
@if $return == 'key' {
@return (nth(map-keys($collection), 1));
}
@else {
@return map-get($collection, nth(map-keys($collection), 1));
}
}
}
@else {
@return false;
}
}
// ------------------------------------------------
// Get the last key or value from a list or map
//
// @param {List|Map} $collection - List or Map
// @param {String} $return - What to return: key or value
//
// @requires _get-in-collection-unit-tests()
@function get-last ($collection, $return: key) {
$return: to-lower_case($return);
$errors: _get-in-collection-unit-tests($collection, $return);
@if not $errors {
@if type-of($collection) == list {
@return nth($collection, length($collection))
}
@else {
@if $return == 'key' {
@return nth(map-keys($collection), length($collection));
}
@else {
@return map-get($collection, nth(map-keys($collection), length($collection)));
}
}
}
@else {
@return false;
}
}
@function _get-in-collection-unit-tests ($collection, $return) {
$collection-types: (list, map);
$returns: (key, value);
@if not index($collection-types, type-of($collection)) {
@warn ('$collection needs to be one of the following: #{$collection-types}. Was a: #{type-of($collection)}');
@return true;
}
@if $return and not index($returns, $return) {
@warn ('$return was: #{$return}, but needs to be one of the following: #{$returns}');
@return true;
}
@if type-of($collection) == list and $return == value {
@warn "$collection is a list, which doesn't have values";
@return true;
}
@return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment