@forge/lint 6.0.3-next.8 → 6.1.0-next.21

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/CHANGELOG.md CHANGED
@@ -1,5 +1,104 @@
1
1
  # @forge/lint
2
2
 
3
+ ## 6.1.0-next.21
4
+
5
+ ### Minor Changes
6
+
7
+ - 342098d: Implement server-side linter logic to prevent accidental major app version deployments
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [342098d]
12
+ - @forge/cli-shared@9.3.0-next.19
13
+
14
+ ## 6.0.3-next.20
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies [87d2d74]
19
+ - @forge/csp@6.3.0-next.0
20
+
21
+ ## 6.0.3-next.19
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [4404f62]
26
+ - @forge/manifest@13.3.0-next.10
27
+ - @forge/cli-shared@9.3.0-next.18
28
+
29
+ ## 6.0.3-next.18
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies [8d20095]
34
+ - @forge/cli-shared@9.3.0-next.17
35
+
36
+ ## 6.0.3-next.17
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [905d8c5]
41
+ - @forge/cli-shared@9.3.0-next.16
42
+
43
+ ## 6.0.3-next.16
44
+
45
+ ### Patch Changes
46
+
47
+ - Updated dependencies [52e074e]
48
+ - @forge/cli-shared@9.3.0-next.15
49
+
50
+ ## 6.0.3-next.15
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies [c8105d8]
55
+ - Updated dependencies [3e8de63]
56
+ - @forge/cli-shared@9.3.0-next.14
57
+ - @forge/manifest@13.3.0-next.9
58
+
59
+ ## 6.0.3-next.14
60
+
61
+ ### Patch Changes
62
+
63
+ - Updated dependencies [8a9e608]
64
+ - @forge/cli-shared@9.3.0-next.13
65
+
66
+ ## 6.0.3-next.13
67
+
68
+ ### Patch Changes
69
+
70
+ - 4b90a07: Lint target directory when using the manual packaging
71
+ - Updated dependencies [4b90a07]
72
+ - @forge/manifest@13.3.0-next.8
73
+ - @forge/cli-shared@9.3.0-next.12
74
+
75
+ ## 6.0.3-next.12
76
+
77
+ ### Patch Changes
78
+
79
+ - Updated dependencies [18b920d]
80
+ - @forge/cli-shared@9.3.0-next.11
81
+
82
+ ## 6.0.3-next.11
83
+
84
+ ### Patch Changes
85
+
86
+ - 0f6f64f: Fix linter setup to support multi-entry resource bundling for Frame component
87
+
88
+ ## 6.0.3-next.10
89
+
90
+ ### Patch Changes
91
+
92
+ - Updated dependencies [bc2d278]
93
+ - @forge/cli-shared@9.3.0-next.10
94
+
95
+ ## 6.0.3-next.9
96
+
97
+ ### Patch Changes
98
+
99
+ - Updated dependencies [a36d70b]
100
+ - @forge/cli-shared@9.3.0-next.9
101
+
3
102
  ## 6.0.3-next.8
4
103
 
5
104
  ### Patch Changes
@@ -1,15 +1,45 @@
1
- import { StatsigService } from '@forge/cli-shared';
1
+ import { StatsigService, GraphQLClient } from '@forge/cli-shared';
2
2
  import { ManifestSchema as Manifest } from '@forge/manifest';
3
3
  import fs from 'fs';
4
4
  import { tsParser } from '../parse';
5
5
  import { LinterInterface, LintInput, LintLogger, LintResult } from './linter-interface';
6
+ import { HandlerLinter } from './linters/handler-linter/handler-linter';
7
+ import { FullManifestLinter } from './linters/manifest-linter/full-manifest-linter';
8
+ import { AgentProductContextPermissionsManifestLinter } from './linters/manifest-linter/agent-product-context-permissions-manifest-linter';
9
+ import { PermissionsManifestLinter } from './linters/manifest-linter/permissions-manifest-linter';
10
+ import { PermissionLinter } from './linters/permission-linter/permission-linter';
11
+ import { DeprecatedCspPermissionsManifestLinter } from './linters/manifest-linter/deprecated-csp-permissions-manifest-linter';
12
+ import { DynamicPropertiesPermissionsLinter } from './linters/dynamic-properties-linter/dynamic-properties-permissions-linter';
13
+ import { InvokeEndpointLinter } from './linters/endpoint-linter/invoke-endpoint-linter';
14
+ import { StorageModulesLinter } from './linters/storage-module-linter/storage-module-linter';
15
+ import { FrameComponentLinter } from './linters/frame-component-linter/frame-component-linter';
16
+ import { DeprecatedEgressPermissionsManifestLinter } from './linters/manifest-linter/deprecated-egress-permissions-manifest-linter';
17
+ import { LlmModuleLinter } from './linters/llm-module-linter/llm-module-linter';
18
+ import { DeprecatedApiModuleLinter } from './linters/deprecated-api-module-linter/deprecated-api-module-linter';
19
+ import { AppManagedPermissionsSdkLinter } from './linters/app-managed-permissions-sdk-linter/app-managed-permissions-sdk-linter';
20
+ import { FunctionTimeoutLinter } from './linters/function-timeout-linter/function-timeout-linter';
6
21
  export interface ProblemCount {
7
22
  errors: number;
8
23
  warnings: number;
24
+ approvals: number;
9
25
  }
10
26
  export declare const reportLintResults: (logger: LintLogger, lintResults: LintResult[], showSummary?: boolean) => void;
11
27
  export declare const problemCount: (lintResults: LintResult[]) => ProblemCount;
12
28
  export declare const parseSourceFile: (filepath: string, parser: typeof tsParser, readFilePromise?: typeof fs.readFile.__promisify__) => Promise<LintInput>;
