@anywayseo/gatsby-plugin 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/gatsby-node.d.ts +4 -4
  2. package/gatsby-node.js +60 -80
  3. package/index.d.ts +1 -0
  4. package/index.js +5 -0
  5. package/package.json +14 -6
  6. package/types/index.d.ts +33 -0
  7. package/types/index.js +2 -0
  8. package/utils/slug.d.ts +2 -0
  9. package/utils/slug.js +8 -0
  10. package/utils/source.d.ts +2 -0
  11. package/utils/source.js +15 -0
  12. package/utils/strapi-source/index.d.ts +5 -0
  13. package/utils/strapi-source/index.js +13 -0
  14. package/utils/strapi-source/schema/components.d.ts +1 -0
  15. package/utils/strapi-source/schema/components.js +152 -0
  16. package/utils/strapi-source/schema/index.d.ts +1 -0
  17. package/utils/strapi-source/schema/index.js +10 -0
  18. package/utils/strapi-source/schema/localization.d.ts +1 -0
  19. package/utils/strapi-source/schema/localization.js +14 -0
  20. package/utils/strapi-source/schema/navigation.d.ts +1 -0
  21. package/utils/strapi-source/schema/navigation.js +25 -0
  22. package/utils/strapi-source/schema/page.d.ts +1 -0
  23. package/utils/strapi-source/schema/page.js +17 -0
  24. package/utils/strapi-source/schema/shared.d.ts +1 -0
  25. package/utils/strapi-source/schema/shared.js +22 -0
  26. package/utils/strapi-source/schema/site.d.ts +1 -0
  27. package/utils/strapi-source/schema/site.js +14 -0
  28. package/utils/{strapi-client.d.ts → strapi-source/strapi-client/index.d.ts} +2 -1
  29. package/utils/strapi-source/strapi-client/index.js +44 -0
  30. package/utils/strapi-source/strapi-content/clean-entity.d.ts +2 -0
  31. package/utils/strapi-source/strapi-content/clean-entity.js +93 -0
  32. package/utils/strapi-source/strapi-content/create-nodes.d.ts +3 -0
  33. package/utils/strapi-source/strapi-content/create-nodes.js +202 -0
  34. package/utils/strapi-source/strapi-content/delete-nodes.d.ts +3 -0
  35. package/utils/strapi-source/strapi-content/delete-nodes.js +76 -0
  36. package/utils/strapi-source/strapi-content/download-media.d.ts +15 -0
  37. package/utils/strapi-source/strapi-content/download-media.js +174 -0
  38. package/utils/strapi-source/strapi-content/fetch-entity.d.ts +4 -0
  39. package/utils/strapi-source/strapi-content/fetch-entity.js +35 -0
  40. package/utils/strapi-source/strapi-content/fetch-schemas.d.ts +3 -0
  41. package/utils/strapi-source/strapi-content/fetch-schemas.js +23 -0
  42. package/utils/strapi-source/strapi-content/get-cached-entities.d.ts +3 -0
  43. package/utils/strapi-source/strapi-content/get-cached-entities.js +27 -0
  44. package/utils/strapi-source/strapi-content/get-endpoints.d.ts +2 -0
  45. package/utils/strapi-source/strapi-content/get-endpoints.js +32 -0
  46. package/utils/strapi-source/strapi-content/get-entities.d.ts +2 -0
  47. package/utils/strapi-source/strapi-content/get-entities.js +17 -0
  48. package/utils/strapi-source/strapi-content/helpers.d.ts +9 -0
  49. package/utils/strapi-source/strapi-content/helpers.js +56 -0
  50. package/utils/strapi-source/strapi-content/index.d.ts +3 -0
  51. package/utils/strapi-source/strapi-content/index.js +113 -0
  52. package/utils/strapi-source/strapi-content/types.d.ts +43 -0
  53. package/utils/strapi-source/strapi-content/types.js +2 -0
  54. package/utils/strapi-source/strapi-content/utils.d.ts +5 -0
  55. package/utils/strapi-source/strapi-content/utils.js +30 -0
  56. package/utils/strapi-source/strapi-localization/index.d.ts +3 -0
  57. package/utils/strapi-source/strapi-localization/index.js +38 -0
  58. package/utils/strapi-source/strapi-localization/types.d.ts +9 -0
  59. package/utils/strapi-source/strapi-localization/types.js +2 -0
  60. package/utils/strapi-source/strapi-navigation/index.d.ts +3 -0
  61. package/utils/strapi-source/strapi-navigation/index.js +48 -0
  62. package/utils/strapi-source/strapi-navigation/types.d.ts +5 -0
  63. package/utils/strapi-source/strapi-navigation/types.js +2 -0
  64. package/utils/schema.d.ts +0 -1
  65. package/utils/schema.js +0 -194
  66. package/utils/strapi-client.js +0 -20
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.site = void 0;
4
+ exports.site = `
5
+ # === STRAPI SITE DEFINITIONS ===
6
+ type StrapiSite implements Node {
7
+ id: ID!
8
+ name: String
9
+ locale: String
10
+ currency: String
11
+ seo: Seo
12
+ logo: Image
13
+ }
14
+ `;
@@ -2,5 +2,6 @@ export declare class StrapiClient {
2
2
  private apiUrl;
3
3
  private accessToken;
4
4
  constructor(apiUrl?: string, accessToken?: string);
5
- fetch(path: string): Promise<Response>;
5
+ fetch<T = any>(path: string): Promise<T>;
6
+ getApiUrl(): string;
6
7
  }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.StrapiClient = void 0;
