@hubspot/project-parsing-lib 0.21.0 → 0.22.0

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.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Parsing library for converting projects directory structures to their intermediate representation",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -107,7 +107,7 @@
107
107
  }
108
108
  },
109
109
  "devDependencies": {
110
- "@hubspot/npm-scripts": "0.3.1",
110
+ "@hubspot/npm-scripts": "^0.3.3",
111
111
  "@inquirer/prompts": "^7.1.0",
112
112
  "@types/node": "^24.9.0",
113
113
  "@types/npm-packlist": "7.0.3",
@@ -115,6 +115,7 @@
115
115
  "@types/semver": "^7.5.8",
116
116
  "@typescript-eslint/eslint-plugin": "8.54.0",
117
117
  "@typescript-eslint/parser": "8.54.0",
118
+ "@vitest/coverage-v8": "^3.2.7",
118
119
  "eslint": "^9.38.0",
119
120
  "eslint-plugin-import": "^2.31.0",
120
121
  "husky": "^9.1.7",
@@ -150,7 +151,7 @@
150
151
  "local-dev": "yarn build && cd dist && yarn link && cd .. && tsc --watch --rootDir . --outdir dist",
151
152
  "local-link": "hubspot-linking",
152
153
  "prettier:write": "prettier ./src/** --write",
153
- "test": "vitest run",
154
+ "test": "vitest run --coverage",
154
155
  "release": "tsx ./scripts/release.ts release",
155
156
  "acceptance-test": "yarn --cwd=./acceptance-tests test"
156
157
  },
@@ -1,4 +1,5 @@
1
- export { getProjectMetadata } from '../lib/project.js';
2
- export { projectContainsHsMetaFiles } from '../lib/files.js';
1
+ export { getProjectMetadata, parseProjectConfig, validateProjectConfig, ProjectConfigValidationError, } from '../lib/project.js';
3
2
  export type { ProjectMetadata } from '../lib/project.js';
3
+ export { projectContainsHsMetaFiles } from '../lib/files.js';
4
+ export type { ProjectConfig } from '../lib/types.js';
4
5
  export { LATEST_SUPPORTED_PLATFORM_VERSION, isKnownPlatformVersion, isLegacyProject, meetsMinimumPlatformVersion, } from '../lib/platformVersion.js';
@@ -1,3 +1,3 @@
1
- export { getProjectMetadata } from '../lib/project.js';
1
+ export { getProjectMetadata, parseProjectConfig, validateProjectConfig, ProjectConfigValidationError, } from '../lib/project.js';
2
2
  export { projectContainsHsMetaFiles } from '../lib/files.js';
3
3
  export { LATEST_SUPPORTED_PLATFORM_VERSION, isKnownPlatformVersion, isLegacyProject, meetsMinimumPlatformVersion, } from '../lib/platformVersion.js';
@@ -37,6 +37,14 @@ export declare const errorMessages: {
37
37
  unexpectedToplevelFields: (unexpectedFields: string) => string;
38
38
  wrongDirectoryForComponent: (directory: string, componentType: string, componentMetadata: ComponentMetadata, correctDir: string) => string;
39
39
  };
40
+ projectConfig: {
41
+ couldNotRead: (projectDir: string) => string;
42
+ invalidJson: string;
43
+ mustBeJsonObject: string;
44
+ missingRequiredFields: (fields: string[]) => string;
45
+ srcDirOutsideProject: string;
46
+ srcDirNotFound: (srcDir: string) => string;
47
+ };
40
48
  migrateThemes: {
41
49
  rootReactThemeNotSupported: string;
42
50
  };
package/src/lang/copy.js CHANGED
@@ -1,4 +1,4 @@
1
- import { APP_FUNCTIONS_KEY, APP_KEY, Components, PACKAGE_JSON, } from '../lib/constants.js';
1
+ import { APP_FUNCTIONS_KEY, APP_KEY, Components, HS_PROJECT_JSON_FILENAME, PACKAGE_JSON, } from '../lib/constants.js';
2
2
  import { mapToUserFacingType } from '../lib/transform.js';
