temporal-fmt 0.9.32 → 0.9.41
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/LICENSE +196 -17
- package/README.md +287 -3
- package/dist/calendarUtils.cjs.map +1 -1
- package/dist/calendarUtils.js +2 -2
- package/dist/{chunk-GPB4JHGI.js → chunk-5553YBSV.js} +4 -4
- package/dist/chunk-5553YBSV.js.map +1 -0
- package/dist/{chunk-L24NPTAJ.js → chunk-AX3YNHKK.js} +4 -4
- package/dist/chunk-AX3YNHKK.js.map +1 -0
- package/dist/{chunk-ACKKWH5Z.js → chunk-C3QMVR5T.js} +4 -4
- package/dist/chunk-C3QMVR5T.js.map +1 -0
- package/dist/{chunk-UOPAV3WX.js → chunk-CGI4FL6H.js} +2 -2
- package/dist/chunk-CGI4FL6H.js.map +1 -0
- package/dist/chunk-DDE7YTGV.js +2939 -0
- package/dist/chunk-DDE7YTGV.js.map +1 -0
- package/dist/{chunk-ZQZF5EXW.js → chunk-DFWTCRS3.js} +1 -1
- package/dist/chunk-DFWTCRS3.js.map +1 -0
- package/dist/{chunk-DR62Z6GV.js → chunk-HJCPNB7J.js} +178 -4
- package/dist/chunk-HJCPNB7J.js.map +1 -0
- package/dist/{chunk-4N3WCGEY.js → chunk-JI3B7C5L.js} +5 -5
- package/dist/chunk-JI3B7C5L.js.map +1 -0
- package/dist/{chunk-MKPDLQKD.js → chunk-LOJO7SGQ.js} +1 -1
- package/dist/chunk-LOJO7SGQ.js.map +1 -0
- package/dist/{chunk-5UTV5VP6.js → chunk-M6D57BHI.js} +6 -6
- package/dist/chunk-M6D57BHI.js.map +1 -0
- package/dist/{chunk-EGUUO6LE.js → chunk-OLNU4LON.js} +1 -1
- package/dist/chunk-OLNU4LON.js.map +1 -0
- package/dist/{chunk-YEUASGDK.js → chunk-SOPTTXUI.js} +1 -1
- package/dist/chunk-SOPTTXUI.js.map +1 -0
- package/dist/{chunk-M3GDTHMT.js → chunk-UF3RVLVL.js} +3 -3
- package/dist/chunk-UF3RVLVL.js.map +1 -0
- package/dist/{chunk-H7YQX25T.js → chunk-YXN5RAQ3.js} +3 -3
- package/dist/chunk-YXN5RAQ3.js.map +1 -0
- package/dist/{chunk-TSLPIURC.js → chunk-Z33O2X7I.js} +2 -2
- package/dist/chunk-Z33O2X7I.js.map +1 -0
- package/dist/{chunk-HXY2GUUM.js → chunk-ZSHHTAKC.js} +2 -2
- package/dist/chunk-ZSHHTAKC.js.map +1 -0
- package/dist/config.d.cts +4 -2
- package/dist/config.d.ts +4 -2
- package/dist/duration.cjs.map +1 -1
- package/dist/duration.js +5 -5
- package/dist/format.cjs.map +1 -1
- package/dist/format.js +7 -7
- package/dist/index.cjs +2744 -1951
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -24
- package/dist/index.d.ts +108 -24
- package/dist/index.js +710 -2265
- package/dist/index.js.map +1 -1
- package/dist/interval.cjs +4569 -104
- package/dist/interval.cjs.map +1 -1
- package/dist/interval.js +15 -10
- package/dist/localeRegistry.cjs.map +1 -1
- package/dist/localeRegistry.js +2 -2
- package/dist/modApi.d.cts +131 -0
- package/dist/modApi.d.ts +131 -0
- package/dist/parse.cjs.map +1 -1
- package/dist/parse.js +7 -7
- package/dist/recurrence.cjs.map +1 -1
- package/dist/recurrence.js +4 -5
- package/dist/relativeTime.cjs.map +1 -1
- package/dist/relativeTime.js +7 -7
- package/dist/runtime.d.cts +201 -0
- package/dist/runtime.d.ts +201 -0
- package/dist/timezone.cjs.map +1 -1
- package/dist/timezone.js +5 -5
- package/package.json +3 -3
- package/scripts/cli.mjs +10 -0
- package/dist/chunk-4N3WCGEY.js.map +0 -1
- package/dist/chunk-5UTV5VP6.js.map +0 -1
- package/dist/chunk-ACKKWH5Z.js.map +0 -1
- package/dist/chunk-DR62Z6GV.js.map +0 -1
- package/dist/chunk-EGUUO6LE.js.map +0 -1
- package/dist/chunk-GPB4JHGI.js.map +0 -1
- package/dist/chunk-H7YQX25T.js.map +0 -1
- package/dist/chunk-HXY2GUUM.js.map +0 -1
- package/dist/chunk-L24NPTAJ.js.map +0 -1
- package/dist/chunk-M3GDTHMT.js.map +0 -1
- package/dist/chunk-MKPDLQKD.js.map +0 -1
- package/dist/chunk-P3G4JRYC.js +0 -205
- package/dist/chunk-P3G4JRYC.js.map +0 -1
- package/dist/chunk-RIZ3HN37.js +0 -181
- package/dist/chunk-RIZ3HN37.js.map +0 -1
- package/dist/chunk-TSLPIURC.js.map +0 -1
- package/dist/chunk-UOPAV3WX.js.map +0 -1
- package/dist/chunk-YEUASGDK.js.map +0 -1
- package/dist/chunk-ZQZF5EXW.js.map +0 -1
package/LICENSE
CHANGED
|
@@ -1,22 +1,201 @@
|
|
|
1
|
-
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
7
|
+
1. Definitions.
|
|
11
8
|
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
14
11
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
22
14
|
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# temporal-fmt 🥶🔥
|
|
2
2
|
|
|
3
3
|
-brightgreen?style=flat-square)
|
|
4
|
-
[](https://bundlephobia.com/package/temporal-fmt)
|
|
5
|
-
[](https://bundlephobia.com/package/temporal-fmt)
|
|
6
4
|
|
|
7
5
|
Format and parse `Temporal` values (`PlainDate`, `PlainTime`, `PlainDateTime`,
|
|
8
6
|
`ZonedDateTime`) using date-fns-style tokens, with real validation — bad input
|
|
@@ -72,6 +70,7 @@ The package looks large on npm — locales, recurrence, business calendars, time
|
|
|
72
70
|
- [Extending with custom tokens](#extending-with-custom-tokens)
|
|
73
71
|
- [IDE tooling data](#ide-tooling-data)
|
|
74
72
|
- [CLI](#cli)
|
|
73
|
+
- [Mods](#mods)
|
|
75
74
|
- [Subpath imports](#subpath-imports)
|
|
76
75
|
- [Migrating from Day.js or date-fns](#migrating-from-dayjs-or-date-fns)
|
|
77
76
|
- [Known limitations](#known-limitations)
|
|
@@ -896,6 +895,291 @@ temporal-fmt> exit
|
|
|
896
895
|
|
|
897
896
|
Type a subcommand with all its arguments inline (`validate yyyy-MM-dd`) or just the subcommand name — the REPL prompts for whatever's missing, one field at a time. Errors print and the session keeps going; `exit`, `quit`, or Ctrl+D ends it. This is the same subcommand logic as one-shot mode, just wrapped in a loop that asks instead of exiting on a missing argument — one-shot stays there for scripting, and doesn't touch the REPL machinery.
|
|
898
897
|
|
|
898
|
+
## Mods (advanced, optional)
|
|
899
|
+
|
|
900
|
+
Most people don't need this. It's a feature I added just in case you want to fix or tweak something in the library without forking the whole thing — not something you're expected to reach for day to day. If you never touch `mods/`, nothing about normal usage changes for you.
|
|
901
|
+
|
|
902
|
+
The mod-related scripts (`loadMods.mjs`, `modConfig.mjs`, `semverRange.mjs`) live in this repo's `scripts/` folder, but they're not part of what actually ships in the npm package — the published package only includes `cli.mjs` from that folder. So if you installed this from npm, those files simply aren't on disk in your `node_modules`; they're repo-only. See [Using mods outside the CLI](#using-mods-outside-the-cli) if you want to copy the loader out of this repo and use it yourself.
|
|
903
|
+
|
|
904
|
+
`registerLocale`, `createHolidayCalendar`, and `createFormatter` are already how you extend this library without forking it — [Locales](#locales), [Business calendars and holidays](#business-calendars-and-holidays), and [Extending with custom tokens](#extending-with-custom-tokens) all cover them. Mods are just a delivery mechanism on top of those same functions: drop a file in a `mods/` folder, the CLI picks it up on startup and runs it. No publishing to npm, no build step in this repo, no manifest to register anywhere. If you've used a Minecraft mods folder, it's the same idea — a file the host looks for and loads, not a package the host depends on.
|
|
905
|
+
|
|
906
|
+
This exists so bugfixes and locale corrections don't have to wait on a PR merging and a release going out. If en-GB's holiday list is wrong for your team, a locale you need isn't covered yet, or you want to shave overhead off a hot path, write a mod and drop it in. It's not the right tool for genuinely new capability — if you're building something the override surface can't express, that's a sign to open an issue or PR the feature into the library itself, not to keep stretching a mod to cover it. Whether a given fix ever gets upstreamed into this repo is a separate question from whether it works today as a mod.
|
|
907
|
+
|
|
908
|
+
### Writing a mod
|
|
909
|
+
|
|
910
|
+
A mod is a `.mjs` file that default-exports an object with a `name` and a `register(ctx, config)` function. `ctx` is the same registration API `index.ts` exports for everyone else — `registerLocale`, `registerLocaleVocab`, `registerRelativeGrammar`, `createFormatter`, `createHolidayCalendar` — nothing beyond that. A mod that needs more than those five functions expose is asking for something this library doesn't support yet, not something to route around by reaching into internals that could shift under it without warning. `config` is `{}` for a loose `.mjs` mod — there's no manifest to declare settings in, so there's nothing to resolve; see [Mod settings and `config/`](#mod-settings-and-config) for mods that need user-adjustable settings, which means packaging as `.tfmod`.
|
|
911
|
+
|
|
912
|
+
```js
|
|
913
|
+
// mods/en-gb-bank-holidays.mjs
|
|
914
|
+
export default {
|
|
915
|
+
name: 'en-gb-bank-holidays',
|
|
916
|
+
version: '1.0.0',
|
|
917
|
+
register(ctx) {
|
|
918
|
+
ctx.createHolidayCalendar([
|
|
919
|
+
{ month: 1, day: 1, name: "New Year's Day" },
|
|
920
|
+
{ month: 12, day: 25, name: 'Christmas Day' },
|
|
921
|
+
{ month: 12, day: 26, name: 'Boxing Day' },
|
|
922
|
+
]);
|
|
923
|
+
},
|
|
924
|
+
};
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Put that in `mods/` at your project root (the folder the CLI is run from, not inside this package's own checkout) and run any CLI command — the loader reports what it found on stderr:
|
|
928
|
+
|
|
929
|
+
```
|
|
930
|
+
$ temporal-fmt validate "yyyy-MM-dd"
|
|
931
|
+
temporal-fmt mods:
|
|
932
|
+
loaded en-gb-bank-holidays@1.0.0 (en-gb-bank-holidays.mjs)
|
|
933
|
+
valid
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
`version` is optional and only shows up in that report — it's for your own tracking, not something the loader checks. That's a different field from `temporalFmtVersion`, which *is* checked against the installed `temporal-fmt` version, but only exists on `.tfmod` manifests (see [Pinning a mod to a `temporal-fmt` version](#pinning-a-mod-to-a-temporal-fmt-version)) — a loose `.mjs` mod has no manifest to declare it in.
|
|
937
|
+
|
|
938
|
+
### Packaging a mod as `.tfmod`
|
|
939
|
+
|
|
940
|
+
A loose `.mjs` file covers the common case, but it's one file — no bundled data, and the loader has to `import()` it just to find out its `name` before deciding load order. For anything bigger than that, package the mod as a `.tfmod` archive instead: a gzipped tar (same format as `.tgz`, renamed for identity) containing a manifest the loader can read without running any code, plus the mod's actual implementation:
|
|
941
|
+
|
|
942
|
+
```
|
|
943
|
+
en-gb-bank-holidays.tfmod
|
|
944
|
+
├── mod.json — name, version, main, requires, priority, temporalFmtVersion, config
|
|
945
|
+
├── main.mjs — the mod's entry point (same shape as a loose .mjs mod's default export, minus `name`/`version`/`requires`/`priority` — mod.json owns those)
|
|
946
|
+
└── data/ — optional: JSON files, locale tables, anything main.mjs wants to read at register() time
|
|
947
|
+
```
|
|
948
|
+
|
|
949
|
+
```json
|
|
950
|
+
// mod.json
|
|
951
|
+
{
|
|
952
|
+
"name": "en-gb-bank-holidays",
|
|
953
|
+
"version": "1.0.0",
|
|
954
|
+
"main": "main.mjs",
|
|
955
|
+
"requires": ["some-other-mod"],
|
|
956
|
+
"priority": 0,
|
|
957
|
+
"temporalFmtVersion": "^0.9.0"
|
|
958
|
+
}
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
```js
|
|
962
|
+
// main.mjs
|
|
963
|
+
export default {
|
|
964
|
+
register(ctx) {
|
|
965
|
+
ctx.createHolidayCalendar([
|
|
966
|
+
{ month: 1, day: 1, name: "New Year's Day" },
|
|
967
|
+
{ month: 12, day: 25, name: 'Christmas Day' },
|
|
968
|
+
]);
|
|
969
|
+
},
|
|
970
|
+
};
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
Build the archive with plain `tar` — no special tooling:
|
|
974
|
+
|
|
975
|
+
```sh
|
|
976
|
+
tar -czf en-gb-bank-holidays.tfmod mod.json main.mjs data/
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
Drop that in `mods/` alongside any loose `.mjs` mods you have; the loader treats both formats as one pool for load-order and conflict purposes. The report shows `mod.json`'s `name`, not anything from `main.mjs` itself:
|
|
980
|
+
|
|
981
|
+
```
|
|
982
|
+
$ temporal-fmt validate "yyyy-MM-dd"
|
|
983
|
+
temporal-fmt mods:
|
|
984
|
+
loaded en-gb-bank-holidays@1.0.0 (en-gb-bank-holidays.tfmod)
|
|
985
|
+
valid
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
Why bother with an archive format at all instead of just supporting multi-file `.mjs` mods directly: `mod.json` is metadata the loader can read with zero code execution, which is what makes cross-mod dependency resolution work honestly — with a loose `.mjs` mod, the loader has no choice but to `import()` the file to learn its `name`/`requires`, before it even knows whether that mod should run. A `.tfmod`'s manifest is checked, and the whole dependency graph is resolved, before `main.mjs` is ever imported. At the current few-mods-loaded-once-at-CLI-startup scale that distinction mostly doesn't matter — but it's the honest reason the format exists rather than "loose files but with a folder," and it's what a "list what's installed without running any of it" feature would build on if that ever comes up.
|
|
989
|
+
|
|
990
|
+
Failure modes are per-archive, same as loose mods — one bad `.tfmod` doesn't block anything else in `mods/`:
|
|
991
|
+
|
|
992
|
+
- `mod.json` missing or malformed (no `name`, no `main`, or `requires`/`priority`/`temporalFmtVersion`/`config` the wrong type) — reported with what was expected, `main.mjs` is never imported.
|
|
993
|
+
- `mod.json` names a `main` file that isn't actually in the archive — reported with the missing filename.
|
|
994
|
+
- The archive isn't a valid gzip/tar (corrupted, wrong format, a `.tfmod` extension slapped on some other file) — reported with the extraction error.
|
|
995
|
+
- `main.mjs`'s default export doesn't have a `register` function — reported, same as a loose mod's malformed export.
|
|
996
|
+
- `temporalFmtVersion` doesn't match the installed `temporal-fmt` version — reported with the range and the actual version, `main.mjs` is never imported. See [Pinning a mod to a `temporal-fmt` version](#pinning-a-mod-to-a-temporal-fmt-version).
|
|
997
|
+
|
|
998
|
+
Extraction happens to a temporary directory that's cleaned up after the load pass — nothing from a `.tfmod` sticks around on disk after the CLI command finishes. Extraction shells out to the system `tar` binary rather than adding a tar/gzip-parsing dependency, consistent with this package staying dependency-free (see [Providing `Temporal`](#providing-temporal) for the same call made about the polyfill) — if `tar` isn't on the system `PATH`, the archive fails to load with that reason rather than crashing the CLI.
|
|
999
|
+
|
|
1000
|
+
### Pinning a mod to a `temporal-fmt` version
|
|
1001
|
+
|
|
1002
|
+
`mod.json` can declare `temporalFmtVersion`, either an exact version (`"0.9.32"`) or a caret range (`"^0.9.0"`, meaning ">=0.9.0, <0.10.0" — same meaning npm gives `^` in `package.json`). If the installed `temporal-fmt` doesn't satisfy it, the mod fails to load with the range and the actual version, before `main.mjs` is ever imported:
|
|
1003
|
+
|
|
1004
|
+
```
|
|
1005
|
+
failed holidays.tfmod: "en-gb-bank-holidays" needs temporal-fmt ^2.0.0 (>=2.0.0 <3.0.0), host is 0.9.32
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
This exists because nothing else catches the alternative: a mod built against one version's override surface (which functions are zero-fanout and therefore overridable — see [Overriding functions](#overriding-functions)) has no way to know if a future release moved a function it depends on, and would otherwise fail with whatever confusing error `register()` happens to throw, or — worse — silently do nothing if the call it expected to matter just no longer has any effect. A declared range turns that into one clear, pre-`register()` failure instead.
|
|
1009
|
+
|
|
1010
|
+
Omitting `temporalFmtVersion` is allowed — the mod loads against whatever version is installed, same as before this field existed. Loose `.mjs` mods have no manifest to put this in at all, so they can't declare a version requirement; that's one real reason to prefer `.tfmod` for anything you plan to distribute rather than just run yourself.
|
|
1011
|
+
|
|
1012
|
+
There's no dependency-resolution logic here, unlike `requires`/`priority` — this is a single boolean check (does the host version satisfy the range), not something that affects load order.
|
|
1013
|
+
|
|
1014
|
+
### Mod settings and `config/`
|
|
1015
|
+
|
|
1016
|
+
A mod can declare user-adjustable settings in `mod.json`'s `config` array, and `register()` receives the resolved values as its second argument:
|
|
1017
|
+
|
|
1018
|
+
```json
|
|
1019
|
+
// mod.json
|
|
1020
|
+
{
|
|
1021
|
+
"name": "en-gb-bank-holidays",
|
|
1022
|
+
"main": "main.mjs",
|
|
1023
|
+
"config": [
|
|
1024
|
+
{ "key": "includeScottish", "type": "boolean", "default": false },
|
|
1025
|
+
{ "key": "observedRule", "type": "enum", "default": "nearest-weekday", "choices": ["nearest-weekday", "strict-date"] },
|
|
1026
|
+
{ "key": "yearsAhead", "type": "number", "default": 5, "min": 1, "max": 20 }
|
|
1027
|
+
]
|
|
1028
|
+
}
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
```js
|
|
1032
|
+
// main.mjs
|
|
1033
|
+
export default {
|
|
1034
|
+
register(ctx, config) {
|
|
1035
|
+
const years = config.yearsAhead; // 5, unless overridden below
|
|
1036
|
+
ctx.createHolidayCalendar(buildHolidays({ scottish: config.includeScottish, years }));
|
|
1037
|
+
},
|
|
1038
|
+
};
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1041
|
+
Four setting types are supported: `string`, `number` (with optional `min`/`max`), `boolean`, and `enum` (a string constrained to `choices`). Every entry needs a `key` and a `default` — the default is what `register()` gets if the user hasn't overridden that setting, which also means a mod with no `config/<name>.json` file on disk at all still runs normally, just entirely on defaults.
|
|
1042
|
+
|
|
1043
|
+
To override a setting, drop a JSON file at `config/<mod-name>.json` — **next to `mods/`, not inside it** (so re-downloading or updating the `.tfmod` never touches a user's settings, the same reason Forge keeps `config/` and `mods/` as siblings rather than bundling settings into the jar):
|
|
1044
|
+
|
|
1045
|
+
```
|
|
1046
|
+
your-project/
|
|
1047
|
+
├── mods/
|
|
1048
|
+
│ └── en-gb-bank-holidays.tfmod
|
|
1049
|
+
└── config/
|
|
1050
|
+
└── en-gb-bank-holidays.json — { "includeScottish": true, "yearsAhead": 10 }
|
|
1051
|
+
```
|
|
1052
|
+
|
|
1053
|
+
Only keys the schema actually declares can be set — anything else is a mistake worth surfacing, not a silent no-op:
|
|
1054
|
+
|
|
1055
|
+
```
|
|
1056
|
+
temporal-fmt mods:
|
|
1057
|
+
loaded en-gb-bank-holidays@1.0.0 (en-gb-bank-holidays.tfmod)
|
|
1058
|
+
failed config/en-gb-bank-holidays.json: en-gb-bank-holidays: config key "yearsAhead" must be <= 20, got 50 (using default)
|
|
1059
|
+
failed config/en-gb-bank-holidays.json: en-gb-bank-holidays: unknown config key "includeWelsh" (not declared in this mod's schema)
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
An invalid value for a declared key falls back to that key's default rather than failing the whole mod — one typo'd number in a config file shouldn't take down a working mod, but it's reported so the mistake doesn't go unnoticed either. This is deliberately not JSON Schema: no nesting, no `$ref`, no conditional rules — just the handful of primitive shapes an actual setting realistically is, kept dependency-free the same way `temporalFmtVersion` checking and `.tfmod` extraction are.
|
|
1063
|
+
|
|
1064
|
+
Loose `.mjs` mods have no manifest to declare a schema in, so `register()`'s second argument is always `{}` for them — same as a `.tfmod` mod that didn't declare a `config` field at all.
|
|
1065
|
+
|
|
1066
|
+
### Load order, dependencies, and conflicts
|
|
1067
|
+
|
|
1068
|
+
By default mods load in filename order — alphabetical, deterministic, but not something you'd want to rely on once two mods actually need to run in a specific order relative to each other. Two fields on the mod object control that directly:
|
|
1069
|
+
|
|
1070
|
+
- `requires: string[]` — other mods' `name` fields that must load (and finish `register()`) before this one. The loader resolves this as a dependency graph, not just "sort requires first" — if A requires B and B requires nothing, B always loads first regardless of filename.
|
|
1071
|
+
- `priority: number` — tiebreak for mods with no dependency relationship to each other. Higher loads later. Defaults to `0`.
|
|
1072
|
+
|
|
1073
|
+
```js
|
|
1074
|
+
export default {
|
|
1075
|
+
name: 'extended-en-gb-holidays',
|
|
1076
|
+
requires: ['en-gb-bank-holidays'],
|
|
1077
|
+
priority: 10,
|
|
1078
|
+
register(ctx) {
|
|
1079
|
+
// runs after en-gb-bank-holidays, and after anything else at a lower priority
|
|
1080
|
+
},
|
|
1081
|
+
};
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
Two failure modes come out of this, both reported per-mod without blocking the rest:
|
|
1085
|
+
|
|
1086
|
+
- **Missing dependency** — `requires` names a mod that isn't in `mods/`. That mod fails to load; whatever it would've registered doesn't happen, and other mods that don't depend on it load normally.
|
|
1087
|
+
- **Circular dependency** — A requires B requires A (or a longer cycle). Every mod in the cycle fails, each reported with what it's still waiting on.
|
|
1088
|
+
|
|
1089
|
+
Registration itself is still last-write-wins, same as calling `registerLocale` twice for the same tag outside of mods — that's existing, intentional behavior (see [Locales](#locales)), not something mods change. What mods add is *visibility* into it: if two mods register the same locale tag, the same relative-time-grammar language, or the same custom token name, the load report calls it out as a conflict and says which one won:
|
|
1090
|
+
|
|
1091
|
+
```
|
|
1092
|
+
temporal-fmt mods:
|
|
1093
|
+
loaded holiday-pack-a (conflict-1.mjs)
|
|
1094
|
+
loaded holiday-pack-b (conflict-2.mjs)
|
|
1095
|
+
conflict on locale "cv-CV": holiday-pack-a, holiday-pack-b — "holiday-pack-b" wins (loaded last)
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
This is informational, not a failure — both mods still loaded, the last one to register just took the key, and now you know it happened instead of silently getting whichever mod's filename sorted last. If that's not what you want, `priority` is the knob: raise the one that should win, or add a `requires` so the loser explicitly runs first and the winner's intent is unambiguous in the mod itself, not just in a startup log line.
|
|
1099
|
+
|
|
1100
|
+
Mod names have to be unique across `mods/` — two files claiming the same `name` is ambiguous the moment either one shows up in another mod's `requires`, so the second one to load fails with which file already claimed that name.
|
|
1101
|
+
|
|
1102
|
+
### Overriding functions
|
|
1103
|
+
|
|
1104
|
+
The five registration functions above are additive — they add a locale, a holiday set, a token, alongside whatever's already there. `ctx.overrideFormat` and `ctx.overrideParse` work differently: they let a mod replace the actual `format()`/`parse()` implementation everywhere in the library, which is what makes a real bugfix or performance mod possible rather than just new data being registered alongside an unfixed bug.
|
|
1105
|
+
|
|
1106
|
+
```js
|
|
1107
|
+
export default {
|
|
1108
|
+
name: 'fast-format',
|
|
1109
|
+
register(ctx) {
|
|
1110
|
+
ctx.overrideFormat((original, value, formatStr, options) => {
|
|
1111
|
+
// Handle the one hot-path format string yourself; fall back to the
|
|
1112
|
+
// real implementation for everything else.
|
|
1113
|
+
if (formatStr === 'yyyy-MM-dd') {
|
|
1114
|
+
return `${value.year}-${String(value.month).padStart(2, '0')}-${String(value.day).padStart(2, '0')}`;
|
|
1115
|
+
}
|
|
1116
|
+
return original(value, formatStr, options);
|
|
1117
|
+
});
|
|
1118
|
+
},
|
|
1119
|
+
};
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
`impl` always receives the real built-in as its first argument (`original`), regardless of what else is loaded — call it to keep existing behavior for cases you're not trying to change, or ignore it to replace the behavior outright. The override applies consistently everywhere in the library, not just to whoever imports the function from the package root — `formatRange()`'s internal use of `format()`, for instance, sees it too. Remove the mod and restart, and it's back to the unmodified built-in; nothing about this touches the source file on disk.
|
|
1123
|
+
|
|
1124
|
+
**Only one mod may hold each override point.** A second override call for the same function — from any mod, even one that `requires` the first — fails immediately with which mod already owns it:
|
|
1125
|
+
|
|
1126
|
+
```
|
|
1127
|
+
temporal-fmt mods:
|
|
1128
|
+
loaded override-1 (a-override1.mjs)
|
|
1129
|
+
failed b-override2.mjs: temporal-fmt: "format" is already overridden by mod "override-1" — mod "override-2" can't also override it. [...]
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
This is a hard failure, not last-write-wins like the registration functions — two mods silently fighting over the same function's behavior is a correctness bug in whatever depends on this library, not a cosmetic surprise. There's no mechanism for two separate mod files to layer through the same override point in sequence; if two mods both need to change a function's behavior, one has to incorporate the other's fix directly rather than composing through the override twice.
|
|
1133
|
+
|
|
1134
|
+
**Which functions are overridable.** `format`, `formatToParts`, and `parse` always were. Beyond those, any function in this library that nothing *else* in the library calls internally is also overridable — if a function has zero internal call sites, there's no risk of some other module holding a stale direct reference that a mod's fix would silently fail to reach, so it gets the same `overrideXxx()` treatment. As of this version, that's:
|
|
1135
|
+
|
|
1136
|
+
`compileFormat`, `compileParser`, `parseRelative`, `explainFormat`, `tokenizeFormat`, `listTokens`, `tokenInfo`, `isValidFormat`, `validateFormat`, `fieldForToken`, `monthsInYear`, `isLeapYear`, `isLeapMonth`, `weekOfYear`, `weekYear`, `getMonth`, `getWeekday`, `isEqual`, `isBefore`, `isAfter`, `clamp`, `isBetween`, `isToday`, `isTomorrow`, `isYesterday`, `isSameDay`, `isSameWeek`, `isSameMonth`, `isSameQuarter`, `isSameYear`, `isWeekday`, `floor`, `ceil`, `truncate`, `parseRFC3339`, `formatRFC3339`, `parseRFC2822`, `parseHTTPDate`, `fromUnixMicroseconds`, `fromUnixNanoseconds`, `toUnixSeconds`, `toUnixMilliseconds`, `toUnixMicroseconds`, `toUnixNanoseconds`, `parseSQL`, `formatSQL`, `formatDurationToParts`, `parseDuration`, `parseISODuration`, `formatISODuration`, `balanceDuration`, `compareDuration`, `subtractDuration`, `getLocale`, `hasLocale`, `createConfig`, `mergeWithConfig`, `listRegisteredGrammars`, `interval`, `overlaps`, `intersection`, `union`, `mergeIntervals`, `formatRangeToParts`, `between`, `parseRRule`, `formatRRule`, `createBusinessCalendar`, `subtractBusinessDays`, `nextHoliday`, `previousHoliday`, `resolveZoned`, `getNextTransition`, `getPreviousTransition`, `possibleInstantsFor`, `getAutocompleteData`, `getHoverDocs`, `getInlineDiagnostics`, `previewFormat`, `getDocUrl`, `translateDateFnsFormatString`.
|
|
1137
|
+
|
|
1138
|
+
Each follows the `ctx.overrideXxx((original, ...args) => ...)` shape shown above for `overrideFormat`. Functions *not* in this list — `round`, `subtract`, `difference`, `formatDistance`, and others that other parts of this library call directly — aren't overridable this way: something else in the codebase holds its own direct reference to them, so a mod's override would silently miss those internal callers, which is worse than not offering the override at all. A function moves onto this list only when an audit confirms nothing internal still calls it directly. If you need to change one of those, that's a real feature request for making it internally indirect first, not something `overrideFormat`-style code can paper over.
|
|
1139
|
+
|
|
1140
|
+
### If you're writing the mod in TypeScript
|
|
1141
|
+
|
|
1142
|
+
Compile it and rename the output before it goes in `mods/` — the loader only accepts `.mjs`. It won't run a TS file for you, and it won't skip one quietly either: a `.ts` file sitting in `mods/` shows up in the load report as a failure with the exact compile command to run, because a mod that silently never loads is worse than one that fails loudly.
|
|
1143
|
+
|
|
1144
|
+
```sh
|
|
1145
|
+
tsc en-gb-bank-holidays.ts --module esnext --target esnext --outDir mods
|
|
1146
|
+
mv mods/en-gb-bank-holidays.js mods/en-gb-bank-holidays.mjs
|
|
1147
|
+
```
|
|
1148
|
+
|
|
1149
|
+
If you're importing `ModContext` or `Mod` for the types while you write it, both are exported from `temporal-fmt` itself:
|
|
1150
|
+
|
|
1151
|
+
```ts
|
|
1152
|
+
import type { Mod, ModContext } from 'temporal-fmt';
|
|
1153
|
+
|
|
1154
|
+
const mod: Mod = {
|
|
1155
|
+
name: 'en-gb-bank-holidays',
|
|
1156
|
+
register(ctx: ModContext) {
|
|
1157
|
+
ctx.createHolidayCalendar([{ month: 1, day: 1, name: "New Year's Day" }]);
|
|
1158
|
+
},
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
export default mod;
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
### What happens when a mod is broken
|
|
1165
|
+
|
|
1166
|
+
Each mod loads independently — one throwing doesn't stop the rest from loading, and it doesn't stop the CLI command you actually ran. Every failure mode ends up as one line in the report:
|
|
1167
|
+
|
|
1168
|
+
- Wrong file extension (`.ts`, `.js`, anything but `.mjs`) — reported with the compile-and-rename instructions above.
|
|
1169
|
+
- Default export isn't shaped right (missing `name`, missing `register`, `register` isn't a function, or `requires`/`priority` are the wrong type) — reported with what was expected.
|
|
1170
|
+
- The file fails to import (a syntax error, a bad import path inside the mod) — reported with the underlying error message.
|
|
1171
|
+
- Two mods claim the same `name` — reported against whichever file loaded second.
|
|
1172
|
+
- A `requires` entry names a mod that isn't present, or is part of a dependency cycle — see [Load order, dependencies, and conflicts](#load-order-dependencies-and-conflicts).
|
|
1173
|
+
- `register()` throws — reported with the thrown message, same as any other registration call in this library (see [Typed errors](#typed-errors) for what `registerLocale`/`createHolidayCalendar` themselves throw on bad input).
|
|
1174
|
+
|
|
1175
|
+
None of these bring down the CLI. A `mods/` folder that doesn't exist is the common case, not a failure — most runs won't have one, and the loader stays silent about it rather than printing "no mods found" noise on every command.
|
|
1176
|
+
|
|
1177
|
+
### Using mods outside the CLI
|
|
1178
|
+
|
|
1179
|
+
`loadMods()` only exists in `scripts/loadMods.mjs`, not in the published library — it needs `fs`/`path`, and this package stays dependency-free and Node-agnostic on its actual import surface (`import { format } from 'temporal-fmt'` shouldn't drag in filesystem code for someone using this in a browser). If you're embedding `temporal-fmt` in your own app rather than using the CLI, copy that loader (or write your own — it's about 400+ lines) and call it at your own startup with `buildModContext()` and `isMod()` from the library, which *are* published.
|
|
1180
|
+
|
|
1181
|
+
Mod support (loose `.mjs` mods, `.tfmod` archives, and everything under [Mods](#mods)) requires `temporal-fmt` 0.9.4 or later — that's the version it landed in.
|
|
1182
|
+
|
|
899
1183
|
## Subpath imports
|
|
900
1184
|
|
|
901
1185
|
Each capability area is also available as a subpath import, for anyone who wants a slice of the package rather than the whole thing:
|
|
@@ -1211,4 +1495,4 @@ A couple of build-specific notes if you're touching the toolchain:
|
|
|
1211
1495
|
|
|
1212
1496
|
## License
|
|
1213
1497
|
|
|
1214
|
-
|
|
1498
|
+
Apache 2.0 — see [LICENSE](./LICENSE).
|