├── website ├── static │ ├── .nojekyll │ └── img │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── undraw_docusaurus_tree.svg │ │ └── undraw_docusaurus_mountain.svg ├── _redirects ├── sidebars.js ├── .gitignore ├── tsconfig.json ├── blog │ ├── 2019-05-28-hola.md │ ├── 2019-05-29-hello-world.md │ ├── 2019-05-30-welcome.md │ ├── 2020-04-14-blog-plugin.md │ └── 2020-04-14-large-blog-post.md ├── src │ ├── tsconfig.json │ ├── pages │ │ ├── styles.module.css │ │ └── index.tsx │ └── types.d.ts ├── readme.md ├── package.json ├── docusaurus.config.js └── babel.config.js ├── pnpm-workspace.yaml ├── support ├── root │ ├── typedoc.json │ ├── .markdownlint.json │ ├── .huskyrc │ ├── babel.config.js │ ├── .size-limit.json │ ├── tsconfig.json │ ├── .eslintignore │ ├── .lintstagedrc │ ├── .prettierrc.js │ ├── globals.d.ts │ ├── jest.config.js │ ├── readme.md │ └── .eslintrc.js ├── .config.sample.json ├── assets │ ├── readme.md │ └── logo.svg ├── jest │ ├── jest.framework.dom.ts │ ├── readme.md │ ├── patches.d.ts │ ├── helpers.js │ ├── jest.config.js │ └── jest.framework.ts ├── scripts │ ├── babel-register.js │ ├── tsconfig.json │ ├── ambient.d.ts │ ├── run-if-not-ci.ts │ ├── check-pnpm.mjs │ ├── run-if-config.ts │ ├── run-if-clean.ts │ ├── run-if-mac.ts │ ├── enable-pr-changeset.ts │ ├── readme.md │ ├── run-if-publishable.ts │ ├── changelog-dates.ts │ ├── esbuild-register.js │ ├── helpers │ │ ├── read-config.ts │ │ └── index.ts │ ├── changeset-forced-update.ts │ ├── symlink-root.mjs │ └── generate-configs.ts ├── tsconfig.lint.json ├── src │ └── tsconfig.json ├── tsconfig.json ├── readme.md ├── tsconfig.base.json ├── base.babel.js └── package.json ├── .gitattributes ├── packages ├── readme.md ├── tsconfig.json └── template-package │ ├── dist-types │ └── index.d.ts │ ├── src │ ├── index.ts │ └── tsconfig.json │ ├── __tests__ │ ├── index.spec.ts │ └── tsconfig.json │ ├── package.json │ └── readme.md ├── .vscode ├── extensions.json └── settings.json ├── docs ├── readme.md └── contributing.md ├── .changeset ├── config.json └── README.md ├── .github ├── ISSUE_TEMPLATE │ ├── project-roadmap.md │ ├── bug_report.md │ └── config.yml ├── pull_request_template.md ├── actions │ └── pnpm │ │ └── action.yml └── workflows │ ├── docs.yml │ ├── publish.yml │ ├── version.yml │ └── ci.yml ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .npmrc ├── LICENSE ├── .gitignore ├── readme.md └── package.json /website/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/_redirects: -------------------------------------------------------------------------------- 1 | /chat https://discord.gg/C4cfrMK 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'support' 4 | - 'website' 5 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | someSidebar: { 3 | Hello: ['contributing'], 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/remirror/template/HEAD/website/static/img/favicon.ico -------------------------------------------------------------------------------- /support/root/typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryFiles": ["packages/template-package/src/index.ts"], 3 | "out": "docs/api" 4 | } 5 | -------------------------------------------------------------------------------- /support/root/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "header-increment": false, 3 | "line-length": false, 4 | "first-line-h1": false, 5 | "html": false 6 | } 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Generated files we don't want to see in code review/diff 2 | docs/generated/gatsby.ts binary 3 | 4 | **/__image_snapshots__/*.* binary 5 | 6 | -------------------------------------------------------------------------------- /packages/readme.md: -------------------------------------------------------------------------------- 1 | # packages 2 | 3 | This is where all the packages should be placed for the project. Scoped packages should be placed in a sub folder, e.g. `@scoped`. 4 | -------------------------------------------------------------------------------- /support/.config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "preCommit": true, 4 | "prePush": true, 5 | "postMerge": true, 6 | "macPostInstall": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "dbaeumer.vscode-eslint", 4 | "esbenp.prettier-vscode", 5 | "davidanson.vscode-markdownlint" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /support/assets/readme.md: -------------------------------------------------------------------------------- 1 | # Assets 2 | 3 | This folder contains the assets for the remirror project. Here you will find the branding and logos that are used throughout the project. 4 | -------------------------------------------------------------------------------- /support/jest/jest.framework.dom.ts: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom/extend-expect'; 2 | 3 | import { toHaveNoViolations } from 'jest-axe'; 4 | 5 | expect.extend(toHaveNoViolations); 6 | -------------------------------------------------------------------------------- /docs/readme.md: -------------------------------------------------------------------------------- 1 | # Docs 2 | 3 | Welcome to the documentation folder your new project. You can use this as a contents folder. 4 | 5 | - [**Docs**](./) 6 | - [**Contributing**](./contributing.md) 7 | -------------------------------------------------------------------------------- /support/jest/readme.md: -------------------------------------------------------------------------------- 1 | # Jest 2 | 3 | This folder contains the configuration for `jest`. 4 | 5 | ## Usage 6 | 7 | The files are used for the project wide jest configuration and the `e2e` tests. 8 | -------------------------------------------------------------------------------- /support/root/.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "pnpm run if-config hooks.preCommit lint-staged", 4 | "pre-push": "pnpm run if-config hooks.prePush \"pnpm checks\"" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /support/scripts/babel-register.js: -------------------------------------------------------------------------------- 1 | require('@babel/register')({ 2 | rootMode: 'upward-optional', 3 | extensions: ['.es6', '.es', '.jsx', '.js', '.mjs', '.ts', '.tsx'], 4 | cache: true, 5 | }); 6 | -------------------------------------------------------------------------------- /support/root/babel.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../base.babel'); 2 | 3 | module.exports = { 4 | ...config, 5 | babelrcRoots: ['.', 'packages/@*/*', 'packages/*'], 6 | sourceType: 'unambiguous', 7 | }; 8 | -------------------------------------------------------------------------------- /support/scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "noEmit": true, 7 | "skipLibCheck": true 8 | }, 9 | "include": ["./"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../support/tsconfig.base.json", 3 | "compilerOptions": { 4 | "types": [], 5 | "declaration": false, 6 | "noEmit": true, 7 | "skipLibCheck": true 8 | }, 9 | "include": ["./*/src"] 10 | } 11 | -------------------------------------------------------------------------------- /support/root/.size-limit.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "template-package", 4 | "limit": "5 KB", 5 | "path": "packages/template-package/dist/template-package.browser.esm.js", 6 | "ignore": [], 7 | "running": false, 8 | "gzip": true 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /support/scripts/ambient.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@babel/register' { 2 | import { TransformOptions } from '@babel/core'; 3 | 4 | function babelRegister( 5 | config: TransformOptions & { extensions?: string[]; cache?: boolean }, 6 | ): void; 7 | 8 | export = babelRegister; 9 | } 10 | -------------------------------------------------------------------------------- /support/root/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [], 3 | "files": [], 4 | "references": [ 5 | { 6 | "path": "packages/template-package/__tests__" 7 | }, 8 | { 9 | "path": "packages/template-package/src" 10 | }, 11 | { 12 | "path": "website/src" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.3.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "ignore": ["support", "website"], 5 | "updateInternalDependencies": "patch", 6 | "commit": false, 7 | "linked": [], 8 | "access": "public", 9 | "baseBranch": "main" 10 | } 11 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /packages/template-package/dist-types/index.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A groundbreaking algorithm which shatters performance estimates to log the template string to the 3 | * console. 4 | * 5 | * Cross platform, and supporting SSR. Make sure to include in your next project. 6 | */ 7 | export declare function printTemplate({ shouldLog }?: { shouldLog?: boolean }): string; 8 | -------------------------------------------------------------------------------- /support/root/.eslintignore: -------------------------------------------------------------------------------- 1 | !.eslintrc.js 2 | !**/.eslintrc.js 3 | **/lib 4 | lib 5 | **/dist 6 | dist 7 | **/dist-types 8 | dist-types 9 | node_modules 10 | .out 11 | public 12 | coverage 13 | 14 | .cache 15 | **/.next 16 | lerna.json 17 | .vscode 18 | .yarn/** 19 | 20 | **/temp/** 21 | 22 | pnpm-lock.yaml 23 | .pnpm-store/ 24 | support/root/pnpm-lock.yaml 25 | 26 | -------------------------------------------------------------------------------- /support/root/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "**/*.js": [ 3 | "prettier --write", 4 | "eslint --fix" 5 | ], 6 | "*.{json,yml,yaml}": [ 7 | "prettier --write" 8 | ], 9 | "*.{md,mdx}": [ 10 | "prettier --write", 11 | "eslint --fix" 12 | ], 13 | "{packages,support}/**/*.{ts,tsx,js}": [ 14 | "prettier --write", 15 | "eslint --fix" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /support/tsconfig.lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base.json", 3 | "compilerOptions": { 4 | "allowJs": true 5 | }, 6 | "include": [ 7 | "../**/*.ts", 8 | "../**/*.tsx", 9 | "../**/*.js", 10 | "../*.js", 11 | "../.eslintrc.js", 12 | "../**/.eslintrc.js", 13 | "../**/.babelrc.js" 14 | ], 15 | "exclude": ["../**/dist/", "../**/public/", "../**/.cache/", "../**/.linaria-cache/"] 16 | } 17 | -------------------------------------------------------------------------------- /support/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > 'src'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "../tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": [], 11 | "declaration": false, 12 | "noEmit": true 13 | }, 14 | "include": ["./"], 15 | "references": [] 16 | } 17 | -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > 'src'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "../support/tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": [], 11 | "declaration": true, 12 | "noEmit": true, 13 | "allowJs": true 14 | }, 15 | "include": ["src"] 16 | } 17 | -------------------------------------------------------------------------------- /website/blog/2019-05-28-hola.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: hola 3 | title: Hola 4 | author: Gao Wei 5 | author_title: Docusaurus Core Team 6 | author_url: https://github.com/wgao19 7 | author_image_url: https://avatars1.githubusercontent.com/u/2055384?v=4 8 | tags: [hola, docusaurus] 9 | --- 10 | 11 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. 12 | Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet 13 | -------------------------------------------------------------------------------- /support/scripts/run-if-not-ci.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Run the command when not within a `CI` environment. 5 | */ 6 | 7 | import { execSync } from 'child_process'; 8 | 9 | const [, , ...args] = process.argv; 10 | const command = args.join(' '); 11 | const { CI } = process.env; 12 | 13 | if (CI === 'true') { 14 | console.log(`CI='true' - skipping command: '${command}'\n\n`); 15 | process.exit(0); 16 | } 17 | 18 | execSync(command, { stdio: 'inherit' }); 19 | -------------------------------------------------------------------------------- /packages/template-package/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A groundbreaking algorithm which shatters performance estimates to log the template string to the 3 | * console. 4 | * 5 | * Cross platform, and supporting SSR. Make sure to include in your next project. 6 | */ 7 | export function printTemplate({ shouldLog = false }: { shouldLog?: boolean } = {}): string { 8 | const value = 'tEmPlATe'; 9 | 10 | if (shouldLog) { 11 | console.log(value); 12 | } 13 | 14 | return value; 15 | } 16 | -------------------------------------------------------------------------------- /website/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > 'src'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "../../support/tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": [], 11 | "declaration": false, 12 | "noEmit": true, 13 | "allowJs": true 14 | }, 15 | "include": ["./"], 16 | "references": [] 17 | } 18 | -------------------------------------------------------------------------------- /support/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > 'src'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "./tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": ["node"], 11 | "allowJs": true, 12 | "noEmit": true 13 | }, 14 | "exclude": ["templates", "root"], 15 | "include": ["./*.js", "jest", "root", "scripts"] 16 | } 17 | -------------------------------------------------------------------------------- /support/scripts/check-pnpm.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * This is left as a JavaScript file since it is called in the `preinstall` hook 5 | * before any packages have been installed. 6 | */ 7 | import process from 'process'; 8 | 9 | if (!/pnpm\.js$/.test(process.env.npm_execpath || '')) { 10 | console.warn( 11 | "\u001B[33mYou don't seem to be using pnpm. This could produce unexpected results.\n\nInstall with:\u001B[39m\n\nnpm i -g pnpm\n\n", 12 | ); 13 | 14 | process.exit(1); 15 | } 16 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works with multi-package repos, or single-package repos to help you version and publish your code. You can find the full documentation for it [in our repository](https://github.com/changesets/changesets) 4 | 5 | We have a quick list of common questions to get you started engaging with this project in [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 6 | -------------------------------------------------------------------------------- /website/blog/2019-05-29-hello-world.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: hello-world 3 | title: Hello 4 | author: Endilie Yacop Sucipto 5 | author_title: Maintainer of Docusaurus 6 | author_url: https://github.com/endiliey 7 | author_image_url: https://avatars1.githubusercontent.com/u/17883920?s=460&v=4 8 | tags: [hello, docusaurus] 9 | --- 10 | 11 | Welcome to this blog. This blog is created with [**Docusaurus 2 alpha**](https://v2.docusaurus.io/). 12 | 13 | 14 | 15 | This is a test post. 16 | 17 | A whole bunch of other information. 18 | -------------------------------------------------------------------------------- /website/blog/2019-05-30-welcome.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: welcome 3 | title: Welcome 4 | author: Yangshun Tay 5 | author_title: Front End Engineer @ Facebook 6 | author_url: https://github.com/yangshun 7 | author_image_url: https://avatars0.githubusercontent.com/u/1315101?s=400&v=4 8 | tags: [facebook, hello, docusaurus] 9 | --- 10 | 11 | Blog features are powered by the blog plugin. Simply add files to the `blog` directory. It supports 12 | tags as well! 13 | 14 | Delete the whole directory if you don't want the blog features. As simple as that! 15 | -------------------------------------------------------------------------------- /packages/template-package/__tests__/index.spec.ts: -------------------------------------------------------------------------------- 1 | import { printTemplate } from '../'; 2 | 3 | describe('printTemplate', () => { 4 | const spy = jest.spyOn(console, 'log'); 5 | spy.mockImplementation(() => {}); 6 | 7 | it('returns a string', () => { 8 | expect(printTemplate()).toStrictEqual(expect.any(String)); 9 | expect(spy).not.toHaveBeenCalled(); 10 | }); 11 | 12 | it('logs when requested', () => { 13 | printTemplate({ shouldLog: true }); 14 | expect(spy).toHaveBeenCalledWith(expect.any(String)); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /website/blog/2020-04-14-blog-plugin.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Blog Plugin 3 | author: Fanny Vieira 4 | authorTitle: Maintainer of Docusaurus 5 | authorURL: https://github.com/fanny 6 | authorImageURL: https://github.com/fanny.png 7 | authorTwitter: fannyvieiira 8 | tags: [blog, docusaurus] 9 | --- 10 | 11 | You can use our blog plugin to do your posts 12 | 13 | 14 | 15 | If you want add your own component, you can use the `swizzle` command. Check more at our 16 | [doc](https://v2.docusaurus.io/docs/using-themes#swizzling-theme-components) 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/project-roadmap.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 📥 Add to the project roadmap 3 | about: 'Create an issue for concrete work to add to project roadmap. For ideas and questions, choose `Discuss an idea` or `Ask a question` instead.' 4 | --- 5 | 6 | ### Description 7 | 8 | 9 | 10 | ### Context 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/template-package/src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > 'src'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "../../../support/tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": [], 11 | "declaration": true, 12 | "noEmit": false, 13 | "composite": true, 14 | "emitDeclarationOnly": true, 15 | "outDir": "../dist-types" 16 | }, 17 | "include": ["./"], 18 | "references": [] 19 | } 20 | -------------------------------------------------------------------------------- /support/root/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: true, 3 | endOfLine: 'lf', 4 | jsxBracketSameLine: false, 5 | jsxSingleQuote: true, 6 | plugins: [require.resolve('prettier-plugin-packagejson')], 7 | printWidth: 100, 8 | proseWrap: 'always', 9 | semi: true, 10 | singleQuote: true, 11 | tabWidth: 2, 12 | trailingComma: 'all', 13 | useTabs: false, 14 | overrides: [ 15 | { 16 | files: ['.github/**/*.md', '.changeset/**/*.md', 'readme.md'], 17 | options: { 18 | proseWrap: 'never', 19 | }, 20 | }, 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /support/root/globals.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Identifies whether this is an e2e test 3 | */ 4 | declare const __E2E__: boolean; 5 | 6 | /** 7 | * A constant injected by jest to identify when this is a test run. 8 | */ 9 | declare const __TEST__: boolean; 10 | 11 | /** 12 | * A constant injected by the build process to identify the version of the 13 | * currently running package. This is currently only available in public 14 | * packages with a types field. 15 | */ 16 | declare const __VERSION__: string; 17 | 18 | /** 19 | * A constant injected by the build process which is true when this is a 20 | * development build. 21 | */ 22 | declare const __DEV__: boolean; 23 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 4 | 5 | ### Checklist 6 | 7 | 8 | 9 | - [ ] I have read the [**contributing**](https://github.com/remirror/template/blob/HEAD/docs/contributing.md) document. 10 | - [ ] My code follows the code style of this project and `pnpm fix` completed successfully. 11 | - [ ] I have updated the documentation where necessary. 12 | - [ ] New code is unit tested and all current tests pass when running `pnpm test`. 13 | 14 | ### Screenshots 15 | 16 | 17 | -------------------------------------------------------------------------------- /support/scripts/run-if-config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Run the provided script based on the status of the property of the config 5 | * file. This used to decided whether husky hooks should be run. 6 | */ 7 | 8 | import { execSync } from 'child_process'; 9 | 10 | import { readProperty } from './helpers/read-config'; 11 | 12 | const [, , property = '', ...args] = process.argv; 13 | const command = args.join(' '); 14 | 15 | // Check for property 16 | const value = readProperty(property); 17 | 18 | if (value) { 19 | console.log('Opted into husky checks... 😋'); 20 | execSync(command, { stdio: 'inherit' }); 21 | } else { 22 | console.log('Ignoring checks'); 23 | process.exit(0); 24 | } 25 | -------------------------------------------------------------------------------- /.github/actions/pnpm/action.yml: -------------------------------------------------------------------------------- 1 | name: 'pnpm installation' 2 | description: 'Install and audit dependencies for pnpm' 3 | inputs: 4 | cache: # id of input 5 | description: 'The location of the pnpm cache' 6 | required: true 7 | default: '.pnpm-store' 8 | version: # id of input 9 | description: 'The version to use' 10 | required: false 11 | default: 5.15.0 12 | 13 | runs: 14 | using: 'composite' 15 | steps: 16 | - name: install pnpm 17 | run: npm install pnpm@${{ inputs.version }} -g 18 | shell: bash 19 | 20 | - name: setup pnpm config 21 | run: pnpm config set store-dir ${{ inputs.cache }} 22 | shell: bash 23 | 24 | - name: install dependencies 25 | run: pnpm install 26 | shell: bash 27 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node/.devcontainer/base.Dockerfile 2 | ARG VARIANT="14" 3 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT} 4 | 5 | # Install additional OS packages 6 | RUN apt-get update -yq && export DEBIAN_FRONTEND=noninteractive \ 7 | && apt-get -yq install --no-install-recommends nano \ 8 | # Install Git LFS 9 | && curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash \ 10 | && apt-get install -yq git-lfs \ 11 | && git lfs install 12 | 13 | ARG PNPM_VERSION="5.15.0" 14 | # Install more global node modules 15 | RUN sudo -u node npm install -g pnpm@${PNPM_VERSION} 16 | -------------------------------------------------------------------------------- /support/scripts/run-if-clean.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Only run the provided script if the git status is clean. 5 | * 6 | * `pnpm ts support/scripts/run-if-clean publish` -> `publish` only runs if the 7 | * repository is in a clean state. 8 | */ 9 | import { execSync } from 'child_process'; 10 | 11 | const [, , ...args] = process.argv; 12 | const command = args.join(' '); 13 | 14 | // Check if git status is dirty right now 15 | const status = execSync('git status -s').toString(); 16 | 17 | if (status) { 18 | console.error( 19 | '\nThis git repository is currently dirty.', 20 | `\n\nPlease commit or stash your changes to proceed with the command: '${command}'\n\n`, 21 | ); 22 | process.exit(1); 23 | } 24 | 25 | execSync(command, { stdio: 'inherit' }); 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐞 Report a bug 3 | about: Found something broken? Let us know! If it's not yet reproducible, please `Ask a question` instead. 4 | labels: 'type: bug :beetle:' 5 | --- 6 | 7 | ### Summary 8 | 9 | 10 | 11 | ### Steps to reproduce 12 | 13 | 14 | 15 | ### Expected results 16 | 17 | 18 | 19 | ### Actual results 20 | 21 | 22 | 23 | ### Additional context 24 | 25 | 26 | 27 | ### Possible Solution 28 | 29 | 30 | -------------------------------------------------------------------------------- /packages/template-package/__tests__/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "__AUTO_GENERATED__": [ 3 | "To update the configuration edit the following field.", 4 | "`package.json > @remirror > tsconfigs > '__tests__'`", 5 | "", 6 | "Then run: `pnpm -w generate:ts`" 7 | ], 8 | "extends": "../../../support/tsconfig.base.json", 9 | "compilerOptions": { 10 | "types": [ 11 | "jest", 12 | "jest-extended", 13 | "jest-axe", 14 | "@testing-library/jest-dom", 15 | "snapshot-diff", 16 | "node" 17 | ], 18 | "declaration": false, 19 | "noEmit": true, 20 | "skipLibCheck": true, 21 | "importsNotUsedAsValues": "remove" 22 | }, 23 | "include": ["./"], 24 | "references": [ 25 | { 26 | "path": "../src" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /support/root/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require('../jest/jest.config'), 3 | coverageThreshold: { 4 | global: { 5 | statements: 60, 6 | }, 7 | }, 8 | collectCoverageFrom: [ 9 | '**/*.{ts,tsx}', 10 | '!**/*.d.ts', 11 | '!**/*.dts.ts', 12 | '!**/theme-styles.ts', 13 | '!**/styles.ts', 14 | '!**/__mocks__/**', 15 | '!**/__tests__/**', 16 | '!**/__dts__/**', 17 | '!**/__fixtures__/**', 18 | '!support/**', 19 | '!website/**', 20 | ], 21 | coverageReporters: ['json', 'lcov', 'text-summary', 'clover'], 22 | collectCoverage: true, 23 | watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'], 24 | testRunner: 'jest-circus/runner', 25 | testPathIgnorePatterns: ['/support/', '/node_modules/'], 26 | }; 27 | -------------------------------------------------------------------------------- /website/readme.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), and provides the blog and documentation for the remirror project. 4 | 5 | The documentation is compiled from the `.md` and `.mdx` files in the the `/docs` folder 6 | 7 | ### Installation 8 | 9 | From the root directory of the project run the following. 10 | 11 | ```bash 12 | pnpm install 13 | ``` 14 | 15 | ### Local Development 16 | 17 | ```bash 18 | pnpm start 19 | ``` 20 | 21 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 22 | 23 | ### Build 24 | 25 | ```bash 26 | pnpm build 27 | ``` 28 | 29 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 30 | -------------------------------------------------------------------------------- /support/readme.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | This is the support directory. If you're a contributor this is where a lot of the underlying work happens. 4 | 5 | Each folder contains a readme file with the brief explanation of the contents. 6 | 7 | ## Files 8 | 9 | This folder consists of the following. 10 | 11 | - `tsconfig.base.json` - The base config file which is used by all other `tsconfig` files to provide the typescript support in your editor and for builds. 12 | - `tsconfig.lint.json` - The `tsconfig` file used by eslint to provide linting with type information. 13 | - `tsconfig.main.json` - The main `tsconfig` file which provides typecheck for `/packages`, and most of the `/support` files. 14 | - `base.babel.js` - The base babel configuration to prevent the need to constantly override it. 15 | 16 | Take a peek inside each folder to find out more on what it's there for. 17 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # Don't use the workspace protocol. 2 | save-workspace-protocol=false 3 | 4 | # This makes installations on branches that aren't up to date less stressful by 5 | # preserving the latest version in the current workspace. 6 | prefer-workspace-packages=true 7 | 8 | # Set the publish branch to prevent unintentional publishing. 9 | publish-branch="main" 10 | 11 | # Version 5.2.0 introduces automatic hoisting of `@types/*`. I'm turning it off 12 | # for now. 13 | shamefully-hoist=false 14 | 15 | # Support cross platform shell commands. 16 | shell-emulator=true 17 | 18 | # Added since the shell-emulator seems to remove colors from output. There is a 19 | # warning against using this setting in the docs. 20 | # https://pnpm.js.org/en/npmrc#color 21 | color=always 22 | 23 | # Don't check the workspace root when installing workspace dependencies 24 | ignore-workspace-root-check=true 25 | -------------------------------------------------------------------------------- /support/jest/patches.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'diffable-html' { 2 | /** 3 | * This formatter will normalize your HTML in a way that when you diff it, you 4 | * get a clear sense of what changed. 5 | * 6 | * This is a "zero-config" and opinionated HTML formatter. Default rules might 7 | * change in future releases in which case we will push a major release. 8 | * 9 | * Feel free to open issues to discuss better defaults. 10 | * 11 | * ```ts 12 | * import toDiffableHtml from 'diffable-html'; 13 | * 14 | * const html = ` 15 | * 19 | * ` 20 | * 21 | * log(toDiffableHtml(html)); 22 | * ``` 23 | * 24 | */ 25 | function toDiffableHtml(html: string): string; 26 | export = toDiffableHtml; 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | # Remove this file if you don't have **Discussions** enabled for your project. 4 | contact_links: 5 | - name: 💡 Discuss an idea 6 | url: https://github.com/remirror/template/discussions/new 7 | about: 8 | Suggest your ideas for this project. Discussions with high interest and positive feedback will 9 | be added to the roadmap. 10 | 11 | - name: ❔ Ask a question 12 | url: https://github.com/remirror/template/discussions/new 13 | about: Ask questions and discuss with other community members. 14 | 15 | - name: 🙏 Request help 16 | url: https://github.com/remirror/template/discussions/new 17 | about: Ask the `remirror` community for help. 18 | 19 | - name: 🌟 Showcase your work 20 | url: https://github.com/remirror/template/discussions/new 21 | about: Showcase what you've been building with `remirror`. 22 | -------------------------------------------------------------------------------- /support/jest/helpers.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | /** 4 | * @param {string[]} paths - the paths 5 | */ 6 | const baseDir = (...paths) => path.resolve(__dirname, '..', '..', path.join(...paths)); 7 | 8 | /** 9 | * @param {string[]} args - the paths 10 | */ 11 | const jestSupportDir = (...args) => baseDir(path.join('support', 'jest', ...args)); 12 | 13 | const environment = { 14 | get isUnit() { 15 | return !environment.isE2E && !environment.isIntegration; 16 | }, 17 | 18 | get isIntegration() { 19 | return process.env.TEST_ENV === 'integration'; 20 | }, 21 | 22 | get isE2E() { 23 | return process.env.TEST_ENV === 'e2e'; 24 | }, 25 | 26 | get isCI() { 27 | return Boolean(process.env.CI); 28 | }, 29 | 30 | get isMacOS() { 31 | return process.platform === 'darwin'; 32 | }, 33 | }; 34 | 35 | exports.baseDir = baseDir; 36 | exports.jestSupportDir = jestSupportDir; 37 | exports.environment = environment; 38 | -------------------------------------------------------------------------------- /website/src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /* stylelint-disable docusaurus/copyright-header */ 2 | 3 | /** 4 | * CSS files with the .module.css suffix will be treated as CSS modules 5 | * and scoped locally. 6 | */ 7 | 8 | .heroBanner { 9 | padding: 4rem 0; 10 | text-align: center; 11 | position: relative; 12 | overflow: hidden; 13 | } 14 | 15 | @media screen and (max-width: 966px) { 16 | .heroBanner { 17 | padding: 2rem; 18 | } 19 | } 20 | 21 | .buttons { 22 | display: flex; 23 | align-items: center; 24 | justify-content: center; 25 | } 26 | 27 | .hero { 28 | display: flex; 29 | flex-direction: column; 30 | width: 100%; 31 | align-items: center; 32 | place-content: center; 33 | } 34 | 35 | .section { 36 | margin: 10rem; 37 | } 38 | 39 | .features { 40 | display: flex; 41 | align-items: center; 42 | padding: 2rem 0; 43 | width: 100%; 44 | } 45 | 46 | .featureImage { 47 | height: 200px; 48 | width: 200px; 49 | } 50 | -------------------------------------------------------------------------------- /support/jest/jest.config.js: -------------------------------------------------------------------------------- 1 | const { jestSupportDir, baseDir } = require('./helpers'); 2 | 3 | const { TEST_BUILD } = process.env; 4 | 5 | /** @type Partial */ 6 | module.exports = { 7 | clearMocks: true, 8 | verbose: true, 9 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], 10 | globals: { 11 | __DEV__: true, 12 | __TEST__: true, 13 | __E2E__: false, 14 | }, 15 | transform: { 16 | '^.+\\.(js|jsx|ts|tsx)$': [require.resolve('babel-jest'), { rootMode: 'upward' }], 17 | }, 18 | moduleDirectories: ['node_modules'], 19 | testPathIgnorePatterns: ['/lib/', '/node_modules/'], 20 | testRegex: '/__tests__/.*\\.spec\\.tsx?$', 21 | setupFilesAfterEnv: [ 22 | jestSupportDir('jest.framework.ts'), 23 | jestSupportDir('jest.framework.dom.ts'), 24 | ], 25 | cacheDirectory: baseDir('.jest', TEST_BUILD ? 'build' : 'aliased'), 26 | errorOnDeprecated: true, 27 | }; 28 | -------------------------------------------------------------------------------- /support/scripts/run-if-mac.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Run the command if this is a mac. 5 | */ 6 | 7 | import { execSync } from 'child_process'; 8 | 9 | import { environment } from '../jest/helpers'; 10 | import { readProperty } from './helpers/read-config'; 11 | 12 | const shouldRunMacPostInstall = readProperty('hooks.macPostInstall'); 13 | 14 | const [, , ...args] = process.argv; 15 | const command = args.join(' '); 16 | 17 | if (!environment.isMacOS || environment.isCI) { 18 | console.log(`Skipping mac specific command: '${command}'`); 19 | process.exit(0); 20 | } 21 | 22 | if (!shouldRunMacPostInstall) { 23 | console.log( 24 | 'Mac specific commands are being ignored.\n' + 25 | 'Set `hooks.macPostInstall` to `true`\n' + 26 | 'in `.config.json` if you want to reactivate.', 27 | ); 28 | process.exit(0); 29 | } 30 | 31 | console.log('Setting up your machine for mac development'); 32 | execSync(command, { stdio: 'inherit' }); 33 | -------------------------------------------------------------------------------- /support/scripts/enable-pr-changeset.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * This script edits the `/.changeset/config.json` file so that it doesn't need 5 | * the GITHUB_TOKEN to be available in order to build the changeset. 6 | * 7 | * This allows PR's which don't have access to the `GITHUB_TOKEN` to still pass. 8 | */ 9 | 10 | import chalk from 'chalk'; 11 | import writeJson from 'write-json-file'; 12 | 13 | import changesetConfig from '../../.changeset/config.json'; 14 | import { baseDir } from './helpers'; 15 | 16 | async function main() { 17 | if (!process.env.CI) { 18 | console.log( 19 | chalk`{red Attempted to edit the changeset config in a non CI environment.} Exiting...`, 20 | ); 21 | 22 | return; 23 | } 24 | 25 | Reflect.deleteProperty(changesetConfig, 'changelog'); 26 | await writeJson(baseDir('.changeset', 'config.json'), changesetConfig); 27 | 28 | console.log(chalk`{green Successfully updated the CI configuration. }`); 29 | } 30 | 31 | main(); 32 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Editor 3 | "editor.tabSize": 2, 4 | "editor.rulers": [100], 5 | "editor.insertSpaces": true, 6 | "editor.defaultFormatter": "esbenp.prettier-vscode", 7 | "editor.formatOnSave": true, 8 | "editor.codeActionsOnSave": { 9 | "source.fixAll.eslint": true, 10 | "source.fixAll.markdownlint": true 11 | }, 12 | 13 | // Files 14 | "files.insertFinalNewline": true, 15 | "files.trimTrailingWhitespace": true, 16 | "files.exclude": { 17 | ".yarn/releases/**": true 18 | }, 19 | 20 | // JavasSript 21 | "javascript.format.enable": false, 22 | 23 | // TypeScript 24 | "typescript.format.enable": false, 25 | "typescript.tsdk": "node_modules/typescript/lib", 26 | "typescript.enablePromptUseWorkspaceTsdk": true, 27 | 28 | // Prettier 29 | "prettier.ignorePath": ".eslintignore", 30 | 31 | // Node Project 32 | "deno.enable": false, 33 | 34 | // Use PNPM 35 | "npm.packageManager": "pnpm", 36 | "eslint.packageManager": "pnpm", 37 | "prettier.packageManager": "pnpm" 38 | } 39 | -------------------------------------------------------------------------------- /packages/template-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template-package", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "A sample package from `remirror/template`", 6 | "keywords": [], 7 | "homepage": "https://github.com/remirror/template/tree/HEAD/packages/template-package", 8 | "repository": "https://github.com/remirror/template/tree/HEAD/packages/template-package", 9 | "license": "MIT", 10 | "contributors": [], 11 | "sideEffects": false, 12 | "main": "dist/template-package.cjs.js", 13 | "module": "dist/template-package.esm.js", 14 | "browser": { 15 | "./dist/template-package.cjs.js": "./dist/template-package.browser.cjs.js", 16 | "./dist/template-package.esm.js": "./dist/template-package.browser.esm.js" 17 | }, 18 | "types": "dist/template-package.cjs.d.ts", 19 | "files": [ 20 | "dist" 21 | ], 22 | "dependencies": { 23 | "@babel/runtime": "^7.12.13" 24 | }, 25 | "publishConfig": { 26 | "access": "public" 27 | }, 28 | "meta": { 29 | "sizeLimit": "5 KB" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /support/tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "module": "ESNext", 5 | "target": "ESNext", 6 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 7 | "jsx": "react-jsxdev", 8 | "types": ["node", "jest"], 9 | "moduleResolution": "node", 10 | "useDefineForClassFields": true, 11 | "sourceMap": true, 12 | "declaration": true, 13 | "pretty": true, 14 | "noEmit": true, 15 | "strict": true, 16 | "resolveJsonModule": true, 17 | "preserveWatchOutput": true, 18 | "noUncheckedIndexedAccess": true, 19 | 20 | "skipLibCheck": true, 21 | 22 | "experimentalDecorators": true, 23 | 24 | // Import rules 25 | "isolatedModules": true, 26 | "allowSyntheticDefaultImports": true, 27 | "esModuleInterop": true, 28 | 29 | // Stylistic, but faster than eslint 30 | "noUnusedLocals": true, 31 | "noUnusedParameters": true, 32 | "allowUnreachableCode": false, 33 | "forceConsistentCasingInFileNames": true, 34 | "noImplicitReturns": true 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /support/scripts/readme.md: -------------------------------------------------------------------------------- 1 | # Scripts 2 | 3 | This folder includes the custom node scripts. Used in the project. 4 | 5 | ## Files 6 | 7 | - `helpers/` - Some helper functions. 8 | - `check-pnpm.mjs` - Run on `preinstall` to check that `pnpm` is being used. This command will error with instructions if using a different package manager. 9 | - `check-styles.ts` - Check that the css styles are up to date in the project. 10 | - `generate-configs.ts` - Generate configuration files. At the moment this only creates the `.size-limit.json` files. `.size-limit.json` file for checking the file sizes. 11 | - `linaria.ts` - Generate the `css` files for the project. 12 | - `run-if-clean.ts` - Runs a command if the git repo is clean. 13 | - `run-if-config.ts` - Check the private project configuration to see if the command is supported. This is how precommit hooks can tell if they should run. 14 | - `run-if-mac.ts` - Run the provided command on mac only. 15 | - `run-if-not-ci.ts` - Run the command on CI only. 16 | - `symlink-root.mjs` - Symlink the config files to the root directory. 17 | -------------------------------------------------------------------------------- /support/scripts/run-if-publishable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Run the command when the repo is in a publishable state. 5 | */ 6 | 7 | import { exec, readChangesetState } from './helpers'; 8 | 9 | const [, , ...args] = process.argv; 10 | const command = args.join(' '); 11 | const FIFTY_MB_BUFFER_SIZE = 1024 * 1024 * 50; 12 | 13 | async function run() { 14 | const { changesets, preState } = await readChangesetState(); 15 | const shouldSkipCommand = changesets.length > 0; 16 | let tag = 'latest'; 17 | 18 | if (preState) { 19 | tag = preState.tag; 20 | } 21 | 22 | const publishCommand = `${command}:${tag}`; 23 | 24 | if (shouldSkipCommand) { 25 | console.log( 26 | `\u001B[33mUnmerged changesets found. Skipping publish command: '${publishCommand}'\u001B[0m`, 27 | ); 28 | 29 | return; 30 | } 31 | 32 | await exec(publishCommand, { 33 | // @ts-expect-error 34 | stdio: 'inherit', 35 | 36 | // Added so that publishing still succeeds on CI with large publish payloads. 37 | maxBuffer: FIFTY_MB_BUFFER_SIZE, 38 | }); 39 | } 40 | 41 | run(); 42 | -------------------------------------------------------------------------------- /website/src/types.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare module '@docusaurus/Link' { 4 | import { ComponentType, AllHTMLAttributes, ComponentType } from 'react'; 5 | 6 | export interface LinkProps extends AllHTMLAttributes { 7 | readonly isNavLink?: boolean; 8 | readonly to?: string; 9 | readonly href?: string; 10 | } 11 | 12 | const Link: ComponentType; 13 | 14 | export default Link; 15 | } 16 | 17 | declare module '@docusaurus/useBaseUrl' { 18 | export interface BaseUrlOptions { 19 | forcePrependBaseUrl: boolean; 20 | absolute: boolean; 21 | } 22 | 23 | export default function useBaseUrl(url: string, options?: Partial): string; 24 | } 25 | 26 | declare module '@docusaurus/useDocusaurusContext' { 27 | import { DocusaurusContext } from '@docusaurus/types'; 28 | 29 | export default function useDocusaurusContext(): DocusaurusContext; 30 | } 31 | 32 | declare module '@theme/Layout' { 33 | const Layout: ComponentType<{ title: string; description: string }>; 34 | export default Layout; 35 | } 36 | 37 | declare module '*.css'; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021, << TEMPLATE NAME >> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.134.0/containers/javascript-node 3 | { 4 | "name": "template", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick a Node version: 10, 12, 14 8 | "args": { "VARIANT": "14" } 9 | }, 10 | 11 | // Set *default* container specific settings.json values on container create. 12 | "settings": { 13 | "terminal.integrated.shell.linux": "/bin/zsh" 14 | }, 15 | 16 | // Add the IDs of extensions you want installed when the container is created. 17 | "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"], 18 | 19 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 20 | "forwardPorts": [3000, 6006, 3030], 21 | 22 | // Use 'postCreateCommand' to run commands after the container is created. 23 | "postCreateCommand": "pnpm install", 24 | 25 | // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. 26 | "remoteUser": "node" 27 | } 28 | -------------------------------------------------------------------------------- /support/jest/jest.framework.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference 2 | /// 3 | 4 | // Extended the available expect assertions. 5 | import 'jest-extended'; 6 | 7 | import diffHtml from 'diffable-html'; 8 | import { getSnapshotDiffSerializer, toMatchDiffSnapshot } from 'snapshot-diff'; 9 | 10 | // Add enhanced snapshot capabilities. 11 | expect.addSnapshotSerializer(getSnapshotDiffSerializer()); 12 | expect.extend({ toMatchDiffSnapshot }); 13 | 14 | /** 15 | * This is here to make `unhandledRejection` errors easier to debug 16 | */ 17 | process.on('unhandledRejection', (reason) => { 18 | console.error('REJECTION', reason); 19 | }); 20 | 21 | /** 22 | * Add a jest serializer for HTML content. Checks if the snapshot begins with `<` and assumes html. 23 | */ 24 | expect.addSnapshotSerializer({ 25 | test: (object) => { 26 | if (typeof object !== 'string') { 27 | return false; 28 | } 29 | 30 | const trimmed = object.trim(); 31 | return trimmed.length > 2 && trimmed.startsWith('<') && trimmed.endsWith('>'); 32 | }, 33 | serialize: (val: string) => { 34 | return diffHtml(val).trim(); 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /packages/template-package/readme.md: -------------------------------------------------------------------------------- 1 | # template-package 2 | 3 | > A sample package from `remirror/template` 4 | 5 |
6 | 7 | [![Version][version]][npm] [![Weekly Downloads][downloads-badge]][npm] [![Bundled size][size-badge]][size] [![Typed Codebase][typescript]](./src/index.ts) ![MIT License][license] 8 | 9 | [version]: https://flat.badgen.net/npm/v/template-package 10 | [npm]: https://npmjs.com/package/template-package 11 | [license]: https://flat.badgen.net/badge/license/MIT/purple 12 | [size]: https://bundlephobia.com/result?p=template-package 13 | [size-badge]: https://flat.badgen.net/bundlephobia/minzip/template-package 14 | [typescript]: https://flat.badgen.net/badge/icon/TypeScript?icon=typescript&label 15 | [downloads-badge]: https://badgen.net/npm/dw/template-package/red?icon=npm 16 | 17 |
18 | 19 | ## Installation 20 | 21 | ```bash 22 | # yarn 23 | yarn add template-package 24 | 25 | # pnpm 26 | pnpm add template-package 27 | 28 | # npm 29 | npm install template-package 30 | ``` 31 | 32 |
33 | 34 | ## Usage 35 | 36 | The following code creates an instance of this extension. 37 | 38 | ```ts 39 | import { printTemplate } from 'template-package'; 40 | 41 | printTemplate(); // => 'tEmPlATe' 42 | ``` 43 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "repository": "https://github.com/remirror/template/tree/HEAD/website", 6 | "scripts": { 7 | "build": "docusaurus build", 8 | "deploy": "docusaurus deploy", 9 | "docusaurus": "docusaurus", 10 | "serve": "docusaurus serve", 11 | "start": "docusaurus start", 12 | "swizzle": "docusaurus swizzle" 13 | }, 14 | "browserslist": { 15 | "production": [ 16 | ">0.2%", 17 | "not dead", 18 | "not op_mini all" 19 | ], 20 | "development": [ 21 | "last 1 chrome version", 22 | "last 1 firefox version", 23 | "last 1 safari version" 24 | ] 25 | }, 26 | "dependencies": { 27 | "@docusaurus/core": "2.0.0-alpha.70", 28 | "@docusaurus/module-type-aliases": "^2.0.0-alpha.70", 29 | "@docusaurus/preset-classic": "2.0.0-alpha.70", 30 | "@docusaurus/types": "^2.0.0-alpha.70", 31 | "@mdx-js/react": "^1.5.8", 32 | "@types/classnames": "^2.2.11", 33 | "@types/react": "^17.0.1", 34 | "@types/react-dom": "^17.0.0", 35 | "classnames": "^2.2.6", 36 | "react": "^17.0.1", 37 | "react-dom": "^17.0.1" 38 | }, 39 | "meta": { 40 | "tsconfigs": { 41 | "src": { 42 | "compilerOptions": { 43 | "allowJs": true 44 | } 45 | }, 46 | "./": { 47 | "include": [ 48 | "src" 49 | ] 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | env: 8 | PNPM_CACHE_FOLDER: .pnpm-store 9 | 10 | jobs: 11 | github-pages: 12 | timeout-minutes: 10 13 | runs-on: ubuntu-latest 14 | if: github.ref == 'refs/heads/main' || github.event.pull_request 15 | 16 | steps: 17 | - name: checkout code repository 18 | uses: actions/checkout@v2 19 | with: 20 | fetch-depth: 0 21 | lfs: true 22 | 23 | - name: setup caching 24 | uses: actions/cache@v2 25 | with: 26 | path: ${{ env.PNPM_CACHE_FOLDER }} 27 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 28 | restore-keys: | 29 | ${{ runner.os }}-pnpm- 30 | 31 | - name: setup node.js 32 | uses: actions/setup-node@v2-beta 33 | with: 34 | # Uses node 14 to allow nullish coalescing in `.js` files 35 | node-version: 14 36 | 37 | - name: install and audit 38 | uses: ./.github/actions/pnpm 39 | with: 40 | cache: ${{ env.PNPM_CACHE_FOLDER }} 41 | 42 | - name: build project 43 | run: pnpm build 44 | 45 | - name: build docs 46 | run: pnpm build:docs 47 | 48 | - name: deploy docs 🚀 49 | uses: JamesIves/github-pages-deploy-action@3.7.1 50 | with: 51 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 52 | BRANCH: gh-pages 53 | FOLDER: website/build 54 | CLEAN: true 55 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | ## Listens to the CI workflow and runs the publish command to main when applicable. 2 | 3 | name: publish 4 | 5 | on: 6 | workflow_run: 7 | workflows: [ci] 8 | branches: [main] 9 | types: [completed] 10 | 11 | env: 12 | PNPM_CACHE_FOLDER: .pnpm-store 13 | 14 | jobs: 15 | # Publish the project to npm 16 | npm: 17 | if: github.event.workflow_run.conclusion == 'success' 18 | timeout-minutes: 10 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: checkout code repository 23 | uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: setup caching 28 | uses: actions/cache@v2 29 | with: 30 | path: ${{ env.PNPM_CACHE_FOLDER }} 31 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 32 | restore-keys: | 33 | ${{ runner.os }}-pnpm- 34 | 35 | - name: setup node.js 36 | uses: actions/setup-node@v2-beta 37 | with: 38 | node-version: 14 39 | 40 | - name: install and audit 41 | uses: ./.github/actions/pnpm 42 | with: 43 | cache: ${{ env.PNPM_CACHE_FOLDER }} 44 | 45 | - name: build project 46 | run: pnpm build 47 | 48 | - name: publish npm release 49 | run: | 50 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > $HOME/.npmrc 51 | pnpm release 52 | rm $HOME/.npmrc 53 | env: 54 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 55 | -------------------------------------------------------------------------------- /support/base.babel.js: -------------------------------------------------------------------------------- 1 | const ignore = [ 2 | '**/__tests__', 3 | '**/__dts__', 4 | '**/__mocks__', 5 | '**/__fixtures__', 6 | '*.{test,spec}.{ts,tsx}', 7 | '**/*.d.ts', 8 | '*.d.ts', 9 | ]; 10 | 11 | const basePreset = []; 12 | 13 | const presets = [...basePreset, ['@babel/preset-env', {}]]; 14 | 15 | const testBabelPresetEnv = ['@babel/preset-env', { targets: { node: '14' } }]; 16 | const nonTestEnv = { ignore, presets }; 17 | 18 | module.exports = { 19 | presets: [...basePreset, testBabelPresetEnv], 20 | overrides: [ 21 | { 22 | test: /\.ts$/, 23 | plugins: [['@babel/plugin-transform-typescript', { isTSX: false }]], 24 | }, 25 | { 26 | test: /\.tsx$/, 27 | plugins: [['@babel/plugin-transform-typescript', { isTSX: true }]], 28 | }, 29 | { 30 | test: /\.[jt]sx?$/, 31 | plugins: [ 32 | ['@babel/plugin-proposal-class-properties'], 33 | ['@babel/plugin-proposal-private-methods'], 34 | ], 35 | }, 36 | ], 37 | plugins: [ 38 | 'babel-plugin-macros', 39 | ['@babel/plugin-transform-runtime', {}], 40 | ['@babel/plugin-transform-template-literals', {}, 'no-clash'], 41 | '@babel/plugin-proposal-object-rest-spread', 42 | '@babel/plugin-syntax-dynamic-import', 43 | '@babel/plugin-proposal-nullish-coalescing-operator', 44 | '@babel/plugin-proposal-optional-chaining', 45 | '@babel/plugin-proposal-numeric-separator', 46 | ['@babel/plugin-proposal-decorators', { legacy: true }], 47 | 'babel-plugin-annotate-pure-calls', 48 | 'babel-plugin-dev-expression', 49 | ], 50 | env: { production: nonTestEnv, development: nonTestEnv }, 51 | }; 52 | -------------------------------------------------------------------------------- /.github/workflows/version.yml: -------------------------------------------------------------------------------- 1 | name: version 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | env: 13 | PNPM_CACHE_FOLDER: .pnpm-store 14 | 15 | jobs: 16 | # Update package versions with changesets. 17 | version: 18 | timeout-minutes: 8 19 | runs-on: ubuntu-latest 20 | if: false == contains(github.ref, 'changeset') && github.repository == 'remirror/template' 21 | steps: 22 | - name: checkout code repository 23 | uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | 27 | - name: setup caching 28 | uses: actions/cache@v2 29 | with: 30 | path: ${{ env.PNPM_CACHE_FOLDER }} 31 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 32 | restore-keys: | 33 | ${{ runner.os }}-pnpm- 34 | 35 | - name: setup node.js 36 | uses: actions/setup-node@v2-beta 37 | with: 38 | node-version: 14 39 | 40 | - name: install and audit 41 | uses: ./.github/actions/pnpm 42 | with: 43 | cache: ${{ env.PNPM_CACHE_FOLDER }} 44 | 45 | - name: check versions are valid 46 | if: github.event.pull_request_target 47 | run: pnpm version:pr 48 | 49 | - name: create versions 50 | uses: changesets/action@master 51 | if: github.ref == 'refs/heads/main' 52 | with: 53 | version: pnpm version:ci 54 | commit: 'chore(changeset): version update' 55 | title: 'chore(changeset): version update' 56 | env: 57 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 58 | -------------------------------------------------------------------------------- /support/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "support", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "The support directory for remirror/template monorepo", 6 | "repository": "https://github.com/remirror/template/tree/HEAD/support", 7 | "dependencies": { 8 | "@babel/register": "^7.12.13", 9 | "@changesets/get-dependents-graph": "^1.2.0", 10 | "@changesets/pre": "^1.0.5", 11 | "@changesets/read": "^0.4.6", 12 | "@changesets/types": "^3.3.0", 13 | "@remirror/core-helpers": "^1.0.0-next.60", 14 | "@types/babel__core": "^7.1.12", 15 | "@types/lodash.isequal": "^4.5.5", 16 | "@types/minimist": "^1.2.1", 17 | "@types/rimraf": "^3.0.0", 18 | "@types/source-map-support": "^0.5.3", 19 | "camelcase-keys": "^6.2.2", 20 | "chalk": "^4.1.0", 21 | "cpy": "^8.1.1", 22 | "diffable-html": "^4.0.0", 23 | "globby": "^11.0.2", 24 | "jest-axe": "^4.1.0", 25 | "jest-diff": "^26.6.2", 26 | "lodash.isequal": "^4.5.0", 27 | "minimist": "^1.2.5", 28 | "p-limit": "^3.1.0", 29 | "pirates": "^4.0.1", 30 | "rimraf": "^3.0.2", 31 | "sort-keys": "^4.2.0", 32 | "source-map": "^0.7.3", 33 | "source-map-support": "^0.5.19", 34 | "tslog": "^3.1.1", 35 | "type-fest": "^0.20.2", 36 | "write-json-file": "^4.3.0" 37 | }, 38 | "meta": { 39 | "tsconfigs": { 40 | "src": false, 41 | "./": { 42 | "compilerOptions": { 43 | "types": [ 44 | "node" 45 | ], 46 | "allowJs": true, 47 | "noEmit": true 48 | }, 49 | "exclude": [ 50 | "templates", 51 | "root" 52 | ], 53 | "include": [ 54 | "./*.js", 55 | "jest", 56 | "root", 57 | "scripts" 58 | ] 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /support/scripts/changelog-dates.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import { promises as fs } from 'fs'; 3 | import path from 'path'; 4 | 5 | import { getAllDependencies } from './helpers'; 6 | 7 | const NAME = 'CHANGELOG.md'; 8 | 9 | /** 10 | * Read a file. 11 | * 12 | * @param {string} filePath - the filePath 13 | */ 14 | async function readFile(filePath: string) { 15 | try { 16 | return await fs.readFile(filePath, 'utf-8'); 17 | } catch { 18 | return; 19 | } 20 | } 21 | 22 | /** 23 | * Get the release date 24 | * 25 | * @param date - the date to use 26 | */ 27 | function getDate(date: Date = new Date()) { 28 | return `${date.getFullYear()}-${(date.getMonth() + 1) 29 | .toString() 30 | .padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; 31 | } 32 | 33 | /** 34 | * Check if the file has changed. 35 | * 36 | * @param filePath - the file path to check. 37 | */ 38 | function hasFileChanged(filePath: string) { 39 | const isUntracked = !execSync(`git ls-files ${filePath}`).toString().trim(); 40 | 41 | if (isUntracked) { 42 | return true; 43 | } 44 | 45 | return !!execSync(`git --no-pager diff --name-only ${filePath}`).toString().trim(); 46 | } 47 | 48 | /** 49 | * Add dates to all updated changelog files. 50 | */ 51 | async function run() { 52 | const packages = await getAllDependencies({ excludeDeprecated: false }); 53 | 54 | for (const pkg of packages) { 55 | const filePath = path.join(pkg.location, NAME); 56 | const contents = await readFile(filePath); 57 | 58 | if (!contents) { 59 | continue; 60 | } 61 | 62 | const updatedContent = contents.replace( 63 | /## (\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+[\dA-Za-z-]+)?$/m, 64 | `$&\n\n> ${getDate()}`, 65 | ); 66 | 67 | if (contents === updatedContent) { 68 | continue; 69 | } 70 | 71 | if (!hasFileChanged(filePath)) { 72 | continue; 73 | } 74 | 75 | await fs.writeFile(filePath, updatedContent); 76 | 77 | console.log(`\u001B[32mAdded date to changelog: ${filePath}`); 78 | } 79 | } 80 | 81 | run(); 82 | -------------------------------------------------------------------------------- /support/scripts/esbuild-register.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * This script registers `esbuild` as a pre transpilation step. 5 | * 6 | * Adapted from 7 | * https://github.com/egoist/esbuild-register/blob/0aa4077552b9f65ea1eb0734900d101c390cdaaa/src/node.ts#L1-L65 8 | */ 9 | 10 | import { transformSync } from 'esbuild'; 11 | import path from 'path'; 12 | import { addHook } from 'pirates'; 13 | import sourceMapSupport from 'source-map-support'; 14 | 15 | /** @type {{ [file: string]: import('source-map-support').UrlAndMap['map'] }} */ 16 | const map = {}; 17 | 18 | function installSourceMapSupport() { 19 | sourceMapSupport.install({ 20 | handleUncaughtExceptions: false, 21 | environment: 'node', 22 | retrieveSourceMap(file) { 23 | const mappedFile = map[file]; 24 | 25 | if (mappedFile) { 26 | return { 27 | url: file, 28 | map: mappedFile, 29 | }; 30 | } 31 | 32 | return null; 33 | }, 34 | }); 35 | } 36 | 37 | /** 38 | * @typedef {'.js' | '.jsx' | '.ts' |'.tsx'|'.mjs'} Extension 39 | * @typedef {'js' | 'jsx' | 'ts' |'tsx'} Loader 40 | * @typedef {Record} FileLoader 41 | */ 42 | 43 | /** @type {FileLoader } */ 44 | const FILE_LOADERS = { 45 | '.js': 'js', 46 | '.jsx': 'jsx', 47 | '.ts': 'ts', 48 | '.tsx': 'tsx', 49 | '.mjs': 'js', 50 | }; 51 | 52 | const DEFAULT_EXTENSIONS = Object.keys(FILE_LOADERS); 53 | 54 | /** @type {(filename: string) => Loader} */ 55 | function getLoader(filename) { 56 | return FILE_LOADERS[/** @type {Extension} */ (path.extname(filename))]; 57 | } 58 | 59 | /** 60 | * @param {string} code 61 | * @param {string} filename 62 | * 63 | * @returns {string} 64 | */ 65 | function compile(code, filename) { 66 | const { code: js, warnings, map: jsSourceMap } = transformSync(code, { 67 | sourcefile: filename, 68 | sourcemap: true, 69 | loader: getLoader(filename), 70 | target: 'es2017', 71 | }); 72 | 73 | map[filename] = jsSourceMap; 74 | 75 | if (warnings && warnings.length > 0) { 76 | for (const warning of warnings) { 77 | console.log(warning.location); 78 | console.log(warning.text); 79 | } 80 | } 81 | 82 | return js; 83 | } 84 | 85 | function register() { 86 | installSourceMapSupport(); 87 | addHook(compile, { 88 | exts: DEFAULT_EXTENSIONS, 89 | }); 90 | } 91 | 92 | register(); 93 | -------------------------------------------------------------------------------- /support/scripts/helpers/read-config.ts: -------------------------------------------------------------------------------- 1 | import { lstat, readFile } from 'fs/promises'; 2 | 3 | import DEFAULT_CONFIG from '../../.config.sample.json'; 4 | import { baseDir, log } from '.'; 5 | 6 | /** 7 | * Check if a file exists for the provide `filePath` the provided target. 8 | * 9 | * @param {string} filePath 10 | */ 11 | async function fileExists(filePath: string): Promise { 12 | try { 13 | const stat = await lstat(filePath); 14 | return stat.isFile(); 15 | } catch { 16 | return false; 17 | } 18 | } 19 | 20 | export interface HooksConfig { 21 | /** 22 | * Set to true to run the pre commit hook. 23 | */ 24 | preCommit: boolean; 25 | /** 26 | * Set to true to run the checks before pushing code. 27 | */ 28 | prePush: boolean; 29 | 30 | /** 31 | * Set to true to run `pnpm i` after every merge or checkout. Can be overkill. 32 | */ 33 | postMerge: boolean; 34 | 35 | /** 36 | * Run certain commands which are needed for the mac environment. 37 | */ 38 | macPostInstall: boolean; 39 | } 40 | 41 | export interface ConfigFile { 42 | /** 43 | * The hooks that should be run. 44 | */ 45 | hooks: HooksConfig; 46 | } 47 | 48 | const configFilePath = baseDir('.config.json'); 49 | 50 | /** 51 | * Read the JSON from the configuration file. 52 | */ 53 | function readJSON(str: string) { 54 | try { 55 | return JSON.parse(str); 56 | } catch (error) { 57 | log.error('Invalid JSON data in file .config.json', str); 58 | throw error; 59 | } 60 | } 61 | 62 | /** 63 | * Read the configuration file. 64 | */ 65 | export async function readConfigFile(): Promise { 66 | if (!fileExists(configFilePath)) { 67 | log.warn('No .config.json file'); 68 | return DEFAULT_CONFIG; 69 | } 70 | 71 | const fileContents = await readFile(configFilePath, { encoding: 'utf-8' }); 72 | return readJSON(fileContents); 73 | } 74 | 75 | /** 76 | * Read the property from the configuration file. 77 | */ 78 | export function readProperty( 79 | property: string, 80 | config: ConfigFile = DEFAULT_CONFIG, 81 | ): Return | undefined { 82 | let item: any = config; 83 | 84 | if (!property || !config) { 85 | return; 86 | } 87 | 88 | const keys = property.split('.'); 89 | 90 | for (const key of keys) { 91 | if (key in item) { 92 | item = item[key]; 93 | } else { 94 | return; 95 | } 96 | } 97 | 98 | return item; 99 | } 100 | -------------------------------------------------------------------------------- /support/root/readme.md: -------------------------------------------------------------------------------- 1 | # Config Files 2 | 3 | All files in this folder will be symlinked to the root of the repository in the npm `preinstall` hook. This is to remove clutter when browsing the code on GitHub or other online tools. 4 | 5 | This readme file is ignored though. 6 | 7 | ## Why 8 | 9 | Personally I find it intimidating when I open an interesting project only to be bombarded with a long list of files in the root directory. I think this is an elegant solution way of avoiding that problem while retaining the functionality provided by these files. 10 | 11 | By using symlinks we can continue editing and updating files in our usual way once the installation completes. Prior to installation the superfluous implementation is hidden. 12 | 13 | ## Content 14 | 15 | - `.changeset/` - A folder which contains the changeset information, responsible for releases and versioning the project. [`changesets`](https://github.com/atlassian/changesets) is an amazing project and I encourage you to take a look. 16 | - `.vscode/` - A folder which contains the vscode settings for the project. 17 | - `.eslintignore` - The patterns to ignore when running `eslint` on the project. 18 | - `.eslintrc.js` - The eslint rules for the whole project. 19 | - `.huskyrc` - The git hooks for the project which add a precommit and a prepush hook. You can learn more [here](https://github.com/typicode/husky). In order to make things easier for contributors, this file is ignored by default. To turn it on run the following command from the root directory. 20 | 21 | ```bash 22 | pnpm checks:enable 23 | ``` 24 | 25 | And to turn it back off again. 26 | 27 | ```bash 28 | pnpm checks:disable 29 | ``` 30 | 31 | - `.lintagedrc` - Runs on every commit (see previous point) to make sure files are linted, prettified and don't fail any tests. 32 | - `.npmrc` - Checked by [`pnpm`](https://pnpm.js.org/en/npmrc) and [`npm`](https://docs.npmjs.com/configuring-npm/npmrc.html) for configuration options. 33 | - `.prettierrc` - The configuration for [prettier](https://prettier.io/) which is responsible for formatting the project. 34 | - `.size-limit.json` - This file is generated by running `pnpm generate:config` in the root directory. It is possible 35 | - `babel.config.js` - The main babel config for the project. 36 | - `globals.d.ts` - The global types that should be available in the project. 37 | - `jest.config.js` - The jest configuration for running project wide testing. 38 | - `pnpmfile.js` - The pnpm file for adding hooks to the project. This is useful for patching packages, and setting resolutions for different 39 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'Remirror Template', 3 | tagline: 'Welcome to your templated docs', 4 | url: 'https://remirror.github.io/template', 5 | baseUrl: '/', 6 | onBrokenLinks: 'warn', 7 | onBrokenMarkdownLinks: 'warn', 8 | favicon: 'img/favicon.ico', 9 | organizationName: 'remirror', // Usually your GitHub org/user name. 10 | projectName: 'remirror', // Usually your repo name. 11 | themeConfig: { 12 | navbar: { 13 | title: 'Template', 14 | logo: { 15 | alt: 'Docs', 16 | src: 'img/logo.svg', 17 | }, 18 | items: [ 19 | { 20 | to: 'docs/contributing', 21 | activeBasePath: 'docs', 22 | label: 'Docs', 23 | position: 'left', 24 | }, 25 | { to: 'blog', label: 'Blog', position: 'left' }, 26 | { 27 | href: 'https://github.com/remirror/remirror', 28 | label: 'GitHub', 29 | position: 'right', 30 | }, 31 | ], 32 | }, 33 | footer: { 34 | style: 'dark', 35 | links: [ 36 | { 37 | title: 'Community', 38 | items: [ 39 | { 40 | label: 'Stack Overflow', 41 | href: 'https://stackoverflow.com/questions/tagged/remirror', 42 | }, 43 | { 44 | label: 'Discord', 45 | href: 'https://remirror.io/chat', 46 | }, 47 | { 48 | label: 'Twitter', 49 | href: 'https://twitter.com/remirrorio', 50 | }, 51 | ], 52 | }, 53 | { 54 | title: 'More', 55 | items: [ 56 | { 57 | label: 'Blog', 58 | to: 'blog/', 59 | }, 60 | { 61 | label: 'GitHub', 62 | href: 'https://github.com/remirror/remirror', 63 | }, 64 | ], 65 | }, 66 | ], 67 | copyright: `Copyright © ${new Date().getFullYear()} Remirror. Built with Docusaurus.`, 68 | }, 69 | }, 70 | presets: [ 71 | [ 72 | '@docusaurus/preset-classic', 73 | { 74 | docs: { 75 | path: '../docs', 76 | sidebarPath: require.resolve('./sidebars.js'), 77 | editUrl: 'https://github.com/remirror/remirror/edit/HEAD/docs/', 78 | }, 79 | blog: { 80 | showReadingTime: true, 81 | // Please change this to your repo. 82 | editUrl: 'https://github.com/remirror/remirror/edit/HEAD/website/blog/', 83 | }, 84 | }, 85 | ], 86 | ], 87 | }; 88 | -------------------------------------------------------------------------------- /support/scripts/changeset-forced-update.ts: -------------------------------------------------------------------------------- 1 | import { getDependentsGraph } from '@changesets/get-dependents-graph'; 2 | import { getPackages } from '@manypkg/get-packages'; 3 | import { promises as fs } from 'fs'; 4 | import writeJson from 'write-json-file'; 5 | 6 | import { 7 | baseDir, 8 | formatFiles, 9 | getAllDependencies, 10 | Package, 11 | readChangesetState, 12 | rm, 13 | } from './helpers'; 14 | 15 | const [, , ...args] = process.argv; 16 | const clean = args.includes('--clean'); 17 | 18 | const FORCED_FILE_NAME = 'pre-forced-update'; 19 | const FORCED_FILE_PATH = baseDir('.changeset', `${FORCED_FILE_NAME}.md`); 20 | const PRE_FILE_PATH = baseDir('.changeset', 'pre.json'); 21 | 22 | /** 23 | * Create a changeset file which implements all the forced updates. 24 | */ 25 | async function createForcedUpdateFile(packages: Package[]): Promise { 26 | const frontMatter = packages.map((pkg) => `'${pkg.name}': patch`); 27 | const fileContents = `--- 28 | ${frontMatter.join('\n')} 29 | --- 30 | 31 | Forced update in pre-release mode.`; 32 | 33 | await fs.writeFile(FORCED_FILE_PATH, fileContents); 34 | } 35 | 36 | /** 37 | * Run the command. 38 | */ 39 | async function run() { 40 | const { changesets, preState } = await readChangesetState(); 41 | 42 | // This should only be active when the release mode is `pre-release`. 43 | if (!preState) { 44 | return; 45 | } 46 | 47 | // Remove the generated file and the entry from the list of available 48 | // changesets. 49 | if (clean) { 50 | await rm(FORCED_FILE_PATH); 51 | await writeJson(PRE_FILE_PATH, { 52 | ...preState, 53 | changesets: preState.changesets.filter((name) => name !== FORCED_FILE_NAME), 54 | }); 55 | 56 | await formatFiles(PRE_FILE_PATH); 57 | return; 58 | } 59 | 60 | const nameList: string[] = []; 61 | const graph = getDependentsGraph(await getPackages(baseDir())); 62 | 63 | for (const changeset of changesets) { 64 | for (const release of changeset.releases) { 65 | nameList.push(release.name); 66 | const dependents = graph.get(release.name) ?? []; 67 | 68 | // Add all the dependent packages to the included names since they will 69 | // automatically be updated and don't need a forced update. 70 | nameList.push(release.name, ...dependents); 71 | } 72 | } 73 | 74 | const nameSet = new Set(...nameList); 75 | const packages = (await getAllDependencies()).filter( 76 | (pkg) => !pkg.private && !nameSet.has(pkg.name), 77 | ); 78 | 79 | if (packages.length === 0) { 80 | return; 81 | } 82 | 83 | await createForcedUpdateFile(packages); 84 | await formatFiles(FORCED_FILE_PATH); 85 | } 86 | 87 | run(); 88 | -------------------------------------------------------------------------------- /website/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link'; 2 | import useBaseUrl from '@docusaurus/useBaseUrl'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import Layout from '@theme/Layout'; 5 | import classnames from 'classnames'; 6 | import React from 'react'; 7 | 8 | import styles from './styles.module.css'; 9 | 10 | const features = [ 11 | { 12 | title: 'Easy to Use', 13 | imageUrl: 'img/undraw_docusaurus_mountain.svg', 14 | description: ( 15 | <> 16 | Docusaurus was designed from the ground up to be easily installed and used to get your 17 | website up and running quickly. 18 | 19 | ), 20 | }, 21 | { 22 | title: 'Focus on What Matters', 23 | imageUrl: 'img/undraw_docusaurus_tree.svg', 24 | description: ( 25 | <> 26 | Docusaurus lets you focus on your docs, and we'll do the chores. Go ahead and move your 27 | docs into the docs directory. 28 | 29 | ), 30 | }, 31 | { 32 | title: 'Powered by React', 33 | imageUrl: 'img/undraw_docusaurus_react.svg', 34 | description: ( 35 | <> 36 | Extend or customize your website layout by reusing React. Docusaurus can be extended while 37 | reusing the same header and footer. 38 | 39 | ), 40 | }, 41 | ]; 42 | 43 | function Feature({ imageUrl, title, description }: typeof features[number]) { 44 | const imgUrl = useBaseUrl(imageUrl); 45 | return ( 46 |
47 | {imgUrl && ( 48 |
49 | {title} 50 |
51 | )} 52 |

