@codemod-utils/blueprints
Utilities for blueprints
What is it?
@codemod-utils/blueprints helps you create blueprints, files that you use like a "stamp" to create or update files.
API
decideVersion
Returns the version that can be installed for a package.
Always favors the current version in the user's project (a no-op). Uses the latest version only if the project doesn't depend on the package yet.
ts
/**
*
* @param packageName
*
* Name of the package.
*
* @param options
*
* An object with `dependencies` (the current versions in the user's
* project) and `latestVersions` (the versions to install by default).
*
* @return
*
* The version to install.
*/
function decideVersion(
packageName: PackageName,
options: {
dependencies: Map<PackageName, PackageVersion>;
latestVersions: Map<PackageName, PackageVersion>;
},
): PackageVersion;ts
/**
* First, pass `latestVersions` to `decideVersion`.
*/
import { decideVersion } from '@codemod-utils/blueprints';
const latestVersions = new Map([
['embroider-css-modules', '1.0.0'],
['webpack', '5.89.0'],
]);
export function getVersion(packageName, options) {
const { dependencies } = options;
return decideVersion(packageName, {
dependencies,
latestVersions,
});
}ts
/**
* Then, pass `dependencies` to `decideVersion`.
*/
const options = {
dependencies: new Map([
['webpack', '^5.82.0'],
]),
};
getVersion('embroider-css-modules', options); // '^1.0.0'
getVersion('webpack', options); // '^5.82.0' (no-op)NOTE
The example above assumes that:
- You don't want to rely on a library such as
latest-version. (The reasons are, your codemod would have an extra dependency and your tests may fail without stubs—more dependencies.) - Before calling
decideVersion, the codemod has computeddependencies(current dependencies of the user's project) and storedlatestVersions(versions to install by default) somewhere.
getFilePath
Returns where the codemod ends up being installed on the user's machine.
ts
/**
* @param importMetaUrl
*
* Pass the value of `import.meta.url`.
*
* @return
*
* The installation path.
*/
function getFilePath(importMetaUrl: string): string;ts
/**
* To read blueprint files, get the path to the `blueprints` folder.
*/
import { join } from 'node:path';
import { getFilePath } from '@codemod-utils/blueprints';
export const blueprintsRoot = join(
getFilePath(import.meta.url),
'../../blueprints',
);ts
/**
* Afterwards, prepend the file path with `blueprintsRoot`.
*/
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { blueprintsRoot } from '../../some-path';
const blueprintFilePaths = ['LICENSE.md', 'README.md'];
blueprintFilePaths.forEach((blueprintFilePath) => {
const blueprintFile = readFileSync(
join(blueprintsRoot, blueprintFilePath),
'utf8',
);
});processTemplate
Returns the blueprint file after filling it out with data.
ts
/**
* @param file
*
* A blueprint file, which may contain escape, evaluate, and
* interpolate delimiters.
*
* - Escape (`<%- %>`) - escape an HTML code
* - Evaluate (`<% %>`) - evaluate a JavaScript code
* - Interpolate (`<%= %>`) - substitute a value
*
* @param data
*
* An object that provides the data needed for the file.
*
* @return
*
* The processed blueprint file.
*/
function processTemplate(file: string, data?: object): string;js
/*
* First, create a blueprint file.
*/
// blueprints/__testAppLocation__/ember-cli-build.js
'use strict';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function (defaults) {
const app = new EmberApp(defaults, {
// Add options here
autoImport: {
watchDependencies: ['<%= addon.name %>'],
},<% if (testApp.hasTypeScript) { %>
'ember-cli-babel': {
enableTypeScriptTransform: true,
},<% } %>
});
const { maybeEmbroider } = require('@embroider/test-setup');
return maybeEmbroider(app);
};ts
/**
* Then, pass data to the file.
*/
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { processTemplate } from '@codemod-utils/blueprints';
// Read file
const blueprintFilePath = '__testAppLocation__/ember-cli-build.js';
const blueprintFile = readFileSync(
join(blueprintsRoot, blueprintFilePath),
'utf8',
);
// Process file
processTemplate(blueprintFile, {
addon: {
name: 'ember-container-query',
},
app: {
hasTypeScript: true,
},
});