From b1c516da49cb06a8792c0f11e47fa44cfcd52bf5 Mon Sep 17 00:00:00 2001 From: Charlie Greenman Date: Sun, 8 Sep 2024 00:27:23 -0400 Subject: [PATCH] fix --- package-lock.json | 4 +- src/replace.spec.ts | 95 +++++++++++++++++++++++++-------------------- src/replace.ts | 42 +++++++++++++------- tsconfig.json | 71 --------------------------------- 4 files changed, 82 insertions(+), 130 deletions(-) delete mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index e4269a7..d0b075e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@codemorph/core", - "version": "1.5.3", + "version": "1.6.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@codemorph/core", - "version": "1.5.3", + "version": "1.6.3", "license": "RAZROO", "workspaces": [ "src/rz/angular" diff --git a/src/replace.spec.ts b/src/replace.spec.ts index eb6e43d..bd651c7 100644 --- a/src/replace.spec.ts +++ b/src/replace.spec.ts @@ -73,50 +73,61 @@ describe('replace', () => { expect(result).toEqual(expectedResult); }); - describe('parseEJSCode', () => { - it('should replace tag parameters', () => { - const mockParameters = { - name: 'test', - selector: 'test-two', - className: '' - }; - const mockString = `hello <%= name %>`; - const result = parseEJSCode(mockParameters, mockString); - expect(result).toEqual('hello test'); - }); - it('parseEJSCode should parse for loop correctly', () => { - const mockParameters = { - colors: ['blue', 'green', 'red', 'yellow'], - }; - const mockFileString = "import x from 'y';\nclass DynamicClass = {\n<% for(let i=0; i\n<%= colors[i] %>: string;\n<% } %>\n}"; - - const result = parseEJSCode(mockParameters as any, mockFileString); - const expected = "import x from 'y';\nclass DynamicClass = {\n\nblue: string;\n\ngreen: string;\n\nred: string;\n\nyellow: string;\n\n}"; - expect(result).toEqual(expected); - }); + it('should remove beginning forward slash if null value', () => { + const mockParameters = { + name: 'blue', + nameFilePath: '', + } + const mockFileStringWithCurlyBrace = '{nameFilePath}/{name}.mock.ts'; + const result = replaceCurlyBrace(mockParameters, mockFileStringWithCurlyBrace, true); + const expected = 'blue.mock.ts'; + expect(result).toEqual(expected); + }); - it('parseEJSCode should parse object loop correctly', () => { - const mockParameters = { - "nameSchema":{"Stepper":{"title":"String","id":"ID","count":"Int","recipeId":"String"}} - } - const mockFileString = `<% const schema = Object.values(nameSchema)[0] %> - export interface <%= Object.keys(nameSchema)[0] %> {<% for (const prop in schema) { %> - <%= prop %>: <%= schema[prop] %>;<% } %> - } - `; - - const result = parseEJSCode(mockParameters as any, mockFileString); - const expected = ` - export interface Stepper { - title: String; - id: ID; - count: Int; - recipeId: String; - } - `; - expect(result).toEqual(expected); - }); + }); + + describe('parseEJSCode', () => { + it('should replace tag parameters', () => { + const mockParameters = { + name: 'test', + selector: 'test-two', + className: '' + }; + const mockString = `hello <%= name %>`; + const result = parseEJSCode(mockParameters, mockString); + expect(result).toEqual('hello test'); }); + it('parseEJSCode should parse for loop correctly', () => { + const mockParameters = { + colors: ['blue', 'green', 'red', 'yellow'], + }; + const mockFileString = "import x from 'y';\nclass DynamicClass = {\n<% for(let i=0; i\n<%= colors[i] %>: string;\n<% } %>\n}"; + const result = parseEJSCode(mockParameters as any, mockFileString); + const expected = "import x from 'y';\nclass DynamicClass = {\n\nblue: string;\n\ngreen: string;\n\nred: string;\n\nyellow: string;\n\n}"; + expect(result).toEqual(expected); + }); + + it('parseEJSCode should parse object loop correctly', () => { + const mockParameters = { + "nameSchema":{"Stepper":{"title":"String","id":"ID","count":"Int","recipeId":"String"}} + } + const mockFileString = `<% const schema = Object.values(nameSchema)[0] %> + export interface <%= Object.keys(nameSchema)[0] %> {<% for (const prop in schema) { %> + <%= prop %>: <%= schema[prop] %>;<% } %> + } + `; + + const result = parseEJSCode(mockParameters as any, mockFileString); + const expected = ` + export interface Stepper { + title: String; + id: ID; + count: Int; + recipeId: String; + } + `; + expect(result).toEqual(expected); + }); }); }); diff --git a/src/replace.ts b/src/replace.ts index 69c62a0..164ea0c 100644 --- a/src/replace.ts +++ b/src/replace.ts @@ -21,27 +21,39 @@ export const parseEJSCode = ( return ejs.render(toReplace, parameters) } -export const replaceCurlyBrace = (mockParameters: Record, mockFileStringWithCurlyBrace: string, useKebabCase?: boolean): string => { +export const replaceCurlyBrace = (mockParameters: Record, mockFileStringWithCurlyBrace: string, useKebabCase?: boolean): string => { let result = mockFileStringWithCurlyBrace; - for(const key in mockParameters) { - // only use kebab case if non file path + const processValue = (value: any, useKebabCase: boolean): string => { + if (value === null || value === undefined) return 'null'; + if (typeof value === 'string') { + if (useKebabCase && !value.includes('/')) { + return kebabCase(value); + } + return value; + } + return String(value); + }; + + for (const key in mockParameters) { const value = mockParameters[key]; - const isString = typeof value === 'string'; - const valueToReplaceWith = useKebabCase && isString && value.split('/').length < 2 ? kebabCase(value) : value; - result = result.replace(new RegExp(`{${key}}`, 'g'), valueToReplaceWith); + const processedValue = processValue(value, useKebabCase || false); + result = result.replace(new RegExp(`{${key}}`, 'g'), processedValue); } - const hasCurlyBrace = /{.*}/; - if (hasCurlyBrace.test(result)) { - for(const key in mockParameters) { - // only use kebab case if non file path + + // Handle nested curly braces + while (/{.*}/.test(result)) { + for (const key in mockParameters) { const value = mockParameters[key]; - const isString = typeof value === 'string'; - const valueToReplaceWith = useKebabCase && isString && value.split('/').length < 2 ? kebabCase(value) : value; - result = result.replace(new RegExp(`{${key}}`, 'g'), valueToReplaceWith); + const processedValue = processValue(value, useKebabCase || false); + result = result.replace(new RegExp(`{${key}}`, 'g'), processedValue); } } - return result; -} + // Remove leading forward slash if present + result = result.replace(/^\//, ''); + // Remove any remaining empty path segments + result = result.replace(/\/+/g, '/').replace(/^\/|\/$/g, ''); + return result; +} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 956508f..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Basic Options */ - // "incremental": true, /* Enable incremental compilation */ - "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, - "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, - "lib": ["ES2021"], /* Specify library files to be included in the compilation. */ - // "allowJs": true, /* Allow javascript files to be compiled. */ - // "checkJs": true, /* Report errors in .js files. */ - // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ - "declaration": true /* Generates corresponding '.d.ts' file. */, - // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - // "sourceMap": true, /* Generates corresponding '.map' file. */ - // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist" /* Redirect output structure to the directory. */, - // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ - // "composite": true, /* Enable project compilation */ - // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ - // "removeComments": true, /* Do not emit comments to output. */ - // "noEmit": true, /* Do not emit outputs. */ - "importHelpers": true, /* Import emit helpers from 'tslib'. */ - // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ - // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - - /* Strict Type-Checking Options */ - "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ - "strictNullChecks": false, /* Enable strict null checks. */ - // "strictFunctionTypes": true, /* Enable strict checking of function types. */ - // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ - // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ - // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - - /* Additional Checks */ - // "noUnusedLocals": true, /* Report errors on unused locals. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "resolveJsonModule": true, - "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ - // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ - // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - // "typeRoots": [], /* List of folders to include type definitions from. */ - "types": ["node", "jest"], /* Type declaration files to be included in compilation. */ - // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, - // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - - /* Source Map Options */ - // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ - // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - - /* Experimental Options */ - "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ - "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - - /* Advanced Options */ - "skipLibCheck": true /* Skip type checking of declaration files. */, - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ - }, - "include": ["src"], - "exclude": ["node_modules", "**/__tests__/*", "**/*.spec.ts", "**/*.test.ts", "**/*_spec.ts", "**/*_test.ts"] -}