[REFACTOR] twenty-shared multi barrel and CJS/ESM build with preconstruct (#11083)
# Introduction In this PR we've migrated `twenty-shared` from a `vite` app [libary-mode](https://vite.dev/guide/build#library-mode) to a [preconstruct](https://preconstruct.tools/) "atomic" application ( in the future would like to introduce preconstruct to handle of all our atomic dependencies such as `twenty-emails` `twenty-ui` etc it will be integrated at the monorepo's root directly, would be to invasive in the first, starting incremental via `twenty-shared`) For more information regarding the motivations please refer to nor: - https://github.com/twentyhq/core-team-issues/issues/587 - https://github.com/twentyhq/core-team-issues/issues/281#issuecomment-2630949682 close https://github.com/twentyhq/core-team-issues/issues/589 close https://github.com/twentyhq/core-team-issues/issues/590 ## How to test In order to ease the review this PR will ship all the codegen at the very end, the actual meaning full diff is `+2,411 −114` In order to migrate existing dependent packages to `twenty-shared` multi barrel new arch you need to run in local: ```sh yarn tsx packages/twenty-shared/scripts/migrateFromSingleToMultiBarrelImport.ts && \ npx nx run-many -t lint --fix -p twenty-front twenty-ui twenty-server twenty-emails twenty-shared twenty-zapier ``` Note that `migrateFromSingleToMultiBarrelImport` is idempotent, it's atm included in the PR but should not be merged. ( such as codegen will be added before merging this script will be removed ) ## Misc - related opened issue preconstruct https://github.com/preconstruct/preconstruct/issues/617 ## Closed related PR - https://github.com/twentyhq/twenty/pull/11028 - https://github.com/twentyhq/twenty/pull/10993 - https://github.com/twentyhq/twenty/pull/10960 ## Upcoming enhancement: ( in others dedicated PRs ) - 1/ refactor generate barrel to export atomic module instead of `*` - 2/ generate barrel own package with several files and tests - 3/ Migration twenty-ui the same way - 4/ Use `preconstruct` at monorepo global level ## Conclusion As always any suggestions are welcomed !
This commit is contained in:
15
packages/twenty-shared/.babelrc
Normal file
15
packages/twenty-shared/.babelrc
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/babelrc.json",
|
||||
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
|
||||
"plugins": [
|
||||
[
|
||||
"module-resolver",
|
||||
{
|
||||
"root": ["./"],
|
||||
"alias": {
|
||||
"@": "./src"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
4
packages/twenty-shared/constants/package.json
Normal file
4
packages/twenty-shared/constants/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-constants.cjs.js",
|
||||
"module": "dist/twenty-shared-constants.esm.js"
|
||||
}
|
||||
@ -1,7 +1,4 @@
|
||||
import { JestConfigWithTsJest, pathsToModuleNameMapper } from 'ts-jest';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const tsConfig = require('./tsconfig.json');
|
||||
import { JestConfigWithTsJest } from 'ts-jest';
|
||||
|
||||
const jestConfig: JestConfigWithTsJest = {
|
||||
silent: true,
|
||||
@ -21,9 +18,18 @@ const jestConfig: JestConfigWithTsJest = {
|
||||
],
|
||||
},
|
||||
moduleNameMapper: {
|
||||
// TODO prastoin investigate not working with pathsToModuleNameMapper
|
||||
/*
|
||||
{
|
||||
'^@/(.*)\\.js$': './src/$1',
|
||||
'^@/(.*)$': './src/$1',
|
||||
'^(\\.{1,2}/.*)\\.js$': '$1'
|
||||
} // use esm true
|
||||
{ '^@/(.*)$': './src/$1' } // useEsm false
|
||||
*/
|
||||
'/^@/(.*)$/': './src/$1',
|
||||
'\\.(jpg|jpeg|png|gif|webp|svg|svg\\?react)$':
|
||||
'<rootDir>/__mocks__/imageMock.js',
|
||||
...pathsToModuleNameMapper(tsConfig.compilerOptions.paths),
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
|
||||
@ -1,21 +1,46 @@
|
||||
{
|
||||
"name": "twenty-shared",
|
||||
"version": "0.50.0-canary",
|
||||
"main": "dist/twenty-shared.cjs.js",
|
||||
"module": "dist/twenty-shared.esm.js",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/index.js",
|
||||
"scripts": {
|
||||
"build": "npx vite build"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js"
|
||||
}
|
||||
"build": "preconstruct build"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1",
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": "^4.0.2"
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.26.9",
|
||||
"@preconstruct/cli": "patch:@preconstruct/cli@npm%3A2.8.11#~/.yarn/patches/@preconstruct-cli-npm-2.8.11-030abfa6ae.patch",
|
||||
"@prettier/sync": "^0.5.2",
|
||||
"@types/babel__preset-env": "^7",
|
||||
"babel-plugin-module-resolver": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sniptt/guards": "^0.2.0",
|
||||
"zod": "3.23.8"
|
||||
},
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"./index.ts",
|
||||
"./constants/index.ts",
|
||||
"./testing/index.ts",
|
||||
"./translations/index.ts",
|
||||
"./types/index.ts",
|
||||
"./utils/index.ts",
|
||||
"./workspace/index.ts"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"constants",
|
||||
"testing",
|
||||
"translations",
|
||||
"types",
|
||||
"utils",
|
||||
"workspace"
|
||||
]
|
||||
}
|
||||
|
||||
@ -3,13 +3,45 @@
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/twenty-shared/src",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:shared"],
|
||||
"tags": [
|
||||
"scope:shared"
|
||||
],
|
||||
"targets": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"dependsOn": [
|
||||
"generateBarrels",
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
"{projectRoot}/constants/package.json",
|
||||
"{projectRoot}/constants/dist",
|
||||
"{projectRoot}/testing/package.json",
|
||||
"{projectRoot}/testing/dist",
|
||||
"{projectRoot}/translations/package.json",
|
||||
"{projectRoot}/translations/dist",
|
||||
"{projectRoot}/types/package.json",
|
||||
"{projectRoot}/types/dist",
|
||||
"{projectRoot}/utils/package.json",
|
||||
"{projectRoot}/utils/dist",
|
||||
"{projectRoot}/workspace/package.json",
|
||||
"{projectRoot}/workspace/dist"
|
||||
]
|
||||
},
|
||||
"generateBarrels": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": true,
|
||||
"inputs": [
|
||||
"production",
|
||||
"{projectRoot}/scripts/generateBarrels.ts"
|
||||
],
|
||||
"outputs": [
|
||||
"{projectRoot}/src/index.ts",
|
||||
"{projectRoot}/src/*/index.ts",
|
||||
"{projectRoot}/package.json"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "{projectRoot}/dist"
|
||||
"command": "tsx {projectRoot}/scripts/generateBarrels.ts"
|
||||
}
|
||||
},
|
||||
"typecheck": {},
|
||||
|
||||
253
packages/twenty-shared/scripts/generateBarrels.ts
Normal file
253
packages/twenty-shared/scripts/generateBarrels.ts
Normal file
@ -0,0 +1,253 @@
|
||||
import prettier from '@prettier/sync';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
import { Options } from 'prettier';
|
||||
import slash from 'slash';
|
||||
|
||||
// TODO prastoin refactor this file in several one into its dedicated package and make it a TypeScript CLI
|
||||
|
||||
const INCLUDED_EXTENSIONS = ['.ts', '.tsx'];
|
||||
const EXCLUDED_EXTENSIONS = [
|
||||
'.test.ts',
|
||||
'.test.tsx',
|
||||
'.spec.ts',
|
||||
'.spec.tsx',
|
||||
'.stories.ts',
|
||||
'.stories.tsx',
|
||||
];
|
||||
const EXCLUDED_DIRECTORIES = [
|
||||
'__tests__',
|
||||
'__mocks__',
|
||||
'__stories__',
|
||||
'internal',
|
||||
];
|
||||
const INDEX_FILENAME = 'index';
|
||||
const PACKAGE_JSON_FILENAME = 'package.json';
|
||||
const NX_PROJECT_CONFIGURATION_FILENAME = 'project.json';
|
||||
const PACKAGE_PATH = path.resolve('packages/twenty-shared');
|
||||
const SRC_PATH = path.resolve(`${PACKAGE_PATH}/src`);
|
||||
const PACKAGE_JSON_PATH = path.join(PACKAGE_PATH, PACKAGE_JSON_FILENAME);
|
||||
const NX_PROJECT_CONFIGURATION_PATH = path.join(
|
||||
PACKAGE_PATH,
|
||||
NX_PROJECT_CONFIGURATION_FILENAME,
|
||||
);
|
||||
|
||||
const prettierConfigFile = prettier.resolveConfigFile();
|
||||
if (prettierConfigFile == null) {
|
||||
throw new Error('Prettier config file not found');
|
||||
}
|
||||
const prettierConfiguration = prettier.resolveConfig(prettierConfigFile);
|
||||
const prettierFormat = (str: string, parser: Options['parser']) =>
|
||||
prettier.format(str, {
|
||||
...prettierConfiguration,
|
||||
parser,
|
||||
});
|
||||
type createTypeScriptFileArgs = {
|
||||
path: string;
|
||||
content: string;
|
||||
filename: string;
|
||||
};
|
||||
const createTypeScriptFile = ({
|
||||
content,
|
||||
path: filePath,
|
||||
filename,
|
||||
}: createTypeScriptFileArgs) => {
|
||||
const header = `
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \\ \\ /\\ / / _ \\ '_ \\| __| | | | Auto-generated file
|
||||
* | | \\ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \\_/\\_/ \\___|_| |_|\\__|\\__, |
|
||||
* |___/
|
||||
*/
|
||||
`;
|
||||
const formattedContent = prettierFormat(
|
||||
`${header}\n${content}\n`,
|
||||
'typescript',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(filePath, `${filename}.ts`),
|
||||
formattedContent,
|
||||
'utf-8',
|
||||
);
|
||||
};
|
||||
|
||||
const getLastPathFolder = (path: string) => path.split('/').pop();
|
||||
|
||||
const getSubDirectoryPaths = (directoryPath: string): string[] =>
|
||||
fs
|
||||
.readdirSync(directoryPath)
|
||||
.filter((fileOrDirectoryName) => {
|
||||
const isDirectory = fs
|
||||
.statSync(path.join(directoryPath, fileOrDirectoryName))
|
||||
.isDirectory();
|
||||
if (!isDirectory) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isExcludedDirectory =
|
||||
EXCLUDED_DIRECTORIES.includes(fileOrDirectoryName);
|
||||
return !isExcludedDirectory;
|
||||
})
|
||||
.map((subDirectoryName) => path.join(directoryPath, subDirectoryName));
|
||||
|
||||
const getDirectoryPathsRecursive = (directoryPath: string): string[] => [
|
||||
directoryPath,
|
||||
...getSubDirectoryPaths(directoryPath).flatMap(getDirectoryPathsRecursive),
|
||||
];
|
||||
|
||||
const getFilesPaths = (directoryPath: string): string[] =>
|
||||
fs.readdirSync(directoryPath).filter((filePath) => {
|
||||
const isFile = fs.statSync(path.join(directoryPath, filePath)).isFile();
|
||||
if (!isFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isIndexFile = filePath.startsWith(INDEX_FILENAME);
|
||||
if (isIndexFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isWhiteListedExtension = INCLUDED_EXTENSIONS.some((extension) =>
|
||||
filePath.endsWith(extension),
|
||||
);
|
||||
const isExcludedExtension = EXCLUDED_EXTENSIONS.every(
|
||||
(excludedExtension) => !filePath.endsWith(excludedExtension),
|
||||
);
|
||||
return isWhiteListedExtension && isExcludedExtension;
|
||||
});
|
||||
|
||||
type ComputeExportLineForGivenFileArgs = {
|
||||
filePath: string;
|
||||
moduleDirectory: string; // Rename
|
||||
directoryPath: string; // Rename
|
||||
};
|
||||
const computeExportLineForGivenFile = ({
|
||||
filePath,
|
||||
moduleDirectory,
|
||||
directoryPath,
|
||||
}: ComputeExportLineForGivenFileArgs) => {
|
||||
const fileNameWithoutExtension = filePath.split('.').slice(0, -1).join('.');
|
||||
const pathToImport = slash(
|
||||
path.relative(
|
||||
moduleDirectory,
|
||||
path.join(directoryPath, fileNameWithoutExtension),
|
||||
),
|
||||
);
|
||||
// TODO refactor should extract all exports atomically please refer to https://github.com/twentyhq/core-team-issues/issues/644
|
||||
return `export * from './${pathToImport}';`;
|
||||
};
|
||||
|
||||
const generateModuleIndexFiles = (moduleDirectories: string[]) => {
|
||||
return moduleDirectories.map<createTypeScriptFileArgs>((moduleDirectory) => {
|
||||
const directoryPaths = getDirectoryPathsRecursive(moduleDirectory);
|
||||
const content = directoryPaths
|
||||
.flatMap((directoryPath) => {
|
||||
const directFilesPaths = getFilesPaths(directoryPath);
|
||||
|
||||
return directFilesPaths.map((filePath) =>
|
||||
computeExportLineForGivenFile({
|
||||
directoryPath,
|
||||
filePath,
|
||||
moduleDirectory: moduleDirectory,
|
||||
}),
|
||||
);
|
||||
})
|
||||
.sort((a, b) => a.localeCompare(b)) // Could be removed as using prettier afterwards anw ?
|
||||
.join('\n');
|
||||
|
||||
return {
|
||||
content,
|
||||
path: moduleDirectory,
|
||||
filename: INDEX_FILENAME,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
type JsonUpdate = Record<string, any>;
|
||||
type WriteInJsonFileArgs = {
|
||||
content: JsonUpdate;
|
||||
file: string;
|
||||
};
|
||||
const updateJsonFile = ({ content, file }: WriteInJsonFileArgs) => {
|
||||
const updatedJsonFile = JSON.stringify(content);
|
||||
const formattedContent = prettierFormat(updatedJsonFile, 'json-stringify');
|
||||
fs.writeFileSync(file, formattedContent, 'utf-8');
|
||||
};
|
||||
|
||||
const writeInPackageJson = (update: JsonUpdate) => {
|
||||
const rawJsonFile = fs.readFileSync(PACKAGE_JSON_PATH, 'utf-8');
|
||||
const initialJsonFile = JSON.parse(rawJsonFile);
|
||||
|
||||
updateJsonFile({
|
||||
file: PACKAGE_JSON_PATH,
|
||||
content: {
|
||||
...initialJsonFile,
|
||||
...update,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const updateNxProjectConfigurationBuildOutputs = (outputs: JsonUpdate) => {
|
||||
const rawJsonFile = fs.readFileSync(NX_PROJECT_CONFIGURATION_PATH, 'utf-8');
|
||||
const initialJsonFile = JSON.parse(rawJsonFile);
|
||||
|
||||
updateJsonFile({
|
||||
file: NX_PROJECT_CONFIGURATION_PATH,
|
||||
content: {
|
||||
...initialJsonFile,
|
||||
targets: {
|
||||
...initialJsonFile.targets,
|
||||
build: {
|
||||
...initialJsonFile.targets.build,
|
||||
outputs,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const computePackageJsonFilesAndPreconstructConfig = (
|
||||
moduleDirectories: string[],
|
||||
) => {
|
||||
const entrypoints = [...moduleDirectories.map(getLastPathFolder)];
|
||||
|
||||
return {
|
||||
preconstruct: {
|
||||
entrypoints: [
|
||||
'./index.ts',
|
||||
...entrypoints.map((module) => `./${module}/index.ts`),
|
||||
],
|
||||
},
|
||||
files: ['dist', ...entrypoints],
|
||||
};
|
||||
};
|
||||
|
||||
const computeProjectNxBuildOutputsPath = (moduleDirectories: string[]) => {
|
||||
const dynamicOutputsPath = moduleDirectories
|
||||
.map(getLastPathFolder)
|
||||
.flatMap((barrelName) =>
|
||||
['package.json', 'dist'].map(
|
||||
(subPath) => `{projectRoot}/${barrelName}/${subPath}`,
|
||||
),
|
||||
);
|
||||
|
||||
return ['{projectRoot}/dist', ...dynamicOutputsPath];
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
const moduleDirectories = getSubDirectoryPaths(SRC_PATH);
|
||||
const moduleIndexFiles = generateModuleIndexFiles(moduleDirectories);
|
||||
const packageJsonPreconstructConfigAndFiles =
|
||||
computePackageJsonFilesAndPreconstructConfig(moduleDirectories);
|
||||
const nxBuildOutputsPath =
|
||||
computeProjectNxBuildOutputsPath(moduleDirectories);
|
||||
|
||||
updateNxProjectConfigurationBuildOutputs(
|
||||
nxBuildOutputsPath
|
||||
);
|
||||
writeInPackageJson(packageJsonPreconstructConfigAndFiles);
|
||||
moduleIndexFiles.forEach(createTypeScriptFile);
|
||||
};
|
||||
main();
|
||||
@ -0,0 +1,495 @@
|
||||
import prettier from '@prettier/sync';
|
||||
import * as fs from 'fs';
|
||||
import glob from 'glob';
|
||||
import * as path from 'path';
|
||||
import ts from 'typescript';
|
||||
const prettierConfigFile = prettier.resolveConfigFile();
|
||||
if (prettierConfigFile == null) {
|
||||
throw new Error('Prettier config file not found');
|
||||
}
|
||||
const prettierConfiguration = prettier.resolveConfig(prettierConfigFile);
|
||||
|
||||
type DeclarationOccurence = { kind: string; name: string };
|
||||
type ExtractedExports = Array<{
|
||||
file: string;
|
||||
exports: DeclarationOccurence[];
|
||||
}>;
|
||||
type ExtractedImports = Array<{ file: string; imports: string[] }>;
|
||||
|
||||
type ExportPerModule = Array<{
|
||||
moduleName: string;
|
||||
exports: ExtractedExports[number]['exports'];
|
||||
}>;
|
||||
function findAllExports(directoryPath: string): ExtractedExports {
|
||||
const results: ExtractedExports = [];
|
||||
|
||||
const files = getTypeScriptFiles(directoryPath);
|
||||
|
||||
for (const file of files) {
|
||||
const sourceFile = ts.createSourceFile(
|
||||
file,
|
||||
fs.readFileSync(file, 'utf8'),
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
const exports = extractExports(sourceFile);
|
||||
if (exports.length > 0) {
|
||||
results.push({
|
||||
file,
|
||||
exports,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function findAllImports(directoryPath: string): ExtractedImports {
|
||||
const results: ExtractedImports = [];
|
||||
|
||||
const includeIndex = true;
|
||||
const files = getTypeScriptFiles(directoryPath, includeIndex);
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
const sourceFile = ts.createSourceFile(
|
||||
file,
|
||||
fs.readFileSync(file, 'utf8'),
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
const imports = extractImports(sourceFile);
|
||||
if (imports.length > 0) {
|
||||
results.push({
|
||||
file,
|
||||
imports,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Because of file: ', file);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getTypeScriptFiles(
|
||||
directoryPath: string,
|
||||
includeIndex: boolean = false,
|
||||
): string[] {
|
||||
const pattern = path.join(directoryPath, '**/*.{ts,tsx}');
|
||||
const files = glob.sync(pattern);
|
||||
|
||||
return files.filter(
|
||||
(file) =>
|
||||
!file.endsWith('.d.ts') &&
|
||||
(includeIndex ? true : !file.endsWith('index.ts')),
|
||||
);
|
||||
}
|
||||
|
||||
const getKind = (node: ts.VariableStatement) => {
|
||||
const isConst = (node.declarationList.flags & ts.NodeFlags.Const) !== 0;
|
||||
if (isConst) {
|
||||
return 'const';
|
||||
}
|
||||
|
||||
const isLet = (node.declarationList.flags & ts.NodeFlags.Let) !== 0;
|
||||
if (isLet) {
|
||||
return 'let';
|
||||
}
|
||||
|
||||
return 'var';
|
||||
};
|
||||
|
||||
function extractExports(sourceFile: ts.SourceFile) {
|
||||
const exports: DeclarationOccurence[] = [];
|
||||
|
||||
function visit(node: ts.Node) {
|
||||
if (!ts.canHaveModifiers(node)) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
const modifiers = ts.getModifiers(node);
|
||||
const isExport = modifiers?.some(
|
||||
(mod) => mod.kind === ts.SyntaxKind.ExportKeyword,
|
||||
);
|
||||
|
||||
if (!isExport) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case ts.isTypeAliasDeclaration(node):
|
||||
exports.push({
|
||||
kind: 'type',
|
||||
name: node.name.text,
|
||||
});
|
||||
break;
|
||||
|
||||
case ts.isInterfaceDeclaration(node):
|
||||
exports.push({
|
||||
kind: 'interface',
|
||||
name: node.name.text,
|
||||
});
|
||||
break;
|
||||
|
||||
case ts.isEnumDeclaration(node):
|
||||
exports.push({
|
||||
kind: 'enum',
|
||||
name: node.name.text,
|
||||
});
|
||||
break;
|
||||
|
||||
case ts.isFunctionDeclaration(node) && node.name !== undefined:
|
||||
exports.push({
|
||||
kind: 'function',
|
||||
name: node.name.text,
|
||||
});
|
||||
break;
|
||||
|
||||
case ts.isVariableStatement(node):
|
||||
node.declarationList.declarations.forEach((decl) => {
|
||||
if (ts.isIdentifier(decl.name)) {
|
||||
const kind = getKind(node);
|
||||
exports.push({
|
||||
kind,
|
||||
name: decl.name.text,
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case ts.isClassDeclaration(node) && node.name !== undefined:
|
||||
exports.push({
|
||||
kind: 'class',
|
||||
name: node.name.text,
|
||||
});
|
||||
break;
|
||||
}
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
return exports;
|
||||
}
|
||||
|
||||
function extractImports(sourceFile: ts.SourceFile): string[] {
|
||||
const imports: string[] = [];
|
||||
|
||||
function visit(node: ts.Node) {
|
||||
if (!ts.isImportDeclaration(node)) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
const modulePath = node.moduleSpecifier.getText(sourceFile);
|
||||
// Quite static
|
||||
if (modulePath !== `'twenty-shared'`) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
if (!node.importClause) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
if (!node.importClause.namedBindings) {
|
||||
return ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
if (ts.isNamedImports(node.importClause.namedBindings)) {
|
||||
const namedImports = node.importClause.namedBindings.elements.map(
|
||||
(element) => {
|
||||
if (element.propertyName) {
|
||||
return `${element.propertyName.text} as ${element.name.text}`;
|
||||
}
|
||||
|
||||
return element.name.text;
|
||||
},
|
||||
);
|
||||
|
||||
// imports.push(`import { ${namedImports} } from ${modulePath}`);
|
||||
namedImports.forEach((namedImport) => {
|
||||
imports.push(namedImport);
|
||||
});
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
return imports;
|
||||
}
|
||||
|
||||
const getSubDirectoryPaths = (directoryPath: string): string[] =>
|
||||
fs
|
||||
.readdirSync(directoryPath)
|
||||
.filter((fileOrDirectoryName) => {
|
||||
const isDirectory = fs
|
||||
.statSync(path.join(directoryPath, fileOrDirectoryName))
|
||||
.isDirectory();
|
||||
return isDirectory;
|
||||
})
|
||||
.map((subDirectoryName) => path.join(directoryPath, subDirectoryName));
|
||||
|
||||
const retrievePackageExportsPerModule = (srcPath: string) => {
|
||||
const subdirectories = getSubDirectoryPaths(srcPath);
|
||||
return subdirectories.map<ExportPerModule[number]>((moduleDirectory) => {
|
||||
const moduleExportsPerFile = findAllExports(moduleDirectory);
|
||||
const moduleName = moduleDirectory.split('/').pop();
|
||||
if (!moduleName) {
|
||||
throw new Error(
|
||||
`Should never occurs moduleName not found ${moduleDirectory}`,
|
||||
);
|
||||
}
|
||||
|
||||
const flattenExports = Object.values(moduleExportsPerFile).flatMap(
|
||||
(arr) => arr.exports,
|
||||
);
|
||||
return {
|
||||
moduleName,
|
||||
exports: flattenExports,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
type NewImport = { barrel: string; modules: string[] };
|
||||
type MappedResolution = {
|
||||
newImports: Record<string, NewImport>;
|
||||
file: string;
|
||||
};
|
||||
type MapSourceImportToBarrelArgs = {
|
||||
importsPerFile: ExtractedImports;
|
||||
exportsPerModule: ExportPerModule;
|
||||
};
|
||||
const mapSourceImportToBarrel = ({
|
||||
exportsPerModule,
|
||||
importsPerFile,
|
||||
}: MapSourceImportToBarrelArgs): MappedResolution[] => {
|
||||
const mappedResolution: MappedResolution[] = [];
|
||||
for (const fileImport of importsPerFile) {
|
||||
const { file, imports } = fileImport;
|
||||
let result: MappedResolution = {
|
||||
file,
|
||||
newImports: {},
|
||||
};
|
||||
|
||||
for (const importedDeclaration of imports) {
|
||||
const findResult = exportsPerModule.find(({ exports }) =>
|
||||
exports.some((el) => el.name === importedDeclaration),
|
||||
);
|
||||
|
||||
if (findResult === undefined) {
|
||||
throw new Error(
|
||||
`Should never occurs no barrel exports ${importedDeclaration}`,
|
||||
);
|
||||
}
|
||||
|
||||
const { moduleName } = findResult;
|
||||
if (result.newImports[moduleName]) {
|
||||
result.newImports[moduleName].modules.push(importedDeclaration);
|
||||
} else {
|
||||
result.newImports[moduleName] = {
|
||||
barrel: moduleName,
|
||||
modules: [importedDeclaration],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
mappedResolution.push(result);
|
||||
}
|
||||
|
||||
return mappedResolution;
|
||||
};
|
||||
|
||||
const retrieveImportFromPackageInSource = (srcPath: string) => {
|
||||
return findAllImports(srcPath);
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts a new import statement at the top of a TypeScript file
|
||||
* @param filePath Path to the TypeScript file
|
||||
* @param importSpecifier The module to import from (e.g., 'twenty-shared/utils')
|
||||
* @param namedImports Array of named imports (e.g., ['useQuery', 'useMutation'])
|
||||
*/
|
||||
type InsertImportAtTopArgs = {
|
||||
filePath: string;
|
||||
importSpecifier: string;
|
||||
namedImports: string[];
|
||||
};
|
||||
function insertImportAtTop({
|
||||
filePath,
|
||||
importSpecifier,
|
||||
namedImports,
|
||||
}: InsertImportAtTopArgs): void {
|
||||
// Read the file content
|
||||
const sourceText = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
// Create a source file
|
||||
const sourceFile = ts.createSourceFile(
|
||||
filePath,
|
||||
sourceText,
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
// Build the new import statement
|
||||
let newImport = `import { ${namedImports.join(', ')} } from '${importSpecifier}';\n`;
|
||||
|
||||
// Find the position to insert the import
|
||||
let insertPos = 0;
|
||||
|
||||
// Case 1: File has imports - insert after the last import
|
||||
let lastImportEnd = 0;
|
||||
|
||||
ts.forEachChild(sourceFile, (node) => {
|
||||
if (
|
||||
ts.isImportDeclaration(node) ||
|
||||
ts.isImportEqualsDeclaration(node) ||
|
||||
(ts.isExpressionStatement(node) &&
|
||||
ts.isCallExpression(node.expression) &&
|
||||
node.expression.expression.kind === ts.SyntaxKind.ImportKeyword) // Overkill ?
|
||||
) {
|
||||
const end = node.getEnd();
|
||||
if (end > lastImportEnd) {
|
||||
lastImportEnd = end;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (lastImportEnd > 0) {
|
||||
// Insert after the last import with a newline
|
||||
insertPos = lastImportEnd;
|
||||
|
||||
// Check if there's already a newline after the last import
|
||||
if (sourceText[insertPos] !== '\n') {
|
||||
newImport = '\n' + newImport;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert the new import
|
||||
const updatedSourceText =
|
||||
sourceText.substring(0, insertPos) +
|
||||
newImport +
|
||||
sourceText.substring(insertPos);
|
||||
|
||||
// Write back to file
|
||||
fs.writeFileSync(
|
||||
filePath,
|
||||
prettier.format(updatedSourceText, {
|
||||
parser: 'typescript',
|
||||
...prettierConfiguration,
|
||||
}),
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
|
||||
type RemoveSpecificImports = {
|
||||
filePath: string;
|
||||
moduleSpecifier: string;
|
||||
};
|
||||
function removeSpecificImports({
|
||||
filePath,
|
||||
moduleSpecifier,
|
||||
}: RemoveSpecificImports) {
|
||||
const sourceText = fs.readFileSync(filePath, 'utf8');
|
||||
|
||||
const sourceFile = ts.createSourceFile(
|
||||
filePath,
|
||||
sourceText,
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
type Replacement = {
|
||||
start: number;
|
||||
end: number;
|
||||
newText: string;
|
||||
};
|
||||
let replacement: Replacement | undefined;
|
||||
|
||||
function visit(node: ts.Node) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
const importSource = node.moduleSpecifier
|
||||
.getText(sourceFile)
|
||||
.replace(/^['"]|['"]$/g, '');
|
||||
|
||||
if (importSource === moduleSpecifier && node.importClause) {
|
||||
replacement = {
|
||||
start: node.getFullStart(),
|
||||
end: node.getEnd(),
|
||||
newText: '',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
|
||||
let updatedSourceText = sourceText;
|
||||
|
||||
if (replacement) {
|
||||
const { end, newText, start } = replacement;
|
||||
updatedSourceText =
|
||||
updatedSourceText.substring(0, start) +
|
||||
newText +
|
||||
updatedSourceText.substring(end);
|
||||
fs.writeFileSync(
|
||||
filePath,
|
||||
prettier.format(updatedSourceText, {
|
||||
parser: 'typescript',
|
||||
...prettierConfiguration,
|
||||
}),
|
||||
'utf8',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const migrateImports = (mappedResolutions: MappedResolution[]) => {
|
||||
for (const { file, newImports } of mappedResolutions) {
|
||||
for (const { barrel, modules } of Object.values(newImports)) {
|
||||
// TODO could refactor to avoid double source file and read
|
||||
removeSpecificImports({
|
||||
filePath: file,
|
||||
moduleSpecifier: 'twenty-shared',
|
||||
});
|
||||
insertImportAtTop({
|
||||
filePath: file,
|
||||
importSpecifier: `twenty-shared/${barrel}`,
|
||||
namedImports: modules,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const main = () => {
|
||||
const packageSrcPath = 'packages/twenty-shared/src';
|
||||
const exportsPerModule = retrievePackageExportsPerModule(packageSrcPath);
|
||||
|
||||
const packagesToMigrate = [
|
||||
'twenty-front',
|
||||
'twenty-ui',
|
||||
'twenty-server',
|
||||
'twenty-emails',
|
||||
'twenty-zapier',
|
||||
'twenty-chrome-extension',
|
||||
];
|
||||
for (const currPackage of packagesToMigrate) {
|
||||
console.log(`About to run over ${currPackage}`);
|
||||
const importsPerFile = retrieveImportFromPackageInSource(
|
||||
`packages/${currPackage}`,
|
||||
);
|
||||
|
||||
const mappedResolutions = mapSourceImportToBarrel({
|
||||
exportsPerModule,
|
||||
importsPerFile,
|
||||
});
|
||||
migrateImports(mappedResolutions);
|
||||
console.log(`${currPackage} migrated`);
|
||||
}
|
||||
console.log('SUCCESSFULLY COMPLETED');
|
||||
};
|
||||
main();
|
||||
@ -1,3 +1,12 @@
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './FieldForTotalCountAggregateOperation';
|
||||
export * from './PermissionsOnAllObjectRecords';
|
||||
export * from './StandardObjectRecordsUnderObjectRecordsPermissions';
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
export * from './constants/AppLocales';
|
||||
export * from './constants/SourceLocale';
|
||||
@ -1,6 +1,10 @@
|
||||
export * from './constants';
|
||||
export * from './i18n';
|
||||
export * from './testing';
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
export * from './workspace';
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-genreated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edition to this will be override
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export default {};
|
||||
|
||||
@ -1 +1,10 @@
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './types/EachTestingContext.type';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { SOURCE_LOCALE } from 'src/i18n/constants/SourceLocale';
|
||||
import { SOURCE_LOCALE } from '@/translations/constants/SourceLocale';
|
||||
|
||||
export const APP_LOCALES = {
|
||||
[SOURCE_LOCALE]: SOURCE_LOCALE,
|
||||
11
packages/twenty-shared/src/translations/index.ts
Normal file
11
packages/twenty-shared/src/translations/index.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './constants/AppLocales';
|
||||
export * from './constants/SourceLocale';
|
||||
@ -1,3 +1,12 @@
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './ConnectedAccountProvider';
|
||||
export * from './FieldMetadataType';
|
||||
export * from './IsExactly';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { FieldMetadataType } from 'src/types/FieldMetadataType';
|
||||
import { FieldMetadataType } from '@/types';
|
||||
|
||||
export const isFieldMetadataDateKind = (
|
||||
fieldMetadataType?: FieldMetadataType,
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { getImageAbsoluteURI } from '../getImageAbsoluteURI';
|
||||
|
||||
import { getImageAbsoluteURI } from '@/utils/image/getImageAbsoluteURI';
|
||||
describe('getImageAbsoluteURI', () => {
|
||||
it('should return baseUrl if imageUrl is empty string', () => {
|
||||
const imageUrl = '';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import {
|
||||
getLogoUrlFromDomainName,
|
||||
sanitizeURL,
|
||||
} from '../getLogoUrlFromDomainName';
|
||||
} from '@/utils/image/getLogoUrlFromDomainName';
|
||||
|
||||
describe('sanitizeURL', () => {
|
||||
test('should sanitize the URL correctly', () => {
|
||||
|
||||
@ -1,6 +1,22 @@
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './assertUnreachable';
|
||||
export * from './fieldMetadata';
|
||||
export * from './image';
|
||||
export * from './strings';
|
||||
export * from './url';
|
||||
export * from './validation';
|
||||
export * from './fieldMetadata/isFieldMetadataDateKind';
|
||||
export * from './image/getImageAbsoluteURI';
|
||||
export * from './image/getLogoUrlFromDomainName';
|
||||
export * from './strings/capitalize';
|
||||
export * from './url/absoluteUrlSchema';
|
||||
export * from './url/getAbsoluteUrlOrThrow';
|
||||
export * from './url/getUrlHostnameOrThrow';
|
||||
export * from './url/isValidHostname';
|
||||
export * from './url/isValidUrl';
|
||||
export * from './validation/isDefined';
|
||||
export * from './validation/isValidLocale';
|
||||
export * from './validation/isValidUuid';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { capitalize } from '../capitalize';
|
||||
import { capitalize } from '@/utils/strings/capitalize';
|
||||
describe('capitalize', () => {
|
||||
it('should capitalize a string', () => {
|
||||
expect(capitalize('test')).toBe('Test');
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { absoluteUrlSchema } from '../absoluteUrlSchema';
|
||||
import { absoluteUrlSchema } from '@/utils/url/absoluteUrlSchema';
|
||||
|
||||
describe('absoluteUrlSchema', () => {
|
||||
it('validates an absolute url', () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { getAbsoluteUrlOrThrow } from 'src/utils/url/getAbsoluteUrlOrThrow';
|
||||
import { getAbsoluteUrlOrThrow } from '@/utils/url/getAbsoluteUrlOrThrow';
|
||||
|
||||
describe('getAbsoluteUrlOrThrow', () => {
|
||||
it("returns the URL's hostname", () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { getUrlHostnameOrThrow } from 'src/utils/url/getUrlHostnameOrThrow';
|
||||
import { getUrlHostnameOrThrow } from '@/utils/url/getUrlHostnameOrThrow';
|
||||
|
||||
describe('getUrlHostnameOrThrow', () => {
|
||||
it("returns the URL's hostname", () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isValidHostname } from 'src/utils/url/isValidHostname';
|
||||
import { isValidHostname } from '@/utils/url/isValidHostname';
|
||||
|
||||
describe('isValidHostname', () => {
|
||||
it(`should return true if string google`, () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isValidUrl } from '../isValidUrl';
|
||||
import { isValidUrl } from '@/utils/url/isValidUrl';
|
||||
|
||||
describe('isValidUrl', () => {
|
||||
it('test cases', () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isValidHostname } from 'src/utils/url/isValidHostname';
|
||||
import { isValidHostname } from '@/utils/url/isValidHostname';
|
||||
import { z } from 'zod';
|
||||
|
||||
const getAbsoluteUrl = (value: string): string => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { absoluteUrlSchema } from 'src/utils/url/absoluteUrlSchema';
|
||||
import { absoluteUrlSchema } from '@/utils/url/absoluteUrlSchema';
|
||||
|
||||
export const getAbsoluteUrlOrThrow = (url: string): string => {
|
||||
try {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { absoluteUrlSchema } from 'src/utils/url/absoluteUrlSchema';
|
||||
import { absoluteUrlSchema } from '@/utils/url/absoluteUrlSchema';
|
||||
|
||||
export const getUrlHostnameOrThrow = (url: string): string => {
|
||||
const result = absoluteUrlSchema.safeParse(url);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { absoluteUrlSchema } from 'src/utils/url/absoluteUrlSchema';
|
||||
import { absoluteUrlSchema } from '@/utils/url/absoluteUrlSchema';
|
||||
|
||||
export const isValidUrl = (url: string): boolean => {
|
||||
const result = absoluteUrlSchema.safeParse(url);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isDefined } from '../isDefined';
|
||||
import { isDefined } from '@/utils/validation/isDefined';
|
||||
describe('isDefined', () => {
|
||||
it('returns true if value is not undefined nor null', () => {
|
||||
expect(isDefined('')).toBe(true);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { isValidUuid } from '../isValidUuid';
|
||||
import { isValidUuid } from '@/utils/validation/isValidUuid';
|
||||
|
||||
describe('isValidUuid', () => {
|
||||
it('should return true for a valid UUID', () => {
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { APP_LOCALES } from 'src/i18n/constants/AppLocales';
|
||||
import { isValidLocale } from '../isValidLocale';
|
||||
|
||||
import { APP_LOCALES } from '@/translations';
|
||||
import { isValidLocale } from '@/utils/validation/isValidLocale';
|
||||
describe('isValidLocale', () => {
|
||||
it('should return true for valid locales', () => {
|
||||
Object.keys(APP_LOCALES).forEach((locale) => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { APP_LOCALES } from 'src/i18n/constants/AppLocales';
|
||||
import { APP_LOCALES } from '@/translations';
|
||||
|
||||
export const isValidLocale = (
|
||||
value: string | null,
|
||||
|
||||
@ -1,2 +1,11 @@
|
||||
export * from './types';
|
||||
export * from './utils';
|
||||
/*
|
||||
* _____ _
|
||||
*|_ _|_ _____ _ __ | |_ _ _
|
||||
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
|
||||
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
|
||||
* |_| \_/\_/ \___|_| |_|\__|\__, |
|
||||
* |___/
|
||||
*/
|
||||
|
||||
export * from './types/WorkspaceActivationStatus';
|
||||
export * from './utils/isWorkspaceActiveOrSuspended';
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { WorkspaceActivationStatus } from '../../types/WorkspaceActivationStatus';
|
||||
import { isWorkspaceActiveOrSuspended } from '../isWorkspaceActiveOrSuspended';
|
||||
import { WorkspaceActivationStatus } from '@/workspace/types/WorkspaceActivationStatus';
|
||||
import { isWorkspaceActiveOrSuspended } from '@/workspace/utils/isWorkspaceActiveOrSuspended';
|
||||
|
||||
describe('isWorkspaceActiveOrSuspended', () => {
|
||||
it('should return true for Active workspace', () => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { WorkspaceActivationStatus } from '../types/WorkspaceActivationStatus';
|
||||
import { WorkspaceActivationStatus } from '@/workspace/types/WorkspaceActivationStatus';
|
||||
|
||||
export const isWorkspaceActiveOrSuspended = (
|
||||
workspace?: {
|
||||
|
||||
4
packages/twenty-shared/testing/package.json
Normal file
4
packages/twenty-shared/testing/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-testing.cjs.js",
|
||||
"module": "dist/twenty-shared-testing.esm.js"
|
||||
}
|
||||
4
packages/twenty-shared/translations/package.json
Normal file
4
packages/twenty-shared/translations/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-translations.cjs.js",
|
||||
"module": "dist/twenty-shared-translations.esm.js"
|
||||
}
|
||||
@ -4,10 +4,9 @@
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"types": ["vite/client"],
|
||||
"baseUrl": ".",
|
||||
"noEmit": true,
|
||||
"paths": {
|
||||
"twenty-shared": ["packages/twenty-shared/dist"]
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"files": [],
|
||||
|
||||
@ -3,11 +3,10 @@
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noEmit": false,
|
||||
"baseUrl": ".",
|
||||
"outDir": "../../.cache/tsc",
|
||||
"types": [
|
||||
"node",
|
||||
"vite/client"
|
||||
]
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
@ -19,6 +18,5 @@
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx"
|
||||
],
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"],
|
||||
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
|
||||
4
packages/twenty-shared/types/package.json
Normal file
4
packages/twenty-shared/types/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-types.cjs.js",
|
||||
"module": "dist/twenty-shared-types.esm.js"
|
||||
}
|
||||
4
packages/twenty-shared/utils/package.json
Normal file
4
packages/twenty-shared/utils/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-utils.cjs.js",
|
||||
"module": "dist/twenty-shared-utils.esm.js"
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
import * as path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/packages/twenty-shared',
|
||||
|
||||
plugins: [
|
||||
tsconfigPaths(),
|
||||
dts({
|
||||
entryRoot: 'src',
|
||||
tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
|
||||
}),
|
||||
],
|
||||
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
entry: 'src/index.ts',
|
||||
name: 'twenty-shared',
|
||||
fileName: 'index',
|
||||
formats: ['es', 'cjs'],
|
||||
},
|
||||
},
|
||||
});
|
||||
4
packages/twenty-shared/workspace/package.json
Normal file
4
packages/twenty-shared/workspace/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/twenty-shared-workspace.cjs.js",
|
||||
"module": "dist/twenty-shared-workspace.esm.js"
|
||||
}
|
||||
Reference in New Issue
Block a user