@actuate-media/plugin-ai 0.0.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.
Files changed (121) hide show
  1. package/dist/admin/AIScorePanel.d.ts +19 -0
  2. package/dist/admin/AIScorePanel.d.ts.map +1 -0
  3. package/dist/admin/AIScorePanel.js +35 -0
  4. package/dist/admin/AIScorePanel.js.map +1 -0
  5. package/dist/admin/BrandVoiceSettings.d.ts +11 -0
  6. package/dist/admin/BrandVoiceSettings.d.ts.map +1 -0
  7. package/dist/admin/BrandVoiceSettings.js +73 -0
  8. package/dist/admin/BrandVoiceSettings.js.map +1 -0
  9. package/dist/admin/ContentScoreDashboard.d.ts +15 -0
  10. package/dist/admin/ContentScoreDashboard.d.ts.map +1 -0
  11. package/dist/admin/ContentScoreDashboard.js +30 -0
  12. package/dist/admin/ContentScoreDashboard.js.map +1 -0
  13. package/dist/admin/WritingAssistantToolbar.d.ts +13 -0
  14. package/dist/admin/WritingAssistantToolbar.d.ts.map +1 -0
  15. package/dist/admin/WritingAssistantToolbar.js +49 -0
  16. package/dist/admin/WritingAssistantToolbar.js.map +1 -0
  17. package/dist/brand/consistency-checker.d.ts +17 -0
  18. package/dist/brand/consistency-checker.d.ts.map +1 -0
  19. package/dist/brand/consistency-checker.js +47 -0
  20. package/dist/brand/consistency-checker.js.map +1 -0
  21. package/dist/brand/profile-builder.d.ts +10 -0
  22. package/dist/brand/profile-builder.d.ts.map +1 -0
  23. package/dist/brand/profile-builder.js +93 -0
  24. package/dist/brand/profile-builder.js.map +1 -0
  25. package/dist/brand/voice-profile.d.ts +30 -0
  26. package/dist/brand/voice-profile.d.ts.map +1 -0
  27. package/dist/brand/voice-profile.js +2 -0
  28. package/dist/brand/voice-profile.js.map +1 -0
  29. package/dist/collections.d.ts +3 -0
  30. package/dist/collections.d.ts.map +1 -0
  31. package/dist/collections.js +2 -0
  32. package/dist/collections.js.map +1 -0
  33. package/dist/fields.d.ts +3 -0
  34. package/dist/fields.d.ts.map +1 -0
  35. package/dist/fields.js +2 -0
  36. package/dist/fields.js.map +1 -0
  37. package/dist/hooks.d.ts +5 -0
  38. package/dist/hooks.d.ts.map +1 -0
  39. package/dist/hooks.js +75 -0
  40. package/dist/hooks.js.map +1 -0
  41. package/dist/index.d.ts +86 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +74 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/links/smart-links.d.ts +18 -0
  46. package/dist/links/smart-links.d.ts.map +1 -0
  47. package/dist/links/smart-links.js +44 -0
  48. package/dist/links/smart-links.js.map +1 -0
  49. package/dist/media/alt-text-generator.d.ts +16 -0
  50. package/dist/media/alt-text-generator.d.ts.map +1 -0
  51. package/dist/media/alt-text-generator.js +50 -0
  52. package/dist/media/alt-text-generator.js.map +1 -0
  53. package/dist/media/auto-tagger.d.ts +21 -0
  54. package/dist/media/auto-tagger.d.ts.map +1 -0
  55. package/dist/media/auto-tagger.js +43 -0
  56. package/dist/media/auto-tagger.js.map +1 -0
  57. package/dist/providers/anthropic.d.ts +8 -0
  58. package/dist/providers/anthropic.d.ts.map +1 -0
  59. package/dist/providers/anthropic.js +119 -0
  60. package/dist/providers/anthropic.js.map +1 -0
  61. package/dist/providers/index.d.ts +34 -0
  62. package/dist/providers/index.d.ts.map +1 -0
  63. package/dist/providers/index.js +35 -0
  64. package/dist/providers/index.js.map +1 -0
  65. package/dist/providers/openai.d.ts +7 -0
  66. package/dist/providers/openai.d.ts.map +1 -0
  67. package/dist/providers/openai.js +110 -0
  68. package/dist/providers/openai.js.map +1 -0
  69. package/dist/scoring/accessibility.d.ts +24 -0
  70. package/dist/scoring/accessibility.d.ts.map +1 -0
  71. package/dist/scoring/accessibility.js +87 -0
  72. package/dist/scoring/accessibility.js.map +1 -0
  73. package/dist/scoring/brand-alignment.d.ts +12 -0
  74. package/dist/scoring/brand-alignment.d.ts.map +1 -0
  75. package/dist/scoring/brand-alignment.js +46 -0
  76. package/dist/scoring/brand-alignment.js.map +1 -0
  77. package/dist/scoring/composite.d.ts +19 -0
  78. package/dist/scoring/composite.d.ts.map +1 -0
  79. package/dist/scoring/composite.js +38 -0
  80. package/dist/scoring/composite.js.map +1 -0
  81. package/dist/scoring/freshness.d.ts +15 -0
  82. package/dist/scoring/freshness.d.ts.map +1 -0
  83. package/dist/scoring/freshness.js +37 -0
  84. package/dist/scoring/freshness.js.map +1 -0
  85. package/dist/scoring/readability.d.ts +16 -0
  86. package/dist/scoring/readability.d.ts.map +1 -0
  87. package/dist/scoring/readability.js +77 -0
  88. package/dist/scoring/readability.js.map +1 -0
  89. package/dist/scoring/seo-score.d.ts +26 -0
  90. package/dist/scoring/seo-score.d.ts.map +1 -0
  91. package/dist/scoring/seo-score.js +53 -0
  92. package/dist/scoring/seo-score.js.map +1 -0
  93. package/dist/search/clustering.d.ts +20 -0
  94. package/dist/search/clustering.d.ts.map +1 -0
  95. package/dist/search/clustering.js +91 -0
  96. package/dist/search/clustering.js.map +1 -0
  97. package/dist/search/embeddings.d.ts +14 -0
  98. package/dist/search/embeddings.d.ts.map +1 -0
  99. package/dist/search/embeddings.js +42 -0
  100. package/dist/search/embeddings.js.map +1 -0
  101. package/dist/search/semantic-search.d.ts +31 -0
  102. package/dist/search/semantic-search.d.ts.map +1 -0
  103. package/dist/search/semantic-search.js +59 -0
  104. package/dist/search/semantic-search.js.map +1 -0
  105. package/dist/translation/translator.d.ts +24 -0
  106. package/dist/translation/translator.d.ts.map +1 -0
  107. package/dist/translation/translator.js +42 -0
  108. package/dist/translation/translator.js.map +1 -0
  109. package/dist/writing/assistant.d.ts +28 -0
  110. package/dist/writing/assistant.d.ts.map +1 -0
  111. package/dist/writing/assistant.js +110 -0
  112. package/dist/writing/assistant.js.map +1 -0
  113. package/dist/writing/inline-suggestions.d.ts +18 -0
  114. package/dist/writing/inline-suggestions.d.ts.map +1 -0
  115. package/dist/writing/inline-suggestions.js +38 -0
  116. package/dist/writing/inline-suggestions.js.map +1 -0
  117. package/dist/writing/meta-generator.d.ts +13 -0
  118. package/dist/writing/meta-generator.d.ts.map +1 -0
  119. package/dist/writing/meta-generator.js +41 -0
  120. package/dist/writing/meta-generator.js.map +1 -0
  121. package/package.json +37 -0
