@tradecanvas/chart 1.80.0 → 1.81.0
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/dist/{LayoutSession-CX3eWUA1.js → LayoutSession-C4Lp1X6t.js} +2 -2
- package/dist/{LayoutSession-CX3eWUA1.js.map → LayoutSession-C4Lp1X6t.js.map} +1 -1
- package/dist/{LayoutSession-DFvb5ekw.cjs → LayoutSession-CeayqT91.cjs} +2 -2
- package/dist/{LayoutSession-DFvb5ekw.cjs.map → LayoutSession-CeayqT91.cjs.map} +1 -1
- package/dist/{WidgetSymbolSearch-BW7HxOMk.cjs → WidgetSymbolSearch-DeBxGj4a.cjs} +2 -2
- package/dist/{WidgetSymbolSearch-BW7HxOMk.cjs.map → WidgetSymbolSearch-DeBxGj4a.cjs.map} +1 -1
- package/dist/{WidgetSymbolSearch-CYYd9zoA.js → WidgetSymbolSearch-WOskcBJN.js} +24 -24
- package/dist/{WidgetSymbolSearch-CYYd9zoA.js.map → WidgetSymbolSearch-WOskcBJN.js.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/{symbolCatalog-DffhUQSJ.js → symbolCatalog-B_9kDAjE.js} +30 -27
- package/dist/symbolCatalog-B_9kDAjE.js.map +1 -0
- package/dist/symbolCatalog-CXqRu23x.cjs +2 -0
- package/dist/symbolCatalog-CXqRu23x.cjs.map +1 -0
- package/dist/widget/WidgetLoadingOverlay.d.ts.map +1 -1
- package/dist/widget/index.cjs +21 -61
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +1023 -1027
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/symbolCatalog.d.ts +2 -7
- package/dist/widget/symbolCatalog.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/symbolCatalog-CSbI2R5e.cjs +0 -2
- package/dist/symbolCatalog-CSbI2R5e.cjs.map +0 -1
- package/dist/symbolCatalog-DffhUQSJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as e, D as t, E as n, S as r, T as i, _ as a, a as o, b as s, c, g as l, h as u, i as ee, l as te, m as ne, n as re, o as ie, p as ae, r as oe, s as se, t as ce, u as le, v as ue, w as de, x as fe, y as pe } from "./LayoutSession-
|
|
1
|
+
import { C as e, D as t, E as n, S as r, T as i, _ as a, a as o, b as s, c, g as l, h as u, i as ee, l as te, m as ne, n as re, o as ie, p as ae, r as oe, s as se, t as ce, u as le, v as ue, w as de, x as fe, y as pe } from "./LayoutSession-C4Lp1X6t.js";
|
|
2
2
|
import { CHART_STYLE_KEYS as me, DARK_PRICE_LIMITS as he, DARK_TERMINAL as ge, DARK_THEME as _e, DARK_THEME as ve, DEFAULT_DRAWING_STYLE as ye, DEFAULT_FONT_FAMILY as be, DEFAULT_RECONNECT as xe, DEFAULT_SIGNAL_STYLE as Se, DEFAULT_STREAM_CONFIG as Ce, DEFAULT_TIMEFRAME_FAVORITES as we, DEFAULT_TRADE_ZONE_STYLE as Te, DEFAULT_TRADING_CONFIG as Ee, HNX_SESSIONS as De, HOSE_SESSIONS as Oe, KRX_SESSIONS as ke, KR_COLORS as Ae, LIGHT_PRICE_LIMITS as je, LIGHT_THEME as Me, LIGHT_THEME as Ne, MARKET_CRYPTO as Pe, MARKET_HNX as Fe, MARKET_HOSE as Ie, MARKET_HOSE_ETF as Le, MARKET_KRX as Re, MARKET_NXT as d, MARKET_NYSE as f, MARKET_UPBIT_KRW as p, MARKET_UPCOM as m, MARKET_VN30F as h, MS_TIME_THRESHOLD as ze, NXT_SESSIONS as Be, PRICE_SOURCES as Ve, SANS_FONT_FAMILY as He, TC_PALETTE as Ue, TC_SERIES_COLORS as We, TIMEFRAMES_CRYPTO as Ge, TIMEFRAMES_FOREX as Ke, TIMEFRAMES_STOCK as qe, UPCOM_SESSIONS as Je, VN30F_SESSIONS as Ye, VN_COLORS as Xe, VOLUME_ALPHA as Ze, barTimeUnit as Qe, barsAreDaily as $e, computePriceLimits as et, contrastRatio as tt, createMarketTheme as nt, createVNTheme as rt, formatFraction as it, formatNumber as at, formatVND as ot, formatVolumeLoc as st, fractionTick as ct, getCurrentSession as lt, getLocale as ut, indicatorSource as dt, inkOn as ft, isPriceSource as pt, isTimeFrame as mt, isValidTimeZone as ht, marketStatus as gt, normalizeBar as _t, normalizeBarTime as vt, offsetAt as yt, parseIndicatorSource as bt, parseTimeframe as xt, pickBaseTimeframe as St, priceFormatterFor as Ct, priceStepAt as wt, rankSymbols as Tt, readNews as Et, readQuote as Dt, readableOn as Ot, registerLocale as kt, resampleBars as At, roundToPriceStep as jt, scaleMarketPrices as Mt, setLocale as Nt, sourcePrice as Pt, stepDecimals as Ft, symbolTimeZone as It, t as Lt, tickBarCount as Rt, tickerOf as zt, timeframeBucketStart as Bt, timeframeBucketStart as Vt, timeframeToMs as Ht, usesKoreanUnits as Ut, vn30fContracts as Wt, vn30fLastTradingDay as Gt, volumeColor as Kt, wallToUtc as qt, zoneOffsetMinutes as Jt } from "@tradecanvas/commons";
|
|
3
3
|
import { AlertManager as Yt, Animator as Xt, BarCountdown as Zt, BaseFinanceChart as g, BinanceAdapter as Qt, BybitAdapter as $t, CANDLE_PATTERNS as en, ChartLegend as tn, ChartStateManager as nn, CoinbaseAdapter as rn, CompareRenderer as an, CrosshairTooltip as on, CurrentPriceLine as sn, DEFAULT_LEGEND_CONFIG as cn, DEFAULT_MAX_WEBGL_CHARTS as ln, DEFAULT_SESSION_HOURS as un, DataExporter as dn, DrawingBase as fn, Easing as pn, FinanceCrosshair as _, GROUP_HEADER as mn, INDICATOR_CATEGORIES as hn, IndicatorBase as gn, IndicatorValueMap as _n, KEPT_BUCKETS as vn, KeyboardHandler as yn, KrakenAdapter as bn, MAX_ALERT_BARS as xn, MIN_ALERT_BARS as Sn, ManualFeed as Cn, MockAdapter as wn, PaperExecutionAdapter as Tn, PollingAdapter as En, RANGE_PRESETS as Dn, ReconnectManager as On, ReplayController as kn, ReplayManager as An, ResamplingAdapter as jn, ReshapeMemo as Mn, Screenshot as Nn, SessionBreaks as Pn, SessionShading as Fn, SignalMarkerManager as In, StreamManager as Ln, TickAggregator as Rn, TickBarAdapter as zn, TickBarBuilder as Bn, TradeZoneManager as Vn, UndoRedoManager as Hn, UpbitAdapter as v, VolumeRenderer as Un, Watermark as Wn, WebSocketAdapter as Gn, adapterFromFeed as Kn, axisTimes as qn, barIndexToTime as Jn, barIndexToX as Yn, barIndexToX as y, canvasMeasure as Xn, computeBarLayout as Zn, computeCalendarLayout as Qn, computeCounterClockLayout as $n, computeDonutLayout as er, computeHistogramLayout as tr, computeMatrixLayout as nr, computeScatterLayout as rr, correlationMatrix as ir, counterClockPhase as ar, counterClockPhase as or, counterClockPoints as sr, counterClockPoints as cr, describeInputs as lr, detectCandlePatterns as ur, feedFromAdapter as dr, formatTooltipTime as fr, histogramBins as pr, hitBar as b, hitDay as x, hitMatrixCell as S, hitSlice as C, indicatorCategory as mr, isDataFeed as hr, isDataFeed as gr, isPriceLevelAlert as _r, layoutGroupedTreemap as vr, layoutSquarifiedTreemap as yr, layoutUniformGrid as br, lttbDownsample as xr, lttbVisibleIndices as Sr, nearestCounterClockPoint as w, nearestPoint as T, niceScale as Cr, priceToY as wr, priceToYMapper as Tr, priceToYMapper as Er, rangePresetStart as Dr, renderBarChart as Or, renderCalendar as kr, renderCounterClock as Ar, renderDepthChart as jr, renderDonut as Mr, renderEquityCurve as Nr, renderGauge as Pr, renderHeatmap as Fr, renderHistogram as Ir, renderMatrix as Lr, renderScatter as Rr, renderSparkline as zr, renderWaterfall as Br, servesTimeframe as Vr, setMaxWebGLCharts as Hr, shownCount as Ur, timeToX as Wr, timestampToBarIndex as Gr, timestampToBarIndex as Kr, toHeikinAshi as qr, toKagi as Jr, toLineBreak as Yr, toPointAndFigure as Xr, toRangeBars as Zr, toRenko as Qr, withResampling as $r, withTickBars as ei, xToBarIndex as ti, xToBarIndex as E, xToTime as ni, yToPrice as ri, yToPrice as ii } from "@tradecanvas/core";
|
|
4
4
|
//#region src/frameworks/syncIndicators.ts
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { MAX_SYMBOL_LENGTH as e } from "@tradecanvas/commons";
|
|
1
2
|
//#region src/widget/escapeHtml.ts
|
|
2
|
-
function
|
|
3
|
+
function t(e) {
|
|
3
4
|
return e.replace(/[&<>"']/g, (e) => ({
|
|
4
5
|
"&": "&",
|
|
5
6
|
"<": "<",
|
|
@@ -8,22 +9,24 @@ function e(e) {
|
|
|
8
9
|
"'": "'"
|
|
9
10
|
})[e]);
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/widget/symbolCatalog.ts
|
|
14
|
+
var n = 2048, r = 65536, i = /^data:image\/(png|jpeg|gif|webp|avif|svg\+xml)[;,]/i, a = new Set([
|
|
12
15
|
"https:",
|
|
13
16
|
"http:",
|
|
14
17
|
"blob:"
|
|
15
|
-
]),
|
|
18
|
+
]), o = new Set([
|
|
16
19
|
"description",
|
|
17
20
|
"exchange",
|
|
18
21
|
"type",
|
|
19
22
|
"logo"
|
|
20
23
|
]);
|
|
21
|
-
function
|
|
22
|
-
if (typeof
|
|
23
|
-
let
|
|
24
|
-
return
|
|
24
|
+
function s(t) {
|
|
25
|
+
if (typeof t != "string") return null;
|
|
26
|
+
let n = t.trim();
|
|
27
|
+
return n && n.length <= e ? n : null;
|
|
25
28
|
}
|
|
26
|
-
function
|
|
29
|
+
function c(e) {
|
|
27
30
|
let t = [], n = /* @__PURE__ */ new Map();
|
|
28
31
|
if (!Array.isArray(e)) return {
|
|
29
32
|
names: t,
|
|
@@ -31,30 +34,30 @@ function s(e) {
|
|
|
31
34
|
};
|
|
32
35
|
let r = /* @__PURE__ */ new Set();
|
|
33
36
|
for (let i of e) {
|
|
34
|
-
let e = typeof i == "object" && !!i, a =
|
|
35
|
-
!a || r.has(a) || (r.add(a), t.push(a), e && n.set(a,
|
|
37
|
+
let e = typeof i == "object" && !!i, a = s(e ? i.symbol : i);
|
|
38
|
+
!a || r.has(a) || (r.add(a), t.push(a), e && n.set(a, l(i, a)));
|
|
36
39
|
}
|
|
37
40
|
return {
|
|
38
41
|
names: t,
|
|
39
42
|
info: n
|
|
40
43
|
};
|
|
41
44
|
}
|
|
42
|
-
function
|
|
45
|
+
function l(e, t) {
|
|
43
46
|
return {
|
|
44
|
-
...Object.fromEntries(Object.entries(e).filter(([e, t]) => e !== "__proto__" && (!
|
|
47
|
+
...Object.fromEntries(Object.entries(e).filter(([e, t]) => e !== "__proto__" && (!o.has(e) || typeof t == "string" && t.trim() !== ""))),
|
|
45
48
|
symbol: t
|
|
46
49
|
};
|
|
47
50
|
}
|
|
48
|
-
function
|
|
49
|
-
return Array.isArray(e) ? e.filter((e) => typeof e == "object" && !!e && typeof e.symbol == "string" && e.symbol !== "").map((e) =>
|
|
51
|
+
function u(e) {
|
|
52
|
+
return Array.isArray(e) ? e.filter((e) => typeof e == "object" && !!e && typeof e.symbol == "string" && e.symbol !== "").map((e) => l(e, e.symbol)) : [];
|
|
50
53
|
}
|
|
51
|
-
function
|
|
54
|
+
function d(e, t) {
|
|
52
55
|
if (!t) return e;
|
|
53
56
|
if (!e) return t;
|
|
54
57
|
let n = Object.entries(t).filter(([, e]) => e != null);
|
|
55
58
|
return Object.fromEntries([...Object.entries(e), ...n]);
|
|
56
59
|
}
|
|
57
|
-
function
|
|
60
|
+
function f(e) {
|
|
58
61
|
let t = e.lastIndexOf(":");
|
|
59
62
|
return t <= 0 || t === e.length - 1 ? {
|
|
60
63
|
venue: "",
|
|
@@ -64,27 +67,27 @@ function d(e) {
|
|
|
64
67
|
ticker: e.slice(t + 1)
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
|
-
var
|
|
68
|
-
function
|
|
69
|
-
return !t || typeof t.symbol != "string" ? null : t.symbol.toUpperCase() === e.toUpperCase() || t.symbol.includes(":") !== e.includes(":") &&
|
|
70
|
+
var p = (e) => f(e).ticker.toUpperCase();
|
|
71
|
+
function m(e, t) {
|
|
72
|
+
return !t || typeof t.symbol != "string" ? null : t.symbol.toUpperCase() === e.toUpperCase() || t.symbol.includes(":") !== e.includes(":") && p(t.symbol) === p(e) ? t : null;
|
|
70
73
|
}
|
|
71
|
-
function
|
|
74
|
+
function h(e) {
|
|
72
75
|
return [e?.description, e?.exchange].filter(Boolean).join(" · ") || null;
|
|
73
76
|
}
|
|
74
|
-
var
|
|
75
|
-
function
|
|
77
|
+
var g = () => typeof document > "u" ? void 0 : document.baseURI;
|
|
78
|
+
function _(e, t = g()) {
|
|
76
79
|
if (typeof e != "string") return null;
|
|
77
80
|
let o = e.trim();
|
|
78
|
-
if (!o || o.length >
|
|
81
|
+
if (!o || o.length > r) return null;
|
|
79
82
|
let s;
|
|
80
83
|
try {
|
|
81
|
-
s = new URL(o,
|
|
84
|
+
s = new URL(o, t);
|
|
82
85
|
} catch {
|
|
83
86
|
return null;
|
|
84
87
|
}
|
|
85
|
-
return s.protocol === "data:" ?
|
|
88
|
+
return s.protocol === "data:" ? i.test(s.href) && s.href.length <= r ? s.href : null : a.has(s.protocol) && s.href.length <= n ? s.href : null;
|
|
86
89
|
}
|
|
87
90
|
//#endregion
|
|
88
|
-
export {
|
|
91
|
+
export { _ as a, u as c, t as d, l as i, f as l, m as n, d as o, s as r, c as s, e as t, h as u };
|
|
89
92
|
|
|
90
|
-
//# sourceMappingURL=symbolCatalog-
|
|
93
|
+
//# sourceMappingURL=symbolCatalog-B_9kDAjE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbolCatalog-B_9kDAjE.js","names":[],"sources":["../src/widget/escapeHtml.ts","../src/widget/symbolCatalog.ts"],"sourcesContent":["/** Text made safe to put in HTML markup, attribute values included. */\nexport function escapeHtml(text: string): string {\n return text.replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c]!);\n}\n","import { MAX_SYMBOL_LENGTH, type SymbolInfo } from '@tradecanvas/commons';\n\nexport { MAX_SYMBOL_LENGTH };\n/** The longest logo address taken, and the longest image written in a `data:` one. */\nconst MAX_LOGO_URL = 2048;\nconst MAX_LOGO_DATA = 65_536;\n/** The images a `data:` logo may be; a page written in `data:` is none of them. */\nconst DATA_IMAGE = /^data:image\\/(png|jpeg|gif|webp|avif|svg\\+xml)[;,]/i;\nconst LOGO_PROTOCOLS = new Set(['https:', 'http:', 'blob:']);\n/** The fields a row writes as words, or loads (the logo): anything but text there says nothing. */\nconst TEXT_FIELDS: ReadonlySet<string> = new Set(['description', 'exchange', 'type', 'logo']);\n\n/** A ticker trimmed, or null when it isn't one a list can keep. */\nexport function cleanSymbol(v: unknown): string | null {\n if (typeof v !== 'string') return null;\n const symbol = v.trim();\n return symbol && symbol.length <= MAX_SYMBOL_LENGTH ? symbol : null;\n}\n\n/** The symbols on offer: their tickers in order, and the info given with some. */\nexport interface SymbolCatalog {\n names: string[];\n info: Map<string, SymbolInfo>;\n}\n\n/**\n * Symbols from untrusted input (a host's `symbols`, plain JavaScript): a\n * ticker, or a SymbolInfo with one. Tickers are cleaned as a watchlist cleans\n * them, so both key a symbol alike; a repeat keeps the first; anything else is\n * skipped, and anything but a list is no symbols.\n */\nexport function readSymbolCatalog(raw: unknown): SymbolCatalog {\n const names: string[] = [];\n const info = new Map<string, SymbolInfo>();\n if (!Array.isArray(raw)) return { names, info };\n const seen = new Set<string>();\n for (const entry of raw) {\n const isInfo = typeof entry === 'object' && entry !== null;\n const symbol = cleanSymbol(isInfo ? (entry as { symbol?: unknown }).symbol : entry);\n if (!symbol || seen.has(symbol)) continue;\n seen.add(symbol);\n names.push(symbol);\n if (isInfo) info.set(symbol, cleanSymbolInfo(entry, symbol));\n }\n return { names, info };\n}\n\n/**\n * A copy of `info` named `symbol`, its words kept only where they are text:\n * a JSON feed's numeric exchange code, a null or a blank says nothing, so it\n * neither shows nor erases what is known. A \"__proto__\" key, which JSON.parse\n * keeps as a field, is dropped: copied onto another object by assignment, it\n * would hand that object fields no one cleaned.\n */\nexport function cleanSymbolInfo(info: object, symbol: string): SymbolInfo {\n const isWords = ([key, value]: [string, unknown]) =>\n key !== '__proto__' && (!TEXT_FIELDS.has(key) || (typeof value === 'string' && value.trim() !== ''));\n return { ...Object.fromEntries(Object.entries(info).filter(isWords)), symbol } as SymbolInfo;\n}\n\n/**\n * A feed's search results, from untrusted input: those that name a symbol,\n * in order, their words cleaned as the symbols given are; anything but a list\n * is none.\n */\nexport function readSymbolResults(found: unknown): SymbolInfo[] {\n if (!Array.isArray(found)) return [];\n const named = (info: unknown): info is SymbolInfo =>\n typeof info === 'object' && info !== null && typeof (info as { symbol?: unknown }).symbol === 'string' && (info as SymbolInfo).symbol !== '';\n return found.filter(named).map((info) => cleanSymbolInfo(info, info.symbol));\n}\n\n/**\n * `over`'s fields where it has them, `base`'s for the rest: a field left\n * undefined or null (as a JSON feed writes one it has no value for) never\n * erases one. Neither is changed.\n */\nexport function mergeSymbolInfo(base: SymbolInfo | undefined, over: SymbolInfo | null | undefined): SymbolInfo | undefined {\n if (!over) return base;\n if (!base) return over;\n // Defined, not assigned: a \"__proto__\" field is copied as a field and never swaps the copy's prototype.\n const given = Object.entries(over).filter(([, value]) => value !== undefined && value !== null);\n return Object.fromEntries([...Object.entries(base), ...given]) as unknown as SymbolInfo;\n}\n\n/**\n * A symbol's venue, up to its last colon (\"BINANCE:\"), and the ticker after\n * it (\"BTCUSDT\"). No venue when there is no colon, or one at either end: the\n * ticker would be left with nothing.\n */\nexport function splitVenue(symbol: string): { venue: string; ticker: string } {\n const at = symbol.lastIndexOf(':');\n if (at <= 0 || at === symbol.length - 1) return { venue: '', ticker: symbol };\n return { venue: symbol.slice(0, at + 1), ticker: symbol.slice(at + 1) };\n}\n\n/** A ticker without its venue (\"KBS:VCB\" is VCB), in upper case. */\nconst bareTicker = (symbol: string): string => splitVenue(symbol).ticker.toUpperCase();\n\n/**\n * What the chart knows (`getSymbolInfo()`), when it is of `symbol`: in any\n * case, or with a venue before one of the two and not the other. Null when it\n * is still another symbol's, as it stays with no feed to replace it.\n */\nexport function chartInfoFor(symbol: string, info: SymbolInfo | null | undefined): SymbolInfo | null {\n if (!info || typeof info.symbol !== 'string') return null;\n if (info.symbol.toUpperCase() === symbol.toUpperCase()) return info;\n const oneHasVenue = info.symbol.includes(':') !== symbol.includes(':');\n return oneHasVenue && bareTicker(info.symbol) === bareTicker(symbol) ? info : null;\n}\n\n/** A symbol's name and exchange on a line, for a tooltip (\"Vinamilk · HOSE\"); null when neither is known. */\nexport function symbolTitle(info: SymbolInfo | null | undefined): string | null {\n return [info?.description, info?.exchange].filter(Boolean).join(' · ') || null;\n}\n\nconst pageBase = (): string | undefined => (typeof document === 'undefined' ? undefined : document.baseURI);\n\n/**\n * The address to load a logo from, or null for one it must not load. It is\n * only ever an image's `src`, so markup in it is a path that finds nothing;\n * the scheme still has to be one for images, which keeps out `javascript:`\n * and pages written in `data:`.\n */\nexport function logoSrc(raw: unknown, base: string | undefined = pageBase()): string | null {\n if (typeof raw !== 'string') return null;\n const text = raw.trim();\n // One longer than any taken is refused before it is parsed: a row's badge is made again on every keystroke.\n if (!text || text.length > MAX_LOGO_DATA) return null;\n let url: URL;\n try {\n url = new URL(text, base);\n } catch {\n return null;\n }\n if (url.protocol === 'data:') return DATA_IMAGE.test(url.href) && url.href.length <= MAX_LOGO_DATA ? url.href : null;\n return LOGO_PROTOCOLS.has(url.protocol) && url.href.length <= MAX_LOGO_URL ? url.href : null;\n}\n"],"mappings":";;AACA,SAAgB,EAAW,GAAsB;AAC/C,QAAO,EAAK,QAAQ,aAAa,OAAO;EAAE,KAAK;EAAS,KAAK;EAAQ,KAAK;EAAQ,MAAK;EAAU,KAAK;EAAS,EAAE,GAAI;;;;ACEvH,IAAM,IAAe,MACf,IAAgB,OAEhB,IAAa,uDACb,IAAiB,IAAI,IAAI;CAAC;CAAU;CAAS;CAAQ,CAAC,EAEtD,IAAmC,IAAI,IAAI;CAAC;CAAe;CAAY;CAAQ;CAAO,CAAC;AAG7F,SAAgB,EAAY,GAA2B;AACrD,KAAI,OAAO,KAAM,SAAU,QAAO;CAClC,IAAM,IAAS,EAAE,MAAM;AACvB,QAAO,KAAU,EAAO,UAAU,IAAoB,IAAS;;AAejE,SAAgB,EAAkB,GAA6B;CAC7D,IAAM,IAAkB,EAAE,EACpB,oBAAO,IAAI,KAAyB;AAC1C,KAAI,CAAC,MAAM,QAAQ,EAAI,CAAE,QAAO;EAAE;EAAO;EAAM;CAC/C,IAAM,oBAAO,IAAI,KAAa;AAC9B,MAAK,IAAM,KAAS,GAAK;EACvB,IAAM,IAAS,OAAO,KAAU,cAAY,GACtC,IAAS,EAAY,IAAU,EAA+B,SAAS,EAAM;AAC/E,GAAC,KAAU,EAAK,IAAI,EAAO,KAC/B,EAAK,IAAI,EAAO,EAChB,EAAM,KAAK,EAAO,EACd,KAAQ,EAAK,IAAI,GAAQ,EAAgB,GAAO,EAAO,CAAC;;AAE9D,QAAO;EAAE;EAAO;EAAM;;AAUxB,SAAgB,EAAgB,GAAc,GAA4B;AAGxE,QAAO;EAAE,GAAG,OAAO,YAAY,OAAO,QAAQ,EAAK,CAAC,QAFnC,CAAC,GAAK,OACrB,MAAQ,gBAAgB,CAAC,EAAY,IAAI,EAAI,IAAK,OAAO,KAAU,YAAY,EAAM,MAAM,KAAK,IAC/B,CAAC;EAAE;EAAQ;;AAQhF,SAAgB,EAAkB,GAA8B;AAI9D,QAHK,MAAM,QAAQ,EAAM,GAGlB,EAAM,QAFE,MACb,OAAO,KAAS,cAAY,KAAiB,OAAQ,EAA8B,UAAW,YAAa,EAAoB,WAAW,GAClH,CAAC,KAAK,MAAS,EAAgB,GAAM,EAAK,OAAO,CAAC,GAH1C,EAAE;;AAWtC,SAAgB,EAAgB,GAA8B,GAA6D;AACzH,KAAI,CAAC,EAAM,QAAO;AAClB,KAAI,CAAC,EAAM,QAAO;CAElB,IAAM,IAAQ,OAAO,QAAQ,EAAK,CAAC,QAAQ,GAAG,OAAW,KAAiC,KAAK;AAC/F,QAAO,OAAO,YAAY,CAAC,GAAG,OAAO,QAAQ,EAAK,EAAE,GAAG,EAAM,CAAC;;AAQhE,SAAgB,EAAW,GAAmD;CAC5E,IAAM,IAAK,EAAO,YAAY,IAAI;AAElC,QADI,KAAM,KAAK,MAAO,EAAO,SAAS,IAAU;EAAE,OAAO;EAAI,QAAQ;EAAQ,GACtE;EAAE,OAAO,EAAO,MAAM,GAAG,IAAK,EAAE;EAAE,QAAQ,EAAO,MAAM,IAAK,EAAE;EAAE;;AAIzE,IAAM,KAAc,MAA2B,EAAW,EAAO,CAAC,OAAO,aAAa;AAOtF,SAAgB,EAAa,GAAgB,GAAwD;AAInG,QAHI,CAAC,KAAQ,OAAO,EAAK,UAAW,WAAiB,OACjD,EAAK,OAAO,aAAa,KAAK,EAAO,aAAa,IAClC,EAAK,OAAO,SAAS,IAAI,KAAK,EAAO,SAAS,IAAI,IAChD,EAAW,EAAK,OAAO,KAAK,EAAW,EAAO,GAFL,IAEe;;AAIhF,SAAgB,EAAY,GAAoD;AAC9E,QAAO,CAAC,GAAM,aAAa,GAAM,SAAS,CAAC,OAAO,QAAQ,CAAC,KAAK,MAAM,IAAI;;AAG5E,IAAM,UAAsC,OAAO,WAAa,MAAc,KAAA,IAAY,SAAS;AAQnG,SAAgB,EAAQ,GAAc,IAA2B,GAAU,EAAiB;AAC1F,KAAI,OAAO,KAAQ,SAAU,QAAO;CACpC,IAAM,IAAO,EAAI,MAAM;AAEvB,KAAI,CAAC,KAAQ,EAAK,SAAS,EAAe,QAAO;CACjD,IAAI;AACJ,KAAI;AACF,MAAM,IAAI,IAAI,GAAM,EAAK;SACnB;AACN,SAAO;;AAGT,QADI,EAAI,aAAa,UAAgB,EAAW,KAAK,EAAI,KAAK,IAAI,EAAI,KAAK,UAAU,IAAgB,EAAI,OAAO,OACzG,EAAe,IAAI,EAAI,SAAS,IAAI,EAAI,KAAK,UAAU,IAAe,EAAI,OAAO"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require(`@tradecanvas/commons`);function t(e){return e.replace(/[&<>"']/g,e=>({"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`})[e])}var n=2048,r=65536,i=/^data:image\/(png|jpeg|gif|webp|avif|svg\+xml)[;,]/i,a=new Set([`https:`,`http:`,`blob:`]),o=new Set([`description`,`exchange`,`type`,`logo`]);function s(t){if(typeof t!=`string`)return null;let n=t.trim();return n&&n.length<=e.MAX_SYMBOL_LENGTH?n:null}function c(e){let t=[],n=new Map;if(!Array.isArray(e))return{names:t,info:n};let r=new Set;for(let i of e){let e=typeof i==`object`&&!!i,a=s(e?i.symbol:i);!a||r.has(a)||(r.add(a),t.push(a),e&&n.set(a,l(i,a)))}return{names:t,info:n}}function l(e,t){return{...Object.fromEntries(Object.entries(e).filter(([e,t])=>e!==`__proto__`&&(!o.has(e)||typeof t==`string`&&t.trim()!==``))),symbol:t}}function u(e){return Array.isArray(e)?e.filter(e=>typeof e==`object`&&!!e&&typeof e.symbol==`string`&&e.symbol!==``).map(e=>l(e,e.symbol)):[]}function d(e,t){if(!t)return e;if(!e)return t;let n=Object.entries(t).filter(([,e])=>e!=null);return Object.fromEntries([...Object.entries(e),...n])}function f(e){let t=e.lastIndexOf(`:`);return t<=0||t===e.length-1?{venue:``,ticker:e}:{venue:e.slice(0,t+1),ticker:e.slice(t+1)}}var p=e=>f(e).ticker.toUpperCase();function m(e,t){return!t||typeof t.symbol!=`string`?null:t.symbol.toUpperCase()===e.toUpperCase()||t.symbol.includes(`:`)!==e.includes(`:`)&&p(t.symbol)===p(e)?t:null}function h(e){return[e?.description,e?.exchange].filter(Boolean).join(` · `)||null}var g=()=>typeof document>`u`?void 0:document.baseURI;function _(e,t=g()){if(typeof e!=`string`)return null;let o=e.trim();if(!o||o.length>r)return null;let s;try{s=new URL(o,t)}catch{return null}return s.protocol===`data:`?i.test(s.href)&&s.href.length<=r?s.href:null:a.has(s.protocol)&&s.href.length<=n?s.href:null}Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return l}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return t}});
|
|
2
|
+
//# sourceMappingURL=symbolCatalog-CXqRu23x.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbolCatalog-CXqRu23x.cjs","names":[],"sources":["../src/widget/escapeHtml.ts","../src/widget/symbolCatalog.ts"],"sourcesContent":["/** Text made safe to put in HTML markup, attribute values included. */\nexport function escapeHtml(text: string): string {\n return text.replace(/[&<>\"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[c]!);\n}\n","import { MAX_SYMBOL_LENGTH, type SymbolInfo } from '@tradecanvas/commons';\n\nexport { MAX_SYMBOL_LENGTH };\n/** The longest logo address taken, and the longest image written in a `data:` one. */\nconst MAX_LOGO_URL = 2048;\nconst MAX_LOGO_DATA = 65_536;\n/** The images a `data:` logo may be; a page written in `data:` is none of them. */\nconst DATA_IMAGE = /^data:image\\/(png|jpeg|gif|webp|avif|svg\\+xml)[;,]/i;\nconst LOGO_PROTOCOLS = new Set(['https:', 'http:', 'blob:']);\n/** The fields a row writes as words, or loads (the logo): anything but text there says nothing. */\nconst TEXT_FIELDS: ReadonlySet<string> = new Set(['description', 'exchange', 'type', 'logo']);\n\n/** A ticker trimmed, or null when it isn't one a list can keep. */\nexport function cleanSymbol(v: unknown): string | null {\n if (typeof v !== 'string') return null;\n const symbol = v.trim();\n return symbol && symbol.length <= MAX_SYMBOL_LENGTH ? symbol : null;\n}\n\n/** The symbols on offer: their tickers in order, and the info given with some. */\nexport interface SymbolCatalog {\n names: string[];\n info: Map<string, SymbolInfo>;\n}\n\n/**\n * Symbols from untrusted input (a host's `symbols`, plain JavaScript): a\n * ticker, or a SymbolInfo with one. Tickers are cleaned as a watchlist cleans\n * them, so both key a symbol alike; a repeat keeps the first; anything else is\n * skipped, and anything but a list is no symbols.\n */\nexport function readSymbolCatalog(raw: unknown): SymbolCatalog {\n const names: string[] = [];\n const info = new Map<string, SymbolInfo>();\n if (!Array.isArray(raw)) return { names, info };\n const seen = new Set<string>();\n for (const entry of raw) {\n const isInfo = typeof entry === 'object' && entry !== null;\n const symbol = cleanSymbol(isInfo ? (entry as { symbol?: unknown }).symbol : entry);\n if (!symbol || seen.has(symbol)) continue;\n seen.add(symbol);\n names.push(symbol);\n if (isInfo) info.set(symbol, cleanSymbolInfo(entry, symbol));\n }\n return { names, info };\n}\n\n/**\n * A copy of `info` named `symbol`, its words kept only where they are text:\n * a JSON feed's numeric exchange code, a null or a blank says nothing, so it\n * neither shows nor erases what is known. A \"__proto__\" key, which JSON.parse\n * keeps as a field, is dropped: copied onto another object by assignment, it\n * would hand that object fields no one cleaned.\n */\nexport function cleanSymbolInfo(info: object, symbol: string): SymbolInfo {\n const isWords = ([key, value]: [string, unknown]) =>\n key !== '__proto__' && (!TEXT_FIELDS.has(key) || (typeof value === 'string' && value.trim() !== ''));\n return { ...Object.fromEntries(Object.entries(info).filter(isWords)), symbol } as SymbolInfo;\n}\n\n/**\n * A feed's search results, from untrusted input: those that name a symbol,\n * in order, their words cleaned as the symbols given are; anything but a list\n * is none.\n */\nexport function readSymbolResults(found: unknown): SymbolInfo[] {\n if (!Array.isArray(found)) return [];\n const named = (info: unknown): info is SymbolInfo =>\n typeof info === 'object' && info !== null && typeof (info as { symbol?: unknown }).symbol === 'string' && (info as SymbolInfo).symbol !== '';\n return found.filter(named).map((info) => cleanSymbolInfo(info, info.symbol));\n}\n\n/**\n * `over`'s fields where it has them, `base`'s for the rest: a field left\n * undefined or null (as a JSON feed writes one it has no value for) never\n * erases one. Neither is changed.\n */\nexport function mergeSymbolInfo(base: SymbolInfo | undefined, over: SymbolInfo | null | undefined): SymbolInfo | undefined {\n if (!over) return base;\n if (!base) return over;\n // Defined, not assigned: a \"__proto__\" field is copied as a field and never swaps the copy's prototype.\n const given = Object.entries(over).filter(([, value]) => value !== undefined && value !== null);\n return Object.fromEntries([...Object.entries(base), ...given]) as unknown as SymbolInfo;\n}\n\n/**\n * A symbol's venue, up to its last colon (\"BINANCE:\"), and the ticker after\n * it (\"BTCUSDT\"). No venue when there is no colon, or one at either end: the\n * ticker would be left with nothing.\n */\nexport function splitVenue(symbol: string): { venue: string; ticker: string } {\n const at = symbol.lastIndexOf(':');\n if (at <= 0 || at === symbol.length - 1) return { venue: '', ticker: symbol };\n return { venue: symbol.slice(0, at + 1), ticker: symbol.slice(at + 1) };\n}\n\n/** A ticker without its venue (\"KBS:VCB\" is VCB), in upper case. */\nconst bareTicker = (symbol: string): string => splitVenue(symbol).ticker.toUpperCase();\n\n/**\n * What the chart knows (`getSymbolInfo()`), when it is of `symbol`: in any\n * case, or with a venue before one of the two and not the other. Null when it\n * is still another symbol's, as it stays with no feed to replace it.\n */\nexport function chartInfoFor(symbol: string, info: SymbolInfo | null | undefined): SymbolInfo | null {\n if (!info || typeof info.symbol !== 'string') return null;\n if (info.symbol.toUpperCase() === symbol.toUpperCase()) return info;\n const oneHasVenue = info.symbol.includes(':') !== symbol.includes(':');\n return oneHasVenue && bareTicker(info.symbol) === bareTicker(symbol) ? info : null;\n}\n\n/** A symbol's name and exchange on a line, for a tooltip (\"Vinamilk · HOSE\"); null when neither is known. */\nexport function symbolTitle(info: SymbolInfo | null | undefined): string | null {\n return [info?.description, info?.exchange].filter(Boolean).join(' · ') || null;\n}\n\nconst pageBase = (): string | undefined => (typeof document === 'undefined' ? undefined : document.baseURI);\n\n/**\n * The address to load a logo from, or null for one it must not load. It is\n * only ever an image's `src`, so markup in it is a path that finds nothing;\n * the scheme still has to be one for images, which keeps out `javascript:`\n * and pages written in `data:`.\n */\nexport function logoSrc(raw: unknown, base: string | undefined = pageBase()): string | null {\n if (typeof raw !== 'string') return null;\n const text = raw.trim();\n // One longer than any taken is refused before it is parsed: a row's badge is made again on every keystroke.\n if (!text || text.length > MAX_LOGO_DATA) return null;\n let url: URL;\n try {\n url = new URL(text, base);\n } catch {\n return null;\n }\n if (url.protocol === 'data:') return DATA_IMAGE.test(url.href) && url.href.length <= MAX_LOGO_DATA ? url.href : null;\n return LOGO_PROTOCOLS.has(url.protocol) && url.href.length <= MAX_LOGO_URL ? url.href : null;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetLoadingOverlay.d.ts","sourceRoot":"","sources":["../../src/widget/WidgetLoadingOverlay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAkBzC;;;;;;;;;;GAUG;AACH,qBAAa,oBAAoB;IAOE,OAAO,CAAC,QAAQ,CAAC,WAAW;IAN7D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,KAAK,CAA4C;gBAE7C,MAAM,EAAE,WAAW,EAAmB,WAAW,EAAE,MAAM;
|
|
1
|
+
{"version":3,"file":"WidgetLoadingOverlay.d.ts","sourceRoot":"","sources":["../../src/widget/WidgetLoadingOverlay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAkBzC;;;;;;;;;;GAUG;AACH,qBAAa,oBAAoB;IAOE,OAAO,CAAC,QAAQ,CAAC,WAAW;IAN7D,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,SAAS,CAA8C;IAE/D,OAAO,CAAC,KAAK,CAA4C;gBAE7C,MAAM,EAAE,WAAW,EAAmB,WAAW,EAAE,MAAM;IAgCrE;;;OAGG;IACH,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,UAAQ,GAAG,IAAI;IAgBnD,8EAA8E;IAC9E,GAAG,IAAI,IAAI;IAMX,wEAAwE;IACxE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS3B,8EAA8E;IAC9E,QAAQ,IAAI,OAAO;IAInB,iEAAiE;IACjE,SAAS,IAAI,OAAO;IAIpB,uDAAuD;IACvD,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,UAAU;CAMnB"}
|