This is my version for helpers/populate.js and fits my needs … hope it helps
const { createCoreController } = require('@strapi/strapi').factories;
const DEFAULT_POPULATE = { populate: '*' };
const getPathForComponent = (componentDir, componentName) => {
if (componentName.startsWith('api::')) {
const parts = componentName.split('::')[1].split('.');
return `../api/${parts[0]}/content-types/${parts[1]}/schema.json`;
}
return `../components/${componentDir}/${componentName}.json`;
};
const getComponentAttributes = (componentDir, componentName) => {
try {
return Object.entries(require(getPathForComponent(componentDir, componentName)).attributes);
} catch (error) {
console.error(`Error loading attributes for component: ${componentName}`, error);
return [];
}
};
const populateComponent = (component) => {
const componentAttributes = getComponentAttributes(...component.split('.'));
const attrPopulates = componentAttributes.reduce((acc, [attributeName, attribute]) => {
return { ...acc, [attributeName]: populateAttribute(attribute) };
}, {});
return { ...DEFAULT_POPULATE, ...attrPopulates };
};
const populateDynamicZone = ({ components }) => {
if (!components) return DEFAULT_POPULATE;
return {
populate: components.reduce((acc, component) => {
const componentAttributes = Object.entries(require(getPathForComponent(...component.split('.'))).attributes)
.filter(([, attr]) => ['component', 'relation', 'media', 'dynamiczone'].includes(attr.type));
const attrPopulates = componentAttributes.reduce((innerAcc, [attributeName]) => {
return { ...innerAcc, [attributeName]: DEFAULT_POPULATE };
}, {});
return { ...acc, [component.split('.').pop()]: DEFAULT_POPULATE, ...attrPopulates };
}, {})
};
};
const populateAttribute = (attribute) => {
switch (attribute.type) {
case 'component':
return populateComponent(attribute.component);
case 'relation':
const componentAttributes = getComponentAttributes("", attribute.target);
const attrPopulates = componentAttributes.reduce((acc, [attributeName, attr]) => {
return { ...acc, [attributeName]: populateAttribute(attr) };
}, {});
return { ...DEFAULT_POPULATE, ...attrPopulates };
case 'dynamiczone':
return populateDynamicZone(attribute);
default:
return DEFAULT_POPULATE;
}
};
const getPopulateFromSchema = (schema) => {
return Object.keys(schema.attributes).reduce((acc, attributeName) => {
return { ...acc, [attributeName]: populateAttribute(schema.attributes[attributeName]) };
}, {});
};
function createPopulatedController(uid, schema) {
return createCoreController(uid, () => {
return {
async find(ctx) {
ctx.query = { ...ctx.query, populate: getPopulateFromSchema(schema) };
return await super.find(ctx);
},
async findOne(ctx) {
ctx.query = { ...ctx.query, populate: getPopulateFromSchema(schema) };
return await super.findOne(ctx);
},
};
});
}
module.exports = createPopulatedController;