@malloydata/render-validator 0.0.354 → 0.0.355

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.
@@ -1,5 +1,9 @@
1
1
  /**
2
- * Install minimal DOM globals if not already present.
3
- * Called automatically on import; safe to call again.
2
+ * Install minimal DOM globals. Call before loading the renderer UMD.
4
3
  */
5
- export declare function ensureFakeDom(): void;
4
+ export declare function installFakeDom(): void;
5
+ /**
6
+ * Remove the DOM globals we installed, so libraries loaded later
7
+ * (e.g. axios via trino-client) don't think they're in a browser.
8
+ */
9
+ export declare function removeFakeDom(): void;
package/dist/fake-dom.js CHANGED
@@ -4,13 +4,16 @@
4
4
  * SPDX-License-Identifier: MIT
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.ensureFakeDom = ensureFakeDom;
7
+ exports.installFakeDom = installFakeDom;
8
+ exports.removeFakeDom = removeFakeDom;
8
9
  /**
9
10
  * Minimal DOM stub for headless environments (Node.js).
10
11
  * Provides just enough surface for the renderer's UMD bundle to load
11
12
  * without crashing. Not suitable for actual rendering.
12
13
  *
13
- * Importing this module auto-installs globals if they are absent.
14
+ * Use `installFakeDom()` before loading the renderer, then
15
+ * `removeFakeDom()` afterwards so other libraries (e.g. axios)
16
+ * don't mistakenly believe they are running in a browser.
14
17
  */
15
18
  // eslint-disable-next-line @typescript-eslint/no-empty-function
16
19
  const noop = () => { };
@@ -80,23 +83,30 @@ class Document extends Node {
80
83
  return new Text(text);
81
84
  }
82
85
  }
86
+ // Track which globals we installed so we only remove ours.
87
+ let installed = false;
88
+ let hadDocument = false;
89
+ let hadNavigator = false;
90
+ let hadWindow = false;
83
91
  /**
84
- * Install minimal DOM globals if not already present.
85
- * Called automatically on import; safe to call again.
92
+ * Install minimal DOM globals. Call before loading the renderer UMD.
86
93
  */
