notes-to-strapi-export-article-ai 1.0.119 → 3.0.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.
Files changed (46) hide show
  1. package/.eslintrc +30 -22
  2. package/README.md +98 -143
  3. package/images/img.png +0 -0
  4. package/images/img_1.png +0 -0
  5. package/images/img_10.png +0 -0
  6. package/images/img_11.png +0 -0
  7. package/images/img_12.png +0 -0
  8. package/images/img_13.png +0 -0
  9. package/images/img_2.png +0 -0
  10. package/images/img_3.png +0 -0
  11. package/images/img_4.png +0 -0
  12. package/images/img_5.png +0 -0
  13. package/images/img_6.png +0 -0
  14. package/images/img_7.png +0 -0
  15. package/images/img_8.png +0 -0
  16. package/images/img_9.png +0 -0
  17. package/manifest.json +2 -2
  18. package/package.json +29 -26
  19. package/src/components/APIKeys.ts +219 -0
  20. package/src/components/Configuration.ts +663 -0
  21. package/src/components/Dashboard.ts +184 -0
  22. package/src/components/ImageSelectionModal.ts +58 -0
  23. package/src/components/Routes.ts +279 -0
  24. package/src/constants.ts +22 -61
  25. package/src/main.ts +177 -34
  26. package/src/services/configuration-generator.ts +172 -0
  27. package/src/services/field-analyzer.ts +84 -0
  28. package/src/services/frontmatter.ts +329 -0
  29. package/src/services/strapi-export.ts +436 -0
  30. package/src/settings/UnifiedSettingsTab.ts +206 -0
  31. package/src/types/image.ts +27 -16
  32. package/src/types/index.ts +3 -0
  33. package/src/types/route.ts +51 -0
  34. package/src/types/settings.ts +22 -23
  35. package/src/utils/analyse-file.ts +94 -0
  36. package/src/utils/debounce.ts +34 -0
  37. package/src/utils/image-processor.ts +124 -400
  38. package/src/utils/preview-modal.ts +265 -0
  39. package/src/utils/process-file.ts +122 -0
  40. package/src/utils/strapi-uploader.ts +120 -119
  41. package/src/settings.ts +0 -404
  42. package/src/types/article.ts +0 -8
  43. package/src/utils/openai-generator.ts +0 -139
  44. package/src/utils/validators.ts +0 -8
  45. package/version-bump.mjs +0 -14
  46. package/versions.json +0 -119
@@ -0,0 +1,51 @@
1
+ export interface RouteConfig {
2
+ id: string
3
+ name: string
4
+ icon: string
5
+ enabled: boolean
6
+ url: string
7
+
8
+ // Content Configuration
9
+ contentType: string
10
+ contentField: string
11
+ description: string
12
+ subtitle: string
13
+
14
+ // Schema Configuration
15
+ schema: string
16
+ schemaDescription: string
17
+ generatedConfig: string
18
+ language: string
19
+
20
+ // Field Mappings
21
+ fieldMappings: Record<string, FieldMapping>
22
+ additionalInstructions?: string
23
+ }
24
+
25
+ export interface FieldMapping {
26
+ obsidianSource: 'frontmatter' | 'content'
27
+ frontmatterKey?: string
28
+ type?: string
29
+ format?: string
30
+ required?: boolean
31
+ transform?: string | ((value: any) => any) // Support des transformations fonction ou string
32
+ validation?: {
33
+ type: string
34
+ pattern?: string
35
+ min?: number
36
+ max?: number
37
+ }
38
+ value?: string
39
+ }
40
+
41
+ export interface RouteConfig {
42
+ id: string
43
+ name: string
44
+ schema: string
45
+ schemaDescription: string
46
+ generatedConfig: string
47
+ language: string
48
+ contentField: string
49
+ fieldMappings: Record<string, FieldMapping>
50
+ additionalInstructions?: string
51
+ }
@@ -1,28 +1,27 @@
1
- /**
2
- * The settings for the Strapi Exporter plugin
3
- */
1
+ import { RouteConfig } from './route'
2
+
4
3
  export interface StrapiExporterSettings {
4
+ // API Settings
5
5
  strapiUrl: string
6
6
  strapiApiToken: string
7
+ forvoyezApiKey: string
7
8
  openaiApiKey: string
8
- jsonTemplate: string
9
- jsonTemplateDescription: string
10
- strapiArticleCreateUrl: string
11
- strapiContentAttributeName: string
12
- additionalPrompt: string
13
- enableAdditionalApiCall: boolean
14
- additionalJsonTemplate: string
15
- additionalJsonTemplateDescription: string
16
- additionalUrl: string
17
- additionalContentAttributeName: string
18
- // enable elements
19
- mainButtonImageEnabled: boolean
20
- mainButtonGalleryEnabled: boolean
21
- additionalButtonImageEnabled: boolean
22
- additionalButtonGalleryEnabled: boolean
23
- // images and galleries paths (for the body api call)
24
- mainImageFullPathProperty: string
25
- mainGalleryFullPathProperty: string
26
- additionalImageFullPathProperty: string
27
- additionalGalleryFullPathProperty: string
9
+
10
+ // UI Settings
11
+ currentTab: string
12
+
13
+ // Routes Configuration
14
+ routes: RouteConfig[]
15
+
16
+ lastExport?: {
17
+ date: string
18
+ status: 'success' | 'failure'
19
+ message?: string
20
+ }
21
+ }
22
+
23
+ export interface AnalyzedContent {
24
+ [key: string]: any
25
+ content?: string
26
+ meta?: Record<string, any>
28
27
  }
