@northguild/gmt-oxlint 1.1.5 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/config/recommended.json +2 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.js +65 -2
- package/package.json +3 -4
package/README.md
CHANGED
|
@@ -59,6 +59,7 @@ export default defineConfig({
|
|
|
59
59
|
"gmt/no-date-parse": "error",
|
|
60
60
|
"gmt/no-date-utc": "error",
|
|
61
61
|
"gmt/no-date-getTimezoneOffset": "error",
|
|
62
|
+
"gmt/no-date-library-imports": "error",
|
|
62
63
|
},
|
|
63
64
|
});
|
|
64
65
|
```
|
|
@@ -92,7 +93,8 @@ Or explicitly configure each rule. You can use either a string or an array form:
|
|
|
92
93
|
"@northguild/gmt-oxlint/no-date-now": "error",
|
|
93
94
|
"@northguild/gmt-oxlint/no-date-parse": "error",
|
|
94
95
|
"@northguild/gmt-oxlint/no-date-utc": "error",
|
|
95
|
-
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error"
|
|
96
|
+
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error",
|
|
97
|
+
"@northguild/gmt-oxlint/no-date-library-imports": "error"
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
```
|
|
@@ -109,7 +111,8 @@ Array form also supported:
|
|
|
109
111
|
"@northguild/gmt-oxlint/no-date-now": ["error"],
|
|
110
112
|
"@northguild/gmt-oxlint/no-date-parse": ["error"],
|
|
111
113
|
"@northguild/gmt-oxlint/no-date-utc": ["error"],
|
|
112
|
-
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": ["error"]
|
|
114
|
+
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": ["error"],
|
|
115
|
+
"@northguild/gmt-oxlint/no-date-library-imports": ["error"]
|
|
113
116
|
}
|
|
114
117
|
}
|
|
115
118
|
```
|
|
@@ -125,6 +128,10 @@ Array form also supported:
|
|
|
125
128
|
| `Date.UTC(...)` | `no-date-utc` | Use `convertUtcDateTimeToUnix('YYYY-MM-DDTHH:mm:ss', 'milliseconds' or 'seconds')` |
|
|
126
129
|
| `date.getTimezoneOffset()` | `no-date-getTimezoneOffset` | Use `getZonedNow(timezone)`, other gmt zoned helpers such as `convertZonedToUnix(value)`, or `Temporal.ZonedDateTime` |
|
|
127
130
|
|
|
131
|
+
> **`@js-joda/core` is deliberately allowed.** It has its own value types and touches
|
|
132
|
+
> `Date` only at the boundary (reading the clock, host zone lookup, `toDate()` interop),
|
|
133
|
+
> so it does not carry the ambient-timezone and DST problems this ban targets.
|
|
134
|
+
|
|
128
135
|
## Why Temporal?
|
|
129
136
|
|
|
130
137
|
[Temporal](https://tc39.es/proposal-temporal/) solves fundamental issues with JavaScript's `Date` object:
|
package/config/recommended.json
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"@northguild/gmt-oxlint/no-date-now": "error",
|
|
6
6
|
"@northguild/gmt-oxlint/no-date-parse": "error",
|
|
7
7
|
"@northguild/gmt-oxlint/no-date-utc": "error",
|
|
8
|
-
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error"
|
|
8
|
+
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error",
|
|
9
|
+
"@northguild/gmt-oxlint/no-date-library-imports": "error"
|
|
9
10
|
}
|
|
10
11
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,25 @@ type IdentifierNode = Node & {
|
|
|
10
10
|
type CallExpressionNode = Node & {
|
|
11
11
|
type: "CallExpression";
|
|
12
12
|
callee: Node;
|
|
13
|
+
arguments?: Node[];
|
|
14
|
+
};
|
|
15
|
+
type LiteralNode = Node & {
|
|
16
|
+
type: "Literal";
|
|
17
|
+
value?: unknown;
|
|
18
|
+
};
|
|
19
|
+
type ImportDeclarationNode = Node & {
|
|
20
|
+
type: "ImportDeclaration";
|
|
21
|
+
source: LiteralNode;
|
|
22
|
+
};
|
|
23
|
+
/** `import("date-fns")` — the specifier can be any expression, not just a literal. */
|
|
24
|
+
type ImportExpressionNode = Node & {
|
|
25
|
+
type: "ImportExpression";
|
|
26
|
+
source: Node;
|
|
27
|
+
};
|
|
28
|
+
/** `source` is null for `export { x }` with no `from` clause. */
|
|
29
|
+
type ExportFromNode = Node & {
|
|
30
|
+
type: "ExportNamedDeclaration" | "ExportAllDeclaration";
|
|
31
|
+
source?: LiteralNode | null;
|
|
13
32
|
};
|
|
14
33
|
type NewExpressionNode = Node & {
|
|
15
34
|
type: "NewExpression";
|
|
@@ -38,6 +57,10 @@ type RuleListener = {
|
|
|
38
57
|
Program?: (node: ProgramNode) => void;
|
|
39
58
|
NewExpression?: (node: NewExpressionNode) => void;
|
|
40
59
|
CallExpression?: (node: CallExpressionNode) => void;
|
|
60
|
+
ImportDeclaration?: (node: ImportDeclarationNode) => void;
|
|
61
|
+
ImportExpression?: (node: ImportExpressionNode) => void;
|
|
62
|
+
ExportNamedDeclaration?: (node: ExportFromNode) => void;
|
|
63
|
+
ExportAllDeclaration?: (node: ExportFromNode) => void;
|
|
41
64
|
};
|
|
42
65
|
type RuleModule = {
|
|
43
66
|
meta: {
|
|
@@ -68,6 +91,7 @@ declare const recommendedRules: {
|
|
|
68
91
|
readonly "@northguild/gmt-oxlint/no-date-parse": "error";
|
|
69
92
|
readonly "@northguild/gmt-oxlint/no-date-utc": "error";
|
|
70
93
|
readonly "@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error";
|
|
94
|
+
readonly "@northguild/gmt-oxlint/no-date-library-imports": "error";
|
|
71
95
|
};
|
|
72
96
|
declare const recommendedConfig: {
|
|
73
97
|
readonly jsPlugins: readonly ["@northguild/gmt-oxlint"];
|
|
@@ -78,6 +102,7 @@ declare const recommendedConfig: {
|
|
|
78
102
|
readonly "@northguild/gmt-oxlint/no-date-parse": "error";
|
|
79
103
|
readonly "@northguild/gmt-oxlint/no-date-utc": "error";
|
|
80
104
|
readonly "@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error";
|
|
105
|
+
readonly "@northguild/gmt-oxlint/no-date-library-imports": "error";
|
|
81
106
|
};
|
|
82
107
|
};
|
|
83
108
|
declare const plugin: OxlintPlugin;
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ var MSG_DATE_NOW = "Avoid Date.now(). Use @northguild/gmt getUnixNow('millisecon
|
|
|
5
5
|
var MSG_DATE_UTC = "Avoid Date.UTC(). Use @northguild/gmt convertUtcDateTimeToUnix('YYYY-MM-DDTHH:mm:ss', 'milliseconds' | 'seconds') instead.";
|
|
6
6
|
var MSG_DATE_PARSE = "Avoid Date.parse(). Use @northguild/gmt convertZonedToUnix(value) instead.";
|
|
7
7
|
var MSG_GET_TIMEZONE_OFFSET = "Avoid date.getTimezoneOffset(). Timezone offsets change throughout the year, so use @northguild/gmt zoned methods instead.";
|
|
8
|
+
var MSG_DATE_LIBRARY_IMPORT = "Avoid date libraries that wrap native Date (moment, dayjs, luxon, date-fns, spacetime). Use @northguild/gmt instead.";
|
|
8
9
|
|
|
9
10
|
// src/utils/isChainExpression.ts
|
|
10
11
|
function isChainExpression(node) {
|
|
@@ -44,6 +45,25 @@ function hasDateStaticMemberCall(node, memberName) {
|
|
|
44
45
|
return isIdentifier(callee.object, "Date") && isIdentifier(callee.property, memberName);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
// src/utils/isBannedDateLibrary.ts
|
|
49
|
+
var BANNED_DATE_LIBRARIES = [
|
|
50
|
+
"moment",
|
|
51
|
+
"moment-timezone",
|
|
52
|
+
"dayjs",
|
|
53
|
+
"luxon",
|
|
54
|
+
"date-fns",
|
|
55
|
+
"date-fns-tz",
|
|
56
|
+
"spacetime"
|
|
57
|
+
];
|
|
58
|
+
var isBannedDateLibrary = (specifier) => {
|
|
59
|
+
if (typeof specifier !== "string") {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return BANNED_DATE_LIBRARIES.some(
|
|
63
|
+
(lib) => specifier === lib || specifier.startsWith(`${lib}/`)
|
|
64
|
+
);
|
|
65
|
+
};
|
|
66
|
+
|
|
47
67
|
// src/rules/no-date-getTimezoneOffset.ts
|
|
48
68
|
var noDateGetTimezoneOffsetRule = {
|
|
49
69
|
meta: {
|
|
@@ -104,6 +124,47 @@ var noDateGlobalRule = {
|
|
|
104
124
|
}
|
|
105
125
|
};
|
|
106
126
|
|
|
127
|
+
// src/rules/no-date-library-imports.ts
|
|
128
|
+
var reportIfBanned = (context, source) => {
|
|
129
|
+
if (!source || !isBannedDateLibrary(source.value)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
context.report({ node: source, message: MSG_DATE_LIBRARY_IMPORT });
|
|
133
|
+
};
|
|
134
|
+
var noDateLibraryImportsRule = {
|
|
135
|
+
meta: {
|
|
136
|
+
type: "problem",
|
|
137
|
+
docs: {
|
|
138
|
+
description: "Disallow importing date libraries that wrap native Date objects."
|
|
139
|
+
},
|
|
140
|
+
schema: []
|
|
141
|
+
},
|
|
142
|
+
create(context) {
|
|
143
|
+
return {
|
|
144
|
+
ImportDeclaration(node) {
|
|
145
|
+
reportIfBanned(context, node.source);
|
|
146
|
+
},
|
|
147
|
+
// `export { format } from "date-fns"` re-exports the banned API just as
|
|
148
|
+
// effectively as importing it. `source` is null for a local re-export.
|
|
149
|
+
ExportNamedDeclaration(node) {
|
|
150
|
+
reportIfBanned(context, node.source);
|
|
151
|
+
},
|
|
152
|
+
ExportAllDeclaration(node) {
|
|
153
|
+
reportIfBanned(context, node.source);
|
|
154
|
+
},
|
|
155
|
+
ImportExpression(node) {
|
|
156
|
+
reportIfBanned(context, node.source);
|
|
157
|
+
},
|
|
158
|
+
CallExpression(node) {
|
|
159
|
+
if (!isIdentifier(node.callee, "require")) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
reportIfBanned(context, node.arguments?.[0]);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
|
|
107
168
|
// src/rules/no-date-now.ts
|
|
108
169
|
var noDateNowRule = {
|
|
109
170
|
meta: {
|
|
@@ -187,7 +248,8 @@ var recommendedRules = {
|
|
|
187
248
|
"@northguild/gmt-oxlint/no-date-now": "error",
|
|
188
249
|
"@northguild/gmt-oxlint/no-date-parse": "error",
|
|
189
250
|
"@northguild/gmt-oxlint/no-date-utc": "error",
|
|
190
|
-
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error"
|
|
251
|
+
"@northguild/gmt-oxlint/no-date-getTimezoneOffset": "error",
|
|
252
|
+
"@northguild/gmt-oxlint/no-date-library-imports": "error"
|
|
191
253
|
};
|
|
192
254
|
var recommendedConfig = {
|
|
193
255
|
jsPlugins: ["@northguild/gmt-oxlint"],
|
|
@@ -201,7 +263,8 @@ var plugin = {
|
|
|
201
263
|
"no-date-now": noDateNowRule,
|
|
202
264
|
"no-date-parse": noDateParseRule,
|
|
203
265
|
"no-date-utc": noDateUtcRule,
|
|
204
|
-
"no-date-getTimezoneOffset": noDateGetTimezoneOffsetRule
|
|
266
|
+
"no-date-getTimezoneOffset": noDateGetTimezoneOffsetRule,
|
|
267
|
+
"no-date-library-imports": noDateLibraryImportsRule
|
|
205
268
|
},
|
|
206
269
|
configs: { recommended: { rules: recommendedRules } }
|
|
207
270
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@northguild/gmt-oxlint",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Oxlint JS plugin for banning Date APIs in Temporal-first projects",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"date",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"registry": "https://registry.npmjs.org/"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@tanstack/intent": "^0.3.
|
|
58
|
+
"@tanstack/intent": "^0.3.8",
|
|
59
59
|
"oxlint": "^1.0.0",
|
|
60
60
|
"tsup": "^8.5.0",
|
|
61
61
|
"typescript": "^5.0.0"
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"test:watch": "vitest --config vitest.config.ts",
|
|
71
71
|
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
72
72
|
"pack": "npm pack --dry-run",
|
|
73
|
-
"publish:dry-run": "npm publish --access public --dry-run"
|
|
74
|
-
"publish:public": "npm publish --access public"
|
|
73
|
+
"publish:dry-run": "npm publish --access public --dry-run"
|
|
75
74
|
}
|
|
76
75
|
}
|