13
- export declare const lint: (filesToLint: string[], manifest: Manifest, environment: string, logger: LintLogger, statsigService: StatsigService, parseFunction?: (filepath: string, parser: typeof tsParser, readFilePromise?: typeof fs.readFile.__promisify__) => Promise<LintInput>, linters?: LinterInterface[]) => Promise<LintResult[]>;
29
+ export declare const getClientSideLintersOnly: (manifest: Manifest, environment: string, logger: LintLogger, statsigService: StatsigService) => Promise<(FunctionTimeoutLinter | PermissionLinter | HandlerLinter | FullManifestLinter | AgentProductContextPermissionsManifestLinter | PermissionsManifestLinter | DeprecatedCspPermissionsManifestLinter | DynamicPropertiesPermissionsLinter | InvokeEndpointLinter | StorageModulesLinter | FrameComponentLinter | DeprecatedEgressPermissionsManifestLinter | LlmModuleLinter | DeprecatedApiModuleLinter | AppManagedPermissionsSdkLinter)[]>;
30
+ export interface LintConfig {
31
+ parseFunction?: (filepath: string, parser: typeof tsParser, readFilePromise?: typeof fs.readFile.__promisify__) => Promise<LintInput>;
32
+ approveRules?: string[];
33
+ buildTag?: string;
34
+ majorVersion?: number;
35
+ linter: {
36
+ mode: 'server-side' | 'both';
37
+ graphqlClient: GraphQLClient;
38
+ } | {
39
+ mode: 'client-side';
40
+ };
41
+ linters?: LinterInterface[];
42
+ }
43
+ export declare const lint: (filesToLint: string[], manifest: Manifest, environment: string, logger: LintLogger, statsigService: StatsigService, config: LintConfig) => Promise<LintResult[]>;
14
44
  export declare const litelint: (logger: LintLogger, statsigService: StatsigService, linter?: LinterInterface) => Promise<LintResult[]>;
15
45
  //# sourceMappingURL=lint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/lint/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,cAAc,EACf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,oBAAoB,CAAC;AAkBxG,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,iBAAiB,GAAI,QAAQ,UAAU,EAAE,aAAa,UAAU,EAAE,EAAE,qBAAkB,KAAG,IA+CrG,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,aAAa,UAAU,EAAE,KAAG,YAQxD,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,UAAU,MAAM,EAChB,QAAQ,OAAO,QAAQ,EACvB,kBAAiB,OAAO,EAAE,CAAC,QAAQ,CAAC,aAAsC,KACzE,OAAO,CAAC,SAAS,CAOnB,CAAC;AAEF,eAAO,MAAM,IAAI,GACf,aAAa,MAAM,EAAE,EACrB,UAAU,QAAQ,EAClB,aAAa,MAAM,EACnB,QAAQ,UAAU,EAClB,gBAAgB,cAAc,EAC9B,2BAlBU,MAAM,UACR,OAAO,QAAQ,oBACN,OAAO,EAAE,CAAC,QAAQ,CAAC,aAAa,KAChD,OAAO,CAAC,SAAS,CAea,EAC/B,UAAS,eAAe,EAgBvB,KACA,OAAO,CAAC,UAAU,EAAE,CAyCtB,CAAC;AAwBF,eAAO,MAAM,QAAQ,GACnB,QAAQ,UAAU,EAClB,gBAAgB,cAAc,EAC9B,SAAQ,eAAiE,KACxE,OAAO,CAAC,UAAU,EAAE,CAGtB,CAAC"}
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/lint/lint.ts"],"names":[],"mappings":"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"}
package/out/lint/lint.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.litelint = exports.lint = exports.parseSourceFile = exports.problemCount = exports.reportLintResults = void 0;
3
+ exports.litelint = exports.lint = exports.getClientSideLintersOnly = exports.parseSourceFile = exports.problemCount = exports.reportLintResults = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const cli_shared_1 = require("@forge/cli-shared");
6
6
  const fs_1 = tslib_1.__importDefault(require("fs"));
