Design system.
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 

200 líneas
5.6 KiB

  1. import {
  2. cp,
  3. readFile,
  4. rm,
  5. stat,
  6. writeFile,
  7. symlink,
  8. } from 'fs/promises';
  9. import {
  10. dirname,
  11. resolve,
  12. basename,
  13. extname,
  14. join,
  15. } from 'path';
  16. import { Argv } from 'yargs';
  17. import { mkdirp } from 'mkdirp';
  18. import { PackageData } from '../utils/data';
  19. import { CommandError } from '../utils/error';
  20. import { useBasePath } from '../mixins/base-path';
  21. import { useInternalPath } from '../mixins/internal-path';
  22. export enum GenerateReturnCode {
  23. SUCCESS = 0,
  24. COULD_NOT_GENERATE_PAGES = -3,
  25. }
  26. const cleanContent = async (internalPath: string) => {
  27. try {
  28. const destCwd = resolve(internalPath, '.amanuensis', 'next', 'src');
  29. await rm(resolve(destCwd, 'content'), { recursive: true });
  30. } catch {
  31. // noop
  32. }
  33. };
  34. const resetPages = async (internalPath: string) => {
  35. try {
  36. const defaultCwd = resolve(internalPath, 'src', 'next');
  37. const destCwd = resolve(internalPath, '.amanuensis', 'next', 'src');
  38. await rm(resolve(destCwd, 'pages'), { recursive: true });
  39. await cp(resolve(defaultCwd, 'pages'), resolve(destCwd, 'pages'), { recursive: true });
  40. } catch {
  41. // noop
  42. }
  43. };
  44. const linkComponents = async (basePath: string, internalPath: string) => {
  45. process.stdout.write('Linking components...\n');
  46. const customComponentDir = resolve(basePath, '.amanuensis');
  47. const defaultComponentDir = resolve(internalPath, 'src', 'next');
  48. const destCwd = resolve(internalPath, '.amanuensis', 'next', 'src');
  49. // todo merge package.json
  50. const componentsList = [
  51. 'next/src/components/Wrapper.tsx',
  52. 'next/src/components/PageLayout.tsx',
  53. 'next/src/components/theme.ts',
  54. 'next/src/components/postcss.config.js',
  55. 'next/src/components/tailwind.config.js',
  56. ];
  57. await Promise.all(componentsList.map(async (componentPath) => {
  58. const destPath = resolve(destCwd, componentPath);
  59. let componentDir = customComponentDir;
  60. try {
  61. await stat(resolve(componentDir, componentPath));
  62. } catch (errRaw) {
  63. const err = errRaw as NodeJS.ErrnoException;
  64. if (err.code === 'ENOENT') {
  65. componentDir = defaultComponentDir;
  66. }
  67. }
  68. await mkdirp(dirname(destPath));
  69. await cp(
  70. resolve(componentDir, componentPath),
  71. destPath,
  72. );
  73. process.stdout.write(`Linked ${componentPath}\n`);
  74. }));
  75. process.stdout.write('done\n');
  76. };
  77. const pageContent = (preambleImport: string) => `import {NextPage} from 'next';
  78. import {ComponentContext} from '@/contexts/Component';
  79. import {Wrapper} from '@/components/Wrapper';
  80. import {PreambleContext} from '@/contexts/Preamble';
  81. import Preamble from '${preambleImport}';
  82. import {PageLayout} from '@/components/PageLayout';
  83. const IndexPage: NextPage = () => {
  84. return (
  85. <PreambleContext.Provider value={Preamble}>
  86. <Wrapper>
  87. <PageLayout />
  88. </Wrapper>
  89. </PreambleContext.Provider>
  90. );
  91. };
  92. export default IndexPage;
  93. `;
  94. const writeContent = async (basePath: string, internalPath: string) => {
  95. const destCwd = resolve(internalPath, '.amanuensis', 'next', 'src');
  96. const packagesPath = resolve(internalPath, '.amanuensis', 'packages.json');
  97. const packagesDataJson = await readFile(packagesPath, 'utf-8');
  98. const packagesData = JSON.parse(packagesDataJson) as PackageData[];
  99. try {
  100. await Promise.all(packagesData.map(async (pkg) => {
  101. const packageDir = resolve(basePath, pkg.basePath);
  102. const packageLinkDir = resolve(internalPath, '.amanuensis', 'next', 'node_modules', pkg.name);
  103. await mkdirp(dirname(packageLinkDir));
  104. try {
  105. await symlink(packageDir, packageLinkDir);
  106. } catch {
  107. // noop
  108. }
  109. await mkdirp(resolve(destCwd, 'content', pkg.basePath));
  110. await mkdirp(resolve(destCwd, 'pages', pkg.basePath));
  111. await Promise.all(
  112. pkg.markdown.map(async (m) => {
  113. const srcPath = resolve(basePath, pkg.basePath, m.filePath);
  114. const destPath = resolve(destCwd, 'content', pkg.basePath, m.name);
  115. await cp(srcPath, destPath);
  116. const pageDestPath = resolve(destCwd, 'pages', pkg.basePath, `${basename(m.name, extname(m.name))}.tsx`);
  117. const preambleImport = `@/${join('content', pkg.basePath, m.name)}`;
  118. await writeFile(pageDestPath, pageContent(preambleImport));
  119. // todo fetch components for display to props and preamble
  120. // todo fix problem when building with import aliases
  121. // todo find a way to build with tailwind
  122. // todo link components to next project (done)
  123. // todo merge contents of .amanuensis with next project
  124. }),
  125. );
  126. }));
  127. } catch (errRaw) {
  128. throw new CommandError(GenerateReturnCode.COULD_NOT_GENERATE_PAGES, 'Could not write inner page file', errRaw as Error);
  129. }
  130. try {
  131. const srcPath = resolve(basePath, 'README.md');
  132. const destPath = resolve(destCwd, 'content', 'index.md');
  133. await cp(srcPath, destPath);
  134. } catch (errRaw) {
  135. throw new CommandError(GenerateReturnCode.COULD_NOT_GENERATE_PAGES, 'Could not write index file', errRaw as Error);
  136. }
  137. };
  138. export const description = 'Generate documentation from typedoc.json' as const;
  139. export interface RefreshArgs {
  140. subcommands?: string[];
  141. clean?: boolean;
  142. }
  143. export const builder = (yargs: Argv) => yargs
  144. .option('clean', {
  145. alias: 'c',
  146. type: 'boolean',
  147. description: 'Reset generated content',
  148. default: true,
  149. });
  150. const refresh = async (args: RefreshArgs) => {
  151. try {
  152. const internalPath = await useInternalPath();
  153. const { clean = true } = args;
  154. if (clean) {
  155. await cleanContent(internalPath);
  156. await resetPages(internalPath);
  157. }
  158. const basePath = await useBasePath();
  159. await linkComponents(basePath, internalPath);
  160. await writeContent(basePath, internalPath);
  161. } catch (errRaw) {
  162. const err = errRaw as CommandError;
  163. process.stderr.write(`${err.message}\n`);
  164. return err.exitCode;
  165. }
  166. return GenerateReturnCode.SUCCESS;
  167. };
  168. export default refresh;