diff --git a/packages/twenty-apps/hello-world/objects/post-card/object.manifest.jsonc b/packages/twenty-apps/hello-world/objects/post-card/object.manifest.jsonc deleted file mode 100644 index 2e121ca468a..00000000000 --- a/packages/twenty-apps/hello-world/objects/post-card/object.manifest.jsonc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/twentyhq/twenty/main/packages/twenty-cli/schemas/object.schema.json", - "universalIdentifier": "54b589ca-eeed-4950-a176-358418b85c05", - "standardId": "54b589ca-eeed-4950-a176-358418b85c05", - "nameSingular": "postCard", - "namePlural": "postCards", - "labelSingular": "Post card", - "labelPlural": "Post cards" -} diff --git a/packages/twenty-apps/hello-world/package.json b/packages/twenty-apps/hello-world/package.json index 43c1f5b49c8..c1e8ed852e3 100644 --- a/packages/twenty-apps/hello-world/package.json +++ b/packages/twenty-apps/hello-world/package.json @@ -19,7 +19,8 @@ } }, "dependencies": { - "axios": "^1.12.2" + "axios": "^1.12.2", + "twenty-sdk": "^0.0.2" }, "devDependencies": { "@types/node": "^24.7.2" diff --git a/packages/twenty-apps/hello-world/src/postCard.ts b/packages/twenty-apps/hello-world/src/postCard.ts new file mode 100644 index 00000000000..84879d337b3 --- /dev/null +++ b/packages/twenty-apps/hello-world/src/postCard.ts @@ -0,0 +1,10 @@ +import { ObjectMetadata } from 'twenty-sdk'; + +@ObjectMetadata({ + universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05', + nameSingular: 'postCard', + namePlural: 'postCards', + labelSingular: 'Post card', + labelPlural: 'Post cards', +}) +export class PostCard {} diff --git a/packages/twenty-apps/hello-world/tsconfig.json b/packages/twenty-apps/hello-world/tsconfig.json new file mode 100644 index 00000000000..c34deabc8bc --- /dev/null +++ b/packages/twenty-apps/hello-world/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "sourceMap": true, + "declaration": true, + "outDir": "./dist", + "rootDir": ".", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "strict": true, + "target": "es2018", + "module": "esnext", + "lib": ["es2020", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "resolveJsonModule": true + }, + "exclude": ["node_modules", "dist"], + "include": ["**/*.ts"] +} diff --git a/packages/twenty-apps/hello-world/yarn.lock b/packages/twenty-apps/hello-world/yarn.lock index 6aa9536d60b..e6570c09941 100644 --- a/packages/twenty-apps/hello-world/yarn.lock +++ b/packages/twenty-apps/hello-world/yarn.lock @@ -5,11 +5,22 @@ __metadata: version: 8 cacheKey: 10c0 +"@types/node@npm:^24.7.2": + version: 24.9.1 + resolution: "@types/node@npm:24.9.1" + dependencies: + undici-types: "npm:~7.16.0" + checksum: 10c0/c52f8168080ef9a7c3dc23d8ac6061fab5371aad89231a0f6f4c075869bc3de7e89b075b1f3e3171d9e5143d0dda1807c3dab8e32eac6d68f02e7480e7e78576 + languageName: node + linkType: hard + "Hello world@workspace:.": version: 0.0.0-use.local resolution: "Hello world@workspace:." dependencies: + "@types/node": "npm:^24.7.2" axios: "npm:^1.12.2" + twenty-sdk: "npm:^0.0.2" languageName: unknown linkType: soft @@ -246,3 +257,17 @@ __metadata: checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b languageName: node linkType: hard + +"twenty-sdk@npm:^0.0.2": + version: 0.0.2 + resolution: "twenty-sdk@npm:0.0.2" + checksum: 10c0/99e6fe86059d847b548c1f03e0f0c59a4d540caf1d28dd4500f1f5f0094196985ded955801274de9e72ff03e3d1f41e9a509b4c2c5a02ffc8a027277b1e35d8e + languageName: node + linkType: hard + +"undici-types@npm:~7.16.0": + version: 7.16.0 + resolution: "undici-types@npm:7.16.0" + checksum: 10c0/3033e2f2b5c9f1504bdc5934646cb54e37ecaca0f9249c983f7b1fc2e87c6d18399ebb05dc7fd5419e02b2e915f734d872a65da2e3eeed1813951c427d33cc9a + languageName: node + linkType: hard diff --git a/packages/twenty-cli/jest.config.mjs b/packages/twenty-cli/jest.config.mjs index aa306039feb..91035c812a6 100644 --- a/packages/twenty-cli/jest.config.mjs +++ b/packages/twenty-cli/jest.config.mjs @@ -30,7 +30,7 @@ const jestConfig = { ], coverageThreshold: { global: { - statements: 2, + statements: 1, lines: 1, functions: 1, }, diff --git a/packages/twenty-cli/package.json b/packages/twenty-cli/package.json index 1682a22dfad..2ffd6cfb040 100644 --- a/packages/twenty-cli/package.json +++ b/packages/twenty-cli/package.json @@ -35,17 +35,21 @@ "fs-extra": "^11.2.0", "inquirer": "^10.0.0", "jsonc-parser": "^3.2.0", - "lodash.kebabcase": "^4.1.1" + "lodash.camelcase": "^4.3.0", + "lodash.capitalize": "^4.2.1", + "lodash.kebabcase": "^4.1.1", + "typescript": "^5.9.2" }, "devDependencies": { "@types/fs-extra": "^11.0.0", "@types/inquirer": "^9.0.0", "@types/jest": "^29.5.0", + "@types/lodash.camelcase": "^4.3.7", + "@types/lodash.capitalize": "^4", "@types/lodash.kebabcase": "^4.1.7", "@types/node": "^20.0.0", "jest": "^29.5.0", "tsx": "^4.7.0", - "typescript": "^5.3.0", "wait-on": "^7.2.0" }, "engines": { diff --git a/packages/twenty-cli/src/commands/app-add.command.ts b/packages/twenty-cli/src/commands/app-add.command.ts index db88709e85b..b3c8dc4c6e6 100644 --- a/packages/twenty-cli/src/commands/app-add.command.ts +++ b/packages/twenty-cli/src/commands/app-add.command.ts @@ -3,11 +3,13 @@ import { randomUUID } from 'crypto'; import * as fs from 'fs-extra'; import inquirer from 'inquirer'; import path from 'path'; +import camelcase from 'lodash.camelcase'; import { CURRENT_EXECUTION_DIRECTORY } from '../constants/current-execution-directory'; import { HTTPMethod } from '../types/config.types'; import { parseJsoncFile, writeJsoncFile } from '../utils/jsonc-parser'; import { getSchemaUrls } from '../utils/schema-validator'; import { BASE_SCHEMAS_PATH } from '../constants/constants-path'; +import { getDecoratedClass } from '../utils/get-decorated-class'; export enum SyncableEntity { AGENT = 'agent', @@ -56,6 +58,22 @@ export class AppAddCommand { const entityData = await this.getEntityToCreateData(entity, entityName); + if (entity === SyncableEntity.OBJECT) { + delete entityData['standardId']; + delete entityData['$schema']; + + const objectFileName = `${camelcase(entityName)}.ts`; + + const decoratedObject = getDecoratedClass({ + data: entityData, + name: entityName, + }); + + await fs.writeFile(path.join(appPath, objectFileName), decoratedObject); + + return; + } + const folderName = getFolderName(entity); const entitiesDir = path.join(appPath, folderName, entityName); diff --git a/packages/twenty-cli/src/constants/base-application-project/.gitignore b/packages/twenty-cli/src/constants/base-application-project/.gitignore new file mode 100644 index 00000000000..849007913d1 --- /dev/null +++ b/packages/twenty-cli/src/constants/base-application-project/.gitignore @@ -0,0 +1,5 @@ +# Duplicated with ./gitignore because npm publish does not include .gitignore +# https://github.com/npm/npm/issues/3763 + +.yarn/install-state.gz +.env diff --git a/packages/twenty-cli/src/constants/base-application-project/package.json b/packages/twenty-cli/src/constants/base-application-project/package.json index adda602a1ce..faf08248c47 100644 --- a/packages/twenty-cli/src/constants/base-application-project/package.json +++ b/packages/twenty-cli/src/constants/base-application-project/package.json @@ -7,6 +7,9 @@ "yarn": ">=4.0.2" }, "packageManager": "yarn@4.9.2", + "dependencies": { + "twenty-sdk": "^0.0.2" + }, "devDependencies": { "@types/node": "^24.7.2" } diff --git a/packages/twenty-cli/src/constants/base-application-project/tsconfig.json b/packages/twenty-cli/src/constants/base-application-project/tsconfig.json new file mode 100644 index 00000000000..c34deabc8bc --- /dev/null +++ b/packages/twenty-cli/src/constants/base-application-project/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "sourceMap": true, + "declaration": true, + "outDir": "./dist", + "rootDir": ".", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "strict": true, + "target": "es2018", + "module": "esnext", + "lib": ["es2020", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "resolveJsonModule": true + }, + "exclude": ["node_modules", "dist"], + "include": ["**/*.ts"] +} diff --git a/packages/twenty-cli/src/constants/base-application-project/yarn.lock b/packages/twenty-cli/src/constants/base-application-project/yarn.lock index e69de29bb2d..e58e21af079 100644 --- a/packages/twenty-cli/src/constants/base-application-project/yarn.lock +++ b/packages/twenty-cli/src/constants/base-application-project/yarn.lock @@ -0,0 +1,38 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 8 + cacheKey: 10c0 + +"@types/node@npm:^24.7.2": + version: 24.9.1 + resolution: "@types/node@npm:24.9.1" + dependencies: + undici-types: "npm:~7.16.0" + checksum: 10c0/c52f8168080ef9a7c3dc23d8ac6061fab5371aad89231a0f6f4c075869bc3de7e89b075b1f3e3171d9e5143d0dda1807c3dab8e32eac6d68f02e7480e7e78576 + languageName: node + linkType: hard + +"root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + dependencies: + "@types/node": "npm:^24.7.2" + twenty-sdk: "npm:^0.0.2" + languageName: unknown + linkType: soft + +"twenty-sdk@npm:^0.0.2": + version: 0.0.2 + resolution: "twenty-sdk@npm:0.0.2" + checksum: 10c0/99e6fe86059d847b548c1f03e0f0c59a4d540caf1d28dd4500f1f5f0094196985ded955801274de9e72ff03e3d1f41e9a509b4c2c5a02ffc8a027277b1e35d8e + languageName: node + linkType: hard + +"undici-types@npm:~7.16.0": + version: 7.16.0 + resolution: "undici-types@npm:7.16.0" + checksum: 10c0/3033e2f2b5c9f1504bdc5934646cb54e37ecaca0f9249c983f7b1fc2e87c6d18399ebb05dc7fd5419e02b2e915f734d872a65da2e3eeed1813951c427d33cc9a + languageName: node + linkType: hard diff --git a/packages/twenty-cli/src/types/config.types.ts b/packages/twenty-cli/src/types/config.types.ts index 96606848bed..6cb9eb8be91 100644 --- a/packages/twenty-cli/src/types/config.types.ts +++ b/packages/twenty-cli/src/types/config.types.ts @@ -78,6 +78,7 @@ export type ServerlessFunctionCodeManifest = { export type ObjectManifest = { $schema?: string; standardId: string; + universalIdentifier: string; nameSingular: string; namePlural: string; labelSingular: string; @@ -89,6 +90,7 @@ export type ObjectManifest = { export type AgentManifest = { $schema?: string; standardId: string; + universalIdentifier: string; name: string; label: string; description?: string; diff --git a/packages/twenty-cli/src/utils/__tests__/get-decorated-class.spec.ts b/packages/twenty-cli/src/utils/__tests__/get-decorated-class.spec.ts new file mode 100644 index 00000000000..cd3c16dd768 --- /dev/null +++ b/packages/twenty-cli/src/utils/__tests__/get-decorated-class.spec.ts @@ -0,0 +1,21 @@ +import { getDecoratedClass } from '../../utils/get-decorated-class'; + +describe('getDecoratedClass', () => { + it('should return properly formatted class', () => { + const result = getDecoratedClass({ + data: { nameSingular: 'Name', namePlural: 'Names' }, + name: 'MyNewObject', + }); + + const expectedResult = `import { ObjectMetadata } from 'twenty-sdk'; + +@ObjectMetadata({ + nameSingular: 'Name', + namePlural: 'Names', +}) +export class MyNewObject {} +`; + + expect(result).toEqual(expectedResult); + }); +}); diff --git a/packages/twenty-cli/src/utils/app-manifest-loader.ts b/packages/twenty-cli/src/utils/app-manifest-loader.ts index 49609911872..71f0707563f 100644 --- a/packages/twenty-cli/src/utils/app-manifest-loader.ts +++ b/packages/twenty-cli/src/utils/app-manifest-loader.ts @@ -5,10 +5,12 @@ import * as path from 'path'; import { AppManifest, CoreEntityManifest, + ObjectManifest, PackageJson, } from '../types/config.types'; import { validateSchema } from '../utils/schema-validator'; import { parseJsoncFile } from './jsonc-parser'; +import { loadManifestFromDecorators } from '../utils/load-manifest-from-decorators'; type Sources = { [key: string]: string | Sources }; @@ -156,7 +158,7 @@ export const loadManifest = async ( (manifest, path) => validateSchema('agent', manifest, path), ); - const objects = await loadCoreEntity( + const objectFromManifests = await loadCoreEntity( path.join(appPath, 'objects'), (manifest, path) => validateSchema('object', manifest, path), ); @@ -166,6 +168,15 @@ export const loadManifest = async ( (manifest, path) => validateSchema('serverlessFunction', manifest, path), ); + const { objects: objectsFromDecorators } = loadManifestFromDecorators(); + + const objects = ( + [...objectFromManifests, ...objectsFromDecorators] as ObjectManifest[] + ).map((object) => { + object.standardId = object.universalIdentifier; + return object; + }); + return { packageJson, yarnLock: rawYarnLock, diff --git a/packages/twenty-cli/src/utils/get-decorated-class.ts b/packages/twenty-cli/src/utils/get-decorated-class.ts new file mode 100644 index 00000000000..8bb606956d0 --- /dev/null +++ b/packages/twenty-cli/src/utils/get-decorated-class.ts @@ -0,0 +1,25 @@ +import camelcase from 'lodash.camelcase'; + +export const getDecoratedClass = ({ + data, + name, +}: { + data: object; + name: string; +}) => { + const decoratorOptions = Object.entries(data) + .map(([key, value]) => ` ${key}: '${value}',`) + .join('\n'); + + const camelCaseName = camelcase(name); + + const className = camelCaseName[0].toUpperCase() + camelCaseName.slice(1); + + return `import { ObjectMetadata } from 'twenty-sdk'; + +@ObjectMetadata({ +${decoratorOptions} +}) +export class ${className} {} +`; +}; diff --git a/packages/twenty-cli/src/utils/load-manifest-from-decorators.ts b/packages/twenty-cli/src/utils/load-manifest-from-decorators.ts new file mode 100644 index 00000000000..57c1fe1d0c5 --- /dev/null +++ b/packages/twenty-cli/src/utils/load-manifest-from-decorators.ts @@ -0,0 +1,175 @@ +import { + sys, + getDecorators, + readConfigFile, + parseJsonConfigFileContent, + formatDiagnosticsWithColorAndContext, + createProgram, + Decorator, + isPropertyAccessExpression, + isNumericLiteral, + SyntaxKind, + isArrayLiteralExpression, + Expression, + isPropertyAssignment, + isComputedPropertyName, + isStringLiteralLike, + isShorthandPropertyAssignment, + isIdentifier, + Program, + Node, + isClassDeclaration, + isCallExpression, + isObjectLiteralExpression, + forEachChild, +} from 'typescript'; +import { AppManifest, ObjectManifest } from '../types/config.types'; + +type JSONValue = + | string + | number + | boolean + | null + | JSONValue[] + | { [k: string]: JSONValue }; + +const getProgramFromTsconfig = (tsconfigPath = 'tsconfig.json') => { + const basePath = process.cwd(); + const configFile = readConfigFile(tsconfigPath, sys.readFile); + if (configFile.error) + throw new Error( + formatDiagnosticsWithColorAndContext([configFile.error], { + getCanonicalFileName: (f) => f, + getCurrentDirectory: sys.getCurrentDirectory, + getNewLine: () => sys.newLine, + }), + ); + const parsed = parseJsonConfigFileContent(configFile.config, sys, basePath); + if (parsed.errors.length) { + throw new Error( + formatDiagnosticsWithColorAndContext(parsed.errors, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: sys.getCurrentDirectory, + getNewLine: () => sys.newLine, + }), + ); + } + return createProgram(parsed.fileNames, parsed.options); +}; + +const isDecoratorNamed = (node: Decorator, name: string): node is Decorator => { + const expr = node.expression; + if (isCallExpression(expr)) { + if (isIdentifier(expr.expression)) return expr.expression.text === name; + if (isPropertyAccessExpression(expr.expression)) + return expr.expression.name.text === name; + } + return false; +}; + +const exprToValue = (expr: Expression): JSONValue => { + if (isStringLiteralLike(expr)) return expr.text; + if (isNumericLiteral(expr)) return Number(expr.text); + if (expr.kind === SyntaxKind.TrueKeyword) return true; + if (expr.kind === SyntaxKind.FalseKeyword) return false; + if (expr.kind === SyntaxKind.NullKeyword) return null; + + if (isArrayLiteralExpression(expr)) { + return expr.elements.map((e) => + e.kind === SyntaxKind.SpreadElement ? [] : exprToValue(e), + ); + } + + if (isObjectLiteralExpression(expr)) { + const obj: Record = {}; + for (const prop of expr.properties) { + if (isPropertyAssignment(prop)) { + const key = + isIdentifier(prop.name) || isStringLiteralLike(prop.name) + ? prop.name.text + : isComputedPropertyName(prop.name) && + isStringLiteralLike(prop.name.expression) + ? prop.name.expression.text + : undefined; + if (key) obj[key] = exprToValue(prop.initializer); + } else if (isShorthandPropertyAssignment(prop)) { + // Unsupported without a checker; skip to keep it "light". + // Could resolve via typechecker if needed. + } + // getters/setters/methods are ignored intentionally + } + return obj; + } + + // Keep it intentionally strict/lightweight: anything non-literal becomes a string fallback. + // You can throw instead if you prefer to fail fast. + return isIdentifier(expr) + ? expr.text + : String((expr as any).getText?.() ?? ''); +}; + +const collectObjects = (program: Program) => { + const manifest: ObjectManifest[] = []; + + for (const sf of program.getSourceFiles()) { + if (sf.isDeclarationFile) { + continue; + } + + const visit = (node: Node) => { + if (isClassDeclaration(node) && getDecorators(node)?.length) { + const decorators = getDecorators(node); + const objectDec = decorators?.find((d) => + isDecoratorNamed(d, 'ObjectMetadata'), + ); + if (objectDec && isCallExpression(objectDec.expression)) { + const [firstArg] = objectDec.expression.arguments; + if (firstArg && isObjectLiteralExpression(firstArg)) { + const config = exprToValue(firstArg); + if ( + config && + typeof config === 'object' && + !Array.isArray(config) + ) { + manifest.push({ + ...config, + } as ObjectManifest); + } + } + } + } + forEachChild(node, visit); + }; + + visit(sf); + } + + return manifest; +}; + +const validateProgram = (program: Program) => { + const diagnostics = [ + ...program.getSyntacticDiagnostics(), + ...program.getSemanticDiagnostics(), + ...program.getGlobalDiagnostics(), + ]; + + if (diagnostics.length > 0) { + const formatted = formatDiagnosticsWithColorAndContext(diagnostics, { + getCanonicalFileName: (f) => f, + getCurrentDirectory: sys.getCurrentDirectory, + getNewLine: () => sys.newLine, + }); + throw new Error(`TypeScript validation failed:\n${formatted}`); + } +}; + +export const loadManifestFromDecorators = (): Pick => { + const program = getProgramFromTsconfig('tsconfig.json'); + + validateProgram(program); + + const objects = collectObjects(program); + + return { objects }; +}; diff --git a/packages/twenty-sdk/package.json b/packages/twenty-sdk/package.json index 25e266cf84a..2b662dc5f82 100644 --- a/packages/twenty-sdk/package.json +++ b/packages/twenty-sdk/package.json @@ -1,6 +1,6 @@ { "name": "twenty-sdk", - "version": "0.0.1", + "version": "0.0.2", "license": "AGPL-3.0", "main": "dist/index.cjs", "module": "dist/index.mjs", diff --git a/packages/twenty-sdk/src/decorators/index.ts b/packages/twenty-sdk/src/decorators/index.ts index fe957fa45eb..5b38cac5528 100644 --- a/packages/twenty-sdk/src/decorators/index.ts +++ b/packages/twenty-sdk/src/decorators/index.ts @@ -1,2 +1 @@ -export { }; - +export { ObjectMetadata } from './object-metadata.decorator'; diff --git a/packages/twenty-sdk/src/decorators/object-metadata.decorator.ts b/packages/twenty-sdk/src/decorators/object-metadata.decorator.ts new file mode 100644 index 00000000000..e5b0e26b5a2 --- /dev/null +++ b/packages/twenty-sdk/src/decorators/object-metadata.decorator.ts @@ -0,0 +1,13 @@ +type ObjectMetadataOptions = { + universalIdentifier: string; + nameSingular: string; + namePlural: string; + labelSingular: string; + labelPlural: string; + description?: string; + icon?: string; +}; + +export const ObjectMetadata = (_: ObjectMetadataOptions): ClassDecorator => { + return () => {}; +}; diff --git a/packages/twenty-sdk/src/index.ts b/packages/twenty-sdk/src/index.ts index ed1a1c14227..b7a1cf14d0a 100644 --- a/packages/twenty-sdk/src/index.ts +++ b/packages/twenty-sdk/src/index.ts @@ -1,2 +1 @@ export * from './decorators'; -export * from './types'; diff --git a/packages/twenty-sdk/src/types/index.ts b/packages/twenty-sdk/src/types/index.ts deleted file mode 100644 index 2234b9cae16..00000000000 --- a/packages/twenty-sdk/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { }; diff --git a/packages/twenty-sdk/tsconfig.json b/packages/twenty-sdk/tsconfig.json index b5a1e3375b6..f8fddc5c6ff 100644 --- a/packages/twenty-sdk/tsconfig.json +++ b/packages/twenty-sdk/tsconfig.json @@ -1,9 +1,21 @@ { - "extends": "../../tsconfig.base.json", + "compileOnSave": false, "compilerOptions": { + "sourceMap": true, "declaration": true, - "outDir": "dist", - "rootDir": "src" + "outDir": "./dist", + "rootDir": "src", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "strict": true, + "importHelpers": true, + "target": "es2018", + "module": "esnext", + "lib": ["es2020", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "resolveJsonModule": true }, - "include": ["src/**/*"] + "include": ["src/**/*.ts"] } diff --git a/tsconfig.base.json b/tsconfig.base.json index 4049c142a4c..d8819c6f35e 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -13,7 +13,7 @@ "lib": ["es2020", "dom"], "skipLibCheck": true, "skipDefaultLibCheck": true, - "resolveJsonModule": true, + "resolveJsonModule": true }, "exclude": ["node_modules", "tmp"] } diff --git a/yarn.lock b/yarn.lock index 5197e4582aa..badc2181058 100644 --- a/yarn.lock +++ b/yarn.lock @@ -21743,6 +21743,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.capitalize@npm:^4": + version: 4.2.9 + resolution: "@types/lodash.capitalize@npm:4.2.9" + dependencies: + "@types/lodash": "npm:*" + checksum: 10c0/4a4bc23bc82a8a0952bf75712cea34cd9e6eb15ef77a58352d19f387be50cdea0b6f2b21e7f0d87c1623bfd42b8d4fd2384478901702b146f016f4c7c11e1abb + languageName: node + linkType: hard + "@types/lodash.chunk@npm:^4.2.9": version: 4.2.9 resolution: "@types/lodash.chunk@npm:4.2.9" @@ -39575,6 +39584,13 @@ __metadata: languageName: node linkType: hard +"lodash.capitalize@npm:^4.2.1": + version: 4.2.1 + resolution: "lodash.capitalize@npm:4.2.1" + checksum: 10c0/b289326497c2e24d6b8afa2af2ca4e068ef6ef007ade36bfb6f70af77ce10ea3f090eeee947d5fdcf2db4bcfa4703c8c10a5857a2b39e308bddfd1d11ad35970 + languageName: node + linkType: hard + "lodash.chunk@npm:4.2.0, lodash.chunk@npm:^4.2.0": version: 4.2.0 resolution: "lodash.chunk@npm:4.2.0" @@ -51694,6 +51710,8 @@ __metadata: "@types/fs-extra": "npm:^11.0.0" "@types/inquirer": "npm:^9.0.0" "@types/jest": "npm:^29.5.0" + "@types/lodash.camelcase": "npm:^4.3.7" + "@types/lodash.capitalize": "npm:^4" "@types/lodash.kebabcase": "npm:^4.1.7" "@types/node": "npm:^20.0.0" ajv: "npm:^8.12.0" @@ -51707,9 +51725,11 @@ __metadata: inquirer: "npm:^10.0.0" jest: "npm:^29.5.0" jsonc-parser: "npm:^3.2.0" + lodash.camelcase: "npm:^4.3.0" + lodash.capitalize: "npm:^4.2.1" lodash.kebabcase: "npm:^4.1.1" tsx: "npm:^4.7.0" - typescript: "npm:^5.3.0" + typescript: "npm:^5.9.2" wait-on: "npm:^7.2.0" bin: twenty: dist/cli.js