javascript-time-ago
Advanced tools
+12
| import javascript_time_ago from './source/time ago' | ||
| // Add all locale data to `javascript-time-ago`. | ||
| // This module will be ignored when bundling | ||
| // for the browser with Browserify/Webpack. | ||
| global.javascript_time_ago = javascript_time_ago | ||
| require('./locales') | ||
| delete global.javascript_time_ago | ||
| // export { default, from_CLDR } from './source/time ago' | ||
| export default javascript_time_ago | ||
| export { a_day, days_in_a_month, days_in_a_year, gradation } from './source/classify elapsed' |
+20
| 'use strict' | ||
| var javascript_time_ago = require('./build/time ago')['default'] | ||
| // Add all locale data to `javascript-time-ago`. | ||
| // This module will be ignored when bundling | ||
| // for the browser with Browserify/Webpack. | ||
| global.javascript_time_ago = javascript_time_ago | ||
| require('./locales') | ||
| delete global.javascript_time_ago | ||
| exports = module.exports = javascript_time_ago | ||
| exports['default'] = exports | ||
| var classify_elapsed = require('./build/classify elapsed') | ||
| exports.a_day = classify_elapsed.a_day | ||
| exports.days_in_a_month = classify_elapsed.days_in_a_month | ||
| exports.days_in_a_year = classify_elapsed.days_in_a_year | ||
| exports.gradation = classify_elapsed.gradation |
| var fs = require('fs') | ||
| fs.readdirSync('./locales').forEach(function(file) | ||
| { | ||
| var locale = file.replace(/\.js$/, '') | ||
| javascript_time_ago.locale(locale, require('./locales/' + locale)) | ||
| }) |
+7
-3
| { | ||
| "name": "javascript-time-ago", | ||
| "version": "0.2.3", | ||
| "version": "0.2.4", | ||
| "description": "International highly customizable relative time formatting", | ||
| "main": "build/index.js", | ||
| "jsnext:main": "source/index.js", | ||
| "main": "index.umd.js", | ||
| "jsnext:main": "index.es6.js", | ||
| "browser": { | ||
| "./locales": false, | ||
| "./locales.js": false | ||
| }, | ||
| "peerDependencies": { | ||
@@ -8,0 +12,0 @@ "intl-messageformat": "^1.3.0" |
+9
-9
@@ -76,9 +76,9 @@ # javascript-time-ago | ||
| time_ago_english.format(new Date(Date.now() + 60 * 1000)) | ||
| time_ago_english.format(new Date(Date.now() - 60 * 1000)) | ||
| // "a minute ago" | ||
| time_ago_english.format(new Date(Date.now() + 2 * 60 * 60 * 1000)) | ||
| time_ago_english.format(new Date(Date.now() - 2 * 60 * 60 * 1000)) | ||
| // "2 hours ago" | ||
| time_ago_english.format(new Date(Date.now() + 24 * 60 * 60 * 1000)) | ||
| time_ago_english.format(new Date(Date.now() - 24 * 60 * 60 * 1000)) | ||
| // "yesterday" | ||
@@ -91,9 +91,9 @@ | ||
| time_ago_russian.format(new Date(Date.now() + 60 * 1000))) | ||
| time_ago_russian.format(new Date(Date.now() - 60 * 1000))) | ||
| // "минуту назад" | ||
| time_ago_russian.format(new Date(Date.now() + 2 * 60 * 60 * 1000))) | ||
| time_ago_russian.format(new Date(Date.now() - 2 * 60 * 60 * 1000))) | ||
| // "2 часа назад" | ||
| time_ago_russian.format(new Date(Date.now() + 24 * 60 * 60 * 1000)) | ||
| time_ago_russian.format(new Date(Date.now() - 24 * 60 * 60 * 1000)) | ||
| // "вчера" | ||
@@ -125,6 +125,6 @@ ``` | ||
| time_ago.format(new Date(Date.now() + 60 * 1000), twitter) | ||
| time_ago.format(new Date(Date.now() - 60 * 1000), twitter) | ||
| // "1m" | ||
| time_ago.format(new Date(Date.now() + 2 * 60 * 60 * 1000), twitter) | ||
| time_ago.format(new Date(Date.now() - 2 * 60 * 60 * 1000), twitter) | ||
| // "2h" | ||
@@ -264,3 +264,3 @@ ``` | ||
| const time_ago = new javascript_time_ago('ru') | ||
| time_ago.format(new Date(Date.now() + 60 * 1000)) | ||
| time_ago.format(new Date(Date.now() - 60 * 1000)) | ||
| // "1 минуту назад" | ||
@@ -267,0 +267,0 @@ ``` |
-35
| { | ||
| "presets": | ||
| [ | ||
| "react", | ||
| "es2015", | ||
| "stage-0" | ||
| ], | ||
| "plugins": | ||
| [ | ||
| "transform-runtime", | ||
| "add-module-exports", | ||
| "transform-react-display-name" | ||
| ], | ||
| "env": | ||
| { | ||
| "development": | ||
| { | ||
| "plugins": [] | ||
| }, | ||
| "react-intl-extract-default-messages": | ||
| { | ||
| "plugins": | ||
| [ | ||
| ["react-intl", | ||
| { | ||
| "messagesDir": "./build/messages/", | ||
| "enforceDescriptions": true | ||
| }] | ||
| ] | ||
| } | ||
| } | ||
| } |
| # Auto detect text files and perform LF normalization | ||
| * text=auto | ||
| # Custom for Visual Studio | ||
| *.cs diff=csharp | ||
| # Standard to msysgit | ||
| *.doc diff=astextplain | ||
| *.DOC diff=astextplain | ||
| *.docx diff=astextplain | ||
| *.DOCX diff=astextplain | ||
| *.dot diff=astextplain | ||
| *.DOT diff=astextplain | ||
| *.pdf diff=astextplain | ||
| *.PDF diff=astextplain | ||
| *.rtf diff=astextplain | ||
| *.RTF diff=astextplain |
| 'use strict'; | ||
| Object.defineProperty(exports, "__esModule", { | ||
| value: true | ||
| }); | ||
| var _timeAgo = require('./time ago'); | ||
| Object.defineProperty(exports, 'default', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _interopRequireDefault(_timeAgo).default; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'from_CLDR', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _timeAgo.from_CLDR; | ||
| } | ||
| }); | ||
| var _classifyElapsed = require('./classify elapsed'); | ||
| Object.defineProperty(exports, 'classify_elapsed', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _interopRequireDefault(_classifyElapsed).default; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'a_day', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _classifyElapsed.a_day; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'days_in_a_month', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _classifyElapsed.days_in_a_month; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'days_in_a_year', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _classifyElapsed.days_in_a_year; | ||
| } | ||
| }); | ||
| Object.defineProperty(exports, 'gradation', { | ||
| enumerable: true, | ||
| get: function get() { | ||
| return _classifyElapsed.gradation; | ||
| } | ||
| }); | ||
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"sources":["../source/index.js"],"names":[],"mappings":";;;;;;;;;;;4CAES;;;;;;oBAAS;;;;;;;;;oDACT;;;;;;4BAA6B;;;;;;4BAAO;;;;;;4BAAiB;;;;;;4BAAgB","file":"index.js","sourcesContent":["// just an npm package helper\n\nexport { default, from_CLDR, } from './time ago'\nexport { default as classify_elapsed, a_day, days_in_a_month, days_in_a_year, gradation } from './classify elapsed'"]} |
Sorry, the diff of this file is not supported yet
| // https://www.quora.com/What-is-the-average-number-of-days-in-a-month | ||
| export const days_in_a_month = 30.44 | ||
| // "400 years have 146097 days (taking into account leap year rules)" | ||
| export const days_in_a_year = 146097 / 400 | ||
| export const a_day = 24 * 60 * 60 // in seconds | ||
| export const gradation = | ||
| { | ||
| // just now | ||
| // 1 second ago | ||
| // … | ||
| // 59 seconds ago | ||
| // 1 minute ago | ||
| // … | ||
| // 59 minutes ago | ||
| // 1 hour ago | ||
| // … | ||
| // 24 hours ago | ||
| // 1 day ago | ||
| // … | ||
| // 7 days ago | ||
| // 1 week ago | ||
| // … | ||
| // 3 weeks ago | ||
| // 1 month ago | ||
| // … | ||
| // 11 months ago | ||
| // 1 year ago | ||
| // … | ||
| canonical: () => | ||
| { | ||
| const result = | ||
| [ | ||
| { | ||
| unit: 'just-now', | ||
| factor: 1 | ||
| }, | ||
| { | ||
| unit: 'second', | ||
| factor: 1, | ||
| threshold: 0.5 | ||
| }, | ||
| { | ||
| unit: 'minute', | ||
| factor: 60, | ||
| threshold: 59.5 | ||
| }, | ||
| { | ||
| unit: 'hour', | ||
| factor: 60 * 60, | ||
| threshold: 59.5 * 60 | ||
| }, | ||
| { | ||
| unit: 'day', | ||
| factor: a_day, | ||
| threshold: 23.5 * 60 * 60 | ||
| }, | ||
| { | ||
| unit: 'week', | ||
| factor: 7 * a_day, | ||
| threshold: 6.5 * a_day | ||
| }, | ||
| { | ||
| unit: 'month', | ||
| factor: days_in_a_month * a_day, | ||
| threshold: 3.5 * 7 * a_day * a_day | ||
| }, | ||
| { | ||
| unit: 'year', | ||
| factor: days_in_a_year * a_day, | ||
| threshold: 11.5 * days_in_a_month * a_day | ||
| } | ||
| ] | ||
| return result | ||
| }, | ||
| // just now | ||
| // 5 minutes ago | ||
| // 10 minutes ago | ||
| // 15 minutes ago | ||
| // 20 minutes ago | ||
| // half an hour ago | ||
| // an hour ago | ||
| // 2 hours ago | ||
| // … | ||
| // 20 hours ago | ||
| // yesterday | ||
| // 2 days ago | ||
| // 5 days ago | ||
| // a week ago | ||
| // 2 weeks ago | ||
| // 3 weeks ago | ||
| // a month ago | ||
| // 2 months ago | ||
| // 4 months ago | ||
| // half a year ago | ||
| // a year ago | ||
| // 2 years ago | ||
| // … | ||
| convenient: () => | ||
| { | ||
| const result = | ||
| [ | ||
| { | ||
| unit: 'just-now', | ||
| factor: 1 | ||
| }, | ||
| { | ||
| unit: 'second', | ||
| factor: 1, | ||
| threshold: 1 | ||
| }, | ||
| { | ||
| unit: 'minute', | ||
| factor: 60, | ||
| threshold: 45, | ||
| granularity: 5 | ||
| }, | ||
| { | ||
| unit: 'half-hour', | ||
| factor: 30 * 60, | ||
| threshold: 22.5 * 60 | ||
| }, | ||
| { | ||
| unit: 'hour', | ||
| factor: 60 * 60, | ||
| threshold: 42.5 * 60, | ||
| threshold_for_minute: 52.5 * 60 | ||
| }, | ||
| { | ||
| unit: 'day', | ||
| factor: a_day, | ||
| threshold: (20.5 / 24) * a_day | ||
| }, | ||
| { | ||
| unit: 'week', | ||
| factor: 7 * a_day, | ||
| threshold: 5.5 * a_day | ||
| }, | ||
| { | ||
| unit: 'month', | ||
| factor: days_in_a_month * a_day, | ||
| threshold: 3.5 * 7 * a_day | ||
| }, | ||
| { | ||
| unit: 'half-year', | ||
| factor: 0.5 * days_in_a_year * a_day, | ||
| threshold: 4.5 * days_in_a_month * a_day | ||
| }, | ||
| { | ||
| unit: 'year', | ||
| factor: days_in_a_year * a_day, | ||
| threshold: 9 * days_in_a_month * a_day, | ||
| threshold_for_month: 10.5 * days_in_a_month * a_day | ||
| } | ||
| ] | ||
| return result | ||
| } | ||
| } | ||
| // Chooses the appropriate time measurement unit | ||
| // and also returns the corresponding rounded time amount. | ||
| // | ||
| // Rounds the `elapsed` time interval | ||
| // to the most appropriate time measurement unit. | ||
| // | ||
| // Parameters: | ||
| // | ||
| // elapsed - time interval (in seconds) | ||
| // | ||
| // units - a list of allowed time units | ||
| // (e.g. ['second', 'minute', 'hour', …]) | ||
| // | ||
| // gradation - (optional) time scale gradation steps. | ||
| // (e.g. | ||
| // [ | ||
| // { unit: 'second', factor: 1 }, | ||
| // { unit: 'minute', factor: 60, threshold: 60 }, | ||
| // … | ||
| // ]) | ||
| // | ||
| // Returns an object of `unit` and `amount` | ||
| // (e.g. { unit: 'day', amount: 3 }) | ||
| // | ||
| export default function classify_elapsed(elapsed, units, gradation_steps) | ||
| { | ||
| // Time interval measurement unit rounding gradation | ||
| gradation_steps = gradation_steps || gradation.convenient() | ||
| // Leave only supported gradation steps | ||
| gradation_steps = gradation_steps.filter(step => units.indexOf(step.unit) >= 0) | ||
| // Find the most appropriate time scale gradation step | ||
| let i = 0 | ||
| while (i < gradation_steps.length) | ||
| { | ||
| // Current step of time scale | ||
| const step = gradation_steps[i] | ||
| // The next step of time scale | ||
| const next_step = i + 1 < gradation_steps.length ? gradation_steps[i + 1] : undefined | ||
| // If it's not the last step of time scale, | ||
| // and the next step of time scale is reachable, | ||
| // then proceed with that next step of time scale. | ||
| if (next_step) | ||
| { | ||
| // Allows threshold customization | ||
| // based on which time interval measurement units | ||
| // are available at the moment. | ||
| const specific_threshold = next_step[`threshold_for_${step.unit}`] | ||
| const next_step_threshold = specific_threshold || next_step.threshold | ||
| if (elapsed >= next_step_threshold) | ||
| { | ||
| i++ | ||
| continue | ||
| } | ||
| } | ||
| // Either it's the last step of time scale, | ||
| // or the next step of time scale is unreachable, | ||
| // so stick with the current step of time scale. | ||
| const exact_amount = elapsed / step.factor | ||
| let amount = Math.round(exact_amount) | ||
| // Amount shouldn't be zero, | ||
| // so set it to 1 at least. | ||
| if (amount === 0) | ||
| { | ||
| amount = elapsed >= 0 ? 1 : -1 | ||
| } | ||
| // Apply granularity to the time amount | ||
| // (and fallback to the previous step | ||
| // if the first level of granularity | ||
| // isn't met by this amount) | ||
| if (step.granularity) | ||
| { | ||
| // Recalculate time amount based on the granularity | ||
| const remainder = exact_amount % step.granularity | ||
| amount = exact_amount - remainder | ||
| amount += Math.round(remainder / step.granularity) * step.granularity | ||
| // If the granularity for this step of time scale | ||
| // is too high, then fallback | ||
| // to the previous step of time scale. | ||
| // (if there is the previous step of time scale) | ||
| if (amount === 0) | ||
| { | ||
| const previous_step = gradation_steps[i - 1] | ||
| if (previous_step) | ||
| { | ||
| const previous_step_result = | ||
| { | ||
| unit : previous_step.unit, | ||
| amount : Math.round(elapsed / previous_step.factor) | ||
| } | ||
| return previous_step_result | ||
| } | ||
| } | ||
| } | ||
| // Result | ||
| return { unit: step.unit, amount } | ||
| } | ||
| throw new Error(`Not a single time unit of "${units.join(', ')}" was specified ` | ||
| + `in the gradation \n ${JSON.stringify({ gradation: gradation_steps }, null, 3)}`) | ||
| } |
| // just an npm package helper | ||
| export { default, from_CLDR, } from './time ago' | ||
| export { default as classify_elapsed, a_day, days_in_a_month, days_in_a_year, gradation } from './classify elapsed' |
-117
| import { resolve_locale } from './time ago' | ||
| import { gradation, a_day } from './classify elapsed' | ||
| const twitter_formatters = {} | ||
| export default function(locales) | ||
| { | ||
| const styles = | ||
| { | ||
| // Twitter style relative time. | ||
| // Seconds, minutes and hours are shown relatively, | ||
| // and other intervals can be shown using full date format. | ||
| twitter() | ||
| { | ||
| const locale = resolve_locale(locales) | ||
| if (!twitter_formatters[locale]) | ||
| { | ||
| twitter_formatters[locale] = | ||
| { | ||
| // "Apr 11" (MMMd) | ||
| same_year : new Intl.DateTimeFormat(locale, { month: 'short', day: 'numeric' }), | ||
| // "Apr 11, 2017" (yMMMd) | ||
| another_year : new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'short', day: 'numeric' }) | ||
| } | ||
| } | ||
| const twitter_same_year_date_formatter = twitter_formatters[locale].same_year | ||
| const twitter_another_year_date_formatter = twitter_formatters[locale].another_year | ||
| const twitter_gradation = gradation.canonical() | ||
| for (let step of twitter_gradation) | ||
| { | ||
| if (step.unit === 'minute') | ||
| { | ||
| step.threshold = 45 | ||
| break | ||
| } | ||
| } | ||
| const options = | ||
| { | ||
| // Twitter style relative time. | ||
| // Seconds, minutes and hours are shown relatively, | ||
| // and other intervals can be shown using full date format. | ||
| override({ elapsed, time, date, now }) | ||
| { | ||
| // If less than 24 hours elapsed, | ||
| // then format it relatively. | ||
| if (Math.abs(elapsed) < a_day - 30 * 60) | ||
| { | ||
| return | ||
| } | ||
| // If `date` and `now` happened the same year, | ||
| // then show month and day | ||
| if (new Date(now).getFullYear() === date.getFullYear()) | ||
| { | ||
| return twitter_same_year_date_formatter.format(date, 'MMMd') | ||
| } | ||
| // If `date` and `now` happened in defferent years, | ||
| // then show full date | ||
| return twitter_another_year_date_formatter.format(date, 'yMMMd') | ||
| }, | ||
| units: ['just-now', 'minute', 'hour'], | ||
| gradation: twitter_gradation, | ||
| flavour: 'tiny' | ||
| } | ||
| return options | ||
| }, | ||
| // I prefer this one. | ||
| // | ||
| // just now | ||
| // 5 minutes | ||
| // 10 minutes | ||
| // 15 minutes | ||
| // 20 minutes | ||
| // half an hour | ||
| // an hour | ||
| // 2 hours | ||
| // … | ||
| // 20 hours | ||
| // yesterday | ||
| // 2 days | ||
| // a week | ||
| // 2 weeks | ||
| // 3 weeks | ||
| // a month | ||
| // 2 months | ||
| // 3 months | ||
| // 4 months | ||
| // half a year | ||
| // a year | ||
| // 2 years | ||
| // | ||
| fuzzy() | ||
| { | ||
| const options = | ||
| { | ||
| gradation: gradation.convenient(), | ||
| flavour: 'long_concise', | ||
| units: ['just-now', 'minute', 'half-hour', 'hour', 'day', 'week', 'month', 'half-year', 'year'] | ||
| } | ||
| return options | ||
| } | ||
| } | ||
| return styles | ||
| } |
| // a part of this code is adopted from | ||
| // https://github.com/yahoo/intl-relativeformat/ | ||
| import IntlMessageFormat from 'intl-messageformat' | ||
| import classify_elapsed from './classify elapsed' | ||
| import style from './style' | ||
| export default class React_time_ago | ||
| { | ||
| // Fallback locale | ||
| // (when not a single supplied preferred locale is available) | ||
| static default_locale = 'en' | ||
| // For all configured locales | ||
| // their relative time formatter messages will be stored here | ||
| static locale_data = {} | ||
| // Relative time interval message formatters cache | ||
| formatters = {} | ||
| constructor(locales, options) | ||
| { | ||
| // Make a copy of `locales` if it's an array, so that it doesn't change | ||
| // since it's used lazily. | ||
| if (Array.isArray(locales)) | ||
| { | ||
| locales = locales.concat() | ||
| } | ||
| // Choose the most appropriate locale | ||
| this.locale = resolve_locale(locales) | ||
| // Is passed later on to `IntlMessageFormat` | ||
| this.locales = locales | ||
| // Presets | ||
| this.style = style(locales) | ||
| } | ||
| // Formats the relative date. | ||
| // | ||
| // Returns: a string | ||
| // | ||
| // Parameters: | ||
| // | ||
| // options - (optional) | ||
| // | ||
| // units - a list of allowed time units | ||
| // (e.g. ['second', 'minute', 'hour', …]) | ||
| // | ||
| // gradation - time scale gradation steps. | ||
| // (e.g. | ||
| // [ | ||
| // { unit: 'second', factor: 1 }, | ||
| // { unit: 'minute', factor: 60, threshold: 60 }, | ||
| // … | ||
| // ]) | ||
| // | ||
| // override - function ({ elapsed, time, date, now }) | ||
| // | ||
| // If the `override` function returns a value, | ||
| // then the `.format()` call will return that value. | ||
| // Otherwise it has no effect. | ||
| // | ||
| format(input, options = {}) | ||
| { | ||
| // Get locale messages for this formatting flavour | ||
| const { flavour, locale_data } = this.locale_data(options.flavour) | ||
| let date | ||
| let time | ||
| if (typeof input === 'number') | ||
| { | ||
| time = input | ||
| date = new Date(input) | ||
| } | ||
| else if (input.constructor === Date) | ||
| { | ||
| date = input | ||
| time = input.getTime() | ||
| } | ||
| else | ||
| { | ||
| throw new Error(`Unsupported fuzzy time input: ${typeof input}, ${input}`) | ||
| } | ||
| // can pass a custom `now` for testing purpose | ||
| const now = options.now || Date.now() | ||
| // how much time elapsed (in seconds) | ||
| const elapsed = (now - time) / 1000 // in seconds | ||
| // Allows output customization. | ||
| // For example, seconds, minutes and hours can be shown relatively, | ||
| // and other intervals can be shown using full date format. | ||
| // (see Twitter style) | ||
| if (options.override) | ||
| { | ||
| const override = options.override({ elapsed, time, date, now }) | ||
| if (override !== undefined) | ||
| { | ||
| return override | ||
| } | ||
| } | ||
| // Available time interval measurement units | ||
| let units = Object.keys(locale_data) | ||
| if (options.units) | ||
| { | ||
| // Find available time interval measurement units | ||
| units = options.units.filter(unit => units.indexOf(unit) >= 0) | ||
| } | ||
| // Choose the appropriate time measurement unit | ||
| // and get the corresponding rounded time amount | ||
| const { unit, amount } = classify_elapsed(Math.abs(elapsed), units, options.gradation) | ||
| // If no time unit is suitable, just output empty string | ||
| if (!unit) | ||
| { | ||
| return '' | ||
| } | ||
| // format the message for the chosen time measurement unit | ||
| // (second, minute, hour, day, etc) | ||
| const formatters = this.get_formatters(unit, flavour) | ||
| // default formatter: "X units" | ||
| let formatter = formatters.default | ||
| // in case of "0 units" | ||
| if (amount === 0 && formatters.current) | ||
| { | ||
| formatter = formatters.current | ||
| } | ||
| // in case of "previous unit" or "next unit" | ||
| if ((amount === -1 || amount === 1) && formatters.previous_next) | ||
| { | ||
| formatter = formatters.previous_next | ||
| } | ||
| // return formatted time amount | ||
| return formatter.format | ||
| ({ | ||
| '0' : amount, | ||
| when : elapsed >= 0 ? 'past' : 'future' | ||
| }) | ||
| } | ||
| // Gets locale messages for this formatting flavour | ||
| locale_data(flavour) | ||
| { | ||
| // Get relative time formatter messages for this locale | ||
| const locale_data = React_time_ago.locale_data[this.locale] | ||
| // Fallback to "default" flavour if the given flavour isn't available | ||
| if (!flavour || !locale_data[flavour]) | ||
| { | ||
| flavour = 'default' | ||
| } | ||
| return { flavour, locale_data: locale_data[flavour] } | ||
| } | ||
| // lazy creation of a formatter for a given time measurement unit | ||
| // (second, minute, hour, day, etc) | ||
| get_formatters(unit, flavour) | ||
| { | ||
| if (!this.formatters[flavour]) | ||
| { | ||
| this.formatters[flavour] = {} | ||
| } | ||
| const formatters = this.formatters[flavour] | ||
| // Create a new synthetic message based on the locale data from CLDR. | ||
| if (!formatters[unit]) | ||
| { | ||
| formatters[unit] = this.compile_formatters(unit, flavour) | ||
| } | ||
| return formatters[unit] | ||
| } | ||
| // compiles formatter for the specified time measurement unit | ||
| // (second, minute, hour, day, etc) | ||
| compile_formatters(unit, flavour) | ||
| { | ||
| // Locale specific time interval formatter messages | ||
| // for the given time interval measurement unit | ||
| const formatter_messages = React_time_ago.locale_data[this.locale][flavour][unit] | ||
| // Locale specific time interval formatter messages | ||
| // for the given time interval measurement unit | ||
| // for "past" and "future" | ||
| // | ||
| // (e.g. | ||
| // { | ||
| // "relativeTimePattern-count-one": "{0} second ago", | ||
| // "relativeTimePattern-count-other": "{0} seconds ago" | ||
| // }) | ||
| // | ||
| const past_formatter_messages = formatter_messages.past | ||
| const future_formatter_messages = formatter_messages.future | ||
| // `format.js` number formatter messages | ||
| // e.g. "one {# second ago} other {# seconds ago}" | ||
| let past_formatter = '' | ||
| let future_formatter = '' | ||
| // Compose "past" formatter specification | ||
| // (replacing CLDR number placeholder "{0}" | ||
| // with format.js number placeholder "#") | ||
| for (let key of Object.keys(past_formatter_messages)) | ||
| { | ||
| past_formatter += ` ${key} | ||
| {${past_formatter_messages[key].replace('{0}', '#')}}` | ||
| } | ||
| // Compose "future" formatter specification | ||
| // (replacing CLDR number placeholder "{0}" | ||
| // with format.js number placeholder "#") | ||
| for (let key of Object.keys(future_formatter_messages)) | ||
| { | ||
| // e.g. += " one {# sec. ago}" | ||
| future_formatter += ` ${key} | ||
| {${future_formatter_messages[key].replace('{0}', '#')}}` | ||
| } | ||
| // The ultimate time interval `format.js` specification | ||
| // ("0" will be replaced with the first argument | ||
| // when the message will be formatted) | ||
| const message = `{ when, select, past {{0, plural, ${past_formatter}}} | ||
| future {{0, plural, ${future_formatter}}} }` | ||
| // Create the synthetic IntlMessageFormat instance | ||
| // using the original locales specified by the user | ||
| const default_formatter = new IntlMessageFormat(message, this.locales) | ||
| const formatters = | ||
| { | ||
| default: default_formatter | ||
| } | ||
| // "0 units" formatter | ||
| if (formatter_messages.current) | ||
| { | ||
| formatters.current = | ||
| { | ||
| format: () => formatter_messages.current | ||
| } | ||
| } | ||
| // "previous unit" and "next unit" formatter | ||
| if (formatter_messages.previous && formatter_messages.next) | ||
| { | ||
| const previous_next_message = `{ when, select, past {${formatter_messages.previous}} | ||
| future {${formatter_messages.next}} }` | ||
| // Create the synthetic IntlMessageFormat instance | ||
| // using the original locales specified by the user | ||
| formatters.previous_next = new IntlMessageFormat(previous_next_message, this.locales) | ||
| } | ||
| return formatters | ||
| } | ||
| } | ||
| // Chooses the most appropriate locale | ||
| // based on the list of preferred locales supplied by the user | ||
| export function resolve_locale(locales) | ||
| { | ||
| // Suppose it's an array | ||
| if (typeof locales === 'string') | ||
| { | ||
| locales = [locales] | ||
| } | ||
| // Create a copy of the array so we can push on the default locale. | ||
| locales = (locales || []).concat(React_time_ago.default_locale) | ||
| // Using the set of locales + the default locale, we look for the first one | ||
| // which that has been registered. When data does not exist for a locale, we | ||
| // traverse its ancestors to find something that's been registered within | ||
| // its hierarchy of locales. Since we lack the proper `parentLocale` data | ||
| // here, we must take a naive approach to traversal. | ||
| for (let locale of locales) | ||
| { | ||
| const locale_parts = locale.toLowerCase().split('-') | ||
| while (locale_parts.length) | ||
| { | ||
| const locale_try = locale_parts.join('-') | ||
| if (React_time_ago.locale_data[locale_try]) | ||
| { | ||
| // Return the normalized locale string; | ||
| // e.g., we return "en-US", | ||
| // instead of "en-us". | ||
| return locale_try | ||
| } | ||
| locale_parts.pop() | ||
| } | ||
| } | ||
| throw new Error(`No locale data has been added for any of the locales: ${locales.join(', ')}`) | ||
| } | ||
| // Adds locale data | ||
| React_time_ago.locale = function(locale, locale_data) | ||
| { | ||
| const locale_data_map = {} | ||
| // Supports multiple locale variations | ||
| // (e.g. "default", "short", "normal", "long", etc) | ||
| if (!locale_data.default) | ||
| { | ||
| // Convert from CLDR format (if needed) | ||
| locale_data_map.default = from_CLDR(locale_data) | ||
| } | ||
| else | ||
| { | ||
| for (let key of Object.keys(locale_data)) | ||
| { | ||
| // Convert from CLDR format (if needed) | ||
| locale_data_map[key] = from_CLDR(locale_data[key]) | ||
| } | ||
| } | ||
| // Store locale specific messages in the static variable | ||
| React_time_ago.locale_data[locale.toLowerCase()] = locale_data_map | ||
| // (will be added manually by this library user) | ||
| // // Add locale data to IntlMessageFormat | ||
| // // (to be more specific: the `pluralRuleFunction`) | ||
| // require('intl-messageformat/locale-data/ru') | ||
| } | ||
| // Converts locale data from CLDR format (if needed) | ||
| export function from_CLDR(data) | ||
| { | ||
| const converted = {} | ||
| for (let key of Object.keys(data)) | ||
| { | ||
| const entry = data[key] | ||
| const converted_entry = {} | ||
| if (entry.previous) | ||
| { | ||
| converted_entry.previous = entry.previous | ||
| } | ||
| if (entry.current) | ||
| { | ||
| converted_entry.current = entry.current | ||
| } | ||
| if (entry.next) | ||
| { | ||
| converted_entry.next = entry.next | ||
| } | ||
| if (entry.past) | ||
| { | ||
| converted_entry.past = entry.past | ||
| } | ||
| if (entry.future) | ||
| { | ||
| converted_entry.future = entry.future | ||
| } | ||
| converted[key] = converted_entry | ||
| if (entry['relative-type--1']) | ||
| { | ||
| converted_entry.previous = entry['relative-type--1'] | ||
| } | ||
| if (entry['relative-type-0']) | ||
| { | ||
| converted_entry.current = entry['relative-type-0'] | ||
| } | ||
| if (entry['relative-type-1']) | ||
| { | ||
| converted_entry.next = entry['relative-type-1'] | ||
| } | ||
| if (entry['relativeTime-type-past']) | ||
| { | ||
| const past = entry['relativeTime-type-past'] | ||
| converted_entry.past = {} | ||
| for (let subkey of Object.keys(past)) | ||
| { | ||
| const prefix = 'relativeTimePattern-count-' | ||
| const converted_subkey = subkey.replace(prefix, '') | ||
| converted_entry.past[converted_subkey] = past[subkey] | ||
| } | ||
| } | ||
| if (entry['relativeTime-type-future']) | ||
| { | ||
| const future = entry['relativeTime-type-future'] | ||
| converted_entry.future = {} | ||
| for (let subkey of Object.keys(future)) | ||
| { | ||
| const prefix = 'relativeTimePattern-count-' | ||
| const converted_subkey = subkey.replace(prefix, '') | ||
| converted_entry.future[converted_subkey] = future[subkey] | ||
| } | ||
| } | ||
| } | ||
| return converted | ||
| } |
| export const long = { | ||
| "year": { | ||
| "displayName": "year", | ||
| "relative-type--1": "a year ago", | ||
| "relative-type-0": "this year", | ||
| "relative-type-1": "in a year", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} year", | ||
| "relativeTimePattern-count-other": "in {0} years" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} year ago", | ||
| "relativeTimePattern-count-other": "{0} years ago" | ||
| } | ||
| }, | ||
| "half-year": { | ||
| "displayName": "half a year", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-other": "in half a year" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-other": "half a year ago" | ||
| } | ||
| }, | ||
| "month": { | ||
| "displayName": "month", | ||
| "relative-type--1": "a month ago", | ||
| "relative-type-0": "this month", | ||
| "relative-type-1": "in a month", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} month", | ||
| "relativeTimePattern-count-other": "in {0} months" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} month ago", | ||
| "relativeTimePattern-count-other": "{0} months ago" | ||
| } | ||
| }, | ||
| "week": { | ||
| "displayName": "week", | ||
| "relative-type--1": "a week ago", | ||
| "relative-type-0": "this week", | ||
| "relative-type-1": "in a week", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} week", | ||
| "relativeTimePattern-count-other": "in {0} weeks" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} week ago", | ||
| "relativeTimePattern-count-other": "{0} weeks ago" | ||
| } | ||
| }, | ||
| "day": { | ||
| "displayName": "day", | ||
| "relative-type--1": "yesterday", | ||
| "relative-type-0": "today", | ||
| "relative-type-1": "tomorrow", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} day", | ||
| "relativeTimePattern-count-other": "in {0} days" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} day ago", | ||
| "relativeTimePattern-count-other": "{0} days ago" | ||
| } | ||
| }, | ||
| "hour": { | ||
| "displayName": "hour", | ||
| "relative-type--1": "an hour ago", | ||
| "relative-type-0": "this hour", | ||
| "relative-type-1": "in an hour", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} hour", | ||
| "relativeTimePattern-count-other": "in {0} hours" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} hour ago", | ||
| "relativeTimePattern-count-other": "{0} hours ago" | ||
| } | ||
| }, | ||
| "half-hour": { | ||
| "displayName": "half an hour", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-other": "in half an hour" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-other": "half an hour ago" | ||
| } | ||
| }, | ||
| "minute": { | ||
| "displayName": "minute", | ||
| "relative-type--1": "a minute ago", | ||
| "relative-type-0": "this minute", | ||
| "relative-type-1": "in a minute", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} minute", | ||
| "relativeTimePattern-count-other": "in {0} minutes" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} minute ago", | ||
| "relativeTimePattern-count-other": "{0} minutes ago" | ||
| } | ||
| }, | ||
| "second": { | ||
| "displayName": "second", | ||
| "relative-type-0": "now", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} second", | ||
| "relativeTimePattern-count-other": "in {0} seconds" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} second ago", | ||
| "relativeTimePattern-count-other": "{0} seconds ago" | ||
| } | ||
| }, | ||
| "just-now": { | ||
| "displayName": "just now", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-other": "in a moment" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-other": "just now" | ||
| } | ||
| } | ||
| } | ||
| export const short = { | ||
| "year": { | ||
| "displayName": "yr.", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} yr.", | ||
| "relativeTimePattern-count-other": "in {0} yr." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} yr. ago", | ||
| "relativeTimePattern-count-other": "{0} yr. ago" | ||
| } | ||
| }, | ||
| "month": { | ||
| "displayName": "mo.", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} mo.", | ||
| "relativeTimePattern-count-other": "in {0} mo." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} mo. ago", | ||
| "relativeTimePattern-count-other": "{0} mo. ago" | ||
| } | ||
| }, | ||
| "week": { | ||
| "displayName": "wk.", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} wk.", | ||
| "relativeTimePattern-count-other": "in {0} wk." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} wk. ago", | ||
| "relativeTimePattern-count-other": "{0} wk. ago" | ||
| } | ||
| }, | ||
| "day": { | ||
| "displayName": "day", | ||
| "relative-type--1": "yesterday", | ||
| "relative-type-0": "today", | ||
| "relative-type-1": "tomorrow", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} day", | ||
| "relativeTimePattern-count-other": "in {0} days" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} day ago", | ||
| "relativeTimePattern-count-other": "{0} days ago" | ||
| } | ||
| }, | ||
| "hour": { | ||
| "displayName": "hr.", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} hr.", | ||
| "relativeTimePattern-count-other": "in {0} hr." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} hr. ago", | ||
| "relativeTimePattern-count-other": "{0} hr. ago" | ||
| } | ||
| }, | ||
| "minute": { | ||
| "displayName": "min.", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} min.", | ||
| "relativeTimePattern-count-other": "in {0} min." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} min. ago", | ||
| "relativeTimePattern-count-other": "{0} min. ago" | ||
| } | ||
| }, | ||
| "second": { | ||
| "displayName": "sec.", | ||
| "relative-type-0": "now", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-one": "in {0} sec.", | ||
| "relativeTimePattern-count-other": "in {0} sec." | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-one": "{0} sec. ago", | ||
| "relativeTimePattern-count-other": "{0} sec. ago" | ||
| } | ||
| }, | ||
| "just-now": { | ||
| "displayName": "just now", | ||
| "relativeTime-type-future": { | ||
| "relativeTimePattern-count-other": "now" | ||
| }, | ||
| "relativeTime-type-past": { | ||
| "relativeTimePattern-count-other": "now" | ||
| } | ||
| } | ||
| } | ||
| export default long |
| import are_intl_locales_supported from 'intl-locales-supported' | ||
| if (global.Intl) | ||
| { | ||
| // Determine if the built-in `Intl` has the locale data we need | ||
| if (!are_intl_locales_supported(['en', 'ru'])) | ||
| { | ||
| // `Intl` exists, but it doesn't have the data we need, so load the | ||
| // polyfill and patch the constructors we need with the polyfill's | ||
| const Intl_polyfill = require('intl') | ||
| Intl.NumberFormat = Intl_polyfill.NumberFormat | ||
| Intl.DateTimeFormat = Intl_polyfill.DateTimeFormat | ||
| } | ||
| } | ||
| else | ||
| { | ||
| // No `Intl`, so use and load the polyfill | ||
| global.Intl = require('intl') | ||
| } | ||
| import chai from 'chai' | ||
| chai.should() | ||
| require('./time ago') |
-838
| // import chai from 'chai' | ||
| // chai.should() | ||
| // import javascript_time_ago from '../source/time ago' | ||
| import javascript_time_ago, { a_day, days_in_a_month, days_in_a_year, from_CLDR, gradation } from '../source' | ||
| // Load locale specific relative date/time messages | ||
| import { short as english_short_cldr, long as english_long_cldr } from './locales/en-cldr' | ||
| import english, { short as english_short, long as english_long, tiny as english_tiny } from '../locales/en' | ||
| import russian, { short as russian_short, long as russian_long, tiny as russian_tiny } from '../locales/ru' | ||
| // Load number pluralization functions for the locales. | ||
| // (the ones that decide if a number is gonna be | ||
| // "zero", "one", "two", "few", "many" or "other") | ||
| // http://cldr.unicode.org/index/cldr-spec/plural-rules | ||
| // https://github.com/eemeli/make-plural.js | ||
| // | ||
| global.IntlMessageFormat = require('intl-messageformat') | ||
| require('intl-messageformat/dist/locale-data/en') | ||
| require('intl-messageformat/dist/locale-data/ru') | ||
| delete global.IntlMessageFormat | ||
| describe(`time ago`, function() | ||
| { | ||
| beforeEach(function() | ||
| { | ||
| // Set locale specific relative date/time messages | ||
| javascript_time_ago.locale('en', english_long) | ||
| javascript_time_ago.locale('ru', russian_long) | ||
| }) | ||
| afterEach(function() | ||
| { | ||
| // | ||
| }) | ||
| it(`should convert from Unicode CLDR`, function() | ||
| { | ||
| from_CLDR(english_short_cldr).should.deep.equal(english_short) | ||
| from_CLDR(english_long_cldr).should.deep.equal(english_long) | ||
| }) | ||
| // it(`should omit just now`, function() | ||
| // { | ||
| // javascript_time_ago.locale('en', english_short) | ||
| // | ||
| // const time_ago = new javascript_time_ago('en') | ||
| // | ||
| // const custom_gradation = gradation.convenient() | ||
| // while (custom_gradation[0].unit !== 'minute') | ||
| // { | ||
| // custom_gradation.shift() | ||
| // } | ||
| // | ||
| // const now = Date.now() | ||
| // const elapsed = time => time_ago.format(now - time * 1000, { now, gradation: custom_gradation }) | ||
| // | ||
| // elapsed(0 ).should.equal('') | ||
| // elapsed(2.49 * 60).should.equal('') | ||
| // elapsed(2.51 * 60).should.equal('5 min. ago') | ||
| // }) | ||
| it(`should format Twitter style relative time (English)`, function() | ||
| { | ||
| javascript_time_ago.locale('en', english_tiny) | ||
| const time_ago = new javascript_time_ago('en') | ||
| const twitter_style = time_ago.style.twitter() | ||
| const now = new Date(2016, 3, 10, 22, 59).getTime() | ||
| const elapsed = time => time_ago.format(now - time * 1000, { now, ...twitter_style }) | ||
| elapsed(0).should.equal('') | ||
| elapsed(44.9).should.equal('') | ||
| elapsed(45.1).should.equal('1m') | ||
| elapsed(1.49 * 60).should.equal('1m') | ||
| elapsed(1.51 * 60).should.equal('2m') | ||
| elapsed(2.49 * 60).should.equal('2m') | ||
| elapsed(2.51 * 60).should.equal('3m') | ||
| // … | ||
| elapsed(59.49 * 60).should.equal('59m') | ||
| elapsed(59.51 * 60).should.equal('1h') | ||
| elapsed(1.49 * 60 * 60).should.equal('1h') | ||
| elapsed(1.51 * 60 * 60).should.equal('2h') | ||
| elapsed(2.49 * 60 * 60).should.equal('2h') | ||
| elapsed(2.51 * 60 * 60).should.equal('3h') | ||
| // … | ||
| elapsed(23.49 * 60 * 60).should.equal('23h') | ||
| elapsed(a_day + 62 * 60).should.equal('Apr 9') | ||
| // … | ||
| elapsed(days_in_a_year * a_day).should.equal('Apr 11, 2015') | ||
| }) | ||
| it(`should format Twitter style relative time (Russian)`, function() | ||
| { | ||
| javascript_time_ago.locale('ru', russian) | ||
| const time_ago = new javascript_time_ago(['ru']) | ||
| const twitter_style = time_ago.style.twitter() | ||
| const now = new Date(2016, 3, 10, 22, 59).getTime() | ||
| const elapsed = time => time_ago.format(now - time * 1000, { now, ...twitter_style }) | ||
| elapsed(0).should.equal('') | ||
| elapsed(44.9).should.equal('') | ||
| elapsed(45.1).should.equal('1м') | ||
| elapsed(1.49 * 60).should.equal('1м') | ||
| elapsed(1.51 * 60).should.equal('2м') | ||
| elapsed(2.49 * 60).should.equal('2м') | ||
| elapsed(2.51 * 60).should.equal('3м') | ||
| // … | ||
| elapsed(59.49 * 60).should.equal('59м') | ||
| elapsed(59.51 * 60).should.equal('1ч') | ||
| elapsed(1.49 * 60 * 60).should.equal('1ч') | ||
| elapsed(1.51 * 60 * 60).should.equal('2ч') | ||
| elapsed(2.49 * 60 * 60).should.equal('2ч') | ||
| elapsed(2.51 * 60 * 60).should.equal('3ч') | ||
| // … | ||
| elapsed(23.49 * 60 * 60).should.equal('23ч') | ||
| elapsed(a_day + 62 * 60).should.equal('9 апр.') | ||
| // … | ||
| elapsed(days_in_a_year * a_day).should.equal('11 апр. 2015 г.') | ||
| }) | ||
| it(`should format fuzzy style relative time (English)`, function() | ||
| { | ||
| javascript_time_ago.locale('en', english) | ||
| const time_ago = new javascript_time_ago('en-US') | ||
| convenient_gradation_test | ||
| ([ | ||
| 'just now', | ||
| '5 minutes', | ||
| '10 minutes', | ||
| '15 minutes', | ||
| '20 minutes', | ||
| 'half an hour', | ||
| 'half an hour', | ||
| 'half an hour', | ||
| 'half an hour', | ||
| 'an hour', | ||
| 'an hour', | ||
| 'an hour', | ||
| '2 hours', | ||
| '3 hours', | ||
| '4 hours', | ||
| '5 hours', | ||
| '6 hours', | ||
| '7 hours', | ||
| '8 hours', | ||
| '9 hours', | ||
| '10 hours', | ||
| '11 hours', | ||
| '12 hours', | ||
| '13 hours', | ||
| '14 hours', | ||
| '15 hours', | ||
| '16 hours', | ||
| '17 hours', | ||
| '18 hours', | ||
| '19 hours', | ||
| '20 hours', | ||
| 'yesterday', | ||
| '2 days', | ||
| '3 days', | ||
| '4 days', | ||
| '5 days', | ||
| 'a week', | ||
| '2 weeks', | ||
| '3 weeks', | ||
| 'a month', | ||
| '2 months', | ||
| '3 months', | ||
| '4 months', | ||
| 'half a year', | ||
| 'half a year', | ||
| 'half a year', | ||
| 'half a year', | ||
| 'half a year', | ||
| 'a year', | ||
| 'a year', | ||
| 'a year', | ||
| '2 years', | ||
| '3 years', | ||
| '100 years' | ||
| ], | ||
| time_ago, | ||
| time_ago.style.fuzzy()) | ||
| }) | ||
| it(`should format fuzzy style relative time (Russian)`, function() | ||
| { | ||
| javascript_time_ago.locale('ru', russian) | ||
| const time_ago = new javascript_time_ago('ru-RU') | ||
| convenient_gradation_test | ||
| ([ | ||
| 'только что', | ||
| '5 минут', | ||
| '10 минут', | ||
| '15 минут', | ||
| '20 минут', | ||
| 'полчаса', | ||
| 'полчаса', | ||
| 'полчаса', | ||
| 'полчаса', | ||
| 'час', | ||
| 'час', | ||
| 'час', | ||
| '2 часа', | ||
| '3 часа', | ||
| '4 часа', | ||
| '5 часов', | ||
| '6 часов', | ||
| '7 часов', | ||
| '8 часов', | ||
| '9 часов', | ||
| '10 часов', | ||
| '11 часов', | ||
| '12 часов', | ||
| '13 часов', | ||
| '14 часов', | ||
| '15 часов', | ||
| '16 часов', | ||
| '17 часов', | ||
| '18 часов', | ||
| '19 часов', | ||
| '20 часов', | ||
| 'вчера', | ||
| '2 дня', | ||
| '3 дня', | ||
| '4 дня', | ||
| '5 дней', | ||
| 'неделю', | ||
| '2 недели', | ||
| '3 недели', | ||
| 'месяц', | ||
| '2 месяца', | ||
| '3 месяца', | ||
| '4 месяца', | ||
| 'полгода', | ||
| 'полгода', | ||
| 'полгода', | ||
| 'полгода', | ||
| 'полгода', | ||
| 'год', | ||
| 'год', | ||
| 'год', | ||
| '2 года', | ||
| '3 года', | ||
| '100 лет' | ||
| ], | ||
| time_ago, | ||
| time_ago.style.fuzzy()) | ||
| }) | ||
| it(`should reduce locale to language code`, function() | ||
| { | ||
| javascript_time_ago.locale('ru', russian_tiny) | ||
| const time_ago = new javascript_time_ago(['ru-RU']) | ||
| const twitter_style = time_ago.style.twitter() | ||
| const now = Date.now() | ||
| const elapsed = time => time_ago.format(now - time * 1000, { now }) | ||
| elapsed(45.1).should.equal('45с') | ||
| elapsed(45.1 * 60).should.equal('45м') | ||
| }) | ||
| it(`should format time correctly for English language (short)`, function() | ||
| { | ||
| const units = ['just-now', 'minute', 'half-hour', 'hour', 'day', 'week', 'month', 'half-year', 'year'] | ||
| javascript_time_ago.locale('en', english_short) | ||
| convenient_gradation_test | ||
| ([ | ||
| 'now', | ||
| '5 min. ago', | ||
| '10 min. ago', | ||
| '15 min. ago', | ||
| '20 min. ago', | ||
| '25 min. ago', | ||
| '30 min. ago', | ||
| '35 min. ago', | ||
| '40 min. ago', | ||
| '45 min. ago', | ||
| '50 min. ago', | ||
| '1 hr. ago', | ||
| '2 hr. ago', | ||
| '3 hr. ago', | ||
| '4 hr. ago', | ||
| '5 hr. ago', | ||
| '6 hr. ago', | ||
| '7 hr. ago', | ||
| '8 hr. ago', | ||
| '9 hr. ago', | ||
| '10 hr. ago', | ||
| '11 hr. ago', | ||
| '12 hr. ago', | ||
| '13 hr. ago', | ||
| '14 hr. ago', | ||
| '15 hr. ago', | ||
| '16 hr. ago', | ||
| '17 hr. ago', | ||
| '18 hr. ago', | ||
| '19 hr. ago', | ||
| '20 hr. ago', | ||
| 'yesterday', | ||
| '2 days ago', | ||
| '3 days ago', | ||
| '4 days ago', | ||
| '5 days ago', | ||
| '1 wk. ago', | ||
| '2 wk. ago', | ||
| '3 wk. ago', | ||
| '1 mo. ago', | ||
| '2 mo. ago', | ||
| '3 mo. ago', | ||
| '4 mo. ago', | ||
| '5 mo. ago', | ||
| '6 mo. ago', | ||
| '7 mo. ago', | ||
| '8 mo. ago', | ||
| '9 mo. ago', | ||
| '9 mo. ago', | ||
| '10 mo. ago', | ||
| '1 yr. ago', | ||
| '2 yr. ago', | ||
| '3 yr. ago', | ||
| '100 yr. ago' | ||
| ], | ||
| new javascript_time_ago('en'), | ||
| { units }) | ||
| }) | ||
| it(`should format time correctly for English language (long)`, function() | ||
| { | ||
| const units = ['just-now', 'minute', 'half-hour', 'hour', 'day', 'week', 'month', 'half-year', 'year'] | ||
| javascript_time_ago.locale('en', english_long) | ||
| convenient_gradation_test | ||
| ([ | ||
| 'just now', | ||
| '5 minutes ago', | ||
| '10 minutes ago', | ||
| '15 minutes ago', | ||
| '20 minutes ago', | ||
| 'half an hour ago', | ||
| 'half an hour ago', | ||
| 'half an hour ago', | ||
| 'half an hour ago', | ||
| 'an hour ago', | ||
| 'an hour ago', | ||
| 'an hour ago', | ||
| '2 hours ago', | ||
| '3 hours ago', | ||
| '4 hours ago', | ||
| '5 hours ago', | ||
| '6 hours ago', | ||
| '7 hours ago', | ||
| '8 hours ago', | ||
| '9 hours ago', | ||
| '10 hours ago', | ||
| '11 hours ago', | ||
| '12 hours ago', | ||
| '13 hours ago', | ||
| '14 hours ago', | ||
| '15 hours ago', | ||
| '16 hours ago', | ||
| '17 hours ago', | ||
| '18 hours ago', | ||
| '19 hours ago', | ||
| '20 hours ago', | ||
| 'yesterday', | ||
| '2 days ago', | ||
| '3 days ago', | ||
| '4 days ago', | ||
| '5 days ago', | ||
| 'a week ago', | ||
| '2 weeks ago', | ||
| '3 weeks ago', | ||
| 'a month ago', | ||
| '2 months ago', | ||
| '3 months ago', | ||
| '4 months ago', | ||
| 'half a year ago', | ||
| 'half a year ago', | ||
| 'half a year ago', | ||
| 'half a year ago', | ||
| 'half a year ago', | ||
| 'a year ago', | ||
| 'a year ago', | ||
| 'a year ago', | ||
| '2 years ago', | ||
| '3 years ago', | ||
| '100 years ago' | ||
| ], | ||
| new javascript_time_ago('en'), | ||
| { units }) | ||
| }) | ||
| it(`should format time correctly for Russian language (short)`, function() | ||
| { | ||
| const units = ['just-now', 'minute', 'half-hour', 'hour', 'day', 'week', 'month', 'half-year', 'year'] | ||
| javascript_time_ago.locale('ru', russian_short) | ||
| convenient_gradation_test | ||
| ([ | ||
| 'только что', | ||
| '5 мин. назад', | ||
| '10 мин. назад', | ||
| '15 мин. назад', | ||
| '20 мин. назад', | ||
| '25 мин. назад', | ||
| '30 мин. назад', | ||
| '35 мин. назад', | ||
| '40 мин. назад', | ||
| '45 мин. назад', | ||
| '50 мин. назад', | ||
| '1 ч. назад', | ||
| '2 ч. назад', | ||
| '3 ч. назад', | ||
| '4 ч. назад', | ||
| '5 ч. назад', | ||
| '6 ч. назад', | ||
| '7 ч. назад', | ||
| '8 ч. назад', | ||
| '9 ч. назад', | ||
| '10 ч. назад', | ||
| '11 ч. назад', | ||
| '12 ч. назад', | ||
| '13 ч. назад', | ||
| '14 ч. назад', | ||
| '15 ч. назад', | ||
| '16 ч. назад', | ||
| '17 ч. назад', | ||
| '18 ч. назад', | ||
| '19 ч. назад', | ||
| '20 ч. назад', | ||
| 'вчера', | ||
| '2 д. назад', | ||
| '3 д. назад', | ||
| '4 д. назад', | ||
| '5 д. назад', | ||
| '1 нед. назад', | ||
| '2 нед. назад', | ||
| '3 нед. назад', | ||
| '1 мес. назад', | ||
| '2 мес. назад', | ||
| '3 мес. назад', | ||
| '4 мес. назад', | ||
| '5 мес. назад', | ||
| '6 мес. назад', | ||
| '7 мес. назад', | ||
| '8 мес. назад', | ||
| '9 мес. назад', | ||
| '9 мес. назад', | ||
| '10 мес. назад', | ||
| '1 г. назад', | ||
| '2 г. назад', | ||
| '3 г. назад', | ||
| '100 л. назад' | ||
| ], | ||
| new javascript_time_ago('ru'), | ||
| { units }) | ||
| }) | ||
| it(`should format time correctly for Russian language (long)`, function() | ||
| { | ||
| const units = ['just-now', 'minute', 'half-hour', 'hour', 'day', 'week', 'month', 'half-year', 'year'] | ||
| javascript_time_ago.locale('ru', russian_long) | ||
| convenient_gradation_test | ||
| ([ | ||
| 'только что', | ||
| '5 минут назад', | ||
| '10 минут назад', | ||
| '15 минут назад', | ||
| '20 минут назад', | ||
| 'полчаса назад', | ||
| 'полчаса назад', | ||
| 'полчаса назад', | ||
| 'полчаса назад', | ||
| 'час назад', | ||
| 'час назад', | ||
| 'час назад', | ||
| '2 часа назад', | ||
| '3 часа назад', | ||
| '4 часа назад', | ||
| '5 часов назад', | ||
| '6 часов назад', | ||
| '7 часов назад', | ||
| '8 часов назад', | ||
| '9 часов назад', | ||
| '10 часов назад', | ||
| '11 часов назад', | ||
| '12 часов назад', | ||
| '13 часов назад', | ||
| '14 часов назад', | ||
| '15 часов назад', | ||
| '16 часов назад', | ||
| '17 часов назад', | ||
| '18 часов назад', | ||
| '19 часов назад', | ||
| '20 часов назад', | ||
| 'вчера', | ||
| '2 дня назад', | ||
| '3 дня назад', | ||
| '4 дня назад', | ||
| '5 дней назад', | ||
| 'неделю назад', | ||
| '2 недели назад', | ||
| '3 недели назад', | ||
| 'месяц назад', | ||
| '2 месяца назад', | ||
| '3 месяца назад', | ||
| '4 месяца назад', | ||
| 'полгода назад', | ||
| 'полгода назад', | ||
| 'полгода назад', | ||
| 'полгода назад', | ||
| 'полгода назад', | ||
| 'год назад', | ||
| 'год назад', | ||
| 'год назад', | ||
| '2 года назад', | ||
| '3 года назад', | ||
| '100 лет назад' | ||
| ], | ||
| new javascript_time_ago('ru'), | ||
| { units }) | ||
| }) | ||
| }) | ||
| function convenient_gradation_test(convenient_gradation_labels, time_ago, options = {}) | ||
| { | ||
| const now = Date.now() | ||
| const elapsed = time => time_ago.format(now - time * 1000, { now, ...options }) | ||
| if (convenient_gradation.length !== convenient_gradation_labels.length) | ||
| { | ||
| throw new Error(`Array length mismatch. Gradation steps: ${convenient_gradation.length}, labels: ${convenient_gradation_labels.length}`) | ||
| } | ||
| let i = 0 | ||
| while (i < convenient_gradation.length) | ||
| { | ||
| for (let time of convenient_gradation[i]) | ||
| { | ||
| elapsed(time).should.equal(convenient_gradation_labels[i]) | ||
| } | ||
| i++ | ||
| } | ||
| } | ||
| const convenient_gradation = | ||
| [ | ||
| // 'just now': | ||
| [ | ||
| 0, | ||
| 2.49 * 60 | ||
| ], | ||
| // '5 minutes ago': | ||
| [ | ||
| 2.51 * 60, | ||
| 7.49 * 60 | ||
| ], | ||
| // '10 minutes ago': | ||
| [ | ||
| 7.51 * 60, | ||
| 12.49 * 60 | ||
| ], | ||
| // '15 minutes ago': | ||
| [ | ||
| 12.51 * 60, | ||
| 17.49 * 60 | ||
| ], | ||
| // '20 minutes ago': | ||
| [ | ||
| 17.51 * 60, | ||
| 22.49 * 60 | ||
| ], | ||
| // '25 minutes ago': | ||
| [ | ||
| 22.51 * 60, | ||
| 27.49 * 60 | ||
| ], | ||
| // '30 minutes ago': | ||
| [ | ||
| 27.51 * 60, | ||
| 32.49 * 60 | ||
| ], | ||
| // '35 minutes ago': | ||
| [ | ||
| 32.51 * 60, | ||
| 37.49 * 60 | ||
| ], | ||
| // '40 minutes ago': | ||
| [ | ||
| 37.51 * 60, | ||
| 42.49 * 60 | ||
| ], | ||
| // '45 minutes ago': | ||
| [ | ||
| 42.51 * 60, | ||
| 47.49 * 60 | ||
| ], | ||
| // '50 minutes ago': | ||
| [ | ||
| 47.51 * 60, | ||
| 52.49 * 60 | ||
| ], | ||
| // 'an hour ago': | ||
| [ | ||
| 55.01 * 60, | ||
| 1.49 * 60 * 60 | ||
| ], | ||
| // '2 hours ago': | ||
| [ | ||
| 1.51 * 60 * 60, | ||
| 2.49 * 60 * 60 | ||
| ], | ||
| // '3 hours ago': | ||
| [ | ||
| 2.51 * 60 * 60, | ||
| 3.49 * 60 * 60 | ||
| ], | ||
| // '4 hours ago': | ||
| [ | ||
| 3.51 * 60 * 60, | ||
| 4.49 * 60 * 60 | ||
| ], | ||
| // '5 hours ago': | ||
| [ | ||
| 4.51 * 60 * 60, | ||
| 5.49 * 60 * 60 | ||
| ], | ||
| // '6 hours ago': | ||
| [ | ||
| 5.51 * 60 * 60, | ||
| 6.49 * 60 * 60 | ||
| ], | ||
| // '7 hours ago': | ||
| [ | ||
| 6.51 * 60 * 60, | ||
| 7.49 * 60 * 60 | ||
| ], | ||
| // '8 hours ago': | ||
| [ | ||
| 7.51 * 60 * 60, | ||
| 8.49 * 60 * 60 | ||
| ], | ||
| // '9 hours ago': | ||
| [ | ||
| 8.51 * 60 * 60, | ||
| 9.49 * 60 * 60 | ||
| ], | ||
| // '10 hours ago': | ||
| [ | ||
| 9.51 * 60 * 60, | ||
| 10.49 * 60 * 60 | ||
| ], | ||
| // '11 hours ago': | ||
| [ | ||
| 10.51 * 60 * 60, | ||
| 11.49 * 60 * 60 | ||
| ], | ||
| // '12 hours ago': | ||
| [ | ||
| 11.51 * 60 * 60, | ||
| 12.49 * 60 * 60 | ||
| ], | ||
| // '13 hours ago': | ||
| [ | ||
| 12.51 * 60 * 60, | ||
| 13.49 * 60 * 60 | ||
| ], | ||
| // '14 hours ago': | ||
| [ | ||
| 13.51 * 60 * 60, | ||
| 14.49 * 60 * 60 | ||
| ], | ||
| // '15 hours ago': | ||
| [ | ||
| 14.51 * 60 * 60, | ||
| 15.49 * 60 * 60 | ||
| ], | ||
| // '16 hours ago': | ||
| [ | ||
| 15.51 * 60 * 60, | ||
| 16.49 * 60 * 60 | ||
| ], | ||
| // '17 hours ago': | ||
| [ | ||
| 16.51 * 60 * 60, | ||
| 17.49 * 60 * 60 | ||
| ], | ||
| // '18 hours ago': | ||
| [ | ||
| 17.51 * 60 * 60, | ||
| 18.49 * 60 * 60 | ||
| ], | ||
| // '19 hours ago': | ||
| [ | ||
| 18.51 * 60 * 60, | ||
| 19.49 * 60 * 60 | ||
| ], | ||
| // '20 hours ago': | ||
| [ | ||
| 19.51 * 60 * 60, | ||
| 20.49 * 60 * 60 | ||
| ], | ||
| // 'yesterday': | ||
| [ | ||
| 20.51 * 60 * 60, | ||
| 1.49 * a_day | ||
| ], | ||
| // '2 days ago': | ||
| [ | ||
| 1.51 * a_day, | ||
| 2.49 * a_day | ||
| ], | ||
| // '3 days ago': | ||
| [ | ||
| 2.51 * a_day, | ||
| 3.49 * a_day | ||
| ], | ||
| // '4 days ago': | ||
| [ | ||
| 3.51 * a_day, | ||
| 4.49 * a_day | ||
| ], | ||
| // '5 days ago': | ||
| [ | ||
| 4.51 * a_day, | ||
| 5.49 * a_day | ||
| ], | ||
| // 'a week ago': | ||
| [ | ||
| 5.51 * a_day, | ||
| 1.49 * 7 * a_day | ||
| ], | ||
| // '2 weeks ago': | ||
| [ | ||
| 1.51 * 7 * a_day, | ||
| 2.49 * 7 * a_day | ||
| ], | ||
| // '3 weeks ago': | ||
| [ | ||
| 2.51 * 7 * a_day, | ||
| 3.49 * 7 * a_day | ||
| ], | ||
| // 'a month ago': | ||
| [ | ||
| 3.51 * 7 * a_day, | ||
| 1.49 * days_in_a_month * a_day | ||
| ], | ||
| // '2 months ago': | ||
| [ | ||
| 1.51 * days_in_a_month * a_day, | ||
| 2.49 * days_in_a_month * a_day | ||
| ], | ||
| // '3 months ago': | ||
| [ | ||
| 2.51 * days_in_a_month * a_day, | ||
| 3.49 * days_in_a_month * a_day | ||
| ], | ||
| // '4 months ago': | ||
| [ | ||
| 3.51 * days_in_a_month * a_day, | ||
| 4.49 * days_in_a_month * a_day | ||
| ], | ||
| // '5 months ago': | ||
| [ | ||
| 4.51 * days_in_a_month * a_day, | ||
| 5.49 * days_in_a_month * a_day | ||
| ], | ||
| // '6 months ago': | ||
| [ | ||
| 5.51 * days_in_a_month * a_day, | ||
| 6.49 * days_in_a_month * a_day | ||
| ], | ||
| // '7 months ago': | ||
| [ | ||
| 6.51 * days_in_a_month * a_day, | ||
| 7.49 * days_in_a_month * a_day | ||
| ], | ||
| // '8 months ago': | ||
| [ | ||
| 7.51 * days_in_a_month * a_day, | ||
| 8.49 * days_in_a_month * a_day | ||
| ], | ||
| // '9 months ago': | ||
| [ | ||
| 8.51 * days_in_a_month * a_day, | ||
| 8.99 * days_in_a_month * a_day | ||
| ], | ||
| // '9 months ago': | ||
| [ | ||
| 9.01 * days_in_a_month * a_day, | ||
| 9.49 * days_in_a_month * a_day | ||
| ], | ||
| // '10 months ago': | ||
| [ | ||
| 9.51 * days_in_a_month * a_day, | ||
| 10.49 * days_in_a_month * a_day | ||
| ], | ||
| // 'a year ago': | ||
| [ | ||
| 10.51 * days_in_a_month * a_day, | ||
| 1.49 * days_in_a_year * a_day | ||
| ], | ||
| // '2 years ago': | ||
| [ | ||
| 1.51 * days_in_a_year * a_day, | ||
| 2.49 * days_in_a_year * a_day | ||
| ], | ||
| // '3 years ago': | ||
| [ | ||
| 2.51 * days_in_a_year * a_day, | ||
| 3.49 * days_in_a_year * a_day | ||
| ], | ||
| // '100 years ago': | ||
| [ | ||
| 99.51 * days_in_a_year * a_day, | ||
| 100.49 * days_in_a_year * a_day | ||
| ] | ||
| ] |
| 'use strict' | ||
| // source: | ||
| // http://survivejs.com/webpack_react/authoring_libraries/ | ||
| var path = require('path') | ||
| var webpack = require('webpack') | ||
| var HtmlWebpackPlugin = require('html-webpack-plugin') | ||
| var merge = require('webpack-merge') | ||
| var minimist = require('minimist') | ||
| var pkg = require('./package.json') | ||
| var process_arguments = minimist(process.argv.slice(2)) | ||
| var action = process_arguments.action | ||
| if (!action) | ||
| { | ||
| console.log('Action required.') | ||
| console.log('Usage: webpack --target=[dev|gh-pages|build|build-minified]') | ||
| return | ||
| } | ||
| var Root_folder = path.resolve(__dirname) | ||
| var Demo_folder = 'demo' | ||
| var babel = 'babel?optional[]=runtime&stage=0' | ||
| var config = | ||
| { | ||
| paths: | ||
| { | ||
| dist: path.join(Root_folder, 'build'), | ||
| src: path.join(Root_folder, 'source'), | ||
| demo: path.join(Root_folder, Demo_folder), | ||
| demoIndex: path.join(Root_folder, Demo_folder, '/index') | ||
| }, | ||
| filename: 'react-isomorphic-render', | ||
| library: 'react-isomorphic-render' | ||
| } | ||
| var merge_demo = merge.bind(null, | ||
| { | ||
| resolve: | ||
| { | ||
| extensions: ['', '.js', '.jsx', '.md', '.css', '.png', '.jpg'] | ||
| }, | ||
| module: | ||
| { | ||
| loaders: | ||
| [ | ||
| { | ||
| test: /\.css$/, | ||
| loaders: ['style', 'css'] | ||
| }, | ||
| { | ||
| test: /\.md$/, | ||
| loaders: ['html', 'highlight', 'markdown'] | ||
| }, | ||
| { | ||
| test: /\.png$/, | ||
| loader: 'url?limit=100000&mimetype=image/png', | ||
| include: config.paths.demo | ||
| }, | ||
| { | ||
| test: /\.jpg$/, | ||
| loader: 'file', | ||
| include: config.paths.demo | ||
| }, | ||
| { | ||
| test: /\.json$/, | ||
| loader: 'json' | ||
| } | ||
| ] | ||
| } | ||
| }) | ||
| var merge_build = merge.bind(null, | ||
| { | ||
| devtool: 'source-map', | ||
| output: | ||
| { | ||
| path: config.paths.dist, | ||
| libraryTarget: 'umd', | ||
| library: config.library | ||
| }, | ||
| entry: config.paths.src, | ||
| externals: | ||
| { | ||
| //// if you are not testing, just react will do | ||
| //react: 'react', | ||
| // 'react/addons': 'react/addons' | ||
| }, | ||
| module: | ||
| { | ||
| loaders: | ||
| [ | ||
| { | ||
| test: /\.jsx?$/, | ||
| loaders: [babel], | ||
| include: config.paths.src | ||
| } | ||
| ] | ||
| } | ||
| }) | ||
| switch (action) | ||
| { | ||
| // Starts WebPack development server | ||
| case 'dev': | ||
| var IP = '0.0.0.0' | ||
| var PORT = 3000 | ||
| module.exports = merge_demo | ||
| ({ | ||
| ip: IP, | ||
| port: PORT, | ||
| devtool: 'eval', | ||
| entry: | ||
| [ | ||
| 'webpack-dev-server/client?http://' + IP + ':' + PORT, | ||
| 'webpack/hot/only-dev-server', | ||
| config.paths.demoIndex | ||
| ], | ||
| output: | ||
| { | ||
| path: __dirname, | ||
| filename: 'bundle.js', | ||
| publicPath: '/' | ||
| }, | ||
| plugins: | ||
| [ | ||
| new webpack.DefinePlugin | ||
| ({ | ||
| 'process.env': | ||
| { | ||
| 'NODE_ENV': JSON.stringify('development'), | ||
| } | ||
| }), | ||
| new webpack.HotModuleReplacementPlugin(), | ||
| new webpack.NoErrorsPlugin(), | ||
| new HtmlWebpackPlugin() | ||
| ], | ||
| module: | ||
| { | ||
| preLoaders: | ||
| [ | ||
| { | ||
| test: /\.jsx?$/, | ||
| loaders: ['eslint', 'jscs'], | ||
| include: [config.paths.demo, config.paths.src] | ||
| } | ||
| ], | ||
| loaders: | ||
| [ | ||
| { | ||
| test: /\.jsx?$/, | ||
| loaders: ['react-hot', babel], | ||
| include: [config.paths.demo, config.paths.src] | ||
| } | ||
| ] | ||
| } | ||
| }) | ||
| break | ||
| // Generates a github pages website | ||
| case 'gh-pages': | ||
| module.exports = merge_demo | ||
| ({ | ||
| entry: | ||
| { | ||
| app: config.paths.demoIndex, | ||
| // tweak this to include your externs unless you load them some other way | ||
| vendors: ['react/addons'] | ||
| }, | ||
| output: | ||
| { | ||
| path: './gh-pages', | ||
| filename: 'bundle.[chunkhash].js' | ||
| }, | ||
| plugins: | ||
| [ | ||
| new webpack.DefinePlugin | ||
| ({ | ||
| 'process.env': | ||
| { | ||
| // This has effect on the react lib size | ||
| 'NODE_ENV': JSON.stringify('production'), | ||
| } | ||
| }), | ||
| new webpack.optimize.DedupePlugin(), | ||
| new webpack.optimize.UglifyJsPlugin | ||
| ({ | ||
| compress: | ||
| { | ||
| warnings: false | ||
| } | ||
| }), | ||
| new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.[chunkhash].js'), | ||
| new HtmlWebpackPlugin | ||
| ({ | ||
| title: pkg.name + ' - ' + pkg.description | ||
| }) | ||
| ], | ||
| module: | ||
| { | ||
| loaders: | ||
| [ | ||
| { | ||
| test: /\.jsx?$/, | ||
| loaders: [babel], | ||
| include: [config.paths.demo, config.paths.src] | ||
| } | ||
| ] | ||
| } | ||
| }) | ||
| break | ||
| // Builds the project into a single file | ||
| case 'build': | ||
| module.exports = merge_build | ||
| ({ | ||
| output: | ||
| { | ||
| filename: config.filename + '.js' | ||
| } | ||
| }) | ||
| break | ||
| // Builds the project into a single minified file | ||
| case 'build-minified': | ||
| module.exports = merge_build | ||
| ({ | ||
| output: | ||
| { | ||
| filename: config.filename + '.minified.js' | ||
| }, | ||
| plugins: | ||
| [ | ||
| new webpack.optimize.UglifyJsPlugin | ||
| ({ | ||
| compress: | ||
| { | ||
| warnings: false | ||
| } | ||
| }) | ||
| ] | ||
| }) | ||
| break | ||
| } |
Sorry, the diff of this file is not supported yet
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2
-60%99672
-34.03%16
-38.46%1897
-51.26%