1+ // MIT © 2016 azu
2+ "use strict" ;
3+ const chrono = require ( "chrono-node" ) ;
4+ const moment = require ( 'moment' ) ;
5+ /**
6+ * from chrono tags
7+ * @type {[RegExp] }
8+ */
9+ const supportedLang = [
10+ [ / ^ E N / , "en" ] ,
11+ [ / ^ J P / , "ja" ] ,
12+ [ / ^ E S / , "es" ] ,
13+ [ / ^ F R / , "fr" ] ,
14+ [ / ^ Z H / , "zh" ]
15+ ] ;
16+
17+ /**
18+ * detect lang and return language string
19+ * @param {string[] } tags
20+ * @returns {string|null }
21+ */
22+ const detectLang = ( tags ) => {
23+ const targetLangs = supportedLang . filter ( ( [ langRegExp ] ) => {
24+ return tags . some ( tag => langRegExp . test ( tag ) ) ;
25+ } ) ;
26+ if ( targetLangs . length === 0 ) {
27+ return null ;
28+ }
29+ const selectedLang = targetLangs [ 0 ] ;
30+ return selectedLang [ 1 ] ;
31+ } ;
32+ function reporter ( context ) {
33+ const { Syntax, RuleError, report, fixer, getSource} = context ;
34+ if ( typeof Intl === "undefined" ) {
35+ throw new Error ( "Not support your Node.js/browser. should be use latest version." ) ;
36+ }
37+ return {
38+ [ Syntax . Str ] ( node ) {
39+ const text = getSource ( node ) ;
40+ const chronoDate = chrono . parse ( text ) ;
41+ chronoDate . forEach ( chronoDate => {
42+ const lang = detectLang ( Object . keys ( chronoDate . tags ) ) ;
43+ if ( ! lang ) {
44+ // not found lang
45+ return ;
46+ }
47+ // change lang
48+ moment . locale ( lang ) ;
49+ // get weekday from actual date string
50+ const kV = chronoDate . start . knownValues ;
51+ const $moment = moment ( `${ kV . year } -${ kV . month } -${ kV . day } ` , "YYYY-MM-DD" , lang ) ;
52+ const slicedText = text . slice ( chronoDate . index ) ;
53+ // (match) or (match)
54+ const match = slicedText . match ( / \s * ?( [ ( ( ] ) ( [ ^ ( ( ) ] + ) ( [ ) ) ] ) / ) ;
55+ if ( ! match ) {
56+ return ;
57+ }
58+ const actualDateText = match [ 0 ] ;
59+ const actualTextAll = `${ chronoDate . text } ${ actualDateText } ` ;
60+ const pairStartSymbol = match [ 1 ] ; // (
61+ const pairEndSymbol = match [ 3 ] ; // )
62+ const maybeWeekdayText = match [ 2 ] . trim ( ) ; // weekday
63+ // 2016年12月30日 (金曜日)
64+ // ^ ^ ^
65+ // chronoDate.index match.index pairStartSymbol.length
66+ const paddingIndex = chronoDate . index + match . index + pairStartSymbol . length ;
67+ // format http://momentjs.com/docs/#/parsing/string-format/
68+ const weekdayPatterns = [
69+ // date-format , symbols
70+ [ "dd" , moment . weekdaysMin ( ) ] ,
71+ [ "ddd" , moment . weekdaysShort ( ) ] ,
72+ [ "dddd" , moment . weekdays ( ) ]
73+ ] ;
74+ weekdayPatterns . forEach ( ( [ format , symbols ] ) => {
75+ if ( symbols . indexOf ( maybeWeekdayText ) === - 1 ) {
76+ return ;
77+ }
78+ // e.g.) "Friday"
79+ const expectedWeekday = $moment . format ( format ) ;
80+ if ( maybeWeekdayText !== expectedWeekday ) {
81+ const fix = fixer . replaceTextRange (
82+ [ paddingIndex , paddingIndex + expectedWeekday . length ] ,
83+ expectedWeekday
84+ ) ;
85+ report ( node , new RuleError ( `${ actualTextAll } mismatch weekday.\n${ actualTextAll } => ${ chronoDate . text } ${ pairStartSymbol } ${ expectedWeekday } ${ pairEndSymbol } ` , {
86+ index : paddingIndex ,
87+ fix
88+ } ) ) ;
89+ }
90+ } ) ;
91+ } ) ;
92+ }
93+ } ;
94+ }
95+ module . exports = {
96+ linter : reporter ,
97+ fixer : reporter
98+ } ;
0 commit comments