metaowl 0.4.1 → 0.6.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 (83) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +267 -2
  3. package/build/runtime/bin/metaowl-build.js +10 -0
  4. package/{bin → build/runtime/bin}/metaowl-create.js +96 -177
  5. package/build/runtime/bin/metaowl-dev.js +10 -0
  6. package/build/runtime/bin/metaowl-generate.js +231 -0
  7. package/build/runtime/bin/metaowl-lint.js +58 -0
  8. package/build/runtime/bin/utils.js +68 -0
  9. package/build/runtime/index.js +144 -0
  10. package/build/runtime/modules/app-mounter.js +73 -0
  11. package/build/runtime/modules/auto-import.js +140 -0
  12. package/build/runtime/modules/cache.js +49 -0
  13. package/build/runtime/modules/composables.js +353 -0
  14. package/build/runtime/modules/constants.js +38 -0
  15. package/build/runtime/modules/error-boundary.js +116 -0
  16. package/build/runtime/modules/fetch.js +31 -0
  17. package/build/runtime/modules/file-router.js +207 -0
  18. package/build/runtime/modules/fonts.js +172 -0
  19. package/build/runtime/modules/forms.js +193 -0
  20. package/build/runtime/modules/i18n.js +180 -0
  21. package/build/runtime/modules/image.js +175 -0
  22. package/build/runtime/modules/layouts.js +214 -0
  23. package/build/runtime/modules/link.js +141 -0
  24. package/build/runtime/modules/meta.js +117 -0
  25. package/build/runtime/modules/odoo-rpc.js +265 -0
  26. package/build/runtime/modules/pwa.js +272 -0
  27. package/build/runtime/modules/router.js +384 -0
  28. package/build/runtime/modules/seo.js +186 -0
  29. package/build/runtime/modules/store.js +198 -0
  30. package/build/runtime/modules/templates-manager.js +52 -0
  31. package/build/runtime/modules/test-utils.js +238 -0
  32. package/build/runtime/vite/plugin.js +197 -0
  33. package/eslint.js +29 -0
  34. package/package.json +45 -27
  35. package/CONTRIBUTING.md +0 -49
  36. package/bin/metaowl-build.js +0 -12
  37. package/bin/metaowl-dev.js +0 -12
  38. package/bin/metaowl-generate.js +0 -339
  39. package/bin/metaowl-lint.js +0 -71
  40. package/bin/utils.js +0 -82
  41. package/eslint.config.js +0 -3
  42. package/index.js +0 -328
  43. package/modules/app-mounter.js +0 -104
  44. package/modules/auto-import.js +0 -225
  45. package/modules/cache.js +0 -59
  46. package/modules/composables.js +0 -600
  47. package/modules/error-boundary.js +0 -228
  48. package/modules/fetch.js +0 -51
  49. package/modules/file-router.js +0 -478
  50. package/modules/forms.js +0 -353
  51. package/modules/i18n.js +0 -333
  52. package/modules/layouts.js +0 -431
  53. package/modules/link.js +0 -255
  54. package/modules/meta.js +0 -119
  55. package/modules/odoo-rpc.js +0 -511
  56. package/modules/pwa.js +0 -515
  57. package/modules/router.js +0 -769
  58. package/modules/seo.js +0 -501
  59. package/modules/store.js +0 -409
  60. package/modules/templates-manager.js +0 -89
  61. package/modules/test-utils.js +0 -532
  62. package/test/auto-import.test.js +0 -110
  63. package/test/cache.test.js +0 -55
  64. package/test/composables.test.js +0 -103
  65. package/test/dynamic-routes.test.js +0 -469
  66. package/test/error-boundary.test.js +0 -126
  67. package/test/fetch.test.js +0 -100
  68. package/test/file-router.test.js +0 -55
  69. package/test/forms.test.js +0 -203
  70. package/test/i18n.test.js +0 -188
  71. package/test/layouts.test.js +0 -395
  72. package/test/link.test.js +0 -189
  73. package/test/meta.test.js +0 -146
  74. package/test/odoo-rpc.test.js +0 -547
  75. package/test/pwa.test.js +0 -154
  76. package/test/router-guards.test.js +0 -229
  77. package/test/router.test.js +0 -77
  78. package/test/seo.test.js +0 -353
  79. package/test/store.test.js +0 -476
  80. package/test/templates-manager.test.js +0 -83
  81. package/test/test-utils.test.js +0 -314
  82. package/vite/plugin.js +0 -290
  83. package/vitest.config.js +0 -8
