From 0a407bbd04f5ffd10b0edb89d52b4a36f6df6fb5 Mon Sep 17 00:00:00 2001 From: watackeech Date: Wed, 23 Apr 2025 17:29:17 +0900 Subject: [PATCH 1/5] feat: add useCurrentYearIfMissing option to support dates without year --- README.md | 15 ++++++ src/textlint-rule-date-weekday-mismatch.js | 49 ++++++++++++++++++- ...extlint-rule-date-weekday-mismatch-test.js | 39 ++++++++++++++- 3 files changed, 100 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 04c2372..a329697 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,21 @@ But, You can specify `2016-12-30` is `ja-JP` text by options } ``` +- `useCurrentYearIfMissing`: boolean + - Default: false + - If true, when the year is missing in the date string (e.g. `4月23日(月)`), the current year will be automatically added for validation. + - This is useful for documents that often omit the year in dates. + +```json +{ + "rules": { + "date-weekday-mismatch": { + "useCurrentYearIfMissing": true + } + } +} +``` + language format following ISO 639-1. e.g.) `en-US`, `en`, `ja` etc.. diff --git a/src/textlint-rule-date-weekday-mismatch.js b/src/textlint-rule-date-weekday-mismatch.js index 43db0c8..9894c8b 100644 --- a/src/textlint-rule-date-weekday-mismatch.js +++ b/src/textlint-rule-date-weekday-mismatch.js @@ -50,6 +50,30 @@ const detectLang = (tags, preferLang) => { const selectedLang = targetLangs[0]; return selectedLang[1]; }; + +/** + * Add current year to date string if missing. + * @param {string} dateText + * @param {number} year + * @param {string} lang + * @returns {string} + */ +function addYearToDateText(dateText, year, lang) { + // Japanese: 4月23日(月) → 2024年4月23日(月) + if (lang === "ja") { + return `${year}年${dateText}`; + } + // Slash: 4/23(月) → 2024/4/23(月) + if (/^[0-9]{1,2}\/[0-9]{1,2}/.test(dateText)) { + return `${year}/${dateText}`; + } + // Dash: 4-23(Mon) → 2024-4-23(Mon) + if (/^[0-9]{1,2}-[0-9]{1,2}/.test(dateText)) { + return `${year}-${dateText}`; + } + // Default: prepend year and a space + return `${year} ${dateText}`; +} /** * * @param context @@ -57,6 +81,7 @@ const detectLang = (tags, preferLang) => { */ function reporter(context, config = {}) { const preferLang = config.lang; + const useCurrentYearIfMissing = config.useCurrentYearIfMissing; const {Syntax, RuleError, report, fixer, getSource} = context; if (typeof Intl === "undefined") { throw new Error("Not support your Node.js/browser. should be use latest version."); @@ -65,7 +90,29 @@ function reporter(context, config = {}) { return { [Syntax.Str](node){ const text = getSource(node); - const chronoDates = chrono.parse(text); + let chronoDates = chrono.parse(text); + // Add current year if missing and option is enabled + if (useCurrentYearIfMissing) { + const currentYear = (new Date()).getFullYear(); + chronoDates.forEach(chronoDate => { + // If year is not specified in the parsed result + if ( + chronoDate.start && + chronoDate.start.knownValues.year === undefined + ) { + // Detect language for the date string + const lang = detectLang(Object.keys(chronoDate.tags), preferLang); + if (!lang) return; + // Re-parse the text with the year added + const newText = addYearToDateText(chronoDate.text, currentYear, lang); + const reparsed = chrono.parse(newText, undefined, {forwardDate: true}); + // If reparsed successfully, update knownValues with year/month/day + if (reparsed && reparsed[0] && reparsed[0].start && reparsed[0].start.knownValues) { + Object.assign(chronoDate.start.knownValues, reparsed[0].start.knownValues); + } + } + }); + } // ignore "今日" text // ignore not valid data const filteredChronoDates = chronoDates.filter(textIncludesNumber).filter(yearMonthDayShouldKnownValues); diff --git a/test/textlint-rule-date-weekday-mismatch-test.js b/test/textlint-rule-date-weekday-mismatch-test.js index 9ffdc65..dc2dcfd 100644 --- a/test/textlint-rule-date-weekday-mismatch-test.js +++ b/test/textlint-rule-date-weekday-mismatch-test.js @@ -18,7 +18,18 @@ tester.run("rule", rule, { // invalid date should be ignored "11月 25日 (火曜日) ", // ignore relative word - "今日(火曜日)はどうしよう" + "今日(火曜日)はどうしよう", + // useCurrentYearIfMissing option: valid + { + text: "4月23日(水)", + options: { useCurrentYearIfMissing: true, lang: "ja" }, + // 2025年4月23日は水曜日 + }, + { + text: "4/23(Wed)", + options: { useCurrentYearIfMissing: true, lang: "en" }, + // 2025-04-23 is Wednesday + }, ], invalid: [ // single match @@ -122,6 +133,30 @@ tester.run("rule", rule, { } ] }, - + // useCurrentYearIfMissing option: invalid + { + text: "4月23日(金)", + output: "4月23日(水)", + options: { useCurrentYearIfMissing: true, lang: "ja" }, + errors: [ + { + message: "4月23日(金) mismatch weekday.\n4月23日(金) => 4月23日(水)", + line: 1, + column: 7 + } + ] + }, + { + text: "4/23(Fri)", + output: "4/23(Wed)", + options: { useCurrentYearIfMissing: true, lang: "en" }, + errors: [ + { + message: "4/23(Fri) mismatch weekday.\n4/23(Fri) => 4/23(Wed)", + line: 1, + column: 6 + } + ] + }, ] }); From 64959db6976aaa71131f4726057a701be1b277cc Mon Sep 17 00:00:00 2001 From: watackeech Date: Wed, 23 Apr 2025 18:14:59 +0900 Subject: [PATCH 2/5] refactor: convert addYearToDateText to arrow function and improve readability --- src/textlint-rule-date-weekday-mismatch.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/textlint-rule-date-weekday-mismatch.js b/src/textlint-rule-date-weekday-mismatch.js index 9894c8b..83b5103 100644 --- a/src/textlint-rule-date-weekday-mismatch.js +++ b/src/textlint-rule-date-weekday-mismatch.js @@ -50,7 +50,6 @@ const detectLang = (tags, preferLang) => { const selectedLang = targetLangs[0]; return selectedLang[1]; }; - /** * Add current year to date string if missing. * @param {string} dateText @@ -58,7 +57,7 @@ const detectLang = (tags, preferLang) => { * @param {string} lang * @returns {string} */ -function addYearToDateText(dateText, year, lang) { +const addYearToDateText = (dateText, year, lang) => { // Japanese: 4月23日(月) → 2024年4月23日(月) if (lang === "ja") { return `${year}年${dateText}`; @@ -102,7 +101,9 @@ function reporter(context, config = {}) { ) { // Detect language for the date string const lang = detectLang(Object.keys(chronoDate.tags), preferLang); - if (!lang) return; + if (!lang) { + return; + } // Re-parse the text with the year added const newText = addYearToDateText(chronoDate.text, currentYear, lang); const reparsed = chrono.parse(newText, undefined, {forwardDate: true}); From 7402db3b3900c574f7c5fdd2c867feca4f45befc Mon Sep 17 00:00:00 2001 From: watackeech Date: Wed, 23 Apr 2025 18:18:25 +0900 Subject: [PATCH 3/5] chore: add sinon for mocking current date to test `useCurrentYearIfMissing` option --- package.json | 1 + ...extlint-rule-date-weekday-mismatch-test.js | 11 ++++ yarn.lock | 56 ++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8237b15..1bd898f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ }, "homepage": "https://github.com/textlint-rule/textlint-rule-date-weekday-mismatch", "devDependencies": { + "sinon": "^20.0.0", "textlint-scripts": "^12.0.2" }, "keywords": [ diff --git a/test/textlint-rule-date-weekday-mismatch-test.js b/test/textlint-rule-date-weekday-mismatch-test.js index dc2dcfd..cd330d9 100644 --- a/test/textlint-rule-date-weekday-mismatch-test.js +++ b/test/textlint-rule-date-weekday-mismatch-test.js @@ -1,8 +1,19 @@ import TextLintTester from "textlint-tester"; +import sinon from "sinon"; const tester = new TextLintTester(); // rule const rule = require("../src/textlint-rule-date-weekday-mismatch"); + +// Mock: fix current date to 2025-04-23 to test `useCurrentYearIfMissing` option +let clock; +before(() => { + clock = sinon.useFakeTimers(new Date(2025, 4, 23).getTime()); +}); +after(() => { + clock.restore(); +}); + // ruleName, rule, { valid, invalid } tester.run("rule", rule, { valid: [ diff --git a/yarn.lock b/yarn.lock index 9f01aeb..c5c8c63 100644 --- a/yarn.lock +++ b/yarn.lock @@ -993,6 +993,29 @@ readdirp "^2.2.1" upath "^1.1.1" +"@sinonjs/commons@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^13.0.5": + version "13.0.5" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" + integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== + dependencies: + "@sinonjs/commons" "^3.0.1" + +"@sinonjs/samsam@^8.0.1": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.2.tgz#e4386bf668ff36c95949e55a38dc5f5892fc2689" + integrity sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw== + dependencies: + "@sinonjs/commons" "^3.0.1" + lodash.get "^4.4.2" + type-detect "^4.1.0" + "@textlint/ast-node-types@^12.0.0": version "12.0.0" resolved "https://registry.yarnpkg.com/@textlint/ast-node-types/-/ast-node-types-12.0.0.tgz#23bd683f9fc04209ae28bff72954c8aa67c6b1ca" @@ -1785,6 +1808,11 @@ diff@^4.0.2: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +diff@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a" + integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw== + ejs@^2.4.1: version "2.7.1" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" @@ -2565,6 +2593,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== + lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -3614,6 +3647,17 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +sinon@^20.0.0: + version "20.0.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-20.0.0.tgz#4b653468735f7152ba694d05498c2b5d024ab006" + integrity sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ== + dependencies: + "@sinonjs/commons" "^3.0.1" + "@sinonjs/fake-timers" "^13.0.5" + "@sinonjs/samsam" "^8.0.1" + diff "^7.0.0" + supports-color "^7.2.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -3842,7 +3886,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.1.0, supports-color@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -3990,6 +4034,16 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" From da86588dbda443b42ded9743bcab3bd677204f8c Mon Sep 17 00:00:00 2001 From: watackeech Date: Thu, 24 Apr 2025 09:55:09 +0900 Subject: [PATCH 4/5] add: currentYear option and remove sinon dependency --- README.md | 25 +++++++++ package.json | 1 - src/textlint-rule-date-weekday-mismatch.js | 6 +- ...extlint-rule-date-weekday-mismatch-test.js | 18 ++---- yarn.lock | 56 +------------------ 5 files changed, 34 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index a329697..d9d8512 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ But, You can specify `2016-12-30` is `ja-JP` text by options - If true, when the year is missing in the date string (e.g. `4月23日(月)`), the current year will be automatically added for validation. - This is useful for documents that often omit the year in dates. +Example: + ```json { "rules": { @@ -102,6 +104,29 @@ But, You can specify `2016-12-30` is `ja-JP` text by options } ``` +If the text contains `4月23日(水)`, and the current year is 2025, it will be interpreted as `2025年4月23日(水)` for the weekday check. + +- `currentYear`: number + - Default: the current year (from system date) + - If specified, this value will be used as the year when supplementing missing years in date strings (used only when `useCurrentYearIfMissing` is true). + - This is useful for testing or for documents that should always use a specific year for validation. + +Example (using both options): + +```json +{ + "rules": { + "date-weekday-mismatch": { + "useCurrentYearIfMissing": true, + "currentYear": 2025 + } + } +} +``` + +If the text contains `4月23日(水)`, it will always be interpreted as `2025年4月23日(水)` for the weekday check, regardless of the actual system year. + + language format following ISO 639-1. e.g.) `en-US`, `en`, `ja` etc.. diff --git a/package.json b/package.json index 1bd898f..8237b15 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ }, "homepage": "https://github.com/textlint-rule/textlint-rule-date-weekday-mismatch", "devDependencies": { - "sinon": "^20.0.0", "textlint-scripts": "^12.0.2" }, "keywords": [ diff --git a/src/textlint-rule-date-weekday-mismatch.js b/src/textlint-rule-date-weekday-mismatch.js index 83b5103..0b79fc9 100644 --- a/src/textlint-rule-date-weekday-mismatch.js +++ b/src/textlint-rule-date-weekday-mismatch.js @@ -81,6 +81,7 @@ const addYearToDateText = (dateText, year, lang) => { function reporter(context, config = {}) { const preferLang = config.lang; const useCurrentYearIfMissing = config.useCurrentYearIfMissing; + const currentYearOption = config.currentYear; const {Syntax, RuleError, report, fixer, getSource} = context; if (typeof Intl === "undefined") { throw new Error("Not support your Node.js/browser. should be use latest version."); @@ -92,7 +93,8 @@ function reporter(context, config = {}) { let chronoDates = chrono.parse(text); // Add current year if missing and option is enabled if (useCurrentYearIfMissing) { - const currentYear = (new Date()).getFullYear(); + // Use currentYear option if provided, otherwise use system year + const currentYear = currentYearOption ?? (new Date()).getFullYear(); chronoDates.forEach(chronoDate => { // If year is not specified in the parsed result if ( @@ -104,7 +106,7 @@ function reporter(context, config = {}) { if (!lang) { return; } - // Re-parse the text with the year added + // Re-parse the text with the year added (using currentYear) const newText = addYearToDateText(chronoDate.text, currentYear, lang); const reparsed = chrono.parse(newText, undefined, {forwardDate: true}); // If reparsed successfully, update knownValues with year/month/day diff --git a/test/textlint-rule-date-weekday-mismatch-test.js b/test/textlint-rule-date-weekday-mismatch-test.js index cd330d9..d96bb4e 100644 --- a/test/textlint-rule-date-weekday-mismatch-test.js +++ b/test/textlint-rule-date-weekday-mismatch-test.js @@ -1,19 +1,9 @@ import TextLintTester from "textlint-tester"; -import sinon from "sinon"; const tester = new TextLintTester(); // rule const rule = require("../src/textlint-rule-date-weekday-mismatch"); -// Mock: fix current date to 2025-04-23 to test `useCurrentYearIfMissing` option -let clock; -before(() => { - clock = sinon.useFakeTimers(new Date(2025, 4, 23).getTime()); -}); -after(() => { - clock.restore(); -}); - // ruleName, rule, { valid, invalid } tester.run("rule", rule, { valid: [ @@ -33,12 +23,12 @@ tester.run("rule", rule, { // useCurrentYearIfMissing option: valid { text: "4月23日(水)", - options: { useCurrentYearIfMissing: true, lang: "ja" }, + options: { useCurrentYearIfMissing: true, currentYear: 2025, lang: "ja" }, // 2025年4月23日は水曜日 }, { text: "4/23(Wed)", - options: { useCurrentYearIfMissing: true, lang: "en" }, + options: { useCurrentYearIfMissing: true, currentYear: 2025, lang: "en" }, // 2025-04-23 is Wednesday }, ], @@ -148,7 +138,7 @@ tester.run("rule", rule, { { text: "4月23日(金)", output: "4月23日(水)", - options: { useCurrentYearIfMissing: true, lang: "ja" }, + options: { useCurrentYearIfMissing: true, currentYear: 2025, lang: "ja" }, errors: [ { message: "4月23日(金) mismatch weekday.\n4月23日(金) => 4月23日(水)", @@ -160,7 +150,7 @@ tester.run("rule", rule, { { text: "4/23(Fri)", output: "4/23(Wed)", - options: { useCurrentYearIfMissing: true, lang: "en" }, + options: { useCurrentYearIfMissing: true, currentYear: 2025, lang: "en" }, errors: [ { message: "4/23(Fri) mismatch weekday.\n4/23(Fri) => 4/23(Wed)", diff --git a/yarn.lock b/yarn.lock index c5c8c63..9f01aeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -993,29 +993,6 @@ readdirp "^2.2.1" upath "^1.1.1" -"@sinonjs/commons@^3.0.1": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" - integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^13.0.5": - version "13.0.5" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz#36b9dbc21ad5546486ea9173d6bea063eb1717d5" - integrity sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw== - dependencies: - "@sinonjs/commons" "^3.0.1" - -"@sinonjs/samsam@^8.0.1": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.2.tgz#e4386bf668ff36c95949e55a38dc5f5892fc2689" - integrity sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw== - dependencies: - "@sinonjs/commons" "^3.0.1" - lodash.get "^4.4.2" - type-detect "^4.1.0" - "@textlint/ast-node-types@^12.0.0": version "12.0.0" resolved "https://registry.yarnpkg.com/@textlint/ast-node-types/-/ast-node-types-12.0.0.tgz#23bd683f9fc04209ae28bff72954c8aa67c6b1ca" @@ -1808,11 +1785,6 @@ diff@^4.0.2: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-7.0.0.tgz#3fb34d387cd76d803f6eebea67b921dab0182a9a" - integrity sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw== - ejs@^2.4.1: version "2.7.1" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" @@ -2593,11 +2565,6 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== - lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -3647,17 +3614,6 @@ signal-exit@^3.0.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= -sinon@^20.0.0: - version "20.0.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-20.0.0.tgz#4b653468735f7152ba694d05498c2b5d024ab006" - integrity sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ== - dependencies: - "@sinonjs/commons" "^3.0.1" - "@sinonjs/fake-timers" "^13.0.5" - "@sinonjs/samsam" "^8.0.1" - diff "^7.0.0" - supports-color "^7.2.0" - slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -3886,7 +3842,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0, supports-color@^7.2.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -4034,16 +3990,6 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" From 4ed6d4fc93c42cc6f523f6496d5eed7d60ac75b8 Mon Sep 17 00:00:00 2001 From: watackeech Date: Thu, 24 Apr 2025 10:01:38 +0900 Subject: [PATCH 5/5] refactor: avoid using `let` --- src/textlint-rule-date-weekday-mismatch.js | 70 ++++++++++++++-------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/textlint-rule-date-weekday-mismatch.js b/src/textlint-rule-date-weekday-mismatch.js index 0b79fc9..314f0d7 100644 --- a/src/textlint-rule-date-weekday-mismatch.js +++ b/src/textlint-rule-date-weekday-mismatch.js @@ -73,6 +73,43 @@ const addYearToDateText = (dateText, year, lang) => { // Default: prepend year and a space return `${year} ${dateText}`; } +/** + * Create chronoDates array, optionally supplementing year if needed. + * @param {string} text + * @param {Object} options + * @param {string} options.preferLang + * @param {boolean} options.useCurrentYearIfMissing + * @param {number} options.currentYear + * @returns {Array} + */ +function createChronoDates(text, options) { + const { preferLang, useCurrentYearIfMissing, currentYear } = options; + const chronoDates = chrono.parse(text); + if (!useCurrentYearIfMissing) { + return chronoDates; + } + chronoDates.forEach(chronoDate => { + // If year is not specified in the parsed result + if ( + chronoDate.start && + chronoDate.start.knownValues.year === undefined + ) { + // Detect language for the date string + const lang = detectLang(Object.keys(chronoDate.tags), preferLang); + if (!lang) { + return; + } + // Re-parse the text with the year added (using currentYear) + const newText = addYearToDateText(chronoDate.text, currentYear, lang); + const reparsed = chrono.parse(newText, undefined, {forwardDate: true}); + // If reparsed successfully, update knownValues with year/month/day + if (reparsed && reparsed[0] && reparsed[0].start && reparsed[0].start.knownValues) { + Object.assign(chronoDate.start.knownValues, reparsed[0].start.knownValues); + } + } + }); + return chronoDates; +} /** * * @param context @@ -90,32 +127,13 @@ function reporter(context, config = {}) { return { [Syntax.Str](node){ const text = getSource(node); - let chronoDates = chrono.parse(text); - // Add current year if missing and option is enabled - if (useCurrentYearIfMissing) { - // Use currentYear option if provided, otherwise use system year - const currentYear = currentYearOption ?? (new Date()).getFullYear(); - chronoDates.forEach(chronoDate => { - // If year is not specified in the parsed result - if ( - chronoDate.start && - chronoDate.start.knownValues.year === undefined - ) { - // Detect language for the date string - const lang = detectLang(Object.keys(chronoDate.tags), preferLang); - if (!lang) { - return; - } - // Re-parse the text with the year added (using currentYear) - const newText = addYearToDateText(chronoDate.text, currentYear, lang); - const reparsed = chrono.parse(newText, undefined, {forwardDate: true}); - // If reparsed successfully, update knownValues with year/month/day - if (reparsed && reparsed[0] && reparsed[0].start && reparsed[0].start.knownValues) { - Object.assign(chronoDate.start.knownValues, reparsed[0].start.knownValues); - } - } - }); - } + // Use helper function to create chronoDates + const currentYear = currentYearOption ?? (new Date()).getFullYear(); + const chronoDates = createChronoDates(text, { + preferLang, + useCurrentYearIfMissing, + currentYear + }); // ignore "今日" text // ignore not valid data const filteredChronoDates = chronoDates.filter(textIncludesNumber).filter(yearMonthDayShouldKnownValues);