@@ -0,0 +1,94 @@
1
+ import { TFile, App } from 'obsidian'
2
+ import { RouteConfig, AnalyzedContent } from '../types'
3
+ import * as yaml from 'js-yaml'
4
+
5
+ export async function analyzeFile(
6
+ file: TFile,
7
+ app: App,
8
+ route: RouteConfig
9
+ ): Promise<AnalyzedContent> {
10
+ try {
11
+ // Reading file content
12
+ const content = await app.vault.read(file)
13
+
14
+ // Extracting frontmatter and content
15
+ const { frontmatter, body } = extractFrontMatterAndContent(content)
16
+
17
+ // Initialize result with existing frontmatter
18
+ const result: AnalyzedContent = {
19
+ ...frontmatter, // Copy all existing frontmatter fields
20
+ }
21
+
22
+ // Processing field mappings
23
+ for (const [strapiField, mapping] of Object.entries(route.fieldMappings)) {
24
+ // Only override if mapping exists and field is not already set
25
+ if (mapping.obsidianSource === 'frontmatter' && mapping.frontmatterKey) {
26
+ // Only set if not already present
27
+ if (result[strapiField] === undefined) {
28
+ result[strapiField] = frontmatter[mapping.frontmatterKey] ?? null
29
+ }
30
+ }
31
+ // Handle content fields
32
+ else if (mapping.obsidianSource === 'content') {
33
+ result[strapiField] = body
34
+ }
35
+
36
+ // Apply transformations
37
+ if (mapping.transform && result[strapiField] !== null) {
38
+ try {
39
+ result[strapiField] = await applyTransformation(
40
+ result[strapiField],
41
+ mapping.transform,
42
+ strapiField
43
+ )
44
+ } catch (error) {
45
+ throw new Error(
46
+ `Failed to transform field ${strapiField}: ${error.message}`
47
+ )
48
+ }
49
+ }
50
+ }
51
+ return result
52
+ } catch (error) {
53
+ throw new Error(`File analysis failed: ${error.message}`)
54
+ }
55
+ }
56
+
57
+ async function applyTransformation(
58
+ value: any,
59
+ transform: string | ((value: any) => any),
60
+ fieldName: string
61
+ ): Promise<any> {
62
+ try {
63
+ if (typeof transform === 'function') {
64
+ return transform(value)
65
+ } else if (typeof transform === 'string') {
66
+ const transformFunction = new Function('value', `return ${transform}`)
67
+ return transformFunction(value)
68
+ }
69
+ return value
70
+ } catch (error) {
71
+ throw new Error(`Transformation failed: ${error.message}`)
72
+ }
73
+ }
74
+
75
+ export function extractFrontMatterAndContent(fileContent: string): {
76
+ frontmatter: Record<string, any>
77
+ body: string
78
+ } {
79
+ const frontMatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/
80
+ const match = fileContent.match(frontMatterRegex)
81
+
82
+ try {
83
+ if (match) {
84
+ const frontmatter = yaml.load(match[1]) as Record<string, any>
85
+ const body = match[2].trim()
86
+
87
+ return { frontmatter, body }
88
+ }
89
+
90
+ return { frontmatter: {}, body: fileContent.trim() }
91
+ } catch (error) {
92
+ throw new Error(`Failed to parse frontmatter: ${error.message}`)
93
+ }
94
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Creates a debounced version of the provided function
3
+ * @param func The function to debounce
4
+ * @param waitFor The time to wait in milliseconds
5
+ * @returns A debounced version of the function that returns a promise
6
+ */
7
+ export function debounce<F extends (...args: any[]) => any>(
8
+ func: F,
9
+ waitFor: number
10
+ ): (...args: Parameters<F>) => Promise<ReturnType<F>> {
11
+ let timeout: ReturnType<typeof setTimeout> | null = null
12
+
13
+ return (...args: Parameters<F>): Promise<ReturnType<F>> => {
14
+ // Clear existing timeout if any
15
+ if (timeout) {
16
+ clearTimeout(timeout)
17
+ timeout = null
18
+ }
19
+
20
+ // Create new promise
21
+ return new Promise((resolve, reject) => {
22
+ timeout = setTimeout(async () => {
23
+ try {
24
+ const result = await func(...args)
25
+ resolve(result)
26
+ } catch (error) {
27
+ reject(error)
28
+ } finally {
29
+ timeout = null
30
+ }
31
+ }, waitFor)
32
+ })
33
+ }
34
+ }