diff --git a/.eslintrc.json b/.eslintrc.json
index a69b5f2cf..97a4645f8 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -24,6 +24,21 @@
],
"func-names": [
0
+ ],
+ "import/no-extraneous-dependencies": [
+ 0
+ ],
+ "import/no-unresolved": [
+ 2,
+ {
+ "ignore": [
+ "dayjs"
+ ]
+ }
+ ],
+ "import/extensions": [
+ 2,
+ "ignorePackages"
]
}
}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index cf2838a38..2ca2c00de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,10 @@ package-lock.json
# jest
coverage
-# dist
-dist
\ No newline at end of file
+# build
+locale
+plugin
+dayjs.min.js
+
+#dev
+demo.js
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
index b318b779b..7b67ff777 100644
--- a/.npmignore
+++ b/.npmignore
@@ -10,4 +10,9 @@ yarn.lock
package-lock.json
# jest
-coverage
\ No newline at end of file
+coverage
+
+# dev
+src
+test
+build
\ No newline at end of file
diff --git a/README.md b/README.md
index e614ec76e..0b74d1a8c 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,13 @@ English | [简体中文](./README.zh-CN.md)
src="https://img.shields.io/codecov/c/github/xx45/dayjs/master.svg?style=flat-square" alt="Codecov">
+
+
+
+
-> Day.js is a minimalist JavaScript library for modern browsers with a largely Moment.js-compatible API. If you use Moment.js, you already know how to use Day.js.
+> Day.js is a minimalist JavaScript library that parse, validate, manipulate, and display dates and times for modern browsers with a largely Moment.js-compatible API. If you use Moment.js, you already know how to use Day.js.
```js
dayjs().startOf('month').add(1, 'day').set('year', 2018).format('YYYY-MM-DD HH:mm:ss');
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 8fe264c57..a9f18193e 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -16,6 +16,10 @@
src="https://img.shields.io/codecov/c/github/xx45/dayjs/master.svg?style=flat-square" alt="Codecov">
+
+
+
+
> Day.js 是一个轻量的 JavaScript 时间日期处理库,和 Moment.js 的 API 设计保持完全一样. 如果你曾经用过 Moment.js, 那么你已经知道如何使用 Day.js
diff --git a/build/index.js b/build/index.js
new file mode 100644
index 000000000..65b5bc75e
--- /dev/null
+++ b/build/index.js
@@ -0,0 +1,45 @@
+const rollup = require('rollup')
+const configFactory = require('./rollup.config')
+const fs = require('fs')
+const util = require('util')
+const path = require('path')
+
+const { promisify } = util
+
+const promisifyReadDir = promisify(fs.readdir)
+
+const formatName = n => n.replace(/\.js/, '').replace('-', '_')
+
+async function build(option) {
+ const bundle = await rollup.rollup(option.input)
+ await bundle.write(option.output)
+}
+
+(async () => {
+ try {
+ const locales = await promisifyReadDir(path.join(__dirname, '../src/locale'))
+ locales.forEach((l) => {
+ build(configFactory({
+ input: `./src/locale/${l}`,
+ fileName: `./locale/${l}`,
+ name: `dayjs_locale_${formatName(l)}`
+ }))
+ })
+
+ const plugins = await promisifyReadDir(path.join(__dirname, '../src/plugin'))
+ plugins.forEach((l) => {
+ build(configFactory({
+ input: `./src/plugin/${l}`,
+ fileName: `./plugin/${l}`,
+ name: `dayjs_plugin_${formatName(l)}`
+ }))
+ })
+
+ build(configFactory({
+ input: './src/index.js',
+ fileName: './dayjs.min.js'
+ }))
+ } catch (e) {
+ console.error(e) // eslint-disable-line no-console
+ }
+})()
diff --git a/build/rollup.config.js b/build/rollup.config.js
new file mode 100644
index 000000000..4d31b990e
--- /dev/null
+++ b/build/rollup.config.js
@@ -0,0 +1,28 @@
+const babel = require('rollup-plugin-babel')
+const uglify = require('rollup-plugin-uglify')
+
+module.exports = (config) => {
+ const { input, fileName, name } = config
+ return {
+ input: {
+ input,
+ external: [
+ 'dayjs'
+ ],
+ plugins: [
+ babel({
+ exclude: 'node_modules/**'
+ }),
+ uglify()
+ ]
+ },
+ output: {
+ file: fileName,
+ format: 'umd',
+ name: name || 'dayjs',
+ globals: {
+ dayjs: 'dayjs'
+ }
+ }
+ }
+}
diff --git a/karma.sauce.conf.js b/karma.sauce.conf.js
index a146e974d..4d05721ce 100644
--- a/karma.sauce.conf.js
+++ b/karma.sauce.conf.js
@@ -82,7 +82,7 @@ module.exports = function (config) {
basePath: '',
frameworks: ['jasmine'],
files: [
- 'dist/*.js',
+ 'dayjs.min.js',
'test/*spec.js'
],
reporters: ['dots', 'saucelabs'],
@@ -90,6 +90,7 @@ module.exports = function (config) {
colors: true,
logLevel: config.LOG_DEBUG,
sauceLabs: {
+ // build: 'Manual',
testName: 'Day.js'
},
captureTimeout: 200000, // try fix ios timeout
diff --git a/package.json b/package.json
index d03402263..79e789d92 100644
--- a/package.json
+++ b/package.json
@@ -1,21 +1,24 @@
{
"name": "dayjs",
"version": "0.0.0-development",
- "description": "2KB immutable date library alternative to Moment.js with the same modern API ",
- "main": "dist/dayjs.min.js",
+ "description": "2KB immutable date time library alternative to Moment.js with the same modern API ",
+ "main": "dayjs.min.js",
"types": "index.d.ts",
"scripts": {
"test": "jest",
- "lint": "./node_modules/.bin/eslint src/* test/*",
- "build": "BABEL_ENV=build rollup -c",
+ "lint": "./node_modules/.bin/eslint src/* test/* build/*",
+ "build": "BABEL_ENV=build node build",
"sauce": "npx karma start karma.sauce.conf.js",
"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2 && npm run sauce -- 3",
- "gzip-size": "gzip-size ./dist/*.min.js"
+ "gzip-size": "gzip-size dayjs.min.js"
},
"pre-commit": [
"lint"
],
"jest": {
+ "roots": [
+ "test"
+ ],
"testRegex": "test/(.*?/)?.*test.js$",
"coverageDirectory": "./coverage/",
"collectCoverage": true,
@@ -23,6 +26,14 @@
"src/**/*"
]
},
+ "release": {
+ "prepare": [
+ {
+ "path": "@semantic-release/changelog"
+ },
+ "@semantic-release/git"
+ ]
+ },
"keywords": [
"dayjs",
"date",
diff --git a/rollup.config.js b/rollup.config.js
deleted file mode 100644
index 6a1fc4d54..000000000
--- a/rollup.config.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import babel from 'rollup-plugin-babel'
-import uglify from 'rollup-plugin-uglify'
-import packageInfo from './package.json';
-
-export default {
- input: 'src/index.js',
- output: {
- file: `dist/${packageInfo.name}.min.js`,
- format: 'umd',
- name: 'dayjs'
- },
- plugins: [
- babel({
- exclude: 'node_modules/**'
- }),
- uglify()
- ]
-};
\ No newline at end of file
diff --git a/src/constant.js b/src/constant.js
index d92932022..fc6c079bc 100644
--- a/src/constant.js
+++ b/src/constant.js
@@ -21,12 +21,15 @@ export const Q = 'quarter'
export const Y = 'year'
export const DATE = 'date'
-export const WEEKDAYS = 'Sunday.Monday.Tuesday.Wednesday.Thursday.Friday.Saturday'.split('.')
-export const MONTHS = 'January.February.March.April.May.June.July.August.September.October.November.December'.split('.')
-
export const FORMAT_DEFAULT = 'YYYY-MM-DDTHH:mm:ssZ'
// regex
export const REGEX_PARSE = /^(\d{4})-?(\d{1,2})-?(\d{1,2})(.*?(\d{1,2}):(\d{1,2}):(\d{1,2}))?.?(\d{1,3})?$/
export const REGEX_FORMAT = /\[.*?\]|Y{2,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g
+export const en = {
+ name: 'en',
+ weekdays: 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),
+ months: 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_')
+}
+
diff --git a/src/index.js b/src/index.js
index a4cfc6d84..37dad9eb9 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,10 +1,9 @@
import * as C from './constant'
-import * as U from './utils'
-import en from './locale/en'
+import U from './utils'
let L = 'en' // global locale
const Ls = {} // global loaded locale
-Ls[L] = en
+Ls[L] = C.en
const isDayjs = d => d instanceof Dayjs // eslint-disable-line no-use-before-define
diff --git a/src/locale/en.js b/src/locale/en.js
deleted file mode 100644
index 9128a9126..000000000
--- a/src/locale/en.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as C from '../constant'
-
-export default { // may be we just need these two at the present
- name: 'en',
- weekdays: C.WEEKDAYS,
- months: C.MONTHS
-}
diff --git a/src/locale/es.js b/src/locale/es.js
index 7470bffcb..6fc201439 100644
--- a/src/locale/es.js
+++ b/src/locale/es.js
@@ -1,5 +1,12 @@
-export default {
+import dayjs from 'dayjs'
+
+const locale = {
name: 'es',
- weekdays: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
- months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre']
+ weekdays: 'Domingo_Lunes_Martes_Miércoles_Jueves_Viernes_Sábado'.split('_'),
+ months: 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'),
+ ordinal: n => `${n}º`
}
+
+dayjs.locale(locale, null, true)
+
+export default locale
diff --git a/src/locale/zh-cn.js b/src/locale/zh-cn.js
new file mode 100644
index 000000000..6480ebd23
--- /dev/null
+++ b/src/locale/zh-cn.js
@@ -0,0 +1,12 @@
+import dayjs from 'dayjs'
+
+const locale = {
+ name: 'zh-cn',
+ weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
+ months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
+ ordinal: n => n
+}
+
+dayjs.locale(locale, null, true)
+
+export default locale
diff --git a/src/plugin/advancedFormat.js b/src/plugin/advancedFormat.js
index 10200325b..363fe52de 100644
--- a/src/plugin/advancedFormat.js
+++ b/src/plugin/advancedFormat.js
@@ -29,3 +29,4 @@ export default (o, c, d) => { // locale needed later
return oldFormat.bind(this)(result, locale)
}
}
+
diff --git a/src/utils.js b/src/utils.js
index 4d727d2f6..de18ac760 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,17 +1,17 @@
-export const padStart = (string, length, pad) => {
+const padStart = (string, length, pad) => {
const s = String(string)
if (!s || s.length >= length) return string
return `${Array((length + 1) - s.length).join(pad)}${string}`
}
-export const padZoneStr = (negMinuts) => {
+const padZoneStr = (negMinuts) => {
const minutes = Math.abs(negMinuts)
const hourOffset = Math.floor(minutes / 60)
const minuteOffset = minutes % 60
return `${negMinuts <= 0 ? '+' : '-'}${padStart(hourOffset, 2, '0')}:${padStart(minuteOffset, 2, '0')}`
}
-export const monthDiff = (a, b) => {
+const monthDiff = (a, b) => {
// function from moment.js in order to keep the same result
const wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month())
const anchor = a.clone().add(wholeMonthDiff, 'months')
@@ -27,8 +27,17 @@ export const monthDiff = (a, b) => {
return Number(-(wholeMonthDiff + adjust))
}
-export const absFloor = n => (n < 0 ? Math.ceil(n) || 0 : Math.floor(n))
+const absFloor = n => (n < 0 ? Math.ceil(n) || 0 : Math.floor(n))
-export const prettyUnit = u => (u && String(u).toLowerCase().replace(/s$/, ''))
+const prettyUnit = u => (u && String(u).toLowerCase().replace(/s$/, ''))
-export const isUndefined = s => s === undefined
+const isUndefined = s => s === undefined
+
+export default {
+ padStart,
+ padZoneStr,
+ monthDiff,
+ absFloor,
+ prettyUnit,
+ isUndefined
+}
diff --git a/test/__mocks__/dayjs.js b/test/__mocks__/dayjs.js
new file mode 100644
index 000000000..b696adbea
--- /dev/null
+++ b/test/__mocks__/dayjs.js
@@ -0,0 +1,3 @@
+const dayjs = require('../../src')
+
+module.exports = dayjs
diff --git a/test/locale.test.js b/test/locale.test.js
index e90185b9c..88d34e7cf 100644
--- a/test/locale.test.js
+++ b/test/locale.test.js
@@ -1,7 +1,6 @@
import MockDate from 'mockdate'
import dayjs from '../src'
import es from '../src/locale/es'
-import en from '../src/locale/en'
beforeEach(() => {
MockDate.set(new Date())
@@ -39,7 +38,7 @@ it('set locale for this line only', () => {
})
it('set global locale', () => {
- dayjs.locale(en)
+ dayjs.locale('en')
expect(dayjs('2018-4-28').format(format))
.toBe('Saturday 28, April')
dayjs.locale(es)
diff --git a/test/locale/keys.test.js b/test/locale/keys.test.js
new file mode 100644
index 000000000..e6e4d6fdf
--- /dev/null
+++ b/test/locale/keys.test.js
@@ -0,0 +1,29 @@
+import fs from 'fs'
+import path from 'path'
+import dayjs from '../../src'
+
+const localeDir = '../../src/locale'
+const L = []
+
+// load all locales from locale dir
+fs.readdirSync(path.join(__dirname, localeDir))
+ .forEach((file) => {
+ // eslint-disable-next-line
+ L.push(require(path.join(__dirname, localeDir, file)).default)
+ })
+
+it('Locale keys', () => {
+ L.forEach((l) => {
+ const {
+ name, ordinal, weekdays, months
+ } = l
+ expect(name).toEqual(expect.any(String))
+ expect(weekdays).toEqual(expect.any(Array))
+ expect(months).toEqual(expect.any(Array))
+ if (ordinal) {
+ // function pass date return string or number or null
+ expect(ordinal(1)).toEqual(expect.anything())
+ }
+ expect(dayjs().locale(name).$locale().name).toBe(name)
+ })
+})
diff --git a/test/plugin/advancedFormat.test.js b/test/plugin/advancedFormat.test.js
index 6b1f5432e..f93676d2f 100644
--- a/test/plugin/advancedFormat.test.js
+++ b/test/plugin/advancedFormat.test.js
@@ -41,6 +41,8 @@ it('Format Day of Month Do 1 - 31', () => {
it('Format Hour k kk 24-hour 1 - 24', () => {
expect(dayjs().format('k')).toBe(moment().format('k'))
expect(dayjs().format('kk')).toBe(moment().format('kk'))
- const d = '2018-05-02 00:00:00.000'
+ let d = '2018-05-02 00:00:00.000'
+ expect(dayjs(d).format('k')).toBe(moment(d).format('k'))
+ d = '2018-05-02 01:00:00.000'
expect(dayjs(d).format('k')).toBe(moment(d).format('k'))
})
diff --git a/test/utils.test.js b/test/utils.test.js
index 5ab21fddc..e70623e79 100644
--- a/test/utils.test.js
+++ b/test/utils.test.js
@@ -1,4 +1,4 @@
-import * as Utils from '../src/utils'
+import Utils from '../src/utils'
const {
prettyUnit,