@segnavia/idml 0.0.0-stage → 0.29.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/LICENSE +21 -0
- package/dist/frame-preferences.js +45 -0
- package/dist/import.d.ts +13 -0
- package/dist/import.js +27 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/limits.d.ts +15 -0
- package/dist/limits.js +15 -0
- package/dist/map-book.js +73 -0
- package/dist/model.d.ts +44 -0
- package/dist/model.js +268 -0
- package/dist/refusal.js +6 -0
- package/dist/report.d.ts +17 -0
- package/dist/report.js +75 -0
- package/dist/stories.js +141 -0
- package/dist/story-model.js +53 -0
- package/dist/style-mappings.js +52 -0
- package/dist/style-property-report.js +236 -0
- package/dist/styles.js +285 -0
- package/dist/types.d.ts +35 -0
- package/dist/unsupported-elements.js +49 -0
- package/dist/xml.js +18 -0
- package/dist/zip.js +142 -0
- package/package.json +33 -4
- package/README.md +0 -3
package/dist/stories.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { resolveDirection } from "@segnavia/format";
|
|
2
|
+
import { BOOK_COLUMN_MAX, BOOK_COLUMN_MIN } from "@segnavia/html";
|
|
3
|
+
import serialize from "dom-serializer";
|
|
4
|
+
import { Element, Text } from "domhandler";
|
|
5
|
+
//#region src/stories.ts
|
|
6
|
+
const OMITTED = /* @__PURE__ */ new Set([
|
|
7
|
+
"TextFrame",
|
|
8
|
+
"Rectangle",
|
|
9
|
+
"Group",
|
|
10
|
+
"Polygon",
|
|
11
|
+
"Table",
|
|
12
|
+
"Footnote",
|
|
13
|
+
"Note",
|
|
14
|
+
"TextVariableInstance"
|
|
15
|
+
]);
|
|
16
|
+
const WRAPPERS = /* @__PURE__ */ new Set([
|
|
17
|
+
"HyperlinkTextSource",
|
|
18
|
+
"XMLElement",
|
|
19
|
+
"Change"
|
|
20
|
+
]);
|
|
21
|
+
function classes(...values) {
|
|
22
|
+
return values.filter(Boolean).join(" ") || void 0;
|
|
23
|
+
}
|
|
24
|
+
function rangeAttributes(node) {
|
|
25
|
+
if (!node) return {};
|
|
26
|
+
const result = { ...node.attributes };
|
|
27
|
+
const holder = node.children.find((child) => child.name === "Properties");
|
|
28
|
+
for (const child of holder?.children ?? []) if (child.text) result[child.name] = child.text.trim();
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
function tokens(root, report) {
|
|
32
|
+
const result = [];
|
|
33
|
+
const terminal = (node, character) => {
|
|
34
|
+
if (node.name === "Content") result.push({
|
|
35
|
+
kind: "text",
|
|
36
|
+
text: node.text ?? "",
|
|
37
|
+
character,
|
|
38
|
+
location: node.location
|
|
39
|
+
});
|
|
40
|
+
else if (node.name === "Br") result.push({
|
|
41
|
+
kind: "paragraph",
|
|
42
|
+
location: node.location
|
|
43
|
+
});
|
|
44
|
+
else if (node.name === "#processing-instruction") report.add(report.unsupportedSpecialCharacters, node.text ?? "processing instruction", node.location);
|
|
45
|
+
else if (OMITTED.has(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
46
|
+
else if (node.name === "Properties") return true;
|
|
47
|
+
else if (node.name === "Change" && node.attributes.ChangeType !== void 0 && !node.attributes.ChangeType.includes("Inserted")) report.add(report.unsupportedElements, "Change", node.location);
|
|
48
|
+
else return false;
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
51
|
+
const walk = (node, character) => {
|
|
52
|
+
if (terminal(node, character)) return;
|
|
53
|
+
const nextCharacter = node.name === "CharacterStyleRange" ? node : character;
|
|
54
|
+
if (WRAPPERS.has(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
55
|
+
else if (![
|
|
56
|
+
"Story",
|
|
57
|
+
"ParagraphStyleRange",
|
|
58
|
+
"CharacterStyleRange"
|
|
59
|
+
].includes(node.name)) report.add(report.unsupportedElements, node.name, node.location);
|
|
60
|
+
for (const child of node.children) walk(child, nextCharacter);
|
|
61
|
+
};
|
|
62
|
+
walk(root);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
function contentNodes(token, styles, direction) {
|
|
66
|
+
const character = token.character;
|
|
67
|
+
const characterAttributes = rangeAttributes(character);
|
|
68
|
+
const characterStyle = characterAttributes.AppliedCharacterStyle;
|
|
69
|
+
const characterBase = styles.flattened(characterStyle, "character");
|
|
70
|
+
const styleClass = styles.styleClass(characterStyle, "character");
|
|
71
|
+
const localClass = styles.overrideClass(characterAttributes, characterBase, direction, character?.location ?? token.location);
|
|
72
|
+
const nodes = textNodes(token.text ?? "");
|
|
73
|
+
const classValue = classes(styleClass, localClass);
|
|
74
|
+
return classValue ? [new Element("span", { class: classValue }, nodes)] : nodes;
|
|
75
|
+
}
|
|
76
|
+
function textNodes(value) {
|
|
77
|
+
const pieces = value.split("\u2028");
|
|
78
|
+
const result = [];
|
|
79
|
+
for (const [index, piece] of pieces.entries()) {
|
|
80
|
+
if (piece) result.push(new Text(piece));
|
|
81
|
+
if (index < pieces.length - 1) result.push(new Element("br", {}, []));
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
function paragraphNode(paragraph, paragraphTokens, styles, report, bookDirection, bookLanguage, storyDirection, frame) {
|
|
86
|
+
const attributes = rangeAttributes(paragraph);
|
|
87
|
+
const styleId = attributes.AppliedParagraphStyle;
|
|
88
|
+
const flattened = styles.flattened(styleId, "paragraph");
|
|
89
|
+
const rawText = paragraphTokens.filter((token) => token.kind === "text").map((token) => token.text ?? "").join("");
|
|
90
|
+
const resolvedDirection = styles.paragraphDirection(attributes) ?? styles.paragraphDirection(flattened) ?? storyDirection ?? resolveDirection(void 0, void 0, rawText);
|
|
91
|
+
const languageName = attributes.AppliedLanguage ?? flattened.AppliedLanguage;
|
|
92
|
+
const language = styles.language(languageName, paragraph.location);
|
|
93
|
+
const paragraphClass = styles.styleClass(styleId, "paragraph");
|
|
94
|
+
const overrideClass = styles.overrideClass(attributes, flattened, resolvedDirection, paragraph.location, styles.paragraphStyleDirection(flattened));
|
|
95
|
+
const htmlAttributes = {};
|
|
96
|
+
const className = classes(paragraphClass, overrideClass);
|
|
97
|
+
if (className) htmlAttributes.class = className;
|
|
98
|
+
if (resolvedDirection !== bookDirection) htmlAttributes.dir = resolvedDirection;
|
|
99
|
+
if (language && language !== bookLanguage) htmlAttributes.lang = language;
|
|
100
|
+
const span = attributes.SpanColumnType ?? flattened.SpanColumnType;
|
|
101
|
+
if (frame && frame.columns >= 2 && span === "SingleColumn") {
|
|
102
|
+
if (Number.isInteger(frame.columns) && frame.columns >= BOOK_COLUMN_MIN && frame.columns <= BOOK_COLUMN_MAX) htmlAttributes["data-columns"] = String(frame.columns);
|
|
103
|
+
else report.addOnce(report.unsupportedElements, `TextColumnCount:${frame.columns}`, frame.location ?? paragraph.location);
|
|
104
|
+
}
|
|
105
|
+
if (span === "SplitColumns") report.add(report.unsupportedStyleProperties, "SpanColumnType:SplitColumns", paragraph.location);
|
|
106
|
+
const children = [];
|
|
107
|
+
for (const token of paragraphTokens) {
|
|
108
|
+
if (token.kind !== "text") continue;
|
|
109
|
+
children.push(...contentNodes(token, styles, resolvedDirection));
|
|
110
|
+
}
|
|
111
|
+
if (children.length === 0) children.push(new Element("br", {}, []));
|
|
112
|
+
return new Element("p", htmlAttributes, children);
|
|
113
|
+
}
|
|
114
|
+
function storyHtml(story, styles, report, bookDirection, bookLanguage) {
|
|
115
|
+
if (!story.root) return { html: serialize(new Element("p", {}, [new Element("br", {}, [])]), {
|
|
116
|
+
xmlMode: false,
|
|
117
|
+
encodeEntities: "utf8"
|
|
118
|
+
}) };
|
|
119
|
+
const paragraphs = [];
|
|
120
|
+
for (const paragraph of story.root.children.filter((node) => node.name === "ParagraphStyleRange")) {
|
|
121
|
+
const all = tokens(paragraph, report);
|
|
122
|
+
let current = [];
|
|
123
|
+
const flush = () => {
|
|
124
|
+
paragraphs.push(paragraphNode(paragraph, current, styles, report, bookDirection, bookLanguage, story.direction, story.frame));
|
|
125
|
+
current = [];
|
|
126
|
+
};
|
|
127
|
+
for (const token of all) if (token.kind === "paragraph") flush();
|
|
128
|
+
else current.push(token);
|
|
129
|
+
if (current.length > 0 || all.length === 0 || all.at(-1)?.kind !== "paragraph") flush();
|
|
130
|
+
}
|
|
131
|
+
if (paragraphs.length === 0) paragraphs.push(new Element("p", {}, [new Element("br", {}, [])]));
|
|
132
|
+
return {
|
|
133
|
+
html: serialize(paragraphs, {
|
|
134
|
+
xmlMode: false,
|
|
135
|
+
encodeEntities: "utf8"
|
|
136
|
+
}),
|
|
137
|
+
...story.frame ? { gutter: story.frame.gutter } : {}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { storyHtml };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { activeIdmlValue } from "./style-property-report.js";
|
|
2
|
+
import { idmlDirection, localName } from "./xml.js";
|
|
3
|
+
import { isTag } from "domhandler";
|
|
4
|
+
//#region src/story-model.ts
|
|
5
|
+
function textNode(node, part, path) {
|
|
6
|
+
const children = [];
|
|
7
|
+
let childIndex = 0;
|
|
8
|
+
for (const child of node.children) {
|
|
9
|
+
childIndex += 1;
|
|
10
|
+
if (isTag(child)) children.push(textNode(child, part, `${path}/${localName(child.name)}[${childIndex}]`));
|
|
11
|
+
else if (child.type === "directive") children.push({
|
|
12
|
+
name: "#processing-instruction",
|
|
13
|
+
attributes: {},
|
|
14
|
+
text: child.data,
|
|
15
|
+
children: [],
|
|
16
|
+
location: `${part}${path}#pi${childIndex}`
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
const directText = node.children.filter((child) => child.type === "text").map((child) => child.data).join("");
|
|
20
|
+
return {
|
|
21
|
+
name: localName(node.name),
|
|
22
|
+
attributes: { ...node.attribs },
|
|
23
|
+
...directText ? { text: directText } : {},
|
|
24
|
+
children,
|
|
25
|
+
location: `${part}${path}`
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function storyDirection(element, part, id, report) {
|
|
29
|
+
const preference = element.children.find((child) => isTag(child) && localName(child.name) === "StoryPreference");
|
|
30
|
+
for (const [name, value] of Object.entries(preference?.attribs ?? {})) if (name !== "StoryDirection" && activeIdmlValue(value)) report.add(report.unsupportedElements, `StoryPreference:${name}`, `${part}#${id}`);
|
|
31
|
+
return idmlDirection(preference?.attribs.StoryDirection ?? element.attribs.StoryDirection);
|
|
32
|
+
}
|
|
33
|
+
function parseStories(parts, framePreferences, report) {
|
|
34
|
+
const result = [];
|
|
35
|
+
const seen = /* @__PURE__ */ new Set();
|
|
36
|
+
for (const part of parts) for (const element of part.all.filter((candidate) => localName(candidate.name) === "Story")) {
|
|
37
|
+
const id = element.attribs.Self;
|
|
38
|
+
if (!id || seen.has(id)) continue;
|
|
39
|
+
seen.add(id);
|
|
40
|
+
const direction = storyDirection(element, part.name, id, report);
|
|
41
|
+
const frame = framePreferences.preferred(id);
|
|
42
|
+
result.push({
|
|
43
|
+
id,
|
|
44
|
+
part: part.name,
|
|
45
|
+
root: textNode(element, part.name, `/Story[@Self=${id}]`),
|
|
46
|
+
...direction ? { direction } : {},
|
|
47
|
+
...frame ? { frame } : {}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { parseStories };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/style-mappings.ts
|
|
2
|
+
const css = (name) => ({
|
|
3
|
+
kind: "css",
|
|
4
|
+
css: name
|
|
5
|
+
});
|
|
6
|
+
const nonFormatting = { kind: "non-formatting" };
|
|
7
|
+
const STYLE_PROPERTY_MAPPINGS = {
|
|
8
|
+
PointSize: css("font-size"),
|
|
9
|
+
Leading: css("line-height"),
|
|
10
|
+
AutoLeading: css("line-height"),
|
|
11
|
+
Tracking: css("letter-spacing"),
|
|
12
|
+
SpaceBefore: css("margin-block-start"),
|
|
13
|
+
SpaceAfter: css("margin-block-end"),
|
|
14
|
+
FirstLineIndent: css("text-indent"),
|
|
15
|
+
Capitalization: css("capitalization"),
|
|
16
|
+
Underline: css("text-decoration-line"),
|
|
17
|
+
FillColor: css("color"),
|
|
18
|
+
LeftIndent: css("padding-inline"),
|
|
19
|
+
RightIndent: css("padding-inline"),
|
|
20
|
+
Justification: css("text-align"),
|
|
21
|
+
KeepWithNext: css("keeps"),
|
|
22
|
+
KeepLinesTogether: css("keeps"),
|
|
23
|
+
KeepAllLinesTogether: css("keeps"),
|
|
24
|
+
KeepFirstLines: css("keeps"),
|
|
25
|
+
KeepLastLines: css("keeps"),
|
|
26
|
+
StartParagraph: css("starts"),
|
|
27
|
+
ParagraphDirection: { kind: "direction" },
|
|
28
|
+
AppliedLanguage: { kind: "language" },
|
|
29
|
+
AppliedFont: { kind: "font" },
|
|
30
|
+
FontStyle: { kind: "font" },
|
|
31
|
+
SpanColumnType: { kind: "columns" },
|
|
32
|
+
Self: nonFormatting,
|
|
33
|
+
Name: nonFormatting,
|
|
34
|
+
BasedOn: nonFormatting,
|
|
35
|
+
AppliedParagraphStyle: nonFormatting,
|
|
36
|
+
AppliedCharacterStyle: nonFormatting,
|
|
37
|
+
EmitCss: nonFormatting,
|
|
38
|
+
StyleUniqueId: nonFormatting,
|
|
39
|
+
KeyboardShortcut: nonFormatting,
|
|
40
|
+
ExtendedKeyboardShortcut: nonFormatting,
|
|
41
|
+
Imported: nonFormatting,
|
|
42
|
+
PreviewColor: nonFormatting,
|
|
43
|
+
IncludeClass: nonFormatting,
|
|
44
|
+
EpubAriaRole: nonFormatting,
|
|
45
|
+
SplitDocument: nonFormatting,
|
|
46
|
+
NextStyle: nonFormatting
|
|
47
|
+
};
|
|
48
|
+
function stylePropertyMapping(name) {
|
|
49
|
+
return STYLE_PROPERTY_MAPPINGS[name];
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { STYLE_PROPERTY_MAPPINGS, stylePropertyMapping };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { stylePropertyMapping } from "./style-mappings.js";
|
|
2
|
+
//#region src/style-property-report.ts
|
|
3
|
+
const INDESIGN_PROPERTY_DEFAULTS = {
|
|
4
|
+
HorizontalScale: [100],
|
|
5
|
+
VerticalScale: [100],
|
|
6
|
+
Skew: [0],
|
|
7
|
+
BaselineShift: [0],
|
|
8
|
+
DesiredWordSpacing: [100],
|
|
9
|
+
MinimumWordSpacing: [80],
|
|
10
|
+
MaximumWordSpacing: [133],
|
|
11
|
+
DesiredLetterSpacing: [0],
|
|
12
|
+
MinimumLetterSpacing: [0],
|
|
13
|
+
MaximumLetterSpacing: [0],
|
|
14
|
+
DesiredGlyphScaling: [100],
|
|
15
|
+
MinimumGlyphScaling: [100],
|
|
16
|
+
MaximumGlyphScaling: [100],
|
|
17
|
+
FillTint: [-1, 100],
|
|
18
|
+
KerningMethod: ["$ID/Metrics"],
|
|
19
|
+
Ligatures: [true],
|
|
20
|
+
OTFContextualAlternate: [true],
|
|
21
|
+
OTFMark: [true],
|
|
22
|
+
OTFFigureStyle: ["Default"],
|
|
23
|
+
OTFLocale: [true],
|
|
24
|
+
PositionalForm: ["None"],
|
|
25
|
+
CharacterAlignment: ["AlignEmCenter"],
|
|
26
|
+
DigitsType: ["DefaultDigits"],
|
|
27
|
+
CharacterDirection: ["DefaultDirection"],
|
|
28
|
+
DiacriticPosition: ["OpentypePositionFromBaseline"],
|
|
29
|
+
XOffsetDiacritic: [0],
|
|
30
|
+
YOffsetDiacritic: [0],
|
|
31
|
+
Kashidas: ["DefaultKashidas"],
|
|
32
|
+
ParagraphKashidaWidth: [2],
|
|
33
|
+
ParagraphJustification: ["DefaultJustification"],
|
|
34
|
+
GlyphForm: ["None"],
|
|
35
|
+
MiterLimit: [4],
|
|
36
|
+
EndJoin: ["MiterEndJoin"],
|
|
37
|
+
NoBreak: [false],
|
|
38
|
+
SingleWordJustification: ["LeftAlign"],
|
|
39
|
+
"OTF*": [false]
|
|
40
|
+
};
|
|
41
|
+
const JUSTIFICATION_SETTINGS = /* @__PURE__ */ new Set([
|
|
42
|
+
"DesiredWordSpacing",
|
|
43
|
+
"MinimumWordSpacing",
|
|
44
|
+
"MaximumWordSpacing",
|
|
45
|
+
"DesiredLetterSpacing",
|
|
46
|
+
"MinimumLetterSpacing",
|
|
47
|
+
"MaximumLetterSpacing",
|
|
48
|
+
"DesiredGlyphScaling",
|
|
49
|
+
"MinimumGlyphScaling",
|
|
50
|
+
"MaximumGlyphScaling",
|
|
51
|
+
"SingleWordJustification"
|
|
52
|
+
]);
|
|
53
|
+
const CJK_PREFIXES = [
|
|
54
|
+
"Kinsoku",
|
|
55
|
+
"Shatai",
|
|
56
|
+
"CjkGrid",
|
|
57
|
+
"Grid",
|
|
58
|
+
"AutoTcy"
|
|
59
|
+
];
|
|
60
|
+
const CJK_PROPERTIES = /* @__PURE__ */ new Set([
|
|
61
|
+
"Mojikumi",
|
|
62
|
+
"Jidori",
|
|
63
|
+
"Rensuuji",
|
|
64
|
+
"BunriKinshi",
|
|
65
|
+
"Tsume",
|
|
66
|
+
"LeadingAki",
|
|
67
|
+
"TrailingAki",
|
|
68
|
+
"Gyoudori",
|
|
69
|
+
"ParagraphGyoudori",
|
|
70
|
+
"KeyboardDirection",
|
|
71
|
+
"TreatIdeographicSpaceAsSpace",
|
|
72
|
+
"CharacterRotation",
|
|
73
|
+
"RotateSingleByteCharacters"
|
|
74
|
+
]);
|
|
75
|
+
function truthy(value) {
|
|
76
|
+
return value?.trim().toLowerCase() === "true";
|
|
77
|
+
}
|
|
78
|
+
function notNone(value) {
|
|
79
|
+
const normalized = value?.trim().toLowerCase();
|
|
80
|
+
return Boolean(normalized && ![
|
|
81
|
+
"none",
|
|
82
|
+
"$id/none",
|
|
83
|
+
"nolist"
|
|
84
|
+
].includes(normalized));
|
|
85
|
+
}
|
|
86
|
+
const SWITCHED_GROUPS = [
|
|
87
|
+
{
|
|
88
|
+
matches: (name) => name.startsWith("RuleAbove"),
|
|
89
|
+
enabled: (values) => truthy(values.RuleAbove),
|
|
90
|
+
reportAs: "RuleAbove"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
matches: (name) => name.startsWith("RuleBelow"),
|
|
94
|
+
enabled: (values) => truthy(values.RuleBelow),
|
|
95
|
+
reportAs: "RuleBelow"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
matches: (name) => name.startsWith("ParagraphBorder"),
|
|
99
|
+
enabled: (values) => truthy(values.ParagraphBorderOn),
|
|
100
|
+
reportAs: "ParagraphBorderOn"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
matches: (name) => name.startsWith("ParagraphShading"),
|
|
104
|
+
enabled: (values) => truthy(values.ParagraphShadingOn),
|
|
105
|
+
reportAs: "ParagraphShadingOn"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
matches: (name) => name.startsWith("Underline"),
|
|
109
|
+
enabled: (values) => truthy(values.Underline) || values.Underline === "Underline",
|
|
110
|
+
reportAs: "Underline"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
matches: (name) => name.startsWith("StrikeThrough") || name.startsWith("StrikeThru"),
|
|
114
|
+
enabled: (values) => truthy(values.StrikeThru ?? values.StrikeThrough),
|
|
115
|
+
reportAs: "StrikeThru"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
matches: (name) => name.startsWith("Bullets") || name.startsWith("Numbering"),
|
|
119
|
+
enabled: (values) => notNone(values.BulletsAndNumberingListType),
|
|
120
|
+
reportAs: "BulletsAndNumberingListType"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
matches: (name) => name.startsWith("DropCap") || name === "DropcapDetail",
|
|
124
|
+
enabled: (values) => Number(values.DropCapLines) > 0,
|
|
125
|
+
reportAs: "DropCapLines"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
matches: (name) => name.startsWith("Kenten"),
|
|
129
|
+
enabled: (values) => notNone(values.KentenKind),
|
|
130
|
+
reportAs: "KentenKind"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
matches: (name) => name.startsWith("Ruby"),
|
|
134
|
+
enabled: (values) => truthy(values.RubyFlag),
|
|
135
|
+
reportAs: "RubyFlag"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
matches: (name) => name.startsWith("Warichu"),
|
|
139
|
+
enabled: (values) => truthy(values.Warichu),
|
|
140
|
+
reportAs: "Warichu"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
matches: (name) => name.startsWith("Tatechuyoko"),
|
|
144
|
+
enabled: (values) => truthy(values.Tatechuyoko),
|
|
145
|
+
reportAs: "Tatechuyoko"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
matches: (name) => name.startsWith("Gradient"),
|
|
149
|
+
enabled: (values) => [values.FillColor, values.StrokeColor].some((value) => value?.toLowerCase().includes("gradient")),
|
|
150
|
+
reportAs: "Gradient"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
matches: (name) => name.startsWith("Stroke"),
|
|
154
|
+
enabled: (values) => Number(values.StrokeWeight) > 0 && notNone(values.StrokeColor),
|
|
155
|
+
reportAs: "Stroke"
|
|
156
|
+
}
|
|
157
|
+
];
|
|
158
|
+
function equalsDefault(name, value) {
|
|
159
|
+
const defaults = INDESIGN_PROPERTY_DEFAULTS[name] ?? (name.startsWith("OTF") ? INDESIGN_PROPERTY_DEFAULTS["OTF*"] : void 0);
|
|
160
|
+
if (!defaults) return false;
|
|
161
|
+
const normalized = value.trim().toLowerCase();
|
|
162
|
+
return defaults.some((candidate) => String(candidate).toLowerCase() === normalized);
|
|
163
|
+
}
|
|
164
|
+
function hasEntries(value) {
|
|
165
|
+
const normalized = value?.trim().toLowerCase();
|
|
166
|
+
return Boolean(normalized && ![
|
|
167
|
+
"false",
|
|
168
|
+
"0",
|
|
169
|
+
"none",
|
|
170
|
+
"$id/none",
|
|
171
|
+
"[]"
|
|
172
|
+
].includes(normalized));
|
|
173
|
+
}
|
|
174
|
+
function isCjkLanguage(value) {
|
|
175
|
+
return /(?:chinese|japanese|korean|^zh(?:-|$)|^ja(?:-|$)|^ko(?:-|$))/i.test(value ?? "");
|
|
176
|
+
}
|
|
177
|
+
function activeIdmlValue(value) {
|
|
178
|
+
const normalized = value.trim().toLowerCase();
|
|
179
|
+
if (!normalized || [
|
|
180
|
+
"false",
|
|
181
|
+
"none",
|
|
182
|
+
"nothing",
|
|
183
|
+
"$id/none",
|
|
184
|
+
"$id/nothing",
|
|
185
|
+
"n",
|
|
186
|
+
"no",
|
|
187
|
+
"off"
|
|
188
|
+
].includes(normalized)) return false;
|
|
189
|
+
const numbers = normalized.split(/[\s,]+/).map(Number);
|
|
190
|
+
return numbers.length === 0 || !numbers.every((number) => Number.isFinite(number) && number === 0);
|
|
191
|
+
}
|
|
192
|
+
function isHyphenationProperty(name) {
|
|
193
|
+
return name.startsWith("Hyphenat") || name === "HyphenWeight" || name === "ProviderHyphenationStyle";
|
|
194
|
+
}
|
|
195
|
+
function groupedProperties(names, resolved) {
|
|
196
|
+
const output = [];
|
|
197
|
+
if (names.some(isHyphenationProperty) && truthy(resolved.Hyphenation)) output.push("Hyphenation");
|
|
198
|
+
const changedJustification = [...JUSTIFICATION_SETTINGS].some((name) => {
|
|
199
|
+
const value = resolved[name];
|
|
200
|
+
return value !== void 0 && !equalsDefault(name, value);
|
|
201
|
+
});
|
|
202
|
+
if (names.some((name) => JUSTIFICATION_SETTINGS.has(name)) && changedJustification) output.push("JustificationSettings");
|
|
203
|
+
return output;
|
|
204
|
+
}
|
|
205
|
+
function reportableProperty(name, value, resolved, root) {
|
|
206
|
+
if (stylePropertyMapping(name)) return void 0;
|
|
207
|
+
if (isHyphenationProperty(name) || JUSTIFICATION_SETTINGS.has(name)) return void 0;
|
|
208
|
+
if ([
|
|
209
|
+
"EmptyGrepStyles",
|
|
210
|
+
"EmptyNestedStyles",
|
|
211
|
+
"EmptyLineStyles"
|
|
212
|
+
].includes(name)) return void 0;
|
|
213
|
+
if ([
|
|
214
|
+
"AllGREPStyles",
|
|
215
|
+
"AllNestedStyles",
|
|
216
|
+
"AllLineStyles"
|
|
217
|
+
].includes(name) || name === "TabList") return hasEntries(value) ? name : void 0;
|
|
218
|
+
const switched = SWITCHED_GROUPS.find((group) => group.matches(name));
|
|
219
|
+
if (switched) return switched.enabled(resolved) ? switched.reportAs : void 0;
|
|
220
|
+
if ((CJK_PREFIXES.some((prefix) => name.startsWith(prefix)) || CJK_PROPERTIES.has(name)) && !isCjkLanguage(resolved.AppliedLanguage)) return void 0;
|
|
221
|
+
if (equalsDefault(name, value)) return void 0;
|
|
222
|
+
return !root || activeIdmlValue(value) ? name : void 0;
|
|
223
|
+
}
|
|
224
|
+
function reportableStyleProperties(source, resolved, root = false) {
|
|
225
|
+
const names = Object.keys(source);
|
|
226
|
+
const output = new Set(groupedProperties(names, resolved));
|
|
227
|
+
for (const name of names) {
|
|
228
|
+
const value = source[name];
|
|
229
|
+
if (value === void 0) continue;
|
|
230
|
+
const reported = reportableProperty(name, value, resolved, root);
|
|
231
|
+
if (reported) output.add(reported);
|
|
232
|
+
}
|
|
233
|
+
return [...output];
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
export { INDESIGN_PROPERTY_DEFAULTS, activeIdmlValue, reportableStyleProperties };
|