{title}

53 |

{description}

54 |
55 | ); 56 | } 57 | 58 | function Home() { 59 | const { siteConfig } = useDocusaurusContext(); 60 | 61 | return ( 62 | 66 |
67 |
68 |

{siteConfig.title}

69 |

{siteConfig.tagline}

70 |
71 | Get Started 72 |
73 |
74 |
75 | {features && features.length > 0 && ( 76 |
77 |
78 | {features.map((props, idx) => ( 79 | 80 | ))} 81 |
82 |
83 | )} 84 |
85 |
86 |
87 | ); 88 | } 89 | 90 | export default Home; 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/Node 2 | 3 | ### Node ### 4 | # Logs 5 | logs 6 | *.log 7 | pnpm-debug.log* 8 | pnpm-error.log* 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # Bower dependency directory (https://bower.io/) 33 | bower_components 34 | 35 | # node-waf configuration 36 | .lock-wscript 37 | 38 | # Compiled binary addons (https://nodejs.org/api/addons.html) 39 | build/Release 40 | 41 | # Dependency directories 42 | node_modules/ 43 | **/node_modules/ 44 | jspm_packages/ 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | 64 | # parcel-bundler cache (https://parceljs.org/) 65 | .cache 66 | 67 | # next.js build output 68 | .next 69 | 70 | # nuxt.js build output 71 | .nuxt 72 | 73 | # vuepress build output 74 | .vuepress/dist 75 | 76 | # Serverless directories 77 | .serverless 78 | 79 | .DS_Store 80 | # End of https://www.gitignore.io/api/Node 81 | 82 | # Build files 83 | dist 84 | dist-types 85 | 86 | # We are using pnpm 87 | .yarn/ 88 | .yarnrc 89 | yarn.lock 90 | **/yarn.lock 91 | package-lock.json 92 | **/package-lock.json 93 | 94 | 95 | # secrets 96 | .runtimeconfig.json 97 | secrets/crypt.key 98 | 99 | .jest 100 | 101 | .runtimeconfig.json 102 | 103 | tmp** 104 | **tmp** 105 | temp.* 106 | temp-* 107 | 108 | @example/ 109 | *.tar.gz 110 | 111 | # CI caching folder 112 | .ci 113 | .local.env 114 | 115 | yarn.lock 116 | **/yarn.lock 117 | 118 | ./**/.vscode 119 | 120 | 121 | /report.*.json 122 | 123 | .config.json 124 | 125 | key.json 126 | db.json 127 | secret.json 128 | 129 | .env 130 | *.env 131 | 132 | .out 133 | 134 | docs/public/** 135 | docs/.cache/ 136 | docs/.linaria-cache/ 137 | *.tsbuildinfo 138 | support/e2e/__failed-diffs__ 139 | cc-reporter 140 | 141 | # CI Pnpm cache 142 | .pnpm-store/ 143 | 144 | ## Ignore root files 145 | /.eslintignore 146 | /.eslintrc.js 147 | /.size-limit.json 148 | /.stylelintignore 149 | /.stylelintrc.json 150 | /babel.config.js 151 | /globals.d.ts 152 | /linaria.config.js 153 | /lingui.config.js 154 | /jest.config.js 155 | /.prettierrc.js 156 | /.huskyrc 157 | /.lintstagedrc 158 | /tsconfig.json 159 | /tsconfig.dev.json 160 | /tsconfig.docs.json 161 | /typedoc.json 162 | /.markdownlint.json 163 | -------------------------------------------------------------------------------- /support/scripts/symlink-root.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * This is left as a JavaScript file since it is called in the `preinstall` hook 5 | * before any packages have been installed. It only has access to the `node` 6 | * internals. 7 | */ 8 | 9 | import { lstatSync, readdirSync, readlinkSync, rmdirSync, symlinkSync, unlinkSync } from 'fs'; 10 | import { dirname, join, resolve } from 'path'; 11 | import { fileURLToPath } from 'url'; 12 | 13 | const __dirname = dirname(fileURLToPath(import.meta.url)); 14 | 15 | const targets = readdirSync(baseDir('support', 'root')) 16 | // Exclude the `readme.md` file from being symlinked. 17 | .filter((filename) => !filename.endsWith('readme.md')) 18 | .map((filename) => ({ 19 | original: baseDir('support', 'root', filename), 20 | target: baseDir(filename), 21 | })); 22 | 23 | /** 24 | * Resolve a path relative to the base directory. 25 | * 26 | * @param {string[]} paths 27 | */ 28 | function baseDir(...paths) { 29 | return resolve(__dirname, '../..', ...paths); 30 | } 31 | 32 | /** 33 | * Safely get the stats for a file. 34 | * 35 | * @param {string} target 36 | */ 37 | function getFileStatSync(target) { 38 | try { 39 | return lstatSync(target); 40 | } catch { 41 | return; 42 | } 43 | } 44 | 45 | /** 46 | * Delete a file or folder recursively. 47 | * 48 | * @param {string} path 49 | * 50 | * @returns {void} 51 | */ 52 | function deletePath(path) { 53 | const stat = getFileStatSync(path); 54 | 55 | if (!stat) { 56 | return; 57 | } 58 | 59 | if (stat.isFile()) { 60 | console.log('deleting file', path); 61 | unlinkSync(path); 62 | } 63 | 64 | if (!stat.isDirectory()) { 65 | return; 66 | } 67 | 68 | // Delete all nested paths 69 | for (const file of readdirSync(path)) { 70 | deletePath(join(path, file)); 71 | } 72 | 73 | // Delete the directory 74 | rmdirSync(path); 75 | } 76 | 77 | /** 78 | * Check that the path is linked to the target. 79 | * 80 | * @param {string} path 81 | * @param {string} target 82 | */ 83 | function isLinkedTo(path, target) { 84 | try { 85 | const checkTarget = readlinkSync(path); 86 | return checkTarget === target; 87 | } catch { 88 | return false; 89 | } 90 | } 91 | 92 | for (const { original, target } of targets) { 93 | const targetStat = getFileStatSync(target); 94 | 95 | // Nothing to do since the path is linked correctly. 96 | if (isLinkedTo(target, original)) { 97 | continue; 98 | } 99 | 100 | // The file or directory exists but is not symlinked correctly. It should be 101 | // deleted. 102 | if (targetStat) { 103 | console.log('deleting path', target); 104 | deletePath(target); 105 | } 106 | 107 | symlinkSync(original, target); 108 | } 109 | 110 | console.log( 111 | '\n\u001B[32mSuccessfully symlinked the `support/root` files to the root directory.\u001B[0m\n', 112 | ); 113 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | /** 4 | * @param {import('@babel/core').ConfigAPI} api 5 | * @returns {import('@babel/core').TransformOptions} 6 | */ 7 | function babelConfig(api) { 8 | const caller = api.caller((caller) => 9 | caller === null || caller === void 0 ? void 0 : caller.name, 10 | ); 11 | const isServer = caller === 'server'; 12 | const absoluteRuntimePath = path.dirname(require.resolve('@babel/runtime/package.json')); 13 | 14 | return { 15 | overrides: [ 16 | { 17 | test: /\.ts$/, 18 | plugins: [[require.resolve('@babel/plugin-transform-typescript'), { isTSX: false }]], 19 | }, 20 | { 21 | test: /\.tsx$/, 22 | plugins: [[require.resolve('@babel/plugin-transform-typescript'), { isTSX: true }]], 23 | }, 24 | { 25 | test: /\.[jt]sx?$/, 26 | plugins: [ 27 | require.resolve('babel-plugin-macros'), 28 | 29 | // Polyfills the runtime needed for async/await, generators, and friends 30 | // https://babeljs.io/docs/en/babel-plugin-transform-runtime 31 | [ 32 | require.resolve('@babel/plugin-transform-runtime'), 33 | { 34 | corejs: false, 35 | helpers: true, 36 | // By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0, better to 37 | // explicitly specify the version so that it can reuse the helper better 38 | // See https://github.com/babel/babel/issues/10261 39 | version: require('@babel/runtime/package.json').version, 40 | regenerator: true, 41 | useESModules: true, 42 | // Undocumented option that lets us encapsulate our runtime, ensuring 43 | // the correct version is used 44 | // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42 45 | absoluteRuntime: absoluteRuntimePath, 46 | }, 47 | ], 48 | 49 | // Adds syntax support for import() 50 | isServer 51 | ? require.resolve('babel-plugin-dynamic-import-node') 52 | : require.resolve('@babel/plugin-syntax-dynamic-import'), 53 | 54 | require.resolve('@babel/plugin-transform-template-literals'), 55 | require.resolve('@babel/plugin-proposal-object-rest-spread'), 56 | require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'), 57 | require.resolve('@babel/plugin-proposal-optional-chaining'), 58 | require.resolve('@babel/plugin-proposal-numeric-separator'), 59 | [require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }], 60 | [require.resolve('@babel/plugin-proposal-class-properties')], 61 | [require.resolve('@babel/plugin-proposal-private-methods')], 62 | ], 63 | }, 64 | ], 65 | presets: [ 66 | isServer 67 | ? [ 68 | require.resolve('@babel/preset-env'), 69 | { 70 | targets: { 71 | node: 'current', 72 | }, 73 | }, 74 | ] 75 | : [ 76 | require.resolve('@babel/preset-env'), 77 | { 78 | useBuiltIns: 'entry', 79 | loose: true, 80 | corejs: { version: '3.6', proposals: true }, 81 | // Do not transform modules to CJS 82 | modules: false, 83 | // Exclude transforms that make all code slower 84 | exclude: ['transform-typeof-symbol'], 85 | }, 86 | ], 87 | require.resolve('@babel/preset-react'), 88 | ], 89 | plugins: [], 90 | }; 91 | } 92 | 93 | module.exports = babelConfig; 94 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | svg logo from undraw.co 4 | 5 |

