@microsoft/rayfin-connector-fabric-semanticmodel 1.34.0-alpha.1148

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) Microsoft Corporation.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # @microsoft/rayfin-connector-fabric-semanticmodel
2
+
3
+ > **Experimental** — this package is experimental and may change substantially in the near future.
4
+ > Mount the typed connectors runtime via the experimental subpath of
5
+ > `@microsoft/rayfin-client` (see snippet below) rather than the stable
6
+ > `RayfinClient` entry.
7
+
8
+ Typed marker for the Rayfin `fabric-semanticmodel` connector category.
9
+
10
+ This package contributes nothing at runtime — it only exports the types
11
+ needed to make `client.connectors.<name>.executeQuery(...)` strongly typed
12
+ when `<name>` points at a `fabric-semanticmodel` connector in `rayfin.yml`.
13
+
14
+ ## Usage
15
+
16
+ Declare your app's connector schema:
17
+
18
+ ```ts
19
+ // rayfin/connectors/schema.ts
20
+ import type { ConnectorsSchema } from '@microsoft/rayfin-client/experimental';
21
+ import type { FabricSemanticModel } from '@microsoft/rayfin-connector-fabric-semanticmodel';
22
+
23
+ export type AppConnectorsSchema = {
24
+ salesModel: FabricSemanticModel<'executeQuery'>;
25
+ };
26
+
27
+ // Optional compile-time guard:
28
+ const _check: ConnectorsSchema = null as unknown as AppConnectorsSchema;
29
+ void _check;
30
+ ```
31
+
32
+ Pass it as the third type parameter of `ConnectorsRayfinClient`:
33
+
34
+ ```ts
35
+ import { ConnectorsRayfinClient } from '@microsoft/rayfin-client/experimental';
36
+ import type { AppConnectorsSchema } from '../rayfin/connectors/schema';
37
+
38
+ const client = new ConnectorsRayfinClient<
39
+ DataSchema,
40
+ FunctionsSchema,
41
+ AppConnectorsSchema
42
+ >({
43
+ baseUrl: import.meta.env.VITE_RAYFIN_BASE_URL,
44
+ publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY,
45
+ });
46
+ ```
47
+
48
+ Then call:
49
+
50
+ ```ts
51
+ const response = await client.connectors.salesModel.executeQuery({
52
+ query: 'EVALUATE TOPN(10, Sales)',
53
+ });
54
+ console.log(response.output.tables[0]?.rows);
55
+ ```
56
+
57
+ The connector's `workspaceId` and `itemId` come from the `connectors.salesModel.config`
58
+ block in `rayfin.yml` — the client never sees them.
59
+
60
+ ## Normalising the response
61
+
62
+ The wire response mirrors Power BI's `executeQueries` shape (rows are
63
+ keyed by qualified column name) and surfaces FuncSet adapter metadata
64
+ such as `requestId`, structured `queryError` / `responseError`, and the
65
+ dataset's sensitivity label. Use `toQueryResult` to fold it into a
66
+ column-aligned, discriminated-union result that's easy to render:
67
+
68
+ ```ts
69
+ import { toQueryResult } from '@microsoft/rayfin-connector-fabric-semanticmodel';
70
+
71
+ const response = await client.connectors.salesModel.executeQuery({
72
+ query: 'EVALUATE TOPN(10, Sales)',
73
+ });
74
+
75
+ const result = toQueryResult(response);
76
+ if (result.status === 'success') {
77
+ console.log(result.table.columns, result.table.rows);
78
+ } else {
79
+ console.error(result.error.category, result.error.message);
80
+ }
81
+ ```
82
+
83
+ Column `dataType` defaults to `'unknown'` until the FuncSet adapter
84
+ surfaces type metadata from an Arrow-capable endpoint.
@@ -0,0 +1,5 @@
1
+ export type { ExecuteQueryInput, FabricSemanticModelColumn, FabricSemanticModelError, FabricSemanticModelInformationProtectionLabel, FabricSemanticModelOutput, FabricSemanticModelTable, FabricSemanticModelTabularResponse, } from './types.js';
2
+ export type { FabricSemanticModel, FabricSemanticModelOperation, FabricSemanticModelOperationCatalog, } from './marker.js';
3
+ export { toQueryResult } from './queryResult.js';
4
+ export type { QueryColumn, QueryError, QueryErrorCategory, QueryTable, SemanticModelQueryResult, } from './queryResult.js';
5
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { toQueryResult } from './queryResult.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Typed marker for the `fabric-semanticmodel` connector
3
+ * category. Contributes the operation catalog that the typed
4
+ * `client.connectors.<name>` proxy uses to type its operations.
5
+ */
6
+ import type { ConnectorMarker, OperationDef } from '@microsoft/rayfin-connectors';
7
+ import type { ExecuteQueryInput, FabricSemanticModelTabularResponse } from './types.js';
8
+ /**
9
+ * Union of all operation names this connector category supports.
10
+ */
11
+ export type FabricSemanticModelOperation = 'executeQuery';
12
+ /**
13
+ * The full catalog of typed operations for `fabric-semanticmodel`.
14
+ */
15
+ export interface FabricSemanticModelOperationCatalog {
16
+ executeQuery: OperationDef<ExecuteQueryInput, FabricSemanticModelTabularResponse>;
17
+ }
18
+ /**
19
+ * Type marker for a `fabric-semanticmodel` connector instance.
20
+ *
21
+ * Pick which operations you want to expose via the union type parameter
22
+ * (defaults to all of them).
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * type AppConnectorsSchema = {
27
+ * salesModel: FabricSemanticModel<'executeQuery'>;
28
+ * };
29
+ * ```
30
+ */
31
+ export type FabricSemanticModel<TOps extends FabricSemanticModelOperation = FabricSemanticModelOperation> = ConnectorMarker<Pick<FabricSemanticModelOperationCatalog, TOps>>;
32
+ //# sourceMappingURL=marker.d.ts.map
package/dist/marker.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Typed marker for the `fabric-semanticmodel` connector
3
+ * category. Contributes the operation catalog that the typed
4
+ * `client.connectors.<name>` proxy uses to type its operations.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=marker.js.map
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Helper that normalises a {@link FabricSemanticModelTabularResponse} into
3
+ * a UI-friendly {@link SemanticModelQueryResult}.
4
+ *
5
+ * The normalised shape is a discriminated union on `status`, with
6
+ * column-aligned rows (`unknown[][]`), categorised errors, and the Power
7
+ * BI `requestId` preserved for traceability.
8
+ */
9
+ import type { FabricSemanticModelTabularResponse } from './types.js';
10
+ /**
11
+ * A single column's metadata in a normalised query result.
12
+ */
13
+ export interface QueryColumn {
14
+ /** Column name, e.g. `"Sales[Amount]"` or `"[Total]"`. */
15
+ name: string;
16
+ /**
17
+ * Power-BI-style dataType, e.g. `"Int64"`, `"String"`, `"DateTime"`.
18
+ *
19
+ * The Power BI JSON `executeQueries` endpoint does not return column
20
+ * types, so this defaults to `"unknown"` until the FuncSet adapter is
21
+ * upgraded to surface real type information.
22
+ */
23
+ dataType: string;
24
+ }
25
+ /**
26
+ * A normalised, table-renderer-friendly query result table.
27
+ *
28
+ * Unlike the raw wire shape (which uses `Record<string, unknown>` rows),
29
+ * this shape uses column-aligned `unknown[][]` rows so consumers can feed
30
+ * them directly into data-grid components.
31
+ */
32
+ export interface QueryTable {
33
+ /** Column definitions in display order. */
34
+ columns: QueryColumn[];
35
+ /** Row-major data. Each row is an array of values aligned with `columns`. */
36
+ rows: unknown[][];
37
+ }
38
+ /**
39
+ * Categorisation for query errors, useful for retry/UX strategies.
40
+ *
41
+ * - `'api'` — transport, auth, or dataset-level failure.
42
+ * - `'query'` — DAX query error (syntax, semantic, etc.).
43
+ * - `'overflow'` — Power BI row/byte cap exceeded; data may be truncated.
44
+ * - `'unknown'` — could not categorise.
45
+ */
46
+ export type QueryErrorCategory = 'api' | 'query' | 'overflow' | 'unknown';
47
+ /**
48
+ * Structured error in a normalised query result.
49
+ */
50
+ export interface QueryError {
51
+ /** Error category. */
52
+ category: QueryErrorCategory;
53
+ /** Human-readable message. */
54
+ message: string;
55
+ /** Error code, when known. */
56
+ code?: string;
57
+ }
58
+ /**
59
+ * Discriminated union representing a normalised query result.
60
+ */
61
+ export type SemanticModelQueryResult = {
62
+ status: 'success';
63
+ table: QueryTable;
64
+ /** Power BI `RequestId` header value, or empty string when unavailable. */
65
+ requestId: string;
66
+ } | {
67
+ status: 'error';
68
+ error: QueryError;
69
+ requestId: string;
70
+ };
71
+ /**
72
+ * Normalise a {@link FabricSemanticModelTabularResponse} into a
73
+ * {@link SemanticModelQueryResult}.
74
+ *
75
+ * Error precedence (highest first):
76
+ *
77
+ * 1. Non-empty `response.errors[]` (FuncSet/transport failure) → `'api'`.
78
+ * 2. `response.output.responseError` (dataset-level) → `'api'`.
79
+ * 3. `response.output.queryError` (per-query) → `'query'`.
80
+ * 4. `response.output.tables[0].error` (per-table) → `'overflow'`.
81
+ *
82
+ * On success, column metadata is taken from `tables[0].columns` if the
83
+ * adapter provided it; otherwise column names are inferred from
84
+ * `Object.keys(rows[0])` and dataTypes default to `'unknown'`.
85
+ */
86
+ export declare function toQueryResult(response: FabricSemanticModelTabularResponse): SemanticModelQueryResult;
87
+ //# sourceMappingURL=queryResult.d.ts.map
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Helper that normalises a {@link FabricSemanticModelTabularResponse} into
3
+ * a UI-friendly {@link SemanticModelQueryResult}.
4
+ *
5
+ * The normalised shape is a discriminated union on `status`, with
6
+ * column-aligned rows (`unknown[][]`), categorised errors, and the Power
7
+ * BI `requestId` preserved for traceability.
8
+ */
9
+ /**
10
+ * Normalise a {@link FabricSemanticModelTabularResponse} into a
11
+ * {@link SemanticModelQueryResult}.
12
+ *
13
+ * Error precedence (highest first):
14
+ *
15
+ * 1. Non-empty `response.errors[]` (FuncSet/transport failure) → `'api'`.
16
+ * 2. `response.output.responseError` (dataset-level) → `'api'`.
17
+ * 3. `response.output.queryError` (per-query) → `'query'`.
18
+ * 4. `response.output.tables[0].error` (per-table) → `'overflow'`.
19
+ *
20
+ * On success, column metadata is taken from `tables[0].columns` if the
21
+ * adapter provided it; otherwise column names are inferred from
22
+ * `Object.keys(rows[0])` and dataTypes default to `'unknown'`.
23
+ */
24
+ export function toQueryResult(response) {
25
+ const requestId = response.output?.requestId ?? '';
26
+ // 1. FuncSet/transport error — invocation didn't return a clean Power BI payload.
27
+ if (Array.isArray(response.errors) && response.errors.length > 0) {
28
+ return {
29
+ status: 'error',
30
+ error: toApiError(response.errors[0]),
31
+ requestId,
32
+ };
33
+ }
34
+ // 2. Top-level response error (dataset/auth).
35
+ if (response.output?.responseError) {
36
+ return {
37
+ status: 'error',
38
+ error: toCategorisedError(response.output.responseError, 'api'),
39
+ requestId,
40
+ };
41
+ }
42
+ // 3. Per-query error.
43
+ if (response.output?.queryError) {
44
+ return {
45
+ status: 'error',
46
+ error: toCategorisedError(response.output.queryError, 'query'),
47
+ requestId,
48
+ };
49
+ }
50
+ // 4. Per-table error → overflow (row/byte cap exceeded).
51
+ const firstTable = response.output?.tables?.[0];
52
+ if (firstTable?.error) {
53
+ return {
54
+ status: 'error',
55
+ error: toCategorisedError(firstTable.error, 'overflow'),
56
+ requestId,
57
+ };
58
+ }
59
+ // 5. Success — build a column-aligned table.
60
+ const rawRows = firstTable?.rows ?? [];
61
+ const wireColumns = firstTable?.columns;
62
+ const columns = wireColumns
63
+ ? wireColumns.map((c) => ({
64
+ name: c.name,
65
+ dataType: c.dataType ?? 'unknown',
66
+ }))
67
+ : (rawRows.length > 0 ? Object.keys(rawRows[0]) : []).map((name) => ({
68
+ name,
69
+ dataType: 'unknown',
70
+ }));
71
+ const rows = rawRows.map((row) => columns.map((col) => row[col.name] ?? null));
72
+ return {
73
+ status: 'success',
74
+ table: { columns, rows },
75
+ requestId,
76
+ };
77
+ }
78
+ function toCategorisedError(err, category) {
79
+ return {
80
+ category,
81
+ message: err.message,
82
+ ...(err.code !== undefined ? { code: err.code } : {}),
83
+ };
84
+ }
85
+ /**
86
+ * Convert an opaque FuncSet error entry to a {@link QueryError}.
87
+ *
88
+ * The FuncSet adapter emits JSON-encoded `RuntimeError` messages for
89
+ * non-200 Power BI responses (see the Python UDF), so this helper tries
90
+ * to parse a JSON envelope of the form
91
+ * `{ httpStatus, code, message, requestId }` out of the entry's
92
+ * `message` field. Falls back to the raw string when parsing fails.
93
+ */
94
+ function toApiError(entry) {
95
+ if (typeof entry === 'object' && entry !== null) {
96
+ const obj = entry;
97
+ const rawMessage = typeof obj.message === 'string' ? obj.message : undefined;
98
+ if (rawMessage !== undefined) {
99
+ const parsed = tryParseJson(rawMessage);
100
+ if (parsed && typeof parsed === 'object') {
101
+ const p = parsed;
102
+ const code = typeof p.code === 'string'
103
+ ? p.code
104
+ : typeof p.httpStatus === 'number'
105
+ ? String(p.httpStatus)
106
+ : undefined;
107
+ return {
108
+ category: 'api',
109
+ message: typeof p.message === 'string' ? p.message : rawMessage,
110
+ ...(code !== undefined ? { code } : {}),
111
+ };
112
+ }
113
+ return { category: 'api', message: rawMessage };
114
+ }
115
+ }
116
+ if (typeof entry === 'string') {
117
+ return { category: 'api', message: entry };
118
+ }
119
+ return { category: 'api', message: 'Connector returned an error.' };
120
+ }
121
+ function tryParseJson(value) {
122
+ try {
123
+ return JSON.parse(value);
124
+ }
125
+ catch {
126
+ return undefined;
127
+ }
128
+ }
129
+ //# sourceMappingURL=queryResult.js.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Runtime + type shapes for `fabric-semanticmodel`
3
+ * operation payloads.
4
+ */
5
+ /**
6
+ * Input payload for the `executeQuery` operation.
7
+ *
8
+ * The Builder only sends the DAX `query`. The connector's target
9
+ * `workspaceId` and `itemId` are declared once under
10
+ * `connectors.<name>.config` in `rayfin.yml`; the BaaS host injects them
11
+ * into the request server-side from that config before forwarding to the
12
+ * FuncSet adapter. The Builder does not (and cannot) send them on the
13
+ * wire — the YAML is the single source of truth.
14
+ */
15
+ export interface ExecuteQueryInput {
16
+ /** A DAX query string. */
17
+ query: string;
18
+ }
19
+ /**
20
+ * Tabular query response from the `executeQuery` operation.
21
+ *
22
+ * The wire envelope wraps the Power BI executeQueries result with metadata
23
+ * surfaced by the FuncSet adapter (`requestId`, structured errors,
24
+ * sensitivity label). `output.tables[]` is the underlying Power BI shape.
25
+ *
26
+ * See {@link toQueryResult} for a normalised, UI-friendly view.
27
+ */
28
+ export interface FabricSemanticModelTabularResponse {
29
+ /** FuncSet invocation status, e.g. `"Succeeded"`. */
30
+ status: string;
31
+ /** The tabular payload. */
32
+ output: FabricSemanticModelOutput;
33
+ /** Errors collected by FuncSet during invocation. Empty array on success. */
34
+ errors: unknown[];
35
+ }
36
+ /**
37
+ * Tabular payload from the connector. Mirrors the Power BI
38
+ * `DatasetExecuteQueriesResponse` shape augmented by the FuncSet adapter.
39
+ */
40
+ export interface FabricSemanticModelOutput {
41
+ /** Tables returned for the query. Power BI returns exactly one table per query. */
42
+ tables: FabricSemanticModelTable[];
43
+ /**
44
+ * Power BI server-assigned request id (from the `RequestId` response
45
+ * header). Use it when reporting issues to the platform team.
46
+ */
47
+ requestId?: string;
48
+ /**
49
+ * Per-query error — for example, `"More than one result table in a query"`.
50
+ * `null` (or omitted) when the query succeeded.
51
+ */
52
+ queryError?: FabricSemanticModelError | null;
53
+ /**
54
+ * Top-level response error — for example, dataset-level authorisation
55
+ * failures. `null` (or omitted) when the response succeeded.
56
+ */
57
+ responseError?: FabricSemanticModelError | null;
58
+ /**
59
+ * Sensitivity label associated with the dataset, if any. Useful for
60
+ * compliance UIs that need to badge data with its classification.
61
+ */
62
+ informationProtectionLabel?: FabricSemanticModelInformationProtectionLabel;
63
+ }
64
+ /**
65
+ * A single result table from the query.
66
+ *
67
+ * Today only `rows` is populated by the FuncSet adapter (Power BI's JSON
68
+ * `executeQueries` endpoint does not return column metadata). The optional
69
+ * `columns` field is reserved for a future adapter upgrade that surfaces
70
+ * Arrow-derived dataTypes.
71
+ */
72
+ export interface FabricSemanticModelTable {
73
+ /** Row data. Keys are fully-qualified column names, e.g. `"Sales[Amount]"`. */
74
+ rows: Array<Record<string, unknown>>;
75
+ /**
76
+ * Per-table error — set by Power BI when row/byte caps are exceeded
77
+ * (e.g. `"More than 1000000 rows in a query result"`). When present, the
78
+ * row data is truncated.
79
+ */
80
+ error?: FabricSemanticModelError;
81
+ /**
82
+ * Reserved for future use. When the FuncSet adapter starts surfacing
83
+ * column metadata (names + dataTypes) from an Arrow-capable endpoint,
84
+ * this field will be populated. Until then, column dataTypes are
85
+ * inferred as `'unknown'` by {@link toQueryResult}.
86
+ */
87
+ columns?: FabricSemanticModelColumn[];
88
+ }
89
+ /**
90
+ * Column metadata, when available from the adapter.
91
+ */
92
+ export interface FabricSemanticModelColumn {
93
+ /** Column name, e.g. `"Sales[Amount]"` or `"[Total]"`. */
94
+ name: string;
95
+ /**
96
+ * Power-BI-style dataType, e.g. `"Int64"`, `"String"`, `"Double"`,
97
+ * `"Decimal"`, `"DateTime"`, or `"Boolean"`. Omitted when the adapter
98
+ * cannot determine the type.
99
+ */
100
+ dataType?: string;
101
+ }
102
+ /**
103
+ * Structured error returned by Power BI. Mirrors the
104
+ * `DatasetExecuteQueriesError` shape.
105
+ */
106
+ export interface FabricSemanticModelError {
107
+ /** Power BI error code, e.g. `"DatasetExecuteQueriesError"`. */
108
+ code?: string;
109
+ /** Human-readable error message. */
110
+ message: string;
111
+ }
112
+ /**
113
+ * Sensitivity label associated with the dataset.
114
+ */
115
+ export interface FabricSemanticModelInformationProtectionLabel {
116
+ /** Label GUID. */
117
+ id: string;
118
+ /** Display name, e.g. `"General"`, `"Confidential"`. */
119
+ name: string;
120
+ }
121
+ //# sourceMappingURL=types.d.ts.map
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Runtime + type shapes for `fabric-semanticmodel`
3
+ * operation payloads.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@microsoft/rayfin-connector-fabric-semanticmodel",
3
+ "version": "1.34.0-alpha.1148",
4
+ "description": "Typed connector marker for the Fabric semantic-model (Power BI dataset) connector category. Pair with @microsoft/rayfin-client to type `client.connectors.<name>.executeQuery(...)`.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*.js",
9
+ "dist/**/*.d.ts",
10
+ "!dist/**/__tests__/**",
11
+ "LICENSE"
12
+ ],
13
+ "devDependencies": {
14
+ "eslint": "^9.28.0",
15
+ "prettier": "^3.5.3",
16
+ "typescript": "^5.8.3",
17
+ "vitest": "^3.2.3",
18
+ "@vitest/coverage-v8": "~3.2.4",
19
+ "rimraf": "~6.0.1"
20
+ },
21
+ "dependencies": {
22
+ "@microsoft/rayfin-connectors": "1.34.0-alpha.1148"
23
+ },
24
+ "publishConfig": {
25
+ "registry": "https://npm.pkg.github.com",
26
+ "access": "restricted"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/microsoft/project-rayfin.git",
31
+ "directory": "packages/typescript-sdk/connector-fabric-semanticmodel"
32
+ },
33
+ "keywords": [
34
+ "rayfin",
35
+ "fabric",
36
+ "semantic-model",
37
+ "powerbi",
38
+ "dax"
39
+ ],
40
+ "author": "Microsoft",
41
+ "license": "MIT",
42
+ "type": "module",
43
+ "scripts": {
44
+ "build": "tsc && node ../scripts/fix-esm-extensions.mjs ./dist",
45
+ "build:watch": "tsc --watch",
46
+ "clean": "rimraf dist && rimraf .tsbuildinfo",
47
+ "test": "vitest run --passWithNoTests"
48
+ }
49
+ }