@embedpdf/core-acrojs 3.0.0-next.13 → 3.0.0-next.15
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/index.cjs +141 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -26
- package/dist/index.d.ts +30 -26
- package/dist/index.js +141 -128
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
//#region src/actions.ts
|
|
3
3
|
/**
|
|
4
4
|
* Return executable JavaScript in PDF action order (root, then `/Next`
|
|
5
|
-
* depth-first). A poisoned native snapshot is never partially executed.
|
|
5
|
+
* depth-first). A poisoned native snapshot is never partially executed. Any
|
|
6
|
+
* kind of destination will do: only the scripts are read.
|
|
6
7
|
*/
|
|
7
8
|
function javaScriptSourcesFromActionTree(tree) {
|
|
8
9
|
if (tree.incomplete) throw new Error("Refusing to execute an incomplete PDF action tree");
|
|
@@ -23,7 +24,7 @@ function javaScriptProgramFromActionTree(tree) {
|
|
|
23
24
|
/**
|
|
24
25
|
* Host-side Acrobat color-array conversions — the commit sinks and world
|
|
25
26
|
* builders cross the Acrobat-array ↔ renderer-color boundary through these.
|
|
26
|
-
* The
|
|
27
|
+
* The prelude inlines its own identical formulas (it must stay
|
|
27
28
|
* self-contained); `prelude.test.ts` pins the two implementations together.
|
|
28
29
|
*
|
|
29
30
|
* Conversion vectors (the documented Acrobat semantics):
|
|
@@ -47,11 +48,11 @@ function scriptColorToRgb(color) {
|
|
|
47
48
|
b: color[3]
|
|
48
49
|
};
|
|
49
50
|
case "CMYK": {
|
|
50
|
-
const [,
|
|
51
|
+
const [, cyan, magenta, yellow, black] = color;
|
|
51
52
|
return {
|
|
52
|
-
r: 1 - Math.min(1,
|
|
53
|
-
g: 1 - Math.min(1,
|
|
54
|
-
b: 1 - Math.min(1,
|
|
53
|
+
r: 1 - Math.min(1, cyan + black),
|
|
54
|
+
g: 1 - Math.min(1, magenta + black),
|
|
55
|
+
b: 1 - Math.min(1, yellow + black)
|
|
55
56
|
};
|
|
56
57
|
}
|
|
57
58
|
}
|
|
@@ -92,10 +93,10 @@ function isScriptColorArray(value) {
|
|
|
92
93
|
//#endregion
|
|
93
94
|
//#region src/types.ts
|
|
94
95
|
/**
|
|
95
|
-
* The writable-property validity matrix, keyed by engine subtype — the
|
|
96
|
+
* The writable-property validity matrix, keyed by engine subtype — the one
|
|
96
97
|
* exported table (the prelude inlines an identical copy; a parity test pins
|
|
97
98
|
* them together, and plugin-annotation drift-guards this against the kind
|
|
98
|
-
* registry's
|
|
99
|
+
* registry's FieldSpecs). Flags + contents are writable everywhere
|
|
99
100
|
* script-addressable; appearance keys vary by kind.
|
|
100
101
|
*/
|
|
101
102
|
const ANNOT_WRITABLE_KEYS = Object.freeze({
|
|
@@ -219,16 +220,16 @@ function seedFrom(documentId, sequence) {
|
|
|
219
220
|
}
|
|
220
221
|
return hash >>> 0;
|
|
221
222
|
}
|
|
222
|
-
/**
|
|
223
|
-
* standard `ScriptHostOptions.identity` builder. */
|
|
223
|
+
/** The session's identity, as Acrobat JavaScript's `identity` object, under
|
|
224
|
+
* embedder overrides — the standard `ScriptHostOptions.identity` builder. */
|
|
224
225
|
function resolveScriptIdentity(doc, overrides) {
|
|
225
|
-
const
|
|
226
|
+
const identity = doc.security.identity;
|
|
226
227
|
const supplied = typeof overrides === "function" ? overrides() : overrides ?? {};
|
|
227
228
|
return {
|
|
228
|
-
name: supplied.name ??
|
|
229
|
-
loginName: supplied.loginName ??
|
|
230
|
-
corporation: supplied.corporation ??
|
|
231
|
-
email: supplied.email ?? ""
|
|
229
|
+
name: supplied.name ?? identity?.displayName ?? identity?.userId ?? "",
|
|
230
|
+
loginName: supplied.loginName ?? identity?.userId ?? "",
|
|
231
|
+
corporation: supplied.corporation ?? identity?.organization ?? "",
|
|
232
|
+
email: supplied.email ?? identity?.email ?? ""
|
|
232
233
|
};
|
|
233
234
|
}
|
|
234
235
|
function createScriptHost(options) {
|
|
@@ -262,7 +263,7 @@ function createScriptHost(options) {
|
|
|
262
263
|
...world.annotsCoverDocument !== void 0 ? { annotsCoverDocument: world.annotsCoverDocument } : {},
|
|
263
264
|
event: world.event
|
|
264
265
|
});
|
|
265
|
-
/** A resource fault poisons the realm: rebuild + re-boot lazily
|
|
266
|
+
/** A resource fault poisons the realm: rebuild + re-boot lazily next time. */
|
|
266
267
|
const noteFault = (sandbox) => {
|
|
267
268
|
if (!sandbox.disposed) return;
|
|
268
269
|
sandboxPromise = null;
|
|
@@ -346,25 +347,42 @@ function valueFromEntry(entry) {
|
|
|
346
347
|
case "unsupported": return null;
|
|
347
348
|
}
|
|
348
349
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
350
|
+
/**
|
|
351
|
+
* A field value as scripts see it. A checkbox or radio group shows the export
|
|
352
|
+
* value of its checked widget, as Acrobat's `field.value` does, or `'Off'`.
|
|
353
|
+
*/
|
|
354
|
+
function fieldValueFromEntry(field, entry) {
|
|
355
|
+
if (field.family !== "checkbox" && field.family !== "radio") return valueFromEntry(entry);
|
|
356
|
+
if (entry.kind !== "scalar") return "Off";
|
|
357
|
+
return field.widgets.find((widget) => widget.onState === entry.value)?.exportValue ?? entry.value;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* How a widget shows, as Acrobat's `field.display` reads its flags: hidden;
|
|
361
|
+
* on screen but not printed; printed but not on screen; or visible.
|
|
362
|
+
*/
|
|
363
|
+
function displayOf(row) {
|
|
364
|
+
if (!row) return "visible";
|
|
365
|
+
if (row.hidden) return "hidden";
|
|
366
|
+
if (row.noView) return "noView";
|
|
367
|
+
return row.print ? "visible" : "noPrint";
|
|
352
368
|
}
|
|
353
369
|
/** Build the VM's detached field view from the engine's lossless snapshot. */
|
|
354
370
|
function scriptFieldsFromSnapshot(snapshot) {
|
|
371
|
+
const rows = new Map(snapshot.widgets.map((row) => [row.ref.kind === "objectNumber" ? row.ref.objectNumber : 0, row]));
|
|
355
372
|
return snapshot.fields.map((field) => ({
|
|
356
373
|
ref: field.ref,
|
|
357
374
|
name: field.name,
|
|
358
375
|
family: field.family,
|
|
359
|
-
value: fieldValueFromEntry(field
|
|
360
|
-
defaultValue: fieldValueFromEntry(field
|
|
361
|
-
display:
|
|
362
|
-
readOnly: field.
|
|
363
|
-
required: field.
|
|
376
|
+
value: fieldValueFromEntry(field, field.valueEntry),
|
|
377
|
+
defaultValue: fieldValueFromEntry(field, field.defaultValueEntry),
|
|
378
|
+
display: displayOf(rows.get(field.widgets?.[0]?.objectNumber ?? -1)),
|
|
379
|
+
readOnly: field.readOnly,
|
|
380
|
+
required: field.required,
|
|
364
381
|
..."options" in field ? { options: field.options.map((option) => ({
|
|
365
382
|
label: option.label,
|
|
366
383
|
value: option.value
|
|
367
|
-
})) } : {}
|
|
384
|
+
})) } : {},
|
|
385
|
+
...field.family === "checkbox" || field.family === "radio" ? { exportValues: field.widgets.map((widget) => widget.exportValue) } : {}
|
|
368
386
|
}));
|
|
369
387
|
}
|
|
370
388
|
//#endregion
|
|
@@ -376,18 +394,18 @@ function scriptFieldsFromSnapshot(snapshot) {
|
|
|
376
394
|
* values. The sandbox ships `installAcroJs.toString()` into QuickJS, while
|
|
377
395
|
* tests execute the same source in a Node VM. Types disappear at build time.
|
|
378
396
|
*/
|
|
379
|
-
function installAcroJs(
|
|
380
|
-
const host =
|
|
397
|
+
function installAcroJs(globalObject) {
|
|
398
|
+
const host = globalObject;
|
|
381
399
|
const NativeDate = Date;
|
|
382
400
|
let state = null;
|
|
383
401
|
const cloneValue = (value) => Array.isArray(value) ? value.map((item) => String(item)) : value;
|
|
384
|
-
const sameValue = (
|
|
385
|
-
if (Array.isArray(
|
|
386
|
-
return
|
|
402
|
+
const sameValue = (left, right) => {
|
|
403
|
+
if (Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((item, index) => item === right[index]);
|
|
404
|
+
return left === right;
|
|
387
405
|
};
|
|
388
406
|
const refKey = (ref) => {
|
|
389
407
|
const value = ref;
|
|
390
|
-
return value?.kind === "objectNumber" ? `obj:${String(value.
|
|
408
|
+
return value?.kind === "objectNumber" ? `obj:${String(value.objectNumber)}` : `fqn:${String(value?.name ?? "")}`;
|
|
391
409
|
};
|
|
392
410
|
const diagnostic = (code, message) => {
|
|
393
411
|
state?.diagnostics.push({
|
|
@@ -584,19 +602,19 @@ function installAcroJs(g) {
|
|
|
584
602
|
Number(color[2]),
|
|
585
603
|
Number(color[3])
|
|
586
604
|
];
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const
|
|
590
|
-
const
|
|
605
|
+
const cyan = Number(color[1]);
|
|
606
|
+
const magenta = Number(color[2]);
|
|
607
|
+
const yellow = Number(color[3]);
|
|
608
|
+
const black = Number(color[4]);
|
|
591
609
|
return [
|
|
592
|
-
1 - Math.min(1,
|
|
593
|
-
1 - Math.min(1,
|
|
594
|
-
1 - Math.min(1,
|
|
610
|
+
1 - Math.min(1, cyan + black),
|
|
611
|
+
1 - Math.min(1, magenta + black),
|
|
612
|
+
1 - Math.min(1, yellow + black)
|
|
595
613
|
];
|
|
596
614
|
};
|
|
597
|
-
const sameAnnotValue = (
|
|
598
|
-
if (Array.isArray(
|
|
599
|
-
return
|
|
615
|
+
const sameAnnotValue = (left, right) => {
|
|
616
|
+
if (Array.isArray(left) && Array.isArray(right)) return left.length === right.length && left.every((item, index) => item === right[index]);
|
|
617
|
+
return left === right;
|
|
600
618
|
};
|
|
601
619
|
const cloneAnnotValue = (value) => Array.isArray(value) ? [...value] : value;
|
|
602
620
|
const makeAnnot = (record) => {
|
|
@@ -624,8 +642,8 @@ function installAcroJs(g) {
|
|
|
624
642
|
get: () => cloneAnnotValue(record.current[key]),
|
|
625
643
|
set: (value) => stage(key, value, validate)
|
|
626
644
|
});
|
|
627
|
-
const isNum = (
|
|
628
|
-
const isBool = (
|
|
645
|
+
const isNum = (value) => typeof value === "number" && isFinite(value);
|
|
646
|
+
const isBool = (value) => typeof value === "boolean";
|
|
629
647
|
Object.defineProperties(wrapper, {
|
|
630
648
|
name: {
|
|
631
649
|
enumerable: true,
|
|
@@ -649,12 +667,12 @@ function installAcroJs(g) {
|
|
|
649
667
|
},
|
|
650
668
|
strokeColor: prop("strokeColor", isColorArray),
|
|
651
669
|
fillColor: prop("fillColor", isColorArray),
|
|
652
|
-
opacity: prop("opacity", (
|
|
653
|
-
width: prop("width", (
|
|
654
|
-
style: prop("borderStyle", (
|
|
655
|
-
dash: prop("dash", (
|
|
656
|
-
rect: prop("rect", (
|
|
657
|
-
contents: prop("contents", (
|
|
670
|
+
opacity: prop("opacity", (value) => isNum(value) && Number(value) >= 0 && Number(value) <= 1),
|
|
671
|
+
width: prop("width", (value) => isNum(value) && Number(value) >= 0),
|
|
672
|
+
style: prop("borderStyle", (value) => value === "S" || value === "D"),
|
|
673
|
+
dash: prop("dash", (value) => Array.isArray(value) && value.every(isNum)),
|
|
674
|
+
rect: prop("rect", (value) => Array.isArray(value) && value.length === 4 && value.every(isNum)),
|
|
675
|
+
contents: prop("contents", (value) => typeof value === "string"),
|
|
658
676
|
hidden: prop("hidden", isBool),
|
|
659
677
|
print: prop("print", isBool),
|
|
660
678
|
readOnly: prop("readOnly", isBool),
|
|
@@ -872,30 +890,30 @@ function installAcroJs(g) {
|
|
|
872
890
|
});
|
|
873
891
|
const fieldsByName = new Map(fields.map((field) => [String(field.input.name), field]));
|
|
874
892
|
const fieldsByRef = new Map(fields.map((field) => [refKey(field.input.ref), field]));
|
|
875
|
-
const annots = (input.annots ?? []).map((
|
|
893
|
+
const annots = (input.annots ?? []).map((annotation) => {
|
|
876
894
|
const writableSnapshot = () => ({
|
|
877
|
-
strokeColor: cloneAnnotValue(
|
|
878
|
-
fillColor: cloneAnnotValue(
|
|
879
|
-
opacity: Number(
|
|
880
|
-
width: Number(
|
|
881
|
-
borderStyle: String(
|
|
882
|
-
dash: cloneAnnotValue(
|
|
883
|
-
rect: cloneAnnotValue(
|
|
895
|
+
strokeColor: cloneAnnotValue(annotation.strokeColor ?? ["T"]),
|
|
896
|
+
fillColor: cloneAnnotValue(annotation.fillColor ?? ["T"]),
|
|
897
|
+
opacity: Number(annotation.opacity ?? 1),
|
|
898
|
+
width: Number(annotation.width ?? 1),
|
|
899
|
+
borderStyle: String(annotation.borderStyle ?? "S"),
|
|
900
|
+
dash: cloneAnnotValue(annotation.dash ?? []),
|
|
901
|
+
rect: cloneAnnotValue(annotation.rect ?? [
|
|
884
902
|
0,
|
|
885
903
|
0,
|
|
886
904
|
0,
|
|
887
905
|
0
|
|
888
906
|
]),
|
|
889
|
-
contents: String(
|
|
890
|
-
hidden: Boolean(
|
|
891
|
-
print: Boolean(
|
|
892
|
-
readOnly: Boolean(
|
|
893
|
-
locked: Boolean(
|
|
894
|
-
noView: Boolean(
|
|
895
|
-
toggleNoView: Boolean(
|
|
907
|
+
contents: String(annotation.contents ?? ""),
|
|
908
|
+
hidden: Boolean(annotation.hidden),
|
|
909
|
+
print: Boolean(annotation.print),
|
|
910
|
+
readOnly: Boolean(annotation.readOnly),
|
|
911
|
+
locked: Boolean(annotation.locked),
|
|
912
|
+
noView: Boolean(annotation.noView),
|
|
913
|
+
toggleNoView: Boolean(annotation.toggleNoView)
|
|
896
914
|
});
|
|
897
915
|
const record = {
|
|
898
|
-
input:
|
|
916
|
+
input: annotation,
|
|
899
917
|
original: writableSnapshot(),
|
|
900
918
|
current: writableSnapshot(),
|
|
901
919
|
wrapper: {}
|
|
@@ -952,22 +970,17 @@ function installAcroJs(g) {
|
|
|
952
970
|
};
|
|
953
971
|
const formValue = (field, value) => {
|
|
954
972
|
const family = String(field.input.family);
|
|
955
|
-
if (family === "text") return {
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
};
|
|
967
|
-
if (family === "listbox") return {
|
|
968
|
-
type: "choice",
|
|
969
|
-
values: Array.isArray(value) ? value.map(String) : [String(value ?? "")]
|
|
970
|
-
};
|
|
973
|
+
if (family === "text") return { value: String(value ?? "") };
|
|
974
|
+
if (family === "checkbox" || family === "radio") return { value: value === null || value === void 0 || String(value) === "Off" ? null : String(value) };
|
|
975
|
+
if (family === "combobox") {
|
|
976
|
+
const selected = Array.isArray(value) ? value[0] : value;
|
|
977
|
+
const text = selected === null || selected === void 0 ? "" : String(selected);
|
|
978
|
+
return { value: text === "" ? null : text };
|
|
979
|
+
}
|
|
980
|
+
if (family === "listbox") {
|
|
981
|
+
if (Array.isArray(value)) return { selectedValues: value.map(String) };
|
|
982
|
+
return { selectedValues: value === null || value === void 0 || value === "" ? [] : [String(value)] };
|
|
983
|
+
}
|
|
971
984
|
diagnostic("invalid-field-value", `field '${String(field.input.name)}' cannot accept a scripted value`);
|
|
972
985
|
return null;
|
|
973
986
|
};
|
|
@@ -1158,23 +1171,23 @@ function installAcroJs(g) {
|
|
|
1158
1171
|
rgb[2]
|
|
1159
1172
|
];
|
|
1160
1173
|
if (target === "CMYK") {
|
|
1161
|
-
const
|
|
1174
|
+
const black = 1 - Math.max(rgb[0], rgb[1], rgb[2]);
|
|
1162
1175
|
return [
|
|
1163
1176
|
"CMYK",
|
|
1164
|
-
1 - rgb[0] -
|
|
1165
|
-
1 - rgb[1] -
|
|
1166
|
-
1 - rgb[2] -
|
|
1167
|
-
|
|
1177
|
+
1 - rgb[0] - black,
|
|
1178
|
+
1 - rgb[1] - black,
|
|
1179
|
+
1 - rgb[2] - black,
|
|
1180
|
+
black
|
|
1168
1181
|
];
|
|
1169
1182
|
}
|
|
1170
1183
|
return ["T"];
|
|
1171
1184
|
},
|
|
1172
|
-
equal: (
|
|
1173
|
-
if (!isColorArray(
|
|
1174
|
-
const
|
|
1175
|
-
const
|
|
1176
|
-
if (
|
|
1177
|
-
return
|
|
1185
|
+
equal: (left, right) => {
|
|
1186
|
+
if (!isColorArray(left) || !isColorArray(right)) return false;
|
|
1187
|
+
const leftRgb = colorToRgbTriple(left);
|
|
1188
|
+
const rightRgb = colorToRgbTriple(right);
|
|
1189
|
+
if (leftRgb === null || rightRgb === null) return leftRgb === rightRgb;
|
|
1190
|
+
return leftRgb.every((component, index) => Math.abs(component - rightRgb[index]) < 1e-6);
|
|
1178
1191
|
}
|
|
1179
1192
|
});
|
|
1180
1193
|
host.getField = getField;
|
|
@@ -1222,7 +1235,7 @@ function installAcroJs(g) {
|
|
|
1222
1235
|
host.AFSimple_Calculate = (operation, names) => {
|
|
1223
1236
|
const values = (Array.isArray(names) ? names : String(names).split(",")).map((name) => numberValue(getField(String(name).trim())?.value));
|
|
1224
1237
|
const op = String(operation).toUpperCase();
|
|
1225
|
-
const value = values.length === 0 ? 0 : op === "PRD" ? values.reduce((
|
|
1238
|
+
const value = values.length === 0 ? 0 : op === "PRD" ? values.reduce((left, right) => left * right, 1) : op === "AVG" ? values.reduce((left, right) => left + right, 0) / values.length : op === "MIN" ? Math.min(...values) : op === "MAX" ? Math.max(...values) : values.reduce((left, right) => left + right, 0);
|
|
1226
1239
|
if (state) state.event.value = value;
|
|
1227
1240
|
};
|
|
1228
1241
|
host.AFNumber_Format = (decimals, separatorStyle, _negativeStyle, _currencyStyle, currency, prepend) => {
|
|
@@ -1275,12 +1288,12 @@ function installAcroJs(g) {
|
|
|
1275
1288
|
const formatMismatch = () => rejectWithAlert(`The value entered does not match the format of the field [ ${String(state?.event.targetName ?? "")} ]`);
|
|
1276
1289
|
const dateMismatch = (format) => rejectWithAlert(`Invalid date/time: please ensure that the date/time exists. Field [ ${String(state?.event.targetName ?? "")} ] should match format ${String(format ?? "")}`);
|
|
1277
1290
|
const mergeChange = (eventObject) => {
|
|
1278
|
-
const
|
|
1279
|
-
const value = String(
|
|
1280
|
-
if (
|
|
1281
|
-
const start = Math.max(0, Math.trunc(Number(
|
|
1282
|
-
const end = Math.max(start, Math.trunc(Number(
|
|
1283
|
-
return value.slice(0, start) + String(
|
|
1291
|
+
const event = eventObject ?? state?.event ?? {};
|
|
1292
|
+
const value = String(event.value ?? "");
|
|
1293
|
+
if (event.willCommit) return value;
|
|
1294
|
+
const start = Math.max(0, Math.trunc(Number(event.selStart ?? 0)));
|
|
1295
|
+
const end = Math.max(start, Math.trunc(Number(event.selEnd ?? 0)));
|
|
1296
|
+
return value.slice(0, start) + String(event.change ?? "") + value.slice(end);
|
|
1284
1297
|
};
|
|
1285
1298
|
host.AFMergeChange = mergeChange;
|
|
1286
1299
|
const makeNumber = (value) => {
|
|
@@ -1375,17 +1388,17 @@ function installAcroJs(g) {
|
|
|
1375
1388
|
break;
|
|
1376
1389
|
}
|
|
1377
1390
|
const timeMatch = /(\d{1,2}):(\d{2})(?::(\d{2}))?\s*(am|pm)?/i.exec(text);
|
|
1378
|
-
let
|
|
1379
|
-
let
|
|
1380
|
-
let
|
|
1391
|
+
let hours = 0;
|
|
1392
|
+
let minutes = 0;
|
|
1393
|
+
let seconds = 0;
|
|
1381
1394
|
if (timeMatch) {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1395
|
+
hours = Number(timeMatch[1]);
|
|
1396
|
+
minutes = Number(timeMatch[2]);
|
|
1397
|
+
seconds = Number(timeMatch[3] ?? 0);
|
|
1385
1398
|
const marker = String(timeMatch[4] ?? "").toLowerCase();
|
|
1386
|
-
if (marker === "pm" &&
|
|
1387
|
-
if (marker === "am" &&
|
|
1388
|
-
if (
|
|
1399
|
+
if (marker === "pm" && hours < 12) hours += 12;
|
|
1400
|
+
if (marker === "am" && hours === 12) hours = 0;
|
|
1401
|
+
if (hours > 23 || minutes > 59 || seconds > 59) return null;
|
|
1389
1402
|
}
|
|
1390
1403
|
const numbers = ((timeMatch ? text.slice(0, timeMatch.index) + text.slice(timeMatch.index + timeMatch[0].length) : text).match(/\d+/g) ?? []).map((token) => Number(token));
|
|
1391
1404
|
const order = [];
|
|
@@ -1393,35 +1406,35 @@ function installAcroJs(g) {
|
|
|
1393
1406
|
const kind = token[0] === "y" ? "y" : token[0] === "m" ? "m" : "d";
|
|
1394
1407
|
if (order.indexOf(kind) < 0) order.push(kind);
|
|
1395
1408
|
}
|
|
1396
|
-
let
|
|
1397
|
-
let
|
|
1398
|
-
let
|
|
1409
|
+
let year = null;
|
|
1410
|
+
let month = namedMonth;
|
|
1411
|
+
let day = null;
|
|
1399
1412
|
let cursor = 0;
|
|
1400
1413
|
for (const kind of order) {
|
|
1401
1414
|
if (kind === "m" && namedMonth !== null) continue;
|
|
1402
1415
|
if (cursor >= numbers.length) break;
|
|
1403
1416
|
const value = numbers[cursor];
|
|
1404
1417
|
cursor += 1;
|
|
1405
|
-
if (kind === "y")
|
|
1406
|
-
else if (kind === "m")
|
|
1407
|
-
else
|
|
1418
|
+
if (kind === "y") year = value;
|
|
1419
|
+
else if (kind === "m") month = value;
|
|
1420
|
+
else day = value;
|
|
1408
1421
|
}
|
|
1409
|
-
if (
|
|
1422
|
+
if (year === null && month === null && day === null && !timeMatch) return null;
|
|
1410
1423
|
const today = nowWall();
|
|
1411
|
-
if (
|
|
1412
|
-
else if (
|
|
1413
|
-
if (
|
|
1414
|
-
if (
|
|
1415
|
-
if (
|
|
1416
|
-
const probe = new NativeDate(NativeDate.UTC(
|
|
1417
|
-
if (probe.getUTCFullYear() !==
|
|
1424
|
+
if (year === null) year = today.y;
|
|
1425
|
+
else if (year < 100) year = year < 50 ? 2e3 + year : 1900 + year;
|
|
1426
|
+
if (month === null) month = today.m;
|
|
1427
|
+
if (day === null) day = 1;
|
|
1428
|
+
if (month < 1 || month > 12 || day < 1 || day > 31) return null;
|
|
1429
|
+
const probe = new NativeDate(NativeDate.UTC(year, month - 1, day));
|
|
1430
|
+
if (probe.getUTCFullYear() !== year || probe.getUTCMonth() !== month - 1 || probe.getUTCDate() !== day) return null;
|
|
1418
1431
|
return {
|
|
1419
|
-
y,
|
|
1420
|
-
m,
|
|
1421
|
-
d,
|
|
1422
|
-
H,
|
|
1423
|
-
M,
|
|
1424
|
-
S
|
|
1432
|
+
y: year,
|
|
1433
|
+
m: month,
|
|
1434
|
+
d: day,
|
|
1435
|
+
H: hours,
|
|
1436
|
+
M: minutes,
|
|
1437
|
+
S: seconds
|
|
1425
1438
|
};
|
|
1426
1439
|
};
|
|
1427
1440
|
const afDateFormatEx = (format) => {
|