13
+ class StrapiClient {
14
+ constructor(apiUrl, accessToken) {
15
+ if (!apiUrl || !accessToken) {
16
+ throw new Error('Missing STRAPI_API_URL or STRAPI_TOKEN in environment variables.');
17
+ }
18
+ this.apiUrl = apiUrl;
19
+ this.accessToken = accessToken;
20
+ }
21
+ fetch(path) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ try {
24
+ const result = yield fetch(`${this.apiUrl}/api/${path}`, {
25
+ headers: {
26
+ Authorization: `Bearer ${this.accessToken}`,
27
+ },
28
+ });
29
+ if (!result.ok) {
30
+ throw new Error(`Fetch Error with status ${result.status}: ${result.statusText}`);
31
+ }
32
+ const data = yield result.json();
33
+ return data;
34
+ }
35
+ catch (error) {
36
+ throw new Error(`Error occurred while fetching ${path}: ${error}`);
37
+ }
38
+ });
39
+ }
40
+ getApiUrl() {
41
+ return this.apiUrl;
42
+ }
43
+ }
44
+ exports.StrapiClient = StrapiClient;
@@ -0,0 +1,2 @@
1
+ import type { Entity, Schema } from './types';
2
+ export declare function cleanEntity(entity: Entity, contentTypeUid: string, schemas: Schema[]): Entity;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.cleanEntity = cleanEntity;
4
+ const helpers_1 = require("./helpers");
5
+ const utils_1 = require("./utils");
6
+ const MEDIA_FIELDS = [
7
+ 'id',
8
+ 'name',
9
+ 'alternativeText',
10
+ 'caption',
11
+ 'width',
12
+ 'height',
13
+ 'formats',
14
+ 'hash',
15
+ 'ext',
16
+ 'mime',
17
+ 'size',
18
+ 'url',
19
+ 'previewUrl',
20
+ 'createdAt',
21
+ 'updatedAt',
22
+ 'documentId',
23
+ 'publishedAt',
24
+ ];
25
+ const restrictedFields = new Set(['__component', 'children', 'fields', 'internal', 'parent']);
26
+ function cleanAttributes(entity, currentSchema, schemas) {
27
+ return Object.entries(entity).reduce((accumulator, [name, value]) => {
28
+ const attribute = currentSchema.schema.attributes[name];
29
+ const attributeName = restrictedFields.has(name)
30
+ ? (0, utils_1.toSnakeCase)(`strapi_${name.startsWith('__') ? name.slice(2) : name}`)
31
+ : name;
32
+ if (!(attribute === null || attribute === void 0 ? void 0 : attribute.type)) {
33
+ accumulator[attributeName] = value;
34
+ return accumulator;
35
+ }
36
+ if (attribute.type === 'richtext') {
37
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: {
38
+ data: value || '',
39
+ medias: [],
40
+ } });
41
+ }
42
+ if (!value) {
43
+ accumulator[attributeName] = value;
44
+ return accumulator;
45
+ }
46
+ if (attribute.type === 'dynamiczone') {
47
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: value.map((entity) => {
48
+ const schema = (0, helpers_1.getContentTypeSchema)(schemas, entity.__component);
49
+ if (!schema) {
50
+ return entity;
51
+ }
52
+ return cleanAttributes(entity, schema, schemas);
53
+ }) });
54
+ }
55
+ if (attribute.type === 'component') {
56
+ const schema = (0, helpers_1.getContentTypeSchema)(schemas, attribute.component);
57
+ if (!schema) {
58
+ return accumulator;
59
+ }
60
+ if (attribute.repeatable) {
61
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: value.map((entity) => cleanAttributes(entity, schema, schemas)) });
62
+ }
63
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: cleanAttributes(value, schema, schemas) });
64
+ }
65
+ if (attribute.type === 'media') {
66
+ if (Array.isArray(value)) {
67
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: value.map((data) => (0, utils_1.pick)(data, MEDIA_FIELDS)) });
68
+ }
69
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: value ? (0, utils_1.pick)(value, MEDIA_FIELDS) : undefined });
70
+ }
71
+ if (attribute.type === 'relation') {
72
+ const schema = (0, helpers_1.getContentTypeSchema)(schemas, attribute.target);
73
+ if (!schema) {
74
+ return accumulator;
75
+ }
76
+ if (Array.isArray(value)) {
77
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: value.map((data) => {
78
+ return cleanAttributes(data, schema, schemas);
79
+ }) });
80
+ }
81
+ return Object.assign(Object.assign({}, accumulator), { [attributeName]: cleanAttributes(value, schema, schemas) });
82
+ }
83
+ accumulator[attributeName] = value;
84
+ return accumulator;
85
+ }, {});
86
+ }
87
+ function cleanEntity(entity, contentTypeUid, schemas) {
88
+ const contentTypeSchema = (0, helpers_1.getContentTypeSchema)(schemas, contentTypeUid);
89
+ if (!contentTypeSchema) {
90
+ return entity;
91
+ }
92
+ return cleanAttributes(entity, contentTypeSchema, schemas);
93
+ }
@@ -0,0 +1,3 @@
1
+ import type { NodeInput, SourceNodesArgs } from 'gatsby';
2
+ import type { Entity, Schema } from './types';
3
+ export declare function createNodes(entity: Entity, uid: string, schemas: Schema[], actions: SourceNodesArgs): NodeInput[];
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNodes = createNodes;
4
+ const helpers_1 = require("./helpers");
5
+ const utils_1 = require("./utils");
6
+ function prepareNodeId(parentNode, attributeName, name) {
7
+ return `${parentNode[utils_1.STRAPI_ID_PROPERTY]}-${parentNode.internal.type}-${attributeName}-${name}`;
8
+ }
9
+ function prepareTextNode(text, context) {
10
+ const { parentNode, attributeName, actions } = context;
11
+ const { createContentDigest, createNodeId } = actions;
12
+ const id = createNodeId(prepareNodeId(parentNode, attributeName, 'TextNode'));
13
+ const textNode = {
14
+ id,
15
+ parent: parentNode.id,
16
+ children: [],
17
+ internal: {
18
+ type: `${parentNode.internal.type}_${attributeName}_TextNode`.toUpperCase(),
19
+ mediaType: `text/markdown`,
20
+ content: text,
21
+ contentDigest: createContentDigest(text),
22
+ },
23
+ [attributeName]: text,
24
+ };
25
+ return textNode;
26
+ }
27
+ function prepareJsonNode(json, context) {
28
+ const { parentNode, attributeName, actions } = context;
29
+ const { createContentDigest, createNodeId } = actions;
30
+ const id = createNodeId(prepareNodeId(parentNode, attributeName, 'JSONNode'));
31
+ const jsonNode = {
32
+ id,
33
+ parent: parentNode.id,
34
+ children: [],
35
+ internal: {
36
+ type: `${parentNode.internal.type}_${attributeName}_JSONNode`.toUpperCase(),
37
+ mediaType: `application/json`,
38
+ content: JSON.stringify(json),
39
+ contentDigest: createContentDigest(json),
40
+ },
41
+ strapi_json_value: json,
42
+ };
43
+ return jsonNode;
44
+ }
45
+ function prepareMediaNode(media, context) {
46
+ const { parentNode, actions } = context;
47
+ const { createNodeId, createContentDigest } = actions;
48
+ const nodeType = 'STRAPI__MEDIA';
49
+ const id = createNodeId(`${nodeType}-${media.id}`);
50
+ const mediaNode = Object.assign(Object.assign({}, media), { id, parent: parentNode.id, children: [], internal: {
51
+ type: nodeType,
52
+ content: JSON.stringify(media),
53
+ contentDigest: createContentDigest(media),
54
+ }, [utils_1.STRAPI_ID_PROPERTY]: media.id, documentId: media.documentId });
55
+ return mediaNode;
56
+ }
57
+ function prepareRelationNode(relation, context) {
58
+ const { parentNode, targetSchemaUid, schemas, actions } = context;
59
+ const { createNodeId, createContentDigest } = actions;
60
+ const nodeType = (0, helpers_1.makeParentNodeName)(schemas, targetSchemaUid);
61
+ const id = createNodeId(`${nodeType}-${relation.id}`);
62
+ const node = Object.assign(Object.assign({}, relation), { id, parent: parentNode.id, children: [], internal: {
63
+ type: nodeType,
64
+ content: JSON.stringify(relation),
65
+ contentDigest: createContentDigest(relation),
66
+ }, [utils_1.STRAPI_ID_PROPERTY]: relation.id, documentId: relation.documentId });
67
+ return node;
68
+ }
69
+ function createNodes(entity, uid, schemas, actions) {
70
+ var _a;
71
+ const { createNodeId, createContentDigest, getNode } = actions;
72
+ const nodes = [];
73
+ const nodeType = (0, helpers_1.makeParentNodeName)(schemas, uid);
74
+ const schema = (0, helpers_1.getContentTypeSchema)(schemas, uid);
75
+ if (!schema) {
76
+ return [];
77
+ }
78
+ let entryNode = {
79
+ id: createNodeId(`${nodeType}-${entity.id}`),
80
+ parent: null,
81
+ children: [],
82
+ internal: {
83
+ type: nodeType,
84
+ content: JSON.stringify(entity),
85
+ contentDigest: createContentDigest(entity),
86
+ },
87
+ [utils_1.STRAPI_ID_PROPERTY]: entity.id,
88
+ documentId: entity.documentId,
89
+ };
90
+ for (const attributeName of Object.keys(entity)) {
91
+ const value = entity[attributeName];
92
+ const attribute = schema.schema.attributes[attributeName];
93
+ const type = attribute === null || attribute === void 0 ? void 0 : attribute.type;
94
+ if (value) {
95
+ if (type === 'dynamiczone') {
96
+ for (const v of value) {
97
+ const componentNodeName = (0, helpers_1.makeParentNodeName)(schemas, v.strapi_component);
98
+ const componentsNodes = createNodes(v, v.strapi_component, schemas, actions).flat();
99
+ entity[`${attributeName}___NODE`] = [
100
+ ...(entity[`${attributeName}___NODE`] || []),
101
+ ...componentsNodes.filter(({ internal }) => internal.type === componentNodeName).map(({ id }) => id),
102
+ ];
103
+ for (const node of componentsNodes) {
104
+ nodes.push(node);
105
+ }
106
+ }
107
+ delete entity[attributeName];
108
+ }
109
+ if (type === 'component') {
110
+ const componentSchema = (0, helpers_1.getContentTypeSchema)(schemas, attribute.component);
111
+ if (!componentSchema) {
112
+ continue;
113
+ }
114
+ const componentNodeName = (0, helpers_1.makeParentNodeName)(schemas, componentSchema.uid);
115
+ if (attribute.repeatable) {
116
+ const componentNodes = value.flatMap((entity) => createNodes(entity, attribute.component, schemas, actions));
117
+ entity[`${attributeName}___NODE`] = componentNodes
118
+ .filter(({ internal }) => internal.type === componentNodeName)
119
+ .map(({ id }) => id);
120
+ for (const node of componentNodes) {
121
+ nodes.push(node);
122
+ }
123
+ }
124
+ else {
125
+ const componentNodes = createNodes(value, attribute.component, schemas, actions).flat();
126
+ const foundNode = componentNodes.find(({ internal }) => internal.type === componentNodeName);
127
+ if (foundNode) {
128
+ entity[`${attributeName}___NODE`] = foundNode.id;
129
+ }
130
+ for (const node of componentNodes) {
131
+ nodes.push(node);
132
+ }
133
+ }
134
+ delete entity[attributeName];
135
+ }
136
+ if (type === 'richtext') {
137
+ const textNode = prepareTextNode(value.data, { parentNode: entryNode, attributeName, actions });
138
+ entity[attributeName][`data___NODE`] = textNode.id;
139
+ nodes.push(textNode);
140
+ delete entity[attributeName].data;
141
+ }
142
+ if (type === 'json') {
143
+ const jsonNode = prepareJsonNode(value, { parentNode: entryNode, attributeName, actions });
144
+ entryNode.children = [...((_a = entryNode.children) !== null && _a !== void 0 ? _a : []), jsonNode.id];
145
+ entity[`${attributeName}___NODE`] = jsonNode.id;
146
+ nodes.push(jsonNode);
147
+ delete entity[attributeName];
148
+ }
149
+ if (type == 'media') {
150
+ const context = {
151
+ parentNode: entryNode,
152
+ actions,
153
+ };
154
+ if (Array.isArray(value)) {
155
+ const mediaNodes = value.map((relation) => prepareMediaNode(relation, context));
156
+ entity[`${attributeName}___NODE`] = mediaNodes.map(({ id }) => id);
157
+ for (const node of mediaNodes) {
158
+ if (!getNode(node.id)) {
159
+ nodes.push(node);
160
+ }
161
+ }
162
+ }
163
+ else {
164
+ const mediaNode = prepareMediaNode(value, context);
165
+ entity[`${attributeName}___NODE`] = mediaNode.id;
166
+ if (!getNode(mediaNode.id)) {
167
+ nodes.push(mediaNode);
168
+ }
169
+ }
170
+ delete entity[attributeName];
171
+ }
172
+ if (type === 'relation') {
173
+ const context = {
174
+ parentNode: entryNode,
175
+ targetSchemaUid: attribute.target,
176
+ schemas,
177
+ actions,
178
+ };
179
+ if (Array.isArray(value)) {
180
+ const relationNodes = value.map((relation) => prepareRelationNode(relation, context));
181
+ entity[`${attributeName}___NODE`] = relationNodes.map(({ id }) => id);
182
+ for (const node of relationNodes) {
183
+ if (!getNode(node.id)) {
184
+ nodes.push(node);
185
+ }
186
+ }
187
+ }
188
+ else {
189
+ const node = prepareRelationNode(value, context);
190
+ entity[`${attributeName}___NODE`] = node.id;
191
+ if (!getNode(node.id)) {
192
+ nodes.push(node);
193
+ }
194
+ }
195
+ delete entity[attributeName];
196
+ }
197
+ }
198
+ }
199
+ entryNode = Object.assign(Object.assign({}, entity), entryNode);
200
+ nodes.push(entryNode);
201
+ return nodes;
202
+ }
@@ -0,0 +1,3 @@
1
+ import type { SourceNodesArgs } from 'gatsby';
2
+ import type { Entity, SchemaEndpoint } from './types';
3
+ export declare function deleteNodes(data: Entity[][], endpoints: SchemaEndpoint[], args: SourceNodesArgs): void;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deleteNodes = deleteNodes;
4
+ const helpers_1 = require("./helpers");
5
+ const utils_1 = require("./utils");
6
+ const buildMapFromNodes = (nodes) => {
7
+ return nodes.reduce((map, node) => {
8
+ var _a, _b;
9
+ const id = node.id;
10
+ const nodeName = (_a = node.internal) === null || _a === void 0 ? void 0 : _a.type;
11
+ const strapiId = node[utils_1.STRAPI_ID_PROPERTY];
12
+ if (nodeName.includes('STRAPI__COMPONENT_')) {
13
+ return map;
14
+ }
15
+ if (nodeName.includes('_JSONNODE')) {
16
+ return map;
17
+ }
18
+ if (nodeName.includes('_TEXTNODE')) {
19
+ return map;
20
+ }
21
+ if (nodeName && id && strapiId) {
22
+ map[nodeName] = [{ id, [utils_1.STRAPI_ID_PROPERTY]: String(strapiId) }, ...((_b = map[nodeName]) !== null && _b !== void 0 ? _b : [])];
23
+ }
24
+ return map;
25
+ }, {});
26
+ };
27
+ const buildMapFromData = (data, endpoints) => {
28
+ const map = {};
29
+ if (data.length) {
30
+ for (const [index, { singularName }] of endpoints.entries()) {
31
+ const nodeName = (0, helpers_1.makeNodeName)(singularName);
32
+ if (data[index] && data[index].length) {
33
+ for (const entity of data[index]) {
34
+ map[nodeName] = [{ [utils_1.STRAPI_ID_PROPERTY]: entity.id }, ...(map[nodeName] || [])];
35
+ }
36
+ }
37
+ }
38
+ }
39
+ return map;
40
+ };
41
+ const buildNodesToRemoveMap = (nodes, data, endpoints) => {
42
+ const existingNodes = buildMapFromNodes(nodes);
43
+ const newNodes = buildMapFromData(data, endpoints);
44
+ const nodesToRemove = Object.entries(existingNodes).reduce((accumulator, [name, value]) => {
45
+ const currentNodes = newNodes[name];
46
+ if (!currentNodes) {
47
+ return accumulator;
48
+ }
49
+ accumulator[name] = value.filter((index) => {
50
+ return !currentNodes.some((node) => node[utils_1.STRAPI_ID_PROPERTY] === index[utils_1.STRAPI_ID_PROPERTY]);
51
+ });
52
+ return accumulator;
53
+ }, {});
54
+ return nodesToRemove;
55
+ };
56
+ function deleteNodes(data, endpoints, args) {
57
+ const { reporter, actions, getNode, getNodes } = args;
58
+ const { touchNode, deleteNode } = actions;
59
+ const strapiNodes = getNodes().filter(helpers_1.isStrapiOrFileNode);
60
+ for (const node of strapiNodes) {
61
+ touchNode(node);
62
+ }
63
+ const nodesToRemoveMap = buildNodesToRemoveMap(strapiNodes, data, endpoints);
64
+ for (const [nodeName, nodesToRemove] of Object.entries(nodesToRemoveMap)) {
65
+ if (nodesToRemove.length) {
66
+ reporter.info(`Strapi: ${nodeName} deleting ${nodesToRemove.length}`);
67
+ for (const { id } of nodesToRemove) {
68
+ const node = getNode(String(id));
69
+ if (node) {
70
+ touchNode(node);
71
+ deleteNode(node);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
@@ -0,0 +1,15 @@
1
+ import type { SourceNodesArgs } from 'gatsby';
2
+ import type { StrapiClient } from '../strapi-client';
3
+ import type { Entity, Schema } from './types';
4
+ interface IDownloadMediaConfig {
5
+ apiUrl: string;
6
+ remoteFileHeaders?: Record<string, string>;
7
+ }
8
+ interface IDownloadMediaContext {
9
+ schemas: Schema[];
10
+ strapiClient: StrapiClient;
11
+ config: IDownloadMediaConfig;
12
+ args: SourceNodesArgs;
13
+ }
14
+ export declare function downloadMediaFiles(entities: Entity[], uid: string, context: IDownloadMediaContext): Promise<void>;
15
+ export {};
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.downloadMediaFiles = downloadMediaFiles;
16
+ const gatsby_source_filesystem_1 = require("gatsby-source-filesystem");
17
+ const commonmark_1 = require("commonmark");
18
+ const qs_1 = __importDefault(require("qs"));
19
+ const helpers_1 = require("./helpers");
20
+ const reader = new commonmark_1.Parser();
21
+ /** Retrieves all medias from the markdown */
22
+ function extractFiles(text, apiUrl) {
23
+ var _a;
24
+ const files = [];
25
+ const parsed = reader.parse(text);
26
+ const walker = parsed.walker();
27
+ let event, node;
28
+ while ((event = walker.next())) {
29
+ node = event.node;
30
+ // process image nodes
31
+ if (event.entering && node.type === 'image') {
32
+ let destination;
33
+ const alternativeText = ((_a = node.firstChild) === null || _a === void 0 ? void 0 : _a.literal) || '';
34
+ if (typeof node.destination === 'string' && /^\//.test(node.destination)) {
35
+ destination = `${apiUrl}${node.destination}`;
36
+ }
37
+ else if (typeof node.destination === 'string' && /^http/i.test(node.destination)) {
38
+ destination = node.destination;
39
+ }
40
+ if (destination) {
41
+ files.push({ url: destination, src: node.destination, alternativeText });
42
+ }
43
+ }
44
+ }
45
+ return files.filter(Boolean);
46
+ }
47
+ /** Download file and create node */
48
+ function downloadFile(file, context) {
49
+ return __awaiter(this, void 0, void 0, function* () {
50
+ const { args, config } = context;
51
+ const { actions, cache, createNodeId, getNode } = args;
52
+ const { createNode, touchNode } = actions;
53
+ const { apiUrl, remoteFileHeaders } = config;
54
+ let fileNodeID = null;
55
+ const mediaDataCacheKey = `strapi-media-${file.id}`;
56
+ const cacheMediaData = yield cache.get(mediaDataCacheKey);
57
+ // If we have cached media data and it wasn't modified, reuse
58
+ // previously created file node to not try to redownload
59
+ if (cacheMediaData && cacheMediaData.updatedAt === file.updatedAt) {
60
+ fileNodeID = cacheMediaData.fileNodeID;
61
+ const existingNode = getNode(fileNodeID);
62
+ if (existingNode) {
63
+ touchNode(existingNode);
64
+ }
65
+ }
66
+ if (!fileNodeID) {
67
+ try {
68
+ const url = `${file.url.startsWith('http') ? '' : apiUrl}${file.url}`;
69
+ const fileNode = yield (0, gatsby_source_filesystem_1.createRemoteFileNode)({
70
+ url,
71
+ cache,
72
+ httpHeaders: remoteFileHeaders || {},
73
+ createNode,
74
+ createNodeId,
75
+ });
76
+ if (fileNode) {
77
+ fileNodeID = fileNode.id;
78
+ yield cache.set(mediaDataCacheKey, { fileNodeID, updatedAt: file.updatedAt });
79
+ }
80
+ }
81
+ catch (error) {
82
+ console.log('Error while downloading media occurred:', error);
83
+ }
84
+ }
85
+ return fileNodeID;
86
+ });
87
+ }
88
+ /** Extract images and create remote nodes for images in all fields. */
89
+ function extractImages(item, uid, context) {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ const { schemas, strapiClient, config } = context;
92
+ const { apiUrl } = config;
93
+ const schema = (0, helpers_1.getContentTypeSchema)(schemas, uid);
94
+ if (!schema) {
95
+ return;
96
+ }
97
+ for (const attributeName of Object.keys(item)) {
98
+ const value = item[attributeName];
99
+ const attribute = schema.schema.attributes[attributeName];
100
+ const type = attribute === null || attribute === void 0 ? void 0 : attribute.type;
101
+ if (value && type) {
102
+ if (type === 'richtext') {
103
+ const extractedFiles = extractFiles(value.data, apiUrl);
104
+ const files = yield Promise.all(extractedFiles.map((_a) => __awaiter(this, [_a], void 0, function* ({ url }) {
105
+ const filters = qs_1.default.stringify({ filters: { url: url.replace(`${apiUrl}`, '') } }, { encode: false });
106
+ const result = yield strapiClient.fetch(`upload/files?${filters}`);
107
+ const file = result.length ? result[0] : null;
108
+ if (!file) {
109
+ return;
110
+ }
111
+ const fileNodeID = yield downloadFile(file, context);
112
+ return { fileNodeID, file };
113
+ })));
114
+ const fileNodes = files.filter(Boolean);
115
+ for (const [index, fileNode] of fileNodes.entries()) {
116
+ if ((fileNode === null || fileNode === void 0 ? void 0 : fileNode.fileNodeID) && (fileNode === null || fileNode === void 0 ? void 0 : fileNode.file)) {
117
+ item[attributeName].medias.push({
118
+ alternativeText: extractedFiles[index].alternativeText,
119
+ url: extractedFiles[index].url,
120
+ src: extractedFiles[index].src,
121
+ localFile___NODE: fileNode.fileNodeID,
122
+ file: fileNode.file,
123
+ });
124
+ }
125
+ }
126
+ }
127
+ if (type === 'dynamiczone') {
128
+ for (const element of value) {
129
+ yield extractImages(element, element.strapi_component, context);
130
+ }
131
+ }
132
+ if (type === 'component') {
133
+ if (attribute.repeatable) {
134
+ for (const element of value) {
135
+ yield extractImages(element, attribute.component, context);
136
+ }
137
+ }
138
+ else {
139
+ yield extractImages(value, attribute.component, context);
140
+ }
141
+ }
142
+ if (type === 'relation') {
143
+ yield extractImages(value, attribute.target, context);
144
+ }
145
+ if (type === 'media') {
146
+ const isMultiple = attribute.multiple;
147
+ const imagesField = isMultiple ? value : [value];
148
+ // Dowload all files
149
+ const files = yield Promise.all(imagesField.map((file) => __awaiter(this, void 0, void 0, function* () {
150
+ const fileNodeID = yield downloadFile(file, context);
151
+ return fileNodeID;
152
+ })));
153
+ const images = files.filter(Boolean);
154
+ if (images && images.length > 0) {
155
+ if (isMultiple) {
156
+ for (let index = 0; index < value.length; index++) {
157
+ item[attributeName][index][`localFile___NODE`] = images[index];
158
+ }
159
+ }
160
+ else {
161
+ item[attributeName][`localFile___NODE`] = isMultiple ? images : images[0];
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+ });
168
+ }
169
+ // Downloads media from image type fields
170
+ function downloadMediaFiles(entities, uid, context) {
171
+ return __awaiter(this, void 0, void 0, function* () {
172
+ yield Promise.all(entities.map((entity) => extractImages(entity, uid, context)));
173
+ });
174
+ }
@@ -0,0 +1,4 @@
1
+ import type { Reporter } from 'gatsby';
2
+ import type { StrapiClient } from '../strapi-client';
3
+ import type { Entity, Schema, SchemaEndpoint } from './types';
4
+ export declare function fetchEntity({ endpoint, queryParams, uid }: SchemaEndpoint, schemas: Schema[], strapiClient: StrapiClient, reporter: Reporter): Promise<Entity[]>;