155 lines
5.1 KiB
JavaScript
155 lines
5.1 KiB
JavaScript
import {
|
||
Document,
|
||
Paragraph,
|
||
TextRun,
|
||
CommentRangeStart,
|
||
CommentRangeEnd,
|
||
CommentReference,
|
||
LevelFormat,
|
||
LevelSuffix,
|
||
AlignmentType,
|
||
Packer
|
||
} from 'docx';
|
||
import JSZip from 'jszip';
|
||
import fs from 'fs';
|
||
|
||
function htmlToPlainText(html) {
|
||
return String(html || '')
|
||
.replace(/ /g, ' ')
|
||
.replace(/<br\s*\/?>/gi, ' ')
|
||
.replace(/<[^>]*>/g, '')
|
||
.replace(/\s+/g, ' ')
|
||
.trim();
|
||
}
|
||
|
||
function parseSingleAuthorName(nameStr) {
|
||
const token = String(nameStr || '').trim();
|
||
if (!token || /^et al\.?$/i.test(token)) return null;
|
||
const parts = token.split(/\s+/).filter(Boolean);
|
||
if (!parts.length) return null;
|
||
if (parts.length === 1) return { first: '', last: parts[0] };
|
||
return { first: parts.slice(0, -1).join(' '), last: parts[parts.length - 1] };
|
||
}
|
||
|
||
function firstNameToAmaInitials(first) {
|
||
return String(first || '')
|
||
.split(/[\s-]+/)
|
||
.filter(Boolean)
|
||
.map((part) => part.charAt(0).toUpperCase())
|
||
.join('');
|
||
}
|
||
|
||
function formatOneAmaAuthor(nameStr) {
|
||
const parsed = parseSingleAuthorName(nameStr);
|
||
if (!parsed || !parsed.last) return '';
|
||
const initials = firstNameToAmaInitials(parsed.first);
|
||
return initials ? parsed.last + ' ' + initials : parsed.last;
|
||
}
|
||
|
||
function splitAuthorList(authorText) {
|
||
return String(authorText || '')
|
||
.split(/\s*,\s*/)
|
||
.map((part) => part.trim())
|
||
.filter(Boolean);
|
||
}
|
||
|
||
function isAmaAbbreviatedAuthorList(authorText) {
|
||
const authors = splitAuthorList(htmlToPlainText(authorText));
|
||
if (!authors.length) return true;
|
||
return authors.every((token) => {
|
||
if (/^et al\.?$/i.test(token)) return true;
|
||
return /^[\p{L}][\p{L}\-'']*\s+[A-Z](?:-?[A-Z])*\.?$/u.test(token);
|
||
});
|
||
}
|
||
|
||
function needsAmaAuthorAbbreviation(authorText) {
|
||
const plain = htmlToPlainText(authorText).trim();
|
||
if (!plain || isAmaAbbreviatedAuthorList(plain)) return false;
|
||
return splitAuthorList(plain).some((token) => {
|
||
const parts = token.split(/\s+/).filter(Boolean);
|
||
if (parts.length < 2) return false;
|
||
return parts[0].length > 2;
|
||
});
|
||
}
|
||
|
||
function buildAmaAuthorAbbreviation(authorText) {
|
||
const authors = splitAuthorList(htmlToPlainText(authorText));
|
||
return authors
|
||
.map((token) => (/^et al\.?$/i.test(token) ? 'et al' : formatOneAmaAuthor(token)))
|
||
.filter(Boolean)
|
||
.join(', ');
|
||
}
|
||
|
||
function buildBookAmaAuthorComment(ref) {
|
||
if (!ref || ref.refer_type !== 'book') return '';
|
||
const authorSource = ref.author ? htmlToPlainText(ref.author) : '';
|
||
if (!authorSource || !needsAmaAuthorAbbreviation(authorSource)) return '';
|
||
const amaAuthors = buildAmaAuthorAbbreviation(authorSource);
|
||
return amaAuthors ? 'AMA格式作者缩写:' + amaAuthors : '';
|
||
}
|
||
|
||
const ref = {
|
||
refer_type: 'book',
|
||
author: 'Jacqueline Fawcett, Susan DeSanto-Madeya',
|
||
title: 'Contemporary Nursing Knowledge',
|
||
dateno: '(3rd Edition). Philadelphia, PA: F. A. Davis Company; 2013.',
|
||
isbn: '978-0-8036-2765-9'
|
||
};
|
||
|
||
const commentText = buildBookAmaAuthorComment(ref);
|
||
console.log('comment text:', commentText);
|
||
|
||
const commentId = 0;
|
||
const doc = new Document({
|
||
numbering: {
|
||
config: [{
|
||
reference: 'ref-num',
|
||
levels: [{
|
||
level: 0,
|
||
format: LevelFormat.DECIMAL,
|
||
text: '%1.',
|
||
alignment: AlignmentType.START,
|
||
suffix: LevelSuffix.TAB,
|
||
style: { paragraph: { indent: { left: 720, hanging: 360 } } }
|
||
}]
|
||
}]
|
||
},
|
||
comments: {
|
||
children: [{
|
||
id: commentId,
|
||
author: 'Editor',
|
||
initials: 'Ed',
|
||
date: new Date(),
|
||
children: [new Paragraph({ children: [new TextRun(commentText)] })]
|
||
}]
|
||
},
|
||
sections: [{
|
||
children: [new Paragraph({
|
||
numbering: { reference: 'ref-num', level: 0 },
|
||
children: [
|
||
new CommentRangeStart(commentId),
|
||
new TextRun('Jacqueline Fawcett, Susan DeSanto-Madeya. Contemporary Nursing Knowledge.'),
|
||
new CommentRangeEnd(commentId),
|
||
new TextRun({ children: [new CommentReference(commentId)] })
|
||
]
|
||
})]
|
||
}]
|
||
});
|
||
|
||
const buf = await Packer.toBuffer(doc);
|
||
fs.writeFileSync('test-ref-comment-standalone.docx', buf);
|
||
|
||
const zip = await JSZip.loadAsync(buf);
|
||
const docXml = await zip.file('word/document.xml').async('string');
|
||
const commentsXml = zip.file('word/comments.xml');
|
||
const relsXml = zip.file('word/_rels/document.xml.rels');
|
||
const contentTypes = zip.file('[Content_Types].xml');
|
||
|
||
console.log('has comments.xml:', !!commentsXml);
|
||
console.log('has commentReference in document:', docXml.includes('commentReference'));
|
||
console.log('has comments rel in document.xml.rels:', relsXml ? (await relsXml.async('string')).includes('comments') : false);
|
||
console.log('has comments in Content_Types:', contentTypes ? (await contentTypes.async('string')).includes('comments') : false);
|
||
if (commentsXml) {
|
||
console.log('comments preview:', (await commentsXml.async('string')).slice(0, 800));
|
||
}
|