node_modules ignore

This commit is contained in:
oier committed 2025-05-08 23:43:47 +02:00
1 parent e19d52f172
commit 4574544c9f
65041 files changed
+10593536

No files matched your search

+89
View File
@@ -0,0 +1,89 @@
import { AnyAttribute, Attribute, ComponentAttribute, DynamicZoneAttribute, Model, RelationalAttribute } from '../types';
export interface Path {
raw: string | null;
attribute: string | null;
}
export interface Parent {
attribute?: Attribute;
key: string | null;
path: Path;
schema: Model;
}
export interface TraverseOptions {
schema: Model;
path?: Path;
parent?: Parent;
getModel(uid: string): Model;
}
export interface VisitorOptions {
data: unknown;
value: unknown;
schema: Model;
key: string;
attribute?: AnyAttribute;
path: Path;
parent?: Parent;
getModel(uid: string): Model;
}
export type Traverse = (visitor: Visitor, options: TraverseOptions, data: unknown) => Promise<unknown>;
export interface Visitor {
(visitorOptions: VisitorOptions, opts: Pick<TransformUtils, 'set' | 'remove'>): void;
}
interface Interceptor<T = unknown> {
predicate(data: unknown): data is T;
handler(visitor: Visitor, options: TraverseOptions, data: T, recurseOptions: {
recurse: Traverse;
}): void;
}
interface ParseUtils<T> {
transform(data: T): unknown;
remove(key: string, data: T): unknown;
set(key: string, value: unknown, data: T): unknown;
keys(data: T): string[];
get(key: string, data: T): unknown;
}
interface Parser<T = unknown> {
predicate(data: unknown): data is T;
parser(data: T): ParseUtils<T>;
}
interface Ignore {
(ctx: Context): boolean;
}
interface AttributeHandler<AttributeType = Attribute> {
predicate(ctx: Context<AttributeType>): boolean;
handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;
}
interface CommonHandler<AttributeType = Attribute> {
predicate(ctx: Context<AttributeType>): boolean;
handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;
}
export interface TransformUtils {
remove(key: string): void;
set(key: string, value: unknown): void;
recurse: Traverse;
}
interface Context<AttributeType = Attribute> {
key: string;
value: unknown;
attribute: AttributeType;
schema: Model;
path: Path;
data: unknown;
visitor: Visitor;
parent?: Parent;
getModel(uid: string): Model;
}
declare const _default: () => {
traverse: Traverse;
intercept<T>(predicate: Interceptor<T>['predicate'], handler: Interceptor<T>['handler']): any;
parse<T_1>(predicate: (data: unknown) => data is T_1, parser: (data: T_1) => ParseUtils<T_1>): any;
ignore(predicate: Ignore): any;
on(predicate: CommonHandler['predicate'], handler: CommonHandler['handler']): any;
onAttribute(predicate: AttributeHandler['predicate'], handler: AttributeHandler['handler']): any;
onRelation(handler: AttributeHandler<RelationalAttribute>['handler']): any;
onMedia(handler: AttributeHandler<RelationalAttribute>['handler']): any;
onComponent(handler: AttributeHandler<ComponentAttribute>['handler']): any;
onDynamicZone(handler: AttributeHandler<DynamicZoneAttribute>['handler']): any;
};
export default _default;
//# sourceMappingURL=factory.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/traverse/factory.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,YAAY,EACZ,SAAS,EACT,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,EACL,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,IAAI;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,MAAM;IACrB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,KAAK,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,KAAK,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAED,MAAM,MAAM,QAAQ,GAAG,CACrB,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,OAAO,KACV,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,MAAM,WAAW,OAAO;IACtB,CAAC,cAAc,EAAE,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC;CACtF;AAED,UAAU,WAAW,CAAC,CAAC,GAAG,OAAO;IAC/B,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC;IACpC,OAAO,CACL,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,CAAC,EACP,cAAc,EAAE;QAAE,OAAO,EAAE,QAAQ,CAAA;KAAE,GACpC,IAAI,CAAC;CACT;AAED,UAAU,UAAU,CAAC,CAAC;IACpB,SAAS,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;IAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;IACtC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;IACnD,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC;CACpC;AAED,UAAU,MAAM,CAAC,CAAC,GAAG,OAAO;IAC1B,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC;IACpC,MAAM,CAAC,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;CAChC;AAED,UAAU,MAAM;IACd,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;CACzB;AAED,UAAU,gBAAgB,CAAC,aAAa,GAAG,SAAS;IAClD,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC;IAChD,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;CAC3F;AACD,UAAU,aAAa,CAAC,aAAa,GAAG,SAAS;IAC/C,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC;IAChD,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC;CAC3F;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACvC,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED,UAAU,OAAO,CAAC,aAAa,GAAG,SAAS;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,aAAa,CAAC;IACzB,MAAM,EAAE,KAAK,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;;;4BA4H2B,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC;;sBAUrE,MAAM;kBAKV,aAAa,CAAC,WAAW,CAAC,WAAW,aAAa,CAAC,SAAS,CAAC;2BAKpD,gBAAgB,CAAC,WAAW,CAAC,WAAW,gBAAgB,CAAC,SAAS,CAAC;wBAKtE,iBAAiB,mBAAmB,CAAC,CAAC,SAAS,CAAC;qBAInD,iBAAiB,mBAAmB,CAAC,CAAC,SAAS,CAAC;yBAI5C,iBAAiB,kBAAkB,CAAC,CAAC,SAAS,CAAC;2BAI7C,iBAAiB,oBAAoB,CAAC,CAAC,SAAS,CAAC;;AAnJ5E,wBAuJE"}
+158
View File
@@ -0,0 +1,158 @@
'use strict';
var fp = require('lodash/fp');
const DEFAULT_PATH = {
raw: null,
attribute: null
};
var traverseFactory = (()=>{
const state = {
parsers: [],
interceptors: [],
ignore: [],
handlers: {
attributes: [],
common: []
}
};
const traverse = async (visitor, options, data)=>{
const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};
// interceptors
for (const { predicate, handler } of state.interceptors){
if (predicate(data)) {
return handler(visitor, options, data, {
recurse: traverse
});
}
}
// parsers
const parser = state.parsers.find((parser)=>parser.predicate(data))?.parser;
const utils = parser?.(data);
// Return the data untouched if we don't know how to traverse it
if (!utils) {
return data;
}
// main loop
let out = utils.transform(data);
const keys = utils.keys(out);
for (const key of keys){
const attribute = schema?.attributes?.[key];
const newPath = {
...path
};
newPath.raw = fp.isNil(path.raw) ? key : `${path.raw}.${key}`;
if (!fp.isNil(attribute)) {
newPath.attribute = fp.isNil(path.attribute) ? key : `${path.attribute}.${key}`;
}
// visitors
const visitorOptions = {
key,
value: utils.get(key, out),
attribute,
schema,
path: newPath,
data: out,
getModel,
parent
};
const transformUtils = {
remove (key) {
out = utils.remove(key, out);
},
set (key, value) {
out = utils.set(key, value, out);
},
recurse: traverse
};
await visitor(visitorOptions, fp.pick([
'remove',
'set'
], transformUtils));
const value = utils.get(key, out);
const createContext = ()=>({
key,
value,
attribute,
schema,
path: newPath,
data: out,
visitor,
getModel,
parent
});
// ignore
const ignoreCtx = createContext();
const shouldIgnore = state.ignore.some((predicate)=>predicate(ignoreCtx));
if (shouldIgnore) {
continue;
}
// handlers
const handlers = [
...state.handlers.common,
...state.handlers.attributes
];
for await (const handler of handlers){
const ctx = createContext();
const pass = await handler.predicate(ctx);
if (pass) {
await handler.handler(ctx, fp.pick([
'recurse',
'set'
], transformUtils));
}
}
}
return out;
};
return {
traverse,
intercept (predicate, handler) {
state.interceptors.push({
predicate,
handler
});
return this;
},
parse (predicate, parser) {
state.parsers.push({
predicate,
parser
});
return this;
},
ignore (predicate) {
state.ignore.push(predicate);
return this;
},
on (predicate, handler) {
state.handlers.common.push({
predicate,
handler
});
return this;
},
onAttribute (predicate, handler) {
state.handlers.attributes.push({
predicate,
handler
});
return this;
},
onRelation (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'relation', handler);
},
onMedia (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'media', handler);
},
onComponent (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'component', handler);
},
onDynamicZone (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'dynamiczone', handler);
}
};
});
module.exports = traverseFactory;
//# sourceMappingURL=factory.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"factory.js","sources":["../../src/traverse/factory.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-loop-func */\nimport { isNil, pick } from 'lodash/fp';\n\nimport {\n AnyAttribute,\n Attribute,\n ComponentAttribute,\n DynamicZoneAttribute,\n Model,\n RelationalAttribute,\n} from '../types';\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport interface VisitorOptions {\n data: unknown;\n value: unknown;\n schema: Model;\n key: string;\n attribute?: AnyAttribute;\n path: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport type Traverse = (\n visitor: Visitor,\n options: TraverseOptions,\n data: unknown\n) => Promise<unknown>;\n\nexport interface Visitor {\n (visitorOptions: VisitorOptions, opts: Pick<TransformUtils, 'set' | 'remove'>): void;\n}\n\ninterface Interceptor<T = unknown> {\n predicate(data: unknown): data is T;\n handler(\n visitor: Visitor,\n options: TraverseOptions,\n data: T,\n recurseOptions: { recurse: Traverse }\n ): void;\n}\n\ninterface ParseUtils<T> {\n transform(data: T): unknown;\n remove(key: string, data: T): unknown;\n set(key: string, value: unknown, data: T): unknown;\n keys(data: T): string[];\n get(key: string, data: T): unknown;\n}\n\ninterface Parser<T = unknown> {\n predicate(data: unknown): data is T;\n parser(data: T): ParseUtils<T>;\n}\n\ninterface Ignore {\n (ctx: Context): boolean;\n}\n\ninterface AttributeHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\ninterface CommonHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\n\nexport interface TransformUtils {\n remove(key: string): void;\n set(key: string, value: unknown): void;\n recurse: Traverse;\n}\n\ninterface Context<AttributeType = Attribute> {\n key: string;\n value: unknown;\n attribute: AttributeType;\n schema: Model;\n path: Path;\n data: unknown;\n visitor: Visitor;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\ninterface State {\n parsers: Parser[];\n interceptors: Interceptor[];\n ignore: Ignore[];\n handlers: {\n attributes: AttributeHandler[];\n common: CommonHandler[];\n };\n}\n\nconst DEFAULT_PATH = { raw: null, attribute: null } satisfies Path;\n\nexport default () => {\n const state: State = {\n parsers: [],\n interceptors: [],\n ignore: [],\n handlers: {\n attributes: [],\n common: [],\n },\n };\n\n const traverse: Traverse = async (visitor, options, data) => {\n const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};\n\n // interceptors\n for (const { predicate, handler } of state.interceptors) {\n if (predicate(data)) {\n return handler(visitor, options, data, { recurse: traverse });\n }\n }\n\n // parsers\n const parser = state.parsers.find((parser) => parser.predicate(data))?.parser;\n const utils = parser?.(data);\n\n // Return the data untouched if we don't know how to traverse it\n if (!utils) {\n return data;\n }\n\n // main loop\n let out = utils.transform(data);\n const keys = utils.keys(out);\n\n for (const key of keys) {\n const attribute = schema?.attributes?.[key];\n\n const newPath = { ...path };\n\n newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;\n\n if (!isNil(attribute)) {\n newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;\n }\n\n // visitors\n const visitorOptions: VisitorOptions = {\n key,\n value: utils.get(key, out),\n attribute,\n schema,\n path: newPath,\n data: out,\n getModel,\n parent,\n };\n\n const transformUtils: TransformUtils = {\n remove(key) {\n out = utils.remove(key, out);\n },\n set(key, value) {\n out = utils.set(key, value, out);\n },\n recurse: traverse,\n };\n\n await visitor(visitorOptions, pick(['remove', 'set'], transformUtils));\n\n const value = utils.get(key, out);\n\n const createContext = (): Context => ({\n key,\n value,\n attribute,\n schema,\n path: newPath,\n data: out,\n visitor,\n getModel,\n parent,\n });\n\n // ignore\n const ignoreCtx = createContext();\n const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));\n\n if (shouldIgnore) {\n Line truncated
+156
View File
@@ -0,0 +1,156 @@
import { isNil, pick } from 'lodash/fp';
const DEFAULT_PATH = {
raw: null,
attribute: null
};
var traverseFactory = (()=>{
const state = {
parsers: [],
interceptors: [],
ignore: [],
handlers: {
attributes: [],
common: []
}
};
const traverse = async (visitor, options, data)=>{
const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};
// interceptors
for (const { predicate, handler } of state.interceptors){
if (predicate(data)) {
return handler(visitor, options, data, {
recurse: traverse
});
}
}
// parsers
const parser = state.parsers.find((parser)=>parser.predicate(data))?.parser;
const utils = parser?.(data);
// Return the data untouched if we don't know how to traverse it
if (!utils) {
return data;
}
// main loop
let out = utils.transform(data);
const keys = utils.keys(out);
for (const key of keys){
const attribute = schema?.attributes?.[key];
const newPath = {
...path
};
newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;
if (!isNil(attribute)) {
newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;
}
// visitors
const visitorOptions = {
key,
value: utils.get(key, out),
attribute,
schema,
path: newPath,
data: out,
getModel,
parent
};
const transformUtils = {
remove (key) {
out = utils.remove(key, out);
},
set (key, value) {
out = utils.set(key, value, out);
},
recurse: traverse
};
await visitor(visitorOptions, pick([
'remove',
'set'
], transformUtils));
const value = utils.get(key, out);
const createContext = ()=>({
key,
value,
attribute,
schema,
path: newPath,
data: out,
visitor,
getModel,
parent
});
// ignore
const ignoreCtx = createContext();
const shouldIgnore = state.ignore.some((predicate)=>predicate(ignoreCtx));
if (shouldIgnore) {
continue;
}
// handlers
const handlers = [
...state.handlers.common,
...state.handlers.attributes
];
for await (const handler of handlers){
const ctx = createContext();
const pass = await handler.predicate(ctx);
if (pass) {
await handler.handler(ctx, pick([
'recurse',
'set'
], transformUtils));
}
}
}
return out;
};
return {
traverse,
intercept (predicate, handler) {
state.interceptors.push({
predicate,
handler
});
return this;
},
parse (predicate, parser) {
state.parsers.push({
predicate,
parser
});
return this;
},
ignore (predicate) {
state.ignore.push(predicate);
return this;
},
on (predicate, handler) {
state.handlers.common.push({
predicate,
handler
});
return this;
},
onAttribute (predicate, handler) {
state.handlers.attributes.push({
predicate,
handler
});
return this;
},
onRelation (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'relation', handler);
},
onMedia (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'media', handler);
},
onComponent (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'component', handler);
},
onDynamicZone (handler) {
return this.onAttribute(({ attribute })=>attribute?.type === 'dynamiczone', handler);
}
};
});
export { traverseFactory as default };
//# sourceMappingURL=factory.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"factory.mjs","sources":["../../src/traverse/factory.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-loop-func */\nimport { isNil, pick } from 'lodash/fp';\n\nimport {\n AnyAttribute,\n Attribute,\n ComponentAttribute,\n DynamicZoneAttribute,\n Model,\n RelationalAttribute,\n} from '../types';\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport interface VisitorOptions {\n data: unknown;\n value: unknown;\n schema: Model;\n key: string;\n attribute?: AnyAttribute;\n path: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport type Traverse = (\n visitor: Visitor,\n options: TraverseOptions,\n data: unknown\n) => Promise<unknown>;\n\nexport interface Visitor {\n (visitorOptions: VisitorOptions, opts: Pick<TransformUtils, 'set' | 'remove'>): void;\n}\n\ninterface Interceptor<T = unknown> {\n predicate(data: unknown): data is T;\n handler(\n visitor: Visitor,\n options: TraverseOptions,\n data: T,\n recurseOptions: { recurse: Traverse }\n ): void;\n}\n\ninterface ParseUtils<T> {\n transform(data: T): unknown;\n remove(key: string, data: T): unknown;\n set(key: string, value: unknown, data: T): unknown;\n keys(data: T): string[];\n get(key: string, data: T): unknown;\n}\n\ninterface Parser<T = unknown> {\n predicate(data: unknown): data is T;\n parser(data: T): ParseUtils<T>;\n}\n\ninterface Ignore {\n (ctx: Context): boolean;\n}\n\ninterface AttributeHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\ninterface CommonHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\n\nexport interface TransformUtils {\n remove(key: string): void;\n set(key: string, value: unknown): void;\n recurse: Traverse;\n}\n\ninterface Context<AttributeType = Attribute> {\n key: string;\n value: unknown;\n attribute: AttributeType;\n schema: Model;\n path: Path;\n data: unknown;\n visitor: Visitor;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\ninterface State {\n parsers: Parser[];\n interceptors: Interceptor[];\n ignore: Ignore[];\n handlers: {\n attributes: AttributeHandler[];\n common: CommonHandler[];\n };\n}\n\nconst DEFAULT_PATH = { raw: null, attribute: null } satisfies Path;\n\nexport default () => {\n const state: State = {\n parsers: [],\n interceptors: [],\n ignore: [],\n handlers: {\n attributes: [],\n common: [],\n },\n };\n\n const traverse: Traverse = async (visitor, options, data) => {\n const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};\n\n // interceptors\n for (const { predicate, handler } of state.interceptors) {\n if (predicate(data)) {\n return handler(visitor, options, data, { recurse: traverse });\n }\n }\n\n // parsers\n const parser = state.parsers.find((parser) => parser.predicate(data))?.parser;\n const utils = parser?.(data);\n\n // Return the data untouched if we don't know how to traverse it\n if (!utils) {\n return data;\n }\n\n // main loop\n let out = utils.transform(data);\n const keys = utils.keys(out);\n\n for (const key of keys) {\n const attribute = schema?.attributes?.[key];\n\n const newPath = { ...path };\n\n newPath.raw = isNil(path.raw) ? key : `${path.raw}.${key}`;\n\n if (!isNil(attribute)) {\n newPath.attribute = isNil(path.attribute) ? key : `${path.attribute}.${key}`;\n }\n\n // visitors\n const visitorOptions: VisitorOptions = {\n key,\n value: utils.get(key, out),\n attribute,\n schema,\n path: newPath,\n data: out,\n getModel,\n parent,\n };\n\n const transformUtils: TransformUtils = {\n remove(key) {\n out = utils.remove(key, out);\n },\n set(key, value) {\n out = utils.set(key, value, out);\n },\n recurse: traverse,\n };\n\n await visitor(visitorOptions, pick(['remove', 'set'], transformUtils));\n\n const value = utils.get(key, out);\n\n const createContext = (): Context => ({\n key,\n value,\n attribute,\n schema,\n path: newPath,\n data: out,\n visitor,\n getModel,\n parent,\n });\n\n // ignore\n const ignoreCtx = createContext();\n const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));\n\n if (shouldIgnore) {\n Line truncated
+5
View File
@@ -0,0 +1,5 @@
export { default as traverseQueryFilters } from './query-filters';
export { default as traverseQuerySort } from './query-sort';
export { default as traverseQueryPopulate } from './query-populate';
export { default as traverseQueryFields } from './query-fields';
//# sourceMappingURL=index.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/traverse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
+14
View File
@@ -0,0 +1,14 @@
'use strict';
var queryFilters = require('./query-filters.js');
var querySort = require('./query-sort.js');
var queryPopulate = require('./query-populate.js');
var queryFields = require('./query-fields.js');
exports.traverseQueryFilters = queryFilters;
exports.traverseQuerySort = querySort;
exports.traverseQueryPopulate = queryPopulate;
exports.traverseQueryFields = queryFields;
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
+5
View File
@@ -0,0 +1,5 @@
export { default as traverseQueryFilters } from './query-filters.mjs';
export { default as traverseQuerySort } from './query-sort.mjs';
export { default as traverseQueryPopulate } from './query-populate.mjs';
export { default as traverseQueryFields } from './query-fields.mjs';
//# sourceMappingURL=index.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"}
+4
View File
@@ -0,0 +1,4 @@
/// <reference types="lodash" />
declare const _default: import("lodash").CurriedFunction3<import("./factory").Visitor, import("./factory").TraverseOptions, unknown, Promise<unknown>>;
export default _default;
//# sourceMappingURL=query-fields.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"query-fields.d.ts","sourceRoot":"","sources":["../../src/traverse/query-fields.ts"],"names":[],"mappings":";;AA+CA,wBAAsC"}
+41
View File
@@ -0,0 +1,41 @@
'use strict';
var fp = require('lodash/fp');
var factory = require('./factory.js');
const isStringArray = (value)=>{
return fp.isArray(value) && value.every(fp.isString);
};
const fields = factory()// Intercept array of strings
// e.g. fields=['title', 'description']
.intercept(isStringArray, async (visitor, options, fields, { recurse })=>{
return Promise.all(fields.map((field)=>recurse(visitor, options, field)));
})// Intercept comma separated fields (as string)
// e.g. fields='title,description'
.intercept((value)=>fp.isString(value) && value.includes(','), (visitor, options, fields, { recurse })=>{
return Promise.all(fields.split(',').map((field)=>recurse(visitor, options, field)));
})// Return wildcards as is
.intercept((value)=>fp.eq('*', value), fp.constant('*'))// Parse string values
// Since we're parsing strings only, each value should be an attribute name (and it's value, undefined),
// thus it shouldn't be possible to set a new value, and get should return the whole data if key === data
.parse(fp.isString, ()=>({
transform: fp.trim,
remove (key, data) {
return data === key ? undefined : data;
},
set (_key, _value, data) {
return data;
},
keys (data) {
return [
data
];
},
get (key, data) {
return key === data ? data : undefined;
}
}));
var traverseQueryFields = fp.curry(fields.traverse);
module.exports = traverseQueryFields;
//# sourceMappingURL=query-fields.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-fields.js","sources":["../../src/traverse/query-fields.ts"],"sourcesContent":["import { curry, isArray, isString, eq, trim, constant } from 'lodash/fp';\n\nimport traverseFactory from './factory';\n\nconst isStringArray = (value: unknown): value is string[] => {\n return isArray(value) && value.every(isString);\n};\n\nconst fields = traverseFactory()\n // Intercept array of strings\n // e.g. fields=['title', 'description']\n .intercept(isStringArray, async (visitor, options, fields, { recurse }) => {\n return Promise.all(fields.map((field) => recurse(visitor, options, field)));\n })\n // Intercept comma separated fields (as string)\n // e.g. fields='title,description'\n .intercept(\n (value): value is string => isString(value) && value.includes(','),\n (visitor, options, fields, { recurse }) => {\n return Promise.all(fields.split(',').map((field) => recurse(visitor, options, field)));\n }\n )\n // Return wildcards as is\n .intercept((value): value is string => eq('*', value), constant('*'))\n // Parse string values\n // Since we're parsing strings only, each value should be an attribute name (and it's value, undefined),\n // thus it shouldn't be possible to set a new value, and get should return the whole data if key === data\n .parse(isString, () => ({\n transform: trim,\n\n remove(key, data) {\n return data === key ? undefined : data;\n },\n\n set(_key, _value, data) {\n return data;\n },\n\n keys(data) {\n return [data];\n },\n\n get(key, data) {\n return key === data ? data : undefined;\n },\n }));\n\nexport default curry(fields.traverse);\n"],"names":["isStringArray","value","isArray","every","isString","fields","traverseFactory","intercept","visitor","options","recurse","Promise","all","map","field","includes","split","eq","constant","parse","transform","trim","remove","key","data","undefined","set","_key","_value","keys","get","curry","traverse"],"mappings":";;;;;AAIA,MAAMA,gBAAgB,CAACC,KAAAA,GAAAA;AACrB,IAAA,OAAOC,UAAQD,CAAAA,KAAAA,CAAAA,IAAUA,KAAME,CAAAA,KAAK,CAACC,WAAAA,CAAAA;AACvC,CAAA;AAEA,MAAMC,MAAAA,GAASC,SACb;AACA;CACCC,SAAS,CAACP,eAAe,OAAOQ,OAAAA,EAASC,SAASJ,MAAQ,EAAA,EAAEK,OAAO,EAAE,GAAA;IACpE,OAAOC,OAAAA,CAAQC,GAAG,CAACP,MAAOQ,CAAAA,GAAG,CAAC,CAACC,KAAAA,GAAUJ,OAAQF,CAAAA,OAAAA,EAASC,OAASK,EAAAA,KAAAA,CAAAA,CAAAA,CAAAA;AACrE,CAAA,CACA;AACA;AACCP,CAAAA,SAAS,CACR,CAACN,KAA2BG,GAAAA,WAAAA,CAASH,UAAUA,KAAMc,CAAAA,QAAQ,CAAC,GAAA,CAAA,EAC9D,CAACP,OAASC,EAAAA,OAAAA,EAASJ,MAAQ,EAAA,EAAEK,OAAO,EAAE,GAAA;AACpC,IAAA,OAAOC,OAAQC,CAAAA,GAAG,CAACP,MAAAA,CAAOW,KAAK,CAAC,GAAKH,CAAAA,CAAAA,GAAG,CAAC,CAACC,KAAUJ,GAAAA,OAAAA,CAAQF,SAASC,OAASK,EAAAA,KAAAA,CAAAA,CAAAA,CAAAA;AAChF,CAAA,CAEF;CACCP,SAAS,CAAC,CAACN,KAA2BgB,GAAAA,KAAAA,CAAG,KAAKhB,KAAQiB,CAAAA,EAAAA,WAAAA,CAAS,KAChE;AACA;AACA;CACCC,KAAK,CAACf,WAAU,EAAA,KAAO;QACtBgB,SAAWC,EAAAA,OAAAA;QAEXC,MAAOC,CAAAA,CAAAA,GAAG,EAAEC,IAAI,EAAA;YACd,OAAOA,IAAAA,KAASD,MAAME,SAAYD,GAAAA,IAAAA;AACpC,SAAA;AAEAE,QAAAA,GAAAA,CAAAA,CAAIC,IAAI,EAAEC,MAAM,EAAEJ,IAAI,EAAA;YACpB,OAAOA,IAAAA;AACT,SAAA;AAEAK,QAAAA,IAAAA,CAAAA,CAAKL,IAAI,EAAA;YACP,OAAO;AAACA,gBAAAA;AAAK,aAAA;AACf,SAAA;QAEAM,GAAIP,CAAAA,CAAAA,GAAG,EAAEC,IAAI,EAAA;YACX,OAAOD,GAAAA,KAAQC,OAAOA,IAAOC,GAAAA,SAAAA;AAC/B;KACF,CAAA,CAAA;AAEF,0BAAeM,QAAAA,CAAM1B,MAAO2B,CAAAA,QAAQ,CAAE;;;;"}
+39
View File
@@ -0,0 +1,39 @@
import { isString, eq, constant, trim, curry, isArray } from 'lodash/fp';
import traverseFactory from './factory.mjs';
const isStringArray = (value)=>{
return isArray(value) && value.every(isString);
};
const fields = traverseFactory()// Intercept array of strings
// e.g. fields=['title', 'description']
.intercept(isStringArray, async (visitor, options, fields, { recurse })=>{
return Promise.all(fields.map((field)=>recurse(visitor, options, field)));
})// Intercept comma separated fields (as string)
// e.g. fields='title,description'
.intercept((value)=>isString(value) && value.includes(','), (visitor, options, fields, { recurse })=>{
return Promise.all(fields.split(',').map((field)=>recurse(visitor, options, field)));
})// Return wildcards as is
.intercept((value)=>eq('*', value), constant('*'))// Parse string values
// Since we're parsing strings only, each value should be an attribute name (and it's value, undefined),
// thus it shouldn't be possible to set a new value, and get should return the whole data if key === data
.parse(isString, ()=>({
transform: trim,
remove (key, data) {
return data === key ? undefined : data;
},
set (_key, _value, data) {
return data;
},
keys (data) {
return [
data
];
},
get (key, data) {
return key === data ? data : undefined;
}
}));
var traverseQueryFields = curry(fields.traverse);
export { traverseQueryFields as default };
//# sourceMappingURL=query-fields.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-fields.mjs","sources":["../../src/traverse/query-fields.ts"],"sourcesContent":["import { curry, isArray, isString, eq, trim, constant } from 'lodash/fp';\n\nimport traverseFactory from './factory';\n\nconst isStringArray = (value: unknown): value is string[] => {\n return isArray(value) && value.every(isString);\n};\n\nconst fields = traverseFactory()\n // Intercept array of strings\n // e.g. fields=['title', 'description']\n .intercept(isStringArray, async (visitor, options, fields, { recurse }) => {\n return Promise.all(fields.map((field) => recurse(visitor, options, field)));\n })\n // Intercept comma separated fields (as string)\n // e.g. fields='title,description'\n .intercept(\n (value): value is string => isString(value) && value.includes(','),\n (visitor, options, fields, { recurse }) => {\n return Promise.all(fields.split(',').map((field) => recurse(visitor, options, field)));\n }\n )\n // Return wildcards as is\n .intercept((value): value is string => eq('*', value), constant('*'))\n // Parse string values\n // Since we're parsing strings only, each value should be an attribute name (and it's value, undefined),\n // thus it shouldn't be possible to set a new value, and get should return the whole data if key === data\n .parse(isString, () => ({\n transform: trim,\n\n remove(key, data) {\n return data === key ? undefined : data;\n },\n\n set(_key, _value, data) {\n return data;\n },\n\n keys(data) {\n return [data];\n },\n\n get(key, data) {\n return key === data ? data : undefined;\n },\n }));\n\nexport default curry(fields.traverse);\n"],"names":["isStringArray","value","isArray","every","isString","fields","traverseFactory","intercept","visitor","options","recurse","Promise","all","map","field","includes","split","eq","constant","parse","transform","trim","remove","key","data","undefined","set","_key","_value","keys","get","curry","traverse"],"mappings":";;;AAIA,MAAMA,gBAAgB,CAACC,KAAAA,GAAAA;AACrB,IAAA,OAAOC,OAAQD,CAAAA,KAAAA,CAAAA,IAAUA,KAAME,CAAAA,KAAK,CAACC,QAAAA,CAAAA;AACvC,CAAA;AAEA,MAAMC,MAAAA,GAASC,iBACb;AACA;CACCC,SAAS,CAACP,eAAe,OAAOQ,OAAAA,EAASC,SAASJ,MAAQ,EAAA,EAAEK,OAAO,EAAE,GAAA;IACpE,OAAOC,OAAAA,CAAQC,GAAG,CAACP,MAAOQ,CAAAA,GAAG,CAAC,CAACC,KAAAA,GAAUJ,OAAQF,CAAAA,OAAAA,EAASC,OAASK,EAAAA,KAAAA,CAAAA,CAAAA,CAAAA;AACrE,CAAA,CACA;AACA;AACCP,CAAAA,SAAS,CACR,CAACN,KAA2BG,GAAAA,QAAAA,CAASH,UAAUA,KAAMc,CAAAA,QAAQ,CAAC,GAAA,CAAA,EAC9D,CAACP,OAASC,EAAAA,OAAAA,EAASJ,MAAQ,EAAA,EAAEK,OAAO,EAAE,GAAA;AACpC,IAAA,OAAOC,OAAQC,CAAAA,GAAG,CAACP,MAAAA,CAAOW,KAAK,CAAC,GAAKH,CAAAA,CAAAA,GAAG,CAAC,CAACC,KAAUJ,GAAAA,OAAAA,CAAQF,SAASC,OAASK,EAAAA,KAAAA,CAAAA,CAAAA,CAAAA;AAChF,CAAA,CAEF;CACCP,SAAS,CAAC,CAACN,KAA2BgB,GAAAA,EAAAA,CAAG,KAAKhB,KAAQiB,CAAAA,EAAAA,QAAAA,CAAS,KAChE;AACA;AACA;CACCC,KAAK,CAACf,QAAU,EAAA,KAAO;QACtBgB,SAAWC,EAAAA,IAAAA;QAEXC,MAAOC,CAAAA,CAAAA,GAAG,EAAEC,IAAI,EAAA;YACd,OAAOA,IAAAA,KAASD,MAAME,SAAYD,GAAAA,IAAAA;AACpC,SAAA;AAEAE,QAAAA,GAAAA,CAAAA,CAAIC,IAAI,EAAEC,MAAM,EAAEJ,IAAI,EAAA;YACpB,OAAOA,IAAAA;AACT,SAAA;AAEAK,QAAAA,IAAAA,CAAAA,CAAKL,IAAI,EAAA;YACP,OAAO;AAACA,gBAAAA;AAAK,aAAA;AACf,SAAA;QAEAM,GAAIP,CAAAA,CAAAA,GAAG,EAAEC,IAAI,EAAA;YACX,OAAOD,GAAAA,KAAQC,OAAOA,IAAOC,GAAAA,SAAAA;AAC/B;KACF,CAAA,CAAA;AAEF,0BAAeM,KAAAA,CAAM1B,MAAO2B,CAAAA,QAAQ,CAAE;;;;"}
+4
View File
@@ -0,0 +1,4 @@
/// <reference types="lodash" />
declare const _default: import("lodash").CurriedFunction3<import("./factory").Visitor, import("./factory").TraverseOptions, unknown, Promise<unknown>>;
export default _default;
//# sourceMappingURL=query-filters.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"query-filters.d.ts","sourceRoot":"","sources":["../../src/traverse/query-filters.ts"],"names":[],"mappings":";;AAoHA,wBAAuC"}
+114
View File
@@ -0,0 +1,114 @@
'use strict';
var fp = require('lodash/fp');
var factory = require('./factory.js');
const isObj = (value)=>fp.isObject(value);
const filters = factory().intercept(// Intercept filters arrays and apply the traversal to each one individually
fp.isArray, async (visitor, options, filters, { recurse })=>{
return Promise.all(filters.map((filter, i)=>{
// In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]
// can have a value array, thus we can update the raw path but not the attribute one
const newPath = options.path ? {
...options.path,
raw: `${options.path.raw}[${i}]`
} : options.path;
return recurse(visitor, {
...options,
path: newPath
}, filter);
})).then((res)=>res.filter((val)=>!(fp.isObject(val) && fp.isEmpty(val))));
}).intercept(// Ignore non object filters and return the value as-is
(filters)=>!fp.isObject(filters), (_, __, filters)=>{
return filters;
})// Parse object values
.parse(isObj, ()=>({
transform: fp.cloneDeep,
remove (key, data) {
return fp.omit(key, data);
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
}))// Ignore null or undefined values
.ignore(({ value })=>fp.isNil(value))// Recursion on operators (non attributes)
.on(({ attribute })=>fp.isNil(attribute), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
set(key, await recurse(visitor, {
schema,
path,
getModel,
parent
}, value));
})// Handle relation recursion
.onRelation(async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse })=>{
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
if (isMorphRelation) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
}).onComponent(async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle media recursion
.onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
});
var traverseQueryFilters = fp.curry(filters.traverse);
module.exports = traverseQueryFilters;
//# sourceMappingURL=query-filters.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-filters.js","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n });\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","keys","Object","get","ignore","isNil","on","attribute","schema","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","curry","traverse"],"mappings":";;;;;AAIA,MAAMA,KAAAA,GAAQ,CAACC,KAAAA,GAAqDC,WAASD,CAAAA,KAAAA,CAAAA;AAE7E,MAAME,OAAUC,GAAAA,OAAAA,EAAAA,CACbC,SAAS;AAERC,UAAAA,EACA,OAAOC,OAASC,EAAAA,OAAAA,EAASL,OAAS,EAAA,EAAEM,OAAO,EAAE,GAAA;AAC3C,IAAA,OAAOC,QAAQC,GAAG,CAChBR,QAAQS,GAAG,CAAC,CAACC,MAAQC,EAAAA,CAAAA,GAAAA;;;QAGnB,MAAMC,OAAAA,GAAUP,OAAQQ,CAAAA,IAAI,GACxB;AAAE,YAAA,GAAGR,QAAQQ,IAAI;YAAEC,GAAK,EAAA,CAAC,EAAET,OAAAA,CAAQQ,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEH,CAAE,CAAA,CAAC;AAAE,SAAA,GACpDN,QAAQQ,IAAI;AAEhB,QAAA,OAAOP,QAAQF,OAAS,EAAA;AAAE,YAAA,GAAGC,OAAO;YAAEQ,IAAMD,EAAAA;SAAWF,EAAAA,MAAAA,CAAAA;AACzD,KAAA,CAAA,CAAA,CAEAK,IAAI,CAAC,CAACC,GAAAA,GAAQA,IAAIN,MAAM,CAAC,CAACO,GAAAA,GAAQ,EAAElB,WAASkB,CAAAA,GAAAA,CAAAA,IAAQC,WAAQD,GAAG,CAAA,CAAA,CAALine truncated
+112
View File
@@ -0,0 +1,112 @@
import { isArray, isObject, isEmpty, cloneDeep, omit, isNil, curry } from 'lodash/fp';
import traverseFactory from './factory.mjs';
const isObj = (value)=>isObject(value);
const filters = traverseFactory().intercept(// Intercept filters arrays and apply the traversal to each one individually
isArray, async (visitor, options, filters, { recurse })=>{
return Promise.all(filters.map((filter, i)=>{
// In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]
// can have a value array, thus we can update the raw path but not the attribute one
const newPath = options.path ? {
...options.path,
raw: `${options.path.raw}[${i}]`
} : options.path;
return recurse(visitor, {
...options,
path: newPath
}, filter);
})).then((res)=>res.filter((val)=>!(isObject(val) && isEmpty(val))));
}).intercept(// Ignore non object filters and return the value as-is
(filters)=>!isObject(filters), (_, __, filters)=>{
return filters;
})// Parse object values
.parse(isObj, ()=>({
transform: cloneDeep,
remove (key, data) {
return omit(key, data);
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
}))// Ignore null or undefined values
.ignore(({ value })=>isNil(value))// Recursion on operators (non attributes)
.on(({ attribute })=>isNil(attribute), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
set(key, await recurse(visitor, {
schema,
path,
getModel,
parent
}, value));
})// Handle relation recursion
.onRelation(async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse })=>{
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
if (isMorphRelation) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
}).onComponent(async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle media recursion
.onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
});
var traverseQueryFilters = curry(filters.traverse);
export { traverseQueryFilters as default };
//# sourceMappingURL=query-filters.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"query-filters.mjs","sources":["../../src/traverse/query-filters.ts"],"sourcesContent":["import { curry, isObject, isEmpty, isArray, isNil, cloneDeep, omit } from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst filters = traverseFactory()\n .intercept(\n // Intercept filters arrays and apply the traversal to each one individually\n isArray,\n async (visitor, options, filters, { recurse }) => {\n return Promise.all(\n filters.map((filter, i) => {\n // In filters, only operators such as $and, $in, $notIn or $or and implicit operators like [...]\n // can have a value array, thus we can update the raw path but not the attribute one\n const newPath = options.path\n ? { ...options.path, raw: `${options.path.raw}[${i}]` }\n : options.path;\n\n return recurse(visitor, { ...options, path: newPath }, filter);\n })\n // todo: move that to the visitors\n ).then((res) => res.filter((val) => !(isObject(val) && isEmpty(val))));\n }\n )\n .intercept(\n // Ignore non object filters and return the value as-is\n (filters): filters is unknown => !isObject(filters),\n (_, __, filters) => {\n return filters;\n }\n )\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n return omit(key, data);\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Ignore null or undefined values\n .ignore(({ value }) => isNil(value))\n // Recursion on operators (non attributes)\n .on(\n ({ attribute }) => isNil(attribute),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n set(key, await recurse(visitor, { schema, path, getModel, parent }, value));\n }\n )\n // Handle relation recursion\n .onRelation(\n async ({ key, attribute, visitor, path, value, schema, getModel }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n .onComponent(\n async ({ key, attribute, visitor, path, schema, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n const targetSchema = getModel(attribute.component);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle media recursion\n .onMedia(async ({ key, visitor, path, schema, attribute, value, getModel }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n });\n\nexport default curry(filters.traverse);\n"],"names":["isObj","value","isObject","filters","traverseFactory","intercept","isArray","visitor","options","recurse","Promise","all","map","filter","i","newPath","path","raw","then","res","val","isEmpty","_","__","parse","transform","cloneDeep","remove","key","data","omit","set","keys","Object","get","ignore","isNil","on","attribute","schema","getModel","parent","onRelation","isMorphRelation","relation","toLowerCase","startsWith","targetSchemaUID","target","targetSchema","newValue","onComponent","component","onMedia","curry","traverse"],"mappings":";;;AAIA,MAAMA,KAAAA,GAAQ,CAACC,KAAAA,GAAqDC,QAASD,CAAAA,KAAAA,CAAAA;AAE7E,MAAME,OAAUC,GAAAA,eAAAA,EAAAA,CACbC,SAAS;AAERC,OAAAA,EACA,OAAOC,OAASC,EAAAA,OAAAA,EAASL,OAAS,EAAA,EAAEM,OAAO,EAAE,GAAA;AAC3C,IAAA,OAAOC,QAAQC,GAAG,CAChBR,QAAQS,GAAG,CAAC,CAACC,MAAQC,EAAAA,CAAAA,GAAAA;;;QAGnB,MAAMC,OAAAA,GAAUP,OAAQQ,CAAAA,IAAI,GACxB;AAAE,YAAA,GAAGR,QAAQQ,IAAI;YAAEC,GAAK,EAAA,CAAC,EAAET,OAAAA,CAAQQ,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEH,CAAE,CAAA,CAAC;AAAE,SAAA,GACpDN,QAAQQ,IAAI;AAEhB,QAAA,OAAOP,QAAQF,OAAS,EAAA;AAAE,YAAA,GAAGC,OAAO;YAAEQ,IAAMD,EAAAA;SAAWF,EAAAA,MAAAA,CAAAA;AACzD,KAAA,CAAA,CAAA,CAEAK,IAAI,CAAC,CAACC,GAAAA,GAAQA,IAAIN,MAAM,CAAC,CAACO,GAAAA,GAAQ,EAAElB,QAASkB,CAAAA,GAAAA,CAAAA,IAAQC,QAAQD,GAAG,CAAA,CAAA,CAAALine truncated
+4
View File
@@ -0,0 +1,4 @@
/// <reference types="lodash" />
declare const _default: import("lodash").CurriedFunction3<import("./factory").Visitor, import("./factory").TraverseOptions, unknown, Promise<unknown>>;
export default _default;
//# sourceMappingURL=query-populate.d.ts.map
@@ -0,0 +1 @@
{"version":3,"file":"query-populate.d.ts","sourceRoot":"","sources":["../../src/traverse/query-populate.ts"],"names":[],"mappings":";;AA0RA,wBAAwC"}
+280
View File
@@ -0,0 +1,280 @@
'use strict';
var fp = require('lodash/fp');
var factory = require('./factory.js');
var contentTypes = require('../content-types.js');
const isKeyword = (keyword)=>{
return ({ key, attribute })=>{
return !attribute && keyword === key;
};
};
const isWildcard = (value)=>value === '*';
const isPopulateString = (value)=>{
return fp.isString(value) && !isWildcard(value);
};
const isStringArray = (value)=>fp.isArray(value) && value.every(fp.isString);
const isObj = (value)=>fp.isObject(value);
const populate = factory().intercept(isPopulateString, async (visitor, options, populate, { recurse })=>{
/**
* Ensure the populate clause its in the extended format ( { populate: { ... } }, and not just a string)
* This gives a consistent structure to track the "parent" node of each nested populate clause
*/ const populateObject = pathsToObjectPopulate([
populate
]);
const traversedPopulate = await recurse(visitor, options, populateObject);
const [result] = objectPopulateToPaths(traversedPopulate);
return result;
})// Array of strings ['foo', 'bar.baz'] => map(recurse), then filter out empty items
.intercept(isStringArray, async (visitor, options, populate, { recurse })=>{
const paths = await Promise.all(populate.map((subClause)=>recurse(visitor, options, subClause)));
return paths.filter((item)=>!fp.isNil(item));
})// for wildcard, generate custom utilities to modify the values
.parse(isWildcard, ()=>({
/**
* Since value is '*', we don't need to transform it
*/ transform: fp.identity,
/**
* '*' isn't a key/value structure, so regardless
* of the given key, it returns the data ('*')
*/ get: (_key, data)=>data,
/**
* '*' isn't a key/value structure, so regardless
* of the given `key`, use `value` as the new `data`
*/ set: (_key, value)=>value,
/**
* '*' isn't a key/value structure, but we need to simulate at least one to enable
* the data traversal. We're using '' since it represents a falsy string value
*/ keys: fp.constant([
''
]),
/**
* Removing '*' means setting it to undefined, regardless of the given key
*/ remove: fp.constant(undefined)
}))// Parse string values
.parse(fp.isString, ()=>{
const tokenize = fp.split('.');
const recompose = fp.join('.');
return {
transform: fp.trim,
remove (key, data) {
const [root] = tokenize(data);
return root === key ? undefined : data;
},
set (key, value, data) {
const [root] = tokenize(data);
if (root !== key) {
return data;
}
return fp.isNil(value) || fp.isEmpty(value) ? root : `${root}.${value}`;
},
keys (data) {
const v = fp.first(tokenize(data));
return v ? [
v
] : [];
},
get (key, data) {
const [root, ...rest] = tokenize(data);
return key === root ? recompose(rest) : undefined;
}
};
})// Parse object values
.parse(isObj, ()=>({
transform: fp.cloneDeep,
remove (key, data) {
// eslint-disable-next-line no-unused-vars
const { [key]: ignored, ...rest } = data;
return rest;
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
})).ignore(({ key, attribute })=>{
// we don't want to recurse using traversePopulate and instead let
// the visitors recurse with the appropriate traversal (sort, filters, etc...)
return [
'sort',
'filters',
'fields'
].includes(key) && !attribute;
}).on(// Handle recursion on populate."populate"
isKeyword('populate'), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const newValue = await recurse(visitor, {
schema,
path,
getModel,
parent
}, value);
set(key, newValue);
}).on(isKeyword('on'), async ({ key, visitor, path, value, getModel, parent }, { set, recurse })=>{
const newOn = {};
if (!isObj(value)) {
return;
}
for (const [uid, subPopulate] of Object.entries(value)){
const model = getModel(uid);
const newPath = {
...path,
raw: `${path.raw}[${uid}]`
};
newOn[uid] = await recurse(visitor, {
schema: model,
path: newPath,
getModel,
parent
}, subPopulate);
}
set(key, newOn);
})// Handle populate on relation
.onRelation(async ({ key, value, attribute, visitor, path, schema, getModel }, { set, recurse })=>{
if (fp.isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
if (contentTypes.isMorphToRelationalAttribute(attribute)) {
// Don't traverse values that cannot be parsed
if (!fp.isObject(value) || !('on' in value && fp.isObject(value?.on))) {
return;
}
// If there is a populate fragment defined, traverse it
const newValue = await recurse(visitor, {
schema,
path,
getModel,
parent
}, {
on: value?.on
});
set(key, newValue);
return;
}
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on media
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
if (fp.isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on components
.onComponent(async ({ key, value, schema, visitor, path, attribute, getModel }, { recurse, set })=>{
if (fp.isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on dynamic zones
.onDynamicZone(async ({ key, value, schema, visitor, path, attribute, getModel }, { set, recurse })=>{
if (fp.isNil(value) || !fp.isObject(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
// Handle fragment syntax
if ('on' in value && value.on) {
const newOn = await recurse(visitor, {
schema,
path,
getModel,
parent
}, {
on: value.on
});
set(key, newOn);
}
});
var traverseQueryPopulate = fp.curry(populate.traverse);
const objectPopulateToPaths = (input)=>{
const paths = [];
function traverse(currentObj, parentPath) {
for (const [key, value] of Object.entries(currentObj)){
const currentPath = parentPath ? `${parentPath}.${key}` : key;
if (value === true) {
paths.push(currentPath);
} else {
traverse(value.populate, currentPath);
}
}
}
traverse(input, '');
return paths;
};
const pathsToObjectPopulate = (input)=>{
const result = {};
function traverse(object, keys) {
const [first, ...rest] = keys;
if (rest.length === 0) {
object[first] = true;
} else {
if (!object[first] || typeof object[first] === 'boolean') {
object[first] = {
populate: {}
};
}
traverse(object[first].populate, rest);
}
}
input.forEach((clause)=>traverse(result, clause.split('.')));
return result;
};
module.exports = traverseQueryPopulate;
//# sourceMappingURL=query-populate.js.map
@@ -0,0 +1 @@
{"version":3,"file":"query-populate.js","sources":["../../src/traverse/query-populate.ts"],"sourcesContent":["import {\n curry,\n isString,\n isArray,\n isEmpty,\n split,\n isObject,\n trim,\n constant,\n isNil,\n identity,\n cloneDeep,\n join,\n first,\n} from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\nimport { Attribute } from '../types';\nimport { isMorphToRelationalAttribute } from '../content-types';\n\nconst isKeyword = (keyword: string) => {\n return ({ key, attribute }: { key: string; attribute: Attribute }) => {\n return !attribute && keyword === key;\n };\n};\n\nconst isWildcard = (value: unknown): value is '*' => value === '*';\n\nconst isPopulateString = (value: unknown): value is string => {\n return isString(value) && !isWildcard(value);\n};\n\nconst isStringArray = (value: unknown): value is string[] =>\n isArray(value) && value.every(isString);\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst populate = traverseFactory()\n .intercept(isPopulateString, async (visitor, options, populate, { recurse }) => {\n /**\n * Ensure the populate clause its in the extended format ( { populate: { ... } }, and not just a string)\n * This gives a consistent structure to track the \"parent\" node of each nested populate clause\n */\n const populateObject = pathsToObjectPopulate([populate]);\n const traversedPopulate = (await recurse(visitor, options, populateObject)) as PopulateObject;\n const [result] = objectPopulateToPaths(traversedPopulate);\n\n return result;\n })\n // Array of strings ['foo', 'bar.baz'] => map(recurse), then filter out empty items\n .intercept(isStringArray, async (visitor, options, populate, { recurse }) => {\n const paths = await Promise.all(\n populate.map((subClause) => recurse(visitor, options, subClause))\n );\n\n return paths.filter((item) => !isNil(item));\n })\n // for wildcard, generate custom utilities to modify the values\n .parse(isWildcard, () => ({\n /**\n * Since value is '*', we don't need to transform it\n */\n transform: identity,\n\n /**\n * '*' isn't a key/value structure, so regardless\n * of the given key, it returns the data ('*')\n */\n get: (_key, data) => data,\n\n /**\n * '*' isn't a key/value structure, so regardless\n * of the given `key`, use `value` as the new `data`\n */\n set: (_key, value) => value,\n\n /**\n * '*' isn't a key/value structure, but we need to simulate at least one to enable\n * the data traversal. We're using '' since it represents a falsy string value\n */\n keys: constant(['']),\n\n /**\n * Removing '*' means setting it to undefined, regardless of the given key\n */\n remove: constant(undefined),\n }))\n\n // Parse string values\n .parse(isString, () => {\n const tokenize = split('.');\n const recompose = join('.');\n\n return {\n transform: trim,\n\n remove(key, data) {\n const [root] = tokenize(data);\n\n return root === key ? undefined : data;\n },\n\n set(key, value, data) {\n const [root] = tokenize(data);\n\n if (root !== key) {\n return data;\n }\n\n return isNil(value) || isEmpty(value) ? root : `${root}.${value}`;\n },\n\n keys(data) {\n const v = first(tokenize(data));\n return v ? [v] : [];\n },\n\n get(key, data) {\n const [root, ...rest] = tokenize(data);\n\n return key === root ? recompose(rest) : undefined;\n },\n };\n })\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n // eslint-disable-next-line no-unused-vars\n const { [key]: ignored, ...rest } = data;\n\n return rest;\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n .ignore(({ key, attribute }) => {\n // we don't want to recurse using traversePopulate and instead let\n // the visitors recurse with the appropriate traversal (sort, filters, etc...)\n return ['sort', 'filters', 'fields'].includes(key) && !attribute;\n })\n .on(\n // Handle recursion on populate.\"populate\"\n isKeyword('populate'),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const newValue = await recurse(visitor, { schema, path, getModel, parent }, value);\n\n set(key, newValue);\n }\n )\n .on(\n isKeyword('on'),\n async ({ key, visitor, path, value, getModel, parent }, { set, recurse }) => {\n const newOn: Record<string, unknown> = {};\n\n if (!isObj(value)) {\n return;\n }\n\n for (const [uid, subPopulate] of Object.eLine truncated
+278
View File
@@ -0,0 +1,278 @@
import { isNil, identity, constant, isString, split, join, trim, isEmpty, first, cloneDeep, isObject, curry, isArray } from 'lodash/fp';
import traverseFactory from './factory.mjs';
import { isMorphToRelationalAttribute } from '../content-types.mjs';
const isKeyword = (keyword)=>{
return ({ key, attribute })=>{
return !attribute && keyword === key;
};
};
const isWildcard = (value)=>value === '*';
const isPopulateString = (value)=>{
return isString(value) && !isWildcard(value);
};
const isStringArray = (value)=>isArray(value) && value.every(isString);
const isObj = (value)=>isObject(value);
const populate = traverseFactory().intercept(isPopulateString, async (visitor, options, populate, { recurse })=>{
/**
* Ensure the populate clause its in the extended format ( { populate: { ... } }, and not just a string)
* This gives a consistent structure to track the "parent" node of each nested populate clause
*/ const populateObject = pathsToObjectPopulate([
populate
]);
const traversedPopulate = await recurse(visitor, options, populateObject);
const [result] = objectPopulateToPaths(traversedPopulate);
return result;
})// Array of strings ['foo', 'bar.baz'] => map(recurse), then filter out empty items
.intercept(isStringArray, async (visitor, options, populate, { recurse })=>{
const paths = await Promise.all(populate.map((subClause)=>recurse(visitor, options, subClause)));
return paths.filter((item)=>!isNil(item));
})// for wildcard, generate custom utilities to modify the values
.parse(isWildcard, ()=>({
/**
* Since value is '*', we don't need to transform it
*/ transform: identity,
/**
* '*' isn't a key/value structure, so regardless
* of the given key, it returns the data ('*')
*/ get: (_key, data)=>data,
/**
* '*' isn't a key/value structure, so regardless
* of the given `key`, use `value` as the new `data`
*/ set: (_key, value)=>value,
/**
* '*' isn't a key/value structure, but we need to simulate at least one to enable
* the data traversal. We're using '' since it represents a falsy string value
*/ keys: constant([
''
]),
/**
* Removing '*' means setting it to undefined, regardless of the given key
*/ remove: constant(undefined)
}))// Parse string values
.parse(isString, ()=>{
const tokenize = split('.');
const recompose = join('.');
return {
transform: trim,
remove (key, data) {
const [root] = tokenize(data);
return root === key ? undefined : data;
},
set (key, value, data) {
const [root] = tokenize(data);
if (root !== key) {
return data;
}
return isNil(value) || isEmpty(value) ? root : `${root}.${value}`;
},
keys (data) {
const v = first(tokenize(data));
return v ? [
v
] : [];
},
get (key, data) {
const [root, ...rest] = tokenize(data);
return key === root ? recompose(rest) : undefined;
}
};
})// Parse object values
.parse(isObj, ()=>({
transform: cloneDeep,
remove (key, data) {
// eslint-disable-next-line no-unused-vars
const { [key]: ignored, ...rest } = data;
return rest;
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
})).ignore(({ key, attribute })=>{
// we don't want to recurse using traversePopulate and instead let
// the visitors recurse with the appropriate traversal (sort, filters, etc...)
return [
'sort',
'filters',
'fields'
].includes(key) && !attribute;
}).on(// Handle recursion on populate."populate"
isKeyword('populate'), async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse })=>{
const parent = {
key,
path,
schema,
attribute
};
const newValue = await recurse(visitor, {
schema,
path,
getModel,
parent
}, value);
set(key, newValue);
}).on(isKeyword('on'), async ({ key, visitor, path, value, getModel, parent }, { set, recurse })=>{
const newOn = {};
if (!isObj(value)) {
return;
}
for (const [uid, subPopulate] of Object.entries(value)){
const model = getModel(uid);
const newPath = {
...path,
raw: `${path.raw}[${uid}]`
};
newOn[uid] = await recurse(visitor, {
schema: model,
path: newPath,
getModel,
parent
}, subPopulate);
}
set(key, newOn);
})// Handle populate on relation
.onRelation(async ({ key, value, attribute, visitor, path, schema, getModel }, { set, recurse })=>{
if (isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
if (isMorphToRelationalAttribute(attribute)) {
// Don't traverse values that cannot be parsed
if (!isObject(value) || !('on' in value && isObject(value?.on))) {
return;
}
// If there is a populate fragment defined, traverse it
const newValue = await recurse(visitor, {
schema,
path,
getModel,
parent
}, {
on: value?.on
});
set(key, newValue);
return;
}
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on media
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
if (isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on components
.onComponent(async ({ key, value, schema, visitor, path, attribute, getModel }, { recurse, set })=>{
if (isNil(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle populate on dynamic zones
.onDynamicZone(async ({ key, value, schema, visitor, path, attribute, getModel }, { set, recurse })=>{
if (isNil(value) || !isObject(value)) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
// Handle fragment syntax
if ('on' in value && value.on) {
const newOn = await recurse(visitor, {
schema,
path,
getModel,
parent
}, {
on: value.on
});
set(key, newOn);
}
});
var traverseQueryPopulate = curry(populate.traverse);
const objectPopulateToPaths = (input)=>{
const paths = [];
function traverse(currentObj, parentPath) {
for (const [key, value] of Object.entries(currentObj)){
const currentPath = parentPath ? `${parentPath}.${key}` : key;
if (value === true) {
paths.push(currentPath);
} else {
traverse(value.populate, currentPath);
}
}
}
traverse(input, '');
return paths;
};
const pathsToObjectPopulate = (input)=>{
const result = {};
function traverse(object, keys) {
const [first, ...rest] = keys;
if (rest.length === 0) {
object[first] = true;
} else {
if (!object[first] || typeof object[first] === 'boolean') {
object[first] = {
populate: {}
};
}
traverse(object[first].populate, rest);
}
}
input.forEach((clause)=>traverse(result, clause.split('.')));
return result;
};
export { traverseQueryPopulate as default };
//# sourceMappingURL=query-populate.mjs.map
@@ -0,0 +1 @@
{"version":3,"file":"query-populate.mjs","sources":["../../src/traverse/query-populate.ts"],"sourcesContent":["import {\n curry,\n isString,\n isArray,\n isEmpty,\n split,\n isObject,\n trim,\n constant,\n isNil,\n identity,\n cloneDeep,\n join,\n first,\n} from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\nimport { Attribute } from '../types';\nimport { isMorphToRelationalAttribute } from '../content-types';\n\nconst isKeyword = (keyword: string) => {\n return ({ key, attribute }: { key: string; attribute: Attribute }) => {\n return !attribute && keyword === key;\n };\n};\n\nconst isWildcard = (value: unknown): value is '*' => value === '*';\n\nconst isPopulateString = (value: unknown): value is string => {\n return isString(value) && !isWildcard(value);\n};\n\nconst isStringArray = (value: unknown): value is string[] =>\n isArray(value) && value.every(isString);\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst populate = traverseFactory()\n .intercept(isPopulateString, async (visitor, options, populate, { recurse }) => {\n /**\n * Ensure the populate clause its in the extended format ( { populate: { ... } }, and not just a string)\n * This gives a consistent structure to track the \"parent\" node of each nested populate clause\n */\n const populateObject = pathsToObjectPopulate([populate]);\n const traversedPopulate = (await recurse(visitor, options, populateObject)) as PopulateObject;\n const [result] = objectPopulateToPaths(traversedPopulate);\n\n return result;\n })\n // Array of strings ['foo', 'bar.baz'] => map(recurse), then filter out empty items\n .intercept(isStringArray, async (visitor, options, populate, { recurse }) => {\n const paths = await Promise.all(\n populate.map((subClause) => recurse(visitor, options, subClause))\n );\n\n return paths.filter((item) => !isNil(item));\n })\n // for wildcard, generate custom utilities to modify the values\n .parse(isWildcard, () => ({\n /**\n * Since value is '*', we don't need to transform it\n */\n transform: identity,\n\n /**\n * '*' isn't a key/value structure, so regardless\n * of the given key, it returns the data ('*')\n */\n get: (_key, data) => data,\n\n /**\n * '*' isn't a key/value structure, so regardless\n * of the given `key`, use `value` as the new `data`\n */\n set: (_key, value) => value,\n\n /**\n * '*' isn't a key/value structure, but we need to simulate at least one to enable\n * the data traversal. We're using '' since it represents a falsy string value\n */\n keys: constant(['']),\n\n /**\n * Removing '*' means setting it to undefined, regardless of the given key\n */\n remove: constant(undefined),\n }))\n\n // Parse string values\n .parse(isString, () => {\n const tokenize = split('.');\n const recompose = join('.');\n\n return {\n transform: trim,\n\n remove(key, data) {\n const [root] = tokenize(data);\n\n return root === key ? undefined : data;\n },\n\n set(key, value, data) {\n const [root] = tokenize(data);\n\n if (root !== key) {\n return data;\n }\n\n return isNil(value) || isEmpty(value) ? root : `${root}.${value}`;\n },\n\n keys(data) {\n const v = first(tokenize(data));\n return v ? [v] : [];\n },\n\n get(key, data) {\n const [root, ...rest] = tokenize(data);\n\n return key === root ? recompose(rest) : undefined;\n },\n };\n })\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n // eslint-disable-next-line no-unused-vars\n const { [key]: ignored, ...rest } = data;\n\n return rest;\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n .ignore(({ key, attribute }) => {\n // we don't want to recurse using traversePopulate and instead let\n // the visitors recurse with the appropriate traversal (sort, filters, etc...)\n return ['sort', 'filters', 'fields'].includes(key) && !attribute;\n })\n .on(\n // Handle recursion on populate.\"populate\"\n isKeyword('populate'),\n async ({ key, visitor, path, value, schema, getModel, attribute }, { set, recurse }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const newValue = await recurse(visitor, { schema, path, getModel, parent }, value);\n\n set(key, newValue);\n }\n )\n .on(\n isKeyword('on'),\n async ({ key, visitor, path, value, getModel, parent }, { set, recurse }) => {\n const newOn: Record<string, unknown> = {};\n\n if (!isObj(value)) {\n return;\n }\n\n for (const [uid, subPopulate] of Object.Line truncated
+4
View File
@@ -0,0 +1,4 @@
/// <reference types="lodash" />
declare const _default: import("lodash").CurriedFunction3<import("./factory").Visitor, import("./factory").TraverseOptions, unknown, Promise<unknown>>;
export default _default;
//# sourceMappingURL=query-sort.d.ts.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-sort.d.ts","sourceRoot":"","sources":["../../src/traverse/query-sort.ts"],"names":[],"mappings":";;AA+LA,wBAAoC"}
+144
View File
@@ -0,0 +1,144 @@
'use strict';
var fp = require('lodash/fp');
var factory = require('./factory.js');
const ORDERS = {
asc: 'asc',
desc: 'desc'
};
const ORDER_VALUES = Object.values(ORDERS);
const isSortOrder = (value)=>ORDER_VALUES.includes(value.toLowerCase());
const isStringArray = (value)=>Array.isArray(value) && value.every(fp.isString);
const isObjectArray = (value)=>Array.isArray(value) && value.every(fp.isObject);
const isNestedSorts = (value)=>fp.isString(value) && value.split(',').length > 1;
const isObj = (value)=>fp.isObject(value);
const sort = factory().intercept(// String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose
isNestedSorts, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.split(',').map(fp.trim).map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((part)=>!fp.isEmpty(part)).join(','));
}).intercept(// Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
isStringArray, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!fp.isEmpty(nestedSort)));
}).intercept(// Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items
isObjectArray, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!fp.isEmpty(nestedSort)));
})// Parse string values
.parse(fp.isString, ()=>{
const tokenize = fp.pipe(fp.split('.'), fp.map(fp.split(':')), fp.flatten);
const recompose = (parts)=>{
if (parts.length === 0) {
return undefined;
}
return parts.reduce((acc, part)=>{
if (fp.isEmpty(part)) {
return acc;
}
if (acc === '') {
return part;
}
return isSortOrder(part) ? `${acc}:${part}` : `${acc}.${part}`;
}, '');
};
return {
transform: fp.trim,
remove (key, data) {
const [root] = tokenize(data);
return root === key ? undefined : data;
},
set (key, value, data) {
const [root] = tokenize(data);
if (root !== key) {
return data;
}
return fp.isNil(value) ? root : `${root}.${value}`;
},
keys (data) {
const v = fp.first(tokenize(data));
return v ? [
v
] : [];
},
get (key, data) {
const [root, ...rest] = tokenize(data);
return key === root ? recompose(rest) : undefined;
}
};
})// Parse object values
.parse(isObj, ()=>({
transform: fp.cloneDeep,
remove (key, data) {
// eslint-disable-next-line no-unused-vars
const { [key]: ignored, ...rest } = data;
return rest;
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
}))// Handle deep sort on relation
.onRelation(async ({ key, value, attribute, visitor, path, getModel, schema }, { set, recurse })=>{
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
if (isMorphRelation) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle deep sort on media
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle deep sort on components
.onComponent(async ({ key, value, visitor, path, schema, attribute, getModel }, { recurse, set })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
});
var traverseQuerySort = fp.curry(sort.traverse);
module.exports = traverseQuerySort;
//# sourceMappingURL=query-sort.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-sort.js","sources":["../../src/traverse/query-sort.ts"],"sourcesContent":["import {\n curry,\n isString,\n isObject,\n map,\n trim,\n split,\n isEmpty,\n flatten,\n pipe,\n isNil,\n first,\n cloneDeep,\n} from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst ORDERS = { asc: 'asc', desc: 'desc' };\nconst ORDER_VALUES = Object.values(ORDERS);\n\nconst isSortOrder = (value: string) => ORDER_VALUES.includes(value.toLowerCase());\nconst isStringArray = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every(isString);\nconst isObjectArray = (value: unknown): value is object[] =>\n Array.isArray(value) && value.every(isObject);\nconst isNestedSorts = (value: unknown): value is string =>\n isString(value) && value.split(',').length > 1;\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst sort = traverseFactory()\n .intercept(\n // String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose\n isNestedSorts,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(\n sort\n .split(',')\n .map(trim)\n .map((nestedSort) => recurse(visitor, options, nestedSort))\n ).then((res) => res.filter((part) => !isEmpty(part)).join(','));\n }\n )\n .intercept(\n // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items\n isStringArray,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(sort.map((nestedSort) => recurse(visitor, options, nestedSort))).then(\n (res) => res.filter((nestedSort) => !isEmpty(nestedSort))\n );\n }\n )\n .intercept(\n // Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items\n isObjectArray,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(sort.map((nestedSort) => recurse(visitor, options, nestedSort))).then(\n (res) => res.filter((nestedSort) => !isEmpty(nestedSort))\n );\n }\n )\n // Parse string values\n .parse(isString, () => {\n const tokenize = pipe(split('.'), map(split(':')), flatten);\n const recompose = (parts: string[]) => {\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.reduce((acc, part) => {\n if (isEmpty(part)) {\n return acc;\n }\n\n if (acc === '') {\n return part;\n }\n\n return isSortOrder(part) ? `${acc}:${part}` : `${acc}.${part}`;\n }, '');\n };\n\n return {\n transform: trim,\n\n remove(key, data) {\n const [root] = tokenize(data);\n\n return root === key ? undefined : data;\n },\n\n set(key, value, data) {\n const [root] = tokenize(data);\n\n if (root !== key) {\n return data;\n }\n\n return isNil(value) ? root : `${root}.${value}`;\n },\n\n keys(data) {\n const v = first(tokenize(data));\n return v ? [v] : [];\n },\n\n get(key, data) {\n const [root, ...rest] = tokenize(data);\n\n return key === root ? recompose(rest) : undefined;\n },\n };\n })\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n // eslint-disable-next-line no-unused-vars\n const { [key]: ignored, ...rest } = data;\n\n return rest;\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Handle deep sort on relation\n .onRelation(\n async ({ key, value, attribute, visitor, path, getModel, schema }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle deep sort on media\n .onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n })\n // Handle deep sort on components\n .onComponent(\n async ({ key, value, visitor, path, schema, attribute, getModel }, { recurse, set }) => {\n conLine truncated
+142
View File
@@ -0,0 +1,142 @@
import { trim, isEmpty, isString, pipe, split, map, flatten, isNil, first, cloneDeep, curry, isObject } from 'lodash/fp';
import traverseFactory from './factory.mjs';
const ORDERS = {
asc: 'asc',
desc: 'desc'
};
const ORDER_VALUES = Object.values(ORDERS);
const isSortOrder = (value)=>ORDER_VALUES.includes(value.toLowerCase());
const isStringArray = (value)=>Array.isArray(value) && value.every(isString);
const isObjectArray = (value)=>Array.isArray(value) && value.every(isObject);
const isNestedSorts = (value)=>isString(value) && value.split(',').length > 1;
const isObj = (value)=>isObject(value);
const sort = traverseFactory().intercept(// String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose
isNestedSorts, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.split(',').map(trim).map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((part)=>!isEmpty(part)).join(','));
}).intercept(// Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
isStringArray, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!isEmpty(nestedSort)));
}).intercept(// Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items
isObjectArray, async (visitor, options, sort, { recurse })=>{
return Promise.all(sort.map((nestedSort)=>recurse(visitor, options, nestedSort))).then((res)=>res.filter((nestedSort)=>!isEmpty(nestedSort)));
})// Parse string values
.parse(isString, ()=>{
const tokenize = pipe(split('.'), map(split(':')), flatten);
const recompose = (parts)=>{
if (parts.length === 0) {
return undefined;
}
return parts.reduce((acc, part)=>{
if (isEmpty(part)) {
return acc;
}
if (acc === '') {
return part;
}
return isSortOrder(part) ? `${acc}:${part}` : `${acc}.${part}`;
}, '');
};
return {
transform: trim,
remove (key, data) {
const [root] = tokenize(data);
return root === key ? undefined : data;
},
set (key, value, data) {
const [root] = tokenize(data);
if (root !== key) {
return data;
}
return isNil(value) ? root : `${root}.${value}`;
},
keys (data) {
const v = first(tokenize(data));
return v ? [
v
] : [];
},
get (key, data) {
const [root, ...rest] = tokenize(data);
return key === root ? recompose(rest) : undefined;
}
};
})// Parse object values
.parse(isObj, ()=>({
transform: cloneDeep,
remove (key, data) {
// eslint-disable-next-line no-unused-vars
const { [key]: ignored, ...rest } = data;
return rest;
},
set (key, value, data) {
return {
...data,
[key]: value
};
},
keys (data) {
return Object.keys(data);
},
get (key, data) {
return data[key];
}
}))// Handle deep sort on relation
.onRelation(async ({ key, value, attribute, visitor, path, getModel, schema }, { set, recurse })=>{
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
if (isMorphRelation) {
return;
}
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = attribute.target;
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle deep sort on media
.onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchemaUID = 'plugin::upload.file';
const targetSchema = getModel(targetSchemaUID);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
})// Handle deep sort on components
.onComponent(async ({ key, value, visitor, path, schema, attribute, getModel }, { recurse, set })=>{
const parent = {
key,
path,
schema,
attribute
};
const targetSchema = getModel(attribute.component);
const newValue = await recurse(visitor, {
schema: targetSchema,
path,
getModel,
parent
}, value);
set(key, newValue);
});
var traverseQuerySort = curry(sort.traverse);
export { traverseQuerySort as default };
//# sourceMappingURL=query-sort.mjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"query-sort.mjs","sources":["../../src/traverse/query-sort.ts"],"sourcesContent":["import {\n curry,\n isString,\n isObject,\n map,\n trim,\n split,\n isEmpty,\n flatten,\n pipe,\n isNil,\n first,\n cloneDeep,\n} from 'lodash/fp';\n\nimport traverseFactory, { type Parent } from './factory';\n\nconst ORDERS = { asc: 'asc', desc: 'desc' };\nconst ORDER_VALUES = Object.values(ORDERS);\n\nconst isSortOrder = (value: string) => ORDER_VALUES.includes(value.toLowerCase());\nconst isStringArray = (value: unknown): value is string[] =>\n Array.isArray(value) && value.every(isString);\nconst isObjectArray = (value: unknown): value is object[] =>\n Array.isArray(value) && value.every(isObject);\nconst isNestedSorts = (value: unknown): value is string =>\n isString(value) && value.split(',').length > 1;\n\nconst isObj = (value: unknown): value is Record<string, unknown> => isObject(value);\n\nconst sort = traverseFactory()\n .intercept(\n // String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose\n isNestedSorts,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(\n sort\n .split(',')\n .map(trim)\n .map((nestedSort) => recurse(visitor, options, nestedSort))\n ).then((res) => res.filter((part) => !isEmpty(part)).join(','));\n }\n )\n .intercept(\n // Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items\n isStringArray,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(sort.map((nestedSort) => recurse(visitor, options, nestedSort))).then(\n (res) => res.filter((nestedSort) => !isEmpty(nestedSort))\n );\n }\n )\n .intercept(\n // Array of objects [{ foo: 'asc' }, { bar: 'desc', baz: 'asc' }] => map(recurse), then filter out empty items\n isObjectArray,\n async (visitor, options, sort, { recurse }) => {\n return Promise.all(sort.map((nestedSort) => recurse(visitor, options, nestedSort))).then(\n (res) => res.filter((nestedSort) => !isEmpty(nestedSort))\n );\n }\n )\n // Parse string values\n .parse(isString, () => {\n const tokenize = pipe(split('.'), map(split(':')), flatten);\n const recompose = (parts: string[]) => {\n if (parts.length === 0) {\n return undefined;\n }\n\n return parts.reduce((acc, part) => {\n if (isEmpty(part)) {\n return acc;\n }\n\n if (acc === '') {\n return part;\n }\n\n return isSortOrder(part) ? `${acc}:${part}` : `${acc}.${part}`;\n }, '');\n };\n\n return {\n transform: trim,\n\n remove(key, data) {\n const [root] = tokenize(data);\n\n return root === key ? undefined : data;\n },\n\n set(key, value, data) {\n const [root] = tokenize(data);\n\n if (root !== key) {\n return data;\n }\n\n return isNil(value) ? root : `${root}.${value}`;\n },\n\n keys(data) {\n const v = first(tokenize(data));\n return v ? [v] : [];\n },\n\n get(key, data) {\n const [root, ...rest] = tokenize(data);\n\n return key === root ? recompose(rest) : undefined;\n },\n };\n })\n // Parse object values\n .parse(isObj, () => ({\n transform: cloneDeep,\n\n remove(key, data) {\n // eslint-disable-next-line no-unused-vars\n const { [key]: ignored, ...rest } = data;\n\n return rest;\n },\n\n set(key, value, data) {\n return { ...data, [key]: value };\n },\n\n keys(data) {\n return Object.keys(data);\n },\n\n get(key, data) {\n return data[key];\n },\n }))\n // Handle deep sort on relation\n .onRelation(\n async ({ key, value, attribute, visitor, path, getModel, schema }, { set, recurse }) => {\n const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');\n\n if (isMorphRelation) {\n return;\n }\n\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = attribute.target;\n const targetSchema = getModel(targetSchemaUID!);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n }\n )\n // Handle deep sort on media\n .onMedia(async ({ key, path, schema, attribute, visitor, value, getModel }, { recurse, set }) => {\n const parent: Parent = { key, path, schema, attribute };\n\n const targetSchemaUID = 'plugin::upload.file';\n const targetSchema = getModel(targetSchemaUID);\n\n const newValue = await recurse(\n visitor,\n { schema: targetSchema, path, getModel, parent },\n value\n );\n\n set(key, newValue);\n })\n // Handle deep sort on components\n .onComponent(\n async ({ key, value, visitor, path, schema, attribute, getModel }, { recurse, set }) => {\n coLine truncated