diff --git a/.changeset/blue-turtles-shake.md b/.changeset/blue-turtles-shake.md new file mode 100644 index 000000000..30e8a22b2 --- /dev/null +++ b/.changeset/blue-turtles-shake.md @@ -0,0 +1,5 @@ +--- +'modular-scripts': major +--- + +Removed commands: convert, init, port, rename diff --git a/docs/commands/convert.md b/docs/commands/convert.md deleted file mode 100644 index 6116f7f70..000000000 --- a/docs/commands/convert.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -parent: Commands -title: modular convert ---- - -# `modular convert` - -Converts the react app in the current directory into a modular project with a -modular app workspace. - -This action is `atomic` so if an error occurs while converting, it will stash -any changes made and bring the repo back to the previous state prior to the -attempt. - -- Sets up the current directory as a modular project with a `packages/` - workspaces - -- Moves the current react app source content (`src/` and `public/`) into a - modular app within `packages/` workspace - -- Relocates setupTests file from `src/` to `modular/` - -- Updates the `react-app-env.d.ts` file within the modular app to reference - modular-scripts for types - -- Updates `tsconfig.json` to include the modular packages workspace - -- Removes `react-scripts` as a dependency and installs - eslint-config-modular-app. You can point to it by adding 'modular-app' to the - extends array in your eslint config. diff --git a/docs/commands/init.md b/docs/commands/init.md deleted file mode 100644 index 0999bca2a..000000000 --- a/docs/commands/init.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -parent: Commands -title: modular init ---- - -# `modular init` - -Initializes a modular root type package.json in the current directory with -packages folder set up to add modular packages to. - -## Options: - -`-y`: Equivalent to setting it for `npm init`. Generates an empty npm project -without all of the interactive processes. - -`--prefer-offline`: Uses offline yarn cache when possible - -`--verbose`: Run yarn commands with --verbose set and sets -`MODULAR_LOGGER_DEBUG` to true diff --git a/docs/commands/port.md b/docs/commands/port.md deleted file mode 100644 index dba1eddda..000000000 --- a/docs/commands/port.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -parent: Commands -title: modular port ---- - -# `modular port ` - -Takes a relative path from the modular root directory to the targeted -create-react-app project and ports it over to the current modular project as a -modular app. - -``` -$ modular port ../another-react-app -``` - -This action is `atomic` so if an error occurs while porting, it will stash any -changes made and bring the repo back to the previous state prior to the attempt. - -- Creates a new folder in packages workspace, named using your targeted app's - package.json name - -- Moves the `src` and `public` folders into the new workspace - -- If present, updates the `react-app-env.d.ts` file within the new workspace to - reference modular-scripts for types of static assets (e.g. svgs) - -- Creates a tsconfig.json within the new workspace to extend the root - `tsconfig.json` - -- If you do not have a `modular/setupTests` file and the targeted app has a - `src/setupTests` file, it will move it into the `modular` folder to load - before executing `modular test` - -- Resolves dependencies between the two repos. - -## Dependency Resolution - -`modular port` does not set up `nohoist` in `package.json` for mismatched -versions. - -If the targeted app has a `dependency` that is versioned differently than the -modular root dependency, the package@version in modular root will take -precedence. - -If the targeted app has a `devDependency` that is marked as a `dependency` in -modular root, it will not be ported over into the modular app as a -`devDependency` but instead be kept as a dependency in modular root. During this -resolution, if modular root has the package in its dependencies, the version in -modular root will take precedence. - -Given the case that the app you are porting over has a dependency that is a -local package in modular worktree, if the target app's dep has a different -version than the local version, that package would not be symlinked to the local -package at all if brought over directly. It would get its own copy in its -node_modules. -(https://github.com/yarnpkg/yarn/issues/6898#issuecomment-478188695) - -Example: TargetApp's dependency: foo@^1.0.5 - -Modular package foo's local version: 2.0.1 - -TargetApp will have copy of foo@1.0.5 in its workspace node_modules. - -It will be marked as a `mismatchedWorkspaceDependencies` in yarn workspaces. We -do not allow `mismatchedWorkspaceDependencies` in the modular workspace. - -If the targeted app has a `dependency` or `devDependency` of a package that is a -local workspace in your modular repo, we will remove that dependency from the -target app and have it use the local symlinked version instead. diff --git a/docs/commands/rename.md b/docs/commands/rename.md deleted file mode 100644 index 9329b25aa..000000000 --- a/docs/commands/rename.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -parent: Commands -title: modular rename ---- - -# `modular rename ` - -Renames oldPackageName to newPackageName by: - -1. Re-writing the "name" field in the existing package.json to newPackageName -1. Parsing all the sources in all the depending packages and rewriting the - imports to oldPackageName to import newPackageName - -This action is `atomic`: if an error occurs while converting, it will stash any -changes made and bring the repo back to the previous state prior to the attempt. - -Please note that the directory containing oldPackageName is _not_ renamed, -because the link between directory name and package name is not unambiguous: for -example, nested or scoped packages created with modular get a nested path that -is not easily unambiguosly invertible. The user will need to rename the -directory if needed. - -## Options: - -`--verbose`: Shows debug information diff --git a/docs/how-to/convert-react-app.md b/docs/how-to/convert-react-app.md new file mode 100644 index 000000000..bcc4a07d2 --- /dev/null +++ b/docs/how-to/convert-react-app.md @@ -0,0 +1,30 @@ +--- +parent: How To +nav_order: 1 +title: Convert CRA Project to Modular Project +--- + +# Convert a Create React App project to a Modular Project + +To convert an existing [Create React App](https://create-react-app.dev/) project +into a Modular app, start by creating a new Modular project as shown in the +[getting started documentation](../index.md): + +`yarn create modular-react-app my-new-modular-project` + +Once created: + +- Replace the source code within the `app` workspace inside the `packages/` + directory with your React app source content. +- Copy the dependencies from the old root package.json to the new Modular one + within the `app` workspace. + - Ensure the React version and other dependencies in the root Modular + package.json are the same as those used in the React app. +- Copy over any necessary custom configurations, and ensure `modular start` + `test` and `build` scripts succesfully start, test and build your app. + +Your app will now be a Modular `app` package. You can change the package type in +the package's package.json `modular.type` field to `view` if more appropriate. + +Feel free to rename the workspace by following this guide: +[Rename Package](./rename-package). diff --git a/docs/how-to/create-template.md b/docs/how-to/create-template.md new file mode 100644 index 000000000..1368026d1 --- /dev/null +++ b/docs/how-to/create-template.md @@ -0,0 +1,44 @@ +--- +parent: How To +nav_order: 3 +title: Create Template +--- + +# Create a Modular Template + +To create a [Modular Template](../concepts/templates.md), start with any Modular +package type for which you want to create a template for (`app`, `package`, +etc). The package's contents will be copied into any new package created using +the template. + +To convert the package into a template, make the following changes to the +package's package.json: + +- Change `modular.type` field to `"template"` +- Add `modular.templateType` with the desired target package type + +Example configuration for a template that generates `esm-view`s. + +```json +{ + "modular": { + "type": "template", + "templateType": "esm-view" + } +} +``` + +Optionally, include a `files` array pattern containing any files that Modular +should include from the template when creating a new package using it. Example: + +```json +{ + "files": [ + "path/to/file-to-include-1.tsx", + "path/to/file-to-include-2.ts", + "folder-to-include" + ] +} +``` + +If not specified, Modular will include all files. diff --git a/docs/how-to/index.md b/docs/how-to/index.md new file mode 100644 index 000000000..669e3aa1e --- /dev/null +++ b/docs/how-to/index.md @@ -0,0 +1,7 @@ +--- +has_children: true +title: How To +nav_order: 300 +--- + +# How To diff --git a/docs/how-to/rename-package.md b/docs/how-to/rename-package.md new file mode 100644 index 000000000..cb0c104ff --- /dev/null +++ b/docs/how-to/rename-package.md @@ -0,0 +1,16 @@ +--- +parent: How To +nav_order: 2 +title: Rename Modular Package +--- + +# Rename a Modular Package + +To rename a Modular package, find and replace the package name in the following +places: + +- The `name` field in the package's package.json +- All places where the package is imported/referenced + +Feel free to rename the package directory, although this will not have an impact +on the package. diff --git a/docs/index.md b/docs/index.md index 137590075..da9b833c9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -38,20 +38,22 @@ It supports three flags: ## Commands -- [`init`](./commands/init.md) - [`workspace`](./commands/workspace.md) - [`check`](./commands/check.md) - [`add`](./commands/add.md) - [`start`](./commands/start.md) - [`test`](./commands/test.md) - [`build`](./commands/build.md) -- [`convert`](./commands/convert.md) -- [`port`](./commands/port.md) - [`typecheck`](./commands/typecheck.md) - [`lint`](./commands/lint.md) -- [`rename`](./commands/rename.md) ## Concepts - [Views](./concepts/views.md) - [Linting](./concepts/linting.md) + +## How to + +- [`Create a Template`](./how-to/create-template.md) +- [`Convert Existing CRA Project`](./how-to/convert-react-app.md) +- [`Rename a Modular Package`](./how-to/rename-package.md) diff --git a/docs/releases/4.0.x.md b/docs/releases/4.0.x.md index fab1d9ebf..e0dae3986 100644 --- a/docs/releases/4.0.x.md +++ b/docs/releases/4.0.x.md @@ -49,8 +49,15 @@ the update. ### Removed Commands -We no longer provide the following commands: (FILL AS NEEDED) (PROVIDE/LINK -DOCUMENTATION FOR HOW TO REPLICATE COMMAND BEHAVIOUR MANUALLY) +We no longer provide the following commands: + +- `modular convert ` +- `modular init` +- `modular port` +- `modular rename` + +Refer to the [How To](../how-to/index.md) section for instructions on how to +manually complete the tasks previously covered by these commands. ### Other diff --git a/packages/modular-scripts/src/__tests__/__snapshots__/init.test.tsx.snap b/packages/modular-scripts/src/__tests__/__snapshots__/init.test.tsx.snap deleted file mode 100644 index 8f0919733..000000000 --- a/packages/modular-scripts/src/__tests__/__snapshots__/init.test.tsx.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Creating a new modular folder should have an empty yarn.lock 1`] = ` -"# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -" -`; - -exports[`Creating a new modular folder should make a new repo with the right name and properties 1`] = ` -{ - "author": "", - "browserslist": { - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version", - ], - "production": [ - ">0.2%", - "not dead", - "not op_mini all", - ], - }, - "description": "", - "keywords": [], - "license": "MIT", - "main": "index.js", - "modular": { - "type": "root", - }, - "name": "test-modular-app", - "private": true, - "scripts": { - "test": "echo "Error: no test specified" && exit 1", - }, - "version": "1.0.0", - "workspaces": [ - "packages/**", - ], -} -`; diff --git a/packages/modular-scripts/src/__tests__/convert.test.ts b/packages/modular-scripts/src/__tests__/convert.test.ts deleted file mode 100644 index 3e27ca214..000000000 --- a/packages/modular-scripts/src/__tests__/convert.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { IncludeDefinition as TSConfig } from '@schemastore/tsconfig'; -import * as path from 'path'; -import * as tmp from 'tmp'; -import * as fs from 'fs-extra'; - -import * as getModularRoot from '../utils/getModularRoot'; -import { convert } from '../convert'; -import tree from 'tree-view-for-tests'; - -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -jest.mock('../utils/getModularRoot'); - -const mockedModularRoot = getModularRoot.default as jest.MockedFunction< - typeof getModularRoot.default ->; - -describe('Converting a react app to modular app', () => { - let tmpFolder: tmp.DirResult; - let tmpFolderPath: string; - const tmpProjectName = 'test-modular-convert'; - const rootPackageJson: ModularPackageJson = { - name: tmpProjectName, - browserslist: { - production: ['>0.2%', 'not dead', 'not op_mini all'], - development: [ - 'last 1 chrome version', - 'last 1 firefox version', - 'last 1 safari version', - ], - }, - dependencies: { - 'react-scripts': '4.0.3', - }, - }; - - beforeAll(async () => { - tmpFolder = tmp.dirSync({ unsafeCleanup: true }); - tmpFolderPath = path.join(tmpFolder.name, tmpProjectName); - await fs.mkdirp(tmpFolderPath); - mockedModularRoot.mockImplementation(() => tmpFolderPath); - const starterFolder = ['src', 'public']; - starterFolder.forEach((dir) => { - fs.copySync( - path.join(__dirname, '..', '..', '..', 'modular-template-app', dir), - path.join(tmpFolderPath, dir), - { - overwrite: true, - filter(src) { - return !(path.basename(src) === 'package.json'); - }, - }, - ); - }); - fs.writeJSONSync( - path.join(tmpFolderPath, 'package.json'), - rootPackageJson, - { spaces: 2 }, - ); - fs.writeFileSync( - path.join(tmpFolderPath, 'src', 'setupTests.ts'), - Buffer.from("import '@testing-library/jest-dom/extend-expect';"), - ); - await convert(tmpFolderPath); - }); - - afterAll(() => { - tmpFolder.removeCallback(); - tmpFolderPath = ''; - mockedModularRoot.mockClear(); - jest.clearAllMocks(); - }); - - it('should create a modular app with the name of the current directory', () => { - const packageJson = fs.readJSONSync( - path.join(tmpFolderPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - - expect(packageJson?.modular?.type).toBe('app'); - expect( - fs.existsSync(path.join(tmpFolderPath, 'packages', tmpProjectName)), - ).toBe(true); - }); - - it('should move the starting src folder into the modular app src folder', () => { - expect(tree(path.join(tmpFolderPath, 'packages', tmpProjectName, 'src'))) - .toMatchInlineSnapshot(` - "src - ├─ App.css #1o0zosm - ├─ App.tsx #c80ven - ├─ __tests__ - │ └─ App.test.tsx #1u72nad - ├─ index.css #o7sk21 - ├─ index.tsx #zdn6mw - ├─ logo.svg #1okqmlj - └─ react-app-env.d.ts #t4ygcy" - `); - }); - - it('should move the starting public folder into the modular app public folder', () => { - expect(tree(path.join(tmpFolderPath, 'packages', tmpProjectName, 'public'))) - .toMatchInlineSnapshot(` - "public - ├─ favicon.ico #6pu3rg - ├─ index.html #1m6toxd - ├─ logo192.png #1nez7vk - ├─ logo512.png #1hwqvcc - ├─ manifest.json #19gah8o - └─ robots.txt #1sjb8b3" - `); - }); - - it('should update tsconfig.json', () => { - const tsConfigFile = fs.readJsonSync( - path.join(tmpFolderPath, 'tsconfig.json'), - ) as TSConfig; - expect(tsConfigFile.include).not.toContain('src'); - expect(tsConfigFile.include).toContain('packages/**/src'); - }); - - it('should point react-app-env.d.ts to modular-scripts', () => { - const reactAppEnvFile = fs - .readFileSync( - path.join( - tmpFolderPath, - 'packages', - tmpProjectName, - 'src', - 'react-app-env.d.ts', - ), - ) - .toString(); - expect(reactAppEnvFile).not.toMatch(''); - expect(reactAppEnvFile).toMatch( - '', - ); - }); - - it('should copy setupTests file to modular with correct extension', () => { - expect( - fs - .readFileSync(path.join(tmpFolderPath, 'modular', 'setupTests.ts')) - .toString(), - ).toMatch("import '@testing-library/jest-dom/extend-expect';"); - expect( - fs.existsSync( - path.join( - tmpFolderPath, - 'packages', - tmpProjectName, - 'src', - 'setupTests.ts', - ), - ), - ).toBe(false); - }); - - it('should remove react-scripts from the dependencies', () => { - const updatedPackageJson = fs.readJsonSync( - path.join(tmpFolderPath, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(updatedPackageJson.dependencies || {})).not.toContain( - 'react-scripts', - ); - }); - - it('should add eslint-config-modular-app to the dependencies', () => { - const updatedPackageJson = fs.readJsonSync( - path.join(tmpFolderPath, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(updatedPackageJson.dependencies || {})).toContain( - 'eslint-config-modular-app', - ); - }); -}); diff --git a/packages/modular-scripts/src/__tests__/init.test.tsx b/packages/modular-scripts/src/__tests__/init.test.tsx deleted file mode 100644 index bc188933f..000000000 --- a/packages/modular-scripts/src/__tests__/init.test.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { initModularFolder } from '../init'; -import * as path from 'path'; -import * as tmp from 'tmp'; -import * as fs from 'fs-extra'; -import { promisify } from 'util'; -import { getWorkspacePackages } from '../utils/getAllWorkspaces'; - -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -const mktempd = promisify(tmp.dir); - -describe('Creating a new modular folder', () => { - let folder: string; - beforeEach(async () => { - folder = await mktempd(); - await initModularFolder(folder, true); - }); - - afterEach(async () => { - await fs.remove(folder); - }); - - it('should make a new repo with the right name and properties', async () => { - const packageJson = (await fs.readJSON( - path.join(folder, 'package.json'), - )) as ModularPackageJson; - - packageJson.name = 'test-modular-app'; - - expect(packageJson).toMatchSnapshot(); - }); - - it('should create a modular folder', async () => { - expect(fs.existsSync(path.join(folder, 'modular'))).toBe(true); - expect(await fs.readdir(path.join(folder, 'modular'))).toEqual([]); - }); - - it('should create a packages folder', async () => { - expect(fs.existsSync(path.join(folder, 'packages'))).toBe(true); - expect(await fs.readdir(path.join(folder, 'packages'))).toEqual([]); - }); - - it('should have an empty yarn.lock', async () => { - const lockfile = await fs.readFile(path.join(folder, 'yarn.lock')); - - expect(String(lockfile)).toMatchSnapshot(); - }); - - it('should contain 1 workspace (the root) and an empty dependency analysis', async () => { - const workspace = await getWorkspacePackages(folder, folder); - - // 1 item in the workspace output (the root package) - expect(workspace[0].size).toBe(1); - const workspaceMap = workspace[0]; - expect(workspaceMap).toEqual(expect.any(Map)); - const [, workspaceContent] = Array.from(workspaceMap)[0]; - expect(workspaceContent).toEqual( - expect.objectContaining({ version: '1.0.0', workspace: true }), - ); - - // Empty dependency analysis - expect(workspace[1]).toEqual({}); - }); -}); diff --git a/packages/modular-scripts/src/__tests__/port.test.ts b/packages/modular-scripts/src/__tests__/port.test.ts deleted file mode 100644 index 79aef15d5..000000000 --- a/packages/modular-scripts/src/__tests__/port.test.ts +++ /dev/null @@ -1,246 +0,0 @@ -/** - * @jest-environment node - */ - -import * as path from 'path'; -import * as tmp from 'tmp'; -import * as fs from 'fs-extra'; -import rimraf from 'rimraf'; - -import * as getModularRoot from '../utils/getModularRoot'; -import { port } from '../port'; -import { initModularFolder } from '../init'; - -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -jest.mock('../utils/getModularRoot'); - -const mockedModularRoot = getModularRoot.default as jest.MockedFunction< - typeof getModularRoot.default ->; - -let tmpApp: tmp.DirResult; -let tmpAppPath: string; -let tmpRoot: tmp.DirResult; -let tmpRootPath: string; -const tmpProjectName = 'test-modular-port'; -const tmpModularRootName = 'modular-root'; - -async function setupTempModularRoot() { - tmpRoot = tmp.dirSync({ unsafeCleanup: true }); - tmpRootPath = path.join(tmpRoot.name, tmpModularRootName); - await fs.mkdirp(tmpRootPath); - await initModularFolder(tmpRootPath, true); - mockedModularRoot.mockImplementation(() => tmpRootPath); -} - -const appPackageJson: ModularPackageJson = { - name: tmpProjectName, - browserslist: { - production: ['>0.2%', 'not dead', 'not op_mini all'], - development: [ - 'last 1 chrome version', - 'last 1 firefox version', - 'last 1 safari version', - ], - }, - dependencies: { - 'react-scripts': '4.0.3', - lodash: '^4.17.20', - }, - devDependencies: { - 'monaco-editor-webpack-plugin': '^3.0.1', - }, -}; - -async function setUpTempApp() { - tmpApp = tmp.dirSync({ unsafeCleanup: true }); - tmpAppPath = path.join(tmpApp.name, tmpProjectName); - await fs.mkdir(tmpAppPath); - const starterFolder = ['src', 'public']; - starterFolder.forEach((dir) => { - fs.copySync( - path.join(__dirname, '..', '..', '..', 'modular-template-app', dir), - path.join(tmpAppPath, dir), - { - overwrite: true, - filter(src) { - return !(path.basename(src) === 'package.json'); - }, - }, - ); - }); - fs.writeJSONSync(path.join(tmpAppPath, 'package.json'), appPackageJson, { - spaces: 2, - }); - fs.writeFileSync( - path.join(tmpAppPath, 'src', 'setupTests.ts'), - Buffer.from("import '@testing-library/jest-dom/extend-expect';"), - ); -} - -describe('Porting a react app into a modular project', () => { - beforeEach(async () => { - await setupTempModularRoot(); - await setUpTempApp(); - }); - - afterEach(() => { - tmpApp.removeCallback(); - tmpAppPath = ''; - tmpRoot.removeCallback(); - tmpRootPath = ''; - mockedModularRoot.mockClear(); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it('should port a react app over as a modular app in packages workspace', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - expect( - fs.existsSync(path.join(tmpRootPath, 'packages', tmpProjectName)), - ).toBe(true); - - const packageJson = fs.readJSONSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - - expect(packageJson?.modular?.type).toBe('app'); - }); - - it('should update react-app-env.d.ts to modular-scripts', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - const reactAppEnvFile = fs - .readFileSync( - path.join( - tmpRootPath, - 'packages', - tmpProjectName, - 'src', - 'react-app-env.d.ts', - ), - ) - .toString(); - expect(reactAppEnvFile).not.toMatch(''); - expect(reactAppEnvFile).toMatch( - '', - ); - }); - - describe('when there is already a setupTests file in modular folder', () => { - it('should not copy over the setupTests file', async () => { - fs.writeFileSync( - path.join(tmpRootPath, 'modular', 'setupTests.ts'), - Buffer.from('Testing setupTests file'), - ); - await port(path.relative(tmpRootPath, tmpAppPath)); - expect( - fs - .readFileSync(path.join(tmpRootPath, 'modular', 'setupTests.ts')) - .toString(), - ).toMatch('Testing setupTests file'); - }); - }); - - describe('when there is not a setupTests file in modular', () => { - it('should copy over the setupTest file', async () => { - rimraf.sync(path.join(tmpRootPath, 'modular')); - await port(path.relative(tmpRootPath, tmpAppPath)); - expect( - fs - .readFileSync(path.join(tmpRootPath, 'modular', 'setupTests.ts')) - .toString(), - ).toMatch("import '@testing-library/jest-dom/extend-expect';"); - }); - }); - - it('should copy over root browserslist into app package.json', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(newPackageJson.browserslist).toMatchObject( - appPackageJson.browserslist as Record, - ); - }); - - it('should remove react-scripts from the dependencies', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(newPackageJson.dependencies || {})).not.toContain( - 'react-scripts', - ); - }); - - describe('when modular root does not have the targeted app dependency', () => { - it('should add it to the new app package.json', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(newPackageJson.dependencies || {})).toContain( - 'lodash', - ); - }); - }); - - describe('when modular root has the targeted app dependency', () => { - it('should not add it to the new app package.json', async () => { - fs.writeJsonSync( - path.join(tmpRootPath, 'package.json'), - { - ...fs.readJsonSync(path.join(tmpRootPath, 'package.json')), - dependencies: { - lodash: '^4.17.20', - }, - }, - { spaces: 2 }, - ); - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(newPackageJson.dependencies || {})).not.toContain( - 'lodash', - ); - }); - }); - - describe('when modular root does not have the targeted app dev dependency', () => { - it('should add it to the new app package.json', async () => { - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(newPackageJson.devDependencies || {})).toContain( - 'monaco-editor-webpack-plugin', - ); - }); - }); - - describe('when modular root has the targeted app dev dependency', () => { - it('should not add it to the new app package.json', async () => { - fs.writeJsonSync( - path.join(tmpRootPath, 'package.json'), - { - ...fs.readJsonSync(path.join(tmpRootPath, 'package.json')), - devDependencies: { - 'monaco-editor-webpack-plugin': '^3.0.1', - }, - }, - { spaces: 2 }, - ); - await port(path.relative(tmpRootPath, tmpAppPath)); - const newPackageJson = fs.readJsonSync( - path.join(tmpRootPath, 'packages', tmpProjectName, 'package.json'), - ) as ModularPackageJson; - expect(Object.keys(newPackageJson.devDependencies || {})).not.toContain( - 'monaco-editor-webpack-plugin', - ); - }); - }); -}); diff --git a/packages/modular-scripts/src/convert.ts b/packages/modular-scripts/src/convert.ts deleted file mode 100644 index 18b9d07e8..000000000 --- a/packages/modular-scripts/src/convert.ts +++ /dev/null @@ -1,172 +0,0 @@ -import * as path from 'path'; - -import type { IncludeDefinition as TSConfig } from '@schemastore/tsconfig'; -import type { Dependency } from '@schemastore/package'; -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -import execa from 'execa'; -import { paramCase as toParamCase } from 'change-case'; -import * as fs from 'fs-extra'; -import rimraf from 'rimraf'; - -import { check } from './check'; -import { isValidModularRootPackageJson } from './check/verifyModularRootPackageJson'; -import { cleanGit, stashChanges } from './utils/gitActions'; -import * as logger from './utils/logger'; - -process.on('SIGINT', () => { - stashChanges(); - process.exit(1); -}); - -export async function convert(cwd: string = process.cwd()): Promise { - if (!cleanGit(cwd)) { - throw new Error( - 'You have unsaved changes. Please save or stash them before we attempt to convert this react app to modular app.', - ); - } - - try { - if ( - !isValidModularRootPackageJson(cwd) || - !fs.existsSync(path.join(cwd, 'packages')) - ) { - const { initModularFolder } = await import('./init'); - logger.debug( - "You don't have a modular repo initialized. Setting it up for you now.", - ); - await initModularFolder(cwd, true); - } - - const rootPackageJson = (await fs.readJson( - path.join(cwd, 'package.json'), - )) as ModularPackageJson; - - const packageName = rootPackageJson.name as string; - - logger.log(`Setting up new modular app for ${packageName}`); - - // Create a modular app package folder - const packageTypePath = path.join(__dirname, '../types', 'app'); - const newPackagePath = path.join(cwd, 'packages', toParamCase(packageName)); - fs.mkdirpSync(newPackagePath); - - const newPackageJson: ModularPackageJson = { - name: packageName, - version: '1.1.0', - private: true, - modular: { - type: 'app', - }, - }; - - fs.writeJsonSync( - path.join(newPackagePath, 'package.json'), - newPackageJson, - { spaces: 2 }, - ); - - // Move the cwd folders to the modular app - const srcFolders = ['src', 'public']; - srcFolders.forEach((dir: string) => { - if (fs.existsSync(path.join(cwd, dir))) { - fs.moveSync(path.join(cwd, dir), path.join(newPackagePath, dir)); - } else { - fs.copySync( - path.join(packageTypePath, dir), - path.join(newPackagePath, dir), - { overwrite: true }, - ); - } - }); - - logger.debug('Set tsconfig.json to include your workspaces'); - - let tsConfig: TSConfig = { - extends: 'modular-scripts/tsconfig.json', - include: ['modular', 'packages/**/src'], - }; - - const rootTSConfigPath = path.join(cwd, 'tsconfig.json'); - // If they have a tsconfig, include packages/**/src - if (fs.existsSync(rootTSConfigPath)) { - tsConfig = fs.readJsonSync(rootTSConfigPath) as TSConfig; - - // The tsconfig might already have the necessary includes - // but just in case, this will ensure that it does - const include: string[] = tsConfig.include || []; - tsConfig.include = include.filter( - (key: string) => !['src', 'packages/**/src'].includes(key), - ); - tsConfig.include.push('packages/**/src'); - } - fs.writeJsonSync(rootTSConfigPath, tsConfig, { spaces: 2 }); - fs.writeJSONSync( - path.join(newPackagePath, 'tsconfig.json'), - { - extends: path.relative(newPackagePath, cwd) + '/tsconfig.json', - }, - { spaces: 2 }, - ); - - if (fs.existsSync(path.join(newPackagePath, 'src', 'react-app-env.d.ts'))) { - logger.debug('Updating your react-app-env.d.ts for modular-scripts'); - fs.writeFileSync( - path.join(newPackagePath, 'src', 'react-app-env.d.ts'), - fs - .readFileSync( - path.join(newPackagePath, 'src', 'react-app-env.d.ts'), - 'utf8', - ) - .replace( - '', - '', - ), - ); - } - - logger.debug('Migrating your setupTests file to modular'); - - const setupFileName = 'setupTests'; - const setupFilesExts = ['js', 'ts']; - setupFilesExts.forEach((ext) => { - const file = `${setupFileName}.${ext}`; - if (fs.existsSync(path.join(newPackagePath, 'src', file))) { - fs.writeFileSync( - path.join(cwd, 'modular', file), - fs.readFileSync(path.join(newPackagePath, 'src', file), 'utf8'), - ); - rimraf.sync(path.join(newPackagePath, 'src', file)); - } - }); - - logger.debug('Removing react-scripts from dependencies list'); - - const rootDeps: Dependency = rootPackageJson.dependencies || {}; - rootPackageJson.dependencies = Object.keys(rootDeps).reduce((acc, dep) => { - if (dep !== 'react-scripts') { - return { ...acc, [dep]: rootDeps[dep] }; - } - return acc; - }, {}); - - // Deps that need to be reintroduced because we removed react-scripts - const additionalDeps = ['eslint-config-modular-app']; - - fs.writeJsonSync(path.join(cwd, 'package.json'), rootPackageJson, { - spaces: 2, - }); - - logger.log('Running yarn to update dependencies'); - - execa.sync('yarnpkg', ['--silent', 'add', '-W', ...additionalDeps], { - cwd, - }); - - logger.log('Validating your modular project...'); - await check({ fix: false, target: cwd }); - } catch (err) { - logger.error(err as string); - stashChanges(); - } -} diff --git a/packages/modular-scripts/src/init.ts b/packages/modular-scripts/src/init.ts deleted file mode 100644 index dd6bcb154..000000000 --- a/packages/modular-scripts/src/init.ts +++ /dev/null @@ -1,72 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { defaultBrowsers } from './utils/checkBrowsers'; -import execAsync from './utils/execAsync'; -import * as logger from './utils/logger'; - -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -export async function initModularFolder( - folder: string, - initOverride: boolean, - preferOffline = true, - verbose = false, -): Promise { - const packageJsonPath = path.join(folder, 'package.json'); - - let packageJson: Partial; - - try { - packageJson = (await fs.readJSON(packageJsonPath)) as ModularPackageJson; - } catch (e) { - packageJson = {}; - } - - packageJson.modular = { - type: 'root', - }; - - packageJson.private = true; - - if (!packageJson.workspaces) { - packageJson.workspaces = ['packages/**']; - } - - if (!packageJson.browserslist) { - packageJson.browserslist = defaultBrowsers; - } - - await fs.writeJSON(packageJsonPath, packageJson, { - spaces: 2, - }); - - // now run npm init to ensure that our new content is picked up properly. - // we don't do this before because npm init prints the package.json to console - // at the end - so we want our new values to also be picked up. - const args = ['init']; - if (initOverride) { - args.push('-y'); - } - await execAsync('npm', args, { - cwd: folder, - }); - - await fs.mkdirp(path.join(folder, 'modular')); - await fs.mkdirp(path.join(folder, 'packages')); - - const yarnArgs = verbose ? ['--verbose'] : ['--silent']; - if (preferOffline) { - yarnArgs.push('--prefer-offline'); - } - await execAsync('yarnpkg', yarnArgs, { cwd: folder }); - - logger.log('Modular repository initialized!'); -} - -export default function init( - initOverride = false, - preferOffline = true, - verbose = false, -): Promise { - return initModularFolder(process.cwd(), initOverride, preferOffline, verbose); -} diff --git a/packages/modular-scripts/src/port.ts b/packages/modular-scripts/src/port.ts deleted file mode 100644 index 1a8d4bd2f..000000000 --- a/packages/modular-scripts/src/port.ts +++ /dev/null @@ -1,367 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import execa from 'execa'; -import type { Dependency } from '@schemastore/package'; -import rimraf from 'rimraf'; -import chalk from 'chalk'; -import semver from 'semver'; -import { paramCase as toParamCase } from 'change-case'; - -import * as logger from './utils/logger'; -import getModularRoot from './utils/getModularRoot'; -import getWorkspaceInfo from './utils/getWorkspaceInfo'; -import actionPreflightCheck from './utils/actionPreflightCheck'; -import { cleanGit, stashChanges } from './utils/gitActions'; -import { check } from './check'; - -import type { ModularPackageJson } from '@modular-scripts/modular-types'; - -process.on('SIGINT', () => { - stashChanges(); - process.exit(1); -}); - -export async function port(relativePath: string): Promise { - const modularRoot = getModularRoot(); - if (!cleanGit(modularRoot)) { - throw new Error( - 'You have unsaved changes. Please save or stash them before we attempt to port this react app to your modular project.', - ); - } - const targetRoot = path.resolve(modularRoot, relativePath); - if (!fs.existsSync(path.join(targetRoot, 'package.json'))) { - throw new Error( - "Couldn't find a `package.json` in your react-app directory. Unable to proceed.", - ); - } - - try { - const targetedAppPackageJson = (await fs.readJSON( - path.join(targetRoot, 'package.json'), - )) as ModularPackageJson; - - const targetedAppName = targetedAppPackageJson.name as string; - - logger.log( - `Porting ${targetedAppName} over into packages as a modular app...`, - ); - // Create a modular app package to funnel targeted app into - const packageTypePath = path.join(__dirname, '../types', 'app'); - const newPackagePath = path.join( - modularRoot, - 'packages', - toParamCase(targetedAppName), - ); - fs.mkdirpSync(newPackagePath); - - // Copy the targeted folders to the modular app - const srcFolders = ['src', 'public']; - srcFolders.forEach((dir: string) => { - if (fs.existsSync(path.join(targetRoot, dir))) { - fs.copySync( - path.join(targetRoot, dir), - path.join(newPackagePath, dir), - { overwrite: true }, - ); - } else { - fs.copySync( - path.join(packageTypePath, dir), - path.join(newPackagePath, dir), - { overwrite: true }, - ); - } - }); - - logger.debug('Updating your react-app-env.d.ts for modular-scripts'); - - if (fs.existsSync(path.join(newPackagePath, 'src', 'react-app-env.d.ts'))) { - fs.writeFileSync( - path.join(newPackagePath, 'src', 'react-app-env.d.ts'), - fs - .readFileSync( - path.join(newPackagePath, 'src', 'react-app-env.d.ts'), - 'utf8', - ) - .replace( - '', - '', - ), - ); - } - - fs.writeJSONSync( - path.join(newPackagePath, 'tsconfig.json'), - { - extends: path.relative(newPackagePath, modularRoot) + '/tsconfig.json', - }, - { spaces: 2 }, - ); - - logger.debug('Migrating setupTests file if it does not already exist'); - - const setupFilesExts = ['setupTests.js', 'setupTests.ts']; - - const originSetupTest = setupFilesExts.find((file) => { - return fs.existsSync(path.join(newPackagePath, 'src', file)); - }); - - const modularSetUpTest = setupFilesExts.find((file) => { - return fs.existsSync(path.join(modularRoot, 'modular', file)); - }); - - if (originSetupTest && !modularSetUpTest) { - fs.mkdirpSync(path.join(modularRoot, 'modular')); - fs.writeFileSync( - path.join(modularRoot, 'modular', originSetupTest), - fs.readFileSync( - path.join(newPackagePath, 'src', originSetupTest), - 'utf8', - ), - ); - rimraf.sync(path.join(newPackagePath, 'src', originSetupTest)); - } - - if (originSetupTest && modularSetUpTest) { - logger.log( - chalk.gray( - 'There is already a setupTests file present in the modular folder. ' + - "Skipping porting the app's setupTests file over...", - ), - ); - rimraf.sync(path.join(newPackagePath, 'src', originSetupTest)); - } - - // Staging ported package.json - const { - name, - version, - browserslist, - private: prv, - } = targetedAppPackageJson; - - const stagedPackageJson: ModularPackageJson = { - name, - version, - browserslist, - modular: { - type: 'app', - }, - private: prv, - }; - - /* ****** NOTE ****** - * This does not set up 'nohoist' or 'exceptions' in workspaces - * for mismatched versions. If the targeted app has a - * dependency that is versioned differently than the modular root - * dependency, the package & version in modular root will take precedence. - * - * If the targeted app has a devDependency that is marked - * as a dependency in modular root, it will not be ported over - * into the modular app as a devDependency but instead be kept as a - * dependency in modular root. - * - * During this resolution, if modular root has the package in its - * dependencies, the version in modular root will take precedence. - * - * This may affect the yarn workspaces mismatchedWorkspaceDependencies - * property in workspace info. - * (https://github.com/yarnpkg/yarn/issues/6898#issuecomment-478188695) - * - * Given the case that the app you are porting over has a dependency that is a - * local package in the workspace, if the target app's dep has a different - * version than the local version, that package would not be symlinked to - * the local package at all. It would get its own copy in its node_modules. - * - * Example: - * TargetApp's dependency: foo@^1.0.5 - * Modular package foo's local version: 2.0.1 - * - * TargetApp will have copy of foo@1.0.5 in its workspace node_modules. - * It will be marked as a mismatchedWorkspaceDependencies in yarn workspaces. - * - * We do not allow mismatchedWorkspaceDependencies in the modular workspace. - * Thus, we will remove that dependency from the target app and have it use - * the local symlinked version instead. - * - */ - - logger.log('Resolving dependencies...'); - - const modularRootPackageJson = (await fs.readJSON( - path.join(modularRoot, 'package.json'), - )) as ModularPackageJson; - - const { dependencies: rootDeps = {}, devDependencies: rootDevDeps = {} } = - modularRootPackageJson; - - const { - dependencies: targetDeps = {}, - devDependencies: targetDevDeps = {}, - } = targetedAppPackageJson; - - const workspaces = await getWorkspaceInfo(modularRoot); - - const publicPackages = Object.keys(workspaces).filter( - (name) => workspaces[name].public, - ); - - // [targeted dep name] : root dep version that's taken precedence - const droppedDeps: Dependency = {}; - - // [targeted dep name] : local package version that's taken precedence - const droppedWorkspaceDeps: Dependency = {}; - - const workspaceDeps: Dependency = Object.keys(targetDeps || {}).reduce( - (acc, dep) => { - // Do not bring over dep if it's react-scripts or if modular root has it - // or if it is a public package in the modular workspace - if (dep !== 'react-scripts') { - if (!rootDeps[dep] && !publicPackages.includes(dep)) { - return { ...acc, [dep]: targetDeps[dep] }; - } - // if local package is marked as dependency, note it for later warnings - if (publicPackages.includes(dep)) { - droppedWorkspaceDeps[dep] = ( - fs.readJsonSync( - path.join( - modularRoot, - workspaces[dep].location, - 'package.json', - ), - ) as ModularPackageJson - ).version as string; - return acc; - } - // if it modular workspace dep doesn't satisfy semver, note it for later warnings - if ( - rootDeps[dep] && - !semver.satisfies(rootDeps[dep], targetDeps[dep]) - ) { - droppedDeps[dep] = rootDeps[dep]; - return acc; - } - } - return acc; - }, - {}, - ); - - const workspaceDevDeps = Object.keys(targetDevDeps || {}).reduce( - (acc, devDep) => { - // Do not bring over dep if it's react-scripts or if modular root has it - // or if it is a public package in the modular workspace - if (devDep !== 'react-scripts') { - if ( - !rootDevDeps[devDep] && - !rootDeps[devDep] && - !publicPackages.includes(devDep) - ) { - return { ...acc, [devDep]: targetDevDeps[devDep] }; - } - // if local package is marked as dependency, note it for later warnings - if (publicPackages.includes(devDep)) { - droppedWorkspaceDeps[devDep] = ( - fs.readJsonSync( - path.join( - modularRoot, - workspaces[devDep].location, - 'package.json', - ), - ) as ModularPackageJson - ).version as string; - return acc; - } - // if it modular workspace dep doesn't satisfy semver, note it for later warnings - if ( - rootDeps[devDep] && - !semver.satisfies(rootDeps[devDep], targetDevDeps[devDep]) - ) { - droppedDeps[devDep] = rootDeps[devDep]; - return acc; - } - if ( - rootDevDeps[devDep] && - !semver.satisfies(rootDevDeps[devDep], targetDevDeps[devDep]) - ) { - droppedDeps[devDep] = rootDevDeps[devDep]; - return acc; - } - } - return acc; - }, - {}, - ); - - // Add updated dependencies to new app's package.json - fs.writeJsonSync( - path.join(newPackagePath, 'package.json'), - { - ...stagedPackageJson, - dependencies: workspaceDeps, - devDependencies: workspaceDevDeps, - }, - { spaces: 2 }, - ); - - logger.log('Installing dependencies...'); - - execa.sync('yarnpkg', ['--silent'], { cwd: modularRoot }); - - logger.log('Validating your modular project...'); - - await check({ fix: false, target: modularRoot }); - - logger.log('Successfully ported your app over!'); - - const droppedDepKeys = Object.keys(droppedDeps); - const droppedWorkspaceKeys = Object.keys(droppedWorkspaceDeps); - - if (droppedDepKeys.length) { - logger.warn( - 'We found mismatched dependency versions between your targeted app and the root modular workspace', - ); - logger.warn( - 'As part of the dependency resolution process, the dependencies in modular workspace were given precedence.', - ); - logger.warn( - `Your targeted app (${targetedAppName}) will use these modular workspace dependencies:\n\n` + - droppedDepKeys - .map((dep) => chalk.bold(` \u2022 ${dep}: ${droppedDeps[dep]}`)) - .join('\n') + - '\n\n', - ); - } - - if (droppedWorkspaceKeys.length) { - logger.warn( - 'Your targeted app has a modular workspace public package marked as a dependency.', - ); - logger.warn( - "As part of the dependency resolution process, the local public package's version was given precedence.", - ); - logger.warn( - `Your targeted app (${targetedAppName}) will use the local package version:\n\n` + - droppedWorkspaceKeys - .map((dep) => - chalk.bold(` \u2022 ${dep}: ${droppedWorkspaceDeps[dep]}`), - ) - .join('\n') + - '\n\n', - ); - } - - if (droppedDepKeys.length || droppedWorkspaceDeps.length) { - logger.error( - 'You should look at the dependency resolution warning(s) above and confirm the current workspace dependencies will work for your app', - ); - logger.error( - 'You may encounter issues later if you ignore these warnings.', - ); - } - } catch (err) { - logger.error(err as string); - stashChanges(); - } -} - -export default actionPreflightCheck(port); diff --git a/packages/modular-scripts/src/program.ts b/packages/modular-scripts/src/program.ts index 294a279fd..a034d734d 100755 --- a/packages/modular-scripts/src/program.ts +++ b/packages/modular-scripts/src/program.ts @@ -219,23 +219,6 @@ program }), ); -interface InitOptions { - y: boolean; - preferOffline: boolean; - verbose: boolean; -} - -program - .command('init') - .description('Initialize a new modular root in the current folder') - .option('-y', 'equivalent to the -y flag in NPM') - .option('--prefer-offline [value]', 'delegate to offline cache first', true) - .option('--verbose', 'Run yarn commands with --verbose set') - .action(async (options: InitOptions) => { - const { default: initWorkspace } = await import('./init'); - await initWorkspace(options.y, options.preferOffline, options.verbose); - }); - program .command('check') .description( @@ -249,29 +232,6 @@ program logger.log(chalk.green('Success!')); }); -program - .command('convert') - .description('Converts react app in current directory into a modular package') - .action(async () => { - const { convert } = await import('./convert'); - await convert(); - logger.log( - chalk.green('Successfully converted your app into a modular app!'), - ); - }); - -// TODO: enhancement - should take a type option (app, view, package) -// port are only available for apps right now -program - .command('port ') - .description( - 'Ports the react app in specified directory over into the current modular project as a modular app', - ) - .action(async (relativePath: string) => { - const { port } = await import('./port'); - await port(relativePath); - }); - const lintStagedFlag = '--staged'; program .command('lint [regexes...]') @@ -304,15 +264,6 @@ program await typecheck(); }); -program - .command('rename ') - .description(`Rename a package.`) - .option('--verbose', 'Enables verbose logging within modular.') - .action(async (oldPackageName: string, newPackageName: string) => { - const { default: rename } = await import('./rename'); - await rename(oldPackageName, newPackageName); - }); - interface ServeOptions { port: string; } diff --git a/packages/modular-scripts/src/rename.ts b/packages/modular-scripts/src/rename.ts deleted file mode 100644 index 0feaf5b8b..000000000 --- a/packages/modular-scripts/src/rename.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Project } from 'ts-morph'; -import execa from 'execa'; -import type { CoreProperties } from '@schemastore/package'; -import actionPreflightCheck from './utils/actionPreflightCheck'; -import getModularRoot from './utils/getModularRoot'; -import getWorkspaceInfo from './utils/getWorkspaceInfo'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as logger from './utils/logger'; -import { cleanGit, stashChanges } from './utils/gitActions'; - -process.on('SIGINT', () => { - stashChanges(); - process.exit(1); -}); - -async function rename( - oldPackageName: string, - newPackageName: string, -): Promise { - const workspace = await getWorkspaceInfo(); - - logger.debug(`Checking for existence of ${oldPackageName} in workspace.`); - const workspacePackage = workspace[oldPackageName]; - if (!workspacePackage) { - throw new Error(`Package ${oldPackageName} not found.`); - } - logger.debug(`Checking for collision with ${newPackageName} in workspace.`); - if (workspace[newPackageName]) { - throw new Error(`Package ${newPackageName} already exists.`); - } - - if (!cleanGit(process.cwd())) { - throw new Error( - 'You have unsaved changes. Please save or stash them before we attempt to rename a package.', - ); - } - - try { - const packageJsonLocation = path.join( - workspacePackage.location, - './package.json', - ); - - const packageJson = (await fs.readJson( - packageJsonLocation, - )) as CoreProperties; - - logger.log( - `Changing package name ${packageJson.name as string} → ${newPackageName}`, - ); - packageJson.name = newPackageName; - - await fs.writeJson(packageJsonLocation, packageJson, { spaces: 2 }); - - logger.log(`Rewriting imports in source files`); - await Promise.all( - Object.values(workspace).map(async (packageData) => { - const project = new Project(); - project.addSourceFilesAtPaths( - path.join( - getModularRoot(), - packageData.location, - 'src/**/*{.d.ts,.ts,.js,.jsx,.tsx}', - ), - ); - const sourceFiles = project.getSourceFiles(); - - sourceFiles.forEach((sourceFile) => { - const imports = sourceFile.getImportDeclarations(); - imports.forEach((importDeclaration) => { - if ( - importDeclaration.getModuleSpecifierValue() === oldPackageName - ) { - logger.debug( - `Rewriting \`${importDeclaration.getText()}\` in ${sourceFile.getFilePath()}`, - ); - importDeclaration.setModuleSpecifier(newPackageName); - } - }); - }); - await project.save(); - }), - ); - - logger.log(`Refreshing packages`); - execa.sync('yarnpkg', ['--silent'], { cwd: getModularRoot() }); - } catch (err) { - logger.error(err as string); - stashChanges(); - } -} - -export default actionPreflightCheck(rename);