@@ -0,0 +1,34 @@
1
+ export interface GenerateOptions {
2
+ maxTokens?: number;
3
+ temperature?: number;
4
+ systemPrompt?: string;
5
+ }
6
+ export interface GenerateResult {
7
+ text: string;
8
+ usage: {
9
+ promptTokens: number;
10
+ completionTokens: number;
11
+ };
12
+ }
13
+ export interface StreamOptions extends GenerateOptions {
14
+ }
15
+ export interface AIProvider {
16
+ generateText(prompt: string, options?: GenerateOptions): Promise<GenerateResult>;
17
+ generateEmbedding(text: string): Promise<number[]>;
18
+ streamText(prompt: string, options?: StreamOptions): AsyncIterable<string>;
19
+ }
20
+ export interface AIProviderConfig {
21
+ provider: "anthropic" | "openai";
22
+ apiKey: string;
23
+ model?: string;
24
+ openaiApiKey?: string;
25
+ }
26
+ /** Creates an AI provider instance for the specified backend. */
27
+ export declare function createAIProvider(config: AIProviderConfig): AIProvider;
28
+ /** Set the global AI provider used by all plugin features. */
29
+ export declare function setAIProvider(provider: AIProvider): void;
30
+ /** Get the global AI provider. Returns null if not configured. */
31
+ export declare function getAIProvider(): AIProvider | null;
32
+ /** Get the global AI provider or throw if not configured. */
33
+ export declare function requireAIProvider(): AIProvider;
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3D;AAED,MAAM,WAAW,aAAc,SAAQ,eAAe;CAAG;AAEzD,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACjF,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnD,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,GAAG,QAAQ,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAarE;AAED,8DAA8D;AAC9D,wBAAgB,aAAa,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAExD;AAED,kEAAkE;AAClE,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,IAAI,UAAU,CAQ9C"}
@@ -0,0 +1,35 @@
1
+ import { createAnthropicProvider } from "./anthropic";
2
+ import { createOpenAIProvider } from "./openai";
3
+ let _globalProvider = null;
4
+ /** Creates an AI provider instance for the specified backend. */
5
+ export function createAIProvider(config) {
6
+ switch (config.provider) {
7
+ case "anthropic":
8
+ return createAnthropicProvider({
9
+ apiKey: config.apiKey,
10
+ model: config.model,
11
+ openaiApiKey: config.openaiApiKey,
12
+ });
13
+ case "openai":
14
+ return createOpenAIProvider({ apiKey: config.apiKey, model: config.model });
15
+ default:
16
+ throw new Error(`Unsupported AI provider: ${config.provider}`);
17
+ }
18
+ }
19
+ /** Set the global AI provider used by all plugin features. */
20
+ export function setAIProvider(provider) {
21
+ _globalProvider = provider;
22
+ }
23
+ /** Get the global AI provider. Returns null if not configured. */
24
+ export function getAIProvider() {
25
+ return _globalProvider;
26
+ }
27
+ /** Get the global AI provider or throw if not configured. */
28
+ export function requireAIProvider() {
29
+ if (!_globalProvider) {
30
+ throw new Error("AI provider not configured. Call aiPlugin({ provider, apiKey }) " +
31
+ "or setAIProvider() before using AI features.");
32
+ }
33
+ return _globalProvider;
34
+ }
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AA4BhD,IAAI,eAAe,GAAsB,IAAI,CAAC;AAE9C,iEAAiE;AACjE,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,WAAW;YACd,OAAO,uBAAuB,CAAC;gBAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,YAAY,EAAE,MAAM,CAAC,YAAY;aAClC,CAAC,CAAC;QACL,KAAK,QAAQ;YACX,OAAO,oBAAoB,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC9E;YACE,MAAM,IAAI,KAAK,CAAC,4BAA4B,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACnE,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,aAAa,CAAC,QAAoB;IAChD,eAAe,GAAG,QAAQ,CAAC;AAC7B,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,aAAa;IAC3B,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CACb,kEAAkE;YAClE,8CAA8C,CAC/C,CAAC;IACJ,CAAC;IACD,OAAO,eAAe,CAAC;AACzB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { AIProvider } from "./index";
2
+ /** Creates an OpenAI-backed AI provider. */
3
+ export declare function createOpenAIProvider(config: {
4
+ apiKey: string;
5
+ model?: string;
6
+ }): AIProvider;
7
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAkD,MAAM,SAAS,CAAC;AAM1F,4CAA4C;AAC5C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,UAAU,CAyHb"}
@@ -0,0 +1,110 @@
1
+ const DEFAULT_MODEL = "gpt-4o";
2
+ const EMBEDDING_MODEL = "text-embedding-3-small";
3
+ const API_BASE = "https://api.openai.com/v1";
4
+ /** Creates an OpenAI-backed AI provider. */
5
+ export function createOpenAIProvider(config) {
6
+ const model = config.model ?? DEFAULT_MODEL;
7
+ const headers = {
8
+ "Authorization": `Bearer ${config.apiKey}`,
9
+ "Content-Type": "application/json",
10
+ };
11
+ return {
12
+ async generateText(prompt, options) {
13
+ const response = await fetch(`${API_BASE}/chat/completions`, {
14
+ method: "POST",
15
+ headers,
16
+ body: JSON.stringify({
17
+ model,
18
+ max_tokens: options?.maxTokens ?? 1024,
19
+ temperature: options?.temperature ?? 0.7,
20
+ messages: [
21
+ ...(options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : []),
22
+ { role: "user", content: prompt },
23
+ ],
24
+ }),
25
+ });
26
+ if (!response.ok) {
27
+ const err = await response.text().catch(() => "Unknown error");
28
+ throw new Error(`OpenAI API error (${response.status}): ${err}`);
29
+ }
30
+ const data = await response.json();
31
+ return {
32
+ text: data.choices[0]?.message?.content ?? "",
33
+ usage: {
34
+ promptTokens: data.usage?.prompt_tokens ?? 0,
35
+ completionTokens: data.usage?.completion_tokens ?? 0,
36
+ },
37
+ };
38
+ },
39
+ async generateEmbedding(text) {
40
+ const response = await fetch(`${API_BASE}/embeddings`, {
41
+ method: "POST",
42
+ headers,
43
+ body: JSON.stringify({
44
+ model: EMBEDDING_MODEL,
45
+ input: text,
46
+ }),
47
+ });
48
+ if (!response.ok) {
49
+ const err = await response.text().catch(() => "Unknown error");
50
+ throw new Error(`OpenAI embeddings error (${response.status}): ${err}`);
51
+ }
52
+ const data = await response.json();
53
+ return data.data[0]?.embedding ?? [];
54
+ },
55
+ async *streamText(prompt, options) {
56
+ const response = await fetch(`${API_BASE}/chat/completions`, {
57
+ method: "POST",
58
+ headers,
59
+ body: JSON.stringify({
60
+ model,
61
+ max_tokens: options?.maxTokens ?? 1024,
62
+ temperature: options?.temperature ?? 0.7,
63
+ stream: true,
64
+ messages: [
65
+ ...(options?.systemPrompt ? [{ role: "system", content: options.systemPrompt }] : []),
66
+ { role: "user", content: prompt },
67
+ ],
68
+ }),
69
+ });
70
+ if (!response.ok) {
71
+ const err = await response.text().catch(() => "Unknown error");
72
+ throw new Error(`OpenAI stream error (${response.status}): ${err}`);
73
+ }
74
+ const reader = response.body?.getReader();
75
+ if (!reader)
76
+ throw new Error("No response body for streaming");
77
+ const decoder = new TextDecoder();
78
+ let buffer = "";
79
+ try {
80
+ while (true) {
81
+ const { done, value } = await reader.read();
82
+ if (done)
83
+ break;
84
+ buffer += decoder.decode(value, { stream: true });
85
+ const lines = buffer.split("\n");
86
+ buffer = lines.pop() ?? "";
87
+ for (const line of lines) {
88
+ const trimmed = line.trim();
89
+ if (!trimmed || !trimmed.startsWith("data: "))
90
+ continue;
91
+ const payload = trimmed.slice(6);
92
+ if (payload === "[DONE]")
93
+ return;
94
+ try {
95
+ const chunk = JSON.parse(payload);
96
+ const content = chunk.choices[0]?.delta?.content;
97
+ if (content)
98
+ yield content;
99
+ }
100
+ catch { }
101
+ }
102
+ }
103
+ }
104
+ finally {
105
+ reader.releaseLock();
106
+ }
107
+ },
108
+ };
109
+ }
110
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/providers/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface AccessibilityContent {
2
+ html: string;
3
+ images: Array<{
4
+ src: string;
5
+ alt?: string;
6
+ }>;
7
+ headings: string[];
8
+ links: Array<{
9
+ text: string;
10
+ href: string;
11
+ }>;
12
+ }
13
+ export interface AccessibilityResult {
14
+ score: number;
15
+ issues: Array<{
16
+ type: "error" | "warning" | "info";
17
+ rule: string;
18
+ message: string;
19
+ element?: string;
20
+ }>;
21
+ }
22
+ /** Calculates an accessibility score based on common WCAG criteria. */
23
+ export declare function calculateAccessibilityScore(content: AccessibilityContent): AccessibilityResult;
24
+ //# sourceMappingURL=accessibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibility.d.ts","sourceRoot":"","sources":["../../src/scoring/accessibility.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;QACnC,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,uEAAuE;AACvE,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CA0FrB"}
@@ -0,0 +1,87 @@
1
+ /** Calculates an accessibility score based on common WCAG criteria. */
2
+ export function calculateAccessibilityScore(content) {
3
+ const issues = [];
4
+ let deductions = 0;
5
+ for (const img of content.images) {
6
+ if (!img.alt || img.alt.trim().length === 0) {
7
+ issues.push({
8
+ type: "error",
9
+ rule: "img-alt",
10
+ message: "Image is missing alt text",
11
+ element: `<img src="${img.src}">`,
12
+ });
13
+ deductions += 10;
14
+ }
15
+ else if (img.alt.length > 125) {
16
+ issues.push({
17
+ type: "warning",
18
+ rule: "img-alt-length",
19
+ message: "Alt text exceeds recommended 125 characters",
20
+ element: `<img alt="${img.alt.slice(0, 30)}...">`,
21
+ });
22
+ deductions += 3;
23
+ }
24
+ }
25
+ for (const link of content.links) {
26
+ if (!link.text || link.text.trim().length === 0) {
27
+ issues.push({
28
+ type: "error",
29
+ rule: "link-text",
30
+ message: "Link has no accessible text",
31
+ element: `<a href="${link.href}">`,
32
+ });
33
+ deductions += 10;
34
+ }
35
+ const genericTexts = ["click here", "read more", "here", "link", "more"];
36
+ if (genericTexts.includes(link.text.toLowerCase().trim())) {
37
+ issues.push({
38
+ type: "warning",
39
+ rule: "link-text-descriptive",
40
+ message: `Link text "${link.text}" is not descriptive`,
41
+ element: `<a href="${link.href}">${link.text}</a>`,
42
+ });
43
+ deductions += 5;
44
+ }
45
+ }
46
+ const headingPattern = /^h(\d)$/i;
47
+ let prevLevel = 0;
48
+ for (const heading of content.headings) {
49
+ const match = heading.match(headingPattern);
50
+ if (match) {
51
+ const level = parseInt(match[1] ?? "0", 10);
52
+ if (level > prevLevel + 1 && prevLevel > 0) {
53
+ issues.push({
54
+ type: "warning",
55
+ rule: "heading-order",
56
+ message: `Heading level skipped from h${prevLevel} to h${level}`,
57
+ element: heading,
58
+ });
59
+ deductions += 5;
60
+ }
61
+ prevLevel = level;
62
+ }
63
+ }
64
+ if (content.headings.length === 0) {
65
+ issues.push({
66
+ type: "info",
67
+ rule: "heading-presence",
68
+ message: "No headings found — headings improve navigation for screen readers",
69
+ });
70
+ deductions += 5;
71
+ }
72
+ const plainText = content.html.replace(/<[^>]*>/g, "");
73
+ const words = plainText.split(/\s+/).filter(Boolean);
74
+ const longWords = words.filter((w) => w.length > 14).length;
75
+ const longWordRatio = words.length > 0 ? longWords / words.length : 0;
76
+ if (longWordRatio > 0.15) {
77
+ issues.push({
78
+ type: "info",
79
+ rule: "reading-level",
80
+ message: "Content may be difficult to read — high proportion of complex words",
81
+ });
82
+ deductions += 3;
83
+ }
84
+ const score = Math.max(0, Math.min(100, 100 - deductions));
85
+ return { score, issues };
86
+ }
87
+ //# sourceMappingURL=accessibility.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accessibility.js","sourceRoot":"","sources":["../../src/scoring/accessibility.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { BrandVoiceProfile } from "../brand/voice-profile.js";
2
+ export interface BrandAlignmentResult {
3
+ score: number;
4
+ dimensions: Array<{
5
+ name: string;
6
+ score: number;
7
+ feedback: string;
8
+ }>;
9
+ }
10
+ /** Calculates how well the given content aligns with a brand voice profile. */
11
+ export declare function calculateBrandAlignment(content: string, profile: BrandVoiceProfile): BrandAlignmentResult;
12
+ //# sourceMappingURL=brand-alignment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand-alignment.d.ts","sourceRoot":"","sources":["../../src/scoring/brand-alignment.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtE;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,GACzB,oBAAoB,CAsDtB"}
@@ -0,0 +1,46 @@
1
+ /** Calculates how well the given content aligns with a brand voice profile. */
2
+ export function calculateBrandAlignment(content, profile) {
3
+ const dimensions = [];
4
+ const words = content.split(/\s+/).filter(Boolean);
5
+ const sentences = content.split(/[.!?]+/).filter(Boolean);
6
+ const avgSentenceLength = sentences.length > 0 ? words.length / sentences.length : 0;
7
+ const targetLengths = { short: 12, medium: 20, long: 30, varied: 18 };
8
+ const targetLen = targetLengths[profile.style.sentenceLength] ?? 18;
9
+ const sentenceDelta = Math.abs(avgSentenceLength - targetLen);
10
+ const sentenceScore = Math.max(0, 100 - sentenceDelta * 5);
11
+ dimensions.push({
12
+ name: "Sentence length",
13
+ score: Math.round(sentenceScore),
14
+ feedback: sentenceDelta < 3 ? "Sentence length matches brand style" : `Average sentence length (${Math.round(avgSentenceLength)}) differs from target (${targetLen})`,
15
+ });
16
+ const preferredHits = profile.vocabulary.preferred.filter((w) => content.toLowerCase().includes(w.toLowerCase())).length;
17
+ const preferredRatio = profile.vocabulary.preferred.length > 0
18
+ ? (preferredHits / profile.vocabulary.preferred.length) * 100
19
+ : 100;
20
+ dimensions.push({
21
+ name: "Preferred vocabulary",
22
+ score: Math.round(preferredRatio),
23
+ feedback: preferredRatio > 70 ? "Good use of brand vocabulary" : "Consider using more brand-preferred terms",
24
+ });
25
+ const avoidedHits = profile.vocabulary.avoided.filter((w) => content.toLowerCase().includes(w.toLowerCase())).length;
26
+ const avoidedScore = profile.vocabulary.avoided.length > 0
27
+ ? Math.max(0, 100 - avoidedHits * 25)
28
+ : 100;
29
+ dimensions.push({
30
+ name: "Avoided vocabulary",
31
+ score: Math.round(avoidedScore),
32
+ feedback: avoidedHits === 0 ? "No off-brand terms detected" : `Found ${avoidedHits} term(s) that should be avoided`,
33
+ });
34
+ for (const tone of profile.tone) {
35
+ dimensions.push({
36
+ name: `Tone: ${tone.dimension}`,
37
+ score: Math.round(tone.value * 100),
38
+ feedback: `Tone dimension "${tone.dimension}" requires AI analysis for accurate measurement`,
39
+ });
40
+ }
41
+ const avgScore = dimensions.length > 0
42
+ ? dimensions.reduce((sum, d) => sum + d.score, 0) / dimensions.length
43
+ : 0;
44
+ return { score: Math.round(avgScore), dimensions };
45
+ }
46
+ //# sourceMappingURL=brand-alignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brand-alignment.js","sourceRoot":"","sources":["../../src/scoring/brand-alignment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface ScoreInputs {
2
+ readability?: number;
3
+ seo?: number;
4
+ brandAlignment?: number;
5
+ accessibility?: number;
6
+ freshness?: number;
7
+ }
8
+ export interface CompositeScore {
9
+ overall: number;
10
+ breakdown: Record<string, {
11
+ score: number;
12
+ weight: number;
13
+ weighted: number;
14
+ }>;
15
+ grade: "A" | "B" | "C" | "D" | "F";
16
+ }
17
+ /** Calculates a weighted composite score from individual content quality dimensions. */
18
+ export declare function calculateCompositeScore(scores: ScoreInputs, weights?: Partial<Record<keyof ScoreInputs, number>>): CompositeScore;
19
+ //# sourceMappingURL=composite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite.d.ts","sourceRoot":"","sources":["../../src/scoring/composite.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/E,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACpC;AAUD,wFAAwF;AACxF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,WAAW,EAAE,MAAM,CAAC,CAAC,GACnD,cAAc,CA6BhB"}
@@ -0,0 +1,38 @@
1
+ const DEFAULT_WEIGHTS = {
2
+ readability: 0.2,
3
+ seo: 0.25,
4
+ brandAlignment: 0.2,
5
+ accessibility: 0.2,
6
+ freshness: 0.15,
7
+ };
8
+ /** Calculates a weighted composite score from individual content quality dimensions. */
9
+ export function calculateCompositeScore(scores, weights) {
10
+ const mergedWeights = { ...DEFAULT_WEIGHTS, ...weights };
11
+ const breakdown = {};
12
+ let totalWeight = 0;
13
+ let totalWeighted = 0;
14
+ for (const [key, value] of Object.entries(scores)) {
15
+ if (value === undefined)
16
+ continue;
17
+ const k = key;
18
+ const weight = mergedWeights[k] ?? 0;
19
+ const weighted = value * weight;
20
+ breakdown[key] = { score: value, weight, weighted };
21
+ totalWeight += weight;
22
+ totalWeighted += weighted;
23
+ }
24
+ const overall = totalWeight > 0 ? Math.round(totalWeighted / totalWeight) : 0;
25
+ let grade;
26
+ if (overall >= 90)
27
+ grade = "A";
28
+ else if (overall >= 80)
29
+ grade = "B";
30
+ else if (overall >= 70)
31
+ grade = "C";
32
+ else if (overall >= 60)
33
+ grade = "D";
34
+ else
35
+ grade = "F";
36
+ return { overall, breakdown, grade };
37
+ }
38
+ //# sourceMappingURL=composite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite.js","sourceRoot":"","sources":["../../src/scoring/composite.ts"],"names":[],"mappings":"AAcA,MAAM,eAAe,GAAsC;IACzD,WAAW,EAAE,GAAG;IAChB,GAAG,EAAE,IAAI;IACT,cAAc,EAAE,GAAG;IACnB,aAAa,EAAE,GAAG;IAClB,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,wFAAwF;AACxF,MAAM,UAAU,uBAAuB,CACrC,MAAmB,EACnB,OAAoD;IAEpD,MAAM,aAAa,GAAG,EAAE,GAAG,eAAe,EAAE,GAAG,OAAO,EAAE,CAAC;IAEzD,MAAM,SAAS,GAAgC,EAAE,CAAC;IAClD,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAElC,MAAM,CAAC,GAAG,GAAwB,CAAC;QACnC,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;QAEhC,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACpD,WAAW,IAAI,MAAM,CAAC;QACtB,aAAa,IAAI,QAAQ,CAAC;IAC5B,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9E,IAAI,KAA8B,CAAC;IACnC,IAAI,OAAO,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SAC1B,IAAI,OAAO,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SAC/B,IAAI,OAAO,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;SAC/B,IAAI,OAAO,IAAI,EAAE;QAAE,KAAK,GAAG,GAAG,CAAC;;QAC/B,KAAK,GAAG,GAAG,CAAC;IAEjB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACvC,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface FreshnessOptions {
2
+ publishedAt: Date;
3
+ updatedAt?: Date;
4
+ contentType: string;
5
+ averageLifespanDays?: number;
6
+ }
7
+ export interface FreshnessResult {
8
+ score: number;
9
+ decayRate: number;
10
+ daysOld: number;
11
+ recommendation: "current" | "review" | "stale" | "outdated";
12
+ }
13
+ /** Calculates a freshness score using exponential decay based on content age. */
14
+ export declare function calculateFreshnessScore(options: FreshnessOptions): FreshnessResult;
15
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../src/scoring/freshness.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;CAC7D;AAUD,iFAAiF;AACjF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CA2BlF"}
@@ -0,0 +1,37 @@
1
+ const DEFAULT_LIFESPANS = {
2
+ news: 7,
3
+ blog: 180,
4
+ tutorial: 365,
5
+ documentation: 730,
6
+ evergreen: 1095,
7
+ };
8
+ /** Calculates a freshness score using exponential decay based on content age. */
9
+ export function calculateFreshnessScore(options) {
10
+ const lifespanDays = options.averageLifespanDays
11
+ ?? DEFAULT_LIFESPANS[options.contentType]
12
+ ?? 365;
13
+ const referenceDate = options.updatedAt ?? options.publishedAt;
14
+ const now = new Date();
15
+ const msPerDay = 1000 * 60 * 60 * 24;
16
+ const daysOld = Math.max(0, (now.getTime() - referenceDate.getTime()) / msPerDay);
17
+ const halfLife = lifespanDays / 2;
18
+ const decayRate = Math.LN2 / halfLife;
19
+ const score = Math.round(100 * Math.exp(-decayRate * daysOld));
20
+ const clampedScore = Math.max(0, Math.min(100, score));
21
+ let recommendation;
22
+ if (clampedScore >= 75)
23
+ recommendation = "current";
24
+ else if (clampedScore >= 50)
25
+ recommendation = "review";
26
+ else if (clampedScore >= 25)
27
+ recommendation = "stale";
28
+ else
29
+ recommendation = "outdated";
30
+ return {
31
+ score: clampedScore,
32
+ decayRate: Math.round(decayRate * 10000) / 10000,
33
+ daysOld: Math.round(daysOld),
34
+ recommendation,
35
+ };
36
+ }
37
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../../src/scoring/freshness.ts"],"names":[],"mappings":"AAcA,MAAM,iBAAiB,GAA2B;IAChD,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,GAAG;IACT,QAAQ,EAAE,GAAG;IACb,aAAa,EAAE,GAAG;IAClB,SAAS,EAAE,IAAI;CAChB,CAAC;AAEF,iFAAiF;AACjF,MAAM,UAAU,uBAAuB,CAAC,OAAyB;IAC/D,MAAM,YAAY,GAAG,OAAO,CAAC,mBAAmB;WAC3C,iBAAiB,CAAC,OAAO,CAAC,WAAW,CAAC;WACtC,GAAG,CAAC;IAET,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,WAAW,CAAC;IAC/D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC;IAElF,MAAM,QAAQ,GAAG,YAAY,GAAG,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,GAAG,QAAQ,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEvD,IAAI,cAAiD,CAAC;IACtD,IAAI,YAAY,IAAI,EAAE;QAAE,cAAc,GAAG,SAAS,CAAC;SAC9C,IAAI,YAAY,IAAI,EAAE;QAAE,cAAc,GAAG,QAAQ,CAAC;SAClD,IAAI,YAAY,IAAI,EAAE;QAAE,cAAc,GAAG,OAAO,CAAC;;QACjD,cAAc,GAAG,UAAU,CAAC;IAEjC,OAAO;QACL,KAAK,EAAE,YAAY;QACnB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK;QAChD,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC;QAC5B,cAAc;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ export interface ReadabilityResult {
2
+ fleschKincaid: number;
3
+ gunningFog: number;
4
+ smog: number;
5
+ averageGradeLevel: number;
6
+ difficulty: "easy" | "moderate" | "difficult" | "expert";
7
+ }
8
+ /** Calculates the Flesch-Kincaid grade level for the given text. */
9
+ export declare function calculateFleschKincaid(text: string): number;
10
+ /** Calculates the Gunning Fog index for the given text. */
11
+ export declare function calculateGunningFog(text: string): number;
12
+ /** Calculates the SMOG readability index for the given text. */
13
+ export declare function calculateSMOG(text: string): number;
14
+ /** Returns a comprehensive readability analysis of the given text. */
15
+ export declare function getReadabilityScore(text: string): ReadabilityResult;
16
+ //# sourceMappingURL=readability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readability.d.ts","sourceRoot":"","sources":["../../src/scoring/readability.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;CAC1D;AAmCD,oEAAoE;AACpE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY3D;AAED,2DAA2D;AAC3D,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQxD;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAanE"}
@@ -0,0 +1,77 @@
1
+ function countSentences(text) {
2
+ const matches = text.match(/[.!?]+/g);
3
+ return matches ? matches.length : 1;
4
+ }
5
+ function countWords(text) {
6
+ const matches = text.trim().split(/\s+/).filter(Boolean);
7
+ return matches.length;
8
+ }
9
+ function countSyllables(word) {
10
+ const cleaned = word.toLowerCase().replace(/[^a-z]/g, "");
11
+ if (cleaned.length <= 3)
12
+ return 1;
13
+ let count = 0;
14
+ const vowels = "aeiouy";
15
+ let previousWasVowel = false;
16
+ for (const char of cleaned) {
17
+ const isVowel = vowels.includes(char);
18
+ if (isVowel && !previousWasVowel)
19
+ count++;
20
+ previousWasVowel = isVowel;
21
+ }
22
+ if (cleaned.endsWith("e") && count > 1)
23
+ count--;
24
+ return Math.max(count, 1);
25
+ }
26
+ function countComplexWords(text) {
27
+ const words = text.trim().split(/\s+/).filter(Boolean);
28
+ return words.filter((w) => countSyllables(w) >= 3).length;
29
+ }
30
+ /** Calculates the Flesch-Kincaid grade level for the given text. */
31
+ export function calculateFleschKincaid(text) {
32
+ const words = countWords(text);
33
+ const sentences = countSentences(text);
34
+ const syllables = text
35
+ .trim()
36
+ .split(/\s+/)
37
+ .filter(Boolean)
38
+ .reduce((sum, word) => sum + countSyllables(word), 0);
39
+ if (words === 0 || sentences === 0)
40
+ return 0;
41
+ return 0.39 * (words / sentences) + 11.8 * (syllables / words) - 15.59;
42
+ }
43
+ /** Calculates the Gunning Fog index for the given text. */
44
+ export function calculateGunningFog(text) {
45
+ const words = countWords(text);
46
+ const sentences = countSentences(text);
47
+ const complex = countComplexWords(text);
48
+ if (words === 0 || sentences === 0)
49
+ return 0;
50
+ return 0.4 * (words / sentences + 100 * (complex / words));
51
+ }
52
+ /** Calculates the SMOG readability index for the given text. */
53
+ export function calculateSMOG(text) {
54
+ const sentences = countSentences(text);
55
+ const complex = countComplexWords(text);
56
+ if (sentences === 0)
57
+ return 0;
58
+ return 1.0430 * Math.sqrt(complex * (30 / sentences)) + 3.1291;
59
+ }
60
+ /** Returns a comprehensive readability analysis of the given text. */
61
+ export function getReadabilityScore(text) {
62
+ const fleschKincaid = calculateFleschKincaid(text);
63
+ const gunningFog = calculateGunningFog(text);
64
+ const smog = calculateSMOG(text);
65
+ const averageGradeLevel = (fleschKincaid + gunningFog + smog) / 3;
66
+ let difficulty;
67
+ if (averageGradeLevel <= 6)
68
+ difficulty = "easy";
69
+ else if (averageGradeLevel <= 10)
70
+ difficulty = "moderate";
71
+ else if (averageGradeLevel <= 14)
72
+ difficulty = "difficult";
73
+ else
74
+ difficulty = "expert";
75
+ return { fleschKincaid, gunningFog, smog, averageGradeLevel, difficulty };
76
+ }
77
+ //# sourceMappingURL=readability.js.map