@mondaydotcomorg/z2h-cli 0.34.1 → 0.34.2
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 +2969 -0
- package/dist/backend/__tests__/ast.test.d.ts +2 -0
- package/dist/backend/__tests__/ast.test.d.ts.map +1 -0
- package/dist/backend/__tests__/parse.test.d.ts +2 -0
- package/dist/backend/__tests__/parse.test.d.ts.map +1 -0
- package/dist/backend/ast.d.ts +41 -0
- package/dist/backend/ast.d.ts.map +1 -0
- package/dist/backend/ast.js +152 -0
- package/dist/backend/handler-declaration.d.ts +17 -0
- package/dist/backend/handler-declaration.d.ts.map +1 -0
- package/dist/backend/handler-declaration.js +83 -0
- package/dist/backend/messages.d.ts +10 -0
- package/dist/backend/messages.d.ts.map +1 -0
- package/dist/backend/messages.js +14 -0
- package/dist/backend/parse.d.ts +11 -0
- package/dist/backend/parse.d.ts.map +1 -0
- package/dist/backend/parse.js +66 -0
- package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
- package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
- package/dist/backend/rules/index.d.ts +5 -0
- package/dist/backend/rules/index.d.ts.map +1 -0
- package/dist/backend/rules/index.js +8 -0
- package/dist/backend/rules/snowflake-static-sql.d.ts +15 -0
- package/dist/backend/rules/snowflake-static-sql.d.ts.map +1 -0
- package/dist/backend/rules/snowflake-static-sql.js +75 -0
- package/dist/backend/rules/types.d.ts +29 -0
- package/dist/backend/rules/types.d.ts.map +1 -0
- package/dist/backend/rules/types.js +1 -0
- package/dist/commands/__tests__/delete.test.d.ts +2 -0
- package/dist/commands/__tests__/delete.test.d.ts.map +1 -0
- package/dist/commands/backend.d.ts +0 -1
- package/dist/commands/backend.d.ts.map +1 -1
- package/dist/commands/backend.js +4 -4
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +7 -5
- package/dist/constants.d.ts +2 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +12 -0
- package/dist/esm/backend/__tests__/ast.test.d.ts +2 -0
- package/dist/esm/backend/__tests__/ast.test.d.ts.map +1 -0
- package/dist/esm/backend/__tests__/parse.test.d.ts +2 -0
- package/dist/esm/backend/__tests__/parse.test.d.ts.map +1 -0
- package/dist/esm/backend/ast.d.ts +41 -0
- package/dist/esm/backend/ast.d.ts.map +1 -0
- package/dist/esm/backend/ast.mjs +146 -0
- package/dist/esm/backend/handler-declaration.d.ts +17 -0
- package/dist/esm/backend/handler-declaration.d.ts.map +1 -0
- package/dist/esm/backend/handler-declaration.mjs +78 -0
- package/dist/esm/backend/messages.d.ts +10 -0
- package/dist/esm/backend/messages.d.ts.map +1 -0
- package/dist/esm/backend/messages.mjs +12 -0
- package/dist/esm/backend/parse.d.ts +11 -0
- package/dist/esm/backend/parse.d.ts.map +1 -0
- package/dist/esm/backend/parse.mjs +64 -0
- package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
- package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
- package/dist/esm/backend/rules/index.d.ts +5 -0
- package/dist/esm/backend/rules/index.d.ts.map +1 -0
- package/dist/esm/backend/rules/index.mjs +6 -0
- package/dist/esm/backend/rules/snowflake-static-sql.d.ts +15 -0
- package/dist/esm/backend/rules/snowflake-static-sql.d.ts.map +1 -0
- package/dist/esm/backend/rules/snowflake-static-sql.mjs +73 -0
- package/dist/esm/backend/rules/types.d.ts +29 -0
- package/dist/esm/backend/rules/types.d.ts.map +1 -0
- package/dist/esm/backend/rules/types.mjs +1 -0
- package/dist/esm/commands/__tests__/delete.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/delete.test.d.ts.map +1 -0
- package/dist/esm/commands/backend.d.ts +0 -1
- package/dist/esm/commands/backend.d.ts.map +1 -1
- package/dist/esm/commands/backend.mjs +4 -4
- package/dist/esm/commands/deploy.d.ts.map +1 -1
- package/dist/esm/commands/deploy.mjs +7 -5
- package/dist/esm/constants.d.ts +2 -1
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +5 -2
- package/dist/esm/util/__tests__/usage-upload.test.d.ts +2 -0
- package/dist/esm/util/__tests__/usage-upload.test.d.ts.map +1 -0
- package/dist/esm/util/auth/__tests__/index.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/index.test.d.ts.map +1 -0
- package/dist/esm/util/auth/broker-credential-provider.d.ts +6 -1
- package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -1
- package/dist/esm/util/auth/broker-credential-provider.mjs +2 -2
- package/dist/esm/util/auth/index.d.ts +3 -0
- package/dist/esm/util/auth/index.d.ts.map +1 -0
- package/dist/esm/util/auth/index.mjs +2 -0
- package/dist/esm/util/broker/app.d.ts +0 -1
- package/dist/esm/util/broker/app.d.ts.map +1 -1
- package/dist/esm/util/broker/app.mjs +3 -4
- package/dist/esm/util/usage-json.d.ts +2 -2
- package/dist/esm/util/usage-json.d.ts.map +1 -1
- package/dist/esm/util/usage-json.mjs +5 -2
- package/dist/esm/util/usage-upload.d.ts +3 -0
- package/dist/esm/util/usage-upload.d.ts.map +1 -0
- package/dist/esm/util/usage-upload.mjs +29 -0
- package/dist/util/__tests__/usage-upload.test.d.ts +2 -0
- package/dist/util/__tests__/usage-upload.test.d.ts.map +1 -0
- package/dist/util/auth/__tests__/index.test.d.ts +2 -0
- package/dist/util/auth/__tests__/index.test.d.ts.map +1 -0
- package/dist/util/auth/broker-credential-provider.d.ts +6 -1
- package/dist/util/auth/broker-credential-provider.d.ts.map +1 -1
- package/dist/util/auth/broker-credential-provider.js +2 -2
- package/dist/util/auth/index.d.ts +3 -0
- package/dist/util/auth/index.d.ts.map +1 -0
- package/dist/util/auth/index.js +11 -0
- package/dist/util/broker/app.d.ts +0 -1
- package/dist/util/broker/app.d.ts.map +1 -1
- package/dist/util/broker/app.js +3 -4
- package/dist/util/usage-json.d.ts +2 -2
- package/dist/util/usage-json.d.ts.map +1 -1
- package/dist/util/usage-json.js +5 -2
- package/dist/util/usage-upload.d.ts +3 -0
- package/dist/util/usage-upload.d.ts.map +1 -0
- package/dist/util/usage-upload.js +31 -0
- package/package.json +3 -3
- package/src/commands/__tests__/backend-deploy.test.ts +2 -4
- package/src/commands/__tests__/deploy.test.ts +43 -11
- package/src/commands/backend.ts +4 -5
- package/src/commands/deploy.ts +9 -5
- package/src/constants.ts +6 -0
- package/src/util/__tests__/usage-upload.test.ts +58 -0
- package/src/util/auth/__tests__/broker-credential-provider.test.ts +4 -4
- package/src/util/auth/broker-credential-provider.ts +4 -4
- package/src/util/broker/app.ts +2 -15
- package/src/util/usage-json.ts +11 -4
- package/src/util/usage-upload.ts +38 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,UAAU,EAA2C,MAAM,4BAA4B,CAAC;AAatG,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAWD,wBAAsB,aAAa,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB3E"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -12,6 +12,7 @@ const util_auth_authStore = require('../util/auth/auth-store.js');
|
|
|
12
12
|
const util_appName = require('../util/app-name.js');
|
|
13
13
|
const util_git_repo = require('../util/git/repo.js');
|
|
14
14
|
const util_usageJson = require('../util/usage-json.js');
|
|
15
|
+
const util_usageUpload = require('../util/usage-upload.js');
|
|
15
16
|
const util_git_gitEnv = require('../util/git/git-env.js');
|
|
16
17
|
const util_git_remoteOptions = require('../util/git/remote-options.js');
|
|
17
18
|
const util_s3_client = require('../util/s3/client.js');
|
|
@@ -89,7 +90,7 @@ async function uploadAndRegister(opts) {
|
|
|
89
90
|
const { paths, keyPrefix, appName, token, nextVersion, entry, gitRemote, isPreview, description, masterAppName } = opts;
|
|
90
91
|
// Runs before the frontend upload so a `deployBackend` failure can't leave a
|
|
91
92
|
// preview's unversioned `MF` dir overwritten with no rollback.
|
|
92
|
-
const { integrations, handlerNames
|
|
93
|
+
const { integrations, handlerNames } = await commands_backend.deployBackend({
|
|
93
94
|
appDir: process.cwd(),
|
|
94
95
|
appName,
|
|
95
96
|
mfKeyPrefix: keyPrefix,
|
|
@@ -108,7 +109,6 @@ async function uploadAndRegister(opts) {
|
|
|
108
109
|
gitRemote,
|
|
109
110
|
integrations,
|
|
110
111
|
handlerNames,
|
|
111
|
-
apiUsages,
|
|
112
112
|
description,
|
|
113
113
|
masterAppName,
|
|
114
114
|
});
|
|
@@ -142,7 +142,7 @@ async function deployPreview({ paths, consumerName, appName, token, opts }) {
|
|
|
142
142
|
const url = `${z2hSharedUtils.BUCKET_READ_DNS_URL}/${keyPrefix}`;
|
|
143
143
|
// No catch-all: every stage below tags its own DeployError reason at the throw site,
|
|
144
144
|
// and anything unclassified reports as `unknown` via reasonOf() in runCommand.
|
|
145
|
-
const nextVersion = (await util_auth_brokerCredentialProvider.fetchDeployVersion(previewAppName)) + 1;
|
|
145
|
+
const nextVersion = (await util_auth_brokerCredentialProvider.fetchDeployVersion(previewAppName)).version + 1;
|
|
146
146
|
util_logger.info('building');
|
|
147
147
|
const entry = await buildAndStamp({
|
|
148
148
|
paths,
|
|
@@ -207,9 +207,10 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
207
207
|
await util_git_repo.initRepo(process.cwd(), remote);
|
|
208
208
|
gitRemote = remote;
|
|
209
209
|
}
|
|
210
|
-
const version = await util_auth_brokerCredentialProvider.fetchDeployVersion(appName);
|
|
210
|
+
const { version, id: appId } = await util_auth_brokerCredentialProvider.fetchDeployVersion(appName);
|
|
211
211
|
const nextVersion = version + 1;
|
|
212
212
|
const gitEnv = await util_git_gitEnv.resolveGitEnv(appName, gitRemote);
|
|
213
|
+
let usage = {};
|
|
213
214
|
// Sync git first so a divergence (GitConflictError) stops us.
|
|
214
215
|
// The skill commits the working tree (with an LLM-authored message) before
|
|
215
216
|
// invoking deploy, so the tree should be clean here.
|
|
@@ -218,7 +219,7 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
218
219
|
await util_git_repo.guardCleanTree(process.cwd());
|
|
219
220
|
util_logger.info('syncing with git remote');
|
|
220
221
|
await util_git_repo.pullAndResolve(process.cwd(), gitEnv);
|
|
221
|
-
await util_usageJson.updateOrCreateUsageJson(process.cwd(), appName, util_machineIdentity.whoAmI());
|
|
222
|
+
usage = await util_usageJson.updateOrCreateUsageJson(process.cwd(), appName, util_machineIdentity.whoAmI());
|
|
222
223
|
}
|
|
223
224
|
catch (err) {
|
|
224
225
|
throw util_errors.tagDeployError('git_error', err);
|
|
@@ -275,6 +276,7 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
275
276
|
util_logger.info('releasing deploy lock');
|
|
276
277
|
await releaseLockBestEffort(appName, token);
|
|
277
278
|
}
|
|
279
|
+
await util_usageUpload.putAppUsage(appName, appId, usage, nextVersion);
|
|
278
280
|
// Tags are a post-deploy concern: the S3 upload has already succeeded, so a
|
|
279
281
|
// tag failure never fails the deploy (handled inside).
|
|
280
282
|
await handleDeployTags(appName);
|
package/dist/constants.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare const SHADOW_DEV_DEPS: Record<string, string>;
|
|
|
8
8
|
export declare const MIN_PORT = 13000;
|
|
9
9
|
export declare const MAX_PORT = 19999;
|
|
10
10
|
export declare const GITIGNORE_ENTRIES: string[];
|
|
11
|
-
export { ALWAYS_ON_CHANNELS, APP_NAME_PATTERN, BUCKET_READ_DNS_NAME, BUCKET_READ_DNS_URL, BUCKET_WRITE_NAME, BUCKET_WRITE_URL, DATAVIZ_SKILLS_PREFIX, DECLARED_INTEGRATIONS, MANIFEST_KEY, MANIFEST_READ_URL, PREVIEW_APP_NAME_PREFIX, REGION, S3_PREVIEWS_FOLDER, S3_SKILLS_BUCKET_NAME, type DeclaredIntegration, } from '@mondaydotcomorg/z2h-shared-utils';
|
|
11
|
+
export { ALWAYS_ON_CHANNELS, APP_USAGE_BUCKET_NAME, appUsageFolder, APP_NAME_PATTERN, BUCKET_READ_DNS_NAME, BUCKET_READ_DNS_URL, BUCKET_WRITE_NAME, BUCKET_WRITE_URL, DATAVIZ_SKILLS_PREFIX, DECLARED_INTEGRATIONS, MANIFEST_KEY, MANIFEST_READ_URL, PREVIEW_APP_NAME_PREFIX, REGION, S3_PREVIEWS_FOLDER, S3_SKILLS_BUCKET_NAME, type DeclaredIntegration, } from '@mondaydotcomorg/z2h-shared-utils';
|
|
12
12
|
export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me";
|
|
13
13
|
/**
|
|
14
14
|
* Resolves the broker origin (no trailing slash). Honors
|
|
@@ -16,6 +16,7 @@ export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me
|
|
|
16
16
|
* STS credential provider and the npm-broker registry URL.
|
|
17
17
|
*/
|
|
18
18
|
export declare function brokerBaseUrl(): string;
|
|
19
|
+
export declare function isProdBroker(): boolean;
|
|
19
20
|
export declare function routingHeaders(): Record<string, string>;
|
|
20
21
|
export declare const NPM_BROKER_PATH = "/z2h-cli/npm";
|
|
21
22
|
export declare const BROKER_NPM_SCOPE = "@mondaydotcomorg";
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAI3C,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,mCAAmC,CAAC;AAK3C,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAI3C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,mCAAmC,CAAC;AAK3C,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
package/dist/constants.js
CHANGED
|
@@ -38,6 +38,9 @@ const DEFAULT_BROKER_BASE_URL = 'https://bigbrain-zth.bigbrain.me';
|
|
|
38
38
|
function brokerBaseUrl() {
|
|
39
39
|
return process.env.Z2H_BROKER_BASE_URL || DEFAULT_BROKER_BASE_URL;
|
|
40
40
|
}
|
|
41
|
+
function isProdBroker() {
|
|
42
|
+
return brokerBaseUrl() === DEFAULT_BROKER_BASE_URL;
|
|
43
|
+
}
|
|
41
44
|
// Returns Baggage header for monday-mirror routing when Z2H_ROUTING_KEY is set.
|
|
42
45
|
// No-op in production (returns {}) — only activates when the env var is set.
|
|
43
46
|
function routingHeaders() {
|
|
@@ -75,6 +78,10 @@ Object.defineProperty(exports, 'APP_NAME_PATTERN', {
|
|
|
75
78
|
enumerable: true,
|
|
76
79
|
get: () => z2hSharedUtils.APP_NAME_PATTERN
|
|
77
80
|
});
|
|
81
|
+
Object.defineProperty(exports, 'APP_USAGE_BUCKET_NAME', {
|
|
82
|
+
enumerable: true,
|
|
83
|
+
get: () => z2hSharedUtils.APP_USAGE_BUCKET_NAME
|
|
84
|
+
});
|
|
78
85
|
Object.defineProperty(exports, 'BUCKET_READ_DNS_NAME', {
|
|
79
86
|
enumerable: true,
|
|
80
87
|
get: () => z2hSharedUtils.BUCKET_READ_DNS_NAME
|
|
@@ -123,6 +130,10 @@ Object.defineProperty(exports, 'S3_SKILLS_BUCKET_NAME', {
|
|
|
123
130
|
enumerable: true,
|
|
124
131
|
get: () => z2hSharedUtils.S3_SKILLS_BUCKET_NAME
|
|
125
132
|
});
|
|
133
|
+
Object.defineProperty(exports, 'appUsageFolder', {
|
|
134
|
+
enumerable: true,
|
|
135
|
+
get: () => z2hSharedUtils.appUsageFolder
|
|
136
|
+
});
|
|
126
137
|
exports.BROKER_NPM_SCOPE = BROKER_NPM_SCOPE;
|
|
127
138
|
exports.DEFAULT_BROKER_BASE_URL = DEFAULT_BROKER_BASE_URL;
|
|
128
139
|
exports.GITIGNORE_ENTRIES = GITIGNORE_ENTRIES;
|
|
@@ -136,4 +147,5 @@ exports.SHADOW_SCRIPTS = SHADOW_SCRIPTS;
|
|
|
136
147
|
exports.Z2H_NPM_TOKEN_ENV = Z2H_NPM_TOKEN_ENV;
|
|
137
148
|
exports.brokerBaseUrl = brokerBaseUrl;
|
|
138
149
|
exports.brokerNpmRegistryUrl = brokerNpmRegistryUrl;
|
|
150
|
+
exports.isProdBroker = isProdBroker;
|
|
139
151
|
exports.routingHeaders = routingHeaders;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.test.d.ts","sourceRoot":"","sources":["../../../../src/backend/__tests__/ast.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.test.d.ts","sourceRoot":"","sources":["../../../../src/backend/__tests__/parse.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AnyNode, Expression, Node, Pattern, Program, VariableDeclaration } from 'acorn';
|
|
2
|
+
/** 1-based line a node starts on; requires the program to be parsed with `locations: true`. */
|
|
3
|
+
export declare const lineOf: (node: Node) => number | undefined;
|
|
4
|
+
export interface Declaration {
|
|
5
|
+
kind: VariableDeclaration['kind'];
|
|
6
|
+
init: Expression | null | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Property path from `init` to this binding: `[]` for `const x = init`,
|
|
9
|
+
* `['a', 'b']` for `const { a: { b: x } } = init`, `undefined` when the value
|
|
10
|
+
* is not a plain property read (array/rest/default patterns).
|
|
11
|
+
*/
|
|
12
|
+
path: string[] | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface Bindings {
|
|
15
|
+
/** Every `var|let|const <name> = …` in the file, by name. */
|
|
16
|
+
declarations: Map<string, Declaration[]>;
|
|
17
|
+
/** Names whose value cannot be pinned: reassigned, updated, or bound as parameters. */
|
|
18
|
+
unpinnable: Set<string>;
|
|
19
|
+
}
|
|
20
|
+
/** Every identifier a binding pattern introduces (`{ a, b: [c] } = …` → a, c). */
|
|
21
|
+
export declare const patternNames: (pattern: Pattern) => string[];
|
|
22
|
+
export declare function collectBindings(program: Program): Bindings;
|
|
23
|
+
export interface PathResolver {
|
|
24
|
+
/**
|
|
25
|
+
* Dotted path of a member chain, following `const` aliases back to their
|
|
26
|
+
* source: with `const sf = ctx.api.v1.snowflake`, `sf.query` resolves to
|
|
27
|
+
* `ctx.api.v1.snowflake.query`. Destructuring counts too
|
|
28
|
+
* (`const { snowflake: sf } = ctx.api.v1`). `undefined` if any link is dynamic.
|
|
29
|
+
*
|
|
30
|
+
* Only single, never-reassigned, never-shadowed `const` bindings are followed —
|
|
31
|
+
* anything else is left as written, so a `let` alias or a parameter of the same
|
|
32
|
+
* name is never mistaken for the channel. The handler's first parameter is
|
|
33
|
+
* treated as `ctx` even when renamed (`handler(context)` → `context.api.v1.db`
|
|
34
|
+
* resolves as `ctx.api.v1.db`).
|
|
35
|
+
*/
|
|
36
|
+
pathOf(node: AnyNode): string | undefined;
|
|
37
|
+
}
|
|
38
|
+
export declare function createPathResolver(bindings: Bindings, contextParam?: string): PathResolver;
|
|
39
|
+
/** Every `ctx.api.v1.<domain>` the program touches (known or not), through `paths`. */
|
|
40
|
+
export declare function collectApiDomains(program: Program, paths: PathResolver): Set<string>;
|
|
41
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/backend/ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAG9F,+FAA+F;AAC/F,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,KAAG,MAAM,GAAG,SAAiC,CAAC;AAI/E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,6DAA6D;IAC7D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,uFAAuF;IACvF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AA8CD,kFAAkF;AAClF,eAAO,MAAM,YAAY,GAAI,SAAS,OAAO,KAAG,MAAM,EAAmD,CAAC;AAE1G,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CA4C1D;AA2BD,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CA6B1F;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAWpF"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { full, simple } from 'acorn-walk';
|
|
2
|
+
|
|
3
|
+
/** 1-based line a node starts on; requires the program to be parsed with `locations: true`. */
|
|
4
|
+
const lineOf = (node) => node.loc?.start.line;
|
|
5
|
+
/**
|
|
6
|
+
* Every identifier a binding pattern introduces, with its property path from the
|
|
7
|
+
* pattern's value. `path` is deliberately not defaulted: callers pass `[]` for
|
|
8
|
+
* the root and `undefined` once the pattern stops being a plain property read.
|
|
9
|
+
*/
|
|
10
|
+
function patternBindings(pattern, path) {
|
|
11
|
+
switch (pattern.type) {
|
|
12
|
+
case 'Identifier':
|
|
13
|
+
return [{ name: pattern.name, path }];
|
|
14
|
+
case 'ObjectPattern':
|
|
15
|
+
return pattern.properties.flatMap(p => {
|
|
16
|
+
if (p.type === 'RestElement') {
|
|
17
|
+
return patternBindings(p.argument, undefined);
|
|
18
|
+
}
|
|
19
|
+
const key = propertyKey(p.key, p.computed);
|
|
20
|
+
return patternBindings(p.value, path && key !== undefined ? [...path, key] : undefined);
|
|
21
|
+
});
|
|
22
|
+
case 'ArrayPattern':
|
|
23
|
+
return pattern.elements.flatMap(e => (e ? patternBindings(e, undefined) : []));
|
|
24
|
+
case 'AssignmentPattern':
|
|
25
|
+
return patternBindings(pattern.left, undefined);
|
|
26
|
+
case 'RestElement':
|
|
27
|
+
return patternBindings(pattern.argument, undefined);
|
|
28
|
+
default:
|
|
29
|
+
// MemberExpression targets (`obj.x = …`) bind no names.
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function propertyKey(key, computed) {
|
|
34
|
+
if (key.type === 'Literal' && typeof key.value === 'string') {
|
|
35
|
+
return key.value;
|
|
36
|
+
}
|
|
37
|
+
if (!computed && key.type === 'Identifier') {
|
|
38
|
+
return key.name;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Every identifier a binding pattern introduces (`{ a, b: [c] } = …` → a, c). */
|
|
43
|
+
const patternNames = (pattern) => patternBindings(pattern, []).map(b => b.name);
|
|
44
|
+
function collectBindings(program) {
|
|
45
|
+
const declarations = new Map();
|
|
46
|
+
const unpinnable = new Set();
|
|
47
|
+
const markUnpinnable = (pattern) => patternNames(pattern).forEach(n => unpinnable.add(n));
|
|
48
|
+
full(program, node => {
|
|
49
|
+
switch (node.type) {
|
|
50
|
+
case 'VariableDeclaration':
|
|
51
|
+
for (const declarator of node.declarations) {
|
|
52
|
+
for (const { name, path } of patternBindings(declarator.id, [])) {
|
|
53
|
+
const list = declarations.get(name) ?? [];
|
|
54
|
+
list.push({ kind: node.kind, init: declarator.init, path });
|
|
55
|
+
declarations.set(name, list);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'AssignmentExpression':
|
|
60
|
+
markUnpinnable(node.left);
|
|
61
|
+
break;
|
|
62
|
+
case 'UpdateExpression':
|
|
63
|
+
if (node.argument.type === 'Identifier') {
|
|
64
|
+
unpinnable.add(node.argument.name);
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case 'ForInStatement':
|
|
68
|
+
case 'ForOfStatement':
|
|
69
|
+
if (node.left.type !== 'VariableDeclaration') {
|
|
70
|
+
markUnpinnable(node.left);
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case 'FunctionDeclaration':
|
|
74
|
+
case 'FunctionExpression':
|
|
75
|
+
case 'ArrowFunctionExpression':
|
|
76
|
+
node.params.forEach(markUnpinnable);
|
|
77
|
+
break;
|
|
78
|
+
case 'CatchClause':
|
|
79
|
+
if (node.param) {
|
|
80
|
+
markUnpinnable(node.param);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return { declarations, unpinnable };
|
|
86
|
+
}
|
|
87
|
+
/** `a.b.c` / `a['b'].c` → root `a`, parts `[b, c]`; `undefined` if any link is dynamic or the root is not an identifier. */
|
|
88
|
+
function memberChain(node) {
|
|
89
|
+
if (node.type === 'ChainExpression') {
|
|
90
|
+
return memberChain(node.expression);
|
|
91
|
+
}
|
|
92
|
+
const parts = [];
|
|
93
|
+
let cur = node;
|
|
94
|
+
while (cur.type === 'MemberExpression') {
|
|
95
|
+
const key = propertyKey(cur.property, cur.computed);
|
|
96
|
+
if (key === undefined) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
parts.unshift(key);
|
|
100
|
+
cur = cur.object;
|
|
101
|
+
}
|
|
102
|
+
return cur.type === 'Identifier' ? { root: cur.name, parts } : undefined;
|
|
103
|
+
}
|
|
104
|
+
function createPathResolver(bindings, contextParam) {
|
|
105
|
+
function resolveChain(node, resolving) {
|
|
106
|
+
const chain = memberChain(node);
|
|
107
|
+
if (!chain) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return [resolveRoot(chain.root, resolving), ...chain.parts].join('.');
|
|
111
|
+
}
|
|
112
|
+
function resolveRoot(name, resolving) {
|
|
113
|
+
if (contextParam !== undefined && name === contextParam) {
|
|
114
|
+
return 'ctx';
|
|
115
|
+
}
|
|
116
|
+
if (bindings.unpinnable.has(name) || resolving.has(name)) {
|
|
117
|
+
return name;
|
|
118
|
+
}
|
|
119
|
+
const decls = bindings.declarations.get(name);
|
|
120
|
+
if (!decls || decls.length !== 1) {
|
|
121
|
+
return name;
|
|
122
|
+
}
|
|
123
|
+
const [{ kind, init, path }] = decls;
|
|
124
|
+
if (kind !== 'const' || !init || !path) {
|
|
125
|
+
return name;
|
|
126
|
+
}
|
|
127
|
+
const base = resolveChain(init, new Set(resolving).add(name));
|
|
128
|
+
return base ? [base, ...path].join('.') : name;
|
|
129
|
+
}
|
|
130
|
+
return { pathOf: node => resolveChain(node, new Set()) };
|
|
131
|
+
}
|
|
132
|
+
/** Every `ctx.api.v1.<domain>` the program touches (known or not), through `paths`. */
|
|
133
|
+
function collectApiDomains(program, paths) {
|
|
134
|
+
const apiDomains = new Set();
|
|
135
|
+
simple(program, {
|
|
136
|
+
MemberExpression(node) {
|
|
137
|
+
const [obj, api, version, domain] = paths.pathOf(node)?.split('.') ?? [];
|
|
138
|
+
if (obj === 'ctx' && api === 'api' && version === 'v1' && domain) {
|
|
139
|
+
apiDomains.add(domain);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
return apiDomains;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { collectApiDomains, collectBindings, createPathResolver, lineOf, patternNames };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Expression, FunctionDeclaration, ModuleDeclaration, Statement } from 'acorn';
|
|
2
|
+
export type HandlerDeclaration = {
|
|
3
|
+
kind: 'function';
|
|
4
|
+
params: FunctionDeclaration['params'];
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'variable';
|
|
7
|
+
init: Expression | null | undefined;
|
|
8
|
+
};
|
|
9
|
+
/** The top-level declaration that binds `handler`, if any. */
|
|
10
|
+
export declare function findHandlerDeclaration(body: readonly (Statement | ModuleDeclaration)[]): HandlerDeclaration | undefined;
|
|
11
|
+
/** `export function handler`, `export const handler`, `export { handler }`, `export default handler`. */
|
|
12
|
+
export declare function exportsHandler(node: Statement | ModuleDeclaration): boolean;
|
|
13
|
+
/** First positional parameter of `handler`, when it's a plain identifier (`ctx`, `context`, …). */
|
|
14
|
+
export declare function handlerContextParamName(declaration: HandlerDeclaration): string | undefined;
|
|
15
|
+
/** Values that can never be a function, so `const handler = <this>` is caught at build time. */
|
|
16
|
+
export declare const NEVER_A_FUNCTION: ReadonlySet<string>;
|
|
17
|
+
//# sourceMappingURL=handler-declaration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-declaration.d.ts","sourceRoot":"","sources":["../../../src/backend/handler-declaration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,UAAU,EACV,mBAAmB,EAEnB,iBAAiB,EAEjB,SAAS,EACV,MAAM,OAAO,CAAC;AAMf,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,CAAC;AAE9D,8DAA8D;AAC9D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,CAAC,SAAS,GAAG,iBAAiB,CAAC,EAAE,GAC/C,kBAAkB,GAAG,SAAS,CAahC;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,GAAG,OAAO,CAe3E;AAsCD,mGAAmG;AACnG,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAG3F;AAED,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAK/C,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** True for the `handler` identifier specifically — used everywhere a node might name the binding. */
|
|
2
|
+
const isHandlerIdentifier = (candidate) => candidate?.type === 'Identifier' && candidate.name === 'handler';
|
|
3
|
+
/** The top-level declaration that binds `handler`, if any. */
|
|
4
|
+
function findHandlerDeclaration(body) {
|
|
5
|
+
for (const node of body) {
|
|
6
|
+
if (node.type === 'FunctionDeclaration' && isHandlerIdentifier(node.id)) {
|
|
7
|
+
return { kind: 'function', params: node.params };
|
|
8
|
+
}
|
|
9
|
+
if (node.type === 'VariableDeclaration') {
|
|
10
|
+
const declarator = node.declarations.find(d => isHandlerIdentifier(d.id));
|
|
11
|
+
if (declarator) {
|
|
12
|
+
return { kind: 'variable', init: declarator.init };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/** `export function handler`, `export const handler`, `export { handler }`, `export default handler`. */
|
|
19
|
+
function exportsHandler(node) {
|
|
20
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
21
|
+
return ((node.declaration != null && findHandlerDeclaration([node.declaration]) !== undefined) ||
|
|
22
|
+
node.specifiers.some(s => isHandlerIdentifier(s.local) || isHandlerIdentifier(s.exported)));
|
|
23
|
+
}
|
|
24
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
25
|
+
const { declaration } = node;
|
|
26
|
+
return ((declaration.type === 'FunctionDeclaration' && isHandlerIdentifier(declaration.id)) ||
|
|
27
|
+
isHandlerIdentifier(declaration));
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/** Peel `wrap(fn)`, `(0, fn)`, and the like until a function expression remains. */
|
|
32
|
+
function asFunction(expr) {
|
|
33
|
+
if (!expr) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
switch (expr.type) {
|
|
37
|
+
case 'FunctionExpression':
|
|
38
|
+
case 'ArrowFunctionExpression':
|
|
39
|
+
return expr;
|
|
40
|
+
case 'SequenceExpression':
|
|
41
|
+
return asFunction(expr.expressions.at(-1));
|
|
42
|
+
case 'CallExpression': {
|
|
43
|
+
for (const arg of expr.arguments) {
|
|
44
|
+
if (arg.type === 'SpreadElement') {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const fn = asFunction(arg);
|
|
48
|
+
if (fn) {
|
|
49
|
+
return fn;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function firstParamName(params) {
|
|
59
|
+
let first = params[0];
|
|
60
|
+
if (first?.type === 'AssignmentPattern') {
|
|
61
|
+
first = first.left;
|
|
62
|
+
}
|
|
63
|
+
return first?.type === 'Identifier' ? first.name : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** First positional parameter of `handler`, when it's a plain identifier (`ctx`, `context`, …). */
|
|
66
|
+
function handlerContextParamName(declaration) {
|
|
67
|
+
const params = declaration.kind === 'function' ? declaration.params : asFunction(declaration.init)?.params;
|
|
68
|
+
return params ? firstParamName(params) : undefined;
|
|
69
|
+
}
|
|
70
|
+
/** Values that can never be a function, so `const handler = <this>` is caught at build time. */
|
|
71
|
+
const NEVER_A_FUNCTION = new Set([
|
|
72
|
+
'Literal',
|
|
73
|
+
'ObjectExpression',
|
|
74
|
+
'ArrayExpression',
|
|
75
|
+
'TemplateLiteral',
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
export { NEVER_A_FUNCTION, exportsHandler, findHandlerDeclaration, handlerContextParamName };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const messages: {
|
|
2
|
+
mustDefine: (file: string) => string;
|
|
3
|
+
notAFunction: (file: string) => string;
|
|
4
|
+
mustNotImport: (file: string) => string;
|
|
5
|
+
mustNotExportHandler: (file: string) => string;
|
|
6
|
+
mustNotExport: (file: string) => string;
|
|
7
|
+
moduleOnlySyntax: (file: string, detail: string) => string;
|
|
8
|
+
syntaxError: (file: string, line: number, column: number, detail: string) => string;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/backend/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;uBACA,MAAM;yBACJ,MAAM;0BACL,MAAM;iCAEC,MAAM;0BAEb,MAAM;6BAEH,MAAM,UAAU,MAAM;wBAE3B,MAAM,QAAQ,MAAM,UAAU,MAAM,UAAU,MAAM;CAEzE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const EXAMPLE = 'async function handler(ctx) { ... }';
|
|
2
|
+
const messages = {
|
|
3
|
+
mustDefine: (file) => `${file} must define a handler — e.g. ${EXAMPLE}`,
|
|
4
|
+
notAFunction: (file) => `${file} declares handler but it is not a function — e.g. ${EXAMPLE}`,
|
|
5
|
+
mustNotImport: (file) => `${file} must not import other files or packages — handlers are self-contained; reach the outside world through ctx capabilities`,
|
|
6
|
+
mustNotExportHandler: (file) => `${file} must not export handler — the isolate has no module system; declare it as a plain global, e.g. ${EXAMPLE}`,
|
|
7
|
+
mustNotExport: (file) => `${file} must not use export — the isolate has no module system; declare handler as a plain global, e.g. ${EXAMPLE}`,
|
|
8
|
+
moduleOnlySyntax: (file, detail) => `${file} uses module-only syntax (${detail}) — handlers run as plain scripts, so top-level await and import.meta are not available`,
|
|
9
|
+
syntaxError: (file, line, column, detail) => `${file}:${line}:${column}: not valid JavaScript — ${detail}`,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { messages };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Program } from 'acorn';
|
|
2
|
+
/**
|
|
3
|
+
* The runner compiles handlers with `isolate.compileScript`, i.e. the classic
|
|
4
|
+
* *script* grammar — so that is the grammar we validate against. `import`/`export`
|
|
5
|
+
* declarations and top-level `await`/`import.meta` are only legal under the
|
|
6
|
+
* *module* grammar, so a handler using any of them fails the script parse; we
|
|
7
|
+
* re-parse it as a module purely to name which of those four things it was,
|
|
8
|
+
* instead of surfacing V8's bare "Unexpected token 'export'".
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseOrThrow(file: string, code: string): Program;
|
|
11
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../../src/backend/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8D,KAAK,OAAO,EAAkB,MAAM,OAAO,CAAC;AAkDjH;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAuBhE"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { parse } from 'acorn';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { trackEvent } from '../util/tracker.mjs';
|
|
4
|
+
import { exportsHandler } from './handler-declaration.mjs';
|
|
5
|
+
import { messages } from './messages.mjs';
|
|
6
|
+
|
|
7
|
+
const acornLocSchema = z.object({ line: z.number(), column: z.number() });
|
|
8
|
+
function isAcornSyntaxError(err) {
|
|
9
|
+
return err instanceof SyntaxError && acornLocSchema.safeParse(err.loc).success;
|
|
10
|
+
}
|
|
11
|
+
function tryParse(code, sourceType) {
|
|
12
|
+
try {
|
|
13
|
+
return { ok: true, program: parse(code, { ecmaVersion: 'latest', sourceType, locations: true }) };
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (isAcornSyntaxError(err)) {
|
|
17
|
+
return { ok: false, error: err };
|
|
18
|
+
}
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Acorn appends ` (line:col)` to its messages; we report the position ourselves. */
|
|
23
|
+
const stripPosition = (message) => message.replace(/ \(\d+:\d+\)$/, '');
|
|
24
|
+
const isImportLike = (node) => node.type === 'ImportDeclaration' ||
|
|
25
|
+
node.type === 'ExportAllDeclaration' ||
|
|
26
|
+
(node.type === 'ExportNamedDeclaration' && node.source != null);
|
|
27
|
+
const isExport = (node) => node.type === 'ExportNamedDeclaration' || node.type === 'ExportDefaultDeclaration';
|
|
28
|
+
/** Reports the failure, then returns the error for the caller to throw. */
|
|
29
|
+
function parseError(message) {
|
|
30
|
+
void trackEvent('z2h_cli_handler_parse_error', { error: message });
|
|
31
|
+
return new Error(message);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The runner compiles handlers with `isolate.compileScript`, i.e. the classic
|
|
35
|
+
* *script* grammar — so that is the grammar we validate against. `import`/`export`
|
|
36
|
+
* declarations and top-level `await`/`import.meta` are only legal under the
|
|
37
|
+
* *module* grammar, so a handler using any of them fails the script parse; we
|
|
38
|
+
* re-parse it as a module purely to name which of those four things it was,
|
|
39
|
+
* instead of surfacing V8's bare "Unexpected token 'export'".
|
|
40
|
+
*/
|
|
41
|
+
function parseOrThrow(file, code) {
|
|
42
|
+
const asScript = tryParse(code, 'script');
|
|
43
|
+
if (asScript.ok) {
|
|
44
|
+
return asScript.program;
|
|
45
|
+
}
|
|
46
|
+
const asModule = tryParse(code, 'module');
|
|
47
|
+
if (asModule.ok) {
|
|
48
|
+
const { body } = asModule.program;
|
|
49
|
+
if (body.some(exportsHandler)) {
|
|
50
|
+
throw parseError(messages.mustNotExportHandler(file));
|
|
51
|
+
}
|
|
52
|
+
if (body.some(isImportLike)) {
|
|
53
|
+
throw parseError(messages.mustNotImport(file));
|
|
54
|
+
}
|
|
55
|
+
if (body.some(isExport)) {
|
|
56
|
+
throw parseError(messages.mustNotExport(file));
|
|
57
|
+
}
|
|
58
|
+
throw parseError(messages.moduleOnlySyntax(file, stripPosition(asScript.error.message)));
|
|
59
|
+
}
|
|
60
|
+
const { line, column } = asScript.error.loc;
|
|
61
|
+
throw parseError(messages.syntaxError(file, line, column, stripPosition(asScript.error.message)));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { parseOrThrow };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snowflake-static-sql.test.d.ts","sourceRoot":"","sources":["../../../../../src/backend/rules/__tests__/snowflake-static-sql.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HandlerRule } from './types';
|
|
2
|
+
export type { HandlerRule, RuleContext } from './types';
|
|
3
|
+
/** Every rule the validator runs, in order. Add new capability rules here. */
|
|
4
|
+
export declare const HANDLER_RULES: readonly HandlerRule[];
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/backend/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAExD,8EAA8E;AAC9E,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAAmC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HandlerRule, RuleContext } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `ctx.api.v1.snowflake.query(sql, params?, options?)` — the SQL text must live
|
|
4
|
+
* in the handler. The frontend chooses *which* handler to call and supplies
|
|
5
|
+
* `params` / `options`; it never ships SQL. Binding placeholders (`:name`) are
|
|
6
|
+
* how client values reach the query.
|
|
7
|
+
*
|
|
8
|
+
* The call is matched through `const` aliases of the channel
|
|
9
|
+
* (`const sf = ctx.api.v1.snowflake; sf.query(…)`), see `PathResolver`.
|
|
10
|
+
*/
|
|
11
|
+
export declare class SnowflakeStaticSqlRule implements HandlerRule {
|
|
12
|
+
readonly name = "snowflake/static-sql";
|
|
13
|
+
check({ file, program, bindings, paths }: RuleContext): string[];
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=snowflake-static-sql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snowflake-static-sql.d.ts","sourceRoot":"","sources":["../../../../src/backend/rules/snowflake-static-sql.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAgDxD;;;;;;;;GAQG;AACH,qBAAa,sBAAuB,YAAW,WAAW;IACxD,QAAQ,CAAC,IAAI,0BAA0B;IAEvC,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,WAAW,GAAG,MAAM,EAAE;CAcjE"}
|