@es-joy/jsoe 0.26.1 → 0.28.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/.gitignore +10 -0
- package/.npmignore +9 -0
- package/CHANGES.md +76 -0
- package/README.md +6 -4
- package/badges/coverage-badge.svg +1 -1
- package/badges/tests-badge.svg +1 -0
- package/dist/formats/schema.d.ts +11 -0
- package/dist/formats/schema.d.ts.map +1 -1
- package/dist/formats/structuredCloning.d.ts.map +1 -1
- package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
- package/dist/fundamentalTypes/stringType.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/typeChoices.d.ts +32 -2
- package/dist/typeChoices.d.ts.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/rawTypesonEditor.d.ts +110 -0
- package/dist/utils/rawTypesonEditor.d.ts.map +1 -0
- package/dist/vendor-imports.d.ts +4 -0
- package/docs/proposals/raw-typeson-edit-view.md +575 -0
- package/eslint.config.js +36 -27
- package/mmr.json +6 -0
- package/package.json +22 -12
- package/pnpm-workspace.yaml +4 -2
- package/src/formats/schema.js +38 -7
- package/src/formats/structuredCloning.js +24 -17
- package/src/fundamentalTypes/arrayType.js +135 -7
- package/src/fundamentalTypes/stringType.js +5 -0
- package/src/jsoe.css +12 -0
- package/src/typeChoices.js +39 -8
- package/src/types.js +20 -2
- package/src/utils/rawTypesonEditor.js +669 -0
- package/src/vendor-imports.js +12 -0
- package/tsconfig.json +1 -1
- package/typings/json-6.d.ts +12 -0
- package/vendor/@codemirror/autocomplete/dist/index.js +2125 -0
- package/vendor/@codemirror/commands/dist/index.js +1826 -0
- package/vendor/@codemirror/lang-javascript/dist/index.js +513 -0
- package/vendor/@codemirror/language/dist/index.js +2693 -0
- package/vendor/@codemirror/lint/dist/index.js +956 -0
- package/vendor/@codemirror/search/dist/index.js +1238 -0
- package/vendor/@codemirror/state/dist/index.js +3947 -0
- package/vendor/@codemirror/view/dist/index.js +11867 -0
- package/vendor/@lezer/common/dist/index.js +2202 -0
- package/vendor/@lezer/highlight/dist/index.js +927 -0
- package/vendor/@lezer/javascript/dist/index.js +192 -0
- package/vendor/@lezer/lr/dist/index.js +1889 -0
- package/vendor/@marijn/find-cluster-break/src/index.js +87 -0
- package/vendor/codemirror/dist/index.js +96 -0
- package/vendor/crelt/index.js +28 -0
- package/vendor/json-6/dist/index.mjs +1783 -0
- package/vendor/style-mod/src/style-mod.js +172 -0
- package/vendor/typeson-registry/dist/index.js +83 -10
- package/vendor/w3c-keyname/index.js +119 -0
- package/vendor/zod/classic/checks.d.ts +1 -1
- package/vendor/zod/classic/checks.js +1 -1
- package/vendor/zod/classic/external.d.ts +1 -1
- package/vendor/zod/classic/external.js +1 -1
- package/vendor/zod/classic/from-json-schema.js +245 -24
- package/vendor/zod/classic/schemas.d.ts +17 -1
- package/vendor/zod/classic/schemas.js +77 -29
- package/vendor/zod/core/api.d.ts +6 -4
- package/vendor/zod/core/api.js +17 -2
- package/vendor/zod/core/checks.d.ts +1 -1
- package/vendor/zod/core/checks.js +0 -96
- package/vendor/zod/core/compile.d.ts +18 -4
- package/vendor/zod/core/compile.js +146 -67
- package/vendor/zod/core/doc.js +7 -2
- package/vendor/zod/core/errors.js +2 -5
- package/vendor/zod/core/json-schema-generator.js +2 -2
- package/vendor/zod/core/json-schema-processors.d.ts +17 -0
- package/vendor/zod/core/json-schema-processors.js +195 -64
- package/vendor/zod/core/memoizer.js +72 -23
- package/vendor/zod/core/parse.js +37 -16
- package/vendor/zod/core/regexes.d.ts +2 -0
- package/vendor/zod/core/regexes.js +8 -4
- package/vendor/zod/core/schemas.d.ts +42 -7
- package/vendor/zod/core/schemas.js +301 -94
- package/vendor/zod/core/to-json-schema.d.ts +7 -3
- package/vendor/zod/core/to-json-schema.js +8 -7
- package/vendor/zod/core/util.d.ts +25 -4
- package/vendor/zod/core/util.js +160 -143
- package/vendor/zod/core/versions.d.ts +1 -1
- package/vendor/zod/core/versions.js +2 -2
- package/vendor/zod/core/visit.js +12 -0
- package/vendor/zod/locales/ar.js +1 -0
- package/vendor/zod/locales/az.js +1 -0
- package/vendor/zod/locales/be.js +1 -0
- package/vendor/zod/locales/bg.js +1 -0
- package/vendor/zod/locales/bn.js +1 -0
- package/vendor/zod/locales/ca.js +1 -0
- package/vendor/zod/locales/ckb.js +1 -0
- package/vendor/zod/locales/cs.js +1 -0
- package/vendor/zod/locales/da.js +1 -0
- package/vendor/zod/locales/de.js +1 -0
- package/vendor/zod/locales/el.js +1 -0
- package/vendor/zod/locales/en.js +1 -0
- package/vendor/zod/locales/eo.js +1 -0
- package/vendor/zod/locales/es.js +1 -0
- package/vendor/zod/locales/fa.js +1 -0
- package/vendor/zod/locales/fi.js +1 -0
- package/vendor/zod/locales/fr-CA.js +1 -0
- package/vendor/zod/locales/fr.js +1 -0
- package/vendor/zod/locales/gu.js +1 -0
- package/vendor/zod/locales/he.js +1 -0
- package/vendor/zod/locales/hi.js +1 -0
- package/vendor/zod/locales/hr.js +1 -0
- package/vendor/zod/locales/hu.js +1 -0
- package/vendor/zod/locales/hy.js +1 -0
- package/vendor/zod/locales/id.js +1 -0
- package/vendor/zod/locales/index.d.ts +1 -0
- package/vendor/zod/locales/index.js +1 -0
- package/vendor/zod/locales/is.js +1 -0
- package/vendor/zod/locales/it.js +1 -0
- package/vendor/zod/locales/ja.js +1 -0
- package/vendor/zod/locales/ka.js +1 -0
- package/vendor/zod/locales/km.js +1 -0
- package/vendor/zod/locales/kn.js +1 -0
- package/vendor/zod/locales/ko.js +1 -0
- package/vendor/zod/locales/lt.js +1 -0
- package/vendor/zod/locales/mk.js +1 -0
- package/vendor/zod/locales/ms.js +1 -0
- package/vendor/zod/locales/ne.js +1 -0
- package/vendor/zod/locales/nl.js +1 -0
- package/vendor/zod/locales/nn.js +1 -0
- package/vendor/zod/locales/no.js +1 -0
- package/vendor/zod/locales/ota.js +1 -0
- package/vendor/zod/locales/pl.js +1 -0
- package/vendor/zod/locales/ps.js +1 -0
- package/vendor/zod/locales/pt-BR.js +1 -0
- package/vendor/zod/locales/pt.js +1 -0
- package/vendor/zod/locales/ro.js +1 -0
- package/vendor/zod/locales/ru.js +1 -0
- package/vendor/zod/locales/sk.js +1 -0
- package/vendor/zod/locales/sl.js +1 -0
- package/vendor/zod/locales/sv.js +1 -0
- package/vendor/zod/locales/ta.js +1 -0
- package/vendor/zod/locales/tg.d.ts +4 -0
- package/vendor/zod/locales/tg.js +116 -0
- package/vendor/zod/locales/th.js +1 -0
- package/vendor/zod/locales/tk.js +1 -0
- package/vendor/zod/locales/tr.js +1 -0
- package/vendor/zod/locales/uk.js +1 -0
- package/vendor/zod/locales/ur.js +1 -0
- package/vendor/zod/locales/uz.js +1 -0
- package/vendor/zod/locales/vi.js +1 -0
- package/vendor/zod/locales/yo.js +1 -0
- package/vendor/zod/locales/zh-CN.js +1 -0
- package/vendor/zod/locales/zh-TW.js +1 -0
- package/vendor/zod/mini/checks.d.ts +1 -1
- package/vendor/zod/mini/checks.js +1 -1
- package/vendor/zod/mini/external.d.ts +1 -1
- package/vendor/zod/mini/external.js +1 -1
- package/vendor/zod/mini/schemas.d.ts +8 -0
- package/vendor/zod/mini/schemas.js +19 -2
- package/vendor/zodexy/dist/esm/index.js +34 -1
- package/vendor/zodexy/dist/schema.zodexy.json +18 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
import dialogs from './dialogs.js';
|
|
2
|
+
import {$e, DOM} from './templateUtils.js';
|
|
3
|
+
import {
|
|
4
|
+
Typeson, JSON6, EditorView, basicSetup, EditorState,
|
|
5
|
+
javascript, toStringTag
|
|
6
|
+
} from '../vendor-imports.js';
|
|
7
|
+
import {structuredCloningJsoe} from '../formats/structuredCloning.js';
|
|
8
|
+
import {parseValue} from '../formats/schema.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @returns {import('typeson').Typeson}
|
|
12
|
+
*/
|
|
13
|
+
const buildTypeson = () => {
|
|
14
|
+
return new Typeson().register(structuredCloningJsoe);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const identifierKeyRegex = (/^[A-Za-z_$][\w$]*$/u);
|
|
18
|
+
|
|
19
|
+
/** @type {ReadonlySet<string>} */
|
|
20
|
+
const typedArrayTagNames = new Set([
|
|
21
|
+
'Int8Array', 'Uint8Array', 'Uint8ClampedArray', 'Int16Array',
|
|
22
|
+
'Uint16Array', 'Int32Array', 'Uint32Array', 'Float16Array',
|
|
23
|
+
'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array'
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/** @type {ReadonlySet<string>} */
|
|
27
|
+
const errorTagNames = new Set([
|
|
28
|
+
'Error', 'TypeError', 'RangeError', 'SyntaxError', 'ReferenceError',
|
|
29
|
+
'EvalError', 'URIError', 'AggregateError'
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Base64-encodes raw bytes, chunked so a large buffer doesn't blow the
|
|
34
|
+
* argument-count limit `String.fromCodePoint(...bytes)` would hit spread
|
|
35
|
+
* over the whole thing at once.
|
|
36
|
+
* @param {Uint8Array} bytes
|
|
37
|
+
* @returns {string}
|
|
38
|
+
*/
|
|
39
|
+
const bytesToBase64 = (bytes) => {
|
|
40
|
+
const chunkSize = 0x8000;
|
|
41
|
+
let binary = '';
|
|
42
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
43
|
+
binary += String.fromCodePoint(...bytes.subarray(i, i + chunkSize));
|
|
44
|
+
}
|
|
45
|
+
return btoa(binary);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* A minimal JSON6-*subset* stringifier: unquotes object keys that are valid
|
|
50
|
+
* identifiers (for the "simplified" display the JSON6 mode is meant to
|
|
51
|
+
* give), while always fully quoting string *values* via `JSON.stringify`.
|
|
52
|
+
*
|
|
53
|
+
* `JSON6.stringify` (from the `json-6` package) was tried first but has a
|
|
54
|
+
* real bug: it runs the same identifier-unquoting logic it uses for keys
|
|
55
|
+
* on string *values* too, so e.g. the value `"hello"` is emitted as the
|
|
56
|
+
* bare word `hello` — not valid JS/JSON6 syntax as a value, and not even
|
|
57
|
+
* re-parseable by the package's own `JSON6.parse`. Hand-rolling this
|
|
58
|
+
* avoids depending on that broken path while still using `JSON6.parse`
|
|
59
|
+
* (which is correct) to read the text back after editing.
|
|
60
|
+
* @param {unknown} value
|
|
61
|
+
* @param {string} indent
|
|
62
|
+
* @param {string} curIndent
|
|
63
|
+
* @returns {string}
|
|
64
|
+
*/
|
|
65
|
+
const stringifyJSON6 = (value, indent, curIndent) => {
|
|
66
|
+
if (value === null || typeof value !== 'object') {
|
|
67
|
+
return JSON.stringify(value);
|
|
68
|
+
}
|
|
69
|
+
const nextIndent = curIndent + indent;
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
|
+
if (!value.length) {
|
|
72
|
+
return '[]';
|
|
73
|
+
}
|
|
74
|
+
const items = value.map((item) => {
|
|
75
|
+
return `${nextIndent}${stringifyJSON6(item, indent, nextIndent)}`;
|
|
76
|
+
});
|
|
77
|
+
return `[\n${items.join(',\n')}\n${curIndent}]`;
|
|
78
|
+
}
|
|
79
|
+
const keys = Object.keys(value);
|
|
80
|
+
if (!keys.length) {
|
|
81
|
+
return '{}';
|
|
82
|
+
}
|
|
83
|
+
const items = keys.map((key) => {
|
|
84
|
+
const keyText = identifierKeyRegex.test(key)
|
|
85
|
+
? key
|
|
86
|
+
: JSON.stringify(key);
|
|
87
|
+
return `${nextIndent}${keyText}: ${
|
|
88
|
+
stringifyJSON6(
|
|
89
|
+
/** @type {{[key: string]: unknown}} */ (value)[key], indent,
|
|
90
|
+
nextIndent
|
|
91
|
+
)
|
|
92
|
+
}`;
|
|
93
|
+
});
|
|
94
|
+
return `{\n${items.join(',\n')}\n${curIndent}}`;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Builds the Typeson/JSON6 text shown by both the view-mode "View raw"
|
|
99
|
+
* button and, seeded, the edit-mode "Edit raw" button's Typeson mode.
|
|
100
|
+
* @param {unknown} value
|
|
101
|
+
* @returns {Promise<string>}
|
|
102
|
+
*/
|
|
103
|
+
export async function getTypesonTextForValue (value) {
|
|
104
|
+
const typeson = buildTypeson();
|
|
105
|
+
// `throwOnBadSyncType: false` matches `../formats/structuredCloning.js`'s
|
|
106
|
+
// own `encapsulateAsync` call: without it, Typeson throws when a value
|
|
107
|
+
// has no actually-async parts (no Blob/File/Promise) and so resolves
|
|
108
|
+
// synchronously despite the "Async" method having been called.
|
|
109
|
+
const encapsulated = await typeson.encapsulateAsync(value, null, {
|
|
110
|
+
throwOnBadSyncType: false
|
|
111
|
+
});
|
|
112
|
+
return stringifyJSON6(encapsulated, ' ', '');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Reverses `getTypesonTextForValue`: parses JSON6 (superset) syntax and
|
|
117
|
+
* revives any Typeson-tagged values back into real JS values.
|
|
118
|
+
* @param {string} text
|
|
119
|
+
* @returns {unknown}
|
|
120
|
+
*/
|
|
121
|
+
export function getValueForTypesonText (text) {
|
|
122
|
+
const typeson = buildTypeson();
|
|
123
|
+
const parsed = JSON6.parse(text);
|
|
124
|
+
return typeson.revive(parsed);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Only ever called when `types.allowUnsafeEval` is true. The whole point of
|
|
129
|
+
* eval mode is that the user's text is a plain JS expression (e.g.
|
|
130
|
+
* `{a: new Date()}`) that already evaluates to the real value directly;
|
|
131
|
+
* this never touches Typeson, unlike `getValueForTypesonText`.
|
|
132
|
+
* @param {string} text
|
|
133
|
+
* @returns {unknown}
|
|
134
|
+
*/
|
|
135
|
+
export function getValueForEvalText (text) {
|
|
136
|
+
// User explicitly opted in via the `allowUnsafeEval` constructor option;
|
|
137
|
+
// same rationale as `functionSpec.revive` in
|
|
138
|
+
// `../formats/structuredCloning.js`.
|
|
139
|
+
// eslint-disable-next-line no-eval -- User opted in
|
|
140
|
+
return (0, eval)('(' + text + ')');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Base64-encodes a `Blob`/`File`'s content — the one genuinely asynchronous
|
|
145
|
+
* part of eval-mode seeding, since reading a `Blob`'s bytes always returns
|
|
146
|
+
* a promise (unlike `ArrayBuffer`/typed-array bytes, already in memory).
|
|
147
|
+
* @param {Blob} blob
|
|
148
|
+
* @returns {Promise<string>}
|
|
149
|
+
*/
|
|
150
|
+
const blobToBase64 = async (blob) => {
|
|
151
|
+
return bytesToBase64(new Uint8Array(await blob.arrayBuffer()));
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* A dedicated serializer for seeding the editor's text when switching into
|
|
156
|
+
* eval mode. Deliberately does **not** reuse `getTypesonTextForValue`'s
|
|
157
|
+
* output: that form tags special values (e.g. a `Date` becomes an ISO
|
|
158
|
+
* string plus a `$types` entry), and evaluating that tagged text verbatim
|
|
159
|
+
* would hand back the plain tagged object, not a real `Date` — eval mode
|
|
160
|
+
* has no revive step to undo the tagging. This instead emits genuine JS
|
|
161
|
+
* constructor source for the same value.
|
|
162
|
+
*
|
|
163
|
+
* Async because a `Blob`/`File`'s content can only be read
|
|
164
|
+
* asynchronously (`Blob#arrayBuffer()`); every other branch is
|
|
165
|
+
* synchronous work wrapped in a resolved promise.
|
|
166
|
+
* @param {unknown} value
|
|
167
|
+
* @param {Set<unknown>} [seen] Tracks objects already being serialized, to
|
|
168
|
+
* fail clearly on a cyclic value rather than recursing forever.
|
|
169
|
+
* @returns {Promise<string>}
|
|
170
|
+
*/
|
|
171
|
+
export async function getEvalSeedTextForValue (value, seen = new Set()) {
|
|
172
|
+
if (value === null) {
|
|
173
|
+
return 'null';
|
|
174
|
+
}
|
|
175
|
+
if (value === undefined) {
|
|
176
|
+
return 'undefined';
|
|
177
|
+
}
|
|
178
|
+
switch (typeof value) {
|
|
179
|
+
case 'string':
|
|
180
|
+
return JSON.stringify(value);
|
|
181
|
+
case 'number':
|
|
182
|
+
// `String(-0)` is `"0"`, silently losing the sign; matches the
|
|
183
|
+
// convention already used by `../superTypes/SpecialNumberType.js`.
|
|
184
|
+
return Object.is(value, -0) ? '-0' : String(value);
|
|
185
|
+
case 'boolean':
|
|
186
|
+
return String(value);
|
|
187
|
+
case 'bigint':
|
|
188
|
+
return `${value}n`;
|
|
189
|
+
case 'function':
|
|
190
|
+
// Mirrors `functionSpec.replace` in `../formats/structuredCloning.js`.
|
|
191
|
+
return value.toString();
|
|
192
|
+
default:
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
const tag = toStringTag(value);
|
|
196
|
+
if (tag === 'Symbol') {
|
|
197
|
+
// Mirrors `src/fundamentalTypes/symbolType.js`'s own convention
|
|
198
|
+
// (`String(value).slice(7, -1)` rather than `.description`, which
|
|
199
|
+
// would be `undefined` for `Symbol()` with no description).
|
|
200
|
+
const sym = /** @type {symbol} */ (value);
|
|
201
|
+
const key = Symbol.keyFor(sym);
|
|
202
|
+
return key === undefined
|
|
203
|
+
? `Symbol(${JSON.stringify(String(sym).slice(7, -1))})`
|
|
204
|
+
: `Symbol.for(${JSON.stringify(key)})`;
|
|
205
|
+
}
|
|
206
|
+
if (tag === 'Date') {
|
|
207
|
+
return `new Date(${
|
|
208
|
+
JSON.stringify(/** @type {Date} */ (value).toISOString())
|
|
209
|
+
})`;
|
|
210
|
+
}
|
|
211
|
+
if (tag === 'RegExp') {
|
|
212
|
+
return value.toString();
|
|
213
|
+
}
|
|
214
|
+
// Boxed primitives (`new String(...)`/`new Number(...)`/`new Boolean(...)`
|
|
215
|
+
// — distinct from the plain-primitive `string`/`number`/`boolean` cases
|
|
216
|
+
// in the `switch` above, which never reach here).
|
|
217
|
+
if (tag === 'String') {
|
|
218
|
+
const boxed = /** @type {{valueOf: () => string}} */ (value);
|
|
219
|
+
return `new String(${JSON.stringify(boxed.valueOf())})`;
|
|
220
|
+
}
|
|
221
|
+
if (tag === 'Number') {
|
|
222
|
+
const boxed = /** @type {{valueOf: () => number}} */ (value);
|
|
223
|
+
return `new Number(${boxed.valueOf()})`;
|
|
224
|
+
}
|
|
225
|
+
if (tag === 'Boolean') {
|
|
226
|
+
const boxed = /** @type {{valueOf: () => boolean}} */ (value);
|
|
227
|
+
return `new Boolean(${boxed.valueOf()})`;
|
|
228
|
+
}
|
|
229
|
+
if (tag === 'BigInt') {
|
|
230
|
+
// Matches typeson-registry's own `bigintObject` revive:
|
|
231
|
+
// `new Object(BigInt(e))`.
|
|
232
|
+
const boxed = /** @type {{valueOf: () => bigint}} */ (value);
|
|
233
|
+
return `Object(${boxed.valueOf()}n)`;
|
|
234
|
+
}
|
|
235
|
+
if (tag === 'DOMException') {
|
|
236
|
+
const exc = /** @type {DOMException} */ (value);
|
|
237
|
+
return `new DOMException(${JSON.stringify(exc.message)}, ${
|
|
238
|
+
JSON.stringify(exc.name)
|
|
239
|
+
})`;
|
|
240
|
+
}
|
|
241
|
+
// Matches `src/superTypes/domrectType.js`/`dompointType.js`, which support
|
|
242
|
+
// both the read-write and read-only variant under the same base type.
|
|
243
|
+
if (tag === 'DOMRect' || tag === 'DOMRectReadOnly') {
|
|
244
|
+
const r = /** @type {DOMRect} */ (value);
|
|
245
|
+
return `new ${tag}(${r.x}, ${r.y}, ${r.width}, ${r.height})`;
|
|
246
|
+
}
|
|
247
|
+
if (tag === 'DOMPoint' || tag === 'DOMPointReadOnly') {
|
|
248
|
+
const p = /** @type {DOMPoint} */ (value);
|
|
249
|
+
return `new ${tag}(${p.x}, ${p.y}, ${p.z}, ${p.w})`;
|
|
250
|
+
}
|
|
251
|
+
if (tag === 'DOMMatrix' || tag === 'DOMMatrixReadOnly') {
|
|
252
|
+
// Matches `src/superTypes/dommatrixType.js`'s own two constructor forms.
|
|
253
|
+
const m = /** @type {DOMMatrix} */ (value);
|
|
254
|
+
const nums = m.is2D
|
|
255
|
+
? [m.a, m.b, m.c, m.d, m.e, m.f]
|
|
256
|
+
: [
|
|
257
|
+
m.m11, m.m12, m.m13, m.m14,
|
|
258
|
+
m.m21, m.m22, m.m23, m.m24,
|
|
259
|
+
m.m31, m.m32, m.m33, m.m34,
|
|
260
|
+
m.m41, m.m42, m.m43, m.m44
|
|
261
|
+
];
|
|
262
|
+
return `new ${tag}([${nums.join(', ')}])`;
|
|
263
|
+
}
|
|
264
|
+
if (tag === 'ArrayBuffer' || tag === 'DataView' ||
|
|
265
|
+
typedArrayTagNames.has(tag)
|
|
266
|
+
) {
|
|
267
|
+
// Unlike `Blob`/`File`, a buffer's bytes are already in memory — no
|
|
268
|
+
// async read needed, just the same base64 wrapping.
|
|
269
|
+
const bytes = tag === 'ArrayBuffer'
|
|
270
|
+
? new Uint8Array(/** @type {ArrayBuffer} */ (value))
|
|
271
|
+
: new Uint8Array(
|
|
272
|
+
/** @type {{buffer: ArrayBuffer, byteOffset: number, byteLength: number}} */
|
|
273
|
+
(value).buffer,
|
|
274
|
+
/** @type {{byteOffset: number}} */ (value).byteOffset,
|
|
275
|
+
/** @type {{byteLength: number}} */ (value).byteLength
|
|
276
|
+
);
|
|
277
|
+
const bufferExpr = `Uint8Array.from(atob(${
|
|
278
|
+
JSON.stringify(bytesToBase64(bytes))
|
|
279
|
+
}), (c) => c.charCodeAt(0)).buffer`;
|
|
280
|
+
if (tag === 'ArrayBuffer') {
|
|
281
|
+
return bufferExpr;
|
|
282
|
+
}
|
|
283
|
+
return `new ${tag}(${bufferExpr})`;
|
|
284
|
+
}
|
|
285
|
+
if (tag === 'Blob' || tag === 'File') {
|
|
286
|
+
const blob = /** @type {Blob} */ (value);
|
|
287
|
+
const base64 = await blobToBase64(blob);
|
|
288
|
+
const bytesExpr = `Uint8Array.from(atob(${
|
|
289
|
+
JSON.stringify(base64)
|
|
290
|
+
}), (c) => c.charCodeAt(0))`;
|
|
291
|
+
if (tag === 'File') {
|
|
292
|
+
const file = /** @type {File} */ (value);
|
|
293
|
+
return `new File([${bytesExpr}], ${JSON.stringify(file.name)}, ${
|
|
294
|
+
JSON.stringify({type: file.type, lastModified: file.lastModified})
|
|
295
|
+
})`;
|
|
296
|
+
}
|
|
297
|
+
return `new Blob([${bytesExpr}], ${JSON.stringify({type: blob.type})})`;
|
|
298
|
+
}
|
|
299
|
+
if (tag === 'Promise') {
|
|
300
|
+
// A pending/rejected/already-settled `Promise` has no meaningful static
|
|
301
|
+
// literal form; unlike the lossy fallback below, this is a value shape
|
|
302
|
+
// we recognize but have deliberately chosen not to support.
|
|
303
|
+
throw new TypeError(
|
|
304
|
+
'Eval mode cannot represent a Promise as JS source; use the Typeson ' +
|
|
305
|
+
'(JSON6) mode instead.'
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
if (seen.has(value)) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
'Eval mode cannot represent a cyclic/repeated-reference value as ' +
|
|
311
|
+
'JS source; use the Typeson (JSON6) mode instead.'
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
seen.add(value);
|
|
315
|
+
try {
|
|
316
|
+
if (tag === 'FileList' || Array.isArray(value)) {
|
|
317
|
+
// jsoe's own `filelist` control never actually requires a genuine
|
|
318
|
+
// `instanceof FileList` for its value model (see
|
|
319
|
+
// `docs/proposals/raw-typeson-edit-view.md` §1) — a plain array of
|
|
320
|
+
// `File`s round-trips the same way, so no special construct needed.
|
|
321
|
+
let arr;
|
|
322
|
+
if (tag === 'FileList') {
|
|
323
|
+
const fileList = /** @type {Iterable<unknown>} */ (value);
|
|
324
|
+
arr = [...fileList];
|
|
325
|
+
} else {
|
|
326
|
+
arr = /** @type {unknown[]} */ (value);
|
|
327
|
+
}
|
|
328
|
+
const items = await Promise.all(
|
|
329
|
+
arr.map((item) => getEvalSeedTextForValue(item, seen))
|
|
330
|
+
);
|
|
331
|
+
return `[${items.join(', ')}]`;
|
|
332
|
+
}
|
|
333
|
+
if (tag === 'Map') {
|
|
334
|
+
const map = /** @type {Map<unknown, unknown>} */ (value);
|
|
335
|
+
// Not using `Iterator#toArray()`: not yet baseline-widely-available
|
|
336
|
+
// eslint-disable-next-line unicorn/prefer-iterator-to-array -- Above
|
|
337
|
+
const entries = await Promise.all([...map.entries()].map(
|
|
338
|
+
async ([k, v]) => {
|
|
339
|
+
return `[${await getEvalSeedTextForValue(k, seen)}, ${
|
|
340
|
+
await getEvalSeedTextForValue(v, seen)
|
|
341
|
+
}]`;
|
|
342
|
+
}
|
|
343
|
+
));
|
|
344
|
+
return `new Map([${entries.join(', ')}])`;
|
|
345
|
+
}
|
|
346
|
+
if (tag === 'Set') {
|
|
347
|
+
const set = /** @type {Set<unknown>} */ (value);
|
|
348
|
+
const items = await Promise.all(
|
|
349
|
+
[...set].map((item) => getEvalSeedTextForValue(item, seen))
|
|
350
|
+
);
|
|
351
|
+
return `new Set([${items.join(', ')}])`;
|
|
352
|
+
}
|
|
353
|
+
if (tag === 'Error') {
|
|
354
|
+
// `Object.prototype.toString` reports every `Error` subclass as
|
|
355
|
+
// `[object Error]` (an `[[ErrorData]]`-slot check, not a
|
|
356
|
+
// `Symbol.toStringTag` lookup), so `tag` alone can't tell a
|
|
357
|
+
// `TypeError` from a plain `Error` here — recover the real
|
|
358
|
+
// constructor name, falling back to `Error` for a subclass eval
|
|
359
|
+
// mode doesn't know how to name-construct (e.g. a user-defined
|
|
360
|
+
// `class MyError extends Error {}`).
|
|
361
|
+
const err = /**
|
|
362
|
+
* @type {Error & {
|
|
363
|
+
* cause?: unknown, fileName?: string, lineNumber?: number,
|
|
364
|
+
* columnNumber?: number
|
|
365
|
+
* }}
|
|
366
|
+
*/ (value);
|
|
367
|
+
const ctorName = errorTagNames.has(err.constructor?.name)
|
|
368
|
+
? err.constructor.name
|
|
369
|
+
: 'Error';
|
|
370
|
+
const messageExpr = JSON.stringify(err.message);
|
|
371
|
+
const optionsExpr = err.cause === undefined
|
|
372
|
+
? ''
|
|
373
|
+
: `, {cause: ${await getEvalSeedTextForValue(err.cause, seen)}}`;
|
|
374
|
+
const ctorExpr = ctorName === 'AggregateError'
|
|
375
|
+
? `new AggregateError([${
|
|
376
|
+
(await Promise.all(
|
|
377
|
+
/** @type {AggregateError} */ (err).errors.map(
|
|
378
|
+
(e) => getEvalSeedTextForValue(e, seen)
|
|
379
|
+
)
|
|
380
|
+
)).join(', ')
|
|
381
|
+
}], ${messageExpr}${optionsExpr})`
|
|
382
|
+
: `new ${ctorName}(${messageExpr}${optionsExpr})`;
|
|
383
|
+
// `name`/`fileName`/`lineNumber`/`columnNumber`/`stack` aren't
|
|
384
|
+
// constructor arguments — set via `Object.assign`, which (unlike a
|
|
385
|
+
// sequence of statements) still keeps this a single expression.
|
|
386
|
+
const extraProps = [];
|
|
387
|
+
if (typeof err.name === 'string') {
|
|
388
|
+
extraProps.push(`name: ${JSON.stringify(err.name)}`);
|
|
389
|
+
}
|
|
390
|
+
if (typeof err.fileName === 'string') {
|
|
391
|
+
extraProps.push(`fileName: ${JSON.stringify(err.fileName)}`);
|
|
392
|
+
}
|
|
393
|
+
if (typeof err.lineNumber === 'number') {
|
|
394
|
+
extraProps.push(`lineNumber: ${err.lineNumber}`);
|
|
395
|
+
}
|
|
396
|
+
if (typeof err.columnNumber === 'number') {
|
|
397
|
+
extraProps.push(`columnNumber: ${err.columnNumber}`);
|
|
398
|
+
}
|
|
399
|
+
if (typeof err.stack === 'string') {
|
|
400
|
+
extraProps.push(`stack: ${JSON.stringify(err.stack)}`);
|
|
401
|
+
}
|
|
402
|
+
return extraProps.length
|
|
403
|
+
? `Object.assign(${ctorExpr}, {${extraProps.join(', ')}})`
|
|
404
|
+
: ctorExpr;
|
|
405
|
+
}
|
|
406
|
+
if (typeof value === 'object') {
|
|
407
|
+
// Anything reaching here that isn't a plain object literal (a class
|
|
408
|
+
// instance with a non-`Object.prototype` prototype) can't be
|
|
409
|
+
// faithfully reconstructed by the `{...}` literal below — better to
|
|
410
|
+
// fail clearly than silently emit a same-shaped-but-wrong plain
|
|
411
|
+
// object (losing the value's real identity/behavior entirely).
|
|
412
|
+
const proto = Object.getPrototypeOf(value);
|
|
413
|
+
if (proto !== null && proto !== Object.prototype) {
|
|
414
|
+
// `toStringTag` reports a generic `Object` for most user-defined
|
|
415
|
+
// classes (no `Symbol.toStringTag` of their own), so name the
|
|
416
|
+
// error after the actual constructor instead where possible.
|
|
417
|
+
const ctor = /** @type {{constructor?: {name?: string}}} */ (
|
|
418
|
+
value
|
|
419
|
+
).constructor;
|
|
420
|
+
throw new TypeError(
|
|
421
|
+
`Eval mode cannot represent a ${
|
|
422
|
+
ctor?.name || tag || 'non-plain-object'
|
|
423
|
+
} value as JS source; use the Typeson (JSON6) mode instead.`
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
const entries = await Promise.all(
|
|
427
|
+
Object.entries(value).map(async ([k, v]) => {
|
|
428
|
+
const key = (/^[A-Za-z_$][\w$]*$/u).test(k) ? k : JSON.stringify(k);
|
|
429
|
+
return `${key}: ${await getEvalSeedTextForValue(v, seen)}`;
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
return `{${entries.join(', ')}}`;
|
|
433
|
+
}
|
|
434
|
+
/* istanbul ignore next -- No other `typeof` reaches here */
|
|
435
|
+
return String(value);
|
|
436
|
+
} finally {
|
|
437
|
+
seen.delete(value);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Repopulates an existing object/array/set/map/filelist control's children
|
|
443
|
+
* in place after a raw-value edit. Object/array-family type objects have
|
|
444
|
+
* no `setValue` of their own (`types.setValue` is a no-op for them, as
|
|
445
|
+
* only leaf types implement it) — their children are always attached one
|
|
446
|
+
* at a time via `$addAndSetArrayElement`, driven by walking a Typeson
|
|
447
|
+
* `encapsulateAsync` pass. This reuses that exact mechanism, scoped to
|
|
448
|
+
* just this container, by pre-seeding `stateObj.rootUI` with the existing
|
|
449
|
+
* `root` element (see the corresponding change in
|
|
450
|
+
* `../formats/structuredCloning.js`'s `encapsulateObserver`, which reuses
|
|
451
|
+
* a pre-seeded root instead of building a new one).
|
|
452
|
+
*
|
|
453
|
+
* The control's own root element is kept (not replaced), since other code
|
|
454
|
+
* may already hold a reference to it (most importantly, the root control
|
|
455
|
+
* of the whole form). The container's own `itemIndex`/legend-numbering
|
|
456
|
+
* counter, closed over since the control was first built, is reset via
|
|
457
|
+
* `root.$resetItemIndex()` right after its old children are cleared and
|
|
458
|
+
* before the new ones are attached, back to the same baseline the
|
|
459
|
+
* container started at when first built — so the repopulated items (and
|
|
460
|
+
* any later manually-added one, via "+ Item") end up numbered exactly as
|
|
461
|
+
* a fresh container holding the same new items would be, rather than
|
|
462
|
+
* continuing from wherever the replaced content had left off.
|
|
463
|
+
* @param {object} cfg
|
|
464
|
+
* @param {InstanceType<typeof import('../types.js').default>} cfg.types
|
|
465
|
+
* @param {import('../formats.js').AvailableFormat} cfg.format
|
|
466
|
+
* @param {import('../types.js').AvailableArbitraryType} cfg.type
|
|
467
|
+
* @param {HTMLDivElement} cfg.root
|
|
468
|
+
* @param {HTMLDivElement} cfg.topRoot
|
|
469
|
+
* @param {string} [cfg.typeNamespace]
|
|
470
|
+
* @param {import('zodexy').SzType} [cfg.specificSchemaObject]
|
|
471
|
+
* @param {unknown} cfg.value
|
|
472
|
+
* @returns {Promise<void>}
|
|
473
|
+
*/
|
|
474
|
+
export async function commitValueToContainer ({
|
|
475
|
+
types, format, type, root, topRoot, typeNamespace, specificSchemaObject,
|
|
476
|
+
value
|
|
477
|
+
}) {
|
|
478
|
+
const {formats} = types;
|
|
479
|
+
const rootWithCustomMethods = /**
|
|
480
|
+
* @type {{
|
|
481
|
+
* $getArrayItems: () => HTMLElement,
|
|
482
|
+
* $resetItemIndex: () => void
|
|
483
|
+
* }}
|
|
484
|
+
*/ (/** @type {unknown} */ (root));
|
|
485
|
+
DOM.removeChildren(rootWithCustomMethods.$getArrayItems());
|
|
486
|
+
rootWithCustomMethods.$resetItemIndex();
|
|
487
|
+
const stateObj = /** @type {import('../types.js').StateObject} */ ({
|
|
488
|
+
types,
|
|
489
|
+
formats,
|
|
490
|
+
format,
|
|
491
|
+
typeNamespace,
|
|
492
|
+
readonly: false,
|
|
493
|
+
// This container's own schema stands in as the "whole record" schema
|
|
494
|
+
// for this scoped re-population, mirroring how the overall document
|
|
495
|
+
// schema drives the very first `getControlsForFormatAndValue` call.
|
|
496
|
+
schemaContent: specificSchemaObject,
|
|
497
|
+
rootUI: root
|
|
498
|
+
});
|
|
499
|
+
await formats.getAvailableFormat(format).iterate(value, stateObj);
|
|
500
|
+
await stateObj.whenBuilt;
|
|
501
|
+
if (stateObj.error) {
|
|
502
|
+
throw stateObj.error;
|
|
503
|
+
}
|
|
504
|
+
types.validate({type, root, topRoot, avoidReport: false});
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Builds and shows the modal for the "View raw"/"Edit raw" buttons added to
|
|
509
|
+
* every eligible object/array-family control in
|
|
510
|
+
* `../fundamentalTypes/arrayType.js`.
|
|
511
|
+
* @param {object} cfg
|
|
512
|
+
* @param {InstanceType<typeof import('../types.js').default>} cfg.types
|
|
513
|
+
* @param {import('../formats.js').AvailableFormat} cfg.format
|
|
514
|
+
* @param {import('../types.js').AvailableArbitraryType} cfg.type
|
|
515
|
+
* @param {HTMLDivElement} cfg.root
|
|
516
|
+
* @param {HTMLDivElement} cfg.topRoot
|
|
517
|
+
* @param {string} [cfg.typeNamespace]
|
|
518
|
+
* @param {import('zodexy').SzType} [cfg.specificSchemaObject]
|
|
519
|
+
* @param {boolean} cfg.readonly
|
|
520
|
+
* @returns {Promise<void>}
|
|
521
|
+
*/
|
|
522
|
+
export async function openRawEditorDialog ({
|
|
523
|
+
types, format, type, root, topRoot, typeNamespace, specificSchemaObject,
|
|
524
|
+
readonly
|
|
525
|
+
}) {
|
|
526
|
+
const {formats} = types;
|
|
527
|
+
const value = types.getValueForRoot(
|
|
528
|
+
/** @type {any} */ (root),
|
|
529
|
+
/** @type {import('../types.js').StateObject} */ ({
|
|
530
|
+
typeNamespace, formats, format, types
|
|
531
|
+
}),
|
|
532
|
+
''
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
/** @type {'typeson'|'eval'} */
|
|
536
|
+
let mode = 'typeson';
|
|
537
|
+
|
|
538
|
+
// Declared before assignment (rather than `const`) since it is referenced
|
|
539
|
+
// by closures defined further up, before the dialog (and so the mount
|
|
540
|
+
// point `view` is assigned into) exists.
|
|
541
|
+
/** @type {import('codemirror').EditorView} */
|
|
542
|
+
// eslint-disable-next-line prefer-const -- See comment above
|
|
543
|
+
let view;
|
|
544
|
+
|
|
545
|
+
const errorClass = 'jsoe-raw-editor-error';
|
|
546
|
+
const editorClass = 'jsoe-raw-editor';
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* @param {HTMLElement} dialog
|
|
550
|
+
* @param {string} message
|
|
551
|
+
* @returns {void}
|
|
552
|
+
*/
|
|
553
|
+
const showError = (dialog, message) => {
|
|
554
|
+
const errorEl = /** @type {HTMLElement} */ ($e(dialog, `.${errorClass}`));
|
|
555
|
+
errorEl.textContent = message;
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @param {string} text
|
|
560
|
+
* @returns {void}
|
|
561
|
+
*/
|
|
562
|
+
const setText = (text) => {
|
|
563
|
+
view.dispatch({
|
|
564
|
+
changes: {from: 0, to: view.state.doc.length, insert: text}
|
|
565
|
+
});
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const seedTextForMode = async () => {
|
|
569
|
+
return mode === 'eval'
|
|
570
|
+
? await getEvalSeedTextForValue(value)
|
|
571
|
+
: await getTypesonTextForValue(value);
|
|
572
|
+
};
|
|
573
|
+
|
|
574
|
+
const initialText = readonly
|
|
575
|
+
? await getTypesonTextForValue(value)
|
|
576
|
+
: await seedTextForMode();
|
|
577
|
+
|
|
578
|
+
/** @type {import('jamilih').JamilihArray[]} */
|
|
579
|
+
const children = [
|
|
580
|
+
['div', {class: errorClass, role: 'alert'}],
|
|
581
|
+
...(!readonly && types.allowUnsafeEval
|
|
582
|
+
? /** @type {import('jamilih').JamilihArray[]} */ ([
|
|
583
|
+
['select', {
|
|
584
|
+
class: 'jsoe-raw-editor-mode',
|
|
585
|
+
$on: {
|
|
586
|
+
async change (/** @type {Event} */ e) {
|
|
587
|
+
mode = /** @type {HTMLSelectElement} */ (
|
|
588
|
+
e.target
|
|
589
|
+
).value === 'eval'
|
|
590
|
+
? 'eval'
|
|
591
|
+
: 'typeson';
|
|
592
|
+
try {
|
|
593
|
+
setText(await seedTextForMode());
|
|
594
|
+
} catch (error) {
|
|
595
|
+
setText('');
|
|
596
|
+
showError(
|
|
597
|
+
/** @type {HTMLElement} */ (
|
|
598
|
+
/** @type {HTMLSelectElement} */ (e.target).closest(
|
|
599
|
+
'dialog'
|
|
600
|
+
)
|
|
601
|
+
),
|
|
602
|
+
/** @type {Error} */ (error).message
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}, [
|
|
608
|
+
['option', {value: 'typeson'}, ['Typeson (JSON6)']],
|
|
609
|
+
['option', {value: 'eval'}, ['JS (eval)']]
|
|
610
|
+
]]
|
|
611
|
+
])
|
|
612
|
+
: []),
|
|
613
|
+
['div', {class: editorClass}]
|
|
614
|
+
];
|
|
615
|
+
|
|
616
|
+
const dialog = readonly
|
|
617
|
+
// @ts-expect-error TS bug
|
|
618
|
+
? dialogs.makeCancelDialog({children})
|
|
619
|
+
: dialogs.makeSubmitDialog({
|
|
620
|
+
submitText: 'Save',
|
|
621
|
+
async submit ({dialog: dlg}) {
|
|
622
|
+
const text = view.state.doc.toString();
|
|
623
|
+
showError(dlg, '');
|
|
624
|
+
let newValue;
|
|
625
|
+
try {
|
|
626
|
+
newValue = mode === 'eval'
|
|
627
|
+
? getValueForEvalText(text)
|
|
628
|
+
: await getValueForTypesonText(text);
|
|
629
|
+
} catch (error) {
|
|
630
|
+
showError(dlg, /** @type {Error} */ (error).message);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (specificSchemaObject) {
|
|
634
|
+
const result = parseValue(
|
|
635
|
+
types, specificSchemaObject, specificSchemaObject, newValue
|
|
636
|
+
);
|
|
637
|
+
if (!result.success) {
|
|
638
|
+
showError(
|
|
639
|
+
dlg, 'That value does not satisfy this field’s schema.'
|
|
640
|
+
);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
try {
|
|
645
|
+
await commitValueToContainer({
|
|
646
|
+
types, format, type, root, topRoot, typeNamespace,
|
|
647
|
+
specificSchemaObject, value: newValue
|
|
648
|
+
});
|
|
649
|
+
} catch (error) {
|
|
650
|
+
showError(dlg, /** @type {Error} */ (error).message);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
dlg.close();
|
|
654
|
+
},
|
|
655
|
+
// @ts-expect-error TS bug
|
|
656
|
+
children
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
const editorHost = /** @type {HTMLElement} */ ($e(dialog, `.${editorClass}`));
|
|
660
|
+
view = new EditorView({
|
|
661
|
+
doc: initialText,
|
|
662
|
+
extensions: [
|
|
663
|
+
basicSetup,
|
|
664
|
+
javascript(),
|
|
665
|
+
...(readonly ? [EditorState.readOnly.of(true)] : [])
|
|
666
|
+
],
|
|
667
|
+
parent: editorHost
|
|
668
|
+
});
|
|
669
|
+
}
|
package/src/vendor-imports.js
CHANGED
|
@@ -19,3 +19,15 @@ export {default as mimeStandardTypes} from 'mime/types/standard.js';
|
|
|
19
19
|
export {default as mimeOtherTypes} from 'mime/types/other.js';
|
|
20
20
|
// } from '../node_modules/mime/dist/types/standard.js';
|
|
21
21
|
// } from '../node_modules/mime/dist/types/other.js';
|
|
22
|
+
|
|
23
|
+
export {default as JSON6} from 'json-6';
|
|
24
|
+
// } from '../node_modules/json-6/dist/index.mjs';
|
|
25
|
+
|
|
26
|
+
export {EditorView, basicSetup} from 'codemirror';
|
|
27
|
+
// } from '../node_modules/codemirror/dist/index.js';
|
|
28
|
+
|
|
29
|
+
export {EditorState} from '@codemirror/state';
|
|
30
|
+
// } from '../node_modules/@codemirror/state/dist/index.js';
|
|
31
|
+
|
|
32
|
+
export {javascript} from '@codemirror/lang-javascript';
|
|
33
|
+
// } from '../node_modules/@codemirror/lang-javascript/dist/index.js';
|
package/tsconfig.json
CHANGED
|
@@ -15,6 +15,6 @@
|
|
|
15
15
|
"rootDir": "src",
|
|
16
16
|
"outDir": "dist"
|
|
17
17
|
},
|
|
18
|
-
"include": ["src/**/*.js", "typings/sceditor.d.ts"],
|
|
18
|
+
"include": ["src/**/*.js", "typings/sceditor.d.ts", "typings/json-6.d.ts"],
|
|
19
19
|
"exclude": ["node_modules", "src/deepEqual.js", "src/formats/schema.js", "./src/index.ts", "./dist/**/*.js"]
|
|
20
20
|
}
|