assemble / grunt-assemble-permalinks

Permalinks middleware for Assemble, the static site generator for Grunt.js and Yeoman. This plugin enables powerful and configurable URI replacement patterns, presets, uses Moment.js for parsing dates, and much more.
MIT License
43 stars 11 forks source link

Option to use filename as replacement #42

Closed hariadi closed 10 years ago

hariadi commented 10 years ago

Parse a filename structure like this: 2014-02-11-foo.{hbs,md} and convert it to something like this: dest/blog/2014/02/11/foo/index.html (or depends on preset)

Update

I'll attach commit to add filename replacement option with two test using preset and structure.

When this option true, the date will be stripped from filename and then modify page.basename and page.slug to use replacement version.

And then date strip from filename added to page.data.date property if it not exist in yfm data.

hariadi commented 10 years ago

Related: #22

jonschlinkert commented 10 years ago

this is possible with custom replacement patterns I think. See:

jonschlinkert commented 10 years ago

and https://github.com/assemble/assemble-contrib-permalinks#structure

hariadi commented 10 years ago

Haha. I still don't get the right config using custom replacement patterns/structure

Here example file structure I have:

.
└── _posts
       ├── 2013-10-11-foo.md
       ├── 2013-12-31-last-year.md
       ├── 2014-01-01-new-year.md
       └── 2014-02-12-bar.md

and we can make Assemble to force handlebars to recognize .md files as templates.

blog: {
  options: {
    engine: 'handlebars',
    permalinks: {
      structure: 'basename/index:ext',
    }
  },
  files: {
    '<%= config.dest %>/blog/': ['_posts/*.md']
  }
}

result in

_site/blog/2013-10-11-foo/index.html
_site/blog/2013-12-31-last-year/index.html
_site/blog/2014-01-01-new-year/index.html
_site/blog/2014-02-12-bar/index.html

Do you have idea how to result in:

_site/blog/foo/index.html 
_site/blog/last-year/index.html
_site/blog/new-year/index.html
_site/blog/bar/index.html

note that page.basename and page.slug also change to:

foo
last-year
new-year
bar/index

and page.data.date property become date object from filename replacement.

hariadi commented 10 years ago

Maybe add option filedate like this (filedate name look weird):

if(options.filedate === true) {
  page.basename = page.slug = page.basename.replace(/^(\d+)-(\d+)-(\d+)-?/, function (a, y, m, d) {
    page.data.date = (page.data.date) ? page.data.date : new Date([y,m,d].join('-'));
    return [].join('/');
  });
}

So we get new page.basename and page.slug property. Also page.data.date available for plugins/helpers.

doowb commented 10 years ago

@hariadi did you try adding your filedate thing as a custom pattern? Technically, the pattern is just a regex so you should be able to do that and you could pass in a function as the replacement...

options: {
  permalinks: {
    patterns: [
      {
        pattern: /^(\d+)-(\d+)-(\d+)-?/,
        replacement: function (a, y, m, d) {
          page.data.date = (page.data.date) ? page.data.date : new Date([y,m,d].join('-'));
          return [].join('/');
        }
      }
    ]
  }
}

After typing that out, I'm not sure how to get access to page.data.date inside the replacement function. We were talking about this type of thing today and how we can make this work in our strings library.

jonschlinkert commented 10 years ago

exactly what I was thinking @doowb

I'm not sure how to get access to page.data.date inside the replacement function.

I think if it's on the context, it should be usable this way. I'm pretty sure the tests show data from YFM being used with replacement patterns like this. @hariadi if that doesn't work I'd consider it a bug.

hariadi commented 10 years ago

Thanks @doowb, @jonschlinkert! Tried that but doesn't work:

patterns: [
  {
    pattern: /^(\d+)-(\d+)-(\d+)-?/,
    replacement: function (a, y, m, d) {
      return [].join('/');
    }
  }
]

still resulting:

Running "assemble:blog" (assemble) task
Assembling _site/blog/2013-10-11-foo.html OK
Assembling _site/blog/2013-12-31-last-year.html OK
Assembling _site/blog/2014-01-01-new-year.html OK
Assembling _site/blog/2014-02-12-bar.html OK
>> 4 pages assembled.

Done, without errors.

Using code above I'm able to modify page.basename, page.slug and page.data.date to make use of preset for example :

permalinks: {
  //structure: ':category',
  preset: 'pretty',
  filedate: true
}
jonschlinkert commented 10 years ago

@doowb for some reason this doesn't return the context in replacement patterns. The other day I tried it and this returned the actual regex replacement patterns and the page/yfm context. but for some reason it's not working in my current setup. permalinks are working, this is the only thing that isn't. I haven't looked at Strings yet

doowb commented 10 years ago

this is returning the context used in Strings and for permalinks part of that context is from the page/yfm context. Other than that, the context is technically the regex patterns due to how everything is passed to frep. I'm not sure how to extract the regex into actual keys.

This might have to be changed up to work differently for permalinks (maybe remove the this from strings and just bind it in permalinks)

jonschlinkert commented 10 years ago

I have confirmed that this already works. You need to use this.src, since the context is available to the patterns, not just the src.

Here is an example, given you have a filename like 2014-03-27-test-blah-something.md, you can create a function like this:

var toPost = function(str) {
  var path = require('path');
  var name = path.basename(str, path.extname(str));
  var re = /(\d{4})-(\d{2})-(\d{2})-(.+)/;
  return name.replace(re, '$1/$2/$3/$4');
};

Then use it in the replacement patterns:

options: {
  permalinks: {
    structure: ':post/index.html',
    patterns: [
      {
        pattern: ':post',
        replacement: function() {
          return toPost(this.src);
        }
      }
    ]
  }
}

Resulting in: 2014/03/27/test-blah-something/index.html

I'm updating the docs for this. Cosing since I think it's resolved, but reopen if necessary.

jonschlinkert commented 10 years ago

actually, just remembered that there are other things in this pr we can use! @hariadi would you want to do a new pr with the fixtures etc, using the example I gave?