Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Sass variables and documenting BEM/OOCSS hierarchy/relationships #15

Closed
alademann opened this issue Jun 24, 2014 · 6 comments

Comments

@alademann
Copy link
Contributor

Hugo...

I'm curious if it would be possible to support non-mixin/function documentation? I'm needing something like http://sassdocjs.com/doc/, but that repo's code is borderline un-maintainable IMO.

The function and mixin parsing is awesome - and I need that piece. But in order to document a modular front-end framework built with Sass, there are a few more pieces to the puzzle for me. (These are all just suggestions / open for discussion obviously)

First thing is... I need a way to document some basic Sass $variables (and maybe event some nifty Sass map-typed variable traversal).

I also need to document / describe relationships / dependencies between Sass entities (classes, placeholders, ids, etc...) and entire modules (read: Sass partials) in a very large, very modular BEM/OOCSS platform.

I would propose adding the following definitions (I also understand if this needs to be broken into separate issues, but wanted to get a discussion rolling in one place):

Variables

  • @var {type | other type} $name (default value) - description of var
    • I'm assuming combining this with something like @private means that it is scoped to a module, and combined with @public means that it would be declared using !global?
    • Vars would need to be able to declare dependencies on other vars / modules containing vars (see example $panel var below)

Meta

  • @example - provide brief HTML implementation example
  • @usedin - similar to @link - provide an example where a developer could see it being used
  • @since - provide a version when a specific class/function/mixin was made available
  • @support - list of supported browsers for a module

Modular (BEM/OOCSS) Hierarchy

  • @module - define a file as a module.
    • @base - define a class/id as a "base" class/id for a module.
      • @element - define a class/id as a "element" class/id for a "base" class/id
      • @modifier {type} - define a class/id as a "modifier" class/id for a "base" or "element" class/id
        • The {type} would be "open-ended", but would be something like variant or state, for example.
  • @depends - similar to @requires - except this would create a link to an external @module (or even some JS) that is not implied via the declared @base/@element/@modifier syntax.
    • allow multiple via comma-separated list - or multiple @depends lines (see $panel var example below)?
  • @extends - similar to @depends, but this type of element would automatically extend a dependency instead of implying that the other module/component had to be used/included separately.

Example

Below is an example "module" - in a platform that shows a little bit of what I'm envisioning / describing above.

  • This file would be located in a taxonomy such as sass/core/modules/_panels.scss.
// ---------------------------------------------------------
// @module core/modules/panels
// --- 
// Flexible containers that help to isolate/provide context 
// to other core elements in the platform.
// ---
// @since 0.2.1
// ---
// @example
//   <div class="panel panel-default">
//     <div class="panel-heading">
//       <h3 class="panel-title">Panel title</h3>
//     </div>
//     <div class="panel-body">
//       Panel content
//     </div>
//     <div class="panel-footer">
//       Panel content
//     </div>
//   </div>
// ---
// @link http://mystyleguide.com/core/modules/panels
// ---------------------------------------------------------


// @private @var $panel {map} - stores configuration options for .panel module
// ---
// @since 0.5.0
// ---
// @depends core/config/defaults, core/config/colors
$panel: (
  'base': (
    'default': (
      'text': $gray-dark,
      'bg': #fff,
      'bd': #ddd 
    ),
    'success': (
      'text': $state-success-text,
      'bg': $state-success-bg,
      'bd': $state-success-bd
    )
  ),
  'body': (
    'padding': 15px
  ),
  'heading': (
    'padding': 10px 15px
  ),
  'footer': (
    'padding': 10px 15px
  )
) !default;


// @base panel
// ---
// Must be combined with one of the variant modifiers to gain styling.
.panel {
  foo: bar;
}

// @element panel-body
// ---
// Panel contents
.panel-body {
  foo: bar;
}

// @element panel-heading
// ---
// Optional heading above panel contents
// --
// @link http://mystyleguide.com/core/modules/panels-with-heading
.panel-heading {
  foo: bar;
}

// @element panel-title
// ---
// Within panel-heading, strip any `h*` tag of its default margins for spacing.
.panel-title {
  foo: bar;
}

