Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions jsconfig.site.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "./jsconfig.json",
"exclude": [
"./src/lib/**",
"./src/_components/**",
"./src/routes/_components/**",
"./src/routes/_components_ssr/**",
"./src/routes/_examples/**",
"./src/routes/_examples_ssr/**",
"./src/_data/*",
"./src/scripts/**/*"
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"package": "svelte-kit sync && svelte-package -o dist && publint",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./jsconfig.json",
"check:site": "svelte-kit sync && node ./scripts/check-site.js",
"lint": "prettier --check .",
"format": "prettier --write .",
"update_template": "sh ./src/scripts/update_template.sh",
Expand Down
96 changes: 96 additions & 0 deletions scripts/check-site.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env node
/**
* Run svelte-check for internal site code only, ignoring:
* - src/lib (published library)
* - chart demos under src/_components and src/routes/_components*
* - example charts under src/routes/_examples*
*/
import { spawnSync } from 'node:child_process';
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const svelteCheckBin = require.resolve('svelte-check/bin/svelte-check');

/** Paths deferred to a later pass — not part of this site-only check. */
const ignoredPathParts = [
'src/lib/',
'src/_components/',
'src/routes/_components/',
'src/routes/_components_ssr/',
'src/routes/_examples/',
'src/routes/_examples_ssr/'
];
Comment thread
mhkeller marked this conversation as resolved.

/**
* @param {string} file
*/
function isIgnored(file) {
const normalized = file.replaceAll('\\', '/').replace(/^[A-Za-z]:/, '');
return ignoredPathParts.some(part => normalized.includes(`/${part}`) || normalized.startsWith(part));
}
Comment thread
Copilot marked this conversation as resolved.

const result = spawnSync(process.execPath, [svelteCheckBin, '--tsconfig', './jsconfig.site.json'], {
encoding: 'utf8',
maxBuffer: 20 * 1024 * 1024
});

const output = result.stdout || '';
process.stdout.write(output);
if (result.stderr) process.stderr.write(result.stderr);

const lines = output.split('\n');
/** @type {{ file: string, line: number, col: number, msg: string }[]} */
const siteErrors = [];
/** @type {string | null} */
let currentFile = null;
let currentLine = 0;
let currentCol = 0;
/** @type {string | null} */
let currentKind = null;
/** @type {string[]} */
let currentMsg = [];

function flush() {
if (!currentFile || currentKind !== 'Error') return;
if (isIgnored(currentFile)) return;
siteErrors.push({
file: currentFile,
line: currentLine,
col: currentCol,
msg: currentMsg.join('\n').trim()
});
}

for (const line of lines) {
const locParts = line.match(/^(.+):(\d+):(\d+)$/);
if (locParts) {
flush();
currentFile = locParts[1];
currentLine = Number(locParts[2]);
currentCol = Number(locParts[3]);
currentKind = null;
currentMsg = [];
continue;
}
const kind = line.match(/^(Error|Warn|Hint):\s*(.*)$/);
if (kind && currentFile) {
flush();
currentKind = kind[1];
currentMsg = [kind[2]];
continue;
}
if (currentKind && currentFile && line && !line.startsWith('=====')) {
currentMsg.push(line);
}
}
flush();

if (siteErrors.length) {
console.error(
`\ncheck:site found ${siteErrors.length} internal-site error(s) (lib/charts ignored).`
);
process.exit(1);
}

console.log('\ncheck:site passed (no internal-site errors; lib/charts ignored).');
process.exit(0);
34 changes: 28 additions & 6 deletions src/_modules/arrowUtils.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
// Helper functions for creating swoopy arrows

/* --------------------------------------------
/**
* parseCssValue
*
* Parse various inputs and return then as a number
* Can be a number, which will return the input value
* A percentage, which will take the percent of the appropriate dimentions
* A pixel value, which will parse as a number
*
* @param {string|number|null|undefined} d
* @param {number} i
* @param {number} width
* @param {number} height
* @returns {number}
*/
export function parseCssValue(d, i, width, height) {
if (!d) return 0;
Expand All @@ -20,16 +25,18 @@ export function parseCssValue(d, i, width, height) {
return +d.replace('px', '');
}

/* --------------------------------------------
/**
* getElPosition
*
* Constract a bounding box relative in our coordinate space
* that we can attach arrow starting points to
*
* @param {Element} el
* @returns {{ top: number, right: number, bottom: number, left: number, width: number, height: number }}
*/
export function getElPosition(el) {
const annotationBbox = el.getBoundingClientRect();
const parentBbox = el.parentNode.getBoundingClientRect();
const parentBbox = (el.parentElement ?? el).getBoundingClientRect();
const coords = {
top: annotationBbox.top - parentBbox.top,
right: annotationBbox.right - parentBbox.left,
Expand All @@ -50,13 +57,24 @@ export function getElPosition(el) {
export function swoopyArrow() {
let angle = Math.PI;
let clockwise = true;
/** @type {(d: any) => number} */
let xValue = d => d[0];
/** @type {(d: any) => number} */
let yValue = d => d[1];

/**
* @param {number} a
* @param {number} b
* @returns {number}
*/
function hypotenuse(a, b) {
return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}

/**
* @param {any[]} data
* @returns {string}
*/
function render(data) {
data = data.map(d => {
return [xValue(d), yValue(d)];
Expand Down Expand Up @@ -102,27 +120,31 @@ export function swoopyArrow() {
return path;
}

/** @param {number} [_] */
render.angle = function renderAngle(_) {
if (!arguments.length) return angle;
angle = Math.min(Math.max(_, 1e-6), Math.PI - 1e-6);
angle = Math.min(Math.max(/** @type {number} */ (_), 1e-6), Math.PI - 1e-6);
return render;
};

/** @param {boolean} [_] */
render.clockwise = function renderClockwise(_) {
if (!arguments.length) return clockwise;
clockwise = !!_;
return render;
};

/** @param {(d: any) => number} [_] */
render.x = function renderX(_) {
if (!arguments.length) return xValue;
xValue = _;
xValue = /** @type {(d: any) => number} */ (_);
return render;
};

/** @param {(d: any) => number} [_] */
render.y = function renderY(_) {
if (!arguments.length) return yValue;
yValue = _;
yValue = /** @type {(d: any) => number} */ (_);
return render;
};

Expand Down
7 changes: 6 additions & 1 deletion src/_modules/calcThresholds.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
export default function calcThresholds(domain = [0, 1], n) {
/**
* @param {[number, number]} [domain]
* @param {number} [n]
* @returns {number[]}
*/
export default function calcThresholds(domain = [0, 1], n = 1) {
const breaks = [domain[0]];
const brk = (domain[1] - domain[0]) / n;
while (breaks[breaks.length - 1] < domain[1]) {
Expand Down
4 changes: 4 additions & 0 deletions src/_modules/cleanTitle.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @param {string} title
* @returns {string}
*/
export default function cleanTitle(title) {
const parts = title.split('/');
const nameParts = parts[parts.length - 1].split('.');
Expand Down
19 changes: 18 additions & 1 deletion src/_modules/constructReplLink.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@ import { csvParse } from 'd3-dsv';

import { compress_and_encode_text } from './createReplHash.js';

/**
* @typedef {{ title: string, contents: string }} CodeFile
* @typedef {{
* main: CodeFile,
* components: CodeFile[],
* componentModules: CodeFile[],
* modules: CodeFile[],
* componentComponents: CodeFile[],
* jsons: CodeFile[],
* csvs: CodeFile[]
* }} ExampleContent
*/

/**
* @param {string} pageName
* @param {ExampleContent} content
*/
export default async function constructReplLink(pageName, content) {
// TODO, clean up import paths
const pages = [content.main]
Expand All @@ -17,7 +34,7 @@ export default async function constructReplLink(pageName, content) {
const json = {
name: pageTitle.trim(),
files: pages.map(c => {
const filename = c.title.split('/').pop();
const filename = c.title.split('/').pop() ?? '';
const name = cleanName(filename);
return {
type: 'file',
Expand Down
9 changes: 7 additions & 2 deletions src/_modules/downloadBlob.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/**
* @param {BlobPart|Blob} blob
* @param {string} filename
* @param {boolean} [createBlob=false]
*/
export default function downloadBlob(blob, filename, createBlob = false) {
let myBlob;
if (createBlob === true) {
myBlob = new Blob([blob], { type: 'octet/stream' });
myBlob = new Blob([/** @type {BlobPart} */ (blob)], { type: 'octet/stream' });
} else {
myBlob = blob;
myBlob = /** @type {Blob} */ (blob);
}
const url = URL.createObjectURL(myBlob);
const link = document.createElement('a');
Expand Down
Loading
Loading