@@ -23,8 +23,9 @@ const llm_module_linter_1 = require("./linters/llm-module-linter/llm-module-lint
23
23
  const deprecated_api_module_linter_1 = require("./linters/deprecated-api-module-linter/deprecated-api-module-linter");
24
24
  const app_managed_permissions_sdk_linter_1 = require("./linters/app-managed-permissions-sdk-linter/app-managed-permissions-sdk-linter");
25
25
  const function_timeout_linter_1 = require("./linters/function-timeout-linter/function-timeout-linter");
26
+ const server_side_linter_1 = require("./linters/server-side-linter/server-side-linter");
26
27
  const reportLintResults = (logger, lintResults, showSummary = true) => {
27
- let numErrors = 0, numWarnings = 0;
28
+ let numErrors = 0, numWarnings = 0, numApprovals = 0;
28
29
  let noProblemsFound = true;
29
30
  if (lintResults.length) {
30
31
  lintResults.forEach((lintResult) => {
@@ -32,6 +33,7 @@ const reportLintResults = (logger, lintResults, showSummary = true) => {
32
33
  noProblemsFound = false;
33
34
  numErrors += lintResult.errors.length;
34
35
  numWarnings += lintResult.warnings.length;
36
+ numApprovals += lintResult.approvals.length;
35
37
  logger.info(cli_shared_1.Text.lint.filename(path_1.default.resolve(lintResult.file)));
36
38
  lintResult.errors.forEach(({ line, column, message, reference }) => {
37
39
  logger.info(cli_shared_1.Text.lint.error(line, column, message, reference));
@@ -39,6 +41,9 @@ const reportLintResults = (logger, lintResults, showSummary = true) => {
39
41
  lintResult.warnings.forEach(({ line, column, message, reference }) => {
40
42
  logger.info(cli_shared_1.Text.lint.warning(line, column, message, reference));
41
43
  });
44
+ lintResult.approvals.forEach(({ line, column, message, reference }) => {
45
+ logger.info(cli_shared_1.Text.lint.approval(line, column, message, reference));
46
+ });
42
47
  }
43
48
  });
44
49
  }
@@ -51,18 +56,21 @@ const reportLintResults = (logger, lintResults, showSummary = true) => {
51
56
  const numFixableErrors = resultsWithFixers.reduce((count, result) => count + result.errors.length, 0);
52
57
  const numFixableWarnings = resultsWithFixers.reduce((count, result) => count + result.warnings.length, 0);
53
58
  if (showSummary) {
54
- logger.info(cli_shared_1.Text.lint.summary(numErrors, numWarnings, numFixableErrors, numFixableWarnings));
59
+ logger.info(cli_shared_1.Text.lint.summary(numErrors, numWarnings, numApprovals, numFixableErrors, numFixableWarnings));
55
60
  if (numFixableErrors + numFixableWarnings > 0) {
56
61
  logger.info(cli_shared_1.Text.lint.fixSummary(numErrors, numFixableErrors, numFixableWarnings));
57
62
  }
58
63
  else if (numErrors + numWarnings === 1) {
59
64
  logger.info(cli_shared_1.Text.lint.noFixableProblem);
60
65
  }
66
+ else if (numApprovals > 0) {
67
+ logger.info(cli_shared_1.Text.lint.noFixableProblem);
68
+ }
61
69
  else {
62
70
  logger.info(cli_shared_1.Text.lint.noFixableProblems);
63
71
  }
64
72
  }
65
- if (numErrors) {
73
+ if (numErrors || numApprovals) {
66
74
  process.exitCode = 1;
67
75
  }
68
76
  }
@@ -71,8 +79,9 @@ exports.reportLintResults = reportLintResults;
71
79
  const problemCount = (lintResults) => {
72
80
  return lintResults.reduce((prev, curr) => ({
73
81
  errors: prev.errors + curr.errors.length,
74
- warnings: prev.warnings + curr.warnings.length
75
- }), { errors: 0, warnings: 0 });
82
+ warnings: prev.warnings + curr.warnings.length,
83
+ approvals: prev.approvals + curr.approvals.length
84
+ }), { errors: 0, warnings: 0, approvals: 0 });
76
85
  };
77
86
  exports.problemCount = problemCount;
78
87
  const parseSourceFile = async (filepath, parser, readFilePromise = (0, util_1.promisify)(fs_1.default.readFile)) => {
@@ -84,7 +93,12 @@ const parseSourceFile = async (filepath, parser, readFilePromise = (0, util_1.pr
84
93
  };
85
94
  };
86
95
  exports.parseSourceFile = parseSourceFile;
87
- const lint = async (filesToLint, manifest, environment, logger, statsigService, parseFunction = exports.parseSourceFile, linters = [
96
+ const getServerSideLintersOnly = async (manifest, environment, logger, graphqlClient, options) => [await server_side_linter_1.ServerSideLinter.instance(environment, manifest, graphqlClient, logger, options)];
97
+ const getDefaultLinters = async (manifest, environment, logger, statsigService, graphqlClient, options) => [
98
+ ...(await (0, exports.getClientSideLintersOnly)(manifest, environment, logger, statsigService)),
99
+ ...(await getServerSideLintersOnly(manifest, environment, logger, graphqlClient, options))
100
+ ];
101
+ const getClientSideLintersOnly = async (manifest, environment, logger, statsigService) => [
88
102
  new permission_linter_1.PermissionLinter(environment, manifest, logger),
89
103
  new permissions_manifest_linter_1.PermissionsManifestLinter(logger, statsigService),
90
104
  new agent_product_context_permissions_manifest_linter_1.AgentProductContextPermissionsManifestLinter(logger, statsigService),
@@ -100,7 +114,35 @@ const lint = async (filesToLint, manifest, environment, logger, statsigService,
100
114
  new deprecated_egress_permissions_manifest_linter_1.DeprecatedEgressPermissionsManifestLinter(logger, statsigService),
101
115
  new app_managed_permissions_sdk_linter_1.AppManagedPermissionsSdkLinter(manifest, logger),
102
116
  new function_timeout_linter_1.FunctionTimeoutLinter(manifest, logger)
103
- ]) => {
117
+ ];
118
+ exports.getClientSideLintersOnly = getClientSideLintersOnly;
119
+ const lint = async (filesToLint, manifest, environment, logger, statsigService, config) => {
120
+ let linters;
121
+ if (config.linters) {
122
+ linters = config.linters;
123
+ }
124
+ else {
125
+ switch (config.linter.mode) {
126
+ case 'client-side':
127
+ linters = await (0, exports.getClientSideLintersOnly)(manifest, environment, logger, statsigService);
128
+ break;
129
+ case 'server-side':
130
+ linters = await getServerSideLintersOnly(manifest, environment, logger, config.linter.graphqlClient, {
131
+ approveRules: config.approveRules,
132
+ buildTag: config.buildTag,
133
+ majorVersion: config.majorVersion
134
+ });
135
+ break;
136
+ case 'both':
137
+ linters = await getDefaultLinters(manifest, environment, logger, statsigService, config.linter.graphqlClient, {
138
+ approveRules: config.approveRules,
139
+ buildTag: config.buildTag,
140
+ majorVersion: config.majorVersion
141
+ });
142
+ break;
143
+ }
144
+ }
145
+ const parseFunction = config.parseFunction || exports.parseSourceFile;
104
146
  const { include, exclude } = await (0, cli_shared_1.listTSConfigIncludeExclude)(new cli_shared_1.FileSystemReader());
105
147
  const tsInclude = new Set(include);
106
148
  const tsExclude = new Set(exclude);
@@ -126,6 +168,7 @@ const lint = async (filesToLint, manifest, environment, logger, statsigService,
126
168
  const comparator = (a, b) => a.line === b.line ? a.column - b.column : a.line - b.line;
127
169
  result.errors = result.errors.sort(comparator);
128
170
  result.warnings = result.warnings.sort(comparator);
171
+ result.approvals = result.approvals.sort(comparator);
129
172
  return result;
130
173
  });
131
174
  }
@@ -2,7 +2,8 @@ import { ASTParseResult } from '../parse';
2
2
  import { ConfigFile, Logger } from '@forge/cli-shared';
3
3
  export declare enum LintClass {
4
4
  Error = "error",
5
- Warning = "warning"
5
+ Warning = "warning",
6
+ Approval = "approval"
6
7
  }
7
8
  export type LintLogger = Pick<Logger, 'info'>;
8
9
  export type LintFixer = (errors: LintResultRule[], warnings: LintResultRule[], state: LintFixState) => Promise<LintFixState>;
@@ -16,6 +17,7 @@ export declare class LintResult {
16
17
  private fixer?;
17
18
  errors: LintResultRule[];
18
19
  warnings: LintResultRule[];
20
+ approvals: LintResultRule[];
19
21
  constructor(file: string, fixer?: LintFixer | undefined);
20
22
  add(rule: LintResultRule): void;
21
23
  batchAdd(...rules: LintResultRule[]): void;
@@ -1 +1 @@
1
- {"version":3,"file":"linter-interface.d.ts","sourceRoot":"","sources":["../../src/lint/linter-interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEvD,oBAAY,SAAS;IACnB,KAAK,UAAU;IACf,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,CACtB,MAAM,EAAE,cAAc,EAAE,EACxB,QAAQ,EAAE,cAAc,EAAE,EAC1B,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,qBAAa,UAAU;IAKZ,IAAI,EAAE,MAAM;IACnB,OAAO,CAAC,KAAK,CAAC;IALT,MAAM,EAAE,cAAc,EAAE,CAAM;IAC9B,QAAQ,EAAE,cAAc,EAAE,CAAM;gBAG9B,IAAI,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,SAAS,YAAA;IAGpB,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAW/B,QAAQ,CAAC,GAAG,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI;IAI1C,IAAI,IAAI,MAAM;IAId,QAAQ,IAAI,OAAO;IAIb,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;CAMlE;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"linter-interface.d.ts","sourceRoot":"","sources":["../../src/lint/linter-interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEvD,oBAAY,SAAS;IACnB,KAAK,UAAU;IACf,OAAO,YAAY;IACnB,QAAQ,aAAa;CACtB;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9C,MAAM,MAAM,SAAS,GAAG,CACtB,MAAM,EAAE,cAAc,EAAE,EACxB,QAAQ,EAAE,cAAc,EAAE,EAC1B,KAAK,EAAE,YAAY,KAChB,OAAO,CAAC,YAAY,CAAC,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,qBAAa,UAAU;IAMZ,IAAI,EAAE,MAAM;IACnB,OAAO,CAAC,KAAK,CAAC;IANT,MAAM,EAAE,cAAc,EAAE,CAAM;IAC9B,QAAQ,EAAE,cAAc,EAAE,CAAM;IAChC,SAAS,EAAE,cAAc,EAAE,CAAM;gBAG/B,IAAI,EAAE,MAAM,EACX,KAAK,CAAC,EAAE,SAAS,YAAA;IAGpB,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAc/B,QAAQ,CAAC,GAAG,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI;IAI1C,IAAI,IAAI,MAAM;IAId,QAAQ,IAAI,OAAO;IAIb,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;CAMlE;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,cAAc,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,YAAY,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB"}
@@ -5,12 +5,14 @@ var LintClass;
5
5
  (function (LintClass) {
6
6
  LintClass["Error"] = "error";
7
7
  LintClass["Warning"] = "warning";
8
+ LintClass["Approval"] = "approval";
8
9
  })(LintClass || (exports.LintClass = LintClass = {}));
9
10
  class LintResult {
10
11
  file;
11
12
  fixer;
12
13
  errors = [];
13
14
  warnings = [];
15
+ approvals = [];
14
16
  constructor(file, fixer) {
15
17
  this.file = file;
16
18
  this.fixer = fixer;
@@ -20,6 +22,9 @@ class LintResult {
20
22
  case LintClass.Error:
21
23
  this.errors.push(rule);
22
24
  break;
25
+ case LintClass.Approval:
26
+ this.approvals.push(rule);
27
+ break;
23
28
  default:
24
29
  this.warnings.push(rule);
25
30
  break;
@@ -29,7 +34,7 @@ class LintResult {
29
34
  rules.forEach(this.add, this);
30
35
  }
31
36
  size() {
32
- return this.errors.length + this.warnings.length;
37
+ return this.errors.length + this.warnings.length + this.approvals.length;
33
38
  }
34
39
  hasFixer() {
35
40
  return !!this.fixer;
@@ -3,11 +3,11 @@ import { LintClass, LintResultRule } from '../../../linter-interface';
3
3
  import { BaseLintIssueVerifier, LintIssueVerifier } from '../../verifier-interface';
4
4
  import { type FrameResourceInfo } from '../frame-component-interface';
5
5
  export declare class FrameComponentVerifier extends BaseLintIssueVerifier implements LintIssueVerifier<FrameResourceInfo[]> {
6
- private possibleFrameResourceKeys;
6
+ private entryKeysByResourceKey;
7
7
  constructor(environment: string, manifest: Manifest);
8
8
  protected getLintClass(): LintClass;
9
9
  process(frameResources: FrameResourceInfo[]): Promise<LintResultRule[]>;
10
10
  private isValidFrameResourceKey;
11
- private getPossibleFrameResourceKeysFromManifest;
11
+ private getEntryKeysByResourceKeyFromManifest;
12
12
  }
13
13
  //# sourceMappingURL=frame-component-verifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"frame-component-verifier.d.ts","sourceRoot":"","sources":["../../../../../src/lint/linters/frame-component-linter/verifiers/frame-component-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE,qBAAa,sBAAuB,SAAQ,qBAAsB,YAAW,iBAAiB,CAAC,iBAAiB,EAAE,CAAC;IACjH,OAAO,CAAC,yBAAyB,CAAc;gBAEnC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ;IAKnD,SAAS,CAAC,YAAY,IAAI,SAAS;IAItB,OAAO,CAAC,cAAc,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAepF,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,wCAAwC;CAQjD"}
1
+ {"version":3,"file":"frame-component-verifier.d.ts","sourceRoot":"","sources":["../../../../../src/lint/linters/frame-component-linter/verifiers/frame-component-verifier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEtE,qBAAa,sBAAuB,SAAQ,qBAAsB,YAAW,iBAAiB,CAAC,iBAAiB,EAAE,CAAC;IAIjH,OAAO,CAAC,sBAAsB,CAA2B;gBAE7C,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ;IAKnD,SAAS,CAAC,YAAY,IAAI,SAAS;IAItB,OAAO,CAAC,cAAc,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAepF,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,qCAAqC;CAQ9C"}
@@ -5,10 +5,10 @@ const linter_interface_1 = require("../../../linter-interface");
5
5
  const verifier_interface_1 = require("../../verifier-interface");
6
6
  const text_1 = require("../../../text");
7
7
  class FrameComponentVerifier extends verifier_interface_1.BaseLintIssueVerifier {
8
- possibleFrameResourceKeys;
8
+ entryKeysByResourceKey;
9
9
  constructor(environment, manifest) {
10
10
  super(environment, manifest);
11
- this.possibleFrameResourceKeys = this.getPossibleFrameResourceKeysFromManifest();
11
+ this.entryKeysByResourceKey = this.getEntryKeysByResourceKeyFromManifest();
12
12
  }
13
13
  getLintClass() {
14
14
  return linter_interface_1.LintClass.Error;
@@ -31,11 +31,19 @@ class FrameComponentVerifier extends verifier_interface_1.BaseLintIssueVerifier
31
31
  if (!resourceKey) {
32
32
  return false;
33
33
  }
34
- return this.possibleFrameResourceKeys.has(resourceKey);
34
+ const separatorIndex = resourceKey.indexOf('/');
35
+ if (separatorIndex === -1) {
36
+ const entryKeys = this.entryKeysByResourceKey.get(resourceKey);
37
+ return !!entryKeys && entryKeys.size === 0;
38
+ }
39
+ const key = resourceKey.slice(0, separatorIndex);
40
+ const entry = resourceKey.slice(separatorIndex + 1);
41
+ const entryKeys = this.entryKeysByResourceKey.get(key);
42
+ return entry.length > 0 && entryKeys !== undefined && entryKeys.has(entry);
35
43
  }
36
- getPossibleFrameResourceKeysFromManifest() {
44
+ getEntryKeysByResourceKeyFromManifest() {
37
45
  const resources = this.manifest?.resources ?? [];
38
- return new Set(resources.map(({ key }) => key));
46
+ return new Map(resources.map(({ key, entry }) => [key, new Set(entry ? Object.keys(entry) : [])]));
39
47
  }
40
48
  }
41
49
  exports.FrameComponentVerifier = FrameComponentVerifier;
@@ -10,7 +10,8 @@ export declare class HandlerLinter extends BaseLinter<ExportedMethod, HandlerLin
10
10
  private manifest;
11
11
  constructor(environment: string, manifest: Manifest, logger: LintLogger);
12
12
  bootstrap(): Promise<void>;
13
- private getHandlerFileRegex;
13
+ private escapeRegExp;
14
+ private isHandlerFile;
14
15
  private getFunctionHandlers;
15
16
  protected setupMatchesMap(filepath: string): void;
16
17
  protected filterLintInput(inputs: LintInput[]): LintInput[];
@@ -1 +1 @@
1
- {"version":3,"file":"handler-linter.d.ts","sourceRoot":"","sources":["../../../../src/lint/linters/handler-linter/handler-linter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7D,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAW,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGrF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE/D,UAAU,0BAA0B;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC;IAC7B,gBAAgB,EAAE,aAAa,CAAC;CACjC;AAED,qBAAa,aAAc,SAAQ,UAAU,CAAC,cAAc,EAAE,0BAA0B,EAAE,aAAa,CAAC;IAGpG,OAAO,CAAC,QAAQ;gBADhB,WAAW,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAC1B,MAAM,EAAE,UAAU;IAKP,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC,OAAO,CAAC,mBAAmB,CAAqF;IAEhH,OAAO,CAAC,mBAAmB;IAc3B,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYjD,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE;IAO3D,SAAS,CAAC,oBAAoB,CAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAKvF"}
1
+ {"version":3,"file":"handler-linter.d.ts","sourceRoot":"","sources":["../../../../src/lint/linters/handler-linter/handler-linter.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAW,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGrF,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAE/D,UAAU,0BAA0B;IAClC,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAAC;IAC7B,gBAAgB,EAAE,aAAa,CAAC;CACjC;AAED,qBAAa,aAAc,SAAQ,UAAU,CAAC,cAAc,EAAE,0BAA0B,EAAE,aAAa,CAAC;IAGpG,OAAO,CAAC,QAAQ;gBADhB,WAAW,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAC1B,MAAM,EAAE,UAAU;IAKP,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IASvC,OAAO,CAAC,YAAY,CAA2E;IAE/F,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,mBAAmB;IAc3B,SAAS,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYjD,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE;IAK3D,SAAS,CAAC,oBAAoB,CAAC,cAAc,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAKvF"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HandlerLinter = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const cli_shared_1 = require("@forge/cli-shared");
6
+ const manifest_1 = require("@forge/manifest");
6
7
  const base_linter_1 = tslib_1.__importDefault(require("../../base-linter"));
7
8
  const handlers_verifier_1 = require("./verifiers/handlers-verifier");
8
9
  const visitors_1 = require("./visitors");
@@ -19,7 +20,12 @@ class HandlerLinter extends base_linter_1.default {
19
20
  functionHandlers: new handlers_verifier_1.HandlersVerifier(humanReadableEnvironment, this.manifest)
20
21
  };
21
22
  }
22
- getHandlerFileRegex = (fileName) => new RegExp(`^src(\/|\\\\)${fileName}\.[tj](s|sx)$`);
23
+ escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
24
+ isHandlerFile(handler, filepath) {
25
+ const handlersDirectory = (0, manifest_1.getHandlersDirectory)(this.manifest);
26
+ const handlerFileRegex = new RegExp(`^${this.escapeRegExp(handlersDirectory)}(\/|\\\\)${this.escapeRegExp(handler.file)}\.[tj](s|sx)$`);
27
+ return handlerFileRegex.test(filepath);
28
+ }
23
29
  getFunctionHandlers(manifest) {
24
30
  return manifest.modules?.function
25
31
  ?.filter((funcs) => funcs.handler && funcs.handler.split('.').length === 2)
@@ -35,7 +41,7 @@ class HandlerLinter extends base_linter_1.default {
35
41
  }
36
42
  setupMatchesMap(filepath) {
37
43
  const handlers = this.getFunctionHandlers(this.manifest);
38
- const filteredHandlers = handlers?.filter((handler) => this.getHandlerFileRegex(handler.file).test(filepath));
44
+ const filteredHandlers = handlers?.filter((handler) => this.isHandlerFile(handler, filepath));
39
45
  this.matches.set(filepath, {
40
46
  functionHandlers: {
41
47
  expectedMethods: filteredHandlers || [],
@@ -45,7 +51,7 @@ class HandlerLinter extends base_linter_1.default {
45
51
  }
46
52
  filterLintInput(inputs) {
47
53
  const handlers = this.getFunctionHandlers(this.manifest);
48
- return inputs.filter((input) => handlers?.find((handler) => this.getHandlerFileRegex(handler.file).test(input.filepath)));
54
+ return inputs.filter((input) => handlers?.find((handler) => this.isHandlerFile(handler, input.filepath)));
49
55
  }
50
56
  addLintCriteriaMatch(exportedMethod, filepath) {
51
57
  const criteriaMatches = this.matches.get(filepath);
@@ -0,0 +1,13 @@
1
+ export declare class ZipArchiver {
2
+ private readonly archive;
3
+ private readonly tempFile;
4
+ private readonly resolves;
5
+ private readonly rejects;
6
+ private constructor();
7
+ static create(): Promise<ZipArchiver>;
8
+ addFile(fileName: string, contents: Buffer): void;
9
+ finalise(): Promise<string>;
10
+ private readonly onArchiveError;
11
+ private readonly onClose;
12
+ }
13
+ //# sourceMappingURL=archiver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archiver.d.ts","sourceRoot":"","sources":["../../../../src/lint/linters/server-side-linter/archiver.ts"],"names":[],"mappings":"AAaA,qBAAa,WAAW;IAKF,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJ5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAE3D,OAAO;WAOa,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC;IAM3C,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIjD,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAQlC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAK7B;IAEF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAItB;CACH"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ZipArchiver = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const node_fs_1 = require("node:fs");
6
+ const tmp_1 = tslib_1.__importDefault(require("tmp"));
7
+ class ZipArchiver {
8
+ archive;
9
+ tempFile = tmp_1.default.fileSync({ postfix: '.zip' });
10
+ resolves = [];
11
+ rejects = [];
12
+ constructor(archive) {
13
+ this.archive = archive;
14
+ const output = (0, node_fs_1.createWriteStream)(this.tempFile.name).on('close', this.onClose);
15
+ this.archive.pipe(output);
16
+ this.archive.on('warning', this.onArchiveError);
17
+ this.archive.on('error', this.onArchiveError);
18
+ }
19
+ static async create() {
20
+ const { ZipArchive } = await Promise.resolve().then(() => tslib_1.__importStar(require('archiver')));
21
+ return new ZipArchiver(new ZipArchive());
22
+ }
23
+ addFile(fileName, contents) {
24
+ this.archive.append(contents, { name: fileName });
25
+ }
26
+ finalise() {
27
+ return new Promise((resolve, reject) => {
28
+ this.resolves.push(resolve);
29
+ this.rejects.push(reject);
30
+ return this.archive.finalize();
31
+ });
32
+ }
33
+ onArchiveError = (err) => {
34
+ const error = new Error(err.message);
35
+ for (const reject of this.rejects) {
36
+ reject(error);
37
+ }
38
+ };
39
+ onClose = () => {
40
+ for (const resolve of this.resolves) {
41
+ resolve(this.tempFile.name);
42
+ }
43
+ };
44
+ }
45
+ exports.ZipArchiver = ZipArchiver;
@@ -0,0 +1,30 @@
1
+ import { GraphQLClient, UserError } from '@forge/cli-shared';
2
+ interface ManifestCheckChange {
3
+ added?: (string | null)[] | null;
4
+ key: string;
5
+ removed?: (string | null)[] | null;
6
+ }
7
+ export interface ServerSideOutcome {
8
+ changes?: (ManifestCheckChange | null)[] | null;
9
+ reason: string;
10
+ category: string;
11
+ rule: string;
12
+ value: boolean;
13
+ }
14
+ export declare class NoManifestURLError extends Error {
15
+ constructor();
16
+ }
17
+ export declare class MissingManifestError extends UserError {
18
+ constructor();
19
+ }
20
+ export declare class InvalidManifestError extends UserError {
21
+ constructor();
22
+ }
23
+ export declare class GraphqlClient {
24
+ private readonly graphqlClient;
25
+ constructor(graphqlClient: GraphQLClient);
26
+ createAppManifestUploadUrl(appId: string, environmentKey: string): Promise<string>;
27
+ getAppPreDeploymentCheck(appId: string, environmentKey: string, manifestUrl: string, bypassRules: string[], buildTag?: string, majorVersion?: number): Promise<ServerSideOutcome[]>;
28
+ }
29
+ export {};
30
+ //# sourceMappingURL=graphql-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graphql-client.d.ts","sourceRoot":"","sources":["../../../../src/lint/linters/server-side-linter/graphql-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAEb,SAAS,EAIV,MAAM,mBAAmB,CAAC;AAE3B,UAAU,mBAAmB;IAC3B,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,CAAC,mBAAmB,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;;CAI5C;AAED,qBAAa,oBAAqB,SAAQ,SAAS;;CAIlD;AAED,qBAAa,oBAAqB,SAAQ,SAAS;;CAIlD;AAED,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAE5C,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM;IA+ChE,wBAAwB,CACnC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,EAAE,CAAC;CA0DhC"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphqlClient = exports.InvalidManifestError = exports.MissingManifestError = exports.NoManifestURLError = void 0;
4
+ const cli_shared_1 = require("@forge/cli-shared");
5
+ class NoManifestURLError extends Error {
6
+ constructor() {
7
+ super(cli_shared_1.Text.artifact.error.noManifestUrl);
8
+ }
9
+ }
10
+ exports.NoManifestURLError = NoManifestURLError;
11
+ class MissingManifestError extends cli_shared_1.UserError {
12
+ constructor() {
13
+ super(cli_shared_1.Text.lint.errorMissingManifest);
14
+ }
15
+ }
16
+ exports.MissingManifestError = MissingManifestError;
17
+ class InvalidManifestError extends cli_shared_1.UserError {
18
+ constructor() {
19
+ super(cli_shared_1.Text.lint.errorInvalidManifest);
20
+ }
21
+ }
22
+ exports.InvalidManifestError = InvalidManifestError;
23
+ class GraphqlClient {
24
+ graphqlClient;
25
+ constructor(graphqlClient) {
26
+ this.graphqlClient = graphqlClient;
27
+ }
28
+ async createAppManifestUploadUrl(appId, environmentKey) {
29
+ const mutation = `
30
+ mutation forge_cli_createAppManifestUploadUrl($input: CreateAppManifestUploadUrlInput!) {
31
+ createAppManifestUploadUrl(input: $input) {
32
+ success
33
+ preSignedUrl
34
+ errors {
35
+ message
36
+ extensions {
37
+ errorType
38
+ statusCode
39
+ }
40
+ }
41
+ }
42
+ }`;
43
+ const { response: { createAppManifestUploadUrl: { success, preSignedUrl, errors } }, requestId } = await this.graphqlClient.mutate(mutation, {
44
+ input: {
45
+ appId,
46
+ environmentKey
47
+ }
48
+ });
49
+ if (!success) {
50
+ const error = (0, cli_shared_1.getError)(errors);
51
+ throw new cli_shared_1.GraphQlMutationError(`${error.message} (requestId: ${requestId || 'unknown'})`, {
52
+ requestId,
53
+ code: error.code,
54
+ statusCode: error.statusCode
55
+ });
56
+ }
57
+ if (!preSignedUrl) {
58
+ throw new NoManifestURLError();
59
+ }
60
+ return preSignedUrl;
61
+ }
62
+ async getAppPreDeploymentCheck(appId, environmentKey, manifestUrl, bypassRules, buildTag, majorVersion) {
63
+ const query = `
64
+ query forge_cli_appPreDeploymentCheck($input: AppPreDeploymentCheckInput!) {
65
+ appPreDeploymentCheck(input: $input) {
66
+ outcome {
67
+ rule
68
+ category
69
+ value
70
+ reason
71
+ changes {
72
+ key
73
+ added
74
+ removed
75
+ }
76
+ errors {
77
+ key
78
+ message
79
+ line
80
+ column
81
+ }
82
+ }
83
+ }
84
+ }
85
+ `;
86
+ const result = await this.graphqlClient.query(query, {
87
+ input: {
88
+ appId,
89
+ environmentKey,
90
+ manifestUrl,
91
+ bypassRules,
92
+ buildTag,
93
+ majorVersion
94
+ }
95
+ });
96
+ if (!result.appPreDeploymentCheck) {
97
+ throw new MissingManifestError();
98
+ }
99
+ if (!result.appPreDeploymentCheck.outcome) {
100
+ throw new InvalidManifestError();
101
+ }
102
+ return result.appPreDeploymentCheck.outcome.filter((p) => p !== null);
103
+ }
104
+ }
105
+ exports.GraphqlClient = GraphqlClient;
@@ -0,0 +1,31 @@
1
+ import { ManifestSchema as Manifest } from '@forge/manifest';
2
+ import { LintLogger, LintResult } from '../../linter-interface';
3
+ import { AbstractLinter } from '../../abstract-linter';
4
+ import { FileSystemReader, FileUploader, GraphQLClient } from '@forge/cli-shared';
5
+ import { GraphqlClient } from './graphql-client';
6
+ import { ZipArchiver } from './archiver';
7
+ export declare class ServerSideLinter extends AbstractLinter {
8
+ private readonly environment;
9
+ private readonly manifest;
10
+ private readonly client;
11
+ private readonly fileReader;
12
+ private readonly archiver;
13
+ private readonly fileUploader;
14
+ private readonly options;
15
+ private manifestUploadUrl;
16
+ constructor(environment: string, manifest: Manifest, client: GraphqlClient, fileReader: FileSystemReader, archiver: ZipArchiver, fileUploader: FileUploader, logger: LintLogger, options: {
17
+ approveRules?: string[];
18
+ buildTag?: string;
19
+ majorVersion?: number;
20
+ });
21
+ static instance(environment: string, manifest: Manifest, graphqlClient: GraphQLClient, logger: LintLogger, options: {
22
+ approveRules?: string[];
23
+ buildTag?: string;
24
+ majorVersion?: number;
25
+ }): Promise<ServerSideLinter>;
26
+ private mapServerSideResponse;
27
+ batchExecuteImpl(): Promise<LintResult[]>;
28
+ bootstrap(): Promise<void>;
29
+ private getResultsLinter;
30
+ }
31
+ //# sourceMappingURL=server-side-linter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-side-linter.d.ts","sourceRoot":"","sources":["../../../../src/lint/linters/server-side-linter/server-side-linter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,cAAc,IAAI,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAsC,MAAM,mBAAmB,CAAC;AACtH,OAAO,EAAE,aAAa,EAAqB,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,qBAAa,gBAAiB,SAAQ,cAAc;IAIhD,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAE7B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAV1B,OAAO,CAAC,iBAAiB,CAAqB;gBAG3B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,gBAAgB,EAC5B,QAAQ,EAAE,WAAW,EACrB,YAAY,EAAE,YAAY,EAC3C,MAAM,EAAE,UAAU,EACD,OAAO,EAAE;QACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;WAKU,QAAQ,CACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,aAAa,EAC5B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE;QACP,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB;IAeH,OAAO,CAAC,qBAAqB;IAsBvB,gBAAgB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAmBzC,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAehC,OAAO,CAAC,gBAAgB;CAIzB"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServerSideLinter = void 0;
4
+ const manifest_1 = require("@forge/manifest");
5
+ const linter_interface_1 = require("../../linter-interface");
6
+ const abstract_linter_1 = require("../../abstract-linter");
7
+ const cli_shared_1 = require("@forge/cli-shared");
8
+ const graphql_client_1 = require("./graphql-client");
9
+ const archiver_1 = require("./archiver");
10
+ class ServerSideLinter extends abstract_linter_1.AbstractLinter {
11
+ environment;
12
+ manifest;
13
+ client;
14
+ fileReader;
15
+ archiver;
16
+ fileUploader;
17
+ options;
18
+ manifestUploadUrl;
19
+ constructor(environment, manifest, client, fileReader, archiver, fileUploader, logger, options) {
20
+ super(logger);
21
+ this.environment = environment;
22
+ this.manifest = manifest;
23
+ this.client = client;
24
+ this.fileReader = fileReader;
25
+ this.archiver = archiver;
26
+ this.fileUploader = fileUploader;
27
+ this.options = options;
28
+ }
29
+ static async instance(environment, manifest, graphqlClient, logger, options) {
30
+ const fileSystemReader = new cli_shared_1.FileSystemReader();
31
+ return new ServerSideLinter(environment, manifest, new graphql_client_1.GraphqlClient(graphqlClient), fileSystemReader, await archiver_1.ZipArchiver.create(), new cli_shared_1.HttpFileUploader(fileSystemReader), logger, options);
32
+ }
33
+ mapServerSideResponse(results) {
34
+ const manifestLintResults = new linter_interface_1.LintResult(manifest_1.MANIFEST_FILE);
35
+ manifestLintResults.batchAdd(...(this.getResultsLinter(results).map(({ rule, reason, category }) => {
36
+ return {
37
+ class: category.toLowerCase(),
38
+ message: reason,
39
+ reference: rule,
40
+ line: 0,
41
+ column: 0,
42
+ metadata: {}
43
+ };
44
+ }) ?? []).sort((a, b) => a.line - b.line));
45
+ return manifestLintResults;
46
+ }
47
+ async batchExecuteImpl() {
48
+ if (!this.manifestUploadUrl) {
49
+ throw new Error('Bootstrap failed');
50
+ }
51
+ const results = await this.client.getAppPreDeploymentCheck(this.manifest.app.id, this.environment, this.manifestUploadUrl, this.options.approveRules ?? [], this.options.buildTag, this.options.majorVersion);
52
+ return [this.mapServerSideResponse(results)];
53
+ }
54
+ async bootstrap() {
55
+ const manifestContent = this.fileReader.readBinaryFile(cli_shared_1.manifestFileName);
56
+ if (!manifestContent) {
57
+ throw new Error('No Manifest content found');
58
+ }
59
+ this.archiver.addFile(cli_shared_1.manifestFileName, manifestContent);
60
+ const archivePath = await this.archiver.finalise();
61
+ const uploadUrl = await this.client.createAppManifestUploadUrl(this.manifest.app.id, this.environment);
62
+ await this.fileUploader.uploadFromPath(uploadUrl, archivePath);
63
+ this.manifestUploadUrl = uploadUrl;
64
+ }
65
+ getResultsLinter(results) {
66
+ return results?.filter((outcome) => outcome.value) || [];
67
+ }
68
+ }
69
+ exports.ServerSideLinter = ServerSideLinter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/lint",
3
- "version": "6.0.3-next.8",
3
+ "version": "6.1.0-next.21",
4
4
  "description": "Linting for forge apps",
5
5
  "main": "out/index.js",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -19,15 +19,17 @@
19
19
  "eslint-plugin-import": "^2.29.1"
20
20
  },
21
21
  "dependencies": {
22
- "@forge/cli-shared": "9.3.0-next.8",
23
- "@forge/csp": "6.2.0",
22
+ "@forge/cli-shared": "9.3.0-next.19",
23
+ "@forge/csp": "6.3.0-next.0",
24
24
  "@forge/egress": "3.0.0",
25
- "@forge/manifest": "13.3.0-next.7",
25
+ "@forge/manifest": "13.3.0-next.10",
26
26
  "@typescript-eslint/typescript-estree": "^5.62.0",
27
+ "archiver": "^8.0.0",
27
28
  "array.prototype.flatmap": "^1.3.3",
28
29
  "@atlassian/atlassian-openapi": "^1.0.6",
29
30
  "cross-spawn": "^7.0.6",
30
31
  "node-fetch": "2.7.0",
32
+ "tmp": "^0.2.3",
31
33
  "typescript": "5.9.2"
32
34
  },
33
35
  "publishConfig": {