-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Background
Currently, the CLI pre-computes a fixed set of casing variants from the component name and passes each as a separate EJS variable:
// apps/spfx-cli/src/cli/CreateAction.ts
const componentNameCamelCase = camelCase(componentName);
const componentNameHyphenCase = kebabCase(componentName);
const componentNameCapitalCase = upperFirst(camelCase(componentName));
const componentNameAllCaps = snakeCase(componentName).toUpperCase();Each variant is then:
- Passed individually into the EJS render context
- Declared individually in every template's
contextSchemaintemplate.json
This means adding any new casing requires touching CreateAction.ts, the render context, and every template.json.
Problem
- Fragile: templates that forget to declare a variable in
contextSchemasilently receiveundefined - Verbose:
contextSchemain everytemplate.jsonlists the same ~8 variables - Not extensible: a one-off need (e.g.,
UPPER_SNAKE_CASEfor registry IDs in ACE templates) required a new top-level variable (componentNameAllCaps) across all templates - Naming ambiguity: it's unclear which variable to use where — e.g.,
componentNameAllCapsvscomponentNameCapitalCasevscomponentNameUnescaped
Proposed Solution
Pass a single casing utility object (or helper functions) into the EJS render context, so templates can derive any casing on the fly without pre-computation:
Option A — Helper object with named transforms
<%= casing.allCaps(componentName) %> → DATA_VISUALIZATION
<%= casing.camel(componentName) %> → dataVisualization
<%= casing.pascal(componentName) %> → DataVisualization
<%= casing.kebab(componentName) %> → data-visualization
<%= casing.snake(componentName) %> → data_visualizationThe casing object is injected once into the render context:
import { camelCase, kebabCase, snakeCase, upperFirst } from 'lodash';
const casing = {
camel: (s: string) => camelCase(s),
pascal: (s: string) => upperFirst(camelCase(s)),
kebab: (s: string) => kebabCase(s),
snake: (s: string) => snakeCase(s),
allCaps: (s: string) => snakeCase(s).toUpperCase(),
};Option B — Smart string object
Pass a single name object that exposes all casings as properties:
<%= name.allCaps %> → DATA_VISUALIZATION
<%= name.camel %> → dataVisualization
<%= name.pascal %> → DataVisualizationOption C — Keep pre-computing but simplify contextSchema
Instead of per-template contextSchema declarations, define a single shared schema in the template engine that all templates inherit. Templates only need to override if they use a non-standard subset.
Benefits
- Templates are self-documenting about the exact transform being applied
- Adding new casing variants requires changing one place only
contextSchemaintemplate.jsoncan be simplified or removed entirely- Eliminates naming confusion between variants
Migration
The existing componentNameCamelCase, componentNameCapitalCase, etc. variables can be kept as aliases during a transition period, then deprecated.
Related
- Surfaced during review of Fix ace-data-visualization: use correct EJS variables for registry IDs and chunk name #71 (ace-data-visualization registry ID fix, where
componentNameAllCapshad to be added ad-hoc)