Skip to content

Commit 883ed8d

Browse files
committed
customer account rc version support doc generate
1 parent e707b2a commit 883ed8d

32 files changed

+617
-453
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/* eslint-disable no-undef, no-console */
2+
import childProcess from 'child_process';
3+
import fs from 'fs/promises';
4+
import {existsSync} from 'fs';
5+
import path from 'path';
6+
import {fileURLToPath} from 'url';
7+
8+
const EXTENSIONS_API_VERSION = process.argv[2] || 'unstable';
9+
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = path.dirname(__filename);
12+
13+
const rootPath = path.join(__dirname, '../../..');
14+
const docsRelativePath = 'docs/surfaces/customer-account';
15+
const docsGeneratedRelativePath = 'docs/surfaces/customer-account/generated';
16+
const srcRelativePath = 'src/surfaces/customer-account';
17+
const docsPath = path.join(rootPath, docsRelativePath);
18+
const srcPath = path.join(rootPath, srcRelativePath);
19+
const generatedDocsPath = path.join(docsPath, 'generated');
20+
const shopifyDevPath = path.join(rootPath, '../../../shopify-dev');
21+
const shopifyDevDBPath = path.join(
22+
shopifyDevPath,
23+
'db/data/docs/templated_apis',
24+
);
25+
26+
const shopifyDevExists = existsSync(shopifyDevPath);
27+
28+
const generatedDocsDataFile = 'generated_docs_data.json';
29+
const generatedStaticPagesFile = 'generated_static_pages.json';
30+
31+
const componentDefs = path.join(srcPath, 'components.d.ts');
32+
const tempComponentDefs = path.join(srcPath, 'components.ts');
33+
34+
const replaceFileContent = async (filePaths, searchValue, replaceValue) => {
35+
const files = Array.isArray(filePaths) ? filePaths : [filePaths];
36+
for (const filePath of files) {
37+
const content = await fs.readFile(filePath, 'utf8');
38+
// @ts-ignore -- TS should know this is a string but it doesn't
39+
const replacedContent = content.replaceAll(searchValue, replaceValue);
40+
await fs.writeFile(filePath, replacedContent);
41+
}
42+
};
43+
44+
const decodeHTML = (str) => {
45+
return str
46+
.replace(/&/g, '&')
47+
.replace(/&lt;/g, '<')
48+
.replace(/&gt;/g, '>')
49+
.replace(/&quot;/g, '"')
50+
.replace(/&#039;/g, "'");
51+
};
52+
53+
const htmlWrapper = (htmlString, layout) => {
54+
return `<!DOCTYPE html><html><head><style>html, body {height:100%} body {box-sizing: border-box; margin: 0; padding:0.5rem; ${layout}}</style><script src="https://cdn.shopify.com/shopifycloud/app-bridge-ui-experimental.js"></script></head><body>${decodeHTML(
55+
htmlString,
56+
)}</body></html>`;
57+
};
58+
59+
const templates = {
60+
default: (htmlString) =>
61+
htmlWrapper(htmlString, 'display: grid; place-items: center; gap: 0.5rem;'),
62+
wrapped: (htmlString) =>
63+
htmlWrapper(
64+
`<div>${htmlString}</div>`,
65+
'display: grid; place-items: center; gap: 0.5rem;',
66+
),
67+
inline: (htmlString) =>
68+
htmlWrapper(
69+
htmlString,
70+
'display: flex; justify-content: center; align-items: center; gap: 0.5rem;',
71+
),
72+
section: (htmlString) =>
73+
htmlWrapper(
74+
`<s-section padding="none">${htmlString}</s-section>`,
75+
'display: grid; place-items: center; background: #F1F1F1',
76+
),
77+
page: (htmlString) =>
78+
htmlWrapper(
79+
htmlString,
80+
'display: grid; place-items: center; background: #F1F1F1;',
81+
),
82+
none: (htmlString) => htmlWrapper(htmlString, 'padding: 0'),
83+
};
84+
85+
const transformJson = async (filePath) => {
86+
const jsonData = JSON.parse((await fs.readFile(filePath, 'utf8')).toString());
87+
jsonData.forEach((entry) => {
88+
// Temporary to ensure that isOptional is added to all members
89+
if (entry?.definitions && entry.isVisualComponent) {
90+
entry.definitions.forEach((definition) => {
91+
if (definition.typeDefinitions) {
92+
Object.values(definition.typeDefinitions).forEach((typeDef) => {
93+
if (typeDef.members && Array.isArray(typeDef.members)) {
94+
typeDef.members
95+
.sort((first, second) => first.name.localeCompare(second.name))
96+
.forEach((member) => {
97+
// eslint-disable-next-line no-prototype-builtins
98+
if (member.hasOwnProperty('isOptional')) return;
99+
member.isOptional = true;
100+
});
101+
}
102+
});
103+
}
104+
});
105+
}
106+
107+
if (entry?.defaultExample?.codeblock?.tabs) {
108+
const newTabs = [];
109+
entry.defaultExample.codeblock.tabs.forEach((tab) => {
110+
if (tab.language !== 'preview') {
111+
newTabs.push(tab);
112+
return;
113+
}
114+
115+
if (tab.layout && !(tab.layout in templates)) {
116+
console.warn(
117+
`${entry.name} has a layout of ${tab.layout} which is not a valid template.`,
118+
);
119+
}
120+
121+
const previewHTML =
122+
tab.layout && tab.layout in templates
123+
? templates[tab.layout](tab.code)
124+
: templates.default(tab.code);
125+
126+
newTabs.push(
127+
{code: tab.code, language: 'html'},
128+
{code: previewHTML, language: 'preview'},
129+
);
130+
});
131+
132+
entry.defaultExample.codeblock.tabs = newTabs;
133+
}
134+
});
135+
136+
await fs.writeFile(
137+
filePath,
138+
JSON.stringify(jsonData.filter(Boolean), null, 2),
139+
);
140+
};
141+
142+
const generateFiles = async (tsconfig, outputDir) => {
143+
const scripts = [
144+
`yarn tsc --project ${docsRelativePath}/${tsconfig} --moduleResolution node --target esNext --module CommonJS`,
145+
`yarn generate-docs --input ./${docsRelativePath}/reference ./${docsRelativePath} ./${docsRelativePath}/../../../src/surfaces/customer-account/components --typesInput ./${srcRelativePath} --output ./${outputDir}`,
146+
];
147+
148+
scripts.push(
149+
`yarn tsc ${docsRelativePath}/staticPages/*.doc.ts --moduleResolution node --target esNext --module CommonJS`,
150+
`yarn generate-docs --isLandingPage --input ./${docsRelativePath}/staticPages --output ./${outputDir}`,
151+
);
152+
153+
scripts.push(
154+
`yarn tsc ${docsRelativePath}/categories/*.doc.ts --moduleResolution node --target esNext --module CommonJS`,
155+
`yarn generate-docs --isCategoryPage --input ./${docsRelativePath}/categories --output ./${outputDir}`,
156+
);
157+
158+
scripts.forEach((script) => childProcess.execSync(script, {stdio: 'pipe'}));
159+
160+
const srcFiles = await fs.readdir(rootPath, {recursive: true});
161+
const builtFiles = srcFiles.filter((file) => file.endsWith('.ts'));
162+
await Promise.all(
163+
builtFiles.map((file) => {
164+
const jsFilePath = path.join(rootPath, file.replace('.ts', '.js'));
165+
return existsSync(jsFilePath) ? fs.rm(jsFilePath) : Promise.resolve();
166+
}),
167+
);
168+
169+
const generatedFiles = [path.join(outputDir, generatedDocsDataFile)];
170+
generatedFiles.push(path.join(outputDir, generatedStaticPagesFile));
171+
172+
// Make sure https://shopify.dev URLs are relative so they work in Spin.
173+
// See https://github.com/Shopify/generate-docs/issues/181
174+
await replaceFileContent(generatedFiles, 'https://shopify.dev', '');
175+
176+
// @ts-ignore
177+
await transformJson(path.join(outputDir, generatedDocsDataFile));
178+
};
179+
180+
const copyGeneratedToShopifyDev = async () => {
181+
if (!shopifyDevExists) {
182+
console.log(
183+
`Not copying docs to shopify-dev because it was not found at ${shopifyDevPath}.`,
184+
);
185+
process.exit();
186+
}
187+
188+
await fs.cp(generatedDocsPath, shopifyDevDBPath, {recursive: true});
189+
};
190+
191+
const generateExtensionsDocs = async () => {
192+
console.log(
193+
`Building Customer Account UI Extensions docs for ${EXTENSIONS_API_VERSION} version`,
194+
);
195+
196+
if (EXTENSIONS_API_VERSION === 'unstable') {
197+
console.log(
198+
"You can add a calver version argument (e.g. 'yarn docs:customer-account 2024-07') to generate the docs for a stable version.",
199+
);
200+
}
201+
202+
const extensionsOutputDir = `${docsGeneratedRelativePath}/customer_account_ui_extensions/${EXTENSIONS_API_VERSION}`;
203+
204+
await generateFiles('tsconfig.docs.json', extensionsOutputDir);
205+
206+
// Replace 'unstable' with the exact API version in relative doc links
207+
await replaceFileContent(
208+
path.join(extensionsOutputDir, generatedDocsDataFile),
209+
'/docs/api//unstable/',
210+
`/docs/api/customer_account_ui_extensions/${EXTENSIONS_API_VERSION}`,
211+
);
212+
213+
await fs.cp(
214+
path.join(docsPath, 'screenshots'),
215+
path.join(
216+
shopifyDevPath,
217+
'app/assets/images/templated-apis-screenshots/customer_account_ui_extensions',
218+
EXTENSIONS_API_VERSION,
219+
),
220+
{recursive: true},
221+
);
222+
};
223+
224+
try {
225+
if (existsSync(generatedDocsPath)) {
226+
await fs.rm(generatedDocsPath, {recursive: true});
227+
}
228+
await fs.copyFile(componentDefs, tempComponentDefs);
229+
await replaceFileContent(
230+
tempComponentDefs,
231+
/typeof globalThis\.HTMLElement/g,
232+
'any',
233+
);
234+
await generateExtensionsDocs();
235+
await copyGeneratedToShopifyDev();
236+
237+
await fs.rm(tempComponentDefs);
238+
} catch (error) {
239+
debugger;
240+
console.error(error);
241+
console.log(error.stdout.toString());
242+
console.log(error.stderr.toString());
243+
process.exit(1);
244+
}

Diff for: packages/ui-extensions/docs/surfaces/customer-account/build-docs.sh

-95
This file was deleted.

Diff for: packages/ui-extensions/docs/surfaces/customer-account/reference/apis/authenticated-account.doc.ts

+12-12
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ const data: ReferenceEntityTemplateSchema = {
1515
description: CUSTOMER_ACCOUNT_STANDARD_API_DEFINITION.description,
1616
type: 'Docs_Standard_AuthenticatedAccountApi',
1717
},
18-
{
19-
title: 'useAuthenticatedAccountCustomer',
20-
description:
21-
"Returns the current authenticated `Customer`. The value is `undefined` if the customer isn't authenticated.",
22-
type: 'UseAuthenticatedAccountCustomerGeneratedType',
23-
},
24-
{
25-
title: 'useAuthenticatedAccountPurchasingCompany',
26-
description:
27-
"Provides information about the company of the authenticated business customer. The value is `undefined` if a business customer isn't authenticated.",
28-
type: 'UseAuthenticatedAccountPurchasingCompanyGeneratedType',
29-
},
18+
// {
19+
// title: 'useAuthenticatedAccountCustomer',
20+
// description:
21+
// "Returns the current authenticated `Customer`. The value is `undefined` if the customer isn't authenticated.",
22+
// type: 'UseAuthenticatedAccountCustomerGeneratedType',
23+
// },
24+
// {
25+
// title: 'useAuthenticatedAccountPurchasingCompany',
26+
// description:
27+
// "Provides information about the company of the authenticated business customer. The value is `undefined` if a business customer isn't authenticated.",
28+
// type: 'UseAuthenticatedAccountPurchasingCompanyGeneratedType',
29+
// },
3030
],
3131
related: [],
3232
};

Diff for: packages/ui-extensions/docs/surfaces/customer-account/reference/apis/customer-privacy.doc.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ const data: ReferenceEntityTemplateSchema = {
1818
description: CUSTOMER_ACCOUNT_STANDARD_API_DEFINITION.description,
1919
type: 'Docs_Standard_CustomerPrivacyApi',
2020
},
21-
{
22-
title: 'useCustomerPrivacy',
23-
description:
24-
'Returns the current customer privacy settings and metadata and re-renders your component if the customer privacy settings change.',
25-
type: 'UseCustomerPrivacyGeneratedType',
26-
},
21+
// {
22+
// title: 'useCustomerPrivacy',
23+
// description:
24+
// 'Returns the current customer privacy settings and metadata and re-renders your component if the customer privacy settings change.',
25+
// type: 'UseCustomerPrivacyGeneratedType',
26+
// },
2727
],
2828
defaultExample: {
2929
codeblock: {

0 commit comments

Comments
 (0)