@sushichan044/kg-core 0.3.0 → 0.4.1
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/README.md +6 -5
- package/dist/index.d.mts +208 -201
- package/dist/index.mjs +247 -55
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -513,17 +513,9 @@ function parseManuscript(source, options = {}) {
|
|
|
513
513
|
});
|
|
514
514
|
}
|
|
515
515
|
//#endregion
|
|
516
|
-
//#region src/parser/internal/
|
|
517
|
-
function trimContent(text, sourceStart) {
|
|
518
|
-
const trimmedStart = text.trimStart();
|
|
519
|
-
const leadingLength = text.length - trimmedStart.length;
|
|
520
|
-
return {
|
|
521
|
-
text: trimmedStart.trimEnd(),
|
|
522
|
-
sourceStart: sourceStart + leadingLength
|
|
523
|
-
};
|
|
524
|
-
}
|
|
516
|
+
//#region src/parser/internal/line-end.ts
|
|
525
517
|
/**
|
|
526
|
-
*
|
|
518
|
+
* Returns the first line terminator at or after start. Both halves of CRLF remain outside the line.
|
|
527
519
|
*/
|
|
528
520
|
function lineEnd(source, start) {
|
|
529
521
|
const lf = source.indexOf("\n", start);
|
|
@@ -532,6 +524,249 @@ function lineEnd(source, start) {
|
|
|
532
524
|
if (cr === -1) return lf;
|
|
533
525
|
return Math.min(lf, cr);
|
|
534
526
|
}
|
|
527
|
+
//#endregion
|
|
528
|
+
//#region src/parser/internal/notation-warning.ts
|
|
529
|
+
function firstCoveredIndex(manuscript, start) {
|
|
530
|
+
let low = 0;
|
|
531
|
+
let high = manuscript.graphemes.length;
|
|
532
|
+
while (low < high) {
|
|
533
|
+
const middle = Math.floor((low + high) / 2);
|
|
534
|
+
const grapheme = manuscript.graphemes[middle];
|
|
535
|
+
if (grapheme === void 0) return manuscript.graphemes.length;
|
|
536
|
+
if (grapheme.range.source.end <= start) low = middle + 1;
|
|
537
|
+
else high = middle;
|
|
538
|
+
}
|
|
539
|
+
return low;
|
|
540
|
+
}
|
|
541
|
+
function lastCoveredIndex(manuscript, end) {
|
|
542
|
+
let low = 0;
|
|
543
|
+
let high = manuscript.graphemes.length;
|
|
544
|
+
while (low < high) {
|
|
545
|
+
const middle = Math.floor((low + high) / 2);
|
|
546
|
+
const grapheme = manuscript.graphemes[middle];
|
|
547
|
+
if (grapheme === void 0) return -1;
|
|
548
|
+
if (grapheme.range.source.start < end) low = middle + 1;
|
|
549
|
+
else high = middle;
|
|
550
|
+
}
|
|
551
|
+
return low - 1;
|
|
552
|
+
}
|
|
553
|
+
function spanRange(manuscript, span) {
|
|
554
|
+
const first = manuscript.graphemes[firstCoveredIndex(manuscript, span.start)];
|
|
555
|
+
const last = manuscript.graphemes[lastCoveredIndex(manuscript, span.end)];
|
|
556
|
+
if (first === void 0 || last === void 0 || first.range.source.start >= span.end || last.range.source.end <= span.start) return ManuscriptRange.of({
|
|
557
|
+
source: span,
|
|
558
|
+
display: {
|
|
559
|
+
start: 0,
|
|
560
|
+
end: 0
|
|
561
|
+
},
|
|
562
|
+
graphemes: {
|
|
563
|
+
start: 0,
|
|
564
|
+
end: 0
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
return ManuscriptRange.of({
|
|
568
|
+
source: span,
|
|
569
|
+
display: {
|
|
570
|
+
start: first.range.display.start,
|
|
571
|
+
end: last.range.display.end
|
|
572
|
+
},
|
|
573
|
+
graphemes: {
|
|
574
|
+
start: first.range.graphemes.start,
|
|
575
|
+
end: last.range.graphemes.end
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
function unrecognizedNotationWarnings(source, parserId, manuscript, spans) {
|
|
580
|
+
return spans.map((span, order) => ManuscriptDiagnostic.of({
|
|
581
|
+
source,
|
|
582
|
+
origin: {
|
|
583
|
+
kind: "parser",
|
|
584
|
+
id: parserId
|
|
585
|
+
},
|
|
586
|
+
severity: "warning",
|
|
587
|
+
code: `unrecognized-notation-${order}`,
|
|
588
|
+
message: "認識できない記法を原文として扱いました",
|
|
589
|
+
range: spanRange(manuscript, span)
|
|
590
|
+
}));
|
|
591
|
+
}
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region src/parser/kakuyomu-parser.ts
|
|
594
|
+
const PARSER_ID$1 = NamespacedId.of("kg/kakuyomu");
|
|
595
|
+
const MAX_BASE_GRAPHEMES = 20;
|
|
596
|
+
const MAX_READING_GRAPHEMES = 50;
|
|
597
|
+
const HAN = /^\p{Script=Han}$/u;
|
|
598
|
+
function graphemeLength(text) {
|
|
599
|
+
return [...graphemeSegmenter.segment(text)].length;
|
|
600
|
+
}
|
|
601
|
+
function validRuby(parent, reading) {
|
|
602
|
+
return parent.length > 0 && reading.length > 0 && !parent.includes("《") && !parent.includes("》") && !reading.includes("《") && !reading.includes("》") && graphemeLength(parent) <= MAX_BASE_GRAPHEMES && graphemeLength(reading) <= MAX_READING_GRAPHEMES;
|
|
603
|
+
}
|
|
604
|
+
function parseRuby(source, parentStart, parentEnd, opening) {
|
|
605
|
+
const endOfLine = lineEnd(source, opening);
|
|
606
|
+
const closing = source.indexOf("》", opening + 1);
|
|
607
|
+
if (closing === -1 || closing >= endOfLine) return void 0;
|
|
608
|
+
const parent = source.slice(parentStart, parentEnd);
|
|
609
|
+
const reading = source.slice(opening + 1, closing);
|
|
610
|
+
if (!validRuby(parent, reading)) return void 0;
|
|
611
|
+
return {
|
|
612
|
+
parentStart,
|
|
613
|
+
parentEnd,
|
|
614
|
+
reading,
|
|
615
|
+
end: closing + 1
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function parseExplicitRuby(source, start) {
|
|
619
|
+
const endOfLine = lineEnd(source, start + 1);
|
|
620
|
+
const opening = source.indexOf("《", start + 1);
|
|
621
|
+
if (opening === -1 || opening >= endOfLine) return void 0;
|
|
622
|
+
return parseRuby(source, start + 1, opening, opening);
|
|
623
|
+
}
|
|
624
|
+
function parseEmphasis(source, start) {
|
|
625
|
+
const endOfLine = lineEnd(source, start + 2);
|
|
626
|
+
const closing = source.indexOf("》》", start + 2);
|
|
627
|
+
if (closing === -1 || closing >= endOfLine) return void 0;
|
|
628
|
+
const content = source.slice(start + 2, closing);
|
|
629
|
+
if (content.length === 0 || content.includes("《") || content.includes("》")) return void 0;
|
|
630
|
+
return {
|
|
631
|
+
contentStart: start + 2,
|
|
632
|
+
contentEnd: closing,
|
|
633
|
+
end: closing + 2
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function codePointLength(source, index) {
|
|
637
|
+
const codePoint = source.codePointAt(index);
|
|
638
|
+
return codePoint === void 0 || codePoint <= 65535 ? 1 : 2;
|
|
639
|
+
}
|
|
640
|
+
function isHanAt(source, index) {
|
|
641
|
+
return HAN.test(source.slice(index, index + codePointLength(source, index)));
|
|
642
|
+
}
|
|
643
|
+
function invalidNotationEnd(source, start) {
|
|
644
|
+
return lineEnd(source, start + 1);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Understands Kakuyomu's ruby and emphasis-mark notation. Invalid notation stays literal so source
|
|
648
|
+
* ranges remain inspectable, while clear notation candidates receive a parser warning.
|
|
649
|
+
*/
|
|
650
|
+
const kakuyomuParser = {
|
|
651
|
+
id: PARSER_ID$1,
|
|
652
|
+
parse: (source) => {
|
|
653
|
+
const draft = createManuscriptDraft(source);
|
|
654
|
+
const unrecognized = [];
|
|
655
|
+
let index = 0;
|
|
656
|
+
let literalStart = 0;
|
|
657
|
+
let hanRunStart = -1;
|
|
658
|
+
const appendBefore = (end) => {
|
|
659
|
+
if (literalStart < end) draft.append(source.slice(literalStart, end), literalStart);
|
|
660
|
+
};
|
|
661
|
+
const appendNotationWarning = (start, end) => {
|
|
662
|
+
unrecognized.push({
|
|
663
|
+
start,
|
|
664
|
+
end
|
|
665
|
+
});
|
|
666
|
+
};
|
|
667
|
+
while (index < source.length) {
|
|
668
|
+
const character = source[index];
|
|
669
|
+
if (character === "|" || character === "|") {
|
|
670
|
+
if (source[index + 1] === "《") {
|
|
671
|
+
appendBefore(index);
|
|
672
|
+
draft.append("《", index + 1);
|
|
673
|
+
index += 2;
|
|
674
|
+
literalStart = index;
|
|
675
|
+
hanRunStart = -1;
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
const ruby = parseExplicitRuby(source, index);
|
|
679
|
+
if (ruby !== void 0) {
|
|
680
|
+
appendBefore(index);
|
|
681
|
+
const range = draft.append(source.slice(ruby.parentStart, ruby.parentEnd), ruby.parentStart);
|
|
682
|
+
draft.annotate({
|
|
683
|
+
kind: "ruby",
|
|
684
|
+
reading: ruby.reading,
|
|
685
|
+
range: {
|
|
686
|
+
...range,
|
|
687
|
+
source: {
|
|
688
|
+
start: index,
|
|
689
|
+
end: ruby.end
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
index = ruby.end;
|
|
694
|
+
literalStart = index;
|
|
695
|
+
hanRunStart = -1;
|
|
696
|
+
continue;
|
|
697
|
+
}
|
|
698
|
+
const opening = source.indexOf("《", index + 1);
|
|
699
|
+
if (opening !== -1 && opening < lineEnd(source, index + 1)) {
|
|
700
|
+
const end = invalidNotationEnd(source, index);
|
|
701
|
+
appendNotationWarning(index, end);
|
|
702
|
+
index = end;
|
|
703
|
+
hanRunStart = -1;
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (character === "《") {
|
|
708
|
+
const emphasis = source.startsWith("《《", index) ? parseEmphasis(source, index) : void 0;
|
|
709
|
+
if (emphasis !== void 0) {
|
|
710
|
+
appendBefore(index);
|
|
711
|
+
const range = draft.append(source.slice(emphasis.contentStart, emphasis.contentEnd), emphasis.contentStart);
|
|
712
|
+
draft.annotate({
|
|
713
|
+
kind: "emphasis",
|
|
714
|
+
mark: "・",
|
|
715
|
+
range: {
|
|
716
|
+
...range,
|
|
717
|
+
source: {
|
|
718
|
+
start: index,
|
|
719
|
+
end: emphasis.end
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
index = emphasis.end;
|
|
724
|
+
literalStart = index;
|
|
725
|
+
hanRunStart = -1;
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
const ruby = hanRunStart === -1 ? void 0 : parseRuby(source, hanRunStart, index, index);
|
|
729
|
+
if (ruby !== void 0) {
|
|
730
|
+
appendBefore(hanRunStart);
|
|
731
|
+
const range = draft.append(source.slice(ruby.parentStart, ruby.parentEnd), ruby.parentStart);
|
|
732
|
+
draft.annotate({
|
|
733
|
+
kind: "ruby",
|
|
734
|
+
reading: ruby.reading,
|
|
735
|
+
range: {
|
|
736
|
+
...range,
|
|
737
|
+
source: {
|
|
738
|
+
start: ruby.parentStart,
|
|
739
|
+
end: ruby.end
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
index = ruby.end;
|
|
744
|
+
literalStart = index;
|
|
745
|
+
hanRunStart = -1;
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
if (source.startsWith("《《", index) || hanRunStart !== -1) appendNotationWarning(hanRunStart === -1 ? index : hanRunStart, invalidNotationEnd(source, index));
|
|
749
|
+
hanRunStart = -1;
|
|
750
|
+
} else if (isHanAt(source, index)) {
|
|
751
|
+
if (hanRunStart === -1) hanRunStart = index;
|
|
752
|
+
} else hanRunStart = -1;
|
|
753
|
+
index += codePointLength(source, index);
|
|
754
|
+
}
|
|
755
|
+
appendBefore(source.length);
|
|
756
|
+
const manuscript = draft.build();
|
|
757
|
+
return ManuscriptResult.succeed(manuscript, unrecognizedNotationWarnings(source, PARSER_ID$1, manuscript, unrecognized));
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
//#endregion
|
|
761
|
+
//#region src/parser/internal/pixiv-notation.ts
|
|
762
|
+
function trimContent(text, sourceStart) {
|
|
763
|
+
const trimmedStart = text.trimStart();
|
|
764
|
+
const leadingLength = text.length - trimmedStart.length;
|
|
765
|
+
return {
|
|
766
|
+
text: trimmedStart.trimEnd(),
|
|
767
|
+
sourceStart: sourceStart + leadingLength
|
|
768
|
+
};
|
|
769
|
+
}
|
|
535
770
|
function closingIndex(source, start, closing) {
|
|
536
771
|
const end = source.indexOf(closing, start);
|
|
537
772
|
return end !== -1 && end < lineEnd(source, start) ? end : void 0;
|
|
@@ -607,49 +842,6 @@ function literalEnd(source, start) {
|
|
|
607
842
|
//#region src/parser/pixiv-parser.ts
|
|
608
843
|
const PARSER_ID = NamespacedId.of("kg/pixiv");
|
|
609
844
|
/**
|
|
610
|
-
* Locates an unrecognised source span in display and grapheme coordinates for the warning.
|
|
611
|
-
*/
|
|
612
|
-
function spanRange(manuscript, span) {
|
|
613
|
-
const covered = manuscript.graphemes.filter(({ range }) => range.source.start < span.end && range.source.end > span.start);
|
|
614
|
-
const first = covered[0];
|
|
615
|
-
const last = covered.at(-1);
|
|
616
|
-
if (first === void 0 || last === void 0) return ManuscriptRange.of({
|
|
617
|
-
source: span,
|
|
618
|
-
display: {
|
|
619
|
-
start: 0,
|
|
620
|
-
end: 0
|
|
621
|
-
},
|
|
622
|
-
graphemes: {
|
|
623
|
-
start: 0,
|
|
624
|
-
end: 0
|
|
625
|
-
}
|
|
626
|
-
});
|
|
627
|
-
return ManuscriptRange.of({
|
|
628
|
-
source: span,
|
|
629
|
-
display: {
|
|
630
|
-
start: first.range.display.start,
|
|
631
|
-
end: last.range.display.end
|
|
632
|
-
},
|
|
633
|
-
graphemes: {
|
|
634
|
-
start: first.range.graphemes.start,
|
|
635
|
-
end: last.range.graphemes.end
|
|
636
|
-
}
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
function unrecognizedNotationWarning(source, manuscript, span, index) {
|
|
640
|
-
return ManuscriptDiagnostic.of({
|
|
641
|
-
source,
|
|
642
|
-
origin: {
|
|
643
|
-
kind: "parser",
|
|
644
|
-
id: PARSER_ID
|
|
645
|
-
},
|
|
646
|
-
severity: "warning",
|
|
647
|
-
code: `unrecognized-notation-${index}`,
|
|
648
|
-
message: "認識できない記法を原文として扱いました",
|
|
649
|
-
range: spanRange(manuscript, span)
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
/**
|
|
653
845
|
* Understands Pixiv's ruby, bold, italic and emphasis-mark notation. Anything bracket-shaped that
|
|
654
846
|
* does not parse is kept as literal text and reported as a warning rather than dropped.
|
|
655
847
|
*/
|
|
@@ -692,7 +884,7 @@ const pixivParser = {
|
|
|
692
884
|
index = end;
|
|
693
885
|
}
|
|
694
886
|
const manuscript = draft.build();
|
|
695
|
-
return ManuscriptResult.succeed(manuscript,
|
|
887
|
+
return ManuscriptResult.succeed(manuscript, unrecognizedNotationWarnings(source, PARSER_ID, manuscript, unrecognized));
|
|
696
888
|
}
|
|
697
889
|
};
|
|
698
890
|
//#endregion
|
|
@@ -1497,4 +1689,4 @@ function createDefaultProofreadingRules() {
|
|
|
1497
1689
|
];
|
|
1498
1690
|
}
|
|
1499
1691
|
//#endregion
|
|
1500
|
-
export { BoldAnnotation, ComposeError, CompositionStatistics, DiagnosticOrigin, DiagnosticSeverity, DisplayRange, EmphasisAnnotation, FontPreset, FontPresetId, FontSizePt, GraphemeRange, GridCell, GridLine, GridPage, GridSettings, GridStage, InvalidRuleOptions, ItalicAnnotation, LineOffset, ManuscriptAnnotation, ManuscriptAppearanceSettings, ManuscriptCompositionSettings, ManuscriptDiagnostic, ManuscriptGeometry, ManuscriptGridLayout, ManuscriptOffsets, ManuscriptRange, ManuscriptResult, NamespacedId, PaperSize, PaperSizeId, ParseError, ParsedGrapheme, ParsedManuscript, ProofreadError, ProofreadingReport, ProofreadingRuleMeta, Rejection, RubyAnnotation, SourcePosition, SourceRange, TextRange, ValidationIssue, assertNever, composeManuscript, createDefaultProofreadingRules, createMaxArabicNumeralDigitsRule, createParagraphLeadingCharacterRule, evenDashRule, evenEllipsisRule, manuscriptGridComposer, maxArabicNumeralDigitsRule, minusBeforeNumberRule, mmToPt, noConsecutiveChoonpuRule, noConsecutiveInterpunctRule, noConsecutivePunctuationRule, paragraphLeadingCharacterRule, parseManuscript, pixivParser, plainTextParser, proofreadManuscript, ptToMm, punctuationBeforeClosingQuoteRule, spaceAfterQuestionOrExclamationRule, variantCharacterRule };
|
|
1692
|
+
export { BoldAnnotation, ComposeError, CompositionStatistics, DiagnosticOrigin, DiagnosticSeverity, DisplayRange, EmphasisAnnotation, FontPreset, FontPresetId, FontSizePt, GraphemeRange, GridCell, GridLine, GridPage, GridSettings, GridStage, InvalidRuleOptions, ItalicAnnotation, LineOffset, ManuscriptAnnotation, ManuscriptAppearanceSettings, ManuscriptCompositionSettings, ManuscriptDiagnostic, ManuscriptGeometry, ManuscriptGridLayout, ManuscriptOffsets, ManuscriptRange, ManuscriptResult, NamespacedId, PaperSize, PaperSizeId, ParseError, ParsedGrapheme, ParsedManuscript, ProofreadError, ProofreadingReport, ProofreadingRuleMeta, Rejection, RubyAnnotation, SourcePosition, SourceRange, TextRange, ValidationIssue, assertNever, composeManuscript, createDefaultProofreadingRules, createMaxArabicNumeralDigitsRule, createParagraphLeadingCharacterRule, evenDashRule, evenEllipsisRule, kakuyomuParser, manuscriptGridComposer, maxArabicNumeralDigitsRule, minusBeforeNumberRule, mmToPt, noConsecutiveChoonpuRule, noConsecutiveInterpunctRule, noConsecutivePunctuationRule, paragraphLeadingCharacterRule, parseManuscript, pixivParser, plainTextParser, proofreadManuscript, ptToMm, punctuationBeforeClosingQuoteRule, spaceAfterQuestionOrExclamationRule, variantCharacterRule };
|