@rebasepro/common 0.0.1-canary.eae7889 → 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/dist/index.es.js +18 -12
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +18 -12
- package/dist/index.umd.js.map +1 -1
- package/package.json +4 -5
- package/src/collections/CollectionRegistry.ts +11 -8
- package/src/util/conditions.ts +8 -5
- package/src/util/entities.ts +3 -3
- package/src/util/references.ts +1 -1
- package/src/util/relations.ts +5 -5
- package/src/util/resolutions.ts +4 -4
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/common",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"description": "Awesome Firebase/Firestore-based headless open-source CMS",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"./package.json": "./package.json"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"fast-equals": "
|
|
42
|
+
"fast-equals": "6.0.0",
|
|
43
43
|
"json-logic-js": "^2.0.5",
|
|
44
|
-
"@rebasepro/
|
|
45
|
-
"@rebasepro/
|
|
44
|
+
"@rebasepro/types": "0.1.0",
|
|
45
|
+
"@rebasepro/utils": "0.1.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@jest/globals": "^29.7.0",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"jest": "^29.7.0",
|
|
63
63
|
"npm-run-all": "^4.1.5",
|
|
64
64
|
"ts-jest": "^29.3.1",
|
|
65
|
-
"ts-node": "^10.9.2",
|
|
66
65
|
"tsd": "^0.31.2",
|
|
67
66
|
"typescript": "^5.8.3",
|
|
68
67
|
"vite": "^5.4.17"
|
|
@@ -165,7 +165,7 @@ export class CollectionRegistry {
|
|
|
165
165
|
|
|
166
166
|
// 2. Merge with manual relations[] (manual entries win on name conflict)
|
|
167
167
|
const relResult = result as CollectionWithRelations;
|
|
168
|
-
const manualRelations = getDataSourceCapabilities(result.driver).supportsRelations ? (relResult.relations ?? []) : [];
|
|
168
|
+
const manualRelations = getDataSourceCapabilities(result.driver).supportsRelations ? ((relResult as any).relations ?? []) : [];
|
|
169
169
|
const mergedRelationsRaw = [...extractedRelations];
|
|
170
170
|
for (const manual of manualRelations) {
|
|
171
171
|
const name = manual.relationName;
|
|
@@ -192,7 +192,7 @@ export class CollectionRegistry {
|
|
|
192
192
|
});
|
|
193
193
|
|
|
194
194
|
// 3. Set the merged relations on the result copy
|
|
195
|
-
relResult.relations = mergedRelations;
|
|
195
|
+
(relResult as any).relations = mergedRelations;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// 4. Normalize properties (which stamps relation on each property)
|
|
@@ -203,8 +203,8 @@ export class CollectionRegistry {
|
|
|
203
203
|
if (!result.childCollections) {
|
|
204
204
|
if (getDataSourceCapabilities(result.driver).supportsSubcollections && (result as CollectionWithSubcollections).subcollections) {
|
|
205
205
|
result.childCollections = (result as CollectionWithSubcollections).subcollections;
|
|
206
|
-
} else if (getDataSourceCapabilities(result.driver).supportsRelations && relResult.relations) {
|
|
207
|
-
const manyRelations = relResult.relations.filter((r: Relation) => r.cardinality === "many");
|
|
206
|
+
} else if (getDataSourceCapabilities(result.driver).supportsRelations && (relResult as any).relations) {
|
|
207
|
+
const manyRelations = (relResult as any).relations.filter((r: Relation) => r.cardinality === "many");
|
|
208
208
|
if (manyRelations.length > 0) {
|
|
209
209
|
result.childCollections = () => manyRelations.map((r: Relation) => {
|
|
210
210
|
const target = r.target();
|
|
@@ -375,7 +375,10 @@ export class CollectionRegistry {
|
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
// Move to the target collection
|
|
378
|
-
|
|
378
|
+
const target = relation.target();
|
|
379
|
+
const targetRelationKey = relation.relationName || target.slug;
|
|
380
|
+
const targetSlug = relation.overrides?.slug ?? targetRelationKey;
|
|
381
|
+
currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
|
|
379
382
|
|
|
380
383
|
// If there are more segments, continue navigation
|
|
381
384
|
if (i + 1 < pathSegments.length) {
|
|
@@ -447,7 +450,7 @@ export class CollectionRegistry {
|
|
|
447
450
|
if (!subcollection) {
|
|
448
451
|
throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
|
|
449
452
|
}
|
|
450
|
-
currentCollection = subcollection;
|
|
453
|
+
currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);
|
|
451
454
|
collections.push(currentCollection);
|
|
452
455
|
}
|
|
453
456
|
}
|
|
@@ -482,8 +485,8 @@ function areCollectionsEqual(a: EntityCollection, b: EntityCollection) {
|
|
|
482
485
|
// Remove subcollections/relations from comparison objects (already handled above)
|
|
483
486
|
delete restA.subcollections;
|
|
484
487
|
delete restB.subcollections;
|
|
485
|
-
delete restA.relations;
|
|
486
|
-
delete restB.relations;
|
|
488
|
+
delete (restA as any).relations;
|
|
489
|
+
delete (restB as any).relations;
|
|
487
490
|
if (!areCollectionListsEqual(subcollectionsA, subcollectionsB)) {
|
|
488
491
|
return false;
|
|
489
492
|
}
|
package/src/util/conditions.ts
CHANGED
|
@@ -178,7 +178,8 @@ export function applyPropertyConditions(
|
|
|
178
178
|
if (conditions.disabled) {
|
|
179
179
|
const isDisabled = evaluateCondition(conditions.disabled, context);
|
|
180
180
|
if (isDisabled) {
|
|
181
|
-
result.
|
|
181
|
+
result.ui = result.ui || {};
|
|
182
|
+
result.ui.disabled = {
|
|
182
183
|
clearOnDisabled: conditions.clearOnDisabled ?? false,
|
|
183
184
|
disabledMessage: conditions.disabledMessage,
|
|
184
185
|
hidden: false
|
|
@@ -190,8 +191,9 @@ export function applyPropertyConditions(
|
|
|
190
191
|
if (conditions.hidden) {
|
|
191
192
|
const isHidden = evaluateCondition(conditions.hidden, context);
|
|
192
193
|
if (isHidden) {
|
|
193
|
-
result.
|
|
194
|
-
|
|
194
|
+
result.ui = result.ui || {};
|
|
195
|
+
result.ui.disabled = {
|
|
196
|
+
...(typeof result.ui?.disabled === "object" ? result.ui.disabled : {}),
|
|
195
197
|
hidden: true,
|
|
196
198
|
clearOnDisabled: conditions.clearOnDisabled ?? false
|
|
197
199
|
};
|
|
@@ -202,7 +204,8 @@ export function applyPropertyConditions(
|
|
|
202
204
|
if (conditions.readOnly) {
|
|
203
205
|
const isReadOnly = evaluateCondition(conditions.readOnly, context);
|
|
204
206
|
if (isReadOnly) {
|
|
205
|
-
result.
|
|
207
|
+
result.ui = result.ui || {};
|
|
208
|
+
result.ui.readOnly = true;
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
|
|
@@ -250,7 +253,7 @@ export function applyPropertyConditions(
|
|
|
250
253
|
(result as ReferenceProperty).path = evaluateCondition(conditions.referencePath, context) as string;
|
|
251
254
|
}
|
|
252
255
|
if (conditions.referenceFilter) {
|
|
253
|
-
(result as ReferenceProperty).
|
|
256
|
+
(result as ReferenceProperty).fixedFilter = evaluateCondition(conditions.referenceFilter, context) as ReferenceProperty["fixedFilter"];
|
|
254
257
|
}
|
|
255
258
|
}
|
|
256
259
|
|
package/src/util/entities.ts
CHANGED
|
@@ -12,20 +12,20 @@ import { DEFAULT_ONE_OF_TYPE, DEFAULT_ONE_OF_VALUE } from "./common";
|
|
|
12
12
|
import { mergeDeep } from "@rebasepro/utils";
|
|
13
13
|
|
|
14
14
|
export function isReadOnly(property: Property): boolean {
|
|
15
|
-
if (property.readOnly)
|
|
15
|
+
if (property.ui?.readOnly)
|
|
16
16
|
return true;
|
|
17
17
|
if (property.type === "date") {
|
|
18
18
|
if (property.autoValue)
|
|
19
19
|
return true;
|
|
20
20
|
}
|
|
21
21
|
if (property.type === "reference") {
|
|
22
|
-
return !property.path && !("Field" in property && property.Field);
|
|
22
|
+
return !property.path && !("Field" in (property.ui || {}) && property.ui?.Field);
|
|
23
23
|
}
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export function isHidden(property: Property): boolean {
|
|
28
|
-
return typeof property.disabled === "object" && Boolean(property.disabled.hidden);
|
|
28
|
+
return typeof property.ui?.disabled === "object" && Boolean(property.ui?.disabled.hidden);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export function isPropertyBuilder(property?: Property) {
|
package/src/util/references.ts
CHANGED
|
@@ -19,7 +19,7 @@ export function getEntityImagePreviewPropertyKey<M extends Record<string, unknow
|
|
|
19
19
|
// also check for URL properties with image preview type
|
|
20
20
|
for (const key in collection.properties) {
|
|
21
21
|
const property = collection.properties[key];
|
|
22
|
-
if (property.type === "string" && property.url === "image") {
|
|
22
|
+
if (property.type === "string" && property.ui?.url === "image") {
|
|
23
23
|
return key;
|
|
24
24
|
}
|
|
25
25
|
}
|
package/src/util/relations.ts
CHANGED
|
@@ -41,7 +41,7 @@ export function sanitizeRelation(relation: Partial<Relation>, sourceCollection:
|
|
|
41
41
|
|
|
42
42
|
try {
|
|
43
43
|
// Look for an owning relation on the target that points back to this collection
|
|
44
|
-
const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? ((targetCollection as
|
|
44
|
+
const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? (((targetCollection as any).relations) || []) : [];
|
|
45
45
|
for (const targetRel of targetRelations) {
|
|
46
46
|
if (targetRel.direction === "owning" &&
|
|
47
47
|
targetRel.cardinality === "one" &&
|
|
@@ -85,7 +85,7 @@ export function sanitizeRelation(relation: Partial<Relation>, sourceCollection:
|
|
|
85
85
|
// Note: we intentionally do NOT require `through` here because the raw (unsanitized)
|
|
86
86
|
// relations won't have `through` populated yet — sanitizeRelation fills it in later.
|
|
87
87
|
// `cardinality: "many" + direction: "owning"` is sufficient to identify owning M2M.
|
|
88
|
-
const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? ((targetCollection as
|
|
88
|
+
const targetRelations = getDataSourceCapabilities(targetCollection.driver).supportsRelations ? (((targetCollection as any).relations) || []) : [];
|
|
89
89
|
for (const targetRel of targetRelations) {
|
|
90
90
|
if (targetRel.cardinality === "many" &&
|
|
91
91
|
(targetRel.direction === "owning" || !targetRel.direction) &&
|
|
@@ -152,8 +152,8 @@ export function resolveCollectionRelations(
|
|
|
152
152
|
|
|
153
153
|
// 1. Process explicit relations from the `relations` field.
|
|
154
154
|
// Each relation is stored once under its canonical relationName key.
|
|
155
|
-
if (relCollection.relations) {
|
|
156
|
-
relCollection.relations.forEach((relation: Relation) => {
|
|
155
|
+
if ((relCollection as any).relations) {
|
|
156
|
+
(relCollection as any).relations.forEach((relation: Relation) => {
|
|
157
157
|
const normalizedRelation = sanitizeRelation(relation, collection);
|
|
158
158
|
const relationKey = normalizedRelation.relationName;
|
|
159
159
|
if (relationKey) {
|
|
@@ -232,7 +232,7 @@ export function resolvePropertyRelation({
|
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
// 2. Fall back to lookup from collection.relations[] (backward compat)
|
|
235
|
-
const relation = ((sourceCollection as
|
|
235
|
+
const relation = (((sourceCollection as any).relations) ?? []).find((rel: Relation) => rel.relationName === relProp.relationName)
|
|
236
236
|
if (!relation) {
|
|
237
237
|
console.warn(`Unrecognized relation format for property '${propertyKey}' in collection '${sourceCollection.slug}'`);
|
|
238
238
|
return undefined;
|
package/src/util/resolutions.ts
CHANGED
|
@@ -280,7 +280,7 @@ export function resolveArrayProperties<M>({
|
|
|
280
280
|
}).filter(e => Boolean(e)) as Property[]
|
|
281
281
|
: [];
|
|
282
282
|
return resolvedProperties;
|
|
283
|
-
} else if (!("Field" in property && property.Field)) {
|
|
283
|
+
} else if (!("Field" in (property.ui || {}) && property.ui?.Field)) {
|
|
284
284
|
throw Error(`The array property (${propertyKey}) needs to declare an 'of' or a 'oneOf' property, or provide a custom \`Field\` component`);
|
|
285
285
|
} else {
|
|
286
286
|
return [];
|
|
@@ -350,8 +350,8 @@ export function getSubcollections<M extends Record<string, unknown> = Record<str
|
|
|
350
350
|
return (collection as CollectionWithSubcollections).subcollections!() ?? [];
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
if (getDataSourceCapabilities(collection.driver).supportsRelations && (collection as
|
|
354
|
-
const manyRelations = (collection as
|
|
353
|
+
if (getDataSourceCapabilities(collection.driver).supportsRelations && ((collection as any).relations)) {
|
|
354
|
+
const manyRelations = ((collection as any).relations)!.filter((r: Relation) => r.cardinality === "many");
|
|
355
355
|
return manyRelations.map((r: Relation) => {
|
|
356
356
|
const target = r.target();
|
|
357
357
|
if (!target) return undefined;
|
|
@@ -376,7 +376,7 @@ export function getSubcollections<M extends Record<string, unknown> = Record<str
|
|
|
376
376
|
|
|
377
377
|
const targetWithOverrides = { ...target, ...baseOverrides };
|
|
378
378
|
return (r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides) as EntityCollection<Record<string, unknown>>;
|
|
379
|
-
}).filter((c): c is EntityCollection<Record<string, unknown>> => Boolean(c));
|
|
379
|
+
}).filter((c: any): c is EntityCollection<Record<string, unknown>> => Boolean(c));
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
return [];
|