@hubspot/project-parsing-lib 0.10.3 → 0.11.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +48 -11
- package/src/exports/constants.d.ts +1 -0
- package/src/exports/constants.js +1 -0
- package/src/exports/migrate.d.ts +1 -0
- package/src/exports/migrate.js +1 -0
- package/src/exports/profiles.d.ts +3 -0
- package/src/exports/profiles.js +2 -0
- package/src/exports/projects.d.ts +3 -0
- package/src/exports/projects.js +2 -0
- package/src/exports/schema.d.ts +2 -0
- package/src/exports/schema.js +1 -0
- package/src/exports/themes.d.ts +2 -0
- package/src/exports/themes.js +1 -0
- package/src/exports/transform.d.ts +2 -0
- package/src/exports/transform.js +1 -0
- package/src/exports/translate.d.ts +3 -0
- package/src/exports/translate.js +2 -0
- package/src/exports/uid.d.ts +1 -0
- package/src/exports/uid.js +1 -0
- package/src/lang/copy.d.ts +1 -1
- package/src/lang/copy.js +21 -31
- package/src/lib/constants.d.ts +38 -38
- package/src/lib/constants.js +120 -153
- package/src/lib/errors.d.ts +2 -2
- package/src/lib/errors.js +19 -29
- package/src/lib/files.d.ts +1 -1
- package/src/lib/files.js +36 -47
- package/src/lib/localDev.d.ts +1 -1
- package/src/lib/localDev.js +8 -16
- package/src/lib/migrate.js +34 -40
- package/src/lib/migrateThemes.d.ts +3 -4
- package/src/lib/migrateThemes.js +31 -38
- package/src/lib/profiles.d.ts +1 -1
- package/src/lib/profiles.js +12 -20
- package/src/lib/project.js +11 -17
- package/src/lib/schemas.d.ts +2 -2
- package/src/lib/schemas.js +8 -11
- package/src/lib/transform.d.ts +1 -1
- package/src/lib/transform.js +50 -64
- package/src/lib/translate.d.ts +3 -0
- package/src/lib/translate.js +52 -0
- package/src/lib/types.d.ts +1 -1
- package/src/lib/types.js +1 -2
- package/src/lib/uid.js +9 -14
- package/src/lib/utils.d.ts +1 -1
- package/src/lib/utils.js +7 -14
- package/src/lib/validation.d.ts +3 -3
- package/src/lib/validation.js +46 -46
- package/src/index.d.ts +0 -19
- package/src/index.js +0 -94
package/src/lib/transform.js
CHANGED
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
exports.findTransformationByUid = findTransformationByUid;
|
|
10
|
-
exports.transform = transform;
|
|
11
|
-
exports.getIntermediateRepresentation = getIntermediateRepresentation;
|
|
12
|
-
exports.getParsingErrors = getParsingErrors;
|
|
13
|
-
exports.generateServerlessPackageComponent = generateServerlessPackageComponent;
|
|
14
|
-
const path_1 = __importDefault(require("path"));
|
|
15
|
-
const fs_1 = __importDefault(require("fs"));
|
|
16
|
-
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
17
|
-
const profiles_1 = require("./profiles");
|
|
18
|
-
const constants_1 = require("./constants");
|
|
19
|
-
const copy_1 = require("../lang/copy");
|
|
20
|
-
const utils_1 = require("./utils");
|
|
21
|
-
const files_1 = require("./files");
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
4
|
+
import { applyHsProfileVariables, getHsProfileVariables } from './profiles.js';
|
|
5
|
+
import { APP_KEY, APP_OBJECT_KEY, Components, PROJECT_STRUCTURE, APP_FUNCTIONS_KEY, APP_FUNCTIONS_PACKAGE_KEY, USER_FACING_TO_INTERNAL_TYPE, INTERNAL_TYPE_TO_USER_FACING, PACKAGE_JSON, PACKAGE_LOCK_JSON, PROFILE_VARIABLE_TYPES, } from './constants.js';
|
|
6
|
+
import { errorMessages } from '../lang/copy.js';
|
|
7
|
+
import { getJavaNumberType } from './utils.js';
|
|
8
|
+
import { convertPathToPosixPath } from './files.js';
|
|
22
9
|
function calculateComponentDeps(fileValidationResult, parentComponents, appObjects, appFunctionsPackageUid) {
|
|
23
10
|
let dependencies = {};
|
|
24
11
|
// If there are dependencies in the config file, pass them through
|
|
@@ -27,65 +14,65 @@ function calculateComponentDeps(fileValidationResult, parentComponents, appObjec
|
|
|
27
14
|
}
|
|
28
15
|
const { type } = fileValidationResult.content;
|
|
29
16
|
// If the component is a child of the App component, add the app and appObjects as dependencies
|
|
30
|
-
if (
|
|
31
|
-
const parentUid = parentComponents[
|
|
17
|
+
if (Components[type]?.parentComponent === APP_KEY) {
|
|
18
|
+
const parentUid = parentComponents[APP_KEY];
|
|
32
19
|
if (parentUid) {
|
|
33
20
|
dependencies.app = parentUid;
|
|
34
21
|
}
|
|
35
22
|
else {
|
|
36
|
-
|
|
23
|
+
logger.debug(parentComponents);
|
|
37
24
|
return {
|
|
38
25
|
dependencies,
|
|
39
|
-
errors: [
|
|
26
|
+
errors: [errorMessages.project.mustHaveAppComponent(type)],
|
|
40
27
|
};
|
|
41
28
|
}
|
|
42
|
-
if (type !==
|
|
29
|
+
if (type !== APP_OBJECT_KEY) {
|
|
43
30
|
dependencies.allAppObjects = appObjects;
|
|
44
31
|
}
|
|
45
|
-
if (type ===
|
|
32
|
+
if (type === APP_FUNCTIONS_KEY && appFunctionsPackageUid) {
|
|
46
33
|
dependencies.serverlessPackage = appFunctionsPackageUid;
|
|
47
34
|
}
|
|
48
35
|
}
|
|
49
36
|
return { dependencies };
|
|
50
37
|
}
|
|
51
|
-
function mapToInternalType(type) {
|
|
52
|
-
const resolvedType =
|
|
38
|
+
export function mapToInternalType(type) {
|
|
39
|
+
const resolvedType = USER_FACING_TO_INTERNAL_TYPE[type] || type || '';
|
|
53
40
|
return resolvedType.toUpperCase().replace(/-/g, '_');
|
|
54
41
|
}
|
|
55
|
-
function mapToUserFacingType(type) {
|
|
56
|
-
return (
|
|
42
|
+
export function mapToUserFacingType(type) {
|
|
43
|
+
return (INTERNAL_TYPE_TO_USER_FACING[type] || type || '')
|
|
57
44
|
.toLowerCase()
|
|
58
45
|
.replace(/_/g, '-');
|
|
59
46
|
}
|
|
60
|
-
function mapToUserFriendlyName(internalType) {
|
|
61
|
-
return
|
|
47
|
+
export function mapToUserFriendlyName(internalType) {
|
|
48
|
+
return Components[mapToUserFacingType(internalType)]?.userFriendlyName || '';
|
|
62
49
|
}
|
|
63
|
-
function findTransformationByUid(transformations, uid) {
|
|
50
|
+
export function findTransformationByUid(transformations, uid) {
|
|
64
51
|
return transformations.find(t => t.intermediateRepresentation?.uid === uid);
|
|
65
52
|
}
|
|
66
|
-
function transform(fileParseResults, translationContext, hsProfileContents) {
|
|
67
|
-
const parentTypes = Object.keys(
|
|
53
|
+
export function transform(fileParseResults, translationContext, hsProfileContents) {
|
|
54
|
+
const parentTypes = Object.keys(PROJECT_STRUCTURE);
|
|
68
55
|
const parentComponents = {};
|
|
69
56
|
const allAppObjects = [];
|
|
70
57
|
let appUid = '';
|
|
71
58
|
let appFunctionsDirectory;
|
|
72
59
|
// Apply the profile variable overrides to the config
|
|
73
60
|
if (hsProfileContents) {
|
|
74
|
-
fileParseResults =
|
|
61
|
+
fileParseResults = applyHsProfileVariables(fileParseResults, hsProfileContents);
|
|
75
62
|
}
|
|
76
63
|
// Compute the parent components, so we can add them as dependencies to the child components
|
|
77
64
|
fileParseResults.forEach(file => {
|
|
78
65
|
if (file.content?.type && parentTypes.includes(file.content.type)) {
|
|
79
|
-
if (file.content.type ===
|
|
66
|
+
if (file.content.type === APP_KEY) {
|
|
80
67
|
appUid = file.content.uid;
|
|
81
68
|
}
|
|
82
69
|
parentComponents[file.content.type] = file.content.uid;
|
|
83
70
|
}
|
|
84
|
-
if (file.content?.type ===
|
|
71
|
+
if (file.content?.type === APP_OBJECT_KEY) {
|
|
85
72
|
allAppObjects.push(file.content.uid);
|
|
86
73
|
}
|
|
87
|
-
if (file.content?.type ===
|
|
88
|
-
appFunctionsDirectory =
|
|
74
|
+
if (file.content?.type === APP_FUNCTIONS_KEY) {
|
|
75
|
+
appFunctionsDirectory = path.dirname(file.file);
|
|
89
76
|
}
|
|
90
77
|
});
|
|
91
78
|
const autoGeneratedComponents = [];
|
|
@@ -100,8 +87,8 @@ function transform(fileParseResults, translationContext, hsProfileContents) {
|
|
|
100
87
|
}
|
|
101
88
|
const transformations = fileParseResults.map((currentFile) => {
|
|
102
89
|
if (!currentFile.content) {
|
|
103
|
-
if (!currentFile.errors?.includes(
|
|
104
|
-
currentFile.errors?.push(
|
|
90
|
+
if (!currentFile.errors?.includes(errorMessages.validation.invalidJson)) {
|
|
91
|
+
currentFile.errors?.push(errorMessages.project.fileContentMissingFor(currentFile.file));
|
|
105
92
|
}
|
|
106
93
|
return {
|
|
107
94
|
intermediateRepresentation: null,
|
|
@@ -119,7 +106,7 @@ function transform(fileParseResults, translationContext, hsProfileContents) {
|
|
|
119
106
|
config,
|
|
120
107
|
componentType: mapToInternalType(type),
|
|
121
108
|
componentDeps: dependencies,
|
|
122
|
-
metaFilePath:
|
|
109
|
+
metaFilePath: convertPathToPosixPath(currentFile.file),
|
|
123
110
|
files: {},
|
|
124
111
|
},
|
|
125
112
|
fileParseResult: currentFile,
|
|
@@ -127,7 +114,7 @@ function transform(fileParseResults, translationContext, hsProfileContents) {
|
|
|
127
114
|
});
|
|
128
115
|
return [...autoGeneratedComponents, ...transformations];
|
|
129
116
|
}
|
|
130
|
-
function getIntermediateRepresentation(transformations, hsProfileContents, skipValidation) {
|
|
117
|
+
export function getIntermediateRepresentation(transformations, hsProfileContents, skipValidation) {
|
|
131
118
|
const nodes = transformations.reduce((acc, current) => {
|
|
132
119
|
if (!current.intermediateRepresentation) {
|
|
133
120
|
return acc;
|
|
@@ -137,15 +124,14 @@ function getIntermediateRepresentation(transformations, hsProfileContents, skipV
|
|
|
137
124
|
const duplicates = transformations
|
|
138
125
|
.filter(t => t.intermediateRepresentation?.uid === uid)
|
|
139
126
|
.map(t => t.fileParseResult.file);
|
|
140
|
-
throw new Error(
|
|
127
|
+
throw new Error(errorMessages.project.duplicateUid(uid, duplicates));
|
|
141
128
|
}
|
|
142
129
|
if (!skipValidation) {
|
|
143
130
|
return {
|
|
144
131
|
...acc,
|
|
145
132
|
// If the uid is not defined just make one up for the sake of indexing.
|
|
146
133
|
// It will still fail validation, but this prevents collisions so we validate all files.
|
|
147
|
-
[uid ||
|
|
148
|
-
`missing-${current.fileParseResult.file}`]: current.intermediateRepresentation,
|
|
134
|
+
[uid || `missing-${current.fileParseResult.file}`]: current.intermediateRepresentation,
|
|
149
135
|
};
|
|
150
136
|
}
|
|
151
137
|
return {
|
|
@@ -159,7 +145,7 @@ function getIntermediateRepresentation(transformations, hsProfileContents, skipV
|
|
|
159
145
|
profileData,
|
|
160
146
|
};
|
|
161
147
|
}
|
|
162
|
-
function getParsingErrors(transformations) {
|
|
148
|
+
export function getParsingErrors(transformations) {
|
|
163
149
|
return transformations
|
|
164
150
|
.filter(t => t.fileParseResult.errors.length > 0)
|
|
165
151
|
.map(t => t.fileParseResult);
|
|
@@ -167,19 +153,19 @@ function getParsingErrors(transformations) {
|
|
|
167
153
|
function getProfileData(hsProfileContents) {
|
|
168
154
|
const profileVariablesForBE = {};
|
|
169
155
|
if (hsProfileContents && hsProfileContents.variables) {
|
|
170
|
-
const profileVariables =
|
|
156
|
+
const profileVariables = getHsProfileVariables(hsProfileContents);
|
|
171
157
|
Object.keys(profileVariables).forEach(key => {
|
|
172
158
|
const profileVar = profileVariables[key];
|
|
173
159
|
let variableTypeForBE;
|
|
174
160
|
switch (typeof profileVar) {
|
|
175
161
|
case 'string':
|
|
176
|
-
variableTypeForBE =
|
|
162
|
+
variableTypeForBE = PROFILE_VARIABLE_TYPES.PROFILE_STRING;
|
|
177
163
|
break;
|
|
178
164
|
case 'number':
|
|
179
|
-
variableTypeForBE =
|
|
165
|
+
variableTypeForBE = getJavaNumberType(profileVar);
|
|
180
166
|
break;
|
|
181
167
|
case 'boolean':
|
|
182
|
-
variableTypeForBE =
|
|
168
|
+
variableTypeForBE = PROFILE_VARIABLE_TYPES.PROFILE_BOOLEAN;
|
|
183
169
|
break;
|
|
184
170
|
default:
|
|
185
171
|
break;
|
|
@@ -194,14 +180,14 @@ function getProfileData(hsProfileContents) {
|
|
|
194
180
|
}
|
|
195
181
|
return { vars: { profileVariables: profileVariablesForBE } };
|
|
196
182
|
}
|
|
197
|
-
function generateServerlessPackageComponent(appFunctionsDirectory, translationContext, componentDeps) {
|
|
198
|
-
const appFunctionsPosix =
|
|
199
|
-
const packageFilePosix =
|
|
200
|
-
const packageLockFilePosix =
|
|
201
|
-
const projectSourceDirPosix =
|
|
202
|
-
const appFunctionsPackageFile =
|
|
203
|
-
if (!
|
|
204
|
-
throw new Error(
|
|
183
|
+
export function generateServerlessPackageComponent(appFunctionsDirectory, translationContext, componentDeps) {
|
|
184
|
+
const appFunctionsPosix = convertPathToPosixPath(appFunctionsDirectory);
|
|
185
|
+
const packageFilePosix = path.posix.join(appFunctionsPosix, PACKAGE_JSON);
|
|
186
|
+
const packageLockFilePosix = path.posix.join(appFunctionsPosix, PACKAGE_LOCK_JSON);
|
|
187
|
+
const projectSourceDirPosix = convertPathToPosixPath(translationContext.projectSourceDir);
|
|
188
|
+
const appFunctionsPackageFile = path.posix.join(projectSourceDirPosix, packageFilePosix);
|
|
189
|
+
if (!fs.existsSync(appFunctionsPackageFile)) {
|
|
190
|
+
throw new Error(errorMessages.project.noPackageJsonForServerless(appFunctionsPackageFile));
|
|
205
191
|
}
|
|
206
192
|
const uid = `hubspot-serverless-package-uid`;
|
|
207
193
|
return {
|
|
@@ -213,12 +199,12 @@ function generateServerlessPackageComponent(appFunctionsDirectory, translationCo
|
|
|
213
199
|
},
|
|
214
200
|
intermediateRepresentation: {
|
|
215
201
|
uid,
|
|
216
|
-
componentType: mapToInternalType(
|
|
202
|
+
componentType: mapToInternalType(APP_FUNCTIONS_PACKAGE_KEY),
|
|
217
203
|
config: {
|
|
218
204
|
packageFile: packageFilePosix,
|
|
219
|
-
packageLockfile:
|
|
205
|
+
packageLockfile: fs.existsSync(
|
|
220
206
|
// Don't use posix here because we are checking the file system
|
|
221
|
-
|
|
207
|
+
path.join(translationContext.projectSourceDir, path.join(appFunctionsDirectory, PACKAGE_LOCK_JSON)))
|
|
222
208
|
? packageLockFilePosix
|
|
223
209
|
: undefined,
|
|
224
210
|
},
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { IntermediateRepresentation, IntermediateRepresentationLocalDev, TranslationContext, TranslationOptions, TranslationOptionsLocalDev } from './types.js';
|
|
2
|
+
export declare function translate(translationContext: TranslationContext, translationOptions?: TranslationOptions): Promise<IntermediateRepresentation>;
|
|
3
|
+
export declare function translateForLocalDev(translationContext: TranslationContext, translationOptions?: TranslationOptionsLocalDev): Promise<IntermediateRepresentationLocalDev>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { loadHsProfileFile, loadHsMetaFiles } from './files.js';
|
|
2
|
+
import { validateIntermediateRepresentation } from './validation.js';
|
|
3
|
+
import { getIntermediateRepresentation, getParsingErrors, transform, } from './transform.js';
|
|
4
|
+
import { errorMessages } from '../lang/copy.js';
|
|
5
|
+
import { getLocalDevProfileData, getLocalDevProjectNodes, getRemovedNodesAndNodesWithErrors, } from './localDev.js';
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
skipValidation: false,
|
|
8
|
+
};
|
|
9
|
+
export async function translate(translationContext, translationOptions = defaultOptions) {
|
|
10
|
+
const { skipValidation } = translationOptions;
|
|
11
|
+
const metafileContents = await loadHsMetaFiles(translationContext);
|
|
12
|
+
if (metafileContents.length === 0) {
|
|
13
|
+
throw new Error(errorMessages.project.noHsMetaFiles);
|
|
14
|
+
}
|
|
15
|
+
let hsProfileContents;
|
|
16
|
+
if (translationOptions.profile) {
|
|
17
|
+
hsProfileContents = loadHsProfileFile(translationContext.projectSourceDir, translationOptions.profile);
|
|
18
|
+
}
|
|
19
|
+
const transformations = transform(metafileContents, translationContext, hsProfileContents);
|
|
20
|
+
const intermediateRepresentation = getIntermediateRepresentation(transformations, hsProfileContents, skipValidation);
|
|
21
|
+
// Remove once extensions and serverless functions are supported
|
|
22
|
+
if (!skipValidation) {
|
|
23
|
+
await validateIntermediateRepresentation(intermediateRepresentation, transformations, translationContext);
|
|
24
|
+
}
|
|
25
|
+
return intermediateRepresentation;
|
|
26
|
+
}
|
|
27
|
+
export async function translateForLocalDev(translationContext, translationOptions) {
|
|
28
|
+
const metafileContents = await loadHsMetaFiles(translationContext);
|
|
29
|
+
if (metafileContents.length === 0) {
|
|
30
|
+
throw new Error(errorMessages.project.noHsMetaFiles);
|
|
31
|
+
}
|
|
32
|
+
let hsProfileContents;
|
|
33
|
+
if (translationOptions?.profile) {
|
|
34
|
+
hsProfileContents = loadHsProfileFile(translationContext.projectSourceDir, translationOptions.profile);
|
|
35
|
+
}
|
|
36
|
+
const transformation = transform(metafileContents, translationContext, hsProfileContents);
|
|
37
|
+
const baseIntermediateRepresentation = getIntermediateRepresentation(transformation, hsProfileContents, true);
|
|
38
|
+
const parsingErrors = getParsingErrors(transformation);
|
|
39
|
+
const projectNodes = getLocalDevProjectNodes(baseIntermediateRepresentation.intermediateNodesIndexedByUid, translationContext.projectSourceDir, translationOptions?.projectNodesAtLastUpload);
|
|
40
|
+
let projectNodesWithErrors = {};
|
|
41
|
+
if (translationOptions?.projectNodesAtLastUpload) {
|
|
42
|
+
projectNodesWithErrors = getRemovedNodesAndNodesWithErrors(baseIntermediateRepresentation.intermediateNodesIndexedByUid, translationOptions.projectNodesAtLastUpload, parsingErrors);
|
|
43
|
+
}
|
|
44
|
+
const profileData = getLocalDevProfileData(baseIntermediateRepresentation.profileData?.vars.profileVariables);
|
|
45
|
+
return {
|
|
46
|
+
intermediateNodesIndexedByUid: {
|
|
47
|
+
...projectNodes,
|
|
48
|
+
...projectNodesWithErrors,
|
|
49
|
+
},
|
|
50
|
+
profileData,
|
|
51
|
+
};
|
|
52
|
+
}
|
package/src/lib/types.d.ts
CHANGED
package/src/lib/types.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
export {};
|
package/src/lib/uid.js
CHANGED
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.validateUid = validateUid;
|
|
5
|
-
exports.coerceToValidUid = coerceToValidUid;
|
|
6
|
-
const copy_1 = require("../lang/copy");
|
|
7
|
-
exports.MAX_UID_LENGTH = 64;
|
|
8
|
-
function validateUid(uid) {
|
|
1
|
+
import { errorMessages } from '../lang/copy.js';
|
|
2
|
+
export const MAX_UID_LENGTH = 64;
|
|
3
|
+
export function validateUid(uid) {
|
|
9
4
|
if (uid === '' || !uid) {
|
|
10
|
-
return
|
|
5
|
+
return errorMessages.validation.emptyUid;
|
|
11
6
|
}
|
|
12
|
-
if (uid.length >
|
|
13
|
-
return
|
|
7
|
+
if (uid.length > MAX_UID_LENGTH) {
|
|
8
|
+
return errorMessages.validation.uidTooLong;
|
|
14
9
|
}
|
|
15
10
|
if (!/^[a-zA-Z0-9_\-.]+$/.test(uid)) {
|
|
16
|
-
return
|
|
11
|
+
return errorMessages.validation.invalidUid;
|
|
17
12
|
}
|
|
18
13
|
}
|
|
19
|
-
function coerceToValidUid(potentialUid) {
|
|
14
|
+
export function coerceToValidUid(potentialUid) {
|
|
20
15
|
if (typeof potentialUid !== 'string') {
|
|
21
16
|
return undefined;
|
|
22
17
|
}
|
|
23
18
|
const newUid = potentialUid.replace(/[^a-zA-Z0-9_\-.]/g, '');
|
|
24
|
-
return newUid.length === 0 ? undefined : newUid.substring(0,
|
|
19
|
+
return newUid.length === 0 ? undefined : newUid.substring(0, MAX_UID_LENGTH);
|
|
25
20
|
}
|
package/src/lib/utils.d.ts
CHANGED
package/src/lib/utils.js
CHANGED
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadJsonFile = loadJsonFile;
|
|
7
|
-
exports.getJavaNumberType = getJavaNumberType;
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const constants_1 = require("./constants");
|
|
10
|
-
function loadJsonFile(filename) {
|
|
11
|
-
return JSON.parse(fs_1.default.readFileSync(filename, {
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import { PROFILE_VARIABLE_TYPES } from './constants.js';
|
|
3
|
+
export function loadJsonFile(filename) {
|
|
4
|
+
return JSON.parse(fs.readFileSync(filename, {
|
|
12
5
|
encoding: 'utf-8',
|
|
13
6
|
}));
|
|
14
7
|
}
|
|
15
|
-
function getJavaNumberType(value) {
|
|
8
|
+
export function getJavaNumberType(value) {
|
|
16
9
|
const JAVA_INT_MIN = -2_147_483_648;
|
|
17
10
|
const JAVA_INT_MAX = 2_147_483_647;
|
|
18
11
|
// Check if the value fits in Java int range
|
|
19
12
|
if (value >= JAVA_INT_MIN && value <= JAVA_INT_MAX) {
|
|
20
|
-
return
|
|
13
|
+
return PROFILE_VARIABLE_TYPES.PROFILE_INT;
|
|
21
14
|
}
|
|
22
|
-
return
|
|
15
|
+
return PROFILE_VARIABLE_TYPES.PROFILE_LONG;
|
|
23
16
|
}
|
package/src/lib/validation.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { CompiledError, IntermediateRepresentation, Transformation, TranslationContext } from './types';
|
|
2
|
-
import
|
|
1
|
+
import { CompiledError, IntermediateRepresentation, Transformation, TranslationContext } from './types.js';
|
|
2
|
+
import { Ajv2020, ValidateFunction } from 'ajv/dist/2020.js';
|
|
3
3
|
export type ValidResult = {
|
|
4
4
|
valid: true;
|
|
5
5
|
errors?: null;
|
|
@@ -10,5 +10,5 @@ export type ValidationResults = {
|
|
|
10
10
|
errors?: CompiledError;
|
|
11
11
|
schemaValidationErrors?: ValidateFunction['errors'];
|
|
12
12
|
} | ValidResult;
|
|
13
|
-
export declare function createAjvInstance():
|
|
13
|
+
export declare function createAjvInstance(): Ajv2020;
|
|
14
14
|
export declare function validateIntermediateRepresentation(intermediateRepresentation: IntermediateRepresentation, transformations: Transformation[], translationContext: TranslationContext): Promise<ValidResult>;
|
package/src/lib/validation.js
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
(0, ajv_formats_1.default)(ajv);
|
|
1
|
+
import { getIntermediateRepresentationSchema } from './schemas.js';
|
|
2
|
+
import { Ajv2020, } from 'ajv/dist/2020.js';
|
|
3
|
+
import { compileError, TranslationError } from './errors.js';
|
|
4
|
+
import { errorMessages } from '../lang/copy.js';
|
|
5
|
+
import { AUTO_GENERATED_COMPONENT_TYPES, Components } from './constants.js';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { findTransformationByUid, mapToUserFacingType } from './transform.js';
|
|
8
|
+
import { validateUid } from './uid.js';
|
|
9
|
+
// ajv-formats does not play nicely with ESM and TS
|
|
10
|
+
import addFormatsModule from 'ajv-formats';
|
|
11
|
+
const addFormats = addFormatsModule;
|
|
12
|
+
export function createAjvInstance() {
|
|
13
|
+
const ajv = new Ajv2020({
|
|
14
|
+
allErrors: true,
|
|
15
|
+
code: { esm: true },
|
|
16
|
+
strict: false, // Allow Draft 2020-12 features
|
|
17
|
+
});
|
|
18
|
+
addFormats(ajv);
|
|
20
19
|
return ajv;
|
|
21
20
|
}
|
|
22
21
|
function validateIntermediateRepresentationNode(schema, transformation, irNode, translationContext) {
|
|
23
|
-
if (
|
|
22
|
+
if (AUTO_GENERATED_COMPONENT_TYPES.includes(mapToUserFacingType(irNode.componentType))) {
|
|
24
23
|
// Skip validation for auto-generated components
|
|
25
24
|
return {
|
|
26
25
|
valid: true,
|
|
@@ -29,51 +28,51 @@ function validateIntermediateRepresentationNode(schema, transformation, irNode,
|
|
|
29
28
|
if (transformation.fileParseResult.errors.length > 0) {
|
|
30
29
|
return {
|
|
31
30
|
valid: false,
|
|
32
|
-
errors:
|
|
31
|
+
errors: compileError(transformation),
|
|
33
32
|
};
|
|
34
33
|
}
|
|
35
34
|
const ajv = createAjvInstance();
|
|
36
35
|
let shouldSkipValidation = false;
|
|
37
36
|
if (!irNode.uid) {
|
|
38
|
-
transformation.fileParseResult.errors.push(
|
|
37
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.missingUid);
|
|
39
38
|
}
|
|
40
39
|
else {
|
|
41
|
-
const uidValidationResult =
|
|
40
|
+
const uidValidationResult = validateUid(irNode.uid);
|
|
42
41
|
if (uidValidationResult) {
|
|
43
42
|
transformation.fileParseResult.errors.push(uidValidationResult);
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
if (!irNode.config) {
|
|
47
|
-
transformation.fileParseResult.errors.push(
|
|
46
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.missingConfig);
|
|
48
47
|
// If there is no config block, there is nothing to validation
|
|
49
48
|
shouldSkipValidation = true;
|
|
50
49
|
}
|
|
51
50
|
if (!schema[irNode.componentType]) {
|
|
52
51
|
if (!irNode.componentType) {
|
|
53
|
-
transformation.fileParseResult.errors.push(
|
|
52
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.missingType);
|
|
54
53
|
}
|
|
55
54
|
else {
|
|
56
|
-
transformation.fileParseResult.errors.push(
|
|
55
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.unsupportedType(irNode.componentType));
|
|
57
56
|
}
|
|
58
57
|
// If there is no schema for the component type, there is no way to validate
|
|
59
58
|
shouldSkipValidation = true;
|
|
60
59
|
}
|
|
61
|
-
const userFacingType =
|
|
62
|
-
const component =
|
|
60
|
+
const userFacingType = mapToUserFacingType(irNode.componentType);
|
|
61
|
+
const component = Components[userFacingType];
|
|
63
62
|
if (userFacingType && component) {
|
|
64
63
|
const expectedParentDir = component.parentComponent
|
|
65
|
-
?
|
|
64
|
+
? Components[component.parentComponent].dir
|
|
66
65
|
: '';
|
|
67
|
-
const expectedLocation =
|
|
68
|
-
const actualLocation =
|
|
66
|
+
const expectedLocation = path.join(expectedParentDir, component.dir);
|
|
67
|
+
const actualLocation = path.dirname(transformation.fileParseResult.file);
|
|
69
68
|
if (expectedLocation !== actualLocation) {
|
|
70
|
-
transformation.fileParseResult.errors.push(
|
|
69
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.wrongDirectoryForComponent(actualLocation, userFacingType, component, path.join(translationContext.projectSourceDir, expectedLocation)));
|
|
71
70
|
}
|
|
72
71
|
}
|
|
73
72
|
if (shouldSkipValidation) {
|
|
74
73
|
return {
|
|
75
74
|
valid: false,
|
|
76
|
-
errors:
|
|
75
|
+
errors: compileError(transformation),
|
|
77
76
|
};
|
|
78
77
|
}
|
|
79
78
|
const validate = ajv.compile(schema[irNode.componentType]);
|
|
@@ -87,7 +86,7 @@ function validateIntermediateRepresentationNode(schema, transformation, irNode,
|
|
|
87
86
|
}
|
|
88
87
|
: {
|
|
89
88
|
valid: false,
|
|
90
|
-
errors:
|
|
89
|
+
errors: compileError(transformation),
|
|
91
90
|
};
|
|
92
91
|
}
|
|
93
92
|
return {
|
|
@@ -95,21 +94,22 @@ function validateIntermediateRepresentationNode(schema, transformation, irNode,
|
|
|
95
94
|
schemaValidationErrors: validate.errors,
|
|
96
95
|
};
|
|
97
96
|
}
|
|
98
|
-
async function validateIntermediateRepresentation(intermediateRepresentation, transformations, translationContext) {
|
|
97
|
+
export async function validateIntermediateRepresentation(intermediateRepresentation, transformations, translationContext) {
|
|
99
98
|
const hasAnyFileParseErrors = transformations.some(t => t.fileParseResult.errors.length > 0);
|
|
100
|
-
const schema = await
|
|
99
|
+
const schema = await getIntermediateRepresentationSchema(translationContext);
|
|
101
100
|
const potentialDuplicatesByComponent = {};
|
|
102
101
|
const results = Object.values(intermediateRepresentation.intermediateNodesIndexedByUid).map(irNode => {
|
|
103
|
-
const userFacingType =
|
|
104
|
-
const component =
|
|
102
|
+
const userFacingType = mapToUserFacingType(irNode.componentType);
|
|
103
|
+
const component = Components[userFacingType];
|
|
105
104
|
if (component && component.singularComponent) {
|
|
106
|
-
potentialDuplicatesByComponent[userFacingType] =
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
potentialDuplicatesByComponent[userFacingType] =
|
|
106
|
+
potentialDuplicatesByComponent[userFacingType]
|
|
107
|
+
? [...potentialDuplicatesByComponent[userFacingType], irNode]
|
|
108
|
+
: [irNode];
|
|
109
109
|
}
|
|
110
|
-
const transformation =
|
|
110
|
+
const transformation = findTransformationByUid(transformations, irNode.uid);
|
|
111
111
|
if (!transformation) {
|
|
112
|
-
return { valid: false, errors: [
|
|
112
|
+
return { valid: false, errors: [errorMessages.validation.missingUid] };
|
|
113
113
|
}
|
|
114
114
|
return validateIntermediateRepresentationNode(schema, transformation, irNode, translationContext);
|
|
115
115
|
});
|
|
@@ -120,9 +120,9 @@ async function validateIntermediateRepresentation(intermediateRepresentation, tr
|
|
|
120
120
|
}
|
|
121
121
|
hasDuplicates = true;
|
|
122
122
|
potentialDuplicates.forEach(duplicate => {
|
|
123
|
-
const potentialDuplicateTransformation =
|
|
123
|
+
const potentialDuplicateTransformation = findTransformationByUid(transformations, duplicate.uid);
|
|
124
124
|
if (potentialDuplicateTransformation) {
|
|
125
|
-
potentialDuplicateTransformation.fileParseResult.errors.push(
|
|
125
|
+
potentialDuplicateTransformation.fileParseResult.errors.push(errorMessages.project.duplicateComponent(componentType));
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
});
|
|
@@ -135,5 +135,5 @@ async function validateIntermediateRepresentation(intermediateRepresentation, tr
|
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
const schemaValidationErrors = results.map(result => 'schemaValidationErrors' in result ? result.schemaValidationErrors : null);
|
|
138
|
-
throw new
|
|
138
|
+
throw new TranslationError(errorMessages.project.failedToTranslateProject, transformations, schemaValidationErrors, translationContext);
|
|
139
139
|
}
|
package/src/index.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { IntermediateRepresentation, IntermediateRepresentationNode, IntermediateRepresentationLocalDev, TranslationContext, TranslationOptions, IntermediateRepresentationNodeLocalDev, TranslationOptionsLocalDev } from './lib/types';
|
|
2
|
-
import { ValidateFunction, AnySchema, ErrorObject } from 'ajv/dist/2020';
|
|
3
|
-
export declare function translate(translationContext: TranslationContext, translationOptions?: TranslationOptions): Promise<IntermediateRepresentation>;
|
|
4
|
-
export declare function translateForLocalDev(translationContext: TranslationContext, translationOptions?: TranslationOptionsLocalDev): Promise<IntermediateRepresentationLocalDev>;
|
|
5
|
-
export { isTranslationError } from './lib/errors';
|
|
6
|
-
export { IntermediateRepresentation, IntermediateRepresentationNode, IntermediateRepresentationLocalDev, IntermediateRepresentationNodeLocalDev, TranslationContext, };
|
|
7
|
-
export { getHsProfileFilename, validateProfileVariables } from './lib/profiles';
|
|
8
|
-
export { loadHsProfileFile, getAllHsProfiles, projectContainsHsMetaFiles, } from './lib/files';
|
|
9
|
-
export { migrate } from './lib/migrate';
|
|
10
|
-
export { validateUid, coerceToValidUid } from './lib/uid';
|
|
11
|
-
export { mapToUserFriendlyName, mapToInternalType } from './lib/transform';
|
|
12
|
-
export { getIntermediateRepresentationSchema } from './lib/schemas';
|
|
13
|
-
export { createAjvInstance } from './lib/validation';
|
|
14
|
-
export { ValidateFunction, AnySchema, ErrorObject };
|
|
15
|
-
export { metafileExtension, hsProjectJsonFilename } from './lib/constants';
|
|
16
|
-
export { Components } from './lib/types';
|
|
17
|
-
export { AjvErrorKeyword } from './lib/errors';
|
|
18
|
-
export { getInvalidJsonError, getMissingTypeError, getMissingConfigError, getMissingAccountIdError, getMissingRequiredFieldError, getFailedToFetchSchemasError, getUnsupportedTypeError, } from './lang/copy';
|
|
19
|
-
export { migrateThemes, getProjectThemeDetails } from './lib/migrateThemes';
|