/// Shorthand Syntax Parser /// ======================= /// The syntax parser converts [shorthand syntax][short] /// into a map of settings that can be compared/merged with /// other config maps and global setting. /// /// [short]: api.html /// /// @group _parser // Parse // ----- /// The `parse` function provides all the syntax-sugar in Susy, /// converting user shorthand /// into a usable map of keys and values /// that can be normalized and passed to Su. /// /// @group _parser /// @see $susy /// /// @param {list} $shorthand - /// Shorthand expression to define the width of the span, /// optionally containing: /// - a count, length, or column-list span; /// - `at $n`, `first`, or `last` location on asymmetrical grids; /// - `narrow`, `wide`, or `wider` for optionally spreading /// across adjacent gutters; /// - `of $n ` for available grid columns /// and spread of the container /// (span counts like `of 6` are only valid /// in the context of symmetrical grids); /// - and `set-gutters $n` to override global gutter settings /// @param {bool} $context-only [false] - /// Allow the parser to ignore span and span-spread values, /// only parsing context and container-spread. /// This makes it possible to accept spanless values, /// like the `gutters()` syntax. /// When parsing context-only, /// the `of` indicator is optional. /// /// @return {map} - /// Map of span and grid settings /// parsed from shorthand input – /// including all the properties available globally – /// `columns`, `gutters`, `spread`, `container-spread` – /// along with the span-specific properties /// `span`, and `location`. /// /// @throw /// when a shorthand value is not recognized @function susy-parse( $shorthand, $context-only: false ) { $parse-error: 'Unknown shorthand property:'; $options: ( 'first': 'location', 'last': 'location', 'alpha': 'location', 'omega': 'location', 'narrow': 'spread', 'wide': 'spread', 'wider': 'spread', ); $return: (); $span: null; $columns: null; $of: null; $next: false; // Allow context-only shorthand, without span @if ($context-only) and (not index($shorthand, 'of')) { @if su-valid-columns($shorthand, 'fail-silent') { $shorthand: 'of' $shorthand; } @else { $shorthand: join('of', $shorthand); } } // loop through the shorthand list @for $i from 1 through length($shorthand) { $item: nth($shorthand, $i); $type: type-of($item); $error: false; $details: '[#{$type}] `#{$item}`'; // if we know what's supposed to be coming next… @if $next { // Add to the return map $return: map-merge($return, ($next: $item)); // Reset next to `false` $next: false; } @else { // If we don't know what's supposed to be coming… // Keywords… @if ($type == 'string') { // Check the map for keywords… @if map-has-key($options, $item) { $setting: map-get($options, $item); // Spread could be on the span or the container… @if ($setting == 'spread') and ($of) { $return: map-merge($return, ('container-spread': $item)); } @else { $return: map-merge($return, ($setting: $item)); } } @else if ($item == 'all') { // `All` is a span shortcut $span: 'all'; } @else if ($item == 'at') { // Some keywords setup what's next… $next: 'location'; } @else if ($item == 'set-gutters') { $next: 'gutters'; } @else if ($item == 'of') { $of: true; } @else { $error: true; } } @else if ($type == 'number') or ($type == 'list') { // Numbers & lists… @if not ($span or $of) { // We don't have a span, and we're not expecting context… $span: $item; } @else if ($of) and (not $columns) { // We are expecting context… $columns: $item; } @else { $error: true; } } @else { $error: true; } } @if $error { @return _susy-error('#{$parse-error} #{$details}', 'susy-parse'); } } // If we have span, merge it in @if $span { $return: map-merge($return, ('span': $span)); } // If we have columns, merge them in @if $columns { $return: map-merge($return, ('columns': $columns)); } // Return the map of settings… @return $return; }