// @element panel-footer
// ---
// Optional footer below panel contents
.panel-footer {
  foo: bar;
}

// @element panel>list-group
// ---
// List groups in panels
// ---
// @depends core/modules/list-groups
// ---
// @link http://mystyleguide.com/core/modules/panels-list-group
// ---
// @example
//   <div class="panel panel-default">
//     <!-- Default panel contents -->
//     <div class="panel-heading">Panel heading</div>
//     <div class="panel-body">...</div>
//   
//     <!-- List group -->
//     <ul class="list-group">
//       ...
//     </ul>
//   </div>
.panel > .list-group {
  foo: bar;
}

// @element panel>table
// ---
// Tables in panels
// ---
// @depends core/modules/tables
// ---
// @link http://mystyleguide.com/core/modules/panels-tables
// ---
// @example
//   <div class="panel panel-default">
//     <!-- Default panel contents -->
//     <div class="panel-heading">Panel heading</div>
//     <div class="panel-body">...</div>
//   
//     <!-- Table -->
//     <table class="table">
//       ...
//     </table>
//   </div>
.panel > .table {
  foo: bar;
}

// @modifier {variant} default
.panel-default {
    foo: bar;
}

// @modifier {variant} success
.panel-success {
  foo: bar;
}

// @modifier {size-variant} small
.panel-sm {
  foo: bar;
}

// @modifier {state} is-focused
// ---
// @depends js/modules/panels
.panel.is-focused {
    foo: bar;
}

Thanks so much for discussing/considering this - I'm happy to do whatever I can to contribute if you think these are valuable additions to the repo. Any other thoughts on how to make this more intuitive are most welcome and appreciated!

@KittyGiraudel
Copy link
Member

Hello Aaron and thanks a lot for taking the time to have a look.

First, let me remind this project is veryyyyyy young. I have only worked on it for a couple of hours with the help of @valeriangalliat, and I'd never written a single line of Node before it, so it's pretty much a crash test here! That being said, since https://github.com/eoneill/sassdoc has been dead for like 2 years... I thought it might be a good idea to give it a try.

Anyway.


I am willing to include variable documentation. I think it's a perfectly valid request. I'd like to see something like this:

// @var {type} name (value) - description
$var: my variable;

This would be a good way to keep in sync with parameter parsing but I am not convinced with the value being between curved braces. I feel like it should have a stronger place in the line. We'll have to think about it.


I need to implement @example but for that, I need to turn the whole thing into a real parser, and not some shitty regular expressions.

Eventually I want to end up with this:

// @example
//    clamp(10, 1, 5)
//    // -> 5

Or something like that.


Fully okay with @since. Will be very easy to add by the way.


I'll update this comment when I get time.

@aaronlademann-wf
Copy link

Cool, thanks Hugo!

@valeriangalliat
Copy link
Member

Hi all,

Thanks Aaron for all these suggestions! This will bring SassDoc to a new level for sure - and Hugo was just searching improvements ideas. :)

Variables

About the variable documentation, I don't see the need to include the variable name and default value in the docstring. The actual variable declaration just below is giving the name and default value, so why not just display it (like the function/mixin signatures)?

// @var {type} description
$var: default value;

I think we could epurate @param in the same way. Since there may be multiple @params it's more readable to keep the name, but the default value can still be deducted from the signature.

Maybe the @public annotation can be ommited too, since we can see the !global in the variable signature.

Maps

It's interesting to add a documentation format for (nested) maps. I don't like the JSDoc way of doing this:

/**
 * @param {Object} options
 * @param {String} options.foo
 * @param {Number} options.bar
 */

I'd see something more like YAML (this is not valid YAML though):

// @var {map}
//   base:
//     default: {type} description
//       text: {type} description
//       bg: {type} description
//       bd: {type} description
//     success: {type} description
//   ... 
$panel: (...);

But I'm not really sure about it, it will be really verbose.

Another possibility is to add comments directly in the map declaration:

// @var {map} description
$panel: (
  'base': (
    'default': ( // @key {type} description
      'text': $gray-dark, // @key {type} description
      'bg': #fff, // @key {type} description
      'bd': #ddd, // @key {type} description
    ),
  ),
);

