@hubspot/project-parsing-lib 0.1.11 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/project-parsing-lib",
3
- "version": "0.1.11",
3
+ "version": "0.2.0-beta.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",
@@ -33,7 +33,7 @@
33
33
  "build": "ts-node ./scripts/build.ts",
34
34
  "lint": "echo 'Linting is disabled for Blazar'",
35
35
  "lint:local": "eslint --max-warnings=0 . && prettier ./src/** --check",
36
- "local-dev": "yarn build && yarn link --cwd=./dist && tsc --watch --rootDir . --outdir dist",
36
+ "local-dev": "yarn build && cd dist && yarn link && cd .. && tsc --watch --rootDir . --outdir dist",
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",
package/src/index.d.ts CHANGED
@@ -1,9 +1,18 @@
1
1
  import { IntermediateRepresentation, IntermediateRepresentationNode, IntermediateRepresentationLocalDev, TranslationContext, TranslationOptions, IntermediateRepresentationNodeLocalDev } from './lib/types';
2
+ import { ValidateFunction, AnySchema, ErrorObject } from 'ajv/dist/2020';
2
3
  export declare function translate(translationContext: TranslationContext, translationOptions?: TranslationOptions): Promise<IntermediateRepresentation>;
3
- export declare function translateForLocalDev(translationContext: TranslationContext): Promise<IntermediateRepresentationLocalDev>;
4
+ export declare function translateForLocalDev(translationContext: TranslationContext, translationOptions?: Pick<TranslationOptions, 'profile'>): Promise<IntermediateRepresentationLocalDev>;
4
5
  export { isTranslationError } from './lib/errors';
5
6
  export { IntermediateRepresentation, IntermediateRepresentationNode, IntermediateRepresentationLocalDev, IntermediateRepresentationNodeLocalDev, TranslationContext, };
7
+ export { getHsProfileFilename } from './lib/profiles';
8
+ export { loadHsProfileFile, getAllHsProfiles } from './lib/files';
6
9
  export { migrate } from './lib/migrate';
7
10
  export { validateUid } from './lib/uid';
8
11
  export { mapToUserFriendlyName, mapToInternalType } from './lib/transform';
