@fgv/ts-res 5.0.1-9 → 5.0.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/dist/index.browser.js +53 -0
- package/dist/index.js +45 -0
- package/dist/packlets/bundle/bundleBuilder.js +130 -0
- package/dist/packlets/bundle/bundleLoader.js +101 -0
- package/dist/packlets/bundle/bundleNormalizer.js +138 -0
- package/dist/packlets/bundle/bundleUtils.js +113 -0
- package/dist/packlets/bundle/convert.js +75 -0
- package/dist/packlets/bundle/index.js +42 -0
- package/dist/packlets/bundle/model.js +23 -0
- package/dist/packlets/common/conditions.js +47 -0
- package/dist/packlets/common/convert.js +172 -0
- package/dist/packlets/common/helpers/conditions.js +66 -0
- package/dist/packlets/common/helpers/context.js +70 -0
- package/dist/packlets/common/helpers/index.js +26 -0
- package/dist/packlets/common/helpers/qualifierDefaultValues.js +66 -0
- package/dist/packlets/common/helpers/resources.js +93 -0
- package/dist/packlets/common/index.js +28 -0
- package/dist/packlets/common/resources.js +27 -0
- package/dist/packlets/common/validate/conditions.js +544 -0
- package/dist/packlets/common/validate/index.js +26 -0
- package/dist/packlets/common/validate/regularExpressions.js +84 -0
- package/dist/packlets/common/validate/resources.js +209 -0
- package/dist/packlets/conditions/condition.js +252 -0
- package/dist/packlets/conditions/conditionCollector.js +69 -0
- package/dist/packlets/conditions/conditionDecls.js +23 -0
- package/dist/packlets/conditions/conditionSet.js +247 -0
- package/dist/packlets/conditions/conditionSetCollector.js +89 -0
- package/dist/packlets/conditions/conditionSetDecls.js +23 -0
- package/dist/packlets/conditions/conditionToken.js +147 -0
- package/dist/packlets/conditions/convert/conditionSetDecls.js +51 -0
- package/dist/packlets/conditions/convert/decls.js +75 -0
- package/dist/packlets/conditions/convert/index.js +24 -0
- package/dist/packlets/conditions/index.js +31 -0
- package/dist/packlets/config/common.js +78 -0
- package/dist/packlets/config/configInitFactory.js +258 -0
- package/dist/packlets/config/convert.js +56 -0
- package/dist/packlets/config/index.browser.js +34 -0
- package/dist/packlets/config/index.js +28 -0
- package/dist/packlets/config/json.js +23 -0
- package/dist/packlets/config/predefined/default.js +138 -0
- package/dist/packlets/config/predefined/extended.js +190 -0
- package/dist/packlets/config/predefined/index.js +25 -0
- package/dist/packlets/config/systemConfiguration.js +147 -0
- package/dist/packlets/context/contextDecls.js +23 -0
- package/dist/packlets/context/contextToken.js +202 -0
- package/dist/packlets/context/convert/decls.js +91 -0
- package/dist/packlets/context/convert/index.js +23 -0
- package/dist/packlets/context/index.js +26 -0
- package/dist/packlets/decisions/abstractDecision.js +68 -0
- package/dist/packlets/decisions/abstractDecisionCollector.js +90 -0
- package/dist/packlets/decisions/candidate.js +76 -0
- package/dist/packlets/decisions/common.js +23 -0
- package/dist/packlets/decisions/concreteDecision.js +111 -0
- package/dist/packlets/decisions/decision.js +126 -0
- package/dist/packlets/decisions/index.js +28 -0
- package/dist/packlets/import/fsItem.js +134 -0
- package/dist/packlets/import/importContext.js +129 -0
- package/dist/packlets/import/importManager.js +129 -0
- package/dist/packlets/import/importable.js +32 -0
- package/dist/packlets/import/importers/collectionImporter.js +118 -0
- package/dist/packlets/import/importers/fsItemImporter.js +116 -0
- package/dist/packlets/import/importers/importer.js +23 -0
- package/dist/packlets/import/importers/index.browser.js +29 -0
- package/dist/packlets/import/importers/index.js +27 -0
- package/dist/packlets/import/importers/jsonImporter.js +94 -0
- package/dist/packlets/import/importers/pathImporter.js +84 -0
- package/dist/packlets/import/index.browser.js +34 -0
- package/dist/packlets/import/index.js +28 -0
- package/dist/packlets/qualifier-types/config/convert.js +124 -0
- package/dist/packlets/qualifier-types/config/index.js +25 -0
- package/dist/packlets/qualifier-types/config/json.js +32 -0
- package/dist/packlets/qualifier-types/convert.js +56 -0
- package/dist/packlets/qualifier-types/helpers.js +82 -0
- package/dist/packlets/qualifier-types/index.js +32 -0
- package/dist/packlets/qualifier-types/languageQualifierType.js +142 -0
- package/dist/packlets/qualifier-types/literalQualifierType.js +200 -0
- package/dist/packlets/qualifier-types/literalValueHierarchy.js +236 -0
- package/dist/packlets/qualifier-types/qualifierType.js +184 -0
- package/dist/packlets/qualifier-types/qualifierTypeCollector.js +66 -0
- package/dist/packlets/qualifier-types/territoryQualifierType.js +200 -0
- package/dist/packlets/qualifiers/convert/decls.js +70 -0
- package/dist/packlets/qualifiers/convert/index.js +24 -0
- package/dist/packlets/qualifiers/convert/qualifier.js +40 -0
- package/dist/packlets/qualifiers/index.js +29 -0
- package/dist/packlets/qualifiers/qualifier.js +108 -0
- package/dist/packlets/qualifiers/qualifierCollector.js +123 -0
- package/dist/packlets/qualifiers/qualifierDecl.js +23 -0
- package/dist/packlets/qualifiers/qualifierDefaultValueDecls.js +23 -0
- package/dist/packlets/qualifiers/qualifierDefaultValueToken.js +175 -0
- package/dist/packlets/resource-json/compiled/common.js +23 -0
- package/dist/packlets/resource-json/compiled/convert.js +132 -0
- package/dist/packlets/resource-json/compiled/index.js +26 -0
- package/dist/packlets/resource-json/compiled/json.js +2 -0
- package/dist/packlets/resource-json/convert.js +171 -0
- package/dist/packlets/resource-json/helpers.js +241 -0
- package/dist/packlets/resource-json/index.js +31 -0
- package/dist/packlets/resource-json/json.js +36 -0
- package/dist/packlets/resource-json/normalized.js +23 -0
- package/dist/packlets/resource-json/resourceDeclCollection.js +88 -0
- package/dist/packlets/resource-json/resourceDeclContainer.js +23 -0
- package/dist/packlets/resource-json/resourceDeclTree.js +94 -0
- package/dist/packlets/resource-types/config/convert.js +35 -0
- package/dist/packlets/resource-types/config/index.js +25 -0
- package/dist/packlets/resource-types/config/json.js +23 -0
- package/dist/packlets/resource-types/helpers.js +42 -0
- package/dist/packlets/resource-types/index.js +28 -0
- package/dist/packlets/resource-types/jsonResourceType.js +66 -0
- package/dist/packlets/resource-types/resourceType.js +95 -0
- package/dist/packlets/resource-types/resourceTypeCollector.js +61 -0
- package/dist/packlets/resources/candidateReducer.js +246 -0
- package/dist/packlets/resources/candidateValue.js +92 -0
- package/dist/packlets/resources/candidateValueCollector.js +94 -0
- package/dist/packlets/resources/common.js +23 -0
- package/dist/packlets/resources/deltaGenerator.js +338 -0
- package/dist/packlets/resources/index.js +31 -0
- package/dist/packlets/resources/resource.js +207 -0
- package/dist/packlets/resources/resourceBuilder.js +183 -0
- package/dist/packlets/resources/resourceCandidate.js +216 -0
- package/dist/packlets/resources/resourceManagerBuilder.js +890 -0
- package/dist/packlets/runtime/cacheListener.js +58 -0
- package/dist/packlets/runtime/cacheMetrics.js +149 -0
- package/dist/packlets/runtime/compiledResourceCollection.js +473 -0
- package/dist/packlets/runtime/conditionSetResolutionResult.js +134 -0
- package/dist/packlets/runtime/context/contextQualifierProvider.js +29 -0
- package/dist/packlets/runtime/context/contextQualifierProviderValidator.js +146 -0
- package/dist/packlets/runtime/context/index.js +26 -0
- package/dist/packlets/runtime/context/simpleContextQualifierProvider.js +196 -0
- package/dist/packlets/runtime/context/validatingSimpleContextQualifierProvider.js +60 -0
- package/dist/packlets/runtime/iResourceManager.js +23 -0
- package/dist/packlets/runtime/index.js +34 -0
- package/dist/packlets/runtime/resource-tree/common.js +23 -0
- package/dist/packlets/runtime/resource-tree/index.js +26 -0
- package/dist/packlets/runtime/resource-tree/readOnlyResourceTree.js +216 -0
- package/dist/packlets/runtime/resource-tree/resourceTreeChildren.js +97 -0
- package/dist/packlets/runtime/resource-tree/resourceTreeChildrenValidator.js +161 -0
- package/dist/packlets/runtime/resourceResolver.js +481 -0
- package/dist/packlets/runtime/resourceTreeResolver.js +220 -0
- package/dist/packlets/runtime/validate.js +47 -0
- package/dist/packlets/zip-archive/convert.js +100 -0
- package/dist/packlets/zip-archive/index.browser.js +54 -0
- package/dist/packlets/zip-archive/index.js +47 -0
- package/dist/packlets/zip-archive/json.js +23 -0
- package/dist/packlets/zip-archive/types.js +36 -0
- package/dist/packlets/zip-archive/zipArchiveCreator.js +191 -0
- package/dist/packlets/zip-archive/zipArchiveFormat.js +140 -0
- package/dist/packlets/zip-archive/zipArchiveLoader.js +282 -0
- package/dist/test/data/sample.json +32 -0
- package/dist/test/unit/qualifier-types/testQualifierType.js +76 -0
- package/dist/test/unit/resource-types/testDerivedResourceType.js +109 -0
- package/dist/test/unit/resources/deltaGenerator.helpers.js +282 -0
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/index.browser.d.ts +24 -0
- package/lib/index.browser.js +116 -0
- package/lib/packlets/config/index.browser.d.ts +7 -0
- package/lib/packlets/config/index.browser.js +74 -0
- package/lib/packlets/import/importers/index.browser.d.ts +4 -0
- package/lib/packlets/import/importers/index.browser.js +45 -0
- package/lib/packlets/import/index.browser.d.ts +7 -0
- package/lib/packlets/import/index.browser.js +74 -0
- package/lib/packlets/zip-archive/index.browser.d.ts +27 -0
- package/lib/packlets/zip-archive/index.browser.js +102 -0
- package/package.json +21 -7
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { captureResult, mapResults, fail, succeed, useOrInitialize } from '@fgv/ts-utils';
|
|
23
|
+
import { FileTree } from '@fgv/ts-json-base';
|
|
24
|
+
import { Helpers as CommonHelpers, Validate } from '../common';
|
|
25
|
+
import * as Conditions from '../conditions';
|
|
26
|
+
import { ImportContext } from './importContext';
|
|
27
|
+
/**
|
|
28
|
+
* Class describing some file system item to be imported.
|
|
29
|
+
* @public
|
|
30
|
+
*/
|
|
31
|
+
export class FsItem {
|
|
32
|
+
/**
|
|
33
|
+
* Protected constructor creates a new {@link Import.FsItem | FsItem}.
|
|
34
|
+
* @param props - The {@link Import.IFsItemProps | file system item properties} to use for this item.
|
|
35
|
+
* @param qualifiers - The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} used to parse
|
|
36
|
+
* embedded condition set tokens.
|
|
37
|
+
* @param tree - file tree implementation to use for this item.
|
|
38
|
+
* @returns `Success` containing the new {@link Import.FsItem | FsItem} if successful, or a `Failure`
|
|
39
|
+
* containing an error message if not.
|
|
40
|
+
*/
|
|
41
|
+
constructor(props, qualifiers) {
|
|
42
|
+
const { baseName, conditions, item } = props;
|
|
43
|
+
this.baseName = baseName;
|
|
44
|
+
this.conditions = conditions;
|
|
45
|
+
this.item = item;
|
|
46
|
+
this.qualifiers = qualifiers;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates a new {@link Import.FsItem | FsItem} from a `FileTreeItem`.
|
|
50
|
+
* @param item - The `FileTreeItem` to import.
|
|
51
|
+
* @param qualifiers - The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} used to parse
|
|
52
|
+
* embedded condition set tokens.
|
|
53
|
+
* @returns `Success` containing the new {@link Import.FsItem | FsItem} if successful, or a `Failure`
|
|
54
|
+
* containing an error message if not. Note that the result detail `skipped` indicates that the item
|
|
55
|
+
* was not created because it is not relevant - this is a soft error that should be silently ignored.
|
|
56
|
+
*/
|
|
57
|
+
static createForItem(item, qualifiers) {
|
|
58
|
+
const baseName = item.type === 'file' ? item.baseName : item.name;
|
|
59
|
+
return FsItem.tryParseBaseName(baseName, qualifiers)
|
|
60
|
+
.withErrorFormat((msg) => `${baseName}: error extracting conditions - ${msg}`)
|
|
61
|
+
.onSuccess(({ baseName: newBaseName, conditions }) => {
|
|
62
|
+
return captureResult(() => new FsItem({ baseName: newBaseName, conditions, item }, qualifiers));
|
|
63
|
+
})
|
|
64
|
+
.withDetail('failed', 'succeeded');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new {@link Import.FsItem | FsItem} from a file system path.
|
|
68
|
+
* @param importPath - The path to the file system item to import.
|
|
69
|
+
* @param qualifiers - The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} used to parse
|
|
70
|
+
* embedded condition set tokens.
|
|
71
|
+
* @param fs - An optional {@link Import.IImporterFilesystem | file system implementation} to use for this item.
|
|
72
|
+
* @returns `Success` containing the new {@link Import.FsItem | FsItem} if an item is created
|
|
73
|
+
* successfully, or a `Failure` containing an error message if it is not. Note that the result detail
|
|
74
|
+
* `skipped` indicates that the item was not created because it is not relevant - this is a soft error
|
|
75
|
+
* that should be silently ignored.
|
|
76
|
+
*/
|
|
77
|
+
static createForPath(importPath, qualifiers, tree) {
|
|
78
|
+
return useOrInitialize(tree, () => FileTree.forFilesystem())
|
|
79
|
+
.withDetail('failed', 'succeeded')
|
|
80
|
+
.onSuccess((tree) => {
|
|
81
|
+
return tree
|
|
82
|
+
.getItem(importPath)
|
|
83
|
+
.withDetail('failed')
|
|
84
|
+
.onSuccess((item) => FsItem.createForItem(item, qualifiers));
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Tries to parse a base name into a base name and a set of conditions.
|
|
89
|
+
* @param baseName - The base name to parse.
|
|
90
|
+
* @param qualifiers - The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} used to parse
|
|
91
|
+
* embedded condition set tokens.
|
|
92
|
+
* @returns `Success` containing the parsed base name and conditions on success, or `Failure` containing
|
|
93
|
+
* an error message if it is not.
|
|
94
|
+
*/
|
|
95
|
+
static tryParseBaseName(baseName, qualifiers) {
|
|
96
|
+
const nameParts = baseName.split('.');
|
|
97
|
+
const segmentToTest = nameParts.length > 1 ? nameParts[nameParts.length - 1] : nameParts[0];
|
|
98
|
+
const validatedConditions = CommonHelpers.parseConditionSetTokenParts(segmentToTest).onSuccess((parts) => {
|
|
99
|
+
return mapResults(parts.map((part) => Conditions.ConditionTokens.validateConditionTokenParts(part, qualifiers))).onFailure((msg) => {
|
|
100
|
+
if (parts.length === 1 && parts[0].qualifier === undefined) {
|
|
101
|
+
return succeed([]);
|
|
102
|
+
}
|
|
103
|
+
return fail(msg);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
if (validatedConditions.isFailure()) {
|
|
107
|
+
return fail(validatedConditions.message);
|
|
108
|
+
}
|
|
109
|
+
const conditions = validatedConditions.value;
|
|
110
|
+
if (conditions.length > 0) {
|
|
111
|
+
baseName = nameParts.filter((s) => s !== segmentToTest).join('.');
|
|
112
|
+
}
|
|
113
|
+
return succeed({ baseName, conditions });
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Gets the context for this file system item.
|
|
117
|
+
* @returns `Success` containing the {@link Import.ImportContext | import context} for this item
|
|
118
|
+
* if successful, or a `Failure` containing an error message if an error occurs.
|
|
119
|
+
*/
|
|
120
|
+
getContext() {
|
|
121
|
+
return Validate.toOptionalResourceId(this.baseName).onSuccess((baseId) => {
|
|
122
|
+
const conditions = this.conditions.map((c) => {
|
|
123
|
+
return {
|
|
124
|
+
qualifierName: c.qualifier.name,
|
|
125
|
+
value: c.value,
|
|
126
|
+
operator: c.operator,
|
|
127
|
+
priority: c.priority
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
return ImportContext.create({ baseId, conditions });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=fsItem.js.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { Helpers } from '../common';
|
|
23
|
+
import { captureResult, succeed } from '@fgv/ts-utils';
|
|
24
|
+
/**
|
|
25
|
+
* Class to accumulate context for a resource import operation.
|
|
26
|
+
* @public
|
|
27
|
+
*/
|
|
28
|
+
export class ImportContext {
|
|
29
|
+
/**
|
|
30
|
+
* Protected {@link Import.ImportContext | import context} for derived classes.
|
|
31
|
+
* Public consumers use {@link Import.ImportContext.create | create} to create new instances.
|
|
32
|
+
* @param baseId - The base ID for the import context.
|
|
33
|
+
* @param conditions - Conditions to be applied to resources imported in this context.
|
|
34
|
+
*/
|
|
35
|
+
constructor({ baseId, conditions }) {
|
|
36
|
+
this.baseId = Helpers.joinOptionalResourceIds(baseId).orThrow();
|
|
37
|
+
this.conditions = Array.from(conditions !== null && conditions !== void 0 ? conditions : []);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Factory method to create a new {@link Import.ImportContext | import context}.
|
|
41
|
+
* @param context - The {@link Import.IImportContext | import context} to create
|
|
42
|
+
* the new context from.
|
|
43
|
+
* @returns `Success` with the new {@link Import.ImportContext | import context}
|
|
44
|
+
* if successful, or `Failure` with an error message if creation fails.
|
|
45
|
+
*/
|
|
46
|
+
static create(context) {
|
|
47
|
+
/* c8 ignore next */
|
|
48
|
+
context = context !== null && context !== void 0 ? context : { conditions: [] };
|
|
49
|
+
return captureResult(() => new ImportContext(context));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Adds conditions to the import context.
|
|
53
|
+
* @param conditions - Conditions to be added to the import context.
|
|
54
|
+
* @returns `Success` with a new {@link Import.ImportContext | import context} containing the added conditions
|
|
55
|
+
* if successful, or `Failure` with an error message if the operation fails.
|
|
56
|
+
*/
|
|
57
|
+
withConditions(conditions) {
|
|
58
|
+
return ImportContext.create({
|
|
59
|
+
baseId: this.baseId,
|
|
60
|
+
conditions: [...this.conditions, ...conditions]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Appends names to the base ID of the import context.
|
|
65
|
+
* @param name - The base name to set.
|
|
66
|
+
* @returns `Success` with a new {@link Import.ImportContext | import context} containing the new base ID
|
|
67
|
+
* if successful, or `Failure` with an error message if the operation fails.
|
|
68
|
+
*/
|
|
69
|
+
withName(...names) {
|
|
70
|
+
return Helpers.joinResourceIds(this.baseId, ...names).onSuccess((baseId) => {
|
|
71
|
+
return ImportContext.create({ baseId, conditions: this.conditions });
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Extends the import context with additional name segments and conditions.
|
|
76
|
+
* @param context - The {@link Import.IImportContext | import context} to extend this context with.
|
|
77
|
+
* @returns `Success` with a new {@link Import.ImportContext | import context}
|
|
78
|
+
* containing the extended context if successful, or `Failure` with an error
|
|
79
|
+
* message if the operation fails.
|
|
80
|
+
*/
|
|
81
|
+
extend(context) {
|
|
82
|
+
/* c8 ignore next 1 */
|
|
83
|
+
context = context !== null && context !== void 0 ? context : { conditions: [] };
|
|
84
|
+
const conditions = [...this.conditions, ...context.conditions];
|
|
85
|
+
return Helpers.joinOptionalResourceIds(this.baseId, context.baseId).onSuccess((baseId) => {
|
|
86
|
+
return ImportContext.create({ baseId, conditions });
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Creates a new {@link Import.ImportContext | import context} to import resources from a
|
|
91
|
+
* container with the specified {@link ResourceJson.Normalized.IContainerContextDecl | container context declaration}e
|
|
92
|
+
* @param container - The {@link ResourceJson.Normalized.IContainerContextDecl | container context declaration}
|
|
93
|
+
* to consider when creating the new context.
|
|
94
|
+
* @param importer - The base {@link Import.ImportContext | import context} to adjust for the container
|
|
95
|
+
* context.
|
|
96
|
+
* @returns `Success` with the new {@link Import.ImportContext | import context} if successful,
|
|
97
|
+
* or `Failure` with an error message if the operation fails.
|
|
98
|
+
* @remarks
|
|
99
|
+
* A container context declaration may specify a merge method, which determines how the
|
|
100
|
+
* container context is merged with the base context. The merge method can be one of the following:
|
|
101
|
+
* - `augment`: The base context is augmented with the container context. This is the default behavior.
|
|
102
|
+
* - `replace`: The base context is selectively replaced with the container context. If the container context
|
|
103
|
+
* specifies a base ID or conditions, the corresponding values in the base context are ignored.
|
|
104
|
+
* - `delete`: The base context is deleted. This means that the container context is not used at all.
|
|
105
|
+
*/
|
|
106
|
+
static forContainerImport(container, importer) {
|
|
107
|
+
var _a;
|
|
108
|
+
if (!importer) {
|
|
109
|
+
return succeed(undefined);
|
|
110
|
+
}
|
|
111
|
+
/* c8 ignore next 1 */
|
|
112
|
+
container = container !== null && container !== void 0 ? container : {};
|
|
113
|
+
const mergeMethod = (_a = container.mergeMethod) !== null && _a !== void 0 ? _a : 'augment';
|
|
114
|
+
switch (mergeMethod) {
|
|
115
|
+
case 'augment':
|
|
116
|
+
return succeed(importer);
|
|
117
|
+
case 'replace': {
|
|
118
|
+
// if the container defines baseId or conditions, then we ignore
|
|
119
|
+
// the corresponding values in the importer
|
|
120
|
+
const baseId = container.baseId ? undefined : importer.baseId;
|
|
121
|
+
const conditions = container.conditions ? undefined : importer.conditions;
|
|
122
|
+
return ImportContext.create({ baseId, conditions });
|
|
123
|
+
}
|
|
124
|
+
case 'delete':
|
|
125
|
+
return succeed(undefined);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=importContext.js.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { captureResult, MessageAggregator, succeed } from '@fgv/ts-utils';
|
|
23
|
+
import { ImportContext } from './importContext';
|
|
24
|
+
import { FsItemImporter } from './importers/fsItemImporter';
|
|
25
|
+
import { CollectionImporter, JsonImporter, PathImporter } from './importers';
|
|
26
|
+
/**
|
|
27
|
+
* Class to manage the import of resources from various sources.
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export class ImportManager {
|
|
31
|
+
/**
|
|
32
|
+
* The list of {@link Import.Importers.IImporter | importers} to use for the
|
|
33
|
+
* import operations.
|
|
34
|
+
*/
|
|
35
|
+
get importers() {
|
|
36
|
+
return this._importers;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Protected constructor for the {@link Import.ImportManager | ImportManager}.
|
|
40
|
+
* @param params - Parameters for creating the {@link Import.ImportManager | ImportManager}.
|
|
41
|
+
*/
|
|
42
|
+
constructor(params) {
|
|
43
|
+
var _a, _b;
|
|
44
|
+
this._stack = [];
|
|
45
|
+
this._importers = [];
|
|
46
|
+
this.resources = params.resources;
|
|
47
|
+
this.initialContext = (_a = params.initialContext) !== null && _a !== void 0 ? _a : ImportContext.create().orThrow();
|
|
48
|
+
this._importers = Array.from((_b = params.importers) !== null && _b !== void 0 ? _b : ImportManager.getDefaultImporters(this.resources.qualifiers, params.fileTree));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Factory method to create a new {@link Import.ImportManager | ImportManager}.
|
|
52
|
+
* @param params - Parameters for creating the {@link Import.ImportManager | ImportManager}.
|
|
53
|
+
* @returns `Success` with the new {@link Import.ImportManager | ImportManager}
|
|
54
|
+
* if successful, or `Failure` with an error message if creation fails.
|
|
55
|
+
*/
|
|
56
|
+
static create(params) {
|
|
57
|
+
return captureResult(() => new ImportManager(params));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Imports resources from an {@link Import.IImportable | importable} object.
|
|
61
|
+
* @param importable - The {@link Import.IImportable | importable} object to import.
|
|
62
|
+
* @returns `Success` with the {@link Import.ImportManager | ImportManager} if successful,
|
|
63
|
+
* or `Failure` with an error message if the import fails.
|
|
64
|
+
*/
|
|
65
|
+
import(importable) {
|
|
66
|
+
this._stack.push(importable);
|
|
67
|
+
return this._import();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Imports resources from a file system path.
|
|
71
|
+
* @param filePath - The path to import resources from.
|
|
72
|
+
* @returns `Success` with the {@link Import.ImportManager | ImportManager} if successful,
|
|
73
|
+
* or `Failure` with an error message if the import fails.
|
|
74
|
+
*/
|
|
75
|
+
importFromFileSystem(filePath) {
|
|
76
|
+
const importable = { type: 'path', path: filePath };
|
|
77
|
+
return this.import(importable);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Gets the default importers using supplied {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers}
|
|
81
|
+
* and optional `FileTree`.
|
|
82
|
+
* @param qualifiers - The {@link Qualifiers.IReadOnlyQualifierCollector | qualifiers} to use for the import.
|
|
83
|
+
* @param tree - An optional `FileTree` for importing path items.
|
|
84
|
+
* @returns A read-only array of {@link Import.Importers.IImporter | importers}.
|
|
85
|
+
*/
|
|
86
|
+
static getDefaultImporters(qualifiers, tree) {
|
|
87
|
+
return [
|
|
88
|
+
PathImporter.create({ qualifiers, tree }).orThrow(),
|
|
89
|
+
FsItemImporter.create({ qualifiers }).orThrow(),
|
|
90
|
+
JsonImporter.create().orThrow(),
|
|
91
|
+
CollectionImporter.create().orThrow()
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Imports any items on the import stack.
|
|
96
|
+
* @returns `Success` with the {@link Import.ImportManager | ImportManager} if successful,
|
|
97
|
+
* or `Failure` with an error message if the import fails.
|
|
98
|
+
* @public
|
|
99
|
+
*/
|
|
100
|
+
_import() {
|
|
101
|
+
const errors = new MessageAggregator();
|
|
102
|
+
while (this._stack.length > 0) {
|
|
103
|
+
const item = this._stack.pop();
|
|
104
|
+
if (item !== undefined) {
|
|
105
|
+
let processed = false;
|
|
106
|
+
let consumed = false;
|
|
107
|
+
for (const importer of this._importers) {
|
|
108
|
+
if (consumed || !importer.types.includes(item.type)) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const result = importer.import(item, this.resources).aggregateError(errors);
|
|
112
|
+
processed = processed || result.detail !== 'skipped';
|
|
113
|
+
consumed = consumed || result.detail === 'consumed';
|
|
114
|
+
if (result.isSuccess()) {
|
|
115
|
+
this._stack.push(...result.value);
|
|
116
|
+
}
|
|
117
|
+
else if (result.detail !== 'skipped') {
|
|
118
|
+
errors.addMessage(`${item.type}: ${result.message}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (!processed) {
|
|
122
|
+
errors.addMessage(`${item.type}: No matching importer found`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return errors.returnOrReport(succeed(this));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=importManager.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Type guard for {@link Import.Importable | importables}.
|
|
24
|
+
* @param i - The entity to check.
|
|
25
|
+
* @returns `true` if the supplied {@link Import.IImportable | IImportable} is a
|
|
26
|
+
* {@link Import.Importable | known importable}, `false` otherwise.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export function isImportable(i) {
|
|
30
|
+
return ['path', 'fsItem', 'json', 'resourceCollection', 'resourceTree'].includes(i.type);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=importable.js.map
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { captureResult, failWithDetail, MessageAggregator, succeed } from '@fgv/ts-utils';
|
|
23
|
+
import { isImportable } from '../importable';
|
|
24
|
+
import * as ResourceJson from '../../resource-json';
|
|
25
|
+
import { ImportContext } from '../importContext';
|
|
26
|
+
/**
|
|
27
|
+
* {@link Import.Importers.IImporter | Importer} implementation which imports
|
|
28
|
+
* a {@link ResourceJson.ResourceDeclCollection | resource collection} or
|
|
29
|
+
* {@link ResourceJson.ResourceDeclTree | resource tree} from an importable item.
|
|
30
|
+
* @public
|
|
31
|
+
*/
|
|
32
|
+
export class CollectionImporter {
|
|
33
|
+
/**
|
|
34
|
+
* Protected {@link Import.Importers.CollectionImporter | CollectionImporter} constructor for derived classes
|
|
35
|
+
*/
|
|
36
|
+
constructor() {
|
|
37
|
+
/**
|
|
38
|
+
* {@inheritdoc Import.Importers.IImporter.types}
|
|
39
|
+
*/
|
|
40
|
+
this.types = ['resourceCollection', 'resourceTree'];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new {@link Import.Importers.CollectionImporter | CollectionImporter} instance.
|
|
44
|
+
* @returns `Success` with the new {@link Import.Importers.CollectionImporter | CollectionImporter} if successful,
|
|
45
|
+
* `Failure` otherwise.
|
|
46
|
+
*/
|
|
47
|
+
static create() {
|
|
48
|
+
return captureResult(() => new CollectionImporter());
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* {@inheritdoc Import.Importers.IImporter.import}
|
|
52
|
+
*/
|
|
53
|
+
import(item, manager) {
|
|
54
|
+
var _a, _b;
|
|
55
|
+
if (!isImportable(item) || (item.type !== 'resourceCollection' && item.type !== 'resourceTree')) {
|
|
56
|
+
/* c8 ignore next 1 - defense in depth */
|
|
57
|
+
const name = (_b = (_a = item.context) === null || _a === void 0 ? void 0 : _a.baseId) !== null && _b !== void 0 ? _b : 'unknown';
|
|
58
|
+
return failWithDetail(`${name}: invalid resource collection importable (${item.type})`, 'skipped');
|
|
59
|
+
}
|
|
60
|
+
const container = item.type === 'resourceCollection' ? item.collection : item.tree;
|
|
61
|
+
return ImportContext.forContainerImport(container.context, item.context)
|
|
62
|
+
.onSuccess((context) => {
|
|
63
|
+
const errors = new MessageAggregator();
|
|
64
|
+
for (const resource of container.getImporterResources()) {
|
|
65
|
+
this._addResource(manager, resource, context).aggregateError(errors);
|
|
66
|
+
}
|
|
67
|
+
for (const candidate of container.getImporterCandidates()) {
|
|
68
|
+
this._addCandidate(manager, candidate, context).aggregateError(errors);
|
|
69
|
+
}
|
|
70
|
+
return errors.returnOrReport(succeed([]));
|
|
71
|
+
})
|
|
72
|
+
.withDetail('failed', 'consumed');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Adds a {@link ResourceJson.Normalized.IImporterResourceDecl | declared resource} to
|
|
76
|
+
* the supplied {@link Resources.ResourceManagerBuilder | resource manager builder}, merging an
|
|
77
|
+
* optional {@link Import.ImportContext | import context} if provided.
|
|
78
|
+
* @param manager - The {@link Resources.ResourceManagerBuilder | resource manager builder} to which
|
|
79
|
+
* the resource will be added.
|
|
80
|
+
* @param resource - The {@link ResourceJson.Normalized.IImporterResourceDecl | resource}
|
|
81
|
+
* to add.
|
|
82
|
+
* @param context - Optional {@link Import.ImportContext | import context} to merge
|
|
83
|
+
* with the resource.
|
|
84
|
+
* @returns `Success` with the {@link Resources.ResourceBuilder | resource builder}
|
|
85
|
+
* for the resource if successful, `Failure` with an error message if not.
|
|
86
|
+
*/
|
|
87
|
+
_addResource(manager, resource, context) {
|
|
88
|
+
if (context) {
|
|
89
|
+
return ResourceJson.Helpers.mergeLooseResource(resource, context.baseId, context.conditions).onSuccess((merged) => manager.addResource(merged));
|
|
90
|
+
} /* c8 ignore next 4 - defense in depth, should be guarded elsewhere */
|
|
91
|
+
else if (!ResourceJson.Json.isLooseResourceDecl(resource)) {
|
|
92
|
+
return fail('cannot add child resource to manager');
|
|
93
|
+
}
|
|
94
|
+
return manager.addResource(resource);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Adds a {@link ResourceJson.Normalized.IImporterResourceCandidateDecl | declared resource candidate}
|
|
98
|
+
* to the supplied {@link Resources.ResourceManagerBuilder | resource manager builder}, merging an optional
|
|
99
|
+
* {@link Import.ImportContext | import context} if provided.
|
|
100
|
+
* @param manager - The {@link Resources.ResourceManagerBuilder | resource manager builder} to which the
|
|
101
|
+
* candidate will be added.
|
|
102
|
+
* @param candidate - The {@link ResourceJson.Normalized.IImporterResourceCandidateDecl | candidate}
|
|
103
|
+
* to add.
|
|
104
|
+
* @param context - Optional {@link Import.ImportContext | import context} to merge with the candidate.
|
|
105
|
+
* @returns `Success` with the {@link Resources.ResourceCandidate | resource candidate} if successful,
|
|
106
|
+
* `Failure` with an error message if not.
|
|
107
|
+
*/
|
|
108
|
+
_addCandidate(manager, candidate, context) {
|
|
109
|
+
if (context) {
|
|
110
|
+
return ResourceJson.Helpers.mergeLooseCandidate(candidate, context.baseId, context.conditions).onSuccess((merged) => manager.addLooseCandidate(merged));
|
|
111
|
+
} /* c8 ignore next 4 - defense in depth, should be guarded elsewhere */
|
|
112
|
+
else if (!ResourceJson.Json.isLooseResourceCandidateDecl(candidate)) {
|
|
113
|
+
return fail('cannot add child resource candidate to manager');
|
|
114
|
+
}
|
|
115
|
+
return manager.addLooseCandidate(candidate);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=collectionImporter.js.map
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2025 Erik Fortune
|
|
3
|
+
*
|
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
* furnished to do so, subject to the following conditions:
|
|
10
|
+
*
|
|
11
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
* copies or substantial portions of the Software.
|
|
13
|
+
*
|
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
* SOFTWARE.
|
|
21
|
+
*/
|
|
22
|
+
import { captureResult, failWithDetail, succeed, succeedWithDetail, MessageAggregator } from '@fgv/ts-utils';
|
|
23
|
+
import { Converters as JsonConverters } from '@fgv/ts-json-base';
|
|
24
|
+
import { FsItem } from '../fsItem';
|
|
25
|
+
/**
|
|
26
|
+
* {@link Import.Importers.IImporter | Importer} implementation which imports resources from a `FileTree`.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export class FsItemImporter {
|
|
30
|
+
/**
|
|
31
|
+
* Protected constructor for the {@link Import.Importers.FsItemImporter | FsItemImporter}.
|
|
32
|
+
* @param params - Parameters for creating the {@link Import.Importers.FsItemImporter | FsItemImporter}.
|
|
33
|
+
*/
|
|
34
|
+
constructor(params) {
|
|
35
|
+
/**
|
|
36
|
+
* The types of {@link Import.IImportable | importables} that this importer can handle.
|
|
37
|
+
*/
|
|
38
|
+
this.types = ['fsItem'];
|
|
39
|
+
this.qualifiers = params.qualifiers;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates a new {@link Import.Importers.FsItemImporter | FsItemImporter}.
|
|
43
|
+
* @param params - Parameters for creating the {@link Import.Importers.FsItemImporter | FsItemImporter}.
|
|
44
|
+
* @returns `Success` with the new `FsItemImporter` if successful, `Failure` with an error message if not.
|
|
45
|
+
*/
|
|
46
|
+
static create(params) {
|
|
47
|
+
return captureResult(() => new FsItemImporter(params));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* {@inheritdoc Import.Importers.IImporter.import}
|
|
51
|
+
*/
|
|
52
|
+
import(item, __manager) {
|
|
53
|
+
const { value: fsItem, message: getTreeMessage, detail: getTreeDetail } = this._getFileTreeItemFromImportable(item);
|
|
54
|
+
if (getTreeMessage !== undefined) {
|
|
55
|
+
return failWithDetail(getTreeMessage, getTreeDetail === 'skipped' ? 'skipped' : 'failed');
|
|
56
|
+
}
|
|
57
|
+
const { value: context, message: getContextMessage } = fsItem.getContext().onSuccess((fsItemContext) => {
|
|
58
|
+
return item.context ? item.context.extend(fsItemContext) : succeed(fsItemContext);
|
|
59
|
+
});
|
|
60
|
+
/* c8 ignore next 3 - defensive coding: getContext failure is extremely rare in practice */
|
|
61
|
+
if (getContextMessage) {
|
|
62
|
+
return failWithDetail(getContextMessage, 'failed');
|
|
63
|
+
}
|
|
64
|
+
if (fsItem.item.type === 'directory') {
|
|
65
|
+
return fsItem.item
|
|
66
|
+
.getChildren()
|
|
67
|
+
.onSuccess((children) => {
|
|
68
|
+
const errors = new MessageAggregator();
|
|
69
|
+
const items = [];
|
|
70
|
+
for (const child of children) {
|
|
71
|
+
const { value: item, message, detail } = FsItem.createForItem(child, this.qualifiers);
|
|
72
|
+
if (item) {
|
|
73
|
+
items.push({ type: 'fsItem', item, context });
|
|
74
|
+
}
|
|
75
|
+
else if (detail !== 'skipped') {
|
|
76
|
+
errors.addMessage(message);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return errors.returnOrReport(succeed(items));
|
|
80
|
+
})
|
|
81
|
+
.withDetail('failed', 'processed');
|
|
82
|
+
}
|
|
83
|
+
else if (fsItem.item.type === 'file') {
|
|
84
|
+
if (fsItem.item.extension === '.json') {
|
|
85
|
+
return fsItem.item
|
|
86
|
+
.getContents(JsonConverters.jsonValue)
|
|
87
|
+
.onSuccess((json) => {
|
|
88
|
+
const jsonItem = {
|
|
89
|
+
type: 'json',
|
|
90
|
+
json,
|
|
91
|
+
context
|
|
92
|
+
};
|
|
93
|
+
return succeed([jsonItem]);
|
|
94
|
+
})
|
|
95
|
+
.withDetail('failed', 'processed');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/* c8 ignore next 2 - defensive coding: fallback case for unsupported file types */
|
|
99
|
+
return succeedWithDetail([], 'skipped');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Gets an {@link Import.FsItem | FsItem} from an {@link Import.IImportable | importable}.
|
|
103
|
+
* @param item - The importable to convert.
|
|
104
|
+
* @returns `Success` containing the `FsItem` if successful, `Failure` with an error message if not.
|
|
105
|
+
*/
|
|
106
|
+
_getFileTreeItemFromImportable(item) {
|
|
107
|
+
if (item.type === 'fsItem') {
|
|
108
|
+
if ('item' in item && item.item instanceof FsItem) {
|
|
109
|
+
return succeedWithDetail(item.item, 'succeeded');
|
|
110
|
+
}
|
|
111
|
+
return failWithDetail(`malformed fsItem importable does not contain a valid item`, 'failed');
|
|
112
|
+
}
|
|
113
|
+
return failWithDetail(`${item.type}: invalid importable type for an FsItemImporter`, 'skipped');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=fsItemImporter.js.map
|