@paroicms/site-generator-plugin 1.0.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/backend/dist/generator/fake-content-generator/create-database-with-fake-content.js +36 -6
- package/backend/dist/generator/fake-content-generator/fill-lnodes.js +5 -2
- package/backend/dist/generator/fake-content-generator/invoke-generate-fake-content.js +1 -1
- package/backend/dist/generator/lib/markdown-bulleted-list-parser.js +2 -4
- package/backend/dist/generator/llm-queries/invoke-new-site-analysis.js +4 -3
- package/backend/dist/generator/llm-queries/invoke-update-site-schema.js +4 -2
- package/backend/dist/generator/site-generator/labeled-list-template-creator.js +18 -2
- package/backend/dist/generator/site-generator/site-generator.js +5 -4
- package/backend/dist/generator/site-generator/theme-creator-context.js +6 -6
- package/backend/dist/generator/site-schema-generator/create-site-schema.js +21 -16
- package/backend/prompts/initial-1-analysis.md +3 -1
- package/backend/prompts/update-site-schema-1-write-details.md +1 -0
- package/backend/prompts/update-site-schema-2-execute.md +1 -0
- package/frontend/dist/frontend.css +1 -1
- package/frontend/dist/frontend.mjs +1 -1
- package/package.json +6 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getPartTypeByName, getRegularDocumentTypeByName, getRoutingDocumentTypeByName, } from "@paroicms/internal-anywhere-lib";
|
|
1
|
+
import { getPartTypeByName, getRegularDocumentTypeByName, getRoutingDocumentTypeByName, isRootOfSubRoutingCluster, } from "@paroicms/internal-anywhere-lib";
|
|
2
2
|
import { updateGeneratedSiteStepSetAsCompleted, } from "../../db/db-write.queries.js";
|
|
3
3
|
import { createTaskCollector } from "../lib/tasks.js";
|
|
4
4
|
import { createGeneratedContentReport } from "./content-report.js";
|
|
@@ -58,10 +58,40 @@ function fillRoutingDocumentAndAddChildren(ctx, tasks, report, nodeOptions) {
|
|
|
58
58
|
}
|
|
59
59
|
for (const typeName of nodeType.regularChildren ?? []) {
|
|
60
60
|
const childType = getRegularDocumentTypeByName(siteSchema, typeName);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
if (isRootOfSubRoutingCluster(childType)) {
|
|
62
|
+
// Each created instance is the root of its own sub routing cluster (auto-created
|
|
63
|
+
// synchronously by `createDocument`). Load each sub-cluster and recurse to fill it.
|
|
64
|
+
tasks.add(async () => {
|
|
65
|
+
const created = await addRegularDocuments(ctx, report, {
|
|
66
|
+
parentNodeId: clusterNode.nodeId,
|
|
67
|
+
nodeType: childType,
|
|
68
|
+
documentType: childType,
|
|
69
|
+
});
|
|
70
|
+
for (const doc of created) {
|
|
71
|
+
const subCluster = await ctx.siteConnector.loadRoutingClusterFromNode({
|
|
72
|
+
nodeId: doc.nodeId,
|
|
73
|
+
typeName: childType.typeName,
|
|
74
|
+
});
|
|
75
|
+
for (const routingTypeName of childType.routingChildren ?? []) {
|
|
76
|
+
const childNode = subCluster.children?.[routingTypeName];
|
|
77
|
+
if (!childNode)
|
|
78
|
+
continue;
|
|
79
|
+
fillRoutingDocumentAndAddChildren(ctx, tasks, report, {
|
|
80
|
+
clusterNode: childNode,
|
|
81
|
+
nodeType: getRoutingDocumentTypeByName(siteSchema, routingTypeName),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
tasks.add(async () => {
|
|
89
|
+
await addRegularDocuments(ctx, report, {
|
|
90
|
+
parentNodeId: clusterNode.nodeId,
|
|
91
|
+
nodeType: childType,
|
|
92
|
+
documentType: childType,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
}
|
|
66
96
|
}
|
|
67
97
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { encodeLNodeId, } from "@paroicms/public-anywhere-lib";
|
|
2
|
-
import { getHandleOfFeaturedImage, getHandleOfFieldOnNode } from "@paroicms/public-server-lib";
|
|
2
|
+
import { getHandleOfFeaturedImage, getHandleOfFieldOnNode, } from "@paroicms/public-server-lib";
|
|
3
3
|
import { dedupMessages, getTermTypeNames } from "./content-helpers.js";
|
|
4
4
|
import { generateFieldSetContent, generateMultipleFieldSetContents, } from "./generate-fake-content.js";
|
|
5
5
|
export async function updateRoutingDocument(ctx, report, nodeOptions) {
|
|
@@ -42,7 +42,7 @@ export async function addRegularDocuments(ctx, report, nodeOptions) {
|
|
|
42
42
|
// Special case: author terms are created without LLM
|
|
43
43
|
if (nodeOptions.nodeType.typeName === "author") {
|
|
44
44
|
await addSingleAuthor(ctx, report, nodeOptions);
|
|
45
|
-
return;
|
|
45
|
+
return [];
|
|
46
46
|
}
|
|
47
47
|
ctx.logger.debug(`[TASK] Adding regular documents "${nodeOptions.nodeType.typeName}"…`);
|
|
48
48
|
const { parentNodeId, nodeType, documentType } = nodeOptions;
|
|
@@ -76,6 +76,7 @@ export async function addRegularDocuments(ctx, report, nodeOptions) {
|
|
|
76
76
|
if (errorMessages.length > 0) {
|
|
77
77
|
ctx.logger.warn(`Error generating content for ${nodeType.typeName}:\n - ${errorMessages.join("\n - ")}`);
|
|
78
78
|
}
|
|
79
|
+
const createdInfos = [];
|
|
79
80
|
for (const content of list) {
|
|
80
81
|
const [firstLanguage, ...otherLanguages] = siteSchema.languages;
|
|
81
82
|
const parentLNodeId = encodeLNodeId({ nodeId: parentNodeId, language: firstLanguage });
|
|
@@ -87,6 +88,7 @@ export async function addRegularDocuments(ctx, report, nodeOptions) {
|
|
|
87
88
|
values: content.fields,
|
|
88
89
|
});
|
|
89
90
|
const nodeId = info.nodeId;
|
|
91
|
+
createdInfos.push(info);
|
|
90
92
|
await uploadMediaEntries(ctx, nodeId, content.medias);
|
|
91
93
|
report.addId({
|
|
92
94
|
typeName: nodeType.typeName,
|
|
@@ -109,6 +111,7 @@ export async function addRegularDocuments(ctx, report, nodeOptions) {
|
|
|
109
111
|
});
|
|
110
112
|
}
|
|
111
113
|
}
|
|
114
|
+
return createdInfos;
|
|
112
115
|
}
|
|
113
116
|
const HERO_NAMES = [
|
|
114
117
|
"Mario",
|
|
@@ -68,9 +68,6 @@ function appendChildToParentNode(child, parent) {
|
|
|
68
68
|
parent.children.push(child);
|
|
69
69
|
}
|
|
70
70
|
else if (parent.kind === "regularDocument") {
|
|
71
|
-
if (child.kind === "routingDocument") {
|
|
72
|
-
throw new Error(`Regular document type "${parent.typeName}" cannot have ${child.kind} child "${child.typeName}"`);
|
|
73
|
-
}
|
|
74
71
|
parent.children ??= [];
|
|
75
72
|
parent.children.push(child);
|
|
76
73
|
}
|
|
@@ -131,7 +128,8 @@ export function parseLine(input, index) {
|
|
|
131
128
|
};
|
|
132
129
|
}
|
|
133
130
|
// list of `pageSection` (parts), list name: `partSections`
|
|
134
|
-
|
|
131
|
+
// The list name backticks are optional: the LLM is inconsistent about wrapping it.
|
|
132
|
+
const partMatch = cleanLine.match(/^list of `([^`]+)` \(parts\),? list name: `?([^`]+?)`?$/);
|
|
135
133
|
if (partMatch) {
|
|
136
134
|
return {
|
|
137
135
|
kind: "part",
|
|
@@ -9,7 +9,7 @@ import { parseMarkdownBulletedList } from "../lib/markdown-bulleted-list-parser.
|
|
|
9
9
|
import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
|
|
10
10
|
import { safeCallStep } from "../lib/session-utils.js";
|
|
11
11
|
import { createL10n } from "../site-schema-generator/create-l10n.js";
|
|
12
|
-
import { createSiteSchemaFromAnalysis } from "../site-schema-generator/create-site-schema.js";
|
|
12
|
+
import { createSiteSchemaFromAnalysis, ensureSubClusterAutoCreate, } from "../site-schema-generator/create-site-schema.js";
|
|
13
13
|
import { invokeUpdateSiteSchema } from "./invoke-update-site-schema.js";
|
|
14
14
|
export const analyzePrompt = await createPromptTemplate({
|
|
15
15
|
filename: "initial-1-analysis.md",
|
|
@@ -37,6 +37,7 @@ export async function invokeInitialAnalysis(ctx, stepHandle, input) {
|
|
|
37
37
|
});
|
|
38
38
|
const { unusedInformation: unusedInformation2, llmReport: llmReport2 } = await invokeAnalysisStep2(ctx, { prompt: createUnusedInformationPrompt(unusedInformation, analysis) ?? "" }, siteSchema, stepHandle);
|
|
39
39
|
reorderSiteSchemaNodeTypes(siteSchema);
|
|
40
|
+
ensureSubClusterAutoCreate(siteSchema);
|
|
40
41
|
const l10n = createL10n(analysis, siteSchema);
|
|
41
42
|
const siteTitle = {
|
|
42
43
|
[analysis.siteProperties.language]: analysis.siteProperties.title,
|
|
@@ -79,7 +80,7 @@ async function invokeAnalysisStep1(ctx, input, stepHandle) {
|
|
|
79
80
|
const { messageContent, report } = await invokeClaude(ctx, {
|
|
80
81
|
llmTaskName,
|
|
81
82
|
prompt,
|
|
82
|
-
maxTokens:
|
|
83
|
+
maxTokens: 10_000,
|
|
83
84
|
temperature: 0.1,
|
|
84
85
|
systemInstruction: "beSmart",
|
|
85
86
|
});
|
|
@@ -146,7 +147,7 @@ siteSchema, stepHandle) {
|
|
|
146
147
|
const { messageContent, report } = await invokeClaude(ctx, {
|
|
147
148
|
llmTaskName,
|
|
148
149
|
prompt,
|
|
149
|
-
maxTokens:
|
|
150
|
+
maxTokens: 1_000,
|
|
150
151
|
temperature: 0.1,
|
|
151
152
|
systemInstruction: "beFast",
|
|
152
153
|
});
|
|
@@ -5,6 +5,7 @@ import { createPromptTemplate, getPredefinedFields, getSiteSchemaTsDefs, } from
|
|
|
5
5
|
import { debugLlmOutput } from "../lib/debug-utils.js";
|
|
6
6
|
import { parseLlmResponseAsProperties } from "../lib/parse-llm-response.js";
|
|
7
7
|
import { safeCallStep } from "../lib/session-utils.js";
|
|
8
|
+
import { ensureSubClusterAutoCreate } from "../site-schema-generator/create-site-schema.js";
|
|
8
9
|
const prompt1Tpl = await createPromptTemplate({
|
|
9
10
|
filename: "update-site-schema-1-write-details.md",
|
|
10
11
|
});
|
|
@@ -56,6 +57,7 @@ export async function invokeUpdateSiteSchema(ctx, stepHandle, input, { asRemaini
|
|
|
56
57
|
: asRemainingOf.explanation;
|
|
57
58
|
}
|
|
58
59
|
}
|
|
60
|
+
ensureSubClusterAutoCreate(completedValues.siteSchema);
|
|
59
61
|
await saveCompletedSchemaStep(ctx, stepHandle, completedValues);
|
|
60
62
|
}
|
|
61
63
|
async function invokeUpdateSiteSchemaStep1(ctx, input, stepHandle) {
|
|
@@ -80,7 +82,7 @@ async function invokeUpdateSiteSchemaStep1(ctx, input, stepHandle) {
|
|
|
80
82
|
const { messageContent, report } = await invokeClaude(ctx, {
|
|
81
83
|
llmTaskName,
|
|
82
84
|
prompt: message,
|
|
83
|
-
maxTokens:
|
|
85
|
+
maxTokens: 3_000,
|
|
84
86
|
temperature: 0.1,
|
|
85
87
|
systemInstruction: "beSmart",
|
|
86
88
|
});
|
|
@@ -126,7 +128,7 @@ async function invokeUpdateSiteSchemaStep2(ctx, input, stepHandle) {
|
|
|
126
128
|
const { messageContent, report } = await invokeClaude(ctx, {
|
|
127
129
|
llmTaskName,
|
|
128
130
|
prompt: message,
|
|
129
|
-
maxTokens:
|
|
131
|
+
maxTokens: 15_000,
|
|
130
132
|
temperature: 0.1,
|
|
131
133
|
systemInstruction: "beSmart",
|
|
132
134
|
});
|
|
@@ -46,11 +46,27 @@ function getRoutingKeyInCluster(ctx, documentType, options) {
|
|
|
46
46
|
return found;
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
// Resolve the cluster root of the taxonomy by walking ancestors via the parent map: the nearest
|
|
50
|
+
// ancestor that is "home" or a regular document carrying routing children.
|
|
51
|
+
function findClusterRoot(startTypeName) {
|
|
52
|
+
let current = getNodeType(startTypeName);
|
|
53
|
+
while (current && current.kind === "document") {
|
|
54
|
+
if (current.typeName === "home")
|
|
55
|
+
return "home";
|
|
56
|
+
if (current.documentKind === "regular" && (current.routingChildren?.length ?? 0) > 0) {
|
|
57
|
+
return current.typeName;
|
|
58
|
+
}
|
|
59
|
+
current = ctx.getParentTypes(current)[0];
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
const clusterRootTypeName = findClusterRoot(options.sameClusterAs.typeName);
|
|
64
|
+
if (!clusterRootTypeName)
|
|
65
|
+
return;
|
|
50
66
|
const targetPath = findPath(documentType.typeName, clusterRootTypeName, []);
|
|
51
67
|
const sameClusterPath = findPath(options.sameClusterAs.typeName, clusterRootTypeName, []);
|
|
52
68
|
if (!targetPath || !sameClusterPath)
|
|
53
69
|
return;
|
|
54
|
-
targetPath.shift(); // remove leading
|
|
70
|
+
targetPath.shift(); // remove the leading cluster root (path is cluster-root-relative at runtime)
|
|
55
71
|
return `doc.cluster.routing.${targetPath.join(".")}`;
|
|
56
72
|
}
|
|
@@ -48,11 +48,12 @@ export async function generateSite(ctx, input) {
|
|
|
48
48
|
version: "0.0.0",
|
|
49
49
|
});
|
|
50
50
|
const siteConnector = service.getUnsafeSiteConnector({ fqdn: regSite.fqdn });
|
|
51
|
+
const password = Math.random().toString(36).substring(2, 6); // 4 random lowercase characters
|
|
51
52
|
const account = {
|
|
52
53
|
kind: "local",
|
|
53
54
|
email: `${siteId}@yopmail.com`,
|
|
54
55
|
name: "Admin",
|
|
55
|
-
password
|
|
56
|
+
password,
|
|
56
57
|
roles: ["admin"],
|
|
57
58
|
};
|
|
58
59
|
await siteConnector.createAccount(account, { asContactEmail: true });
|
|
@@ -63,7 +64,7 @@ export async function generateSite(ctx, input) {
|
|
|
63
64
|
siteUrl,
|
|
64
65
|
localizedValues,
|
|
65
66
|
loginEmail: account.email,
|
|
66
|
-
loginPassword:
|
|
67
|
+
loginPassword: password,
|
|
67
68
|
};
|
|
68
69
|
await saveGeneratedSiteStep(ctx, stepHandle, values);
|
|
69
70
|
if (withSampleData) {
|
|
@@ -91,7 +92,7 @@ function getPackageJsonContent(options) {
|
|
|
91
92
|
private: true,
|
|
92
93
|
type: "module",
|
|
93
94
|
scripts: {
|
|
94
|
-
start: "paroicms | npm run _pino-pretty",
|
|
95
|
+
start: "paroicms-server | npm run _pino-pretty",
|
|
95
96
|
"start:dev": "nodemon --watch './site-schema*.json' --watch ./config.json",
|
|
96
97
|
clear: "rimraf theme/assets/bundle.css",
|
|
97
98
|
build: "postcss theme/assets/css/index.css -o theme/assets/bundle.css",
|
|
@@ -104,7 +105,7 @@ function getPackageJsonContent(options) {
|
|
|
104
105
|
"@paroicms/content-loading-plugin": "*",
|
|
105
106
|
"@paroicms/internal-link-plugin": "*",
|
|
106
107
|
"@paroicms/list-field-plugin": "*",
|
|
107
|
-
"@paroicms/
|
|
108
|
+
"@paroicms/api-plugin": "*",
|
|
108
109
|
"@paroicms/public-menu-plugin": "*",
|
|
109
110
|
"@paroicms/tiptap-editor-plugin": "*",
|
|
110
111
|
"@paroicms/platform-video-plugin": "*",
|
|
@@ -67,12 +67,12 @@ function makeGetParentTypes(siteSchema) {
|
|
|
67
67
|
for (const type of nodeTypes) {
|
|
68
68
|
if (type.kind !== "document")
|
|
69
69
|
continue;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
// Register routing-child → parent links for every document kind, so a routing document nested
|
|
71
|
+
// under a regular parent (sub routing cluster root) keeps its parent link.
|
|
72
|
+
for (const childName of type.routingChildren ?? []) {
|
|
73
|
+
const list = parentsByChild.get(childName) ?? [];
|
|
74
|
+
list.push(type);
|
|
75
|
+
parentsByChild.set(childName, list);
|
|
76
76
|
}
|
|
77
77
|
for (const childName of type.regularChildren ?? []) {
|
|
78
78
|
const list = parentsByChild.get(childName) ?? [];
|
|
@@ -9,7 +9,7 @@ export function createSiteSchemaFromAnalysis(analysis) {
|
|
|
9
9
|
"@paroicms/content-loading-plugin",
|
|
10
10
|
"@paroicms/internal-link-plugin",
|
|
11
11
|
"@paroicms/list-field-plugin",
|
|
12
|
-
"@paroicms/
|
|
12
|
+
"@paroicms/api-plugin",
|
|
13
13
|
"@paroicms/platform-video-plugin",
|
|
14
14
|
"@paroicms/public-menu-plugin",
|
|
15
15
|
"@paroicms/tiptap-editor-plugin",
|
|
@@ -24,6 +24,20 @@ export function createSiteSchemaFromAnalysis(analysis) {
|
|
|
24
24
|
};
|
|
25
25
|
return siteSchema;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Ensures every regular document that is the root of a sub routing cluster (i.e. has routing
|
|
29
|
+
* children) carries `cluster: { autoCreate: true }`. The LLM schema-update step sometimes strips
|
|
30
|
+
* this flag; without it the runtime would not auto-create the sub-cluster nodes.
|
|
31
|
+
*/
|
|
32
|
+
export function ensureSubClusterAutoCreate(siteSchema) {
|
|
33
|
+
for (const nodeType of siteSchema.nodeTypes ?? []) {
|
|
34
|
+
if (nodeType.kind !== "document" || nodeType.documentKind !== "regular")
|
|
35
|
+
continue;
|
|
36
|
+
if ((nodeType.routingChildren?.length ?? 0) === 0)
|
|
37
|
+
continue;
|
|
38
|
+
nodeType.cluster ??= { autoCreate: true };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
27
41
|
function toNodeTypes(analysis) {
|
|
28
42
|
const nodeTypes = new Map(Object.entries(analysis.dictionary)
|
|
29
43
|
.map(([typeName, saType]) => [typeName, toNodeType(typeName, saType)])
|
|
@@ -69,7 +83,6 @@ function walkTree(saNode, parentNode, ctx) {
|
|
|
69
83
|
nodeType,
|
|
70
84
|
typeName,
|
|
71
85
|
parentNode,
|
|
72
|
-
children: undefined,
|
|
73
86
|
}, ctx);
|
|
74
87
|
}
|
|
75
88
|
else {
|
|
@@ -84,7 +97,6 @@ function walkTree(saNode, parentNode, ctx) {
|
|
|
84
97
|
nodeType,
|
|
85
98
|
typeName,
|
|
86
99
|
parentNode,
|
|
87
|
-
children: undefined,
|
|
88
100
|
listName: saNode.listName,
|
|
89
101
|
}, ctx);
|
|
90
102
|
}
|
|
@@ -117,7 +129,6 @@ function walkTree(saNode, parentNode, ctx) {
|
|
|
117
129
|
nodeType,
|
|
118
130
|
typeName,
|
|
119
131
|
parentNode,
|
|
120
|
-
children: saNode.children,
|
|
121
132
|
}, ctx);
|
|
122
133
|
}
|
|
123
134
|
else if (saNode.kind === "part") {
|
|
@@ -130,7 +141,6 @@ function walkTree(saNode, parentNode, ctx) {
|
|
|
130
141
|
nodeType,
|
|
131
142
|
typeName,
|
|
132
143
|
parentNode,
|
|
133
|
-
children: saNode.children,
|
|
134
144
|
listName: saNode.listName,
|
|
135
145
|
}, ctx);
|
|
136
146
|
}
|
|
@@ -153,14 +163,15 @@ function appendAsRoutingChild(options) {
|
|
|
153
163
|
if (parentNode.kind !== "document") {
|
|
154
164
|
throw new Error(`In the tree, "${typeName}" is used as a routing document but its parent is a "${parentNode.kind}"`);
|
|
155
165
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
166
|
+
// A regular document with routing children is the root of a sub routing cluster: flag it so the
|
|
167
|
+
// runtime auto-creates the sub-cluster nodes (consistent with how the "home" cluster behaves).
|
|
168
|
+
if (parentNode.documentKind === "regular")
|
|
169
|
+
parentNode.cluster ??= { autoCreate: true };
|
|
159
170
|
parentNode.routingChildren ??= [];
|
|
160
171
|
parentNode.routingChildren.push(typeName);
|
|
161
172
|
}
|
|
162
173
|
function appendAsChildRegularDocument(options, ctx) {
|
|
163
|
-
const { nodeType, typeName, parentNode
|
|
174
|
+
const { nodeType, typeName, parentNode } = options;
|
|
164
175
|
const saType = ctx.analysis.dictionary[typeName];
|
|
165
176
|
if (nodeType.kind !== "document") {
|
|
166
177
|
throw new Error(`In the tree, "${typeName}" is used as a regular document but it is a "${nodeType.kind}"`);
|
|
@@ -176,12 +187,9 @@ function appendAsChildRegularDocument(options, ctx) {
|
|
|
176
187
|
parentNode.regularChildrenSorting = saType.temporal ? "publishDate desc" : "title asc";
|
|
177
188
|
}
|
|
178
189
|
parentNode.regularChildren.push(typeName);
|
|
179
|
-
for (const child of children ?? []) {
|
|
180
|
-
walkTree(child, nodeType, ctx);
|
|
181
|
-
}
|
|
182
190
|
}
|
|
183
191
|
function appendAsChildPart(options, ctx) {
|
|
184
|
-
const { nodeType, typeName, parentNode,
|
|
192
|
+
const { nodeType, typeName, parentNode, listName } = options;
|
|
185
193
|
const saType = ctx.analysis.dictionary[typeName];
|
|
186
194
|
if (nodeType.kind !== "part") {
|
|
187
195
|
throw new Error(`In the tree, "${typeName}" is used as a part but it is a "${nodeType.kind}"`);
|
|
@@ -208,9 +216,6 @@ function appendAsChildPart(options, ctx) {
|
|
|
208
216
|
else {
|
|
209
217
|
throw new Error(`Unexpected kind: "${parentNode.kind}"`);
|
|
210
218
|
}
|
|
211
|
-
for (const child of children ?? []) {
|
|
212
|
-
walkTree(child, nodeType, ctx);
|
|
213
|
-
}
|
|
214
219
|
}
|
|
215
220
|
function toNodeType(typeName, saType) {
|
|
216
221
|
if (saType.kind === "part")
|
|
@@ -53,7 +53,7 @@ Guidelines for creating the hierarchical bullet list:
|
|
|
53
53
|
- Start with a **bullet** (*).
|
|
54
54
|
- Write `"list of"`, and then the **type name** within backquotes.
|
|
55
55
|
- Append `(parts)`.
|
|
56
|
-
- Add a coma, then write: `"list name:"` and append an identifier for the list name
|
|
56
|
+
- Add a coma, then write: `"list name:"` and append an identifier for the list name, **within backquotes**.
|
|
57
57
|
- Avoid recursivity. But if you can't avoid reusing a node type, then write its children only on the first occurence.
|
|
58
58
|
- On this task, do not focus on fields. If the website description provide fields then you will report them in the unused information. In particular, a collection of medias (a carousel, a slider, an image gallery, a slideshow, etc.) is a type of field.
|
|
59
59
|
- Don't try to provide a comment mechanism when the user requests a blog. Blog comments do not belong to the hierarchy of node types.
|
|
@@ -115,6 +115,8 @@ Here's an example of correct output using parts, and with the default contact an
|
|
|
115
115
|
- `searchPage` (routing document)
|
|
116
116
|
</correct_example>
|
|
117
117
|
|
|
118
|
+
A routing document **can** be a child of a regular document. This is a valid and supported structure: each instance of the regular document becomes the root of its own nested set of sections (a _sub routing cluster_). Keep such nesting when the website description implies it.
|
|
119
|
+
|
|
118
120
|
### Keep it simple
|
|
119
121
|
|
|
120
122
|
When you have a choice, keep it simple. If the user lets you invent the site's structure, limit the site's sections to **2 main entries**. For example, a “news” routing document with a list of articles and categories, and a list of pages on the site's theme. Plus the usual contact and search pages.
|
|
@@ -50,6 +50,7 @@ Guidelines for reformulating into a detailed sequence of operations:
|
|
|
50
50
|
- If the user's request is simple and doesn't need to be separated into several operations, write a list with a single operation.
|
|
51
51
|
- Describe each operation concisely in a few words.
|
|
52
52
|
- Make sure that the tree structure of node types is not broken. The `site` node is separate. Then, the root of the tree structure is the `home` routing document. Every other routing document type, regular document type, part type, must be the child of another node type.
|
|
53
|
+
- A routing document type **can** be a child of a regular document type: this is a valid _sub routing cluster_ (each instance of the regular document is the root of its own nested sections). Preserve such nesting. A regular document type that has `routingChildren` can carry `cluster: { autoCreate: true }`.
|
|
53
54
|
- Prefer predefined fields where you can. In particular, you can use the `"gallery"` field when the user description is a synonym (carousel, slider, slideshow, image gallery).
|
|
54
55
|
- Never use the same field twice in a list of fields.
|
|
55
56
|
|
|
@@ -129,6 +129,7 @@ Also, the attached locales:
|
|
|
129
129
|
- You are allowed to be proactive, but only when the user asks you to do something.
|
|
130
130
|
- Remember to adhere strictly to the TypeScript typing when making changes. If the update message requests changes that would violate the typing, then prioritize maintaining the correct structure over making those specific changes.
|
|
131
131
|
- Field choice for listing pages: For new routing documents that have `regularChildren` (like blog index, products index, etc.), prefer `introduction[@paroicms/tiptap-editor-plugin]` instead of `htmlContent[@paroicms/tiptap-editor-plugin]`. These pages display a list of child items, so they only need a short introduction, not full HTML content.
|
|
132
|
+
- Preserve _sub routing clusters_: a regular document type may have a routing document type among its `routingChildren`. Keep that nesting intact. A regular document type that has `routingChildren` can carry `cluster: { autoCreate: true }`.
|
|
132
133
|
|
|
133
134
|
# 8. Output
|
|
134
135
|
|