9
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';
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.getIntermediateRepresentationSchema = exports.mapToInternalType = exports.mapToUserFriendlyName = exports.validateUid = exports.migrate = 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.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");
@@ -20,7 +20,11 @@ async function translate(translationContext, translationOptions = defaultOptions
20
20
  if (metafileContents.length === 0) {
21
21
  throw new Error(copy_1.errorMessages.project.noHsMetaFiles);
22
22
  }
23
- const transformation = (0, transform_1.transform)(metafileContents, translationContext);
23
+ let hsProfileContents;
24
+ if (translationOptions.profile) {
25
+ hsProfileContents = (0, files_1.loadHsProfileFile)(translationContext.projectSourceDir, translationOptions.profile);
26
+ }
27
+ const transformation = (0, transform_1.transform)(metafileContents, translationContext, hsProfileContents);
24
28
  const intermediateRepresentation = (0, transform_1.getIntermediateRepresentation)(transformation, skipValidation);
25
29
  // Remove once extensions and serverless functions are supported
26
30
  if (!skipValidation) {
@@ -28,8 +32,11 @@ async function translate(translationContext, translationOptions = defaultOptions
28
32
  }
29
33
  return intermediateRepresentation;
30
34
  }
31
- async function translateForLocalDev(translationContext) {
32
- const IR = await translate(translationContext, { skipValidation: true });
35
+ async function translateForLocalDev(translationContext, translationOptions) {
36
+ const IR = await translate(translationContext, {
37
+ skipValidation: true,
38
+ profile: translationOptions?.profile,
39
+ });
33
40
  const localDevIr = {
34
41
  intermediateNodesIndexedByUid: {},
35
42
  };
@@ -48,6 +55,11 @@ async function translateForLocalDev(translationContext) {
48
55
  }
49
56
  var errors_1 = require("./lib/errors");
50
57
  Object.defineProperty(exports, "isTranslationError", { enumerable: true, get: function () { return errors_1.isTranslationError; } });
58
+ var profiles_1 = require("./lib/profiles");
59
+ Object.defineProperty(exports, "getHsProfileFilename", { enumerable: true, get: function () { return profiles_1.getHsProfileFilename; } });
60
+ var files_2 = require("./lib/files");
61
+ Object.defineProperty(exports, "loadHsProfileFile", { enumerable: true, get: function () { return files_2.loadHsProfileFile; } });
62
+ Object.defineProperty(exports, "getAllHsProfiles", { enumerable: true, get: function () { return files_2.getAllHsProfiles; } });
51
63
  var migrate_1 = require("./lib/migrate");
52
64
  Object.defineProperty(exports, "migrate", { enumerable: true, get: function () { return migrate_1.migrate; } });
53
65
  var uid_1 = require("./lib/uid");
@@ -57,3 +69,18 @@ Object.defineProperty(exports, "mapToUserFriendlyName", { enumerable: true, get:
57
69
  Object.defineProperty(exports, "mapToInternalType", { enumerable: true, get: function () { return transform_2.mapToInternalType; } });
58
70
  var schemas_1 = require("./lib/schemas");
59
71
  Object.defineProperty(exports, "getIntermediateRepresentationSchema", { enumerable: true, get: function () { return schemas_1.getIntermediateRepresentationSchema; } });
72
+ var validation_2 = require("./lib/validation");
73
+ Object.defineProperty(exports, "createAjvInstance", { enumerable: true, get: function () { return validation_2.createAjvInstance; } });
74
+ var constants_1 = require("./lib/constants");
75
+ Object.defineProperty(exports, "metafileExtension", { enumerable: true, get: function () { return constants_1.metafileExtension; } });
76
+ Object.defineProperty(exports, "hsProjectJsonFilename", { enumerable: true, get: function () { return constants_1.hsProjectJsonFilename; } });
77
+ var errors_2 = require("./lib/errors");
78
+ Object.defineProperty(exports, "AjvErrorKeyword", { enumerable: true, get: function () { return errors_2.AjvErrorKeyword; } });
79
+ var copy_2 = require("./lang/copy");
80
+ Object.defineProperty(exports, "getInvalidJsonError", { enumerable: true, get: function () { return copy_2.getInvalidJsonError; } });
81
+ Object.defineProperty(exports, "getMissingTypeError", { enumerable: true, get: function () { return copy_2.getMissingTypeError; } });
82
+ Object.defineProperty(exports, "getMissingConfigError", { enumerable: true, get: function () { return copy_2.getMissingConfigError; } });
83
+ Object.defineProperty(exports, "getMissingAccountIdError", { enumerable: true, get: function () { return copy_2.getMissingAccountIdError; } });
84
+ Object.defineProperty(exports, "getMissingRequiredFieldError", { enumerable: true, get: function () { return copy_2.getMissingRequiredFieldError; } });
85
+ Object.defineProperty(exports, "getFailedToFetchSchemasError", { enumerable: true, get: function () { return copy_2.getFailedToFetchSchemasError; } });
86
+ Object.defineProperty(exports, "getUnsupportedTypeError", { enumerable: true, get: function () { return copy_2.getUnsupportedTypeError; } });
@@ -12,6 +12,12 @@ export declare const errorMessages: {
12
12
  noPackageJsonForServerless: (appFunctionsPackageFile: string) => string;
13
13
  fileContentMissingFor: (file: string) => string;
14
14
  };
15
+ profile: {
16
+ noProfileSpecified: string;
17
+ failedToLoadHsProfile: (profile: string) => string;
18
+ missingValue: (key: string, file: string) => string;
19
+ invalidValue: (key: string) => string;
20
+ };
15
21
  validation: {
16
22
  errorWithFileHeader: (file: string, errors: string[]) => string;
17
23
  missingRequiredField: (field: string) => string;
@@ -27,6 +33,13 @@ export declare const errorMessages: {
27
33
  wrongDirectoryForComponent: (directory: string, componentType: string, componentMetadata: ComponentMetadata, correctDir: string) => string;
28
34
  };
29
35
  };
36
+ export declare function getInvalidJsonError(): string;
37
+ export declare function getMissingTypeError(): string;
38
+ export declare function getMissingConfigError(): string;
39
+ export declare function getMissingAccountIdError(): string;
40
+ export declare function getMissingRequiredFieldError(field: string): string;
41
+ export declare function getFailedToFetchSchemasError(): string;
42
+ export declare function getUnsupportedTypeError(type: string): string;
30
43
  export declare const logMessages: {
31
44
  files: {
32
45
  skippingPath: (path: string) => string;
package/src/lang/copy.js CHANGED
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logMessages = exports.errorMessages = void 0;
4
+ exports.getInvalidJsonError = getInvalidJsonError;
5
+ exports.getMissingTypeError = getMissingTypeError;
6
+ exports.getMissingConfigError = getMissingConfigError;
7
+ exports.getMissingAccountIdError = getMissingAccountIdError;
8
+ exports.getMissingRequiredFieldError = getMissingRequiredFieldError;
9
+ exports.getFailedToFetchSchemasError = getFailedToFetchSchemasError;
10
+ exports.getUnsupportedTypeError = getUnsupportedTypeError;
4
11
  const constants_1 = require("../lib/constants");
5
12
  const transform_1 = require("../lib/transform");
6
13
  exports.errorMessages = {
@@ -16,6 +23,12 @@ exports.errorMessages = {
16
23
  noPackageJsonForServerless: (appFunctionsPackageFile) => `${appFunctionsPackageFile} does not exist. ${constants_1.Components[constants_1.AppFunctionsKey].userFriendlyName} requires a ${constants_1.packageJson} file to exist in this location`,
17
24
  fileContentMissingFor: (file) => `File content is missing for ${file}`,
18
25
  },
26
+ profile: {
27
+ noProfileSpecified: 'No profile specified',
28
+ failedToLoadHsProfile: (profile) => `Failed to load profile ${profile}`,
29
+ missingValue: (key, file) => `Missing value for ${key} in ${file}. Add ${key} to your profile variables.`,
30
+ invalidValue: (key) => `Invalid value for ${key}. Value must be a string, number, or boolean.`,
31
+ },
19
32
  validation: {
20
33
  errorWithFileHeader: (file, errors) => `\n\nEncountered the following errors for ${file}:\n\t- ${errors.join('\n\t- ')}`,
21
34
  missingRequiredField: (field) => `Missing required field: '${field}'`,
@@ -31,6 +44,27 @@ exports.errorMessages = {
31
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`,
32
45
  },
33
46
  };
47
+ function getInvalidJsonError() {
48
+ return exports.errorMessages.validation.invalidJson;
49
+ }
50
+ function getMissingTypeError() {
51
+ return exports.errorMessages.validation.missingType;
52
+ }
53
+ function getMissingConfigError() {
54
+ return exports.errorMessages.validation.missingConfig;
55
+ }
56
+ function getMissingAccountIdError() {
57
+ return exports.errorMessages.api.accountIdIsRequiredToFetchSchemas;
58
+ }
59
+ function getMissingRequiredFieldError(field) {
60
+ return exports.errorMessages.validation.missingRequiredField(field);
61
+ }
62
+ function getFailedToFetchSchemasError() {
63
+ return exports.errorMessages.api.failedToFetchSchemas;
64
+ }
65
+ function getUnsupportedTypeError(type) {
66
+ return exports.errorMessages.validation.unsupportedType(type);
67
+ }
34
68
  exports.logMessages = {
35
69
  files: {
36
70
  skippingPath: (path) => `Skipping ${path} as it is not in a valid directory`,
@@ -27,6 +27,8 @@ export declare const Components: Record<string, ComponentMetadata>;
27
27
  export declare const userFacingToInternalType: Record<string, string>;
28
28
  export declare const internalTypeToUserFacing: Record<string, string>;
29
29
  export declare const metafileExtension = "-hsmeta.json";
30
+ export declare const profileFilePrefix = "hsprofile";
31
+ export declare const hsProjectJsonFilename = "hsproject.json";
30
32
  export declare const packageJson = "package.json";
31
33
  export declare const packageLockJson = "package-lock.json";
32
34
  export declare const allowedAppSubComponentsDirs: string[];
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.allowedSubComponentDirectories = exports.allowedComponentDirectories = exports.ProjectStructure = exports.allowedThemeSubComponentsDirs = exports.allowedAppSubComponentsDirs = exports.packageLockJson = exports.packageJson = exports.metafileExtension = exports.internalTypeToUserFacing = exports.userFacingToInternalType = exports.Components = exports.AutoGeneratedComponentTypes = exports.AppFunctionsPackageKey = exports.WorkflowActionsKey = exports.WebhooksKey = exports.VideoConferencingKey = exports.TimelineEventsKey = exports.MediaBridgeKey = exports.MarketingEventsKey = exports.SettingsKey = exports.CardsKey = exports.CallingKey = exports.AppObjectAssociationKey = exports.AppObjectKey = exports.AppFunctionsKey = exports.ThemeKey = exports.AppKey = void 0;
36
+ exports.allowedSubComponentDirectories = exports.allowedComponentDirectories = exports.ProjectStructure = exports.allowedThemeSubComponentsDirs = exports.allowedAppSubComponentsDirs = exports.packageLockJson = exports.packageJson = exports.hsProjectJsonFilename = exports.profileFilePrefix = exports.metafileExtension = exports.internalTypeToUserFacing = exports.userFacingToInternalType = exports.Components = exports.AutoGeneratedComponentTypes = exports.AppFunctionsPackageKey = exports.WorkflowActionsKey = exports.WebhooksKey = exports.VideoConferencingKey = exports.TimelineEventsKey = exports.MediaBridgeKey = exports.MarketingEventsKey = exports.SettingsKey = exports.CardsKey = exports.CallingKey = exports.AppObjectAssociationKey = exports.AppObjectKey = exports.AppFunctionsKey = exports.ThemeKey = exports.AppKey = void 0;
37
37
  // Top Level Component types
38
38
  const path = __importStar(require("path"));
39
39
  // Component types
@@ -159,6 +159,8 @@ exports.userFacingToInternalType = {
159
159
  };
160
160
  exports.internalTypeToUserFacing = Object.fromEntries(Object.entries(exports.userFacingToInternalType).map(([key, value]) => [value, key]));
161
161
  exports.metafileExtension = '-hsmeta.json';
162
+ exports.profileFilePrefix = 'hsprofile';
163
+ exports.hsProjectJsonFilename = 'hsproject.json';
162
164
  exports.packageJson = 'package.json';
163
165
  exports.packageLockJson = 'package-lock.json';
164
166
  function getSubComponentDirsForParentType(parentComponent) {
@@ -8,3 +8,24 @@ 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 const AjvErrorKeyword: {
12
+ AdditionalItems: string;
13
+ AdditionalProperties: string;
14
+ Dependencies: string;
15
+ Enum: string;
16
+ ExclusiveMaximum: string;
17
+ ExclusiveMinimum: string;
18
+ Maximum: string;
19
+ MaxItems: string;
20
+ MaxLength: string;
21
+ MaxProperties: string;
22
+ Minimum: string;
23
+ MinItems: string;
24
+ MinLength: string;
25
+ MinProperties: string;
26
+ MultipleOf: string;
27
+ OneOf: string;
28
+ Pattern: string;
29
+ Required: string;
30
+ Type: string;
31
+ };
package/src/lib/errors.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.TranslationError = void 0;
6
+ exports.AjvErrorKeyword = exports.TranslationError = void 0;
7
7
  exports.isTranslationError = isTranslationError;
8
8
  exports.compileError = compileError;
9
9
  const copy_1 = require("../lang/copy");
@@ -152,3 +152,24 @@ function isEnumError(error) {
152
152
  function isTypeError(error) {
153
153
  return error.keyword === JSON_SCHEMA_VALIDATION_KEYWORDS.type;
154
154
  }
155
+ exports.AjvErrorKeyword = {
156
+ AdditionalItems: 'additionalItems',
157
+ AdditionalProperties: 'additionalProperties',
158
+ Dependencies: 'dependencies',
159
+ Enum: 'enum',
160
+ ExclusiveMaximum: 'exclusiveMaximum',
161
+ ExclusiveMinimum: 'exclusiveMinimum',
162
+ Maximum: 'maximum',
163
+ MaxItems: 'maxItems',
164
+ MaxLength: 'maxLength',
165
+ MaxProperties: 'maxProperties',
166
+ Minimum: 'minimum',
167
+ MinItems: 'minItems',
168
+ MinLength: 'minLength',
169
+ MinProperties: 'minProperties',
170
+ MultipleOf: 'multipleOf',
171
+ OneOf: 'oneOf',
172
+ Pattern: 'pattern',
173
+ Required: 'required',
174
+ Type: 'type',
175
+ };
@@ -1,2 +1,4 @@
1
- import { FileParseResult, TranslationContext } from './types';
1
+ import { FileParseResult, TranslationContext, HsProfileFile } from './types';
2
+ export declare function loadHsProfileFile(projectSourceDir: string, profile: string): HsProfileFile;
3
+ export declare function getAllHsProfiles(projectSourceDir: string): Promise<string[]>;
2
4
  export declare function loadHsMetaFiles(translationContext: TranslationContext): Promise<FileParseResult[]>;
package/src/lib/files.js CHANGED
@@ -3,20 +3,50 @@ 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.loadHsProfileFile = loadHsProfileFile;
7
+ exports.getAllHsProfiles = getAllHsProfiles;
6
8
  exports.loadHsMetaFiles = loadHsMetaFiles;
7
- const fs_1 = require("@hubspot/local-dev-lib/fs");
9
+ const fs_1 = __importDefault(require("fs"));
8
10
  const path_1 = __importDefault(require("path"));
11
+ const fs_2 = require("@hubspot/local-dev-lib/fs");
9
12
  const constants_1 = require("./constants");
10
- const fs_2 = __importDefault(require("fs"));
11
13
  const copy_1 = require("../lang/copy");
12
14
  const logger_1 = require("@hubspot/local-dev-lib/logger");
15
+ const profiles_1 = require("./profiles");
16
+ function loadHsProfileFile(projectSourceDir, profile) {
17
+ if (!profile) {
18
+ throw new Error(copy_1.errorMessages.profile.noProfileSpecified);
19
+ }
20
+ const profileFile = (0, profiles_1.getHsProfileFilename)(profile);
21
+ const profileFilepath = path_1.default.join(projectSourceDir, profileFile);
22
+ let hsProfile;
23
+ try {
24
+ hsProfile = JSON.parse(fs_1.default.readFileSync(profileFilepath, 'utf8'));
25
+ }
26
+ catch (_e) {
27
+ throw new Error(copy_1.errorMessages.profile.failedToLoadHsProfile(profileFile));
28
+ }
29
+ return hsProfile;
30
+ }
31
+ function getAllHsProfiles(projectSourceDir) {
32
+ return new Promise((resolve, _reject) => {
33
+ fs_1.default.readdir(projectSourceDir, { recursive: false, withFileTypes: true }, (err, files) => {
34
+ if (err) {
35
+ return resolve([]);
36
+ }
37
+ return resolve(files
38
+ .filter(file => file.isFile() && (0, profiles_1.getIsProfileFile)(file.name))
39
+ .map(file => (0, profiles_1.getHsProfileName)(file.name)));
40
+ });
41
+ });
42
+ }
13
43
  async function loadHsMetaFiles(translationContext) {
14
44
  const metaFiles = await locateHsMetaFiles(translationContext);
15
45
  return parseHsMetaFiles(metaFiles, translationContext);
16
46
  }
17
47
  async function locateHsMetaFiles(translationContext) {
18
48
  const { projectSourceDir } = translationContext;
19
- return (await (0, fs_1.walk)(projectSourceDir, ['node_modules'])).reduce((metaFiles, file) => {
49
+ return (await (0, fs_2.walk)(projectSourceDir, ['node_modules'])).reduce((metaFiles, file) => {
20
50
  if (!file.endsWith(constants_1.metafileExtension)) {
21
51
  return metaFiles;
22
52
  }
@@ -45,7 +75,7 @@ function loadFile(metaFileLocation, translationContext) {
45
75
  const { projectSourceDir } = translationContext;
46
76
  return new Promise(async (resolve) => {
47
77
  const { file, parentDirectory } = metaFileLocation;
48
- fs_2.default.readFile(file, 'utf-8', (err, content) => {
78
+ fs_1.default.readFile(file, 'utf-8', (err, content) => {
49
79
  if (err) {
50
80
  return resolve({
51
81
  file,
@@ -12,22 +12,21 @@ const constants_1 = require("./constants");
12
12
  const index_1 = require("../index");
13
13
  const IR_FILENAME = 'ir.json';
14
14
  const filesDirectory = 'files';
15
- const hsProjectJsonFilename = 'hsproject.json';
16
15
  const OUTPUT_IR_FILE = 'FULL_IR.json';
17
16
  async function migrate(inputDir, outputDir) {
18
17
  if (!fs_2.default.existsSync(inputDir)) {
19
18
  throw new Error(`Input directory ${inputDir} does not exist`);
20
19
  }
21
- const hsProjectJsonPath = path_1.default.join(inputDir, hsProjectJsonFilename);
20
+ const hsProjectJsonPath = path_1.default.join(inputDir, constants_1.hsProjectJsonFilename);
22
21
  if (!fs_2.default.existsSync(hsProjectJsonPath)) {
23
- throw new Error(`hsproject.json file does not exist in ${inputDir}`);
22
+ throw new Error(`${constants_1.hsProjectJsonFilename} file does not exist in ${inputDir}`);
24
23
  }
25
24
  let hsProjectJson;
26
25
  try {
27
26
  hsProjectJson = loadJsonFile(hsProjectJsonPath);
28
27
  }
29
28
  catch (e) {
30
- throw new Error(`Error parsing hsproject.json: ${e}`);
29
+ throw new Error(`Error parsing ${constants_1.hsProjectJsonFilename}: ${e}`);
31
30
  }
32
31
  const files = await (0, fs_1.walk)(inputDir);
33
32
  const sourceCodeOutputDir = path_1.default.join(outputDir, 'src');
@@ -0,0 +1,5 @@
1
+ import { FileParseResult, HsProfileFile } from './types';
2
+ export declare function getIsProfileFile(filename: string): boolean;
3
+ export declare function getHsProfileFilename(profileName: string): string;
4
+ export declare function getHsProfileName(profileFilename: string): string;
5
+ export declare function applyHsProfileVariables(fileParseResults: FileParseResult[], hsProfileContents: HsProfileFile): FileParseResult[];
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getIsProfileFile = getIsProfileFile;
4
+ exports.getHsProfileFilename = getHsProfileFilename;
5
+ exports.getHsProfileName = getHsProfileName;
6
+ exports.applyHsProfileVariables = applyHsProfileVariables;
7
+ const constants_1 = require("./constants");
8
+ const copy_1 = require("../lang/copy");
9
+ const profileFilenameRegex = new RegExp(`^${constants_1.profileFilePrefix}\\.([^.]+)\\.json$`);
10
+ const profileInsertRegex = /\${(.*?)}/g;
11
+ function getIsProfileFile(filename) {
12
+ return profileFilenameRegex.test(filename);
13
+ }
14
+ function getHsProfileFilename(profileName) {
15
+ return `${constants_1.profileFilePrefix}.${profileName}.json`;
16
+ }
17
+ function getHsProfileName(profileFilename) {
18
+ const match = profileFilename.match(profileFilenameRegex);
19
+ return match ? match[1] : '';
20
+ }
21
+ function interpolate(file, template, profileVariables) {
22
+ return template.replace(profileInsertRegex, (__match, key) => {
23
+ const profileVariableType = typeof profileVariables[key];
24
+ if (profileVariableType === 'undefined') {
25
+ throw new Error(copy_1.errorMessages.profile.missingValue(key, file));
26
+ }
27
+ if (!['string', 'number', 'boolean'].includes(profileVariableType)) {
28
+ throw new Error(copy_1.errorMessages.profile.invalidValue(key));
29
+ }
30
+ return String(profileVariables[key]);
31
+ });
32
+ }
33
+ function applyHsProfileVariables(fileParseResults, hsProfileContents) {
34
+ const profileVariables = hsProfileContents?.variables &&
35
+ typeof hsProfileContents.variables === 'object' &&
36
+ !Array.isArray(hsProfileContents.variables)
37
+ ? hsProfileContents.variables
38
+ : {};
39
+ return fileParseResults.map(fileParseResult => {
40
+ const { content, file } = fileParseResult;
41
+ if (content && content.config) {
42
+ let interpolatedConfig = content.config;
43
+ interpolatedConfig = JSON.parse(interpolate(file, JSON.stringify(content.config), profileVariables));
44
+ if (interpolatedConfig) {
45
+ return {
46
+ ...fileParseResult,
47
+ content: {
48
+ ...content,
49
+ config: interpolatedConfig,
50
+ },
51
+ };
52
+ }
53
+ }
54
+ return fileParseResult;
55
+ });
56
+ }
@@ -1,8 +1,8 @@
1
- import { Dependencies, FileParseResult, IntermediateRepresentation, Transformation, TranslationContext } from './types';
1
+ import { Dependencies, FileParseResult, HsProfileFile, IntermediateRepresentation, Transformation, TranslationContext } from './types';
2
2
  export declare function mapToInternalType(type: string): string;
3
3
  export declare function mapToUserFacingType(type: string): string;
4
4
  export declare function mapToUserFriendlyName(internalType: string): string;
5
- export declare function transform(fileParseResults: FileParseResult[], translationContext: TranslationContext): Transformation[];
5
+ export declare function transform(fileParseResults: FileParseResult[], translationContext: TranslationContext, hsProfileContents?: HsProfileFile): Transformation[];
6
6
  export declare function getIntermediateRepresentation(transformations: Transformation[], skipValidation: boolean | undefined): IntermediateRepresentation;
7
7
  export declare function generateServerlessPackageComponent(appFunctionsDirectory: string, translationContext: TranslationContext, componentDeps: Dependencies): {
8
8
  uid: string;
@@ -9,6 +9,7 @@ exports.mapToUserFriendlyName = mapToUserFriendlyName;
9
9
  exports.transform = transform;
10
10
  exports.getIntermediateRepresentation = getIntermediateRepresentation;
11
11
  exports.generateServerlessPackageComponent = generateServerlessPackageComponent;
12
+ const profiles_1 = require("./profiles");
12
13
  const constants_1 = require("./constants");
13
14
  const copy_1 = require("../lang/copy");
14
15
  const path_1 = __importDefault(require("path"));
@@ -47,12 +48,16 @@ function mapToUserFacingType(type) {
47
48
  function mapToUserFriendlyName(internalType) {
48
49
  return constants_1.Components[mapToUserFacingType(internalType)]?.userFriendlyName || '';
49
50
  }
50
- function transform(fileParseResults, translationContext) {
51
+ function transform(fileParseResults, translationContext, hsProfileContents) {
51
52
  const parentTypes = Object.keys(constants_1.ProjectStructure);
52
53
  const parentComponents = {};
53
54
  const allAppObjects = [];
54
55
  let appUid = '';
55
56
  let appFunctionsDirectory;
57
+ // Apply the profile variable overrides to the config
58
+ if (hsProfileContents) {
59
+ fileParseResults = (0, profiles_1.applyHsProfileVariables)(fileParseResults, hsProfileContents);
60
+ }
56
61
  // Compute the parent components, so we can add them as dependencies to the child components
57
62
  fileParseResults.forEach(file => {
58
63
  if (file.content?.type && parentTypes.includes(file.content.type)) {
@@ -56,4 +56,11 @@ export interface TranslationContext {
56
56
  }
57
57
  export interface TranslationOptions {
58
58
  skipValidation?: boolean;
59
+ profile?: string;
60
+ }
61
+ export interface HsProfileFile {
62
+ accountId: number;
63
+ variables?: {
64
+ [key: string]: string | number | boolean;
65
+ };
59
66
  }
@@ -1,5 +1,5 @@
1
1
  import { CompiledError, IntermediateRepresentation, Transformation, TranslationContext } from './types';
2
- import { ValidateFunction } from 'ajv/dist/2020';
2
+ import Ajv, { ValidateFunction } from 'ajv/dist/2020';
3
3
  export type ValidResult = {
4
4
  valid: true;
5
5
  errors?: null;
@@ -10,4 +10,5 @@ export type ValidationResults = {
10
10
  errors?: CompiledError;
11
11
  schemaValidationErrors?: ValidateFunction['errors'];
12
12
  } | ValidResult;
13
+ export declare function createAjvInstance(): Ajv;
13
14
  export declare function validateIntermediateRepresentation(intermediateRepresentation: IntermediateRepresentation, transformation: Transformation[], translationContext: TranslationContext): Promise<ValidResult>;
@@ -3,6 +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.createAjvInstance = createAjvInstance;
6
7
  exports.validateIntermediateRepresentation = validateIntermediateRepresentation;
7
8
  const schemas_1 = require("./schemas");
8
9
  const _2020_1 = __importDefault(require("ajv/dist/2020"));
@@ -13,6 +14,11 @@ const path_1 = __importDefault(require("path"));
13
14
  const transform_1 = require("./transform");
14
15
  const ajv_formats_1 = __importDefault(require("ajv-formats"));
15
16
  const uid_1 = require("./uid");
17
+ function createAjvInstance() {
18
+ const ajv = new _2020_1.default({ allErrors: true });
19
+ (0, ajv_formats_1.default)(ajv);
20
+ return ajv;
21
+ }
16
22
  function validateIntermediateRepresentationNode(schema, transformation, irNode, index, translationContext) {
17
23
  if (constants_1.AutoGeneratedComponentTypes.includes((0, transform_1.mapToUserFacingType)(irNode.componentType))) {
18
24
  // Skip validation for auto-generated components
@@ -26,8 +32,7 @@ function validateIntermediateRepresentationNode(schema, transformation, irNode,
26
32
  errors: (0, errors_1.compileError)(transformation[index]),
27
33
  };
28
34
  }
29
- const ajv = new _2020_1.default({ allErrors: true });
30
- (0, ajv_formats_1.default)(ajv);
35
+ const ajv = createAjvInstance();
31
36
  let shouldSkipValidation = false;
32
37
  if (!irNode.uid) {
33
38
  transformation[index].fileParseResult.errors.push(copy_1.errorMessages.validation.missingUid);