@raisenow/tamaro-cli 3.0.0 → 3.1.0-dev.1
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 +10 -1
- package/dist/cli.js +213 -4
- package/package.json +3 -2
- package/.idea/inspectionProfiles/Project_Default.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/tamaro-cli.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/.idea/workspace.xml +0 -62
package/README.md
CHANGED
|
@@ -282,7 +282,16 @@ pnpx @raisenow/tamaro-cli update-epms --tag WEB-123
|
|
|
282
282
|
|
|
283
283
|
## `validate`
|
|
284
284
|
|
|
285
|
-
Validate the current configuration and fail on known issues such as invalid
|
|
285
|
+
Validate the current configuration and fail on known issues such as invalid
|
|
286
|
+
email templates, invalid `.env` values, or RaiseNow-generated tax receipts
|
|
287
|
+
enabled without an uploaded organisation template.
|
|
288
|
+
|
|
289
|
+
When `autogeneratedDonationReceiptEnabled` (or
|
|
290
|
+
`autogenerated_donation_receipt_enabled`) is `true`, this command authenticates
|
|
291
|
+
with EPMS (browser login or client credentials) and checks that a donation
|
|
292
|
+
tax-receipt PDF template exists for each configured account. See the
|
|
293
|
+
[Confluence guide](https://raisenow.atlassian.net/wiki/spaces/PD/pages/6231687230/Tamaro+CLI+Commands#Tax-receipt-validation--how-CS-resolves-it)
|
|
294
|
+
for how to resolve a failed check.
|
|
286
295
|
|
|
287
296
|
### Example
|
|
288
297
|
|
package/dist/cli.js
CHANGED
|
@@ -12,9 +12,10 @@ import ky from "ky";
|
|
|
12
12
|
import { createServer } from "node:http";
|
|
13
13
|
import open from "open";
|
|
14
14
|
import { globSync } from "glob";
|
|
15
|
+
import { codeFrameColumns } from "@babel/code-frame";
|
|
15
16
|
import Handlebars from "handlebars";
|
|
16
17
|
import helpers from "handlebars-helpers";
|
|
17
|
-
import { config } from "dotenv";
|
|
18
|
+
import { config, parse } from "dotenv";
|
|
18
19
|
import { getPortPromise } from "portfinder";
|
|
19
20
|
import prompts from "prompts";
|
|
20
21
|
import columnify from "columnify";
|
|
@@ -279,6 +280,8 @@ var EpmsClient = class EpmsClient {
|
|
|
279
280
|
#cacheKey;
|
|
280
281
|
#epmsClient;
|
|
281
282
|
#authType;
|
|
283
|
+
/** In-memory account UUID → organisation UUID cache for this client instance. */
|
|
284
|
+
#organisationIdByAccountUuid = /* @__PURE__ */ new Map();
|
|
282
285
|
/**
|
|
283
286
|
* Creates an instance of EpmsClient.
|
|
284
287
|
*
|
|
@@ -307,14 +310,25 @@ var EpmsClient = class EpmsClient {
|
|
|
307
310
|
return this.#epmsClient.get("users/myself").json().then((response) => myselfSchema.parse(response));
|
|
308
311
|
}
|
|
309
312
|
async getOrganisationIdByAccountUuid(accountUuid) {
|
|
313
|
+
const cached = this.#organisationIdByAccountUuid.get(accountUuid);
|
|
314
|
+
if (cached) return cached;
|
|
310
315
|
try {
|
|
311
316
|
const organisationUuid = (await this.#epmsClient.get(`accounts/${accountUuid}`).json()).organisation.uuid;
|
|
312
317
|
if (!organisationUuid) throw new Error("Organisation UUID not found in response");
|
|
318
|
+
this.#organisationIdByAccountUuid.set(accountUuid, organisationUuid);
|
|
313
319
|
return organisationUuid;
|
|
314
320
|
} catch (error) {
|
|
315
321
|
throw new Error(`Organisation UUID not found for account UUID: ${accountUuid}`, { cause: error });
|
|
316
322
|
}
|
|
317
323
|
}
|
|
324
|
+
async listOrganisationFiles(organisationUuid) {
|
|
325
|
+
try {
|
|
326
|
+
const response = await this.#epmsClient.get(`organisations/${organisationUuid}/files`).json();
|
|
327
|
+
return Array.isArray(response) ? response : response.data ?? [];
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw new Error(`Failed to list organisation files for organisation UUID: ${organisationUuid}`, { cause: error });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
318
332
|
async updateTamaro(configName, tag, json) {
|
|
319
333
|
return this.#epmsClient.put(`products/tamaro/${configName}/tags/${tag}`, { json }).json();
|
|
320
334
|
}
|
|
@@ -442,6 +456,99 @@ const assertArchiveTargetDoesNotExist = (archiveTarget) => {
|
|
|
442
456
|
if (fs.existsSync(archiveTarget)) halt(`Archive target already exists: ${archiveTarget}. Please remove it first.`);
|
|
443
457
|
};
|
|
444
458
|
//#endregion
|
|
459
|
+
//#region src/lib/validators/validateDonationReceiptTemplates.ts
|
|
460
|
+
/** Internal docs validation guide for CS */
|
|
461
|
+
const DONATION_RECEIPT_VALIDATION_GUIDE_URL = "https://raisenow.atlassian.net/wiki/spaces/PD/pages/6231687230/Tamaro+CLI+Commands#Donation-tax-receipts";
|
|
462
|
+
const FLAG_KEYS = ["autogeneratedDonationReceiptEnabled", "autogenerated_donation_receipt_enabled"];
|
|
463
|
+
/**
|
|
464
|
+
* Resolve which config.yml key enabled RaiseNow-generated donation tax
|
|
465
|
+
* receipts. Supports both camelCase and snake_case keys used in customer
|
|
466
|
+
* configs; returns undefined when the option is not strictly `true`.
|
|
467
|
+
*/
|
|
468
|
+
const isAutogeneratedDonationReceiptEnabled = (rawConfig) => {
|
|
469
|
+
if (!rawConfig || typeof rawConfig !== "object") return;
|
|
470
|
+
const config = rawConfig;
|
|
471
|
+
for (const key of FLAG_KEYS) if (config[key] === true) return key;
|
|
472
|
+
};
|
|
473
|
+
/**
|
|
474
|
+
* Check that a donation tax receipt PDF template exists for the account in
|
|
475
|
+
* the organisation files list. Matches Hub storage layout:
|
|
476
|
+
* `{accountUuid}/donation-receipt-templates/{language}.pdf`
|
|
477
|
+
*/
|
|
478
|
+
const donationReceiptTemplateExists = (files, accountUuid) => {
|
|
479
|
+
const prefix = `${accountUuid}/donation-receipt-templates/`;
|
|
480
|
+
return files.some((file) => file.name.startsWith(prefix) && file.name.endsWith(".pdf") && file.name.slice(prefix.length).length > 0 && !file.name.slice(prefix.length).includes("/"));
|
|
481
|
+
};
|
|
482
|
+
/**
|
|
483
|
+
* Locate the line of a top-level `key:` assignment in the config.yml source,
|
|
484
|
+
* so the error can be rendered as a code frame pointing at the value.
|
|
485
|
+
*/
|
|
486
|
+
const findKeyLocation$1 = (source, key) => {
|
|
487
|
+
const lines = source.split("\n");
|
|
488
|
+
const assignment = new RegExp(String.raw`^\s*${key}\s*:`);
|
|
489
|
+
const index = lines.findIndex((line) => assignment.test(line));
|
|
490
|
+
if (index === -1) return;
|
|
491
|
+
const line = index + 1;
|
|
492
|
+
const valueStart = lines[index].indexOf(":") + 1;
|
|
493
|
+
return {
|
|
494
|
+
end: {
|
|
495
|
+
column: lines[index].length,
|
|
496
|
+
line
|
|
497
|
+
},
|
|
498
|
+
start: {
|
|
499
|
+
column: valueStart + 1,
|
|
500
|
+
line
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
};
|
|
504
|
+
/**
|
|
505
|
+
* Format an error for a `key:` assignment as a code frame pointing at the
|
|
506
|
+
* value, so it looks fancy like this:
|
|
507
|
+
*
|
|
508
|
+
* config.yml:51
|
|
509
|
+
* 50 | show_stored_customer_donation_receipt: true
|
|
510
|
+
* 51 | autogeneratedDonationReceiptEnabled: true
|
|
511
|
+
* | ^^^^ No donation tax receipt PDF template found…
|
|
512
|
+
*/
|
|
513
|
+
const formatError$1 = (configYmlPath, source, key, message) => {
|
|
514
|
+
const location = findKeyLocation$1(source, key);
|
|
515
|
+
if (!location) return `${configYmlPath}: ${key}: ${message}`;
|
|
516
|
+
const frame = codeFrameColumns(source, location, {
|
|
517
|
+
forceColor: true,
|
|
518
|
+
highlightCode: true,
|
|
519
|
+
message
|
|
520
|
+
});
|
|
521
|
+
return `\n${configYmlPath}:${location.start.line}\n${frame}`;
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Validate that RaiseNow-generated tax receipts are only enabled when each
|
|
525
|
+
* configured EPMS account has a donation tax receipt PDF template uploaded.
|
|
526
|
+
*/
|
|
527
|
+
const validateDonationReceiptTemplates = async (configYmlPath) => {
|
|
528
|
+
if (!fs.existsSync(configYmlPath)) return [];
|
|
529
|
+
const source = fs.readFileSync(configYmlPath, "utf8");
|
|
530
|
+
const flagKey = isAutogeneratedDonationReceiptEnabled(yaml.load(source));
|
|
531
|
+
if (!flagKey) return [];
|
|
532
|
+
const { accountUuidProd, accountUuidStage } = loadTamaroMetadataFromConfig(configYmlPath);
|
|
533
|
+
const errors = [];
|
|
534
|
+
const environments = [{
|
|
535
|
+
accountUuid: accountUuidStage,
|
|
536
|
+
env: "stage",
|
|
537
|
+
label: "Stage"
|
|
538
|
+
}, {
|
|
539
|
+
accountUuid: accountUuidProd,
|
|
540
|
+
env: "prod",
|
|
541
|
+
label: "Prod"
|
|
542
|
+
}];
|
|
543
|
+
for (const { accountUuid, env, label } of environments) {
|
|
544
|
+
if (!accountUuid) continue;
|
|
545
|
+
const epmsClient = epmsAuthenticate(env);
|
|
546
|
+
const organisationUuid = await epmsClient.getOrganisationIdByAccountUuid(accountUuid);
|
|
547
|
+
if (!donationReceiptTemplateExists(await epmsClient.listOrganisationFiles(organisationUuid), accountUuid)) errors.push(formatError$1(configYmlPath, source, flagKey, `No donation tax receipt PDF template found for the ${label} account (${accountUuid}). See: ${DONATION_RECEIPT_VALIDATION_GUIDE_URL}`));
|
|
548
|
+
}
|
|
549
|
+
return errors;
|
|
550
|
+
};
|
|
551
|
+
//#endregion
|
|
445
552
|
//#region src/lib/validators/validateEmailTemplates.ts
|
|
446
553
|
/**
|
|
447
554
|
* Register custom Handlebars helpers - the same, which are used in the Email Service.
|
|
@@ -545,6 +652,98 @@ const compileEmailTemplate = (template) => {
|
|
|
545
652
|
Handlebars.compile(template)({});
|
|
546
653
|
};
|
|
547
654
|
//#endregion
|
|
655
|
+
//#region src/lib/validators/validateEnv.ts
|
|
656
|
+
const envSchema = z.strictObject({
|
|
657
|
+
CORE_URL: z.url().optional(),
|
|
658
|
+
CORE_URL_PATTERN: z.string().includes("{{version}}", { message: "Must contain the \"{{version}}\" placeholder" }).optional(),
|
|
659
|
+
CORE_VERSION: z.string().refine((version) => version === version.trim(), { message: "There must be no leading or trailing whitespace in the version string" }).refine((version) => version === version.toLowerCase(), { message: "The version string must be lowercase" }).optional(),
|
|
660
|
+
DISABLE_URL_VERSION_OVERRIDE: z.enum([
|
|
661
|
+
"true",
|
|
662
|
+
"false",
|
|
663
|
+
"1",
|
|
664
|
+
"0"
|
|
665
|
+
]).optional(),
|
|
666
|
+
LOCAL_CORE: z.enum(["true", "false"]).optional()
|
|
667
|
+
});
|
|
668
|
+
const TAMARO_CORE_REGISTRY_URL = "https://registry.npmjs.org/@raisenow/tamaro-core";
|
|
669
|
+
/**
|
|
670
|
+
* Check that the configured version exists for "@raisenow/tamaro-core" on npm:
|
|
671
|
+
* as a dist-tag (e.g. "latest", "lts_2026"), an exact version, or a partial
|
|
672
|
+
* version ("2", "2.15") matching at least one published version.
|
|
673
|
+
*/
|
|
674
|
+
const coreVersionExists = async (version) => {
|
|
675
|
+
const metadata = await ky.get(TAMARO_CORE_REGISTRY_URL, {
|
|
676
|
+
headers: { accept: "application/vnd.npm.install-v1+json" },
|
|
677
|
+
retry: 0,
|
|
678
|
+
timeout: DEFAULT_HTTP_TIMEOUT
|
|
679
|
+
}).json();
|
|
680
|
+
const distTags = Object.keys(metadata["dist-tags"] ?? {});
|
|
681
|
+
const versions = Object.keys(metadata.versions ?? {});
|
|
682
|
+
return distTags.includes(version) || versions.includes(version) || versions.some((existing) => existing.startsWith(`${version}.`));
|
|
683
|
+
};
|
|
684
|
+
/**
|
|
685
|
+
* Locate the line of a `KEY=` assignment in the .env source, so the error can
|
|
686
|
+
* be rendered as a code frame pointing at the value.
|
|
687
|
+
*/
|
|
688
|
+
const findKeyLocation = (source, key) => {
|
|
689
|
+
const lines = source.split("\n");
|
|
690
|
+
const assignment = new RegExp(String.raw`^\s*${key}\s*=`);
|
|
691
|
+
const index = lines.findIndex((line) => assignment.test(line));
|
|
692
|
+
if (index === -1) return;
|
|
693
|
+
const line = index + 1;
|
|
694
|
+
const valueStart = lines[index].indexOf("=") + 1;
|
|
695
|
+
return {
|
|
696
|
+
end: {
|
|
697
|
+
column: lines[index].length,
|
|
698
|
+
line
|
|
699
|
+
},
|
|
700
|
+
start: {
|
|
701
|
+
column: valueStart,
|
|
702
|
+
line
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
};
|
|
706
|
+
/**
|
|
707
|
+
* Format an error for a `KEY=` assignment as a code frame pointing at the
|
|
708
|
+
* value, so it looks fancy like this:
|
|
709
|
+
*
|
|
710
|
+
* .env:2
|
|
711
|
+
* 1 | CORE_VERSION=LTS_2026
|
|
712
|
+
* 2 | CORE_URL_PATTERN=adsf
|
|
713
|
+
* | ^^^^ Must contain the "{{version}}" placeholder
|
|
714
|
+
*/
|
|
715
|
+
const formatError = (dotEnvPath, source, key, message) => {
|
|
716
|
+
const location = findKeyLocation(source, key);
|
|
717
|
+
if (!location) return `${dotEnvPath}: ${key}: ${message}`;
|
|
718
|
+
const frame = codeFrameColumns(source, location, {
|
|
719
|
+
forceColor: true,
|
|
720
|
+
highlightCode: true,
|
|
721
|
+
message
|
|
722
|
+
});
|
|
723
|
+
return `\n${dotEnvPath}:${location.start.line}\n${frame}`;
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* Validate the environment variables in the config's .env file.
|
|
727
|
+
*/
|
|
728
|
+
const validateEnv = async (dotEnvPath) => {
|
|
729
|
+
if (!fs.existsSync(dotEnvPath)) return [];
|
|
730
|
+
const source = fs.readFileSync(dotEnvPath, "utf8");
|
|
731
|
+
const parsed = parse(source);
|
|
732
|
+
const result = envSchema.safeParse(parsed);
|
|
733
|
+
if (!result.success) {
|
|
734
|
+
const errors = [];
|
|
735
|
+
for (const issue of result.error.issues) {
|
|
736
|
+
const keys = issue.code === "unrecognized_keys" ? issue.keys : [String(issue.path[0] ?? "")];
|
|
737
|
+
for (const key of keys) errors.push(formatError(dotEnvPath, source, key, issue.message));
|
|
738
|
+
}
|
|
739
|
+
return errors;
|
|
740
|
+
}
|
|
741
|
+
if (parsed.CORE_VERSION) {
|
|
742
|
+
if (await coreVersionExists(parsed.CORE_VERSION) === false) return [formatError(dotEnvPath, source, "CORE_VERSION", `Version "${parsed.CORE_VERSION}" does not exist. See all versions at https://www.npmjs.com/package/@raisenow/tamaro-core?activeTab=versions`)];
|
|
743
|
+
}
|
|
744
|
+
return [];
|
|
745
|
+
};
|
|
746
|
+
//#endregion
|
|
548
747
|
//#region src/commands/validate.ts
|
|
549
748
|
/**
|
|
550
749
|
* Validates the current Tamaro configuration to avoid common errors.
|
|
@@ -554,8 +753,16 @@ const compileEmailTemplate = (template) => {
|
|
|
554
753
|
* deployed.
|
|
555
754
|
*/
|
|
556
755
|
const validate = async () => {
|
|
557
|
-
const errors =
|
|
558
|
-
|
|
756
|
+
const errors = [
|
|
757
|
+
...await validateEnv(".env"),
|
|
758
|
+
...validateEmailTemplates(globSync("email-config/templates/**/*.hbs").toSorted()),
|
|
759
|
+
...await validateDonationReceiptTemplates("config.yml")
|
|
760
|
+
];
|
|
761
|
+
if (errors.length > 0) {
|
|
762
|
+
logError("❌ Validation failed with the following errors:");
|
|
763
|
+
console.log(errors.map((el) => el.toString()).join("\n"));
|
|
764
|
+
halt();
|
|
765
|
+
}
|
|
559
766
|
logTitle("Validated successfully");
|
|
560
767
|
};
|
|
561
768
|
//#endregion
|
|
@@ -631,6 +838,7 @@ const getOutDir = (configName) => {
|
|
|
631
838
|
//#region src/commands/update-epms.ts
|
|
632
839
|
const updateEpms = async (options) => {
|
|
633
840
|
const configName = getConfigName();
|
|
841
|
+
await validate();
|
|
634
842
|
if (!options.profile && !options.ci) {
|
|
635
843
|
assertAwsProfilesPresent();
|
|
636
844
|
options.profile = await promptAwsProfile();
|
|
@@ -912,6 +1120,7 @@ const dev = async (options) => {
|
|
|
912
1120
|
const configName = getConfigName();
|
|
913
1121
|
const configsPackageRoot = getConfigsPackageRoot();
|
|
914
1122
|
assertCrtExists(configsPackageRoot);
|
|
1123
|
+
await validate();
|
|
915
1124
|
const port = await getPortPromise({ port: Number(DEFAULT_PORT) });
|
|
916
1125
|
logTitle(`\nStarting Vite dev server for "${configName}" configuration...`);
|
|
917
1126
|
runCommandSync(`pnpm vite dev --port ${port}`, {
|
|
@@ -1225,7 +1434,7 @@ const promptBucketTamaroEmailConfig = async () => {
|
|
|
1225
1434
|
//#endregion
|
|
1226
1435
|
//#region package.json
|
|
1227
1436
|
var name = "@raisenow/tamaro-cli";
|
|
1228
|
-
var version = "3.0.
|
|
1437
|
+
var version = "3.1.0-dev.1";
|
|
1229
1438
|
//#endregion
|
|
1230
1439
|
//#region src/cli.ts
|
|
1231
1440
|
const cli = createCommand().name(name).description("CLI for Tamaro Customer Configurations development").version(version, "-v, --version");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raisenow/tamaro-cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.1.0-dev.1",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "RaiseNow",
|
|
6
6
|
"email": "development@raisenow.com"
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"yarn": "please-use-pnpm"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@aws-sdk/client-s3": "^3.
|
|
16
|
+
"@aws-sdk/client-s3": "^3.1081.0",
|
|
17
|
+
"@babel/code-frame": "^8.0.0",
|
|
17
18
|
"@rnw-npm/cli-helpers": "^2.0.1",
|
|
18
19
|
"columnify": "^1.6.0",
|
|
19
20
|
"commander": "^15.0.0",
|
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/tamaro-cli.iml" filepath="$PROJECT_DIR$/.idea/tamaro-cli.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/tamaro-cli.iml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="NewModuleRootManager">
|
|
4
|
-
<content url="file://$MODULE_DIR$">
|
|
5
|
-
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
|
6
|
-
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
|
7
|
-
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
|
8
|
-
</content>
|
|
9
|
-
<orderEntry type="inheritedJdk" />
|
|
10
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
11
|
-
</component>
|
|
12
|
-
</module>
|
package/.idea/vcs.xml
DELETED
package/.idea/workspace.xml
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ChangeListManager">
|
|
4
|
-
<list default="true" id="03cc3f97-55ca-4737-9fe2-779ac8457ab2" name="Changes" comment="" />
|
|
5
|
-
<option name="SHOW_DIALOG" value="false" />
|
|
6
|
-
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
7
|
-
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
8
|
-
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
9
|
-
</component>
|
|
10
|
-
<component name="Git.Settings">
|
|
11
|
-
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
12
|
-
</component>
|
|
13
|
-
<component name="MarkdownSettingsMigration">
|
|
14
|
-
<option name="stateVersion" value="1" />
|
|
15
|
-
</component>
|
|
16
|
-
<component name="ProjectId" id="3BwvHZOW2N4A0f0JXo7q8qDzYwY" />
|
|
17
|
-
<component name="ProjectViewState">
|
|
18
|
-
<option name="autoscrollFromSource" value="true" />
|
|
19
|
-
<option name="autoscrollToSource" value="true" />
|
|
20
|
-
<option name="hideEmptyMiddlePackages" value="true" />
|
|
21
|
-
<option name="showLibraryContents" value="true" />
|
|
22
|
-
<option name="showMembers" value="true" />
|
|
23
|
-
</component>
|
|
24
|
-
<component name="PropertiesComponent">{
|
|
25
|
-
"keyToString": {
|
|
26
|
-
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
27
|
-
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
28
|
-
"WebServerToolWindowFactoryState": "false",
|
|
29
|
-
"node.js.detected.package.eslint": "true",
|
|
30
|
-
"node.js.selected.package.eslint": "(autodetect)",
|
|
31
|
-
"nodejs_package_manager_path": "pnpm",
|
|
32
|
-
"prettierjs.PrettierConfiguration.Package": "/Users/sigerello/dev/_raisenow/tools/tamaro-cli/node_modules/prettier",
|
|
33
|
-
"ts.external.directory.path": "/Users/sigerello/dev/_raisenow/tools/tamaro-cli/node_modules/typescript/lib",
|
|
34
|
-
"vue.rearranger.settings.migration": "true"
|
|
35
|
-
}
|
|
36
|
-
}</component>
|
|
37
|
-
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
|
38
|
-
<component name="TaskManager">
|
|
39
|
-
<task active="true" id="Default" summary="Default task">
|
|
40
|
-
<changelist id="03cc3f97-55ca-4737-9fe2-779ac8457ab2" name="Changes" comment="" />
|
|
41
|
-
<created>1775412859839</created>
|
|
42
|
-
<option name="number" value="Default" />
|
|
43
|
-
<option name="presentableId" value="Default" />
|
|
44
|
-
<updated>1775412859839</updated>
|
|
45
|
-
<workItem from="1775412861312" duration="2060000" />
|
|
46
|
-
<workItem from="1776174639969" duration="1525000" />
|
|
47
|
-
<workItem from="1776736351878" duration="598000" />
|
|
48
|
-
<workItem from="1777934504965" duration="82000" />
|
|
49
|
-
<workItem from="1777936008103" duration="88000" />
|
|
50
|
-
<workItem from="1778477038620" duration="2530000" />
|
|
51
|
-
<workItem from="1780398242165" duration="1962000" />
|
|
52
|
-
<workItem from="1781661280180" duration="2828000" />
|
|
53
|
-
<workItem from="1782699840335" duration="599000" />
|
|
54
|
-
<workItem from="1782869357470" duration="598000" />
|
|
55
|
-
<workItem from="1783270034892" duration="1197000" />
|
|
56
|
-
</task>
|
|
57
|
-
<servers />
|
|
58
|
-
</component>
|
|
59
|
-
<component name="TypeScriptGeneratedFilesManager">
|
|
60
|
-
<option name="version" value="3" />
|
|
61
|
-
</component>
|
|
62
|
-
</project>
|