From 94e3646363e0082c1b4b3714d0a7c5e2210f2e83 Mon Sep 17 00:00:00 2001 From: Isaac Lee <16869656+ijlee2@users.noreply.github.com> Date: Sun, 17 Sep 2023 14:38:03 +0200 Subject: [PATCH] Add tutorial for blueprints (Part 2) (#75) Explained how to create files from blueprints (static) Co-authored-by: ijlee2 --- .../blueprint-for-v2-addon/00-introduction.md | 10 +- .../01-create-a-project.md | 16 +- .../02-sketch-out-the-solution.md | 193 ++++++++++++++++++ .../03-define-codemod-options.md | 11 + 4 files changed, 218 insertions(+), 12 deletions(-) create mode 100644 tutorials/blueprint-for-v2-addon/02-sketch-out-the-solution.md create mode 100644 tutorials/blueprint-for-v2-addon/03-define-codemod-options.md diff --git a/tutorials/blueprint-for-v2-addon/00-introduction.md b/tutorials/blueprint-for-v2-addon/00-introduction.md index dcbc440c..ca98d408 100644 --- a/tutorials/blueprint-for-v2-addon/00-introduction.md +++ b/tutorials/blueprint-for-v2-addon/00-introduction.md @@ -13,15 +13,15 @@ We will partially implement `blueprint-for-v2-addon`, a codemod that helps [CLAR - Generating files is simpler and faster. ```sh -# Average time for @embroider/addon-blueprint -❯ time EMBER_CLI_PNPM=true ember addon "@clark-ui/button" --addon-location "ui/button" --blueprint "@embroider/addon-blueprint" --pnpm --skip-npm --typescript +# Average for @embroider/addon-blueprint +❯ time EMBER_CLI_PNPM=true ember addon "@my-orgs-ui/button" --addon-location "ui/button" --blueprint "@embroider/addon-blueprint" --pnpm --skip-npm --typescript 1.87s user 1.18s system 126% cpu 2.409 total ``` ```sh -# Average time for blueprint-for-v2-addon -❯ time pnpm generate-addon --addon-name "@clark-ui/button" --addon-location "ui/button" +# Average for blueprint-for-v2-addon +❯ time pnpm generate-addon --addon-name "@my-orgs-ui/button" --addon-location "ui/button" 1.86s user 0.23s system 133% cpu 1.565 total ``` @@ -30,3 +30,5 @@ We will partially implement `blueprint-for-v2-addon`, a codemod that helps [CLAR ## Table of contents 1. [Create a project](./01-create-a-project.md) +1. [Sketch out the solution](./02-sketch-out-the-solution.md) +1. [Define codemod options](./03-define-codemod-options.md) diff --git a/tutorials/blueprint-for-v2-addon/01-create-a-project.md b/tutorials/blueprint-for-v2-addon/01-create-a-project.md index ea9da4be..3374625b 100644 --- a/tutorials/blueprint-for-v2-addon/01-create-a-project.md +++ b/tutorials/blueprint-for-v2-addon/01-create-a-project.md @@ -21,20 +21,20 @@ cd blueprint-for-v2-addon pnpm install ``` +> [!NOTE] +> Just like in [the main tutorial](../ember-codemod-rename-test-modules/04-step-1-update-acceptance-tests-part-1.md#remove-the-sample-step), you can remove the sample step, `add-end-of-line`. + ## Folder structure -Let's take a look at how `blueprint-for-v2-addon` is structured as a tree. For simplicity, the tree only shows what's important for the tutorial. +Let's take a look at how `blueprint-for-v2-addon` is structured as a tree. For simplicity, the tree only shows what's new, compared to that from [the main tutorial](ember-codemod-rename-test-modules/02-understand-the-folder-structure.md#folder-structure). ```sh blueprint-for-v2-addon └── src ├── blueprints - ├── steps - ├── types - ├── utils - │ └── blueprints.ts - └── index.ts + └── utils + └── blueprints.ts ``` We see that the CLI has scaffolded `src/blueprints` and `src/utils`. @@ -42,7 +42,7 @@ We see that the CLI has scaffolded `src/blueprints` and `src/utils`. ### blueprints -The `blueprints` directory contains files that we want end-developers (our users) to have. +The `blueprints` folder contains files that we want end-developers (our users) to have. For the most part, the folder structure and file names will match what end-developers will see in their project. At runtime, it is possible to change the file path (e.g. rename `__gitignore__` to `.gitignore`) or exclude the file (e.g. `tsconfig.json` for JavaScript projects). @@ -56,7 +56,7 @@ In short, we can write and test our codemod as usual, without worrying about whe
- Next: + Next: Sketch out the solution
Previous: Introduction diff --git a/tutorials/blueprint-for-v2-addon/02-sketch-out-the-solution.md b/tutorials/blueprint-for-v2-addon/02-sketch-out-the-solution.md new file mode 100644 index 00000000..1e6a2808 --- /dev/null +++ b/tutorials/blueprint-for-v2-addon/02-sketch-out-the-solution.md @@ -0,0 +1,193 @@ +# Sketch out the solution + +Our codemod will support **workspaces**. For us, this means, a project that includes 1 addon and 1 test app, or many addons and equally many test apps. + +```sh +workspace-root +├── packages +│ ├── addon-1 +│ ├── addon-2 +│ ├── ... +│ └── addon-n +└── tests + ├── test-app-for-addon-1 + ├── test-app-for-addon-2 + ├── ... + └── test-app-for-addon-n +``` + +We learned in [the previous chapter](./01-create-a-project.md) that, + +- The `blueprints` folder contains files that our users will have. +- The `blueprintsRoot` variable represents where the blueprint files will be saved on their machine. + +Let's look at how we can read and write these files to their project. + +Goals: + +- Take small steps +- Read and write blueprint files + + +## Add blueprint files + +Let's start out simple by creating 1 file for the addon and 1 file for the test app. Both files are **static**; there's nothing **dynamic** (e.g. string interpolations, conditional statements, for-loops) that would complicate our first step. + +Copy-paste the following starter code: + +
+ +src/blueprints/__addonLocation__/package.json + +```json +{ + "name": "addon-1", + "version": "0.0.0" +} +``` + +
+ +
+ +src/blueprints/__testAppLocation__/package.json + +```json +{ + "name": "test-app-for-addon-1", + "version": "0.0.0" +} +``` + +
+ +Then, scaffold a step called `create-files-from-blueprints`. Use `findFiles()` from `@codemod-utils/files` to find the blueprint files, then log the file paths. + +> [!NOTE] +> Need a refresher on [`findFiles()`](../ember-codemod-rename-test-modules/04-step-1-update-acceptance-tests-part-1.md#find-files)? Don't forget to run tests to check your code. +> +> ```sh +> ❯ pnpm test +> +> [ +> '.gitkeep', +> '__addonLocation__/package.json', +> '__testAppLocation__/package.json' +> ] +> ``` + +
+ +Solution: src/steps/create-files-from-blueprints.ts + +Note, the project root for `findFiles()` points to `blueprintsRoot`, not `options.projectRoot`. + +```ts +import { findFiles } from '@codemod-utils/files'; + +import type { Options } from '../types/index.js'; +import { blueprintsRoot } from '../utils/blueprints.js'; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function createFilesFromBlueprints(options: Options): void { + const blueprintFilePaths = findFiles('**/*', { + projectRoot: blueprintsRoot, + }); + + console.log(blueprintFilePaths); +} +``` + +
+ +
+ +Solution: src/steps/index.ts + +```diff ++ export * from './create-files-from-blueprints.js'; +export * from './create-options.js'; +``` + +
+ +
+ +Solution: src/index.ts + +```diff +- import { createOptions } from './steps/index.js'; ++ import { createFilesFromBlueprints, createOptions } from './steps/index.js'; +import type { CodemodOptions } from './types/index.js'; + +export function runCodemod(codemodOptions: CodemodOptions): void { + const options = createOptions(codemodOptions); + +- // ... ++ createFilesFromBlueprints(options); +} +``` + +
+ + +## Read and write blueprint files + +Unlike in [the main tutorial](../ember-codemod-rename-test-modules/04-step-1-update-acceptance-tests-part-1.md#read-and-write-files), we won't use `writeFileSync()` from Node.js to create files. The reason is, the folders where files will be created (i.e. folders named `__addonLocation__` and `__testAppLocation__`) don't exist on the user's machine. We'd need to write extra code to handle this edge case. + +Luckily, `@codemod-utils/files` provides [`createFiles()`](../../packages/files/README.md#createfiles). It creates multiple files at once and creates folders as needed. We just need to provide this function a `Map`, which maps a blueprint's file path to its file content. + +
+ +Solution: src/steps/create-files-from-blueprints.ts + +```ts +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +import { createFiles, findFiles } from '@codemod-utils/files'; + +import type { Options } from '../types/index.js'; +import { blueprintsRoot } from '../utils/blueprints.js'; + +export function createFilesFromBlueprints(options: Options): void { + const blueprintFilePaths = findFiles('**/*', { + projectRoot: blueprintsRoot, + }); + + const fileMap = new Map( + blueprintFilePaths.map((blueprintFilePath) => { + const blueprintFile = readFileSync( + join(blueprintsRoot, blueprintFilePath), + 'utf8', + ); + + return [blueprintFilePath, blueprintFile]; + }), + ); + + createFiles(fileMap, options); +} +``` + +
+ +Run `./codemod-test-fixtures.sh`. From the `sample-project`'s `output` folder, we see that we're a few steps closer to creating the addon and the test app. ✨ + +```sh +workspace-root +├── __addonLocation__ +│ └── package.json +└── __testAppLocation__ + └── package.json +``` + + +
+
+ Next: Define codemod options +
+
+ Previous: Create a project +
+
diff --git a/tutorials/blueprint-for-v2-addon/03-define-codemod-options.md b/tutorials/blueprint-for-v2-addon/03-define-codemod-options.md new file mode 100644 index 00000000..d9c3e270 --- /dev/null +++ b/tutorials/blueprint-for-v2-addon/03-define-codemod-options.md @@ -0,0 +1,11 @@ +# Define codemod options + + +
+
+ Next: +
+
+ Previous: Sketch out the solution +
+