3
3
  export const errorMessages = {
4
4
  api: {
@@ -38,6 +38,14 @@ export const errorMessages = {
38
38
  unexpectedToplevelFields: (unexpectedFields) => `Unexpected top-level properties found: ${unexpectedFields}`,
39
39
  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`,
40
40
  },
41
+ projectConfig: {
42
+ couldNotRead: (projectDir) => `Could not read ${HS_PROJECT_JSON_FILENAME} in ${projectDir}`,
43
+ invalidJson: `Failed to parse ${HS_PROJECT_JSON_FILENAME}: invalid JSON`,
44
+ mustBeJsonObject: `${HS_PROJECT_JSON_FILENAME} must be a JSON object`,
45
+ missingRequiredFields: (fields) => `${HS_PROJECT_JSON_FILENAME} is missing required field(s): ${fields.join(', ')}`,
46
+ srcDirOutsideProject: `"srcDir" in ${HS_PROJECT_JSON_FILENAME} must be within the project directory`,
47
+ srcDirNotFound: (srcDir) => `The "srcDir" specified in ${HS_PROJECT_JSON_FILENAME} does not exist: ${srcDir}`,
48
+ },
41
49
  migrateThemes: {
42
50
  rootReactThemeNotSupported: 'Migrating themes that live at the root of the project src directory is not supported. Please move the theme to a subdirectory.',
43
51
  },
@@ -1,3 +1,9 @@
1
+ import { ProjectConfig } from './types.js';
2
+ export declare class ProjectConfigValidationError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare function parseProjectConfig(projectDir: string): ProjectConfig;
6
+ export declare function validateProjectConfig(config: unknown, projectDir: string): asserts config is ProjectConfig;
1
7
  export interface ComponentMetadata {
2
8
  count: number;
3
9
  maxCount: number;
@@ -1,7 +1,58 @@
1
- import { Components } from './constants.js';
1
+ import { Components, HS_PROJECT_JSON_FILENAME } from './constants.js';
2
2
  import { locateHsMetaFiles } from './files.js';
3
+ import { errorMessages } from '../lang/copy.js';
3
4
  import path from 'path';
4
5
  import fs from 'fs';
6
+ export class ProjectConfigValidationError extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = 'ProjectConfigValidationError';
10
+ }
11
+ }
12
+ export function parseProjectConfig(projectDir) {
13
+ const configPath = path.join(projectDir, HS_PROJECT_JSON_FILENAME);
14
+ let rawConfig;
15
+ try {
16
+ rawConfig = fs.readFileSync(configPath, 'utf-8');
17
+ }
18
+ catch {
19
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.couldNotRead(projectDir));
20
+ }
21
+ let config;
22
+ try {
23
+ config = JSON.parse(rawConfig);
24
+ }
25
+ catch {
26
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.invalidJson);
27
+ }
28
+ validateProjectConfig(config, projectDir);
29
+ return config;
30
+ }
31
+ export function validateProjectConfig(config, projectDir) {
32
+ if (!config || typeof config !== 'object') {
33
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.mustBeJsonObject);
34
+ }
35
+ const c = config;
36
+ const missingFields = [];
37
+ if (!c['name'])
38
+ missingFields.push('name');
39
+ if (!c['srcDir'])
40
+ missingFields.push('srcDir');
41
+ if (!c['platformVersion'])
42
+ missingFields.push('platformVersion');
43
+ if (missingFields.length > 0) {
44
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.missingRequiredFields(missingFields));
45
+ }
46
+ const srcDirResolved = path.resolve(projectDir, c['srcDir']);
47
+ const projectDirNormalized = path.resolve(projectDir);
48
+ if (srcDirResolved !== projectDirNormalized &&
49
+ !srcDirResolved.startsWith(projectDirNormalized + path.sep)) {
50
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.srcDirOutsideProject);
51
+ }
52
+ if (!fs.existsSync(srcDirResolved)) {
53
+ throw new ProjectConfigValidationError(errorMessages.projectConfig.srcDirNotFound(c['srcDir']));
54
+ }
55
+ }
5
56
  export async function getProjectMetadata(projectSrcDir) {
6
57
  const hsMetaFiles = [];
7
58
  const components = {};
@@ -72,6 +72,12 @@ export type Transformation = {
72
72
  export type CompiledError = {
73
73
  errors: string[];
74
74
  };
75
+ export interface ProjectConfig {
76
+ name: string;
77
+ srcDir: string;
78
+ platformVersion: string;
79
+ [key: string]: unknown;
80
+ }
75
81
  export interface TranslationContext {
76
82
  projectSourceDir: string;
77
83
  platformVersion: string;