@hubspot/project-parsing-lib 0.2.0 → 0.2.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 +2 -1
- package/src/index.d.ts +1 -1
- package/src/index.js +2 -1
- package/src/lang/copy.js +1 -1
- package/src/lib/errors.d.ts +1 -0
- package/src/lib/errors.js +50 -18
- package/src/lib/files.d.ts +1 -0
- package/src/lib/files.js +7 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/project-parsing-lib",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Parsing library for converting projects directory structures to their intermediate representation",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"prettier:write": "prettier ./src/** --write",
|
|
38
38
|
"test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ./node_modules/.bin/jest",
|
|
39
39
|
"release": "yarn ts-node ./scripts/release.ts release",
|
|
40
|
+
"reset-north-star": "git submodule update --init",
|
|
40
41
|
"acceptance-test": "yarn --cwd=./acceptance-tests test",
|
|
41
42
|
"update-north-star": "git submodule update --remote --merge"
|
|
42
43
|
},
|
package/src/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare function translateForLocalDev(translationContext: TranslationCont
|
|
|
5
5
|
export { isTranslationError } from './lib/errors';
|
|
6
6
|
export { IntermediateRepresentation, IntermediateRepresentationNode, IntermediateRepresentationLocalDev, IntermediateRepresentationNodeLocalDev, TranslationContext, };
|
|
7
7
|
export { getHsProfileFilename } from './lib/profiles';
|
|
8
|
-
export { loadHsProfileFile, getAllHsProfiles } from './lib/files';
|
|
8
|
+
export { loadHsProfileFile, getAllHsProfiles, projectContainsHsMetaFiles, } from './lib/files';
|
|
9
9
|
export { migrate } from './lib/migrate';
|
|
10
10
|
export { validateUid } from './lib/uid';
|
|
11
11
|
export { mapToUserFriendlyName, mapToInternalType } from './lib/transform';
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getUnsupportedTypeError = exports.getFailedToFetchSchemasError = exports.getMissingRequiredFieldError = exports.getMissingAccountIdError = exports.getMissingConfigError = exports.getMissingTypeError = exports.getInvalidJsonError = exports.AjvErrorKeyword = exports.hsProjectJsonFilename = exports.metafileExtension = exports.createAjvInstance = exports.getIntermediateRepresentationSchema = exports.mapToInternalType = exports.mapToUserFriendlyName = exports.validateUid = exports.migrate = exports.getAllHsProfiles = exports.loadHsProfileFile = exports.getHsProfileFilename = exports.isTranslationError = void 0;
|
|
6
|
+
exports.getUnsupportedTypeError = exports.getFailedToFetchSchemasError = exports.getMissingRequiredFieldError = exports.getMissingAccountIdError = exports.getMissingConfigError = exports.getMissingTypeError = exports.getInvalidJsonError = exports.AjvErrorKeyword = exports.hsProjectJsonFilename = exports.metafileExtension = exports.createAjvInstance = exports.getIntermediateRepresentationSchema = exports.mapToInternalType = exports.mapToUserFriendlyName = exports.validateUid = exports.migrate = exports.projectContainsHsMetaFiles = exports.getAllHsProfiles = exports.loadHsProfileFile = exports.getHsProfileFilename = exports.isTranslationError = void 0;
|
|
7
7
|
exports.translate = translate;
|
|
8
8
|
exports.translateForLocalDev = translateForLocalDev;
|
|
9
9
|
const files_1 = require("./lib/files");
|
|
@@ -60,6 +60,7 @@ Object.defineProperty(exports, "getHsProfileFilename", { enumerable: true, get:
|
|
|
60
60
|
var files_2 = require("./lib/files");
|
|
61
61
|
Object.defineProperty(exports, "loadHsProfileFile", { enumerable: true, get: function () { return files_2.loadHsProfileFile; } });
|
|
62
62
|
Object.defineProperty(exports, "getAllHsProfiles", { enumerable: true, get: function () { return files_2.getAllHsProfiles; } });
|
|
63
|
+
Object.defineProperty(exports, "projectContainsHsMetaFiles", { enumerable: true, get: function () { return files_2.projectContainsHsMetaFiles; } });
|
|
63
64
|
var migrate_1 = require("./lib/migrate");
|
|
64
65
|
Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return migrate_1.migrate; } });
|
|
65
66
|
var uid_1 = require("./lib/uid");
|
package/src/lang/copy.js
CHANGED
|
@@ -39,7 +39,7 @@ exports.errorMessages = {
|
|
|
39
39
|
missingType: `Missing required field: 'type'`,
|
|
40
40
|
missingConfig: `Missing required field: 'config'`,
|
|
41
41
|
unsupportedType: (type) => `Unsupported type: ${(0, transform_1.mapToUserFacingType)(type)}`,
|
|
42
|
-
errorWithField: (field, error) =>
|
|
42
|
+
errorWithField: (field, error) => `${field}: ${error || 'Unknown error'}`,
|
|
43
43
|
invalidJson: 'Invalid JSON',
|
|
44
44
|
wrongDirectoryForComponent: (directory, componentType, componentMetadata, correctDir) => `The directory '${directory}' is incorrect for type '${componentType}'. ${componentMetadata.userFriendlyName} ${componentMetadata.userFriendlyTypePlural} should only be placed in the '${correctDir}' directory`,
|
|
45
45
|
},
|
package/src/lib/errors.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class TranslationError extends Error {
|
|
|
8
8
|
constructor(message: string, transformations: Transformation[], errors: (ErrorObject[] | null | undefined)[], translationContext: TranslationContext);
|
|
9
9
|
toString(): string;
|
|
10
10
|
}
|
|
11
|
+
export declare function extractDotNotationValueFromTransformation(dotNotation: string, transformation: Transformation): unknown;
|
|
11
12
|
export declare const AjvErrorKeyword: {
|
|
12
13
|
AdditionalItems: string;
|
|
13
14
|
AdditionalProperties: string;
|
package/src/lib/errors.js
CHANGED
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.AjvErrorKeyword = exports.TranslationError = void 0;
|
|
7
7
|
exports.isTranslationError = isTranslationError;
|
|
8
8
|
exports.compileError = compileError;
|
|
9
|
+
exports.extractDotNotationValueFromTransformation = extractDotNotationValueFromTransformation;
|
|
9
10
|
const copy_1 = require("../lang/copy");
|
|
10
11
|
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const logger_1 = require("@hubspot/local-dev-lib/logger");
|
|
11
13
|
function isTranslationError(error) {
|
|
12
14
|
return error instanceof TranslationError;
|
|
13
15
|
}
|
|
@@ -33,9 +35,11 @@ class TranslationError extends Error {
|
|
|
33
35
|
if (errors.length === 0) {
|
|
34
36
|
return null;
|
|
35
37
|
}
|
|
36
|
-
|
|
38
|
+
const projectRoot = path_1.default.dirname(path_1.default.dirname(this.translationContext.projectSourceDir));
|
|
39
|
+
const relativePath = path_1.default.relative(projectRoot, path_1.default.join(this.translationContext.projectSourceDir, file));
|
|
40
|
+
return copy_1.errorMessages.validation.errorWithFileHeader(relativePath, errors);
|
|
37
41
|
});
|
|
38
|
-
return `${this.message}
|
|
42
|
+
return `${this.message}:${listOfErrors
|
|
39
43
|
.filter(error => error !== null)
|
|
40
44
|
.join('')}`;
|
|
41
45
|
}
|
|
@@ -61,16 +65,16 @@ function compileTranslationErrors(transformation, schemaErrors) {
|
|
|
61
65
|
// If there is a one of error, we need to preprocess the errors to group them by instancePath and keyword
|
|
62
66
|
// This allows us to group data from the errors that correspond to the same field
|
|
63
67
|
if (hasOneOfErrors) {
|
|
64
|
-
errors.push(...preprocessSpecialErrors(schemaErrors));
|
|
68
|
+
errors.push(...preprocessSpecialErrors(schemaErrors, transformation));
|
|
65
69
|
}
|
|
66
70
|
else {
|
|
67
71
|
schemaErrors?.forEach(error => {
|
|
68
|
-
errors.push(generateErrorMessage(error));
|
|
72
|
+
errors.push(generateErrorMessage(error, transformation));
|
|
69
73
|
});
|
|
70
74
|
}
|
|
71
75
|
return { file, errors };
|
|
72
76
|
}
|
|
73
|
-
function preprocessSpecialErrors(schemaErrors) {
|
|
77
|
+
function preprocessSpecialErrors(schemaErrors, transformation) {
|
|
74
78
|
const errors = [];
|
|
75
79
|
const preprocessedErrors = {};
|
|
76
80
|
schemaErrors?.forEach(error => {
|
|
@@ -94,11 +98,11 @@ function preprocessSpecialErrors(schemaErrors) {
|
|
|
94
98
|
}
|
|
95
99
|
return cur;
|
|
96
100
|
});
|
|
97
|
-
errors.push(generateErrorMessage(newValue));
|
|
101
|
+
errors.push(generateErrorMessage(newValue, transformation));
|
|
98
102
|
});
|
|
99
103
|
return errors;
|
|
100
104
|
}
|
|
101
|
-
function generateErrorMessage(error) {
|
|
105
|
+
function generateErrorMessage(error, transformation) {
|
|
102
106
|
const errorPath = generateDotNotationPath(error);
|
|
103
107
|
const errorMessage = copy_1.errorMessages.validation.errorWithField(errorPath, error.message);
|
|
104
108
|
const params = Object.entries(error.params);
|
|
@@ -112,7 +116,11 @@ function generateErrorMessage(error) {
|
|
|
112
116
|
return copy_1.errorMessages.validation.missingRequiredField(`${errorPath}.${error.params.missingProperty}`);
|
|
113
117
|
}
|
|
114
118
|
else if (isTypeError(error)) {
|
|
115
|
-
|
|
119
|
+
const dotNotationPath = generateDotNotationPath(error);
|
|
120
|
+
const value = extractDotNotationValueFromTransformation(dotNotationPath, transformation);
|
|
121
|
+
return copy_1.errorMessages.validation.errorWithField(value !== undefined
|
|
122
|
+
? `Value (${value}) in ${dotNotationPath}`
|
|
123
|
+
: dotNotationPath, error.message);
|
|
116
124
|
}
|
|
117
125
|
// Default case, it is not an error we know how to deal with
|
|
118
126
|
return `${errorMessage} ${additionalContext.length > 0
|
|
@@ -134,23 +142,47 @@ function mergeEnumErrors(cur, next) {
|
|
|
134
142
|
},
|
|
135
143
|
};
|
|
136
144
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
145
|
+
function extractDotNotationValueFromTransformation(dotNotation, transformation) {
|
|
146
|
+
try {
|
|
147
|
+
const parts = dotNotation.split('.');
|
|
148
|
+
if (!transformation?.fileParseResult?.content || parts.length === 0) {
|
|
149
|
+
return undefined;
|
|
150
|
+
}
|
|
151
|
+
let value = transformation.fileParseResult.content;
|
|
152
|
+
// Traverse the nested objects and lists to get the end value
|
|
153
|
+
parts.forEach(item => {
|
|
154
|
+
// @ts-expect-error value is unknown since it is user generated config
|
|
155
|
+
const newValue = value[item];
|
|
156
|
+
if (newValue &&
|
|
157
|
+
typeof newValue === 'object' &&
|
|
158
|
+
!Array.isArray(newValue)) {
|
|
159
|
+
value = Object.assign(Object.create(null), newValue);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
value = newValue;
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// If the value is an object/array, stringify the value so it doesn't log as [object Object] or '' for array
|
|
166
|
+
if (typeof value === 'object' && !!value) {
|
|
167
|
+
return JSON.stringify(value);
|
|
168
|
+
}
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
logger_1.logger.debug('Unable to parse dot notation path to located value', e);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
143
175
|
function isOneOfError(error) {
|
|
144
|
-
return error.keyword ===
|
|
176
|
+
return error.keyword === exports.AjvErrorKeyword.OneOf;
|
|
145
177
|
}
|
|
146
178
|
function isRequiredError(error) {
|
|
147
|
-
return error.keyword ===
|
|
179
|
+
return error.keyword === exports.AjvErrorKeyword.Required;
|
|
148
180
|
}
|
|
149
181
|
function isEnumError(error) {
|
|
150
|
-
return error.keyword ===
|
|
182
|
+
return error.keyword === exports.AjvErrorKeyword.Enum;
|
|
151
183
|
}
|
|
152
184
|
function isTypeError(error) {
|
|
153
|
-
return error.keyword ===
|
|
185
|
+
return error.keyword === exports.AjvErrorKeyword.Type;
|
|
154
186
|
}
|
|
155
187
|
exports.AjvErrorKeyword = {
|
|
156
188
|
AdditionalItems: 'additionalItems',
|
package/src/lib/files.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ import { FileParseResult, TranslationContext, HsProfileFile } from './types';
|
|
|
2
2
|
export declare function loadHsProfileFile(projectSourceDir: string, profile: string): HsProfileFile;
|
|
3
3
|
export declare function getAllHsProfiles(projectSourceDir: string): Promise<string[]>;
|
|
4
4
|
export declare function loadHsMetaFiles(translationContext: TranslationContext): Promise<FileParseResult[]>;
|
|
5
|
+
export declare function projectContainsHsMetaFiles(projectSourceDir: string): Promise<boolean>;
|
package/src/lib/files.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.loadHsProfileFile = loadHsProfileFile;
|
|
7
7
|
exports.getAllHsProfiles = getAllHsProfiles;
|
|
8
8
|
exports.loadHsMetaFiles = loadHsMetaFiles;
|
|
9
|
+
exports.projectContainsHsMetaFiles = projectContainsHsMetaFiles;
|
|
9
10
|
const fs_1 = __importDefault(require("fs"));
|
|
10
11
|
const path_1 = __importDefault(require("path"));
|
|
11
12
|
const fs_2 = require("@hubspot/local-dev-lib/fs");
|
|
@@ -41,11 +42,10 @@ function getAllHsProfiles(projectSourceDir) {
|
|
|
41
42
|
});
|
|
42
43
|
}
|
|
43
44
|
async function loadHsMetaFiles(translationContext) {
|
|
44
|
-
const metaFiles = await locateHsMetaFiles(translationContext);
|
|
45
|
+
const metaFiles = await locateHsMetaFiles(translationContext.projectSourceDir);
|
|
45
46
|
return parseHsMetaFiles(metaFiles, translationContext);
|
|
46
47
|
}
|
|
47
|
-
async function locateHsMetaFiles(
|
|
48
|
-
const { projectSourceDir } = translationContext;
|
|
48
|
+
async function locateHsMetaFiles(projectSourceDir) {
|
|
49
49
|
return (await (0, fs_2.walk)(projectSourceDir, ['node_modules'])).reduce((metaFiles, file) => {
|
|
50
50
|
if (!file.endsWith(constants_1.metafileExtension)) {
|
|
51
51
|
return metaFiles;
|
|
@@ -105,3 +105,7 @@ function parseFile(fileLoadResult) {
|
|
|
105
105
|
}
|
|
106
106
|
return { ...fileLoadResult, content: parsedFileContents };
|
|
107
107
|
}
|
|
108
|
+
async function projectContainsHsMetaFiles(projectSourceDir) {
|
|
109
|
+
const hsMetaFiles = (await (0, fs_2.walk)(projectSourceDir, ['node_modules'])).filter(file => file.endsWith(constants_1.metafileExtension));
|
|
110
|
+
return hsMetaFiles.length > 0;
|
|
111
|
+
}
|