-
Notifications
You must be signed in to change notification settings - Fork 40
Customer account rc doc - support doc generate #2768
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,15 @@ | ||
/* eslint-disable no-undef, no-console */ | ||
import childProcess from 'child_process'; | ||
import fs from 'fs/promises'; | ||
import {existsSync} from 'fs'; | ||
import path from 'path'; | ||
import {fileURLToPath} from 'url'; | ||
|
||
import { | ||
generateFiles, | ||
copyGeneratedToShopifyDev, | ||
replaceFileContent, | ||
} from '../build-doc-shared.mjs'; | ||
|
||
const EXTENSIONS_API_VERSION = process.argv[2] || 'unstable'; | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
|
@@ -31,15 +36,8 @@ const generatedStaticPagesFile = 'generated_static_pages.json'; | |
const componentDefs = path.join(srcPath, 'components.d.ts'); | ||
const tempComponentDefs = path.join(srcPath, 'components.ts'); | ||
|
||
const replaceFileContent = async (filePaths, searchValue, replaceValue) => { | ||
const files = Array.isArray(filePaths) ? filePaths : [filePaths]; | ||
for (const filePath of files) { | ||
const content = await fs.readFile(filePath, 'utf8'); | ||
// @ts-ignore -- TS should know this is a string but it doesn't | ||
const replacedContent = content.replaceAll(searchValue, replaceValue); | ||
await fs.writeFile(filePath, replacedContent); | ||
} | ||
}; | ||
const tsconfig = 'tsconfig.docs.json'; | ||
const tsconfigAppBridge = 'tsconfig.ab.docs.json'; | ||
|
||
const decodeHTML = (str) => { | ||
return str | ||
|
@@ -156,57 +154,6 @@ const transformJson = async (filePath, isExtensions) => { | |
await fs.writeFile(filePath, JSON.stringify(jsonData, null, 2)); | ||
}; | ||
|
||
const generateFiles = async (tsconfig, outputDir, isExtensions = true) => { | ||
const scripts = [ | ||
`yarn tsc --project ${docsRelativePath}/${tsconfig} --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --input ./${srcRelativePath} --typesInput ./${srcRelativePath} --output ./${outputDir}`, | ||
]; | ||
|
||
if (isExtensions) { | ||
scripts.push( | ||
`yarn tsc ${docsRelativePath}/staticPages/*.doc.ts --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --isLandingPage --input ./${docsRelativePath}/staticPages --output ./${outputDir}`, | ||
); | ||
} | ||
|
||
scripts.forEach((script) => childProcess.execSync(script, {stdio: 'pipe'})); | ||
|
||
const srcFiles = await fs.readdir(rootPath, {recursive: true}); | ||
const builtFiles = srcFiles.filter((file) => file.endsWith('.ts')); | ||
await Promise.all( | ||
builtFiles.map((file) => { | ||
const jsFilePath = path.join(rootPath, file.replace('.ts', '.js')); | ||
return existsSync(jsFilePath) ? fs.rm(jsFilePath) : Promise.resolve(); | ||
}), | ||
); | ||
|
||
const generatedFiles = [path.join(outputDir, generatedDocsDataFile)]; | ||
if (isExtensions) { | ||
generatedFiles.push(path.join(outputDir, generatedStaticPagesFile)); | ||
} | ||
|
||
// Make sure https://shopify.dev URLs are relative so they work in Spin. | ||
// See https://github.com/Shopify/generate-docs/issues/181 | ||
await replaceFileContent(generatedFiles, 'https://shopify.dev', ''); | ||
|
||
// @ts-ignore | ||
await transformJson( | ||
path.join(outputDir, generatedDocsDataFile), | ||
isExtensions, | ||
); | ||
}; | ||
|
||
const copyGeneratedToShopifyDev = async () => { | ||
if (!shopifyDevExists) { | ||
console.log( | ||
`Not copying docs to shopify-dev because it was not found at ${shopifyDevPath}.`, | ||
); | ||
process.exit(); | ||
} | ||
|
||
await fs.cp(generatedDocsPath, shopifyDevDBPath, {recursive: true}); | ||
}; | ||
|
||
const generateExtensionsDocs = async () => { | ||
console.log( | ||
`Building Admin UI Extensions docs for ${EXTENSIONS_API_VERSION} version`, | ||
|
@@ -218,16 +165,30 @@ const generateExtensionsDocs = async () => { | |
); | ||
} | ||
|
||
const extensionsOutputDir = `${docsGeneratedRelativePath}/admin_extensions/${EXTENSIONS_API_VERSION}`; | ||
const outputDir = `${docsGeneratedRelativePath}/admin_extensions/${EXTENSIONS_API_VERSION}`; | ||
|
||
await generateFiles('tsconfig.docs.json', extensionsOutputDir); | ||
const scripts = [ | ||
`yarn tsc --project ${docsRelativePath}/${tsconfig} --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --input ./${srcRelativePath} --typesInput ./${srcRelativePath} --output ./${outputDir}`, | ||
`yarn tsc ${docsRelativePath}/staticPages/*.doc.ts --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --isLandingPage --input ./${docsRelativePath}/staticPages --output ./${outputDir}`, | ||
]; | ||
|
||
await generateFiles({ | ||
scripts, | ||
outputDir, | ||
rootPath, | ||
generatedDocsDataFile, | ||
generatedStaticPagesFile, | ||
transformJson: (filePath) => transformJson(filePath, true), | ||
}); | ||
|
||
// Replace 'unstable' with the exact API version in relative doc links | ||
await replaceFileContent( | ||
path.join(extensionsOutputDir, generatedDocsDataFile), | ||
'/docs/api/admin-extensions/unstable/', | ||
`/docs/api/admin-extensions/${EXTENSIONS_API_VERSION}`, | ||
); | ||
await replaceFileContent({ | ||
filePaths: path.join(outputDir, generatedDocsDataFile), | ||
searchValue: '/docs/api/admin-extensions/unstable/', | ||
replaceValue: `/docs/api/admin-extensions/${EXTENSIONS_API_VERSION}`, | ||
}); | ||
|
||
await fs.cp( | ||
path.join(docsPath, 'screenshots'), | ||
|
@@ -243,26 +204,38 @@ const generateExtensionsDocs = async () => { | |
const generateAppBridgeDocs = async () => { | ||
console.log('Building App Bridge docs'); | ||
|
||
await generateFiles( | ||
'tsconfig.ab.docs.json', | ||
`${docsGeneratedRelativePath}/app_bridge`, | ||
false, | ||
); | ||
const outputDir = `${docsGeneratedRelativePath}/app_bridge`; | ||
const scripts = [ | ||
`yarn tsc --project ${docsRelativePath}/${tsconfigAppBridge} --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --input ./${srcRelativePath} --typesInput ./${srcRelativePath} --output ./${outputDir}`, | ||
]; | ||
|
||
await generateFiles({ | ||
scripts, | ||
outputDir, | ||
rootPath, | ||
generatedDocsDataFile, | ||
transformJson: (filePath) => transformJson(filePath, false), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we do not pass |
||
}); | ||
}; | ||
|
||
try { | ||
if (existsSync(generatedDocsPath)) { | ||
await fs.rm(generatedDocsPath, {recursive: true}); | ||
} | ||
await fs.copyFile(componentDefs, tempComponentDefs); | ||
await replaceFileContent( | ||
tempComponentDefs, | ||
/typeof globalThis\.HTMLElement/g, | ||
'any', | ||
); | ||
await replaceFileContent({ | ||
filePaths: tempComponentDefs, | ||
searchValue: /typeof globalThis\.HTMLElement/g, | ||
replaceValue: 'any', | ||
}); | ||
await generateExtensionsDocs(); | ||
await generateAppBridgeDocs(); | ||
await copyGeneratedToShopifyDev(); | ||
await copyGeneratedToShopifyDev({ | ||
generatedDocsPath, | ||
shopifyDevPath, | ||
shopifyDevDBPath, | ||
}); | ||
|
||
await fs.rm(tempComponentDefs); | ||
} catch (error) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* eslint-disable no-undef, no-console */ | ||
import childProcess from 'child_process'; | ||
import fs from 'fs/promises'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. all extracted from admin's buold-docs scripts. All these functions will only use parameters, no global variables any more |
||
import {existsSync} from 'fs'; | ||
import path from 'path'; | ||
|
||
export const replaceFileContent = async ({ | ||
filePaths, | ||
searchValue, | ||
replaceValue, | ||
}) => { | ||
const files = Array.isArray(filePaths) ? filePaths : [filePaths]; | ||
for (const filePath of files) { | ||
const content = await fs.readFile(filePath, 'utf8'); | ||
// @ts-ignore -- TS should know this is a string but it doesn't | ||
const replacedContent = content.replaceAll(searchValue, replaceValue); | ||
await fs.writeFile(filePath, replacedContent); | ||
} | ||
}; | ||
|
||
export const generateFiles = async ({ | ||
scripts, | ||
outputDir, | ||
rootPath, | ||
generatedDocsDataFile, | ||
generatedStaticPagesFile, | ||
transformJson, | ||
}) => { | ||
scripts.forEach((script) => childProcess.execSync(script, {stdio: 'pipe'})); | ||
|
||
const srcFiles = await fs.readdir(rootPath, {recursive: true}); | ||
const builtFiles = srcFiles.filter((file) => file.endsWith('.ts')); | ||
await Promise.all( | ||
builtFiles.map((file) => { | ||
const jsFilePath = path.join(rootPath, file.replace('.ts', '.js')); | ||
return existsSync(jsFilePath) ? fs.rm(jsFilePath) : Promise.resolve(); | ||
}), | ||
); | ||
|
||
const generatedFiles = [path.join(outputDir, generatedDocsDataFile)]; | ||
if (generatedStaticPagesFile) { | ||
generatedFiles.push(path.join(outputDir, generatedStaticPagesFile)); | ||
} | ||
|
||
// Make sure https://shopify.dev URLs are relative so they work in Spin. | ||
// See https://github.com/Shopify/generate-docs/issues/181 | ||
await replaceFileContent({ | ||
filePaths: generatedFiles, | ||
searchValue: 'https://shopify.dev', | ||
replaceValue: '', | ||
}); | ||
|
||
if (transformJson) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
await transformJson(path.join(outputDir, generatedDocsDataFile)); | ||
} | ||
}; | ||
|
||
export const copyGeneratedToShopifyDev = async ({ | ||
generatedDocsPath, | ||
shopifyDevPath, | ||
shopifyDevDBPath, | ||
}) => { | ||
const shopifyDevExists = existsSync(shopifyDevPath); | ||
if (!shopifyDevExists) { | ||
console.log( | ||
`Not copying docs to shopify-dev because it was not found at ${shopifyDevPath}.`, | ||
); | ||
process.exit(); | ||
} | ||
|
||
await fs.cp(generatedDocsPath, shopifyDevDBPath, {recursive: true}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
/* eslint-disable no-undef, no-console */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you make the script re-usable and pass in the right paths instead of duplicating? It would be better for maintainance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please don't copy paste this script. Bring it up layers and make it reusable for everyone. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extracted all the shared functions, and let each service construct their own build steps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is great progress but I think there is more to do. The directory I think we should really aim at making one script with arguments that works for all surfaces instead of splitting it into reusable functions. I understand the time pressure folks are under so I am willing to be flexible but I think this still needs a second pass. |
||
import fs from 'fs/promises'; | ||
import {existsSync} from 'fs'; | ||
import path from 'path'; | ||
import {fileURLToPath} from 'url'; | ||
|
||
import { | ||
generateFiles, | ||
copyGeneratedToShopifyDev, | ||
replaceFileContent, | ||
} from '../build-doc-shared.mjs'; | ||
|
||
const EXTENSIONS_API_VERSION = process.argv[2] || 'unstable'; | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
const __dirname = path.dirname(__filename); | ||
|
||
const rootPath = path.join(__dirname, '../../..'); | ||
const docsRelativePath = 'docs/surfaces/customer-account'; | ||
const docsGeneratedRelativePath = 'docs/surfaces/customer-account/generated'; | ||
const srcRelativePath = 'src/surfaces/customer-account'; | ||
const docsPath = path.join(rootPath, docsRelativePath); | ||
const srcPath = path.join(rootPath, srcRelativePath); | ||
const generatedDocsPath = path.join(docsPath, 'generated'); | ||
const shopifyDevPath = path.join(rootPath, '../../../shopify-dev'); | ||
const shopifyDevDBPath = path.join( | ||
shopifyDevPath, | ||
'db/data/docs/templated_apis', | ||
); | ||
|
||
const generatedDocsDataFile = 'generated_docs_data.json'; | ||
const generatedStaticPagesFile = 'generated_static_pages.json'; | ||
|
||
const componentDefs = path.join(srcPath, 'components.d.ts'); | ||
const tempComponentDefs = path.join(srcPath, 'components.ts'); | ||
|
||
const tsconfig = 'tsconfig.docs.json'; | ||
|
||
const transformJson = async (filePath) => { | ||
let jsonData = JSON.parse((await fs.readFile(filePath, 'utf8')).toString()); | ||
|
||
jsonData = jsonData.filter(Boolean); | ||
await fs.writeFile(filePath, JSON.stringify(jsonData, null, 2)); | ||
}; | ||
|
||
const generateExtensionsDocs = async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function should be brought into the admin docs generator and be named something with customer accounts name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extracted some shared functions and make transformJson customizable 0459c0c |
||
console.log( | ||
`Building Customer Account UI Extensions docs for ${EXTENSIONS_API_VERSION} version`, | ||
); | ||
|
||
if (EXTENSIONS_API_VERSION === 'unstable') { | ||
console.log( | ||
"You can add a calver version argument (e.g. 'yarn docs:customer-account 2024-07') to generate the docs for a stable version.", | ||
); | ||
} | ||
|
||
const outputDir = `${docsGeneratedRelativePath}/customer_account_ui_extensions/${EXTENSIONS_API_VERSION}`; | ||
|
||
const scripts = [ | ||
`yarn tsc --project ${docsRelativePath}/${tsconfig} --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --input ./${docsRelativePath}/reference ./${docsRelativePath} ./${docsRelativePath}/../../../src/surfaces/customer-account/components --typesInput ./${srcRelativePath} --output ./${outputDir}`, | ||
`yarn tsc ${docsRelativePath}/staticPages/*.doc.ts --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --isLandingPage --input ./${docsRelativePath}/staticPages --output ./${outputDir}`, | ||
`yarn tsc ${docsRelativePath}/categories/*.doc.ts --moduleResolution node --target esNext --module CommonJS`, | ||
`yarn generate-docs --isCategoryPage --input ./${docsRelativePath}/categories --output ./${outputDir}`, | ||
]; | ||
|
||
await generateFiles({ | ||
scripts, | ||
outputDir, | ||
rootPath, | ||
generatedDocsDataFile, | ||
generatedStaticPagesFile, | ||
transformJson, | ||
}); | ||
|
||
// Replace 'unstable' with the exact API version in relative doc links | ||
await replaceFileContent({ | ||
filePaths: path.join(outputDir, generatedDocsDataFile), | ||
searchValue: '/docs/api//unstable/', | ||
replaceValue: `/docs/api/customer-account-ui-extensions/${EXTENSIONS_API_VERSION}`, | ||
}); | ||
|
||
await fs.cp( | ||
path.join(docsPath, 'screenshots'), | ||
path.join( | ||
shopifyDevPath, | ||
'app/assets/images/templated-apis-screenshots/customer-account-ui-extensions', | ||
EXTENSIONS_API_VERSION, | ||
), | ||
{recursive: true}, | ||
); | ||
}; | ||
|
||
try { | ||
if (existsSync(generatedDocsPath)) { | ||
await fs.rm(generatedDocsPath, {recursive: true}); | ||
} | ||
await fs.copyFile(componentDefs, tempComponentDefs); | ||
await replaceFileContent({ | ||
filePaths: tempComponentDefs, | ||
searchValue: /typeof globalThis\.HTMLElement/g, | ||
replaceValue: 'any', | ||
}); | ||
await generateExtensionsDocs(); | ||
await copyGeneratedToShopifyDev({ | ||
generatedDocsPath, | ||
shopifyDevPath, | ||
shopifyDevDBPath, | ||
}); | ||
|
||
await fs.rm(tempComponentDefs); | ||
} catch (error) { | ||
console.error(error); | ||
console.log(error.stdout.toString()); | ||
console.log(error.stderr.toString()); | ||
process.exit(1); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now this is an optional function, admin will pass it