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

Multiple copies of moment function #2615

Closed
bkputnam opened this issue Sep 16, 2015 · 4 comments
Closed

Multiple copies of moment function #2615

bkputnam opened this issue Sep 16, 2015 · 4 comments

Comments

@bkputnam
Copy link

Is there a way to create multiple, independently-configured copies of the moment() function?

What I would like to do is enforce strict-mode parsing across my entire codebase (disable the fallback to the native Date function). The method I would like to use to do this is covered here - override createFromInputFallback to always return an invalid Date. The only snag in my situation is that I'm developing a widget library that depends on moment and I can't modify the global moment object that my users depend on. If I could configure my own copy of the moment function separately from the global one it would solve that problem neatly.

I can theoretically update all of my moment(string) calls to be moment(string, format, true) and that will give the strict-parsing behavior I would like. The catch is that we would then have to implement a human rule across our team that says "always remember to pass format and true to moment()" but human rules are easy to forget. If it's possible to enforce this behavior in code that seems like a cleaner solution to me.

@mattjohnsonpint
Copy link
Contributor

Why do you need to change moment in order to enforce this? Just write a function in your code.

function createMoment(s, f) {
    return moment(s, f, true);
}

@bkputnam
Copy link
Author

The sticking point with that one is the format parameter f. I'm working on an old codebase that relies on the flexibility of a single-parameter moment(something) call. Many of our functions look something like this:

/**
* Sets the timeframe
* 
* @param {object} start Native JS Date object, Moment.JS date object, or ISO 8601 string to set as new start date
* @param {object} end Native JS Date object, Moment.JS date object, or ISO 8601 string to set as new end date
*/
var setTimeframe = function( start, end ) {
    start = moment(start);
    end = moment(end);
    /* do some stuff */
};

These functions are then called from all corners of the codebase and they rely on moment to normalize their inputs whether they're passed Dates, Strings, or other moment objects. Refactoring this to use a fixed format would require a rewrite of a regrettable amount of code. Often, even when the input is a String the format is not explicitly known except that it's supposed to be some form of ISO 8601 (and when it isn't weird things happen).

It would be great to have something like the moment(String, true) signature proposed in #2469 where you keep all of the standard ISO parsing methods and if they fail you simply return Invalid Date instead of delegating to the Date function. To the best of my Googling ability this has not been implemented, though.

Since I first posted this I've managed to come up with a wrapper along the same lines as the one you suggested that acts more like moment(String, true). This is the gist of it:

function momentStrict() {
    var prevFallback = moment.createFromInputFallback;
    moment.createFromInputFallback = function (config) {
        config._d = new Date(NaN);
    };
    var result = moment.apply(null, arguments);
    moment.createFromInputFallback = prevFallback;
    return result;
}

// Usage: API is the same as the moment() function. These all work like usual:
momentStrict(“1970-01-01);
momentStrict(new Date());
momentStrict(“01/01/1970, “DD/MM/YYYY”, true);
// … etc.

// This is the main difference:
momentStrict(“01/01/1970).isValid(); // will always be false
moment(“01/01/1970).isValid(); // will usually be true, browser-dependent

The wrapper itself feels a little hacky though (modifying global state but not really) - if there is a better way to go about this I would love to improve my code.

Thanks for you time, I appreciate the response.

@ichernev
Copy link
Contributor

@bkputnam I think you didn't get @mj1856 suggestion. He just said to not use moment directly, but instead your own function that does all the crazy stuff you want. Just do a search-and-replace on all your code base for the word moment and replace it with myCrazyMoment, then implement myCrazyMoment to handle all your weird cases and stuff.

You can also bundle moment directly in your library and modify it, but that would mean bigger size of your library. In any case if a plugin is changing the default settings (like falling back to Date) this can have very subtle to find issues in the client's app code, if they happen to be using moment.

So what you suggest is something like

var myMoment = moment.createConstructor({fancy: [options, here]});
myMoment(str); // in rest of code

But that is the same as:

var myMoment = function () {
  // do some crazy stuff, really up to you
  return fancyMomentObjectCreatedInAWeirdWay;
}
myMoment(str);  // in rest of code

@bkputnam
Copy link
Author

Thanks @ichernev, I think we all wound up saying the same thing in the end: @mj1856's createMoment(), your myMoment() and my momentStrict() are all variations on the same theme. At any rate I now have a function like you suggest that does what I need. Thanks again for the responses and the great library.

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

No branches or pull requests

3 participants