@avandar/acclimate 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Avandar Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
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:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
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.
package/README.md ADDED
@@ -0,0 +1,289 @@
1
+ # Acclimate
2
+
3
+ A lightweight TypeScript framework for building type-safe command line
4
+ interfaces.
5
+
6
+ This library is not complete and is still missing a lot of functionality.
7
+ We do not recommend this library be used in production.
8
+
9
+ See the To Do section at the end for what is still missing.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install acclimate
15
+ ```
16
+
17
+ ## Quick start
18
+
19
+ ```ts
20
+ import { Acclimate } from "acclimate";
21
+
22
+ const cli = Acclimate.createCLI("demo-cli")
23
+ .description("A tiny demo CLI")
24
+ .action(() => {
25
+ console.log("Hello, world!");
26
+ });
27
+
28
+ Acclimate.run(cli);
29
+ ```
30
+
31
+ ## API
32
+
33
+ Public exports from `acclimate`:
34
+
35
+ - `Acclimate`
36
+
37
+ ### `Acclimate`
38
+
39
+ #### `Acclimate.createCLI(name)`
40
+
41
+ Create a new CLI instance.
42
+
43
+ ```ts
44
+ Acclimate.createCLI(name: string): IAcclimateCLI
45
+ ```
46
+
47
+ #### `Acclimate.run(cli)`
48
+
49
+ Run a CLI instance using `process.argv.slice(2)`.
50
+
51
+ ```ts
52
+ Acclimate.run(cli: IAcclimateCLI): void
53
+ ```
54
+
55
+ ### `IAcclimateCLI` (CLI builder)
56
+
57
+ `createCLI()` returns an immutable builder. Each method returns a new CLI
58
+ instance with updated configuration.
59
+
60
+ #### `cli.description(description)`
61
+
62
+ ```ts
63
+ cli.description(description: string): IAcclimateCLI
64
+ ```
65
+
66
+ #### `cli.action(action)`
67
+
68
+ Set the function executed when the CLI matches (after parsing).
69
+
70
+ ```ts
71
+ cli.action(
72
+ action: (args: FullCLIArgValues<...>) => void,
73
+ ): IAcclimateCLI
74
+ ```
75
+
76
+ #### `cli.addPositionalArg(param)`
77
+
78
+ Add a positional argument. Positional args are parsed in order.
79
+
80
+ ```ts
81
+ cli.addPositionalArg(param: CLIPositionalParam): IAcclimateCLI
82
+ ```
83
+
84
+ #### `cli.addOption(param)`
85
+
86
+ Add an option local to this CLI level.
87
+
88
+ ```ts
89
+ cli.addOption(param: CLIOptionParam): IAcclimateCLI
90
+ ```
91
+
92
+ #### `cli.addGlobalOption(param)`
93
+
94
+ Add an option that is available to this CLI and all sub-commands.
95
+
96
+ ```ts
97
+ cli.addGlobalOption(param: CLIOptionParam): IAcclimateCLI
98
+ ```
99
+
100
+ #### `cli.addCommand(commandName, commandCLI)`
101
+
102
+ Add a sub-command (a nested CLI). If the first positional token matches a
103
+ command name, parsing continues using that command's CLI.
104
+
105
+ ```ts
106
+ cli.addCommand(
107
+ commandName: string,
108
+ commandCLI: IAcclimateCLI,
109
+ ): IAcclimateCLI
110
+ ```
111
+
112
+ #### `cli.getCommandCLI(commandName)`
113
+
114
+ Get a command CLI by name (throws if missing).
115
+
116
+ ```ts
117
+ cli.getCommandCLI(commandName: string): IAcclimateCLI
118
+ ```
119
+
120
+ ### Param config types
121
+
122
+ Acclimate uses config objects to describe positional args and options.
123
+
124
+ - **Positional args**: `CLIPositionalParam`
125
+ - **name**: `string` (prefer `camelCase` to match runtime parsing)
126
+ - **type**: `"string" | "number" | "boolean"`
127
+ - **required**: `boolean`
128
+ - **description?**: `string`
129
+ - **defaultValue?**: depends on `type`
130
+ - **choices?**: allowed values list
131
+ - **parser?**: `(value: string) => value`
132
+ - **validator?**: `(value) => true | string`
133
+
134
+ - **Options**: `CLIOptionParam`
135
+ - **name**: `--${string}` (example: `--dry-run`)
136
+ - **aliases?**: `readonly ("--x" | "-x")[]`
137
+ - **required**: `boolean`
138
+ - Same `type`, `defaultValue`, `choices`, `parser`, `validator` fields as a
139
+ positional arg
140
+
141
+ ### Parsing behavior (current)
142
+
143
+ - **Positional args**: validated and parsed in order; extra positional args
144
+ throw an error.
145
+ - **Options**: parsing starts at the first token that begins with `-`. Each
146
+ option consumes tokens until the next option; its raw value is the consumed
147
+ tokens joined with spaces.
148
+ - **Option keys in `action(args)`**: option names are camel-cased, so
149
+ `--dry-run` becomes `dryRun`.
150
+ - **Boolean flags**: `--flag` with no value parses as `true` (only the
151
+ literal string `false` parses as `false`).
152
+ - **Errors**: missing required args/options (and invalid values) throw
153
+ `CLIError`.
154
+
155
+ ## Prerequisites
156
+
157
+ - Node.js **18+**
158
+ - npm (bundled with Node)
159
+
160
+ ## Project Layout
161
+
162
+ - `src/` — framework source code.
163
+ - `examples/` — small usage samples; `basic.ts` is runnable via `npm run demo`.
164
+ - `tests/` — Vitest suite.
165
+ - `dist/` — build output generated by `tsup`.
166
+
167
+ ## Setup
168
+
169
+ Install dependencies:
170
+
171
+ ```bash
172
+ npm install
173
+ ```
174
+
175
+ ## Common Scripts
176
+
177
+ - `npm run dev` — build in watch mode with tsup.
178
+ - `npm run build` — produce CJS/ESM bundles and type declarations in `dist/`.
179
+ - `npm run demo` — execute the `examples/basic.ts` sample with tsx.
180
+ - `npm test` — run the Vitest suite once.
181
+ - `npm run test:watch` — run tests in watch mode.
182
+ - `npm run lint` / `npm run lint:fix` — check or auto-fix with ESLint.
183
+ - `npm run format` / `npm run format:fix` — check or write Prettier
184
+ formatting.
185
+ - `npm run type` - check typescript types
186
+
187
+ ## Running & Testing
188
+
189
+ 1. Start a build (optional during development):
190
+
191
+ ```bash
192
+ npm run dev
193
+ ```
194
+
195
+ 1. Run the sample CLI:
196
+
197
+ ```bash
198
+ npm run demo
199
+ ```
200
+
201
+ 1. Execute tests:
202
+
203
+ ```bash
204
+ npm test
205
+ ```
206
+
207
+ The `prepare` script runs `npm run build`, so the package will compile
208
+ automatically when installed from a git dependency.
209
+
210
+ ## Examples
211
+
212
+ ### Hello world
213
+
214
+ Matches `examples/basic.ts`.
215
+
216
+ ```ts
217
+ import { Acclimate } from "acclimate";
218
+
219
+ const cli = Acclimate.createCLI("demo-cli").action(() => {
220
+ console.log("Hello, world!");
221
+ });
222
+
223
+ Acclimate.run(cli);
224
+ ```
225
+
226
+ ### Positional args + options
227
+
228
+ ```ts
229
+ import { Acclimate } from "acclimate";
230
+
231
+ const cli = Acclimate.createCLI("greet")
232
+ .addPositionalArg({
233
+ name: "name",
234
+ type: "string",
235
+ required: true,
236
+ description: "Who to greet",
237
+ })
238
+ .addOption({
239
+ name: "--shout",
240
+ type: "boolean",
241
+ required: false,
242
+ aliases: ["-s"] as const,
243
+ description: "Uppercase the output",
244
+ defaultValue: false,
245
+ })
246
+ .action(({ name, shout }) => {
247
+ const message = `Hello, ${name}!`;
248
+ console.log(shout ? message.toUpperCase() : message);
249
+ });
250
+
251
+ Acclimate.run(cli);
252
+ ```
253
+
254
+ ### Sub-commands + global options
255
+
256
+ ```ts
257
+ import { Acclimate } from "acclimate";
258
+
259
+ const initCmd = Acclimate.createCLI("init")
260
+ .description("Initialize a project")
261
+ .action(({ verbose }) => {
262
+ console.log(`init (verbose=${verbose})`);
263
+ });
264
+
265
+ const root = Acclimate.createCLI("acme")
266
+ .addGlobalOption({
267
+ name: "--verbose",
268
+ type: "boolean",
269
+ required: false,
270
+ aliases: ["-v"] as const,
271
+ defaultValue: false,
272
+ })
273
+ .addCommand("init", initCmd);
274
+
275
+ Acclimate.run(root);
276
+ ```
277
+
278
+ ## To do
279
+
280
+ - [ ] Add semantic arguments: e.g. email (which has a default validator)
281
+ - [ ] Add default `help` command and `--help` option. This should show the CLI
282
+ description and all param documentation.
283
+ - [ ] Make the `description` actually get printed.
284
+ - [ ] Show all CLI param descriptions if command is run with no arguments or if
285
+ there is a param-related error.
286
+ - [ ] Add helper functions to log to stdout in different colors
287
+ - [ ] Add logic for `askIfEmpty` to enter an interactive mode to receive inputs
288
+ for different params.
289
+ - [ ] Add an option to only `askIfEmptyAndRequired`.
package/dist/index.cjs ADDED
@@ -0,0 +1,381 @@
1
+ 'use strict';
2
+
3
+ var changeCase = require('change-case');
4
+ var tsPattern = require('ts-pattern');
5
+
6
+ // src/CLIError.ts
7
+ var CLIError = class _CLIError extends Error {
8
+ static invalidCLIParamValue(options) {
9
+ return new _CLIError({
10
+ message: options.message ?? `Invalid value for CLI param "${options.paramName}"`,
11
+ code: "invalid_cli_param_value",
12
+ details: { paramName: options.paramName, paramValue: options.paramValue }
13
+ });
14
+ }
15
+ static missingRequiredOption(options) {
16
+ return new _CLIError({
17
+ message: options.message ?? `Required option "${options.optionName}" is missing`,
18
+ code: "missing_required_option",
19
+ details: { optionName: options.optionName }
20
+ });
21
+ }
22
+ static missingRequiredPositionalArg(options) {
23
+ return new _CLIError({
24
+ message: options.message ?? `Required positional argument "${options.positionalArgName}" is missing`,
25
+ code: "missing_required_positional_arg",
26
+ details: { positionalArgName: options.positionalArgName }
27
+ });
28
+ }
29
+ static unknownOption(options) {
30
+ return new _CLIError({
31
+ message: options.message ?? `Option "${options.optionName}" not found`,
32
+ code: "unknown_option",
33
+ details: { optionName: options.optionName }
34
+ });
35
+ }
36
+ static tooManyPositionalArgs(options) {
37
+ return new _CLIError({
38
+ message: options.message ?? "Too many positional arguments provided.",
39
+ code: "too_many_positional_args",
40
+ details: { count: options.count }
41
+ });
42
+ }
43
+ static invalidPositionalArgConfig(options) {
44
+ return new _CLIError({
45
+ message: options.message ?? `Positional argument configuration for "${options.positionalArgName}" is invalid`,
46
+ code: "invalid_positional_arg_config",
47
+ details: { positionalArgName: options.positionalArgName }
48
+ });
49
+ }
50
+ static unknownCommand(options) {
51
+ return new _CLIError({
52
+ message: options.message ?? `Command "${options.commandName}" not found`,
53
+ code: "unknown_command",
54
+ details: { commandName: options.commandName }
55
+ });
56
+ }
57
+ static alreadyRun(options = {}) {
58
+ return new _CLIError({
59
+ message: options.message ?? "CLI has already been run",
60
+ code: "already_run",
61
+ details: void 0
62
+ });
63
+ }
64
+ constructor(options) {
65
+ super(`\u274C ${options.message}`);
66
+ }
67
+ };
68
+
69
+ // src/AcclimateCLI/AcclimateCLI.ts
70
+ function AcclimateCLI(state) {
71
+ return {
72
+ state,
73
+ action: (action) => {
74
+ return AcclimateCLI({
75
+ ...state,
76
+ action
77
+ });
78
+ },
79
+ description: (description) => {
80
+ return AcclimateCLI({
81
+ ...state,
82
+ description
83
+ });
84
+ },
85
+ addPositionalArg: (param) => {
86
+ if (param.required && state.positionalArgs.some((p) => {
87
+ return !p.required;
88
+ })) {
89
+ throw CLIError.invalidPositionalArgConfig({
90
+ positionalArgName: param.name,
91
+ message: "Required positional arguments must be before optional positional arguments"
92
+ });
93
+ }
94
+ return AcclimateCLI({
95
+ ...state,
96
+ positionalArgs: [
97
+ ...state.positionalArgs,
98
+ { ...param, required: param.required ?? true }
99
+ ]
100
+ });
101
+ },
102
+ addGlobalOption: (param) => {
103
+ const newAliases = (param.aliases ?? []).reduce(
104
+ (acc, alias) => {
105
+ acc[alias] = param.name;
106
+ return acc;
107
+ },
108
+ {}
109
+ );
110
+ return AcclimateCLI({
111
+ ...state,
112
+ aliases: { ...state.aliases, ...newAliases },
113
+ globalOptionArgs: {
114
+ ...state.globalOptionArgs,
115
+ [param.name]: param
116
+ }
117
+ });
118
+ },
119
+ addOption: (param) => {
120
+ const newAliases = (param.aliases ?? []).reduce(
121
+ (acc, alias) => {
122
+ acc[alias] = param.name;
123
+ return acc;
124
+ },
125
+ {}
126
+ );
127
+ return AcclimateCLI({
128
+ ...state,
129
+ aliases: { ...state.aliases, ...newAliases },
130
+ optionArgs: { ...state.optionArgs, [param.name]: param }
131
+ });
132
+ },
133
+ addCommand: (commandName, cli) => {
134
+ return AcclimateCLI({
135
+ ...state,
136
+ commands: {
137
+ ...state.commands,
138
+ [commandName]: cli
139
+ }
140
+ });
141
+ },
142
+ getCommandCLI: (commandName) => {
143
+ const cmd = state.commands[commandName];
144
+ if (!cmd) {
145
+ throw CLIError.unknownCommand({
146
+ commandName,
147
+ message: `Command "${commandName}" not found`
148
+ });
149
+ }
150
+ return cmd;
151
+ }
152
+ };
153
+ }
154
+
155
+ // src/AcclimateCLI/createCLI/defaultCLIState.ts
156
+ var defaultCLIState = {
157
+ aliases: {},
158
+ description: void 0,
159
+ commands: {},
160
+ positionalArgs: [],
161
+ optionArgs: {},
162
+ globalOptionArgs: {},
163
+ action: () => {
164
+ }
165
+ };
166
+
167
+ // src/AcclimateCLI/createCLI/createCLI.ts
168
+ function createCLI(name) {
169
+ return AcclimateCLI({ ...defaultCLIState, name });
170
+ }
171
+ function _isValidFullOptionName(name) {
172
+ return name.startsWith("--");
173
+ }
174
+ function _isValidOptionAlias(name) {
175
+ return name.startsWith("-");
176
+ }
177
+ function isEmptyObject(obj) {
178
+ return Object.keys(obj).length === 0;
179
+ }
180
+ function _validateParsedValue(options) {
181
+ const { parsedValue, paramConfig } = options;
182
+ if (paramConfig.validator) {
183
+ const validator = paramConfig.validator;
184
+ const validationResult = validator(parsedValue);
185
+ if (validationResult === true) {
186
+ return parsedValue;
187
+ }
188
+ throw CLIError.invalidCLIParamValue({
189
+ paramName: paramConfig.name,
190
+ paramValue: parsedValue,
191
+ message: typeof validationResult === "string" ? validationResult : void 0
192
+ });
193
+ }
194
+ return parsedValue;
195
+ }
196
+ function _parseAndValidateValue(options) {
197
+ const { inputValue, defaultValue, paramConfig } = options;
198
+ if (inputValue === void 0) {
199
+ if (defaultValue === void 0) {
200
+ if (_isValidFullOptionName(paramConfig.name)) {
201
+ throw CLIError.missingRequiredOption({
202
+ optionName: paramConfig.name
203
+ });
204
+ } else {
205
+ throw CLIError.missingRequiredPositionalArg({
206
+ positionalArgName: paramConfig.name
207
+ });
208
+ }
209
+ }
210
+ return _validateParsedValue({
211
+ parsedValue: defaultValue,
212
+ paramConfig
213
+ });
214
+ }
215
+ const parsedValue = paramConfig.parser ? paramConfig.parser(inputValue) : tsPattern.match(paramConfig.type).with("boolean", () => {
216
+ return inputValue === "false" ? false : true;
217
+ }).with("number", () => {
218
+ return Number.parseInt(inputValue, 10);
219
+ }).with("string", () => {
220
+ return inputValue;
221
+ }).exhaustive(() => {
222
+ return inputValue;
223
+ });
224
+ return _validateParsedValue({
225
+ parsedValue,
226
+ paramConfig
227
+ });
228
+ }
229
+ function _replaceAliases({
230
+ aliasedOptionArgs,
231
+ cli
232
+ }) {
233
+ const aliasMap = cli.state.aliases;
234
+ return Object.entries(aliasedOptionArgs).reduce(
235
+ (acc, [aliasKey, value]) => {
236
+ const alias = aliasKey;
237
+ const optionName = aliasMap[alias] ?? alias;
238
+ acc[optionName] = value;
239
+ return acc;
240
+ },
241
+ {}
242
+ );
243
+ }
244
+ function _runCLIHelper(options) {
245
+ const { rawGlobalOptionArgs, rawOptionArgs, rawPositionalArgs, cli } = {
246
+ ...options,
247
+ rawGlobalOptionArgs: _replaceAliases({
248
+ aliasedOptionArgs: options.rawGlobalOptionArgs,
249
+ cli: options.cli
250
+ }),
251
+ rawOptionArgs: _replaceAliases({
252
+ aliasedOptionArgs: options.rawOptionArgs,
253
+ // TODO(jpsyx): fix that this does not have the CLI may not have all
254
+ cli: options.cli
255
+ })
256
+ };
257
+ const firstArg = rawPositionalArgs[0];
258
+ if (firstArg && !isEmptyObject(cli.state.commands) && cli.state.commands[firstArg]) {
259
+ const commandCLI = Object.values(
260
+ cli.state.globalOptionArgs
261
+ ).reduce(
262
+ (newCmd, argConfig) => {
263
+ return newCmd.addGlobalOption(argConfig);
264
+ },
265
+ cli.getCommandCLI(firstArg)
266
+ );
267
+ return _runCLIHelper({
268
+ rawPositionalArgs: rawPositionalArgs.slice(1),
269
+ rawOptionArgs,
270
+ rawGlobalOptionArgs,
271
+ cli: commandCLI
272
+ });
273
+ }
274
+ if (rawPositionalArgs.length > cli.state.positionalArgs.length) {
275
+ throw CLIError.tooManyPositionalArgs({
276
+ count: rawPositionalArgs.length
277
+ });
278
+ }
279
+ const parsedPositionalArgs = cli.state.positionalArgs.reduce(
280
+ (acc, argConfig, idx) => {
281
+ const rawVal = rawPositionalArgs[idx];
282
+ if (argConfig.required && rawVal === void 0) {
283
+ throw CLIError.missingRequiredPositionalArg({
284
+ positionalArgName: argConfig.name
285
+ });
286
+ }
287
+ acc[argConfig.name] = _parseAndValidateValue({
288
+ inputValue: rawVal,
289
+ defaultValue: argConfig.defaultValue,
290
+ paramConfig: argConfig
291
+ });
292
+ return acc;
293
+ },
294
+ {}
295
+ );
296
+ const parsedOptionArgs = Object.values(
297
+ cli.state.optionArgs
298
+ ).reduce(
299
+ (acc, argConfig) => {
300
+ const rawVal = rawOptionArgs[argConfig.name];
301
+ if (argConfig.required && rawVal === void 0) {
302
+ throw CLIError.missingRequiredOption({
303
+ optionName: argConfig.name
304
+ });
305
+ }
306
+ acc[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
307
+ inputValue: rawVal,
308
+ defaultValue: argConfig.defaultValue,
309
+ paramConfig: argConfig
310
+ });
311
+ return acc;
312
+ },
313
+ {}
314
+ );
315
+ const parsedGlobalOptionArgs = Object.values(
316
+ cli.state.globalOptionArgs
317
+ ).reduce(
318
+ (acc, argConfig) => {
319
+ const rawVal = rawGlobalOptionArgs[argConfig.name];
320
+ if (argConfig.required && rawVal === void 0) {
321
+ throw CLIError.missingRequiredOption({
322
+ optionName: argConfig.name
323
+ });
324
+ }
325
+ acc[changeCase.camelCase(argConfig.name)] = _parseAndValidateValue({
326
+ inputValue: rawVal,
327
+ defaultValue: argConfig.defaultValue,
328
+ paramConfig: argConfig
329
+ });
330
+ return acc;
331
+ },
332
+ {}
333
+ );
334
+ cli.state.action({
335
+ ...parsedPositionalArgs,
336
+ ...parsedOptionArgs,
337
+ ...parsedGlobalOptionArgs
338
+ });
339
+ }
340
+ function runCLI(options) {
341
+ const { input, cli } = options;
342
+ const firstOptionIdx = input.findIndex((token) => {
343
+ return token.startsWith("-");
344
+ });
345
+ const [rawPositionalArgs, rest] = firstOptionIdx === -1 ? [input, []] : [input.slice(0, firstOptionIdx), input.slice(firstOptionIdx)];
346
+ const rawOptionArgs = {};
347
+ const rawGlobalOptionArgs = {};
348
+ let currentAlias;
349
+ let currentVals = [];
350
+ const { aliases, globalOptionArgs } = cli.state;
351
+ for (const argVal of rest.concat("-")) {
352
+ if (_isValidOptionAlias(argVal)) {
353
+ if (currentAlias) {
354
+ const rawValue = currentVals.join(" ");
355
+ const optionName = aliases[currentAlias] ?? currentAlias;
356
+ if (_isValidFullOptionName(optionName) && !isEmptyObject(globalOptionArgs) && globalOptionArgs[optionName]) {
357
+ rawGlobalOptionArgs[optionName] = rawValue;
358
+ } else {
359
+ rawOptionArgs[optionName] = rawValue;
360
+ }
361
+ }
362
+ currentAlias = argVal;
363
+ currentVals = [];
364
+ } else {
365
+ currentVals.push(argVal);
366
+ }
367
+ }
368
+ _runCLIHelper({ rawPositionalArgs, rawOptionArgs, rawGlobalOptionArgs, cli });
369
+ }
370
+
371
+ // src/Acclimate.ts
372
+ var Acclimate = {
373
+ createCLI,
374
+ run: (cli) => {
375
+ runCLI({ cli, input: process.argv.slice(2) });
376
+ }
377
+ };
378
+
379
+ exports.Acclimate = Acclimate;
380
+ //# sourceMappingURL=index.cjs.map
381
+ //# sourceMappingURL=index.cjs.map