diff --git a/e2e/angular-extensions/src/misc.test.ts b/e2e/angular-extensions/src/misc.test.ts index e02c618b8e..7b3b72c982 100644 --- a/e2e/angular-extensions/src/misc.test.ts +++ b/e2e/angular-extensions/src/misc.test.ts @@ -7,7 +7,7 @@ import { uniq, updateFile, } from '@nrwl/e2e/utils'; -import { classify } from '@nrwl/workspace/src/utils/strings'; +import { classify } from '@nrwl/devkit/src/utils/string-utils'; describe('Move Angular Project', () => { let proj: string; diff --git a/e2e/next/src/next.test.ts b/e2e/next/src/next.test.ts index 8987c45cbb..663d85c00e 100644 --- a/e2e/next/src/next.test.ts +++ b/e2e/next/src/next.test.ts @@ -1,4 +1,5 @@ import { detectPackageManager, joinPathFragments } from '@nrwl/devkit'; +import { capitalize } from '@nrwl/devkit/src/utils/string-utils'; import { checkFilesExist, cleanupProject, @@ -17,7 +18,6 @@ import { updateFile, updateProjectConfig, } from '@nrwl/e2e/utils'; -import { stringUtils } from '@nrwl/workspace'; import * as http from 'http'; import { checkApp } from './utils'; @@ -111,7 +111,7 @@ describe('Next.js Applications', () => { import dynamic from 'next/dynamic'; const TestComponent = dynamic( - () => import('@${proj}/${nextLib}').then(d => d.${stringUtils.capitalize( + () => import('@${proj}/${nextLib}').then(d => d.${capitalize( nextLib )}) ); diff --git a/packages/angular/src/generators/add-linting/angular-v14/lib/create-eslint-configuration.ts b/packages/angular/src/generators/add-linting/angular-v14/lib/create-eslint-configuration.ts index e7c2060175..786a2f3efe 100644 --- a/packages/angular/src/generators/add-linting/angular-v14/lib/create-eslint-configuration.ts +++ b/packages/angular/src/generators/add-linting/angular-v14/lib/create-eslint-configuration.ts @@ -1,8 +1,8 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, offsetFromRoot, writeJson } from '@nrwl/devkit'; -import { camelize, dasherize } from '@nrwl/workspace/src/utils/strings'; import type { Linter } from 'eslint'; import type { AddLintingGeneratorSchema } from '../schema'; +import { camelize, dasherize } from '@nrwl/devkit/src/utils/string-utils'; type EslintExtensionSchema = { prefix: string; diff --git a/packages/angular/src/generators/add-linting/lib/create-eslint-configuration.ts b/packages/angular/src/generators/add-linting/lib/create-eslint-configuration.ts index e7c2060175..786a2f3efe 100644 --- a/packages/angular/src/generators/add-linting/lib/create-eslint-configuration.ts +++ b/packages/angular/src/generators/add-linting/lib/create-eslint-configuration.ts @@ -1,8 +1,8 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, offsetFromRoot, writeJson } from '@nrwl/devkit'; -import { camelize, dasherize } from '@nrwl/workspace/src/utils/strings'; import type { Linter } from 'eslint'; import type { AddLintingGeneratorSchema } from '../schema'; +import { camelize, dasherize } from '@nrwl/devkit/src/utils/string-utils'; type EslintExtensionSchema = { prefix: string; diff --git a/packages/devkit/src/utils/string-utils.spec.ts b/packages/devkit/src/utils/string-utils.spec.ts new file mode 100644 index 0000000000..2f060e26fe --- /dev/null +++ b/packages/devkit/src/utils/string-utils.spec.ts @@ -0,0 +1,63 @@ +import { classify, dasherize } from './string-utils'; + +describe('String utils', () => { + describe('dasherize', () => { + it('should format camel casing', () => { + expect(dasherize('twoWords')).toEqual('two-words'); + }); + + it('should camel casing with abbreviations', () => { + expect(dasherize('twoWORDS')).toEqual('two-words'); + }); + + it('should format spaces', () => { + expect(dasherize('two words')).toEqual('two-words'); + }); + + it('should format underscores', () => { + expect(dasherize('two_words')).toEqual('two-words'); + }); + + it('should format periods', () => { + expect(dasherize('two.words')).toEqual('two-words'); + }); + + it('should format dashes', () => { + expect(dasherize('two-words')).toEqual('two-words'); + }); + + it('should return single words', () => { + expect(dasherize('word')).toEqual('word'); + }); + }); + + describe('classify', () => { + it('should format camel casing', () => { + expect(classify('twoWords')).toEqual('TwoWords'); + }); + + it('should camel casing with abbreviations', () => { + expect(classify('twoWORDS')).toEqual('TwoWORDS'); + }); + + it('should format spaces', () => { + expect(classify('two words')).toEqual('TwoWords'); + }); + + it('should format underscores', () => { + expect(classify('two_words')).toEqual('TwoWords'); + }); + + it('should format periods', () => { + expect(classify('two.words')).toEqual('Two.Words'); + }); + + it('should format dashes', () => { + expect(classify('two-words')).toEqual('TwoWords'); + }); + + it('should return single words', () => { + expect(classify('word')).toEqual('Word'); + }); + }); +}); diff --git a/packages/devkit/src/utils/string-utils.ts b/packages/devkit/src/utils/string-utils.ts new file mode 100644 index 0000000000..300d399e50 --- /dev/null +++ b/packages/devkit/src/utils/string-utils.ts @@ -0,0 +1,153 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +const STRING_DASHERIZE_REGEXP = /[ _.]/g; +const STRING_DECAMELIZE_REGEXP = /([a-z\d])([A-Z])/g; +const STRING_CAMELIZE_REGEXP = /(-|_|\.|\s)+(.)?/g; +const STRING_UNDERSCORE_REGEXP_1 = /([a-z\d])([A-Z]+)/g; +const STRING_UNDERSCORE_REGEXP_2 = /-|\s+/g; + +/** + * Converts a camelized string into all lower case separated by underscores. + * + ```javascript + decamelize('innerHTML'); // 'inner_html' + decamelize('action_name'); // 'action_name' + decamelize('css-class-name'); // 'css-class-name' + decamelize('my favorite items'); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ +export function decamelize(str: string): string { + return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); +} + +/** + Replaces underscores, spaces, periods, or camelCase with dashes. + + ```javascript + dasherize('innerHTML'); // 'inner-html' + dasherize('action_name'); // 'action-name' + dasherize('css-class-name'); // 'css-class-name' + dasherize('my favorite items'); // 'my-favorite-items' + dasherize('nrwl.io'); // 'nrwl-io' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ +export function dasherize(str?: string): string { + return decamelize(str || '').replace(STRING_DASHERIZE_REGEXP, '-'); +} + +/** + Returns the lowerCamelCase form of a string. + + ```javascript + camelize('innerHTML'); // 'innerHTML' + camelize('action_name'); // 'actionName' + camelize('css-class-name'); // 'cssClassName' + camelize('my favorite items'); // 'myFavoriteItems' + camelize('My Favorite Items'); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ +export function camelize(str: string): string { + return str + .replace( + STRING_CAMELIZE_REGEXP, + (_match: string, _separator: string, chr: string) => { + return chr ? chr.toUpperCase() : ''; + } + ) + .replace(/^([A-Z])/, (match: string) => match.toLowerCase()); +} + +/** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ +export function classify(str: string): string { + return str + .split('.') + .map((part) => capitalize(camelize(part))) + .join('.'); +} + +/** + More general than decamelize. Returns the lower\_case\_and\_underscored + form of a string. + + ```javascript + 'innerHTML'.underscore(); // 'inner_html' + 'action_name'.underscore(); // 'action_name' + 'css-class-name'.underscore(); // 'css_class_name' + 'my favorite items'.underscore(); // 'my_favorite_items' + ``` + + @method underscore + @param {String} str The string to underscore. + @return {String} the underscored string. + */ +export function underscore(str: string): string { + return str + .replace(STRING_UNDERSCORE_REGEXP_1, '$1_$2') + .replace(STRING_UNDERSCORE_REGEXP_2, '_') + .toLowerCase(); +} + +/** + Returns the Capitalized form of a string + + ```javascript + 'innerHTML'.capitalize() // 'InnerHTML' + 'action_name'.capitalize() // 'Action_name' + 'css-class-name'.capitalize() // 'Css-class-name' + 'my favorite items'.capitalize() // 'My favorite items' + ``` + + @method capitalize + @param {String} str The string to capitalize. + @return {String} The capitalized string. + */ +export function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +export function group(name: string, group: string | undefined): string { + return group ? `${group}/${name}` : name; +} + +export function featurePath( + group: boolean | undefined, + flat: boolean | undefined, + path: string, + name: string +): string { + if (group && !flat) { + return `../../${path}/${name}/`; + } + + return group ? `../${path}/` : './'; +} diff --git a/packages/linter/src/generators/workspace-rule/workspace-rule.ts b/packages/linter/src/generators/workspace-rule/workspace-rule.ts index fe7ede7de9..b34537f8a9 100644 --- a/packages/linter/src/generators/workspace-rule/workspace-rule.ts +++ b/packages/linter/src/generators/workspace-rule/workspace-rule.ts @@ -8,7 +8,7 @@ import { logger, Tree, } from '@nrwl/devkit'; -import { camelize } from '@nrwl/workspace/src/utils/strings'; +import { camelize } from '@nrwl/devkit/src/utils/string-utils'; import { join } from 'path'; import * as ts from 'typescript'; import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules'; diff --git a/packages/workspace/src/utils/strings.ts b/packages/workspace/src/utils/strings.ts index 140fe1c3e8..83e2b58674 100644 --- a/packages/workspace/src/utils/strings.ts +++ b/packages/workspace/src/utils/strings.ts @@ -22,6 +22,7 @@ const STRING_UNDERSCORE_REGEXP_2 = /-|\s+/g; ``` @method decamelize + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str The string to decamelize. @return {String} the decamelized string. */ @@ -41,6 +42,7 @@ export function decamelize(str: string): string { ``` @method dasherize + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str The string to dasherize. @return {String} the dasherized string. */ @@ -60,6 +62,7 @@ export function dasherize(str?: string): string { ``` @method camelize + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str The string to camelize. @return {String} the camelized string. */ @@ -85,6 +88,7 @@ export function camelize(str: string): string { ``` @method classify + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str the string to classify @return {String} the classified string */ @@ -107,6 +111,7 @@ export function classify(str: string): string { ``` @method underscore + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str The string to underscore. @return {String} the underscored string. */ @@ -128,6 +133,7 @@ export function underscore(str: string): string { ``` @method capitalize + @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. @param {String} str The string to capitalize. @return {String} The capitalized string. */ @@ -135,10 +141,16 @@ export function capitalize(str: string): string { return str.charAt(0).toUpperCase() + str.slice(1); } +/** + * @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. + */ export function group(name: string, group: string | undefined) { return group ? `${group}/${name}` : name; } +/** + * @deprecated This will be removed from `@nrwl/workspace` in version 17. Prefer `@nrwl/js` when importing. + */ export function featurePath( group: boolean | undefined, flat: boolean | undefined,