@@ -1,225 +0,0 @@
1
- /**
2
- * @module AutoImport
3
- *
4
- * Automatic component importing for MetaOwl applications.
5
- *
6
- * Features:
7
- * - Auto-discovers components from src/components/
8
- * - Generates import statements at build time
9
- * - Optional - disabled by default
10
- *
11
- * Configuration in vite.config.js:
12
- * metaowlConfig({
13
- * autoImport: {
14
- * enabled: true,
15
- * componentsDir: 'src/components',
16
- * pattern: '*.js'
17
- * }
18
- * })
19
- *
20
- * Usage:
21
- * - Components are automatically available in templates
22
- * - No manual import needed
23
- */
24
-
25
- import { globSync } from 'glob'
26
- import { resolve, relative, basename, extname, dirname } from 'node:path'
27
-
28
- /**
29
- * Registry of auto-discovered components.
30
- */
31
- let _importMap = null
32
-
33
- /**
34
- * Generate component import map from directory.
35
- *
36
- * @param {string} componentsDir - e.g. 'src/components'
37
- * @returns {Map<string, string>} Map of PascalCase names to import paths
38
- */
39
- export function generateComponentMap(componentsDir, pattern = '*.js') {
40
- const map = new Map()
41
- const globPattern = pattern.includes('/') ? pattern : `${componentsDir}/${pattern}`
42
- const files = globSync(globPattern)
43
-
44
- for (const file of files) {
45
- if (file.includes('.test.') || file.includes('.spec.')) continue
46
-
47
- const name = getComponentName(file)
48
- if (!name) continue
49
-
50
- const importPath = `/@components/${relative(componentsDir, file).replace(/\\/g, '/')}`
51
- map.set(name, importPath)
52
- }
53
-
54
- return map
55
- }
56
-
57
- function getComponentName(filePath) {
58
- const ext = extname(filePath)
59
- const base = basename(filePath, ext)
60
-
61
- if (basename(filePath) === base + ext) {
62
- return base
63
- }
64
-
65
- const dir = relative(process.cwd(), filePath).split('/')
66
- if (base === 'index' && dir.length > 1) {
67
- return toPascalCase(dir[dir.length - 2])
68
- }
69
-
70
- return toPascalCase(base)
71
- }
72
-
73
- function toPascalCase(str) {
74
- return str
75
- .replace(/[-_](.)/g, (_, char) => char.toUpperCase())
76
- .replace(/^[a-z]/, char => char.toUpperCase())
77
- }
78
-
79
- /**
80
- * Scan components directory for component files.
81
- *
82
- * @param {string} componentsDir - Directory to scan
83
- * @param {object} options - Options
84
- * @param {string} options.pattern - Glob pattern
85
- * @returns {Promise<string[]>} Array of component names
86
- */
87
- export async function scanComponents(componentsDir, options = {}) {
88
- const { pattern = '*.js' } = options
89
- const absoluteDir = resolve(componentsDir)
90
- const fs = await import('fs/promises')
91
- const { join } = await import('path')
92
-
93
- const components = []
94
-
95
- async function scanDir(dir) {
96
- try {
97
- const entries = await fs.readdir(dir, { withFileTypes: true })
98
-
99
- for (const entry of entries) {
100
- const fullPath = join(dir, entry.name)
101
-
102
- if (entry.isDirectory()) {
103
- // Recursively scan subdirectories
104
- await scanDir(fullPath)
105
- } else if (entry.isFile() && entry.name.endsWith('.js')) {
106
- // Skip test files
107
- if (entry.name.includes('.test.') || entry.name.includes('.spec.')) continue
108
-
109
- const name = getComponentName(fullPath)
110
- if (name && !components.includes(name)) {
111
- components.push(name)
112
- }
113
- }
114
- }
115
- } catch {
116
- // Directory doesn't exist or can't be read
117
- }
118
- }
119
-
120
- await scanDir(absoluteDir)
121
- return components
122
- }
123
-
124
- /**
125
- * Generate TypeScript declarations file for components.
126
- *
127
- * @param {string[]} components - Array of component names
128
- * @param {string} outputPath - Path to write .d.ts file
129
- * @returns {Promise<void>}
130
- */
131
- export async function generateComponentDts(components, outputPath) {
132
- const { writeFileSync, mkdirSync } = await import('fs')
133
- const { join } = await import('path')
134
-
135
- // Ensure directory exists
136
- const dir = dirname(outputPath)
137
- mkdirSync(dir, { recursive: true })
138
-
139
- const declarations = components.map(name =>
140
- ` ${name}: typeof import('./components/${name}/${name}.js').default`
141
- ).join('\n')
142
-
143
- const content = `// Auto-generated by metaowl - do not edit\ndeclare module '@metaowl/components' {\n${declarations}\n}\n`
144
-
145
- writeFileSync(outputPath, content, 'utf-8')
146
- }
147
-
148
- export function generateImports(componentMap) {
149
- const lines = []
150
- for (const [name, path] of componentMap) {
151
- lines.push(`import ${name} from '${path}'`)
152
- }
153
- return lines.join('\n')
154
- }
155
-
156
- export function generateComponentsObject(componentMap) {
157
- const entries = Array.from(componentMap.keys())
158
- .map(name => ` ${name}`)
159
- .join(',\n')
160
- return `{\n${entries}\n}`
161
- }
162
-
163
- export function createAutoImportPlugin(options = {}) {
164
- const {
165
- enabled = false,
166
- componentsDir = 'src/components',
167
- pattern = '**/*.js'
168
- } = options
169
-
170
- if (!enabled) {
171
- return null
172
- }
173
-
174
- _importMap = generateComponentMap(componentsDir, `${componentsDir}/${pattern}`)
175
-
176
- return {
177
- name: 'metaowl:auto-import',
178
- enforce: 'pre',
179
-
180
- config(config) {
181
- config.resolve ||= {}
182
- config.resolve.alias ||= {}
183
- config.resolve.alias['/@components'] = resolve(process.cwd(), componentsDir)
184
- },
185
-
186
- transform(code, id) {
187
- if (!id.includes('/pages/') || !/\.[jt]s$/.test(id)) {
188
- return null
189
- }
190
-
191
- if (!code.includes('/* auto-import */') && !code.includes('// auto-import')) {
192
- return null
193
- }
194
-
195
- const imports = generateImports(_importMap)
196
- const componentsObj = generateComponentsObject(_importMap)
197
-
198
- let transformed = imports + '\n\n' + code
199
-
200
- if (transformed.includes('extends Component')) {
201
- transformed = transformed.replace(
202
- /(class\s+\w+\s+extends\s+Component\s*\{)/,
203
- `$1\n static components = ${componentsObj}\n`
204
- )
205
- }
206
-
207
- return { code: transformed, map: null }
208
- }
209
- }
210
- }
211
-
212
- export function registerAutoImport(name, path) {
213
- if (!_importMap) {
214
- _importMap = new Map()
215
- }
216
- _importMap.set(name, path)
217
- }
218
-
219
- export function getAutoImportMap() {
220
- return _importMap ? new Map(_importMap) : null
221
- }
222
-
223
- export function clearAutoImports() {
224
- _importMap = null
225
- }
package/modules/cache.js DELETED
@@ -1,59 +0,0 @@
1
- /**
2
- * @module Cache
3
- *
4
- * Async-style localStorage wrapper.
5
- *
6
- * Values are automatically JSON-serialised on write and deserialised on read.
7
- * All methods return Promises so they are interchangeable with IndexedDB-based
8
- * alternatives without changing call-sites.
9
- */
10
- export default class Cache {
11
- /**
12
- * Retrieve a value by key.
13
- *
14
- * @param {string} key
15
- * @returns {Promise<any>} Parsed value, or `null` if the key does not exist.
16
- */
17
- static async get(key) {
18
- return JSON.parse(localStorage.getItem(key))
19
- }
20
-
21
- /**
22
- * Store a value under the given key.
23
- *
24
- * @param {string} key
25
- * @param {any} value - Must be JSON-serialisable.
26
- * @returns {Promise<void>}
27
- */
28
- static async set(key, value) {
29
- localStorage.setItem(key, JSON.stringify(value))
30
- }
31
-
32
- /**
33
- * Remove a single entry.
34
- *
35
- * @param {string} key
36
- * @returns {Promise<void>}
37
- */
38
- static async remove(key) {
39
- localStorage.removeItem(key)
40
- }
41
-
42
- /**
43
- * Remove **all** entries from localStorage.
44
- *
45
- * @returns {Promise<void>}
46
- */
47
- static async clear() {
48
- localStorage.clear()
49
- }
50
-
51
- /**
52
- * Return all keys currently stored in localStorage.
53
- *
54
- * @returns {Promise<string[]>}
55
- */
56
- static async keys() {
57
- return Array.from({ length: localStorage.length }, (_, i) => localStorage.key(i))
58
- }
59
- }