This would require to parse the whole map to extract the structure, but it's more lightweight to define.

Otherwise, if we display the real variable declaration in the documentation, simple comments like above even without the @key would be sufficient to understand the purpose of the commented keys. For example the Kohana framework's API browser displays the full source code of a function below the formatted docblock, and I find this really handy. A similar thing for variable declarations including comments can be sufficient.

Examples

The @example annotation is a bit tricky for the syntax highlighting. We can want it to highlight Sass or HTML depending on the cases. I think it's fair to assume an @example on a mixin or function will be in Sass, but will contain HTML when applied on a CSS class.

If needed, an optional lang attribute could be added after @example to set the right syntax highlighting, but I don't really see an use case for this (if the contextual syntax above is implemented).

Also since the "long description" is interpreted as Markdown, it's also possible to define the code samples within the description instead of adding @example. What do you think?

Meta

@usedin is interesting, but I'm not sure about the naming. @see would be more standard, but the semantic is not exactly the same.

@support should be @supports to keep it consistant with @returns, @throws, @depends, etc.

BEM

I like the idea of documenting BEM classes.

Like the name and value for variables, we can also get the class name by looking the line after the docblock, it's redundant to add it after the annotation. But maybe it can be tricky to find it in the selector for more complex cases?

@alademann
Copy link
Contributor Author

@valeriangalliat thanks for taking a look!

Variables
Agreed on all points. the name of the var shouldn't need to be included in the docblock

Maps
I think adding the @key declaration directly in the map is a more ideal solution

Examples
This is low priority IMO - I'm much more interested in the @depends / BEM documentation.

Meta
This is also low priority - but i'm cool with changing @support to @supports.

BEM
This is the piece that the SassDocJS tool demonstrates nicely - but it is a poorly coded solution, and I've yet to be able to get it up and running in a local environment.

I think the base class would still need to be declared in the docblock as I showed in my example - but what you're saying is that the "name" could be omitted for the others if the base class was used as reference like so?

// @base panel
.panel { }

// @element
.panel-body {}

In this example - are you saying that the .panel-body class would be reference-able / defined as @element panel-body since it starts with the class defined as a @base?

What I mean by "reference-able" - is... will the docs be able to demonstrate a linked hierarchy and understand the difference, for instance between a @element (nested within the @base) and a @modifier (additional context for a @base OR @element)?

If the referential integrity can still remain simply by inferring that an @element or @modifier with no name listed should simply be stored based on the line immediately after the docblock... I think that would work fine!

Let me know if that makes sense.

@KittyGiraudel
Copy link
Member

Hello.

Okay, so I got cut yesterday night. Let me come back to what I was saying.

@var

Will be implemented under the following syntax:

// @var {type} - Description
$variable: my variable;

A few notes:

  • The hyphen will be optional
  • A !global flag will make the variable public, else it will be private (scoped)
  • Map won't have any special doc at first, it will eventually come later

@example

I want to implement this, but as I said I need a real parser for this. Regular expressions won't do the trick. That being said, writing a parser is complicated, but I'll give it a try.

For now, I suggest you join them in the description since it is being parsed in Markdown. I haven't tried but I'd say that:

// Here is the description or whatever
//    clamp(10, 0, 5);
//    -> 5

... should work.

@usedin

I like the idea but not the name. Perhaps @see would be enough for me. That being said, I want to have something like that so I'm okay.

@SInCE

Agreed. Will be implemented.

@supports

I am not willing to add this. This is very anecdotal and should belong in the description in my opinion. Unless someone has a very strong reason to add such a feature, this is a nope.

Documenting BEM

Okay, I like that. Although I don't think it's possible to do that with regular expressions right now so until we have a dedicated parser, this probably won't work.

I have hard time seeing the difference between @depends and @requires. As far as possible, I'd like to keep only one, unless both are serving strictly different purposes.


I'll open separated issues for all this stuff. Please move discussion to specific issues.

This was referenced Jun 25, 2014
@alademann
Copy link
Contributor Author

@hugogiraudel awesome - thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

4 participants