@hubspot/project-parsing-lib 0.2.2-experimental.0 → 0.2.2-experimental.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 +3 -3
- package/src/exports/projects.d.ts +1 -1
- package/src/exports/projects.js +1 -1
- package/src/exports/translate.d.ts +1 -1
- package/src/lang/copy.d.ts +4 -0
- package/src/lang/copy.js +4 -0
- package/src/lib/constants.d.ts +1 -0
- package/src/lib/constants.js +11 -0
- package/src/lib/platformVersion.d.ts +1 -0
- package/src/lib/platformVersion.js +14 -0
- package/src/lib/transform.js +9 -6
- package/src/lib/types.d.ts +7 -0
- package/src/lib/validation.js +5 -0
- package/src/lib/workspaces.js +4 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/project-parsing-lib",
|
|
3
|
-
"version": "0.2.2-experimental.
|
|
3
|
+
"version": "0.2.2-experimental.1",
|
|
4
4
|
"description": "Parsing library for converting projects directory structures to their intermediate representation",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"@inquirer/prompts": "^7.1.0",
|
|
112
112
|
"@types/node": "^24.9.0",
|
|
113
113
|
"@types/npm-packlist": "7.0.3",
|
|
114
|
-
"@types/npmcli__map-workspaces": "
|
|
114
|
+
"@types/npmcli__map-workspaces": "3.0.4",
|
|
115
115
|
"@types/semver": "^7.5.8",
|
|
116
116
|
"@typescript-eslint/eslint-plugin": "8.54.0",
|
|
117
117
|
"@typescript-eslint/parser": "8.54.0",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
},
|
|
128
128
|
"dependencies": {
|
|
129
129
|
"@hubspot/local-dev-lib": "4.0.4",
|
|
130
|
-
"@npmcli/map-workspaces": "
|
|
130
|
+
"@npmcli/map-workspaces": "4.0.2",
|
|
131
131
|
"ajv": "8.18.0",
|
|
132
132
|
"ajv-formats": "3.0.1",
|
|
133
133
|
"glob": "13.0.0",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { getProjectMetadata } from '../lib/project.js';
|
|
2
2
|
export { projectContainsHsMetaFiles } from '../lib/files.js';
|
|
3
3
|
export type { ProjectMetadata } from '../lib/project.js';
|
|
4
|
-
export { LATEST_SUPPORTED_PLATFORM_VERSION, isSupportedPlatformVersion, isLegacyProject, } from '../lib/platformVersion.js';
|
|
4
|
+
export { LATEST_SUPPORTED_PLATFORM_VERSION, isSupportedPlatformVersion, isLegacyProject, supportsComponentPermissions, } from '../lib/platformVersion.js';
|
package/src/exports/projects.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { getProjectMetadata } from '../lib/project.js';
|
|
2
2
|
export { projectContainsHsMetaFiles } from '../lib/files.js';
|
|
3
|
-
export { LATEST_SUPPORTED_PLATFORM_VERSION, isSupportedPlatformVersion, isLegacyProject, } from '../lib/platformVersion.js';
|
|
3
|
+
export { LATEST_SUPPORTED_PLATFORM_VERSION, isSupportedPlatformVersion, isLegacyProject, supportsComponentPermissions, } from '../lib/platformVersion.js';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { translate, translateForLocalDev } from '../lib/translate.js';
|
|
2
2
|
export { isTranslationError, type TranslationError } from '../lib/errors.js';
|
|
3
|
-
export type { IntermediateRepresentation, IntermediateRepresentationLocalDev, IntermediateRepresentationNodeLocalDev, IntermediateRepresentationNode, TranslationContext, TranslationOptions, TranslationOptionsLocalDev, ComponentMeta, } from '../lib/types.js';
|
|
3
|
+
export type { IntermediateRepresentation, IntermediateRepresentationLocalDev, IntermediateRepresentationNodeLocalDev, IntermediateRepresentationNode, TranslationContext, TranslationOptions, TranslationOptionsLocalDev, ComponentMeta, ComponentPermissions, } from '../lib/types.js';
|
package/src/lang/copy.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare const errorMessages: {
|
|
|
33
33
|
unsupportedType: (type: string) => string;
|
|
34
34
|
errorWithField: (field: string, error: string | undefined) => string;
|
|
35
35
|
invalidJson: string;
|
|
36
|
+
permissionsNotSupported: (platformVersion: string) => string;
|
|
36
37
|
unexpectedToplevelFields: (unexpectedFields: string) => string;
|
|
37
38
|
wrongDirectoryForComponent: (directory: string, componentType: string, componentMetadata: ComponentMetadata, correctDir: string) => string;
|
|
38
39
|
};
|
|
@@ -51,4 +52,7 @@ export declare const logMessages: {
|
|
|
51
52
|
files: {
|
|
52
53
|
skippingPath: (path: string) => string;
|
|
53
54
|
};
|
|
55
|
+
workspaces: {
|
|
56
|
+
cannotAccessDirectory: (dir: string, e: unknown) => string;
|
|
57
|
+
};
|
|
54
58
|
};
|
package/src/lang/copy.js
CHANGED
|
@@ -34,6 +34,7 @@ export const errorMessages = {
|
|
|
34
34
|
unsupportedType: (type) => `Unsupported type: ${mapToUserFacingType(type)}`,
|
|
35
35
|
errorWithField: (field, error) => `${field}: ${error || 'Unknown error'}`,
|
|
36
36
|
invalidJson: 'Invalid JSON',
|
|
37
|
+
permissionsNotSupported: (platformVersion) => `The "permissions" field is not supported on platform version "${platformVersion}". Upgrade to "2026.09" or later to use component-level permissions.`,
|
|
37
38
|
unexpectedToplevelFields: (unexpectedFields) => `Unexpected top-level properties found: ${unexpectedFields}`,
|
|
38
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`,
|
|
39
40
|
},
|
|
@@ -66,4 +67,7 @@ export const logMessages = {
|
|
|
66
67
|
files: {
|
|
67
68
|
skippingPath: (path) => `Skipping ${path} as it is not in a valid directory`,
|
|
68
69
|
},
|
|
70
|
+
workspaces: {
|
|
71
|
+
cannotAccessDirectory: (dir, e) => `Cannot access directory ${dir}: ${e}`,
|
|
72
|
+
},
|
|
69
73
|
};
|
package/src/lib/constants.d.ts
CHANGED
|
@@ -30,6 +30,7 @@ export declare const WEBHOOKS_KEY = "webhooks";
|
|
|
30
30
|
export declare const WEBHOOKS_JOURNAL_KEY = "webhooks-journal";
|
|
31
31
|
export declare const WORKFLOW_ACTIONS_KEY = "workflow-action";
|
|
32
32
|
export declare const ACTIONS_KEY = "action";
|
|
33
|
+
export declare const BREEZE_TOOL_KEY = "breeze-tool";
|
|
33
34
|
export declare const APP_FUNCTIONS_PACKAGE_KEY = "serverless-package";
|
|
34
35
|
export declare const AUTO_GENERATED_COMPONENT_TYPES: string[];
|
|
35
36
|
export interface ComponentMetadata {
|
package/src/lib/constants.js
CHANGED
|
@@ -34,6 +34,7 @@ export const WEBHOOKS_KEY = 'webhooks';
|
|
|
34
34
|
export const WEBHOOKS_JOURNAL_KEY = 'webhooks-journal';
|
|
35
35
|
export const WORKFLOW_ACTIONS_KEY = 'workflow-action';
|
|
36
36
|
export const ACTIONS_KEY = 'action';
|
|
37
|
+
export const BREEZE_TOOL_KEY = 'breeze-tool';
|
|
37
38
|
// Auto-generated component types
|
|
38
39
|
export const APP_FUNCTIONS_PACKAGE_KEY = 'serverless-package';
|
|
39
40
|
export const AUTO_GENERATED_COMPONENT_TYPES = [APP_FUNCTIONS_PACKAGE_KEY];
|
|
@@ -54,6 +55,9 @@ const PAGE_COMPONENT = {
|
|
|
54
55
|
userFriendlyName: 'Page',
|
|
55
56
|
singularComponent: true,
|
|
56
57
|
};
|
|
58
|
+
// Breeze components share a `breeze/` group directory so future breeze features
|
|
59
|
+
// (e.g. breeze/skills, breeze/subagents) can sit alongside breeze/tools.
|
|
60
|
+
const BREEZE_COMPONENT_DIR = 'breeze';
|
|
57
61
|
export const Components = {
|
|
58
62
|
[APP_KEY]: {
|
|
59
63
|
dir: APP_KEY,
|
|
@@ -182,6 +186,12 @@ export const Components = {
|
|
|
182
186
|
singularComponent: true,
|
|
183
187
|
...SUB_COMPONENT_FIELDS,
|
|
184
188
|
},
|
|
189
|
+
[BREEZE_TOOL_KEY]: {
|
|
190
|
+
dir: `${BREEZE_COMPONENT_DIR}/tools`,
|
|
191
|
+
parentComponent: APP_KEY,
|
|
192
|
+
userFriendlyName: 'Breeze Tool',
|
|
193
|
+
...SUB_COMPONENT_FIELDS,
|
|
194
|
+
},
|
|
185
195
|
};
|
|
186
196
|
export const USER_FACING_TO_INTERNAL_TYPE = {
|
|
187
197
|
[APP_KEY]: 'APPLICATION',
|
|
@@ -231,4 +241,5 @@ export const ALLOWED_TOP_LEVEL_FIELDS = new Set([
|
|
|
231
241
|
'type',
|
|
232
242
|
'config',
|
|
233
243
|
'dependencies',
|
|
244
|
+
'permissions',
|
|
234
245
|
]);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare const LATEST_SUPPORTED_PLATFORM_VERSION: string;
|
|
2
2
|
export declare function isSupportedPlatformVersion(platformVersion?: string | null): boolean;
|
|
3
3
|
export declare function isLegacyProject(platformVersion?: string | null): boolean;
|
|
4
|
+
export declare function supportsComponentPermissions(platformVersion: string): boolean;
|
|
@@ -6,11 +6,25 @@ export function isSupportedPlatformVersion(platformVersion) {
|
|
|
6
6
|
if (!platformVersion || typeof platformVersion !== 'string') {
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
|
+
if (process.env.HUBSPOT_PROJECT_INTERNAL_TEST === 'true')
|
|
10
|
+
return true;
|
|
9
11
|
const supportedPlatformVersions = Object.values(PLATFORM_VERSIONS);
|
|
10
12
|
return supportedPlatformVersions.includes(platformVersion);
|
|
11
13
|
}
|
|
12
14
|
export function isLegacyProject(platformVersion) {
|
|
13
15
|
if (!platformVersion)
|
|
14
16
|
return false;
|
|
17
|
+
if (process.env.HUBSPOT_PROJECT_INTERNAL_TEST === 'true')
|
|
18
|
+
return false;
|
|
15
19
|
return [PLATFORM_VERSIONS.v2023_2, PLATFORM_VERSIONS.v2025_1].includes(platformVersion);
|
|
16
20
|
}
|
|
21
|
+
const PRE_PERMISSIONS_VERSIONS = new Set([
|
|
22
|
+
PLATFORM_VERSIONS.v2023_2,
|
|
23
|
+
PLATFORM_VERSIONS.v2025_1,
|
|
24
|
+
PLATFORM_VERSIONS.v2025_2,
|
|
25
|
+
PLATFORM_VERSIONS.v2026_03_BETA,
|
|
26
|
+
PLATFORM_VERSIONS.v2026_03,
|
|
27
|
+
]);
|
|
28
|
+
export function supportsComponentPermissions(platformVersion) {
|
|
29
|
+
return !PRE_PERMISSIONS_VERSIONS.has(platformVersion);
|
|
30
|
+
}
|
package/src/lib/transform.js
CHANGED
|
@@ -7,11 +7,13 @@ import { errorMessages } from '../lang/copy.js';
|
|
|
7
7
|
import { getJavaNumberType } from './utils.js';
|
|
8
8
|
import { convertPathToPosixPath } from './files.js';
|
|
9
9
|
function calculateComponentDeps(fileValidationResult, parentComponents, appObjects, appFunctionsPackageUid) {
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
// Pass through any developer-authored dependencies declared in the hsmeta
|
|
11
|
+
// file. Framework-injected structural dependencies (app, allAppObjects,
|
|
12
|
+
// serverlessPackage) are layered on top below and take precedence over any
|
|
13
|
+
// authored value for those reserved keys.
|
|
14
|
+
const dependencies = {
|
|
15
|
+
...fileValidationResult.content?.dependencies,
|
|
16
|
+
};
|
|
15
17
|
const { type } = fileValidationResult.content;
|
|
16
18
|
// If the component is a child of the App component, add the app and appObjects as dependencies
|
|
17
19
|
if (Components[type]?.parentComponent === APP_KEY) {
|
|
@@ -95,7 +97,7 @@ export function transform(fileParseResults, translationContext, hsProfileContent
|
|
|
95
97
|
fileParseResult: currentFile,
|
|
96
98
|
};
|
|
97
99
|
}
|
|
98
|
-
const { config, uid, type } = currentFile.content;
|
|
100
|
+
const { config, uid, type, permissions } = currentFile.content;
|
|
99
101
|
const { dependencies, errors } = calculateComponentDeps(currentFile, parentComponents, allAppObjects, serverlessPackageUid);
|
|
100
102
|
if (errors) {
|
|
101
103
|
currentFile.errors?.push(...errors);
|
|
@@ -108,6 +110,7 @@ export function transform(fileParseResults, translationContext, hsProfileContent
|
|
|
108
110
|
componentDeps: dependencies,
|
|
109
111
|
metaFilePath: convertPathToPosixPath(currentFile.file),
|
|
110
112
|
files: {},
|
|
113
|
+
...(permissions ? { permissions } : {}),
|
|
111
114
|
},
|
|
112
115
|
fileParseResult: currentFile,
|
|
113
116
|
};
|
package/src/lib/types.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ErrorObject } from 'ajv';
|
|
2
2
|
export type Dependencies = Record<string, string | string[]>;
|
|
3
|
+
export interface ComponentPermissions {
|
|
4
|
+
requiredScopes?: string[];
|
|
5
|
+
optionalScopes?: string[];
|
|
6
|
+
conditionallyRequiredScopes?: string[];
|
|
7
|
+
}
|
|
3
8
|
export interface ComponentMeta {
|
|
4
9
|
uid: string;
|
|
5
10
|
type: string;
|
|
6
11
|
config: unknown;
|
|
7
12
|
dependencies?: Dependencies;
|
|
13
|
+
permissions?: ComponentPermissions;
|
|
8
14
|
}
|
|
9
15
|
export interface FileActionResult {
|
|
10
16
|
file: string;
|
|
@@ -24,6 +30,7 @@ export interface IntermediateRepresentationNode {
|
|
|
24
30
|
uid: string;
|
|
25
31
|
config: unknown;
|
|
26
32
|
files: unknown;
|
|
33
|
+
permissions?: ComponentPermissions;
|
|
27
34
|
}
|
|
28
35
|
export type BEProfileVariableType = 'PROFILE_INT' | 'PROFILE_LONG' | 'PROFILE_STRING' | 'PROFILE_BOOLEAN';
|
|
29
36
|
export interface BEProfileVariables {
|
package/src/lib/validation.js
CHANGED
|
@@ -5,6 +5,7 @@ import { errorMessages } from '../lang/copy.js';
|
|
|
5
5
|
import { AUTO_GENERATED_COMPONENT_TYPES, Components } from './constants.js';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { findTransformationByUid, mapToUserFacingType } from './transform.js';
|
|
8
|
+
import { supportsComponentPermissions } from './platformVersion.js';
|
|
8
9
|
import { validateUid } from './uid.js';
|
|
9
10
|
// ajv-formats does not play nicely with ESM and TS
|
|
10
11
|
import addFormatsModule from 'ajv-formats';
|
|
@@ -47,6 +48,10 @@ function validateIntermediateRepresentationNode(schema, transformation, irNode,
|
|
|
47
48
|
// If there is no config block, there is nothing to validation
|
|
48
49
|
shouldSkipValidation = true;
|
|
49
50
|
}
|
|
51
|
+
if (irNode.permissions &&
|
|
52
|
+
!supportsComponentPermissions(translationContext.platformVersion)) {
|
|
53
|
+
transformation.fileParseResult.errors.push(errorMessages.validation.permissionsNotSupported(translationContext.platformVersion));
|
|
54
|
+
}
|
|
50
55
|
if (!schema[irNode.componentType]) {
|
|
51
56
|
if (!irNode.componentType) {
|
|
52
57
|
transformation.fileParseResult.errors.push(errorMessages.validation.missingType);
|
package/src/lib/workspaces.js
CHANGED
|
@@ -8,6 +8,7 @@ import packlist from 'npm-packlist';
|
|
|
8
8
|
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
9
9
|
import { walk } from '@hubspot/local-dev-lib/fs';
|
|
10
10
|
import { createMinimalTree } from './minimalArboristTree.js';
|
|
11
|
+
import { logMessages } from '../lang/copy.js';
|
|
11
12
|
/**
|
|
12
13
|
* Error thrown when a workspace directory cannot be resolved
|
|
13
14
|
*/
|
|
@@ -60,10 +61,9 @@ export class OrphanWorkspaceProtocolError extends Error {
|
|
|
60
61
|
this.name = 'OrphanWorkspaceProtocolError';
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
|
-
const TARBALL_EXTENSIONS = ['.tgz', '.tar.gz', '.tar'];
|
|
64
64
|
function hasTarballExtension(p) {
|
|
65
|
-
const
|
|
66
|
-
return
|
|
65
|
+
const { ext, name } = path.parse(p.toLowerCase());
|
|
66
|
+
return (ext === '.tgz' || ext === '.tar' || (ext === '.gz' && name.endsWith('.tar')));
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Expands tilde (~) in paths to the user's home directory
|
|
@@ -181,7 +181,7 @@ export async function resolveWorkspaceDirectories(baseDir, workspaceGlobs) {
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
catch (e) {
|
|
184
|
-
logger.warn(
|
|
184
|
+
logger.warn(logMessages.workspaces.cannotAccessDirectory(dir, e));
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
return Array.from(resolved);
|