mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-07 20:04:00 +00:00
Add the ratchet that keeps Cesium inside the renderer
Outside src/render/cesium/, only the 236 files on cesiumAllowList.json may reach Cesium, and each must still do so, so porting a file removes its entry. A file reaches Cesium by importing it or the Cesium adapter, by name or by path, or by being handed the namespace as a parameter, binding or property. Files added to the list since origin/main fail the check, once the list is on main. The renderer contract, stub and conformance suite must stay Cesium-free, and runtime code in a language the check cannot read fails it.
This commit is contained in:
1 parent
8d7f82f110
commit
03f2e2a9b9
3 files changed
+516
No files matched your search
@@ -672,6 +672,8 @@
|
||||
"src/services/requests.js",
|
||||
"src/app/scene.js",
|
||||
"src/app/renderer.test.mjs",
|
||||
"src/render/noCesiumOutsideRender.test.mjs",
|
||||
"src/render/cesiumAllowList.json",
|
||||
"src/geo/geo.test.mjs",
|
||||
"src/geo/celestial.test.mjs",
|
||||
"src/geo/quaternion.test.mjs",
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
[
|
||||
"dev/conformance/main.js",
|
||||
"src/annotations/annotationEngine.js",
|
||||
"src/annotations/drawTool.js",
|
||||
"src/annotations/resolver.js",
|
||||
"src/annotations/screenAnnotationRenderer.js",
|
||||
"src/annotations/worldAnnotationRenderer.js",
|
||||
"src/app/embed.js",
|
||||
"src/app/scene.js",
|
||||
"src/app/viewer.js",
|
||||
"src/camera.js",
|
||||
"src/cameraGroundGuard.js",
|
||||
"src/cameraVerbs.js",
|
||||
"src/celestialRing.js",
|
||||
"src/cockpitCloudEffects.js",
|
||||
"src/cyberSonarGpu.js",
|
||||
"src/cyberSonarScene.js",
|
||||
"src/data/aircraftIconLayer.js",
|
||||
"src/data/aircraftModelLayer.js",
|
||||
"src/data/aircraftMotionRegime.js",
|
||||
"src/data/bhoteKoshiEmbeddedMedia.js",
|
||||
"src/data/bhoteKoshiEvent.js",
|
||||
"src/data/bhoteKoshiLocator.js",
|
||||
"src/data/cameraFraming.js",
|
||||
"src/data/cctvGizmo.js",
|
||||
"src/data/cctvViewshed.js",
|
||||
"src/data/contactTrailRenderer.js",
|
||||
"src/data/dataCredits.js",
|
||||
"src/data/detection.js",
|
||||
"src/data/focusDeemphasis.js",
|
||||
"src/data/geoFileImport.js",
|
||||
"src/data/geoImportPins.js",
|
||||
"src/data/iconOrientation.js",
|
||||
"src/data/iconSegment.js",
|
||||
"src/data/iconSet.js",
|
||||
"src/data/iconSetPrimitive.js",
|
||||
"src/data/localGeojsonCore.js",
|
||||
"src/data/modelRecord.js",
|
||||
"src/data/modelVisualAnchor.js",
|
||||
"src/data/motionModel.js",
|
||||
"src/data/osmOverlays.js",
|
||||
"src/data/trackedCamera.js",
|
||||
"src/data/trailRenderer.js",
|
||||
"src/hud.js",
|
||||
"src/input/dispatcher.js",
|
||||
"src/input/sensorPick.js",
|
||||
"src/layers/airQuality/index.js",
|
||||
"src/layers/alpr/index.js",
|
||||
"src/layers/alpr/model.js",
|
||||
"src/layers/alpr/overlay.js",
|
||||
"src/layers/alpr/presentation.js",
|
||||
"src/layers/alpr/visuals.js",
|
||||
"src/layers/awareness/focus.js",
|
||||
"src/layers/awareness/rendering.js",
|
||||
"src/layers/awareness/state.js",
|
||||
"src/layers/awareness/subject.js",
|
||||
"src/layers/bikeshare/lifecycle.js",
|
||||
"src/layers/bikeshare/policy.js",
|
||||
"src/layers/bikeshare/rendering.js",
|
||||
"src/layers/bikeshare/selection.js",
|
||||
"src/layers/bikeshare/viewport.js",
|
||||
"src/layers/cctv/cards.js",
|
||||
"src/layers/cctv/geometry.js",
|
||||
"src/layers/cctv/geometryQueue.js",
|
||||
"src/layers/cctv/ground.js",
|
||||
"src/layers/cctv/lifecycle.js",
|
||||
"src/layers/cctv/model.js",
|
||||
"src/layers/cctv/navigation.js",
|
||||
"src/layers/cctv/policy.js",
|
||||
"src/layers/cctv/projection.js",
|
||||
"src/layers/cctv/rendering.js",
|
||||
"src/layers/cctv/selection.js",
|
||||
"src/layers/cctv/state.js",
|
||||
"src/layers/cctv/testing.js",
|
||||
"src/layers/cyclones/index.js",
|
||||
"src/layers/cyclones/rendering.js",
|
||||
"src/layers/directions/index.js",
|
||||
"src/layers/earthquakes/index.js",
|
||||
"src/layers/earthquakes/model.js",
|
||||
"src/layers/firms/cards.js",
|
||||
"src/layers/firms/lifecycle.js",
|
||||
"src/layers/firms/model.js",
|
||||
"src/layers/firms/policy.js",
|
||||
"src/layers/firms/rendering.js",
|
||||
"src/layers/firms/state.js",
|
||||
"src/layers/firms/viewport.js",
|
||||
"src/layers/flights/controller.js",
|
||||
"src/layers/flights/enrichment.js",
|
||||
"src/layers/flights/evidence.js",
|
||||
"src/layers/flights/icons.js",
|
||||
"src/layers/flights/lifecycle.js",
|
||||
"src/layers/flights/motion.js",
|
||||
"src/layers/flights/policy.js",
|
||||
"src/layers/flights/queries.js",
|
||||
"src/layers/flights/rendering.js",
|
||||
"src/layers/flights/snapshotRenderer.js",
|
||||
"src/layers/flights/state.js",
|
||||
"src/layers/flights/testing.js",
|
||||
"src/layers/flights/tracking.js",
|
||||
"src/layers/ghostMaps/index.js",
|
||||
"src/layers/gnss/index.js",
|
||||
"src/layers/installations/controls.js",
|
||||
"src/layers/installations/lifecycle.js",
|
||||
"src/layers/installations/model.js",
|
||||
"src/layers/installations/namedMarkers.js",
|
||||
"src/layers/installations/rendering.js",
|
||||
"src/layers/installations/state.js",
|
||||
"src/layers/installations/viewport.js",
|
||||
"src/layers/launches/camera.js",
|
||||
"src/layers/launches/launchPad.js",
|
||||
"src/layers/launches/lifecycle.js",
|
||||
"src/layers/launches/model.js",
|
||||
"src/layers/launches/orbitRendering.js",
|
||||
"src/layers/launches/overlays.js",
|
||||
"src/layers/launches/panel.js",
|
||||
"src/layers/launches/paths.js",
|
||||
"src/layers/launches/policy.js",
|
||||
"src/layers/launches/policyHelpers.js",
|
||||
"src/layers/launches/rendering.js",
|
||||
"src/layers/launches/replay.js",
|
||||
"src/layers/launches/selection.js",
|
||||
"src/layers/launches/state.js",
|
||||
"src/layers/localAdsb/index.js",
|
||||
"src/layers/localAdsb/models.js",
|
||||
"src/layers/localAdsb/motion.js",
|
||||
"src/layers/military/lifecycle.js",
|
||||
"src/layers/military/motion.js",
|
||||
"src/layers/military/policy.js",
|
||||
"src/layers/military/queries.js",
|
||||
"src/layers/military/snapshotRenderer.js",
|
||||
"src/layers/military/state.js",
|
||||
"src/layers/military/testing.js",
|
||||
"src/layers/military/tracking.js",
|
||||
"src/layers/perimeters/index.js",
|
||||
"src/layers/radio/lifecycle.js",
|
||||
"src/layers/radio/navigation.js",
|
||||
"src/layers/radio/queries.js",
|
||||
"src/layers/radio/rendering.js",
|
||||
"src/layers/radio/state.js",
|
||||
"src/layers/recentImagery/rendering.js",
|
||||
"src/layers/satellites/catalog.js",
|
||||
"src/layers/satellites/controls.js",
|
||||
"src/layers/satellites/ingestion.js",
|
||||
"src/layers/satellites/lifecycle.js",
|
||||
"src/layers/satellites/orbits.js",
|
||||
"src/layers/satellites/policy.js",
|
||||
"src/layers/satellites/records.js",
|
||||
"src/layers/satellites/rendering.js",
|
||||
"src/layers/satellites/state.js",
|
||||
"src/layers/satellites/testing.js",
|
||||
"src/layers/satellites/tracking.js",
|
||||
"src/layers/streetLevel/cameraFraming.js",
|
||||
"src/layers/streetLevel/credits.js",
|
||||
"src/layers/streetLevel/groundClick.js",
|
||||
"src/layers/streetLevel/index.js",
|
||||
"src/layers/streetLevel/lineCoverage.js",
|
||||
"src/layers/streetLevel/marker.js",
|
||||
"src/layers/streetLevel/selection.js",
|
||||
"src/layers/streetLevel/sequenceCones.js",
|
||||
"src/layers/streetLevel/view.js",
|
||||
"src/layers/submarineCables/ingestion.js",
|
||||
"src/layers/submarineCables/interaction.js",
|
||||
"src/layers/submarineCables/overlay.js",
|
||||
"src/layers/submarineCables/policy.js",
|
||||
"src/layers/submarineCables/rendering.js",
|
||||
"src/layers/submarineCables/state.js",
|
||||
"src/layers/submarineCables/surface.js",
|
||||
"src/layers/traffic/animation.js",
|
||||
"src/layers/traffic/flow.js",
|
||||
"src/layers/traffic/footprint.js",
|
||||
"src/layers/traffic/ingestion.js",
|
||||
"src/layers/traffic/lifecycle.js",
|
||||
"src/layers/traffic/model.js",
|
||||
"src/layers/traffic/policy.js",
|
||||
"src/layers/traffic/rendering.js",
|
||||
"src/layers/traffic/retention.js",
|
||||
"src/layers/traffic/state.js",
|
||||
"src/layers/traffic/style.js",
|
||||
"src/layers/traffic/surface.js",
|
||||
"src/layers/traffic/timing.js",
|
||||
"src/layers/traffic/viewport.js",
|
||||
"src/layers/transit/height.js",
|
||||
"src/layers/transit/lifecycle.js",
|
||||
"src/layers/transit/rendering.js",
|
||||
"src/layers/transit/selection.js",
|
||||
"src/layers/transit/state.js",
|
||||
"src/layers/transit/testing.js",
|
||||
"src/layers/transit/trails.js",
|
||||
"src/layers/transit/viewport.js",
|
||||
"src/layers/vessels/cameraArea.js",
|
||||
"src/layers/vessels/evidence.js",
|
||||
"src/layers/vessels/queries.js",
|
||||
"src/layers/vessels/rendering.js",
|
||||
"src/layers/vessels/state.js",
|
||||
"src/layers/vessels/tracking.js",
|
||||
"src/layers/weather/index.js",
|
||||
"src/layers/weather/rasterTiles.js",
|
||||
"src/layers/weather/rendering.js",
|
||||
"src/layers/weather/shellRendering.js",
|
||||
"src/layers/wind/gpuRendering.js",
|
||||
"src/layers/wind/index.js",
|
||||
"src/layers/wind/inspection.js",
|
||||
"src/layers/wind/inspectionMarker.js",
|
||||
"src/layers/wind/relief.js",
|
||||
"src/layers/wind/rendering.js",
|
||||
"src/locations.js",
|
||||
"src/maps/catalog.js",
|
||||
"src/maps/controller.js",
|
||||
"src/maps/credits.js",
|
||||
"src/maps/google3d.js",
|
||||
"src/maps/imagery.js",
|
||||
"src/maps/terrain.js",
|
||||
"src/orbit.js",
|
||||
"src/overlays/worldOverlay.js",
|
||||
"src/queries/heights.js",
|
||||
"src/sceneCommandRelease.js",
|
||||
"src/scenes/dataPacks/geometry.js",
|
||||
"src/scenes/dataPacks/presentation.js",
|
||||
"src/scenes/director.js",
|
||||
"src/services/groundSnap.js",
|
||||
"src/services/meshFloorSampler.js",
|
||||
"src/sharelink.js",
|
||||
"src/sky/starrySky.js",
|
||||
"src/ui/applicationShell.js",
|
||||
"src/ui/cameraOrientationControls.js",
|
||||
"src/ui/cockpitCamera.js",
|
||||
"src/ui/cockpitContext.js",
|
||||
"src/ui/cockpitController.js",
|
||||
"src/ui/flyToDataSource.js",
|
||||
"src/ui/imageryBoxTool.js",
|
||||
"src/ui/locationNavigation.js",
|
||||
"src/ui/navigationController.js",
|
||||
"src/ui/shareFollow.js",
|
||||
"src/ui/visualEffects.js",
|
||||
"src/voice/gevActions.js",
|
||||
"src/voice/pointerPick.js",
|
||||
"src/worldFocus.js"
|
||||
]
|
||||
@@ -0,0 +1,276 @@
|
||||
/**
|
||||
* The ratchet: outside `src/render/cesium/`, only the files on
|
||||
* `cesiumAllowList.json` may reach Cesium, and every file on it must still
|
||||
* do so. Porting a file to the renderer contract removes it from the list;
|
||||
* nothing is ever added (checked against the list on `origin/main`).
|
||||
*
|
||||
* A file reaches Cesium when it:
|
||||
* - imports `cesium` or `@cesium/*`, by name or by a path into
|
||||
* `node_modules` (relative or Vite root-relative `/x`, any query ignored);
|
||||
* - imports the Cesium adapter (`src/render/cesium/`);
|
||||
* - is handed the namespace: a parameter or binding named `Cesium`/`cesium`
|
||||
* however destructured, a property of that name (`deps.cesium`,
|
||||
* `window.Cesium`), or member access on an unbound `Cesium`;
|
||||
* - in a `.vue` file, does any of these in a script block, or names Cesium
|
||||
* in `<script src>`.
|
||||
*
|
||||
* Not caught: a Cesium value (a colour, a constant) exported from a listed
|
||||
* module and used elsewhere; each phase 2 port removes those along with its
|
||||
* file. Any name `cesium` counts, so a config field of that name would
|
||||
* over-report rather than slip through.
|
||||
*
|
||||
* Runtime code is every `.js`, `.mjs`, `.cjs` and `.vue` file under `src/`,
|
||||
* `server/` and `dev/`, except tests and test support. */
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { parsers } from 'prettier/plugins/babel.mjs';
|
||||
import { parse as parseSfc } from 'vue/compiler-sfc';
|
||||
|
||||
const root = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
'../..',
|
||||
);
|
||||
const LIST = 'src/render/cesiumAllowList.json';
|
||||
const allowList = JSON.parse(readFileSync(path.join(root, LIST), 'utf8'));
|
||||
|
||||
const SCOPES = ['src', 'server', 'dev'];
|
||||
/** Not runtime code, though not named `.test`: imported by tests only. */
|
||||
const TEST_ONLY = new Set([
|
||||
'src/layers/recentImagery/testDoubles.mjs',
|
||||
'src/layers/weather/shellFixture.mjs',
|
||||
'src/overlays/worldOverlayAllocation.worker.mjs',
|
||||
]);
|
||||
const isTestSupport = (file) =>
|
||||
/\.test\.[cm]?js$/.test(file) ||
|
||||
file.startsWith('src/testSupport/') ||
|
||||
file.startsWith('src/tooling/') ||
|
||||
TEST_ONLY.has(file);
|
||||
const isAdapter = (file) => file.startsWith('src/render/cesium/');
|
||||
|
||||
const git = (...args) =>
|
||||
execFileSync('git', args, { cwd: root, encoding: 'utf8' });
|
||||
const tracked = git(
|
||||
'ls-files',
|
||||
'-z',
|
||||
'--cached',
|
||||
'--others',
|
||||
'--exclude-standard',
|
||||
'--',
|
||||
...SCOPES,
|
||||
)
|
||||
.split('\0')
|
||||
.filter(Boolean);
|
||||
const runtimeFiles = tracked.filter(
|
||||
(file) =>
|
||||
/\.(?:[cm]?js|vue)$/.test(file) && !isTestSupport(file) && !isAdapter(file),
|
||||
);
|
||||
|
||||
/** Whether an import specifier from `file` reaches Cesium. */
|
||||
function reachesCesium(file, specifier) {
|
||||
const bare = specifier.replace(/[?#].*$/, '');
|
||||
if (/^(?:cesium|@cesium\/[^/]+)(?:\/|$)/.test(bare)) return true;
|
||||
if (!bare.startsWith('.') && !bare.startsWith('/')) return false;
|
||||
// Vite reads `/x` from the project root, not the filesystem's.
|
||||
const from = bare.startsWith('/')
|
||||
? root
|
||||
: path.join(root, path.dirname(file));
|
||||
const target = path
|
||||
.relative(root, path.join(from, bare))
|
||||
.split(path.sep)
|
||||
.join('/');
|
||||
return (
|
||||
isAdapter(target) ||
|
||||
/^node_modules\/(?:cesium|@cesium\/[^/]+)(?:\/|$)/.test(target)
|
||||
);
|
||||
}
|
||||
|
||||
const NAMESPACE = new Set(['Cesium', 'cesium']);
|
||||
|
||||
/** The import specifiers of a module, and whether it takes the namespace. */
|
||||
function scan(source) {
|
||||
const imports = [];
|
||||
const bound = new Set();
|
||||
let takesNamespace = false;
|
||||
let usesUnbound = false;
|
||||
const keyName = (property) =>
|
||||
property.computed
|
||||
? property.key?.value
|
||||
: (property.key?.name ?? property.key?.value);
|
||||
/** Any name a binding pattern introduces, however nested or renamed. */
|
||||
const bindName = (node) => {
|
||||
if (!node) return;
|
||||
switch (node.type) {
|
||||
case 'Identifier':
|
||||
if (NAMESPACE.has(node.name)) {
|
||||
bound.add(node.name);
|
||||
takesNamespace = true;
|
||||
}
|
||||
break;
|
||||
case 'AssignmentPattern':
|
||||
bindName(node.left);
|
||||
break;
|
||||
case 'RestElement':
|
||||
bindName(node.argument);
|
||||
break;
|
||||
case 'ArrayPattern':
|
||||
node.elements.forEach(bindName);
|
||||
break;
|
||||
case 'ObjectPattern':
|
||||
for (const property of node.properties) {
|
||||
if (property.type === 'RestElement') bindName(property.argument);
|
||||
else {
|
||||
if (NAMESPACE.has(keyName(property))) takesNamespace = true;
|
||||
bindName(property.value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
function walk(node) {
|
||||
if (!node || typeof node !== 'object') return;
|
||||
if (Array.isArray(node)) return node.forEach(walk);
|
||||
// Every function form (declarations, arrows, object, class and private
|
||||
// methods) carries its parameters as `params`.
|
||||
if (Array.isArray(node.params)) node.params.forEach(bindName);
|
||||
switch (node.type) {
|
||||
case 'ImportDeclaration':
|
||||
case 'ExportNamedDeclaration':
|
||||
case 'ExportAllDeclaration':
|
||||
case 'ImportExpression':
|
||||
if (node.source?.type === 'StringLiteral')
|
||||
imports.push(node.source.value);
|
||||
else if (node.source)
|
||||
throw new Error('Computed module imports are not allowed');
|
||||
if (node.type === 'ImportDeclaration')
|
||||
for (const s of node.specifiers) bound.add(s.local.name);
|
||||
break;
|
||||
case 'CallExpression':
|
||||
if (node.callee?.name === 'require')
|
||||
throw new Error('Runtime modules must use ES imports');
|
||||
break;
|
||||
case 'VariableDeclarator':
|
||||
bindName(node.id);
|
||||
break;
|
||||
case 'CatchClause':
|
||||
bindName(node.param);
|
||||
break;
|
||||
case 'AssignmentExpression':
|
||||
if (node.left?.type?.endsWith('Pattern')) bindName(node.left);
|
||||
break;
|
||||
case 'MemberExpression':
|
||||
case 'OptionalMemberExpression':
|
||||
if (node.object?.type === 'Identifier' && node.object.name === 'Cesium')
|
||||
usesUnbound = true;
|
||||
// The namespace as a property: `deps.cesium`, `window.Cesium`,
|
||||
// `globalThis['Cesium']`.
|
||||
if (
|
||||
NAMESPACE.has(
|
||||
node.computed ? node.property?.value : node.property?.name,
|
||||
)
|
||||
)
|
||||
takesNamespace = true;
|
||||
break;
|
||||
}
|
||||
for (const [key, value] of Object.entries(node)) {
|
||||
if (
|
||||
['loc', 'comments', 'tokens', 'extra', 'leadingComments'].includes(key)
|
||||
)
|
||||
continue;
|
||||
if (value && typeof value === 'object') walk(value);
|
||||
}
|
||||
}
|
||||
walk(parsers.babel.parse(source));
|
||||
// Member access on `Cesium` that nothing in the file binds is a global.
|
||||
if (usesUnbound && !bound.has('Cesium')) takesNamespace = true;
|
||||
return { imports, takesNamespace };
|
||||
}
|
||||
|
||||
/** The scripts of a single-file component, read by Vue's own parser. */
|
||||
function vueScript(file, source) {
|
||||
const { descriptor, errors } = parseSfc(source, { filename: file });
|
||||
if (errors.length) throw errors[0];
|
||||
const blocks = [descriptor.script, descriptor.scriptSetup].filter(Boolean);
|
||||
return {
|
||||
code: blocks.map((block) => block.content).join('\n'),
|
||||
external: blocks.map((block) => block.src).filter(Boolean),
|
||||
};
|
||||
}
|
||||
|
||||
function reachesCesiumFile(file) {
|
||||
const source = readFileSync(path.join(root, file), 'utf8');
|
||||
let code = source;
|
||||
let external = [];
|
||||
if (file.endsWith('.vue')) ({ code, external } = vueScript(file, source));
|
||||
const { imports, takesNamespace } = scan(code);
|
||||
return (
|
||||
takesNamespace ||
|
||||
[...imports, ...external].some((s) => reachesCesium(file, s))
|
||||
);
|
||||
}
|
||||
|
||||
test('only allow-listed files outside the Cesium adapter reach Cesium', () => {
|
||||
const allowed = new Set(allowList);
|
||||
const offenders = runtimeFiles.filter(
|
||||
(file) => !allowed.has(file) && reachesCesiumFile(file),
|
||||
);
|
||||
assert.deepEqual(
|
||||
offenders,
|
||||
[],
|
||||
'Reach the renderer through its contract (src/render/contract) instead.',
|
||||
);
|
||||
});
|
||||
|
||||
test('every allow-listed file still reaches Cesium', () => {
|
||||
const present = new Set(runtimeFiles);
|
||||
const stale = allowList.filter(
|
||||
(file) => !present.has(file) || !reachesCesiumFile(file),
|
||||
);
|
||||
assert.deepEqual(stale, [], `Remove these from ${LIST}.`);
|
||||
});
|
||||
|
||||
test('the allow-list only shrinks', (t) => {
|
||||
// Any git failure fails the check: only the list's confirmed absence on
|
||||
// origin/main (before it lands) skips it.
|
||||
const base = git('merge-base', 'HEAD', 'origin/main').trim();
|
||||
const atBase = git('ls-tree', '--name-only', base, '--', LIST).trim();
|
||||
if (!atBase) {
|
||||
t.skip(`${LIST} is not on origin/main yet`);
|
||||
return;
|
||||
}
|
||||
const before = new Set(JSON.parse(git('show', `${base}:${LIST}`)));
|
||||
const added = allowList.filter((file) => !before.has(file));
|
||||
assert.deepEqual(
|
||||
added,
|
||||
[],
|
||||
`Files added to ${LIST} since ${base} (a moved file needs its old entry removed).`,
|
||||
);
|
||||
});
|
||||
|
||||
test('the allow-list is sorted and has no duplicates', () => {
|
||||
assert.deepEqual(allowList, [...new Set(allowList)].sort());
|
||||
});
|
||||
|
||||
test('no runtime file is in a language the ratchet cannot read', () => {
|
||||
const unread = tracked.filter(
|
||||
(file) =>
|
||||
/\.(?:[cm]?tsx?|jsx)$/.test(file) &&
|
||||
!/\.d\.[cm]?ts$/.test(file) &&
|
||||
!isTestSupport(file),
|
||||
);
|
||||
assert.deepEqual(unread, [], 'Teach the ratchet to read these first.');
|
||||
});
|
||||
|
||||
test('the renderer contract, stub and conformance suite stay Cesium-free', () => {
|
||||
const engineFree = tracked.filter(
|
||||
(file) =>
|
||||
/^src\/render\/(?:contract|stub|conformance)\//.test(file) &&
|
||||
/\.[cm]?js$/.test(file) &&
|
||||
!/\.test\.[cm]?js$/.test(file),
|
||||
);
|
||||
assert.ok(engineFree.length > 0);
|
||||
assert.deepEqual(engineFree.filter(reachesCesiumFile), []);
|
||||
});
|
||||
Reference in new issue
Block a user