6 | 7 |

8 | Add your motivational tagline here. 9 |

10 | 11 |
12 | 13 |

14 | Getting Started · 15 | Why? · 16 | Documentation · 17 | Contributing 18 |

19 | 20 |
21 | 22 |

23 | 24 | Continuous integration badge for github actions 25 | 26 |

27 | 28 |
29 | 30 | ## Getting Started 31 | 32 | Use the following steps when first using this template. 33 | 34 | - Find and replace `remirror/template` with `user/repo` across the whole project. 35 | - Replace `<< TEMPLATE NAME >>` in the `LICENSE` file with the name of your choosing. 36 | - Replace the template package in the packages folder with a package of your choosing. 37 | - **_OPTIONAL_**: For automatic publishing add your npm token to to your [github repo secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) with the name `NPM_TOKEN`. 38 | 39 |
40 | 41 | ## Why 42 | 43 | I've created this template primarily for my work with remirror, to prevent from constantly reinventing the wheel when starting a new project. I've often had ideas and then delayed because the pain of starting from scratch is too high. This toolkit hopefully helps to reduce the friction. 44 | 45 | This template repo comes with the following tools: 46 | 47 | - [`pnpm`](https://pnpm.js.org/) monorepo. 48 | - [`preconstruct`](https://preconstruct.tools/) - Automated builds and great support for JS tooling. 49 | - [`TypeScript`](https://www.typescriptlang.org/) - For typesafe code, great editor support and simpler refactoring. 50 | - [`eslint`](https://eslint.org/) - for code linting. 51 | - [`prettier`](https://prettier.io/) - for code formatting. 52 | - [`babel`](https://babeljs.io/) - used by preconstruct for the compilation of code and macros. 53 | - [`vscode`](https://code.visualstudio.com/) - as the preferred editor integration with recommended plugins. 54 | - [`codespaces`](https://github.com/features/codespaces) - with a dev container which is ready to use. You can launch this codebase as it is or configure as needed for your project. 55 | - [`changesets`](https://github.com/atlassian/changesets) - for automating releases to GitHub and NPM. 56 | - [`GitHub Actions`](https://github.com/features/actions) - as the primary continuous integration (deployment) tool. 57 | - [`husky`](https://github.com/typicode/husky/tree/v4.3.7) - for git hooks. 58 | - [`lint-staged`](https://github.com/okonet/lint-staged) - for automated precommit checks. 59 | - Minimal files at the top level via symlinks to a directory in `support/root`. 60 | 61 |
62 | 63 | ## Contributing 64 | 65 | Please read our [contribution guide] for details on our code of conduct, and the process for submitting pull requests. It also outlines the project structure so you can find help when navigating your way around the codebase. 66 | 67 | In addition each folder in this codebase a readme describing why it exists. 68 | 69 | You might also notice there are surprisingly few files in the root directory of this project. All the configuration files have been moved to the `support/root` directory and are symlinked to the root directory in a `preinstall` hook. For more information take a look at [folder](support/root) and [readme](support/root/readme.md). 70 | 71 |
72 | 73 | ## Versioning 74 | 75 | This project uses [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/remirror/template/tags). 76 | 77 |
78 | 79 | ## License 80 | 81 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 82 | 83 | [contribution guide]: docs/contributing 84 | [typescript]: https://github.com/microsoft/Typescript 85 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | push: 8 | branches: 9 | - main 10 | - 'changeset-release/main' 11 | 12 | pull_request: 13 | branches: 14 | - main 15 | 16 | env: 17 | PNPM_CACHE_FOLDER: .pnpm-store 18 | 19 | jobs: 20 | # Lint the project 21 | lint: 22 | timeout-minutes: 15 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: checkout code repository 26 | uses: actions/checkout@v2 27 | with: 28 | fetch-depth: 0 29 | 30 | - name: setup caching 31 | uses: actions/cache@v2 32 | with: 33 | path: ${{ env.PNPM_CACHE_FOLDER }} 34 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 35 | restore-keys: | 36 | ${{ runner.os }}-pnpm- 37 | 38 | - name: setup node.js 39 | uses: actions/setup-node@v2-beta 40 | with: 41 | node-version: 14 42 | 43 | - name: install and audit 44 | uses: ./.github/actions/pnpm 45 | with: 46 | cache: ${{ env.PNPM_CACHE_FOLDER }} 47 | 48 | - name: check TS / JS files 49 | run: pnpm lint:es 50 | 51 | - name: check markdown code blocks 52 | run: pnpm lint:md 53 | 54 | - name: check formatting 55 | run: pnpm lint:prettier 56 | 57 | - name: check repo and versions 58 | run: pnpm lint:repo 59 | 60 | # Typecheck the project 61 | typecheck: 62 | timeout-minutes: 15 63 | runs-on: ubuntu-latest 64 | steps: 65 | - name: checkout code repository 66 | uses: actions/checkout@v2 67 | with: 68 | fetch-depth: 0 69 | 70 | - name: setup caching 71 | uses: actions/cache@v2 72 | with: 73 | path: ${{ env.PNPM_CACHE_FOLDER }} 74 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 75 | restore-keys: | 76 | ${{ runner.os }}-pnpm- 77 | 78 | - name: setup node.js 79 | uses: actions/setup-node@v2-beta 80 | with: 81 | node-version: 14 82 | 83 | - name: install and audit 84 | uses: ./.github/actions/pnpm 85 | with: 86 | cache: ${{ env.PNPM_CACHE_FOLDER }} 87 | 88 | - name: typecheck project 89 | run: pnpm typecheck 90 | 91 | # Unit test and update coverage report 92 | unit-test: 93 | timeout-minutes: 15 94 | runs-on: ubuntu-latest 95 | steps: 96 | - name: checkout code repository 97 | uses: actions/checkout@v2 98 | with: 99 | fetch-depth: 0 100 | 101 | - name: setup caching 102 | uses: actions/cache@v2 103 | with: 104 | path: ${{ env.PNPM_CACHE_FOLDER }} 105 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 106 | restore-keys: | 107 | ${{ runner.os }}-pnpm- 108 | 109 | - name: setup node.js 110 | uses: actions/setup-node@v2-beta 111 | with: 112 | node-version: 14 113 | 114 | - name: install and audit 115 | uses: ./.github/actions/pnpm 116 | with: 117 | cache: ${{ env.PNPM_CACHE_FOLDER }} 118 | 119 | - name: run unit tests 120 | run: pnpm test 121 | 122 | # Build the project and run tests on built files. 123 | build-test: 124 | timeout-minutes: 15 125 | runs-on: ubuntu-latest 126 | strategy: 127 | matrix: 128 | node-version: [14.x, 15.x] 129 | fail-fast: false 130 | 131 | steps: 132 | - name: checkout code repository 133 | uses: actions/checkout@v2 134 | with: 135 | fetch-depth: 0 136 | 137 | - name: setup caching 138 | uses: actions/cache@v2 139 | with: 140 | path: ${{ env.PNPM_CACHE_FOLDER }} 141 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 142 | restore-keys: | 143 | ${{ runner.os }}-pnpm- 144 | 145 | - name: setup node.js 146 | uses: actions/setup-node@v2-beta 147 | with: 148 | node-version: ${{ matrix.node-version }} 149 | 150 | - name: install and audit 151 | uses: ./.github/actions/pnpm 152 | with: 153 | cache: ${{ env.PNPM_CACHE_FOLDER }} 154 | 155 | - name: build project 156 | run: pnpm build 157 | 158 | - name: run unit tests 159 | run: pnpm test:build 160 | 161 | # Check that package sizes are within their boundaries 162 | size-check: 163 | timeout-minutes: 15 164 | runs-on: ubuntu-latest 165 | steps: 166 | - name: checkout code repository 167 | uses: actions/checkout@v2 168 | with: 169 | fetch-depth: 0 170 | 171 | - name: setup caching 172 | uses: actions/cache@v2 173 | with: 174 | path: ${{ env.PNPM_CACHE_FOLDER }} 175 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 176 | restore-keys: | 177 | ${{ runner.os }}-pnpm- 178 | 179 | - name: setup node.js 180 | uses: actions/setup-node@v2-beta 181 | with: 182 | node-version: 14 183 | 184 | - name: install and audit 185 | uses: ./.github/actions/pnpm 186 | with: 187 | cache: ${{ env.PNPM_CACHE_FOLDER }} 188 | 189 | - name: build project 190 | run: pnpm build 191 | 192 | - name: check sizes 193 | run: pnpm size 194 | -------------------------------------------------------------------------------- /website/blog/2020-04-14-large-blog-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: A large blog post 3 | author: Fanny Vieira 4 | authorTitle: Maintainer of Docusaurus 5 | authorURL: https://github.com/fanny 6 | authorImageURL: https://github.com/fanny.png 7 | authorTwitter: fannyvieiira 8 | tags: [blog, docusaurus] 9 | --- 10 | 11 | Hello, this is an example 12 | 13 | 14 | 15 | ### Section 1 16 | 17 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean 18 | massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec 19 | quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. 20 | Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, 21 | imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. 22 | Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, 23 | porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, 24 | feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean 25 | imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam 26 | rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet 27 | adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. 28 | Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam 29 | quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit amet 30 | nibh. Donec sodales sagittis magna. 31 | 32 | ### Section 2 33 | 34 | Sed consequat, leo eget bibendum sodales, augue velit cursus nunc, quis gravida magna mi a libero. 35 | Fusce vulputate eleifend sapien. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, 36 | metus. Nullam accumsan lorem in dui. Cras ultricies mi eu turpis hendrerit fringilla. Vestibulum 37 | ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; In ac dui quis mi 38 | consectetuer lacinia. Nam pretium turpis et arcu. Duis arcu tortor, suscipit eget, imperdiet nec, 39 | imperdiet iaculis, ipsum. Sed aliquam ultrices mauris. Integer ante arcu, accumsan a, consectetuer 40 | eget, posuere ut, mauris. Praesent adipiscing. Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy 41 | metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut eros et nisl sagittis vestibulum. 42 | Nullam nulla eros, ultricies sit amet, nonummy id, imperdiet feugiat, pede. Sed lectus. Donec mollis 43 | hendrerit risus. Phasellus nec sem in justo pellentesque facilisis. Etiam imperdiet imperdiet orci. 44 | Nunc nec neque. Phasellus leo dolor, tempus non, auctor et, hendrerit quis, nisi. Curabitur ligula 45 | sapien, tincidunt non, euismod vitae, posuere imperdiet, leo. Maecenas malesuada. Praesent congue 46 | erat at massa. Sed cursus turpis vitae tortor. Donec posuere vulputate arcu. Phasellus accumsan 47 | cursus velit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia 48 | Curae; Sed aliquam, nisi quis porttitor congue, elit erat euismod orci, ac placerat dolor lectus 49 | quis orci. Phasellus consectetuer vestibulum elit. Aenean tellus metus, bibendum sed, posuere ac, 50 | mattis non, nunc. Vestibulum fringilla pede sit amet augue. In turpis. Pellentesque posuere. 51 | Praesent turpis. Aenean posuere, tortor sed cursus feugiat, nunc augue blandit nunc, eu sollicitudin 52 | urna dolor sagittis lacus. Donec elit libero, sodales nec, volutpat a, suscipit non, turpis. Nullam 53 | sagittis. Suspendisse pulvinar, augue ac venenatis condimentum, sem libero volutpat nibh, nec 54 | pellentesque velit pede quis nunc. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices 55 | posuere cubilia Curae; Fusce id purus. Ut varius tincidunt libero. Phasellus dolor. Maecenas 56 | vestibulum mollis diam. Pellentesque ut neque. Pellentesque habitant morbi tristique senectus et 57 | netus et malesuada fames ac turpis egestas. In dui magna, posuere eget, vestibulum et, tempor 58 | auctor, justo. In ac felis quis tortor malesuada pretium. Pellentesque auctor neque nec urna. Proin 59 | sapien ipsum, porta a, auctor quis, euismod ut, mi. Aenean viverra rhoncus pede. Pellentesque 60 | habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Ut non enim 61 | eleifend felis pretium feugiat. Vivamus quis mi. Phasellus a est. 62 | 63 | ### Section 3 64 | 65 | Phasellus magna. In hac habitasse platea dictumst. Curabitur at lacus ac velit ornare lobortis. 66 | Curabitur a felis in nunc fringilla tristique. Morbi mattis ullamcorper velit. Phasellus gravida 67 | semper nisi. Nullam vel sem. Pellentesque libero tortor, tincidunt et, tincidunt eget, semper nec, 68 | quam. Sed hendrerit. Morbi ac felis. Nunc egestas, augue at pellentesque laoreet, felis eros 69 | vehicula leo, at malesuada velit leo quis pede. Donec interdum, metus et hendrerit aliquet, dolor 70 | diam sagittis ligula, eget egestas libero turpis vel mi. Nunc nulla. Fusce risus nisl, viverra et, 71 | tempor et, pretium in, sapien. Donec venenatis vulputate lorem. Morbi nec metus. Phasellus blandit 72 | leo ut odio. Maecenas ullamcorper, dui et placerat feugiat, eros pede varius nisi, condimentum 73 | viverra felis nunc et lorem. Sed magna purus, fermentum eu, tincidunt eu, varius ut, felis. In 74 | auctor lobortis lacus. Quisque libero metus, condimentum nec, tempor a, commodo mollis, magna. 75 | Vestibulum ullamcorper mauris at ligula. Fusce fermentum. Nullam cursus lacinia erat. Praesent 76 | blandit laoreet nibh. Fusce convallis metus id felis luctus adipiscing. Pellentesque egestas, neque 77 | sit amet convallis pulvinar, justo nulla eleifend augue, ac auctor orci leo non est. Quisque id mi. 78 | Ut tincidunt tincidunt erat. Etiam feugiat lorem non metus. Vestibulum dapibus nunc ac augue. 79 | Curabitur vestibulum aliquam leo. Praesent egestas neque eu enim. In hac habitasse platea dictumst. 80 | Fusce a quam. Etiam ut purus mattis mauris 81 | -------------------------------------------------------------------------------- /website/static/img/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /support/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "homepage": "https://github.com/remirror/template", 5 | "repository": "https://github.com/remirror/template", 6 | "scripts": { 7 | "audit": "pnpm audit --audit-level high", 8 | "build": "preconstruct build", 9 | "build:dev": "preconstruct dev", 10 | "build:docs": "run-s docs:prod", 11 | "changeset": "changeset", 12 | "check:pnpm": "node support/scripts/check-pnpm.mjs", 13 | "checks": "run-s lint typecheck test", 14 | "checks:ci": "run-s lint typecheck", 15 | "checks:disable": "rimraf ./.config.json", 16 | "checks:enable": "cpy support/.config.sample.json ./ --rename=\".config.json\"", 17 | "checks:fix": "run-s -c fix typecheck test", 18 | "checks:release": "run-s checks build", 19 | "clean": "pnpm if-clean git clean -- -fdx --exclude=.config.json --exclude=node_modules --exclude=**/node_modules", 20 | "clean:all": "git clean -fdX --exclude='.config.json'", 21 | "clean:modules": "git clean -fdX packages support", 22 | "docs:dev": "cd website && pnpm start", 23 | "docs:prod": "cd website && pnpm build", 24 | "docs:redirects": "cpy ./website/_redirects ./website/build/_redirects", 25 | "fix": "run-s -c fix:\\*", 26 | "fix:build": "preconstruct fix", 27 | "fix:config": "pnpm generate:ts", 28 | "fix:es": "pnpm lint:es -- --fix", 29 | "fix:prettier": "pnpm run:prettier -- --write", 30 | "fix:repo": "manypkg fix", 31 | "fix:size": "pnpm generate:size", 32 | "generate:size": "pnpm ts support/scripts/generate-configs.ts -- --size", 33 | "generate:ts": "pnpm ts support/scripts/generate-configs.ts -- --ts-packages", 34 | "if-clean": "pnpm ts support/scripts/run-if-clean.ts", 35 | "if-config": "pnpm ts support/scripts/run-if-config.ts", 36 | "if-not-ci": "pnpm ts support/scripts/run-if-not-ci.ts", 37 | "if-publishable": "pnpm ts support/scripts/run-if-publishable.ts", 38 | "preinstall": "pnpm symlink:root && pnpm check:pnpm", 39 | "postinstall": "run-s build:dev", 40 | "is-logged-in": "npm whoami", 41 | "lint": "run-s lint:\\*", 42 | "lint:build": "preconstruct validate", 43 | "lint:es": "FULL_ESLINT_CHECK=true eslint -f codeframe --ext=.tsx,.ts,.js .", 44 | "lint:md": "eslint -f codeframe --ignore-pattern='*.js' --ignore-pattern='*.ts' --ignore-pattern='*.tsx' .", 45 | "lint:prettier": "pnpm run:prettier -- --check", 46 | "lint:repo": "manypkg check", 47 | "refresh": "pnpm clean:all; pnpm symlink:root; pnpm install -r;", 48 | "prerelease": "pnpm if-not-ci run-s checks:release", 49 | "release": "pnpm if-publishable run-s release", 50 | "release:latest": "pnpm publish -r", 51 | "reset": "pnpm clean:all; rm pnpm-lock.yaml; pnpm symlink:root; pnpm i -r;", 52 | "run:prettier": "prettier --ignore-path .eslintignore \"**/*.{js,jsx,ts,tsx,md,mdx,json,html,css,yml,yaml,graphql}\"", 53 | "size": "size-limit", 54 | "storybook": "manypkg run support/storybook storybook", 55 | "symlink:root": "node support/scripts/symlink-root.mjs", 56 | "test": "jest --verbose", 57 | "test:build": "TEST_BUILD=true jest --verbose --coverage=false", 58 | "test:watch": "jest --watch --verbose=false --coverage=false", 59 | "ts": "node -r esm -r ./support/scripts/babel-register.js", 60 | "typecheck": "tsc -b ./tsconfig.json", 61 | "typecheck:force": "tsc -b --force", 62 | "update:deps": "pnpm update --latest --recursive -i", 63 | "update:workspace": "pnpm up -r --workspace", 64 | "preversion:changeset": "pnpm ts support/scripts/changeset-forced-update.ts", 65 | "version:changeset": "changeset version", 66 | "postversion:changeset": "pnpm ts support/scripts/changeset-forced-update.ts -- --clean", 67 | "version:ci": "run-s version:changeset version:date version:repo fix:prettier version:lockfile", 68 | "version:date": "pnpm ts support/scripts/changelog-dates.ts", 69 | "version:lockfile": "CI= pnpm install --frozen-lockfile=false --lockfile-only", 70 | "version:pr": "pnpm ts support/scripts/enable-pr-changeset.ts", 71 | "version:repo": "CI= run-s fix:repo update:workspace", 72 | "watch": "preconstruct watch # not recommended" 73 | }, 74 | "browserslist": [ 75 | "since 2018" 76 | ], 77 | "dependencies": { 78 | "@babel/core": "^7.12.13", 79 | "@babel/parser": "^7.12.15", 80 | "@babel/plugin-proposal-class-properties": "^7.12.13", 81 | "@babel/plugin-proposal-decorators": "^7.12.13", 82 | "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.13", 83 | "@babel/plugin-proposal-numeric-separator": "^7.12.13", 84 | "@babel/plugin-proposal-object-rest-spread": "^7.12.13", 85 | "@babel/plugin-proposal-optional-chaining": "^7.12.13", 86 | "@babel/plugin-proposal-private-methods": "^7.12.13", 87 | "@babel/plugin-syntax-dynamic-import": "^7.8.3", 88 | "@babel/plugin-transform-runtime": "^7.12.15", 89 | "@babel/plugin-transform-template-literals": "^7.12.13", 90 | "@babel/plugin-transform-typescript": "^7.12.13", 91 | "@babel/preset-env": "^7.12.13", 92 | "@babel/preset-react": "^7.12.13", 93 | "@babel/runtime": "^7.12.13", 94 | "@changesets/cli": "^2.14.1", 95 | "@jest/types": "^26.6.2", 96 | "@manypkg/cli": "^0.17.0", 97 | "@manypkg/get-packages": "^1.1.1", 98 | "@preconstruct/cli": "^2.0.3", 99 | "@size-limit/preset-big-lib": "^4.9.2", 100 | "@testing-library/jest-dom": "^5.11.9", 101 | "@types/eslint": "^7.2.6", 102 | "@types/jest": "^26.0.20", 103 | "@types/jest-axe": "^3.5.1", 104 | "@types/node": "^14.14.25", 105 | "@types/testing-library__jest-dom": "^5.9.5", 106 | "@typescript-eslint/eslint-plugin": "^4.15.0", 107 | "@typescript-eslint/parser": "^4.15.0", 108 | "babel-jest": "^26.6.3", 109 | "babel-plugin-annotate-pure-calls": "^0.4.0", 110 | "babel-plugin-dev-expression": "^0.2.2", 111 | "babel-plugin-macros": "^3.0.1", 112 | "cpy-cli": "^3.1.1", 113 | "esbuild": "^0.8.43", 114 | "eslint": "^7.19.0", 115 | "eslint-config-prettier": "^7.2.0", 116 | "eslint-plugin-eslint-comments": "^3.2.0", 117 | "eslint-plugin-graphql": "^4.0.0", 118 | "eslint-plugin-import": "^2.22.1", 119 | "eslint-plugin-jest": "^24.1.3", 120 | "eslint-plugin-jest-formatting": "^2.0.1", 121 | "eslint-plugin-jsx-a11y": "^6.4.1", 122 | "eslint-plugin-markdown": "^2.0.0-rc.0", 123 | "eslint-plugin-promise": "^4.2.1", 124 | "eslint-plugin-simple-import-sort": "^7.0.0", 125 | "eslint-plugin-unicorn": "^27.0.0", 126 | "esm": "^3.2.25", 127 | "husky": "^5.0.9", 128 | "jest": "^26.6.3", 129 | "jest-circus": "^26.6.3", 130 | "jest-extended": "^0.11.5", 131 | "jest-watch-typeahead": "^0.6.1", 132 | "lint-staged": "^10.5.4", 133 | "npm-run-all": "^4.1.5", 134 | "prettier": "^2.2.1", 135 | "prettier-plugin-packagejson": "^2.2.9", 136 | "rimraf": "^3.0.2", 137 | "size-limit": "^4.9.2", 138 | "snapshot-diff": "^0.8.1", 139 | "typescript": "^4.1.3", 140 | "typescript-snapshots-plugin": "^1.7.0" 141 | }, 142 | "engines": { 143 | "node": ">=14", 144 | "pnpm": "^5.15.0" 145 | }, 146 | "manypkg": { 147 | "defaultBranch": "HEAD" 148 | }, 149 | "preconstruct": { 150 | "packages": [ 151 | "packages/*", 152 | "packages/@*/*" 153 | ] 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /support/scripts/helpers/index.ts: -------------------------------------------------------------------------------- 1 | import { readPreState } from '@changesets/pre'; 2 | import readChangesets from '@changesets/read'; 3 | import { NewChangeset, PreState } from '@changesets/types'; 4 | import { getPackages } from '@manypkg/get-packages'; 5 | import assert from 'assert'; 6 | import camelCaseKeys from 'camelcase-keys'; 7 | import chalk from 'chalk'; 8 | import { exec as _exec } from 'child_process'; 9 | import diff from 'jest-diff'; 10 | import isEqual from 'lodash.isequal'; 11 | import minimist from 'minimist'; 12 | import path from 'path'; 13 | import _rm from 'rimraf'; 14 | import { Logger } from 'tslog'; 15 | import { PackageJson, TsConfigJson } from 'type-fest'; 16 | import { promisify } from 'util'; 17 | 18 | /** 19 | * The `camelCased` argument passed to the cli. 20 | */ 21 | export const cliArgs = camelCaseKeys(minimist(process.argv.slice(2))); 22 | 23 | // The log level to use for scripts. 24 | const minLevel = cliArgs.logLevel ?? process.env.LOG_LEVEL ?? 'debug'; 25 | 26 | /** 27 | * The logger used when running scripts. 28 | */ 29 | export const log: Logger = new Logger({ minLevel }); 30 | 31 | export const exec = promisify(_exec); 32 | export const rm = promisify(_rm); 33 | const separator = '__'; 34 | 35 | /** 36 | * Convert a mangled name to its unmangled version. 37 | * 38 | * `babel__types` => `@babel/types`. 39 | */ 40 | export function unmangleScopedPackage(mangledName: string): string { 41 | return mangledName.includes(separator) ? `@${mangledName.replace(separator, '/')}` : mangledName; 42 | } 43 | 44 | /** 45 | * Mangle a scoped package name. Which removes the `@` symbol and adds a `__` 46 | * separator. 47 | * 48 | * `@babel/types` => `babel__types` 49 | */ 50 | export function mangleScopedPackageName(packageName: string): string { 51 | const [scope, name] = packageName.split('/'); 52 | assert.ok(scope, `Invalid package name provided: ${packageName}`); 53 | 54 | if (name) { 55 | return [scope.replace('@', ''), name].join(separator); 56 | } 57 | 58 | return scope; 59 | } 60 | 61 | /** 62 | * Get a path relative to the base directory of this project. If called with no 63 | * arguments it will return the base directory. 64 | */ 65 | export function baseDir(...paths: string[]): string { 66 | return path.resolve(__dirname, '../../..', path.join(...paths)); 67 | } 68 | 69 | /** 70 | * Get the path relative to the base directory of this project. 71 | */ 72 | export function getRelativePathFromJson({ location }: { location: string }): string { 73 | return path.relative(baseDir(), location); 74 | } 75 | 76 | interface FormatFilesOptions { 77 | /** 78 | * Whether to log anything to the console. 79 | * 80 | * @default false 81 | */ 82 | silent?: boolean; 83 | 84 | /** 85 | * What formatters to use. 86 | * 87 | * @default 'all' 88 | */ 89 | formatter?: 'prettier' | 'eslint' | 'all'; 90 | } 91 | 92 | /** 93 | * Format the provided files with `prettier` and `eslint`. 94 | */ 95 | export async function formatFiles( 96 | path = '', 97 | { silent = false, formatter = 'all' }: FormatFilesOptions = {}, 98 | ): Promise { 99 | const promises: Array> = []; 100 | 101 | if (formatter !== 'prettier') { 102 | promises.push( 103 | exec(`eslint --fix ${path}`, { 104 | // @ts-expect-error 105 | stdio: 'pipe', 106 | }), 107 | ); 108 | } 109 | 110 | if (formatter !== 'eslint') { 111 | promises.push( 112 | exec(`prettier --loglevel warn ${path} --write`, { 113 | // @ts-expect-error 114 | stdio: 'pipe', 115 | }), 116 | ); 117 | } 118 | 119 | const results = await Promise.all(promises); 120 | 121 | if (silent) { 122 | return; 123 | } 124 | 125 | if (results.some((result) => result.stderr)) { 126 | log.fatal(...results.map((result) => result.stderr.trim())); 127 | } 128 | 129 | if (results.some((result) => result.stdout)) { 130 | log.info(...results.map((result) => result.stdout.trim())); 131 | } 132 | } 133 | 134 | export interface PackageMeta { 135 | /** 136 | * The maximum size in KB for the package. 137 | */ 138 | sizeLimit?: string; 139 | 140 | /** 141 | * Set the options for the tsconfig. 142 | * 143 | * False means no tsconfig files will be added to the package. 144 | */ 145 | tsconfigs?: false | TsConfigMeta; 146 | 147 | /** 148 | * Whether to skip the api generation for a package. 149 | */ 150 | skipApi?: boolean; 151 | } 152 | 153 | export interface TsConfigMeta { 154 | [key: string]: TsConfigJson | false | undefined; 155 | __dts__?: TsConfigJson | false; 156 | __tests__?: TsConfigJson | false; 157 | __e2e__?: TsConfigJson | false; 158 | src?: TsConfigJson | false; 159 | } 160 | 161 | export interface Package extends Omit { 162 | /** 163 | * The name of the package. 164 | */ 165 | name: string; 166 | 167 | /** 168 | * The absolute path to the package. 169 | */ 170 | location: string; 171 | 172 | /** 173 | * Custom meta properties consumed by `remirror`. 174 | */ 175 | meta?: PackageMeta; 176 | } 177 | 178 | /** 179 | * The cached packages, to prevent multiple re-computations. 180 | */ 181 | let packages: Promise; 182 | 183 | interface GetAllDependencies { 184 | excludeDeprecated?: boolean; 185 | excludeSupport?: boolean; 186 | } 187 | 188 | /** 189 | * Get all dependencies. 190 | * 191 | * @param excludeDeprecated - when true exclude the deprecated packages 192 | */ 193 | export function getAllDependencies({ 194 | excludeDeprecated = true, 195 | excludeSupport = false, 196 | }: GetAllDependencies = {}): Promise { 197 | if (!packages) { 198 | packages = getPackages(baseDir()).then(({ packages = [] }) => { 199 | const transformedPackages: Package[] = []; 200 | 201 | for (const pkg of packages) { 202 | if (excludeSupport && pkg.dir.startsWith(baseDir('support'))) { 203 | continue; 204 | } 205 | 206 | if (excludeDeprecated && pkg.dir.startsWith(baseDir('deprecated'))) { 207 | continue; 208 | } 209 | 210 | transformedPackages.push({ 211 | ...pkg.packageJson, 212 | location: pkg.dir, 213 | }); 214 | } 215 | 216 | return transformedPackages; 217 | }); 218 | } 219 | 220 | return packages; 221 | } 222 | 223 | /** 224 | * Get all the packages that can be used as dependencies within the project. 225 | * These are identified by having a types field in the package.json. 226 | * 227 | * @param relative - when set to true this will return the paths as 228 | * relative to the root directory. Defaults to `false`. 229 | */ 230 | export async function getTypedPackagesWithPath(relative = false): Promise> { 231 | // Load all the packages within this repository. 232 | const packages = await getAllDependencies(); 233 | 234 | // Get the packages which have a `types` field. 235 | const tsPackages = packages.filter((pkg) => pkg.types); 236 | 237 | /** 238 | * The typed packages to be returned. 239 | */ 240 | const typedPackages: Record = {}; 241 | 242 | // Loop through the typed packages and store the name as a key and path 243 | // (either relative or absolute) as the value. 244 | for (const pkg of tsPackages) { 245 | assert.ok(pkg.name, 'Packages must include a name'); 246 | typedPackages[pkg.name] = relative ? getRelativePathFromJson(pkg) : pkg.location; 247 | } 248 | 249 | return typedPackages; 250 | } 251 | 252 | interface ChangesetState { 253 | preState: PreState | undefined; 254 | changesets: NewChangeset[]; 255 | } 256 | 257 | /** 258 | * Get the value of the current changesets. 259 | */ 260 | export async function readChangesetState(cwd = process.cwd()): Promise { 261 | const preState = await readPreState(cwd); 262 | let changesets = await readChangesets(cwd); 263 | 264 | if (preState?.mode === 'pre') { 265 | const changesetsToFilter = new Set(preState.changesets); 266 | changesets = changesets.filter((x) => !changesetsToFilter.has(x.id)); 267 | } 268 | 269 | return { 270 | preState: preState, 271 | changesets, 272 | }; 273 | } 274 | 275 | const diffOptions = { 276 | contextLines: 1, 277 | expand: false, 278 | aAnnotation: 'Original', 279 | aColor: chalk.red, 280 | bAnnotation: 'Generated', 281 | bColor: chalk.green, 282 | includeChangeCounts: true, 283 | }; 284 | 285 | /** 286 | * Sort the keys alphabetically to produce consistent comparisons. 287 | */ 288 | function orderOutputKeys(output: Record) { 289 | return Object.keys(output) 290 | .sort() 291 | .map((name) => path.relative(process.cwd(), name)); 292 | } 293 | 294 | /** 295 | * Check that the actual output and the expected output are identical. When 296 | * content has changed it will throw an error with a descriptive diff. 297 | * 298 | * @param actual 299 | * @param expected 300 | */ 301 | export function compareOutput(actual: Record, expected: Record) { 302 | const actualKeys = orderOutputKeys(actual); 303 | const expectedKeys = orderOutputKeys(expected); 304 | 305 | if (!isEqual(actualKeys, expectedKeys)) { 306 | throw new Error( 307 | chalk`\n{yellow The generated files are not identical to the original files.}\n\n${ 308 | diff(actualKeys, expectedKeys, diffOptions) || '' 309 | }\n`, 310 | ); 311 | } 312 | 313 | const errorMessages: string[] = []; 314 | 315 | for (const [name, actualContents] of Object.entries(actual)) { 316 | const expectedContents = expected[name]; 317 | const relativeName = path.relative(process.cwd(), name); 318 | 319 | if (isEqual(actualContents, expectedContents)) { 320 | continue; 321 | } 322 | 323 | errorMessages.push( 324 | chalk`{grey ${relativeName}}\n${diff(actualContents, expected[name], diffOptions)}`, 325 | ); 326 | } 327 | 328 | if (errorMessages.length > 0) { 329 | throw new Error( 330 | chalk`\n{bold.yellow The generated file contents differs from current content.}\n\n${errorMessages.join( 331 | '\n\n', 332 | )}\n`, 333 | ); 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | hide_title: true 3 | title: Contributing 4 | --- 5 | 6 | # Contributing 7 | 8 | - [Contributing](#contributing) 9 | - [Setup](#setup) 10 | - [Project Structure](#project-structure) 11 | - [Documentation](#documentation) 12 | - [Testing](#testing) 13 | - [Using Git](#using-git) 14 | - [Development](#development) 15 | - [General](#general) 16 | - [Pull Request (PR) Process](#pull-request-pr-process) 17 | - [Code style](#code-style) 18 | - [Code of Conduct](#code-of-conduct) 19 | - [Our Pledge](#our-pledge) 20 | - [Our Standards](#our-standards) 21 | - [Our Responsibilities](#our-responsibilities) 22 | - [Scope](#scope) 23 | - [Enforcement](#enforcement) 24 | - [Attribution](#attribution) 25 | 26 | ## Setup 27 | 28 | Fork [this repository][repo], clone your fork and add this repository as the upstream remote. 29 | 30 | You will need to have [`pnpm`](https://pnpm.js.org) installed so make sure you follow the 31 | installation [instructions](https://pnpm.js.org/en/installation). 32 | 33 | ```bash 34 | git clone <> 35 | cd template 36 | git remote add upstream https://github.com/remirror/template 37 | pnpm install 38 | 39 | # Checkout a branch and start working on it 40 | git checkout -b BRANCH_NAME 41 | ``` 42 | 43 | If you already have a previous version of the repository checked out then make sure to clean your 44 | `node_modules` by running the following command before installation. 45 | 46 | ```bash 47 | pnpm clean:all 48 | pnpm install 49 | 50 | # An alternative which combines these to commands 51 | pnpm refresh 52 | ``` 53 | 54 | ## Project Structure 55 | 56 | The number of files in the root directory is deliberately as minimal as possible. This is achieved 57 | by moving all configuration files to the `support/root` folder. Whenever you run `pnpm install` 58 | these files are symlinked to the root directory. 59 | 60 | - `.github` - The `GitHub` specific configuration for workflows, issue templates and pull request 61 | templates. 62 | - `docs` - The documentation for this project. 63 | - `packages` - The packages provided by this project. Within this folder there are top level 64 | packages and scoped packages within the `packages/@*/*` folders. 65 | - `support` - This is the package that provides the configuration files, the website, and many other 66 | folders. Each directory includes a readme file that explains it's functionality. Take a 67 | [look](https://github.com/remirror/template/tree/HEAD/support). 68 | 69 | ## Documentation 70 | 71 | Documentation is located within the `docs` folder. 72 | 73 |
74 | 75 | ## Testing 76 | 77 | Unit tests can be run with the following commands. 78 | 79 | ```bash 80 | pnpm test # Unit Test 81 | pnpm test:watch # Test changed files since the last commit 82 | ``` 83 | 84 | Always create your tests inside of a `__tests__/` sub-folder. 85 | 86 | **For naming conventions, use the following.** 87 | 88 | - Unit tests: `*.spec.ts(x)` 89 | 90 |
91 | 92 | ## Using Git 93 | 94 | I recommend that while working on your code you commit early and often. You won't be judged. All 95 | worked submitted in a pull request (see following section) will be squashed into one commit before 96 | merging (unless it makes sense to keep the commits as separate items). 97 | 98 | This project has support for git hooks via [husky]. These hooks help keep the code base quality high 99 | by running checks: 100 | 101 | - Before each commit (lint and test changed files). 102 | - Before each push (lint, typecheck and test). 103 | 104 | By default these checks are **not** run automatically. To enable automatic pre-commit and pre-push 105 | hooks use the following command: 106 | 107 | ```bash 108 | pnpm checks:enable 109 | ``` 110 | 111 | To stop pre-commit / pre-push checks run: 112 | 113 | ```bash 114 | pnpm checks:disable 115 | ``` 116 | 117 |
118 | 119 | ## Development 120 | 121 | If you're modifying a package and import helpers from another packages in the monorepo, ensure that 122 | the other package is referenced in the referring package's `package.json` file. 123 | 124 | ### General 125 | 126 | This project uses [`preconstruct`](https://github.com/preconstruct/preconstruct) to manage builds. 127 | Each time the project is installed `preconstruct dev` is run which automatically sets the dist 128 | folder with entry points mapping to the source files of the package. This is really useful for 129 | development and except for one exception when working on the playground is all you need. 130 | 131 |
132 | 133 | ## Pull Request (PR) Process 134 | 135 | Once your work is complete you'll want to create a Pull Request to share all that goodness with the 136 | rest of us. 137 | 138 | 1. Create a [pull request](https://help.github.com/en/articles/creating-a-pull-request) using the 139 | github interface. The template will automatically populate for you. 140 | 2. Add a description and reference the issue this pull request addresses where applicable. The 141 | description will be used as the body of the git commit message since all pull request are 142 | squashed down into one commit before merging. 143 | 3. Tick off all relevant check boxes by placing an x between the square brackets i.e. `[ ]` to 144 | `[x]`. 145 | 4. Please add a screenshot where the change is related to the user interface or design. It makes it 146 | so much easier to grasp the intentions of your work. You can use your favourite GIF screenshare 147 | tool for creating animated screenshots. 148 | 5. Once submitted the PR will be addressed at our earliest convenience. 149 | 150 |
151 | 152 | ## Code style 153 | 154 | Over time this project has accumulated quite an active set of lint rules. 155 | 156 | The following are some personal preferences for coding style. 157 | 158 | - Functions with more than two arguments should condense these arguments into a parameter object. 159 | - Comment everything. Even if the comment is just to say, `I have no idea what I'm doing`, there is 160 | a lot of information in that comment. 161 | - Choose simplicity over performance. Performance is abstract and it's often better to start with a 162 | simple implementation that can be made more performant, than something that's complex from day 163 | one. 164 | - Use `const` **Arrow Functions** when declaring components. 165 | 166 | ```tsx 167 | const MyComponent = () => { 168 | return
; 169 | }; 170 | ``` 171 | 172 | - Use **Function Declarations** when creating top level functions. 173 | 174 | ```ts 175 | // ✅ - GOOD 176 | function doSomething(something: string) { 177 | return `Cannot do ${something}`; 178 | } 179 | 180 | // ❌ - BAD 181 | const doSomething = (something: string) => { 182 | return `Cannot do ${something}`; 183 | }; 184 | ``` 185 | 186 |
187 | 188 | ## Code of Conduct 189 | 190 |
191 | 192 | ### Our Pledge 193 | 194 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers 195 | pledge to making participation in our project and our community a harassment-free experience for 196 | everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level 197 | of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 198 | 199 | ### Our Standards 200 | 201 | Examples of behavior that contributes to creating a positive environment include: 202 | 203 | - Using welcoming and inclusive language 204 | - Being respectful of differing viewpoints and experiences 205 | - Gracefully accepting constructive criticism 206 | - Focusing on what is best for the community 207 | - Showing empathy towards other community members 208 | 209 | Examples of unacceptable behavior by participants include: 210 | 211 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 212 | - Trolling, insulting/derogatory comments, and personal or political attacks 213 | - Public or private harassment 214 | - Publishing others' private information, such as a physical or electronic address, without explicit 215 | permission 216 | - Other conduct which could reasonably be considered inappropriate in a professional setting 217 | 218 | ### Our Responsibilities 219 | 220 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are 221 | expected to take appropriate and fair corrective action in response to any instances of unacceptable 222 | behavior. 223 | 224 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, 225 | code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or 226 | to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, 227 | threatening, offensive, or harmful. 228 | 229 | ### Scope 230 | 231 | This Code of Conduct applies both within project spaces and in public spaces when an individual is 232 | representing the project or its community. Examples of representing a project or community include 233 | using an official project e-mail address, posting via an official social media account, or acting as 234 | an appointed representative at an online or offline event. Representation of a project may be 235 | further defined and clarified by project maintainers. 236 | 237 | ### Enforcement 238 | 239 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting 240 | the project team at help@kickjump.co. All complaints will be reviewed and investigated and will 241 | result in a response that is deemed necessary and appropriate to the circumstances. The project team 242 | is obligated to maintain confidentiality with regard to the reporter of an incident. Further details 243 | of specific enforcement policies may be posted separately. 244 | 245 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face 246 | temporary or permanent repercussions as determined by other members of the project's leadership. 247 | 248 | ### Attribution 249 | 250 | This Code of Conduct is adapted from the [Contributor Covenant], version 1.4, available at 251 | [http://contributor-covenant.org/version/1/4][version] 252 | 253 | [contributor covenant]: http://contributor-covenant.org 254 | [version]: http://contributor-covenant.org/version/1/4/ 255 | [repo]: https://github.com/remirror/template 256 | [husky]: https://github.com/typicode/husky 257 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_tree.svg: -------------------------------------------------------------------------------- 1 | docu_tree -------------------------------------------------------------------------------- /support/root/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview 3 | * 4 | * This is the eslint config. I've defined in a way that enables to modes. The first mode is for general development and is the default. 5 | * 6 | * This mode doesn't use anything that is intense or would slow down development when in VSCode, 7 | * 8 | * Plugins that are limited are. 9 | * - any rules that need the TypeScript server 10 | * - the imports plugin (requires a parser) 11 | */ 12 | 13 | /** @type {import('eslint').Linter.Config} */ 14 | let config = { 15 | parser: '@typescript-eslint/parser', 16 | plugins: [ 17 | 'jest', 18 | 'jest-formatting', 19 | '@typescript-eslint', 20 | 'unicorn', 21 | 'jsx-a11y', 22 | 'simple-import-sort', 23 | 'eslint-comments', 24 | ], 25 | extends: [ 26 | 'eslint:recommended', 27 | 'plugin:@typescript-eslint/recommended', 28 | 'prettier', 29 | 'prettier/@typescript-eslint', 30 | 'plugin:jest-formatting/recommended', 31 | 'plugin:jest/recommended', 32 | 'plugin:jest/style', 33 | ], 34 | 35 | parserOptions: { 36 | ecmaVersion: 2020, 37 | sourceType: 'module', 38 | }, 39 | env: { 40 | browser: true, 41 | node: true, 42 | jest: true, 43 | es6: true, 44 | }, 45 | rules: { 46 | 'eslint-comments/no-unused-disable': 'error', 47 | 48 | 'unicorn/better-regex': 'error', 49 | 'unicorn/catch-error-name': 'error', 50 | 'unicorn/consistent-destructuring': 'error', 51 | 'unicorn/custom-error-definition': 'off', 52 | 'unicorn/empty-brace-spaces': 'error', 53 | 'unicorn/error-message': 'error', 54 | 'unicorn/escape-case': 'error', 55 | 'unicorn/expiring-todo-comments': 'error', 56 | 'unicorn/explicit-length-check': 'error', 57 | 'unicorn/filename-case': ['error', { case: 'kebabCase' }], 58 | 'unicorn/import-style': 'error', 59 | 'unicorn/new-for-builtins': 'error', 60 | 'unicorn/no-abusive-eslint-disable': 'error', 61 | 'unicorn/no-array-reduce': 'error', 62 | 'unicorn/no-console-spaces': 'error', 63 | 'unicorn/no-for-loop': 'error', 64 | 'unicorn/no-hex-escape': 'error', 65 | 'unicorn/no-instanceof-array': 'error', 66 | 'unicorn/no-keyword-prefix': 'off', 67 | 'unicorn/no-lonely-if': 'error', 68 | 'no-nested-ternary': 'off', 69 | 'unicorn/no-nested-ternary': 'error', 70 | 'unicorn/no-new-array': 'error', 71 | 'unicorn/no-new-buffer': 'error', 72 | 'unicorn/no-process-exit': 'error', 73 | 'unicorn/no-unreadable-array-destructuring': 'error', 74 | 'unicorn/no-unsafe-regex': 'off', 75 | 'unicorn/no-unused-properties': 'off', 76 | 'unicorn/no-useless-undefined': 'error', 77 | 'unicorn/no-zero-fractions': 'error', 78 | 'unicorn/number-literal-case': 'error', 79 | 'unicorn/numeric-separators-style': 'error', 80 | 'unicorn/prefer-add-event-listener': 'error', 81 | 'unicorn/prefer-array-find': 'error', 82 | 'unicorn/prefer-array-flat-map': 'error', 83 | 'unicorn/prefer-array-index-of': 'error', 84 | 'unicorn/prefer-array-some': 'error', 85 | 'unicorn/prefer-date-now': 'error', 86 | 'unicorn/prefer-default-parameters': 'error', 87 | 'unicorn/prefer-dom-node-append': 'error', 88 | 'unicorn/prefer-dom-node-dataset': 'error', 89 | 'unicorn/prefer-dom-node-remove': 'error', 90 | 'unicorn/prefer-dom-node-text-content': 'error', 91 | 'unicorn/prefer-includes': 'error', 92 | 'unicorn/prefer-keyboard-event-key': 'error', 93 | 'unicorn/prefer-math-trunc': 'error', 94 | 'unicorn/prefer-modern-dom-apis': 'error', 95 | 'unicorn/prefer-negative-index': 'error', 96 | 'unicorn/prefer-number-properties': 'error', 97 | 'unicorn/prefer-optional-catch-binding': 'error', 98 | 'unicorn/prefer-query-selector': 'error', 99 | 'unicorn/prefer-reflect-apply': 'error', 100 | 'unicorn/prefer-regexp-test': 'error', 101 | 'unicorn/prefer-set-has': 'error', 102 | 'unicorn/prefer-spread': 'error', 103 | 'unicorn/prefer-string-slice': 'error', 104 | 'unicorn/prefer-string-starts-ends-with': 'error', 105 | 'unicorn/prefer-string-trim-start-end': 'error', 106 | 'unicorn/prefer-ternary': 'error', 107 | 'unicorn/prefer-type-error': 'error', 108 | 'unicorn/string-content': 'off', 109 | 'unicorn/throw-new-error': 'error', 110 | 111 | 'jest/no-test-return-statement': 'off', 112 | 'jest/prefer-strict-equal': 'off', 113 | 'jest/no-export': 'off', 114 | 'jest/consistent-test-it': ['error'], 115 | 'jest/prefer-spy-on': ['warn'], 116 | 'jest/prefer-todo': ['warn'], 117 | 'jest/prefer-hooks-on-top': ['error'], 118 | 'jest/no-large-snapshots': ['warn', { maxSize: 12 }], 119 | 'jest/no-duplicate-hooks': ['error'], 120 | 'jest/no-if': ['error'], 121 | 'jest/no-restricted-matchers': [ 122 | 'error', 123 | { toBeTruthy: 'Avoid `toBeTruthy`', toBeFalsy: 'Avoid `toBeFalsy`' }, 124 | ], 125 | 126 | 'sort-imports': 'off', 127 | 128 | // Use nice import rules 129 | 'simple-import-sort/imports': 'error', 130 | 'simple-import-sort/exports': 'error', 131 | 132 | '@typescript-eslint/no-unused-expressions': [ 133 | 'error', 134 | { allowTernary: true, allowShortCircuit: true }, 135 | ], 136 | 137 | '@typescript-eslint/no-empty-function': 'off', 138 | '@typescript-eslint/no-empty-interface': 'off', 139 | '@typescript-eslint/no-var-requires': 'off', 140 | '@typescript-eslint/explicit-function-return-type': 'off', 141 | '@typescript-eslint/no-explicit-any': 'off', 142 | '@typescript-eslint/no-namespace': 'off', 143 | '@typescript-eslint/no-unused-vars': 'off', 144 | '@typescript-eslint/naming-convention': [ 145 | 'warn', 146 | { selector: 'typeParameter', format: ['StrictPascalCase'] }, 147 | ], 148 | '@typescript-eslint/no-non-null-assertion': 'warn', 149 | '@typescript-eslint/no-inferrable-types': 'warn', 150 | '@typescript-eslint/ban-types': [ 151 | 'warn', 152 | { 153 | extendDefaults: false, 154 | types: { 155 | String: { 156 | message: 'Use string instead', 157 | fixWith: 'string', 158 | }, 159 | Boolean: { 160 | message: 'Use boolean instead', 161 | fixWith: 'boolean', 162 | }, 163 | Number: { 164 | message: 'Use number instead', 165 | fixWith: 'number', 166 | }, 167 | Symbol: { 168 | message: 'Use symbol instead', 169 | fixWith: 'symbol', 170 | }, 171 | Function: { 172 | message: [ 173 | 'The `Function` type accepts any function-like value.', 174 | 'It provides no type safety when calling the function, which can be a common source of bugs.', 175 | 'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.', 176 | 'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.', 177 | ].join('\n'), 178 | }, 179 | Object: { 180 | message: [ 181 | 'The `Object` type actually means "any non-nullish value", so it is marginally better than `unknown`.', 182 | '- If you want a type meaning "any object", you probably want `Record` instead.', 183 | '- If you want a type meaning "any value", you probably want `unknown` instead.', 184 | ].join('\n'), 185 | }, 186 | '{}': { 187 | message: [ 188 | '`{}` actually means "any non-nullish value".', 189 | '- If you want a type meaning "object", you probably want `object` instead.', 190 | '- If you want a type meaning "any value", you probably want `unknown` instead.', 191 | ].join('\n'), 192 | fixWith: 'object', 193 | }, 194 | }, 195 | }, 196 | ], 197 | '@typescript-eslint/explicit-module-boundary-types': 'off', 198 | // Turning off as it leads to code with bad patterns, where implementation 199 | // details are placed before the actual meaningful code. 200 | '@typescript-eslint/no-use-before-define': 'off', 201 | '@typescript-eslint/member-ordering': [ 202 | 'warn', 203 | { 204 | default: ['signature', 'static-field', 'static-method', 'field', 'constructor', 'method'], 205 | }, 206 | ], 207 | '@typescript-eslint/prefer-function-type': 'error', 208 | '@typescript-eslint/array-type': [ 209 | 'error', 210 | { default: 'array-simple', readonly: 'array-simple' }, 211 | ], 212 | 213 | // Built in eslint rules 214 | 'no-constant-condition': 'off', // To many false positives 215 | 'no-empty': 'warn', 216 | 'no-else-return': 'warn', 217 | 'no-useless-escape': 'warn', 218 | 'default-case': 'warn', 219 | 'prefer-template': 'warn', 220 | 'guard-for-in': 'warn', 221 | 'prefer-object-spread': 'warn', 222 | curly: ['warn', 'all'], 223 | 'no-invalid-regexp': 'error', 224 | 'no-multi-str': 'error', 225 | 'no-extra-boolean-cast': 'error', 226 | radix: 'error', 227 | 'no-return-assign': ['error', 'except-parens'], 228 | eqeqeq: ['error', 'always', { null: 'ignore' }], 229 | 'prefer-exponentiation-operator': 'error', 230 | 'prefer-arrow-callback': ['error', { allowNamedFunctions: true }], 231 | 'padding-line-between-statements': [ 232 | 'warn', 233 | { 234 | blankLine: 'always', 235 | prev: '*', 236 | next: ['if', 'switch', 'for', 'do', 'while', 'class', 'function'], 237 | }, 238 | { 239 | blankLine: 'always', 240 | prev: ['if', 'switch', 'for', 'do', 'while', 'class', 'function'], 241 | next: '*', 242 | }, 243 | ], 244 | }, 245 | overrides: [ 246 | { 247 | files: ['*.ts', '*.tsx'], 248 | rules: { 249 | '@typescript-eslint/no-extra-non-null-assertion': ['error'], 250 | '@typescript-eslint/prefer-optional-chain': ['error'], 251 | '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], 252 | '@typescript-eslint/no-dynamic-delete': ['error'], 253 | '@typescript-eslint/no-var-requires': 'error', 254 | }, 255 | }, 256 | { 257 | files: ['**/__tests__/**', 'support/**', '**/*.test.ts', '**/*.spec.ts', '**/*.e2e.ts'], 258 | rules: { 259 | '@typescript-eslint/await-thenable': 'off', 260 | '@typescript-eslint/ban-ts-comment': 'off', 261 | '@typescript-eslint/ban-ts-ignore': 'off', // Often you need to use @ts-ignore in tests 262 | '@typescript-eslint/no-non-null-assertion': 'off', // Makes writing tests more convenient 263 | '@typescript-eslint/no-use-before-define': 'off', 264 | }, 265 | }, 266 | { 267 | files: ['support/scripts/**'], 268 | rules: { 269 | '@typescript-eslint/ban-ts-comment': 'off', 270 | 'unicorn/no-process-exit': 'off', 271 | 'unicorn/no-unreadable-array-destructuring': 'off', 272 | '@typescript-eslint/no-var-requires': 'off', 273 | }, 274 | }, 275 | 276 | { 277 | files: ['**/*.d.ts', '**/__mocks__/**', 'docs/**', 'support/**', 'website/**'], 278 | rules: { 'import/no-default-export': 'off' }, 279 | }, 280 | ], 281 | }; 282 | 283 | // Only apply TypeScript specific rules when in TS Mode. This is a hack for now 284 | // due to the issue raised 285 | // https://github.com/typescript-eslint/typescript-eslint/issues/2373 286 | if (process.env.FULL_ESLINT_CHECK) { 287 | const rules = { 288 | '@typescript-eslint/prefer-readonly': 'warn', 289 | '@typescript-eslint/await-thenable': 'warn', 290 | '@typescript-eslint/no-unnecessary-type-arguments': 'warn', 291 | '@typescript-eslint/restrict-plus-operands': 'warn', 292 | '@typescript-eslint/no-misused-promises': 'warn', 293 | '@typescript-eslint/no-unnecessary-type-assertion': 'error', 294 | '@typescript-eslint/prefer-nullish-coalescing': [ 295 | 'error', 296 | { ignoreConditionalTests: true, ignoreMixedLogicalExpressions: true }, 297 | ], 298 | '@typescript-eslint/restrict-template-expressions': [ 299 | 'warn', 300 | { allowNumber: true, allowBoolean: true }, 301 | ], 302 | }; 303 | 304 | const rulesOff = {}; 305 | 306 | for (const rule of Object.keys(rules)) { 307 | rulesOff[rule] = 'off'; 308 | } 309 | 310 | config = { 311 | ...config, 312 | plugins: [...config.plugins, 'import'], 313 | extends: [...config.extends, 'plugin:import/typescript'], 314 | rules: { 315 | ...config.rules, 316 | 'import/no-deprecated': 'warn', 317 | 'import/max-dependencies': ['warn', { max: 20 }], 318 | 'import/no-default-export': 'warn', 319 | 'import/no-mutable-exports': 'error', 320 | 'import/first': 'error', 321 | 'import/no-duplicates': 'error', 322 | 'import/no-cycle': 'error', 323 | 'import/no-self-import': 'error', 324 | 'import/newline-after-import': 'error', 325 | 326 | // Turn off conflicting import rules 327 | 'import/order': 'off', 328 | }, 329 | overrides: [ 330 | { 331 | parserOptions: { project: [require.resolve('../tsconfig.lint.json')] }, 332 | files: ['**/!(*.{md,mdx})/*.ts', '**/!(*.{md,mdx})/*.tsx'], 333 | rules, 334 | }, 335 | { 336 | files: [ 337 | '**/__tests__/**', 338 | '**/__stories__/**', 339 | 'support/**', 340 | '**/__dts__/**', 341 | '**/*.test.ts', 342 | ], 343 | 344 | // Switch off rules for test files. 345 | rules: rulesOff, 346 | }, 347 | ...config.overrides, 348 | ], 349 | }; 350 | } else { 351 | config.plugins = [...config.plugins, 'markdown']; 352 | config = { 353 | ...config, 354 | // Apply the markdown plugin 355 | plugins: [...config.plugins, 'markdown'], 356 | 357 | // Only apply markdown rules when not in TypeScript mode, since they are 358 | // currently incompatible. 359 | overrides: [ 360 | ...config.overrides, 361 | 362 | { files: ['*.mdx', '*.md'], processor: 'markdown/markdown' }, 363 | { 364 | // Lint code blocks in markdown 365 | files: ['**/*.{md,mdx}/*.{ts,tsx,js}'], 366 | 367 | // Set up rules to be excluded in the markdown blocks. 368 | rules: { 369 | 'unicorn/filename-case': 'off', 370 | }, 371 | }, 372 | ], 373 | }; 374 | } 375 | 376 | module.exports = config; 377 | -------------------------------------------------------------------------------- /support/scripts/generate-configs.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @script 3 | * 4 | * Generate configuration files for `sizeLimit` and package `tsconfig`'s. 5 | */ 6 | 7 | import { deepMerge, isPlainObject, isString, object, omitUndefined } from '@remirror/core-helpers'; 8 | import chalk from 'chalk'; 9 | import { lstat, readdir } from 'fs/promises'; 10 | import globby from 'globby'; 11 | import os from 'os'; 12 | import pLimit from 'p-limit'; 13 | import path from 'path'; 14 | import sortKeys from 'sort-keys'; 15 | import { PackageJson, TsConfigJson } from 'type-fest'; 16 | import writeJSON from 'write-json-file'; 17 | 18 | import { 19 | baseDir, 20 | cliArgs, 21 | compareOutput, 22 | formatFiles, 23 | getAllDependencies, 24 | getRelativePathFromJson, 25 | getTypedPackagesWithPath, 26 | log, 27 | Package, 28 | TsConfigMeta, 29 | } from './helpers'; 30 | 31 | // Store the name used for all tsconfig files. 32 | const tsconfigFileName = 'tsconfig.json'; 33 | 34 | // A collection of the absolute paths where files will be written to. 35 | const paths = { 36 | sizeLimit: baseDir('support', 'root', '.size-limit.json'), 37 | mainTsconfig: baseDir(tsconfigFileName), 38 | baseTsconfig: baseDir('support', 'tsconfig.base.json'), 39 | rootTsconfig: baseDir('support', 'root', tsconfigFileName), 40 | packagesTsconfig: baseDir('packages', tsconfigFileName), 41 | rootTypedoc: baseDir('support', 'root', 'typedoc.json'), 42 | }; 43 | 44 | // A list of all the generated files which will be prettified at the end of the 45 | // process. 46 | const filesToPrettify: string[] = []; 47 | 48 | type Exports = Record; 49 | type ExportField = { [Key in PackageJson.ExportCondition | 'types']?: string } | string; 50 | 51 | /** 52 | * Generate the exports within the packages. 53 | * 54 | * TODO support `typeVersions` field https://github.com/sandersn/downlevel-dts 55 | */ 56 | async function generateExports() { 57 | log.info(chalk`\n{blue Running script for package.json {bold.grey exports} field}`); 58 | 59 | // The following are used for running checks. 60 | const actual: Record = object(); 61 | const expected: Record = object(); 62 | 63 | // Get all the packages in the `pnpm` monorepo. 64 | const packages = await getAllDependencies({ excludeSupport: true }); 65 | 66 | // All the files to update with the new exports object. 67 | const files: Array<[location: string, json: PackageJson]> = []; 68 | 69 | for (const pkg of packages) { 70 | if (!pkg.main) { 71 | continue; 72 | } 73 | 74 | const { location, ...packageJson } = pkg; 75 | const name = pkg.name; 76 | const exportsObject = object(); 77 | 78 | // Reset the exports field so that outdated references aren't persisted. 79 | packageJson.exports = exportsObject; 80 | 81 | // Track the actual stored expected for comparison with the expected. 82 | actual[name] = JSON.stringify(pkg.exports, null, 2) ?? ''; 83 | 84 | const subPackages = await globby('**/package.json', { 85 | cwd: location, 86 | ignore: ['**/node_modules/**'], 87 | onlyFiles: true, 88 | absolute: true, 89 | }); 90 | 91 | for (const subPackage of subPackages) { 92 | const subPackageJson: PackageJson = require(subPackage); 93 | const relativePath = prefixRelativePath(path.relative(location, path.dirname(subPackage))); 94 | 95 | augmentExportsObject(packageJson, relativePath, subPackageJson); 96 | } 97 | 98 | // Make sure the keys are sorted for the exports. 99 | packageJson.exports = sortKeys(exportsObject) ?? ''; 100 | 101 | // Track the generated exports object for testing. 102 | expected[name] = JSON.stringify(packageJson.exports, null, 2); 103 | files.push([path.join(location, 'package.json'), packageJson]); 104 | } 105 | 106 | let error: Error | undefined; 107 | 108 | try { 109 | log.info('\nChecking the generated exports'); 110 | compareOutput(actual, expected); 111 | log.info(chalk`\n{green The generated {bold exports} are valid for all packages.}`); 112 | 113 | if (!cliArgs.force) { 114 | return; 115 | } 116 | 117 | log.info(chalk`\n\nForcing update: {yellow \`--force\`} flag applied.\n\n`); 118 | } catch (error_) { 119 | error = error_; 120 | log.error('\n', error?.message); 121 | } 122 | 123 | if (cliArgs.check && error) { 124 | process.exit(1); 125 | } 126 | 127 | if (cliArgs.check) { 128 | return; 129 | } 130 | 131 | log.info('\nWriting updates to file system.'); 132 | 133 | await Promise.all( 134 | files.map(async ([filepath, json]) => { 135 | filesToPrettify.push(path.relative(process.cwd(), filepath)); 136 | await writeJSON(filepath, json); 137 | }), 138 | ); 139 | } 140 | 141 | /** 142 | * Add a `./` prefix to a path that needs to be seen as relative. 143 | */ 144 | function prefixRelativePath(path: Type): Type { 145 | if (path === undefined || path === '') { 146 | return path; 147 | } 148 | 149 | return path.startsWith('.') ? path : (`./${path}` as Type); 150 | } 151 | 152 | /** 153 | * Add the path with relevant fields to the export field of the provided 154 | * `package.json` object. 155 | */ 156 | function augmentExportsObject(packageJson: PackageJson, filepath: string, json: PackageJson) { 157 | filepath = filepath || '.'; 158 | const browserPath = getBrowserPath(packageJson); 159 | const field: ExportField = { 160 | import: prefixRelativePath(json.module ? path.join(filepath, json.module) : undefined), 161 | require: prefixRelativePath(json.main ? path.join(filepath, json.main) : undefined), 162 | browser: prefixRelativePath(browserPath ? path.join(filepath, browserPath) : undefined), 163 | 164 | // Experimental since this is not currently resolved by TypeScript. 165 | types: prefixRelativePath(json.types ? path.join(filepath, json.types) : undefined), 166 | }; 167 | field.default = field.import; 168 | 169 | let exportsObject: Exports; 170 | 171 | if (isPlainObject(packageJson.exports)) { 172 | exportsObject = packageJson.exports as Exports; 173 | } else { 174 | exportsObject = object(); 175 | packageJson.exports = exportsObject as PackageJson.Exports; 176 | } 177 | 178 | if (!packageJson.exports || isString(packageJson.exports)) { 179 | packageJson.exports = {}; 180 | } 181 | 182 | exportsObject[filepath] = omitUndefined(field); 183 | 184 | if (filepath === '.') { 185 | exportsObject['./package.json'] = './package.json'; 186 | exportsObject['./types/*'] = './dist/declarations/src/*.d.ts'; 187 | } 188 | } 189 | 190 | /** 191 | * Get the relative path for the browser module if it exists, otherwise fallback 192 | * to the module or main path. 193 | */ 194 | function getBrowserPath(pkg: PackageJson) { 195 | const browserPath = isString(pkg.browser) ? pkg.browser : pkg.browser?.[`./${pkg.module}`]; 196 | 197 | return isString(browserPath) ? browserPath : pkg.module; 198 | } 199 | 200 | interface SizeLimitConfig { 201 | /** 202 | * Relative paths to files. The only mandatory option. It could be a path 203 | * "index.js", a pattern "dist/app-*.js" or an array ["index.js", 204 | * "dist/app-*.js", "!dist/app-exclude.js"]. 205 | */ 206 | path: string | string[]; 207 | 208 | /** 209 | * Partial import to test tree-shaking. It could be "{ lib }" to test import { 210 | * lib } from 'lib' or { "a.js": "{ a }", "b.js": "{ b }" } to test multiple 211 | * files. 212 | */ 213 | import?: string | Record; 214 | 215 | /** 216 | * Size or time limit for files from the path option. It should be a string with 217 | * a number and unit, separated by a space. Format: 100 B, 10 KB, 500 ms, 1 s. 218 | */ 219 | limit: string; 220 | 221 | /** 222 | * The name of the current section. It will only be useful if you have multiple 223 | * sections. 224 | */ 225 | name?: string; 226 | 227 | /** 228 | * When using a custom webpack config, a webpack entry could be given. It could 229 | * be a string or an array of strings. By default, the total size of all entry 230 | * points will be checked. 231 | */ 232 | entry?: string | string[]; 233 | 234 | /** 235 | * With false it will disable webpack. 236 | */ 237 | webpack?: boolean; 238 | 239 | /** 240 | * With false it will disable calculating running time. 241 | * 242 | * @default false 243 | */ 244 | running?: boolean; 245 | 246 | /** 247 | * With false it will disable gzip compression. 248 | */ 249 | gzip?: boolean; 250 | 251 | /** 252 | * With true it will use brotli compression and disable gzip compression. 253 | */ 254 | brotli?: boolean; 255 | 256 | /** 257 | * A path to a custom webpack config. 258 | */ 259 | config?: string; 260 | 261 | /** 262 | * An array of files and dependencies to exclude from the project size 263 | * calculation. 264 | */ 265 | ignore?: string[]; 266 | } 267 | 268 | /** 269 | * This generates the `.size-limit.json` file which is currently placed into the 270 | * `support/root` folder. 271 | */ 272 | async function generateSizeLimitConfig() { 273 | log.info(chalk`\n{blue Generating {bold.grey size-limit.json} config file}`); 274 | 275 | // Get all the packages in the `pnpm` monorepo. 276 | const packages = await getAllDependencies(); 277 | 278 | // Container for the size limit config object. This will be written to the 279 | // size limit json file. 280 | const sizes: SizeLimitConfig[] = []; 281 | 282 | for (const pkg of packages) { 283 | const limit = pkg.meta?.sizeLimit; 284 | 285 | // Ignore when there is no limit set for the package. 286 | if (!limit) { 287 | continue; 288 | } 289 | 290 | // The path from the current package to the entry point. 291 | const pathToEntryFile = getBrowserPath(pkg); 292 | 293 | if (!pathToEntryFile) { 294 | continue; 295 | } 296 | 297 | // The path from the root directory to the current package. 298 | const pathToPackage = getRelativePathFromJson(pkg); 299 | 300 | // A list of files to ignore in the size calculations. 301 | const ignore = [ 302 | // Ignore all peer dependencies. 303 | ...Object.keys(pkg.peerDependencies ?? {}), 304 | ]; 305 | 306 | // Add the configuration object to the list of sizes to check. 307 | sizes.push({ 308 | name: pkg.name, 309 | limit, 310 | path: path.join(pathToPackage, pathToEntryFile), 311 | ignore, 312 | running: false, 313 | gzip: true, 314 | }); 315 | } 316 | 317 | await writeJSON(paths.sizeLimit, sizes); 318 | filesToPrettify.push(paths.sizeLimit); 319 | } 320 | 321 | const DEFAULT_TSCONFIG_META: Required = { 322 | src: { 323 | // Flag to show that this file is autogenerated and should not be edited. 324 | compilerOptions: { types: [], declaration: true, noEmit: true }, 325 | include: ['./'], 326 | }, 327 | __e2e__: { 328 | // Flag to show that this file is autogenerated and should not be edited. 329 | compilerOptions: { 330 | types: [ 331 | 'expect-playwright/global', 332 | 'jest-playwright-preset', 333 | 'jest', 334 | 'jest-extended', 335 | 'snapshot-diff', 336 | 'playwright', 337 | 'node', 338 | ], 339 | declaration: false, 340 | noEmit: true, 341 | skipLibCheck: true, 342 | // @ts-ignore 343 | importsNotUsedAsValues: 'remove', 344 | }, 345 | include: ['./'], 346 | }, 347 | __tests__: { 348 | compilerOptions: { 349 | types: [ 350 | 'jest', 351 | 'jest-extended', 352 | 'jest-axe', 353 | '@testing-library/jest-dom', 354 | 'snapshot-diff', 355 | 'node', 356 | ], 357 | declaration: false, 358 | noEmit: true, 359 | skipLibCheck: true, 360 | // @ts-ignore 361 | importsNotUsedAsValues: 'remove', 362 | }, 363 | include: ['./'], 364 | }, 365 | __dts__: { 366 | compilerOptions: { 367 | declarationMap: false, 368 | declaration: false, 369 | noEmit: true, 370 | skipLibCheck: true, 371 | noUnusedLocals: false, 372 | noUnusedParameters: false, 373 | allowUnreachableCode: true, 374 | noImplicitReturns: false, 375 | // @ts-ignore 376 | importsNotUsedAsValues: 'remove', 377 | }, 378 | include: ['./'], 379 | }, 380 | // './': { 381 | // compilerOptions: { 382 | // declaration: false, 383 | // noEmit: true, 384 | // skipLibCheck: true, 385 | // }, 386 | // include: ['src'], 387 | // }, 388 | }; 389 | 390 | interface TsConfigFile { 391 | filepath: string; 392 | json: TsConfigJson; 393 | shouldReference: boolean; 394 | } 395 | 396 | /** 397 | * Add flag to indicate that this file is auto generated. 398 | */ 399 | function createAutoGeneratedFlag(folderName: string): object { 400 | return { 401 | __AUTO_GENERATED__: [ 402 | `To update the configuration edit the following field.`, 403 | `\`package.json > @remirror > tsconfigs > '${folderName}'\``, 404 | '', 405 | `Then run: \`pnpm -w generate:ts\``, 406 | ], 407 | }; 408 | } 409 | 410 | function makeRelative(filepath: string) { 411 | return filepath.startsWith('.') ? filepath : `./${filepath}`; 412 | } 413 | 414 | /** 415 | * Resolve the metadata from the tsconfig file. 416 | */ 417 | async function resolveTsConfigMeta( 418 | pkg: Package, 419 | dependencies: Record, 420 | types: Set, 421 | ): Promise { 422 | const configFiles: TsConfigFile[] = []; 423 | const meta = pkg.meta?.tsconfigs; 424 | 425 | if (meta === false) { 426 | return configFiles; 427 | } 428 | 429 | const foldersInDirectory = await readdir(pkg.location); 430 | const mergedMeta: Required = deepMerge(DEFAULT_TSCONFIG_META, meta ?? {}); 431 | const { './': main, src, ...rest } = mergedMeta; 432 | const references: TsConfigJson.References[] = []; 433 | 434 | if (src !== false) { 435 | const filepath = path.join(pkg.location, 'src', tsconfigFileName); 436 | 437 | // Collect all the references need for the current package. 438 | for (const dependency of Object.keys(pkg.dependencies ?? {})) { 439 | const dependencyPath = dependencies[dependency]; 440 | 441 | // Check if the dependency is one of the internal workspace dependencies. 442 | // We only want to add the internal project dependencies to the 443 | // references. 444 | if (!dependencyPath) { 445 | continue; 446 | } 447 | 448 | references.push({ 449 | // Add the dependency which is a path relative to the current package 450 | // being checked. 451 | path: path.join(path.relative(path.dirname(filepath), path.join(dependencyPath, 'src'))), 452 | }); 453 | } 454 | 455 | const { compilerOptions: original, ...other } = src ?? {}; 456 | const isComposite = 457 | !!pkg.types || 458 | Object.keys(dependencies).includes(pkg.name) || 459 | ['__tests__', '__dts__'].some((folder) => foldersInDirectory.includes(folder)); 460 | const compilerOptions = deepMerge( 461 | {}, 462 | (original as any) ?? {}, 463 | isComposite 464 | ? { composite: true, noEmit: false, emitDeclarationOnly: true, outDir: '../dist-types' } 465 | : { declaration: false, noEmit: true }, 466 | ); 467 | 468 | for (const type of compilerOptions?.types ?? []) { 469 | types.add(type); 470 | } 471 | 472 | configFiles.push({ 473 | shouldReference: true, 474 | filepath, 475 | json: { 476 | ...createAutoGeneratedFlag('src'), 477 | extends: path.relative(path.dirname(filepath), paths.baseTsconfig), 478 | compilerOptions, 479 | ...other, 480 | references, 481 | }, 482 | }); 483 | } 484 | 485 | if (main) { 486 | const filepath = path.join(pkg.location, tsconfigFileName); 487 | const { compilerOptions: original = {}, ...other } = main ?? {}; 488 | const compilerOptions = deepMerge( 489 | src !== false ? (src?.compilerOptions as any) ?? {} : {}, 490 | original as any, 491 | ); 492 | configFiles.push({ 493 | shouldReference: false, 494 | filepath, 495 | json: { 496 | ...createAutoGeneratedFlag('src'), 497 | extends: makeRelative(path.relative(path.dirname(filepath), paths.baseTsconfig)), 498 | compilerOptions, 499 | ...other, 500 | }, 501 | }); 502 | } 503 | 504 | for (const [folder, config] of Object.entries(rest)) { 505 | if (!foldersInDirectory.includes(folder.replace(/^\.\//, '')) || config === false) { 506 | continue; 507 | } 508 | 509 | const filepath = path.join(pkg.location, folder, tsconfigFileName); 510 | const { compilerOptions: original = {}, ...other } = config ?? {}; 511 | const compilerOptions = deepMerge( 512 | src !== false ? (src?.compilerOptions as any) ?? {} : {}, 513 | original as any, 514 | ); 515 | 516 | const extraReferences: TsConfigJson.References[] = []; 517 | 518 | if (['__tests__', '__dts__'].includes(folder)) { 519 | extraReferences.push({ path: '../src' }); 520 | } 521 | 522 | configFiles.push({ 523 | shouldReference: true, 524 | filepath, 525 | json: { 526 | ...createAutoGeneratedFlag(folder), 527 | extends: path.relative(path.dirname(filepath), paths.baseTsconfig), 528 | compilerOptions, 529 | ...other, 530 | references: [...extraReferences, ...references], 531 | }, 532 | }); 533 | } 534 | 535 | return configFiles; 536 | } 537 | 538 | /** 539 | * Generate a tsconfig for every package. 540 | * 541 | * This is currently unused. 542 | */ 543 | async function generatePackageTsConfigs() { 544 | log.info(chalk`\n{blue Generating {bold.grey tsconfig.json} files for all packages}`); 545 | 546 | // Get the full package and the locations of all packages with a `types` field 547 | // in their `package.json`. 548 | const [packages, dependencies] = await Promise.all([ 549 | getAllDependencies(), 550 | getTypedPackagesWithPath(), 551 | ]); 552 | 553 | const promises: Array> = []; 554 | const limit = pLimit(os.cpus().length); 555 | const references: TsConfigJson.References[] = []; 556 | const types: Set = new Set(); 557 | const entryFiles: string[] = []; 558 | 559 | /** 560 | * Write the file for an individual package. 561 | */ 562 | function writePackageTsconfig(pkg: Package) { 563 | if (pkg.types) { 564 | entryFiles.push(path.join(getRelativePathFromJson(pkg), 'src', 'index.ts')); 565 | } 566 | 567 | promises.push( 568 | limit(async () => { 569 | const tsconfigFiles = await resolveTsConfigMeta(pkg, dependencies, types); 570 | 571 | for (const tsconfig of tsconfigFiles) { 572 | if (!tsconfig.shouldReference) { 573 | continue; 574 | } 575 | 576 | references.push({ 577 | path: path.relative(baseDir(), path.dirname(tsconfig.filepath)), 578 | }); 579 | } 580 | 581 | // Write the tsconfig files to disk. 582 | await Promise.all(tsconfigFiles.map(({ filepath, json }) => writeJSON(filepath, json))); 583 | 584 | // Add the file created to the list of files to prettify at the end of 585 | // the script being run. 586 | filesToPrettify.push(tsconfigFiles.map((tsconfig) => tsconfig.filepath).join(' ')); 587 | }), 588 | ); 589 | } 590 | 591 | for (const pkg of packages) { 592 | // Populate the promises. 593 | writePackageTsconfig(pkg); 594 | } 595 | 596 | // Write all the files to the locations. 597 | await Promise.all(promises); 598 | 599 | const packagesTsconfig = { 600 | extends: makeRelative(path.relative(path.dirname(paths.packagesTsconfig), paths.baseTsconfig)), 601 | compilerOptions: { 602 | types: [...types], 603 | declaration: false, 604 | noEmit: true, 605 | skipLibCheck: true, 606 | }, 607 | include: ['./*/src'], 608 | }; 609 | 610 | references.sort((a, b) => a.path.localeCompare(b.path)); 611 | await writeJSON(paths.rootTsconfig, { include: [], files: [], references }); 612 | 613 | const packagesStat = await lstat(path.dirname(paths.packagesTsconfig)); 614 | 615 | if (packagesStat.isDirectory()) { 616 | await writeJSON(paths.packagesTsconfig, packagesTsconfig); 617 | } 618 | 619 | await writeJSON(paths.rootTypedoc, { entryFiles, out: 'docs/api' }); 620 | filesToPrettify.push(paths.rootTsconfig); 621 | } 622 | 623 | /** 624 | * The runner that runs when this is actioned. 625 | */ 626 | async function main() { 627 | if (cliArgs.size) { 628 | // Update the `size-limit.json` file. 629 | await Promise.all([generateSizeLimitConfig()]); 630 | } else if (cliArgs.tsPackages) { 631 | // Run when flag `--ts-packages` is used. 632 | await Promise.all([generatePackageTsConfigs()]); 633 | } else if (cliArgs.exports) { 634 | // Run when `--exports` is used 635 | await Promise.all([generateExports()]); 636 | } else { 637 | // This is the default mode to run. 638 | await Promise.all([generateSizeLimitConfig()]); 639 | } 640 | 641 | if (filesToPrettify.length === 0) { 642 | return; 643 | } 644 | 645 | log.debug('Prettifying the updated and created files'); 646 | 647 | // Format all the files which have been created before exiting. 648 | await formatFiles(filesToPrettify.join(' '), { silent: true, formatter: 'prettier' }); 649 | } 650 | 651 | // Run the script and listen for any errors. 652 | main().catch((error) => { 653 | log.error( 654 | chalk`\n{red Something went wrong while running the} {blue.bold playground:imports} {red script.}`, 655 | ); 656 | 657 | log.fatal('\n', error); 658 | process.exit(1); 659 | }); 660 | -------------------------------------------------------------------------------- /website/static/img/undraw_docusaurus_mountain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | --------------------------------------------------------------------------------