87
- function ensureFakeDom() {
94
+ function installFakeDom() {
88
95
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
96
  const g = globalThis;
90
- if (typeof g.document === 'undefined') {
97
+ hadDocument = typeof g.document !== 'undefined';
98
+ hadNavigator = typeof g.navigator !== 'undefined';
99
+ hadWindow = typeof g.window !== 'undefined';
100
+ if (!hadDocument) {
91
101
  g.document = new Document();
92
102
  }
93
- if (typeof g.navigator === 'undefined') {
103
+ if (!hadNavigator) {
94
104
  g.navigator = { userAgent: '' };
95
105
  }
96
106
  else if (typeof g.navigator.userAgent === 'undefined') {
97
107
  g.navigator.userAgent = '';
98
108
  }
99
- if (typeof g.window === 'undefined') {
109
+ if (!hadWindow) {
100
110
  g.window = Object.assign(g, {
101
111
  addEventListener: noop,
102
112
  removeEventListener: noop,
@@ -105,7 +115,32 @@ function ensureFakeDom() {
105
115
  cancelAnimationFrame: noop,
106
116
  });
107
117
  }
118
+ installed = true;
119
+ }
120
+ /**
121
+ * Remove the DOM globals we installed, so libraries loaded later
122
+ * (e.g. axios via trino-client) don't think they're in a browser.
123
+ */
124
+ function removeFakeDom() {
125
+ if (!installed)
126
+ return;
127
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
128
+ const g = globalThis;
129
+ if (!hadWindow) {
130
+ delete g.window;
131
+ // Clean up the properties we merged onto globalThis
132
+ delete g.addEventListener;
133
+ delete g.removeEventListener;
134
+ delete g.getComputedStyle;
135
+ delete g.requestAnimationFrame;
136
+ delete g.cancelAnimationFrame;
137
+ }
138
+ if (!hadDocument) {
139
+ delete g.document;
140
+ }
141
+ if (!hadNavigator) {
142
+ delete g.navigator;
143
+ }
144
+ installed = false;
108
145
  }
109
- // Auto-install on import
110
- ensureFakeDom();
111
146
  //# sourceMappingURL=fake-dom.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fake-dom.js","sourceRoot":"","sources":["../src/fake-dom.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fake-dom.js","sourceRoot":"","sources":["../src/fake-dom.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAiGH,wCA6BC;AAMD,sCAwBC;AA1JD;;;;;;;;GAQG;AAEH,gEAAgE;AAChE,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;AAEtB,MAAM,IAAI;IAAV;QACE,eAAU,GAAW,EAAE,CAAC;QACxB,eAAU,GAAgB,IAAI,CAAC;QAmB/B,sDAAsD;QACtD,qBAAgB,GAAG,IAAI,CAAC;QACxB,wBAAmB,GAAG,IAAI,CAAC;IAC7B,CAAC;IApBC,WAAW,CAAC,KAAW;QACrB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW,CAAC,KAAW;QACrB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,UAAU;;QACZ,OAAO,MAAA,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,mCAAI,IAAI,CAAC;IACpC,CAAC;CAKF;AAED,MAAM,IAAK,SAAQ,IAAI;IACrB,YAAmB,WAAmB;QACpC,KAAK,EAAE,CAAC;QADS,gBAAW,GAAX,WAAW,CAAQ;IAEtC,CAAC;CACF;AAED,MAAM,OAAQ,SAAQ,IAAI;IAKxB,YAAY,OAAe;QACzB,KAAK,EAAE,CAAC;QAJF,UAAK,GAA2B,EAAE,CAAC;QAC3C,UAAK,GAA2B,EAAE,CAAC;QAIjC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAED,YAAY,CAAC,IAAY,EAAE,KAAa;QACtC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,YAAY,CAAC,IAAY;;QACvB,OAAO,MAAA,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mCAAI,IAAI,CAAC;IAClC,CAAC;IAED,eAAe,CAAC,IAAY;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,QAAS,SAAQ,IAAI;IAA3B;;QACE,SAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3B,SAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QAC3B,oBAAe,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAaxC,CAAC;IAXC,aAAa,CAAC,GAAW;QACvB,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,eAAe,CAAC,GAAW,EAAE,GAAW;QACtC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,cAAc,CAAC,IAAY;QACzB,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;CACF;AAED,2DAA2D;AAC3D,IAAI,SAAS,GAAG,KAAK,CAAC;AACtB,IAAI,WAAW,GAAG,KAAK,CAAC;AACxB,IAAI,YAAY,GAAG,KAAK,CAAC;AACzB,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB;;GAEG;AACH,SAAgB,cAAc;IAC5B,8DAA8D;IAC9D,MAAM,CAAC,GAAG,UAAiB,CAAC;IAE5B,WAAW,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,CAAC;IAChD,YAAY,GAAG,OAAO,CAAC,CAAC,SAAS,KAAK,WAAW,CAAC;IAClD,SAAS,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC;IAE5C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,CAAC,CAAC,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,CAAC,CAAC,SAAS,GAAG,EAAC,SAAS,EAAE,EAAE,EAAC,CAAC;IAChC,CAAC;SAAM,IAAI,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,KAAK,WAAW,EAAE,CAAC;QACxD,CAAC,CAAC,SAAS,CAAC,SAAS,GAAG,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE;YAC1B,gBAAgB,EAAE,IAAI;YACtB,mBAAmB,EAAE,IAAI;YACzB,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;YAC5B,qBAAqB,EAAE,IAAI;YAC3B,oBAAoB,EAAE,IAAI;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa;IAC3B,IAAI,CAAC,SAAS;QAAE,OAAO;IACvB,8DAA8D;IAC9D,MAAM,CAAC,GAAG,UAAiB,CAAC;IAE5B,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,CAAC,MAAM,CAAC;QAChB,oDAAoD;QACpD,OAAO,CAAC,CAAC,gBAAgB,CAAC;QAC1B,OAAO,CAAC,CAAC,mBAAmB,CAAC;QAC7B,OAAO,CAAC,CAAC,gBAAgB,CAAC;QAC1B,OAAO,CAAC,CAAC,qBAAqB,CAAC;QAC/B,OAAO,CAAC,CAAC,oBAAoB,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO,CAAC,CAAC,QAAQ,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,CAAC,SAAS,CAAC;IACrB,CAAC;IAED,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import './fake-dom';
2
1
  import type * as Malloy from '@malloydata/malloy-interfaces';
3
2
  /**
4
3
  * Validate renderer tags on a Malloy result without executing the query
package/dist/index.js CHANGED
@@ -5,11 +5,30 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.validateRenderTags = validateRenderTags;
8
- // Fake DOM must be installed before the renderer UMD loads,
9
- // because Solid.js (bundled inside) touches DOM globals at init time.
10
- // CJS require() is synchronous, so this is guaranteed to run first.
11
- require("./fake-dom");
12
- const render_1 = require("@malloydata/render");
8
+ // WHY THIS FILE USES require() AND A FAKE DOM
9
+ //
10
+ // The renderer validates tags by instantiating (but not mounting) a
11
+ // Solid.js component tree. Solid's delegateEvents() runs during the
12
+ // renderer UMD's IIFE and references `window.document` as a default
13
+ // parameter, so merely loading the module in Node.js crashes with
14
+ // "window is not defined".
15
+ //
16
+ // We install fake DOM globals (window, document, navigator) just long
17
+ // enough for the renderer to load, then immediately remove them. If
18
+ // we left them in place, any library that checks
19
+ // `typeof window !== 'undefined'` (e.g. axios, used by trino-client)
20
+ // would think it's in a browser and break in different ways.
21
+ //
22
+ // We use explicit require() instead of import because TypeScript
23
+ // hoists all import statements to the top of the compiled output,
24
+ // making it impossible to run code between two imports. With require()
25
+ // the calls stay in source order: install shim, load renderer, remove shim.
26
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
27
+ const { installFakeDom, removeFakeDom } = require('./fake-dom');
28
+ installFakeDom();
29
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
30
+ const { MalloyRenderer } = require('@malloydata/render');
31
+ removeFakeDom();
13
32
  /**
14
33
  * Validate renderer tags on a Malloy result without executing the query
15
34
  * or requiring a browser DOM. Intended for headless / MCP use.
@@ -18,7 +37,7 @@ const render_1 = require("@malloydata/render");
18
37
  * @returns Array of log messages (errors, warnings) from tag validation
19
38
  */
20
39
  function validateRenderTags(result) {
21
- const renderer = new render_1.MalloyRenderer();
40
+ const renderer = new MalloyRenderer();
22
41
  const viz = renderer.createViz();
23
42
  viz.setResult(result);
24
43
  return viz.getLogs();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAiBH,gDAKC;AApBD,4DAA4D;AAC5D,sEAAsE;AACtE,oEAAoE;AACpE,sBAAoB;AAGpB,+CAAkD;AAElD;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,MAAqB;IACtD,MAAM,QAAQ,GAAG,IAAI,uBAAc,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACjC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAsCH,gDAKC;AAzCD,8CAA8C;AAC9C,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,oEAAoE;AACpE,kEAAkE;AAClE,2BAA2B;AAC3B,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,iDAAiD;AACjD,qEAAqE;AACrE,6DAA6D;AAC7D,EAAE;AACF,iEAAiE;AACjE,kEAAkE;AAClE,uEAAuE;AACvE,4EAA4E;AAE5E,8DAA8D;AAC9D,MAAM,EAAC,cAAc,EAAE,aAAa,EAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAC9D,cAAc,EAAE,CAAC;AAEjB,8DAA8D;AAC9D,MAAM,EAAC,cAAc,EAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AACvD,aAAa,EAAE,CAAC;AAIhB;;;;;;GAMG;AACH,SAAgB,kBAAkB,CAAC,MAAqB;IACtD,MAAM,QAAQ,GAAG,IAAI,cAAc,EAAE,CAAC;IACtC,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACjC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC;AACvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/render-validator",
3
- "version": "0.0.354",
3
+ "version": "0.0.355",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,7 +17,7 @@
17
17
  "clean": "tsc --build --clean && rm -f tsconfig.tsbuildinfo"
18
18
  },
19
19
  "dependencies": {
20
- "@malloydata/malloy-interfaces": "0.0.354",
21
- "@malloydata/render": "0.0.354"
20
+ "@malloydata/malloy-interfaces": "0.0.355",
21
+ "@malloydata/render": "0.0.355"
22
22
  }
23
23
  }
package/src/fake-dom.ts CHANGED
@@ -8,7 +8,9 @@
8
8
  * Provides just enough surface for the renderer's UMD bundle to load
9
9
  * without crashing. Not suitable for actual rendering.
10
10
  *
11
- * Importing this module auto-installs globals if they are absent.
11
+ * Use `installFakeDom()` before loading the renderer, then
12
+ * `removeFakeDom()` afterwards so other libraries (e.g. axios)
13
+ * don't mistakenly believe they are running in a browser.
12
14
  */
13
15
 
14
16
  // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -87,25 +89,34 @@ class Document extends Node {
87
89
  }
88
90
  }
89
91
 
92
+ // Track which globals we installed so we only remove ours.
93
+ let installed = false;
94
+ let hadDocument = false;
95
+ let hadNavigator = false;
96
+ let hadWindow = false;
97
+
90
98
  /**
91
- * Install minimal DOM globals if not already present.
92
- * Called automatically on import; safe to call again.
99
+ * Install minimal DOM globals. Call before loading the renderer UMD.
93
100
  */
94
- export function ensureFakeDom(): void {
101
+ export function installFakeDom(): void {
95
102
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
103
  const g = globalThis as any;
97
104
 
98
- if (typeof g.document === 'undefined') {
105
+ hadDocument = typeof g.document !== 'undefined';
106
+ hadNavigator = typeof g.navigator !== 'undefined';
107
+ hadWindow = typeof g.window !== 'undefined';
108
+
109
+ if (!hadDocument) {
99
110
  g.document = new Document();
100
111
  }
101
112
 
102
- if (typeof g.navigator === 'undefined') {
113
+ if (!hadNavigator) {
103
114
  g.navigator = {userAgent: ''};
104
115
  } else if (typeof g.navigator.userAgent === 'undefined') {
105
116
  g.navigator.userAgent = '';
106
117
  }
107
118
 
108
- if (typeof g.window === 'undefined') {
119
+ if (!hadWindow) {
109
120
  g.window = Object.assign(g, {
110
121
  addEventListener: noop,
111
122
  removeEventListener: noop,
@@ -114,7 +125,36 @@ export function ensureFakeDom(): void {
114
125
  cancelAnimationFrame: noop,
115
126
  });
116
127
  }
128
+
129
+ installed = true;
117
130
  }
118
131
 
119
- // Auto-install on import
120
- ensureFakeDom();
132
+ /**
133
+ * Remove the DOM globals we installed, so libraries loaded later
134
+ * (e.g. axios via trino-client) don't think they're in a browser.
135
+ */
136
+ export function removeFakeDom(): void {
137
+ if (!installed) return;
138
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
139
+ const g = globalThis as any;
140
+
141
+ if (!hadWindow) {
142
+ delete g.window;
143
+ // Clean up the properties we merged onto globalThis
144
+ delete g.addEventListener;
145
+ delete g.removeEventListener;
146
+ delete g.getComputedStyle;
147
+ delete g.requestAnimationFrame;
148
+ delete g.cancelAnimationFrame;
149
+ }
150
+
151
+ if (!hadDocument) {
152
+ delete g.document;
153
+ }
154
+
155
+ if (!hadNavigator) {
156
+ delete g.navigator;
157
+ }
158
+
159
+ installed = false;
160
+ }
package/src/index.ts CHANGED
@@ -3,13 +3,34 @@
3
3
  * SPDX-License-Identifier: MIT
4
4
  */
5
5
 
6
- // Fake DOM must be installed before the renderer UMD loads,
7
- // because Solid.js (bundled inside) touches DOM globals at init time.
8
- // CJS require() is synchronous, so this is guaranteed to run first.
9
- import './fake-dom';
6
+ // WHY THIS FILE USES require() AND A FAKE DOM
7
+ //
8
+ // The renderer validates tags by instantiating (but not mounting) a
9
+ // Solid.js component tree. Solid's delegateEvents() runs during the
10
+ // renderer UMD's IIFE and references `window.document` as a default
11
+ // parameter, so merely loading the module in Node.js crashes with
12
+ // "window is not defined".
13
+ //
14
+ // We install fake DOM globals (window, document, navigator) just long
15
+ // enough for the renderer to load, then immediately remove them. If
16
+ // we left them in place, any library that checks
17
+ // `typeof window !== 'undefined'` (e.g. axios, used by trino-client)
18
+ // would think it's in a browser and break in different ways.
19
+ //
20
+ // We use explicit require() instead of import because TypeScript
21
+ // hoists all import statements to the top of the compiled output,
22
+ // making it impossible to run code between two imports. With require()
23
+ // the calls stay in source order: install shim, load renderer, remove shim.
24
+
25
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
26
+ const {installFakeDom, removeFakeDom} = require('./fake-dom');
27
+ installFakeDom();
28
+
29
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
30
+ const {MalloyRenderer} = require('@malloydata/render');
31
+ removeFakeDom();
10
32
 
11
33
  import type * as Malloy from '@malloydata/malloy-interfaces';
12
- import {MalloyRenderer} from '@malloydata/render';
13
34
 
14
35
  /**
15
36
  * Validate renderer tags on a Malloy result without executing the query