@maccesar/titools 2.2.11 → 2.2.12
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/package.json
CHANGED
|
@@ -38,78 +38,39 @@ Behavior:
|
|
|
38
38
|
5. Quality: testing, error handling, logging, performance
|
|
39
39
|
6. Cleanup: implement a `cleanup()` pattern for memory management
|
|
40
40
|
|
|
41
|
-
##
|
|
42
|
-
|
|
43
|
-
- Use technical-type organization in `lib` (for example: `api`, `services`, `actions`, `repositories`, `helpers`, `policies`, `providers`).
|
|
44
|
-
- Keep `lib` flat and predictable: `lib/<type>/<file>.js` only.
|
|
45
|
-
- Do not recommend deep nesting like `lib/services/auth/session/login.js`.
|
|
46
|
-
- Keep UI layers aligned by screen (`controllers/`, `views/`, `styles/`) and avoid unnecessary depth.
|
|
47
|
-
|
|
48
|
-
## Quick start example
|
|
49
|
-
|
|
50
|
-
Minimal example that matches the conventions:
|
|
51
|
-
|
|
52
|
-
View (`views/userCard.xml`)
|
|
53
|
-
```xml
|
|
54
|
-
<Alloy>
|
|
55
|
-
<View id="cardContainer">
|
|
56
|
-
<View id="headerRow">
|
|
57
|
-
<ImageView id="userIcon" image="/images/user.png" />
|
|
58
|
-
<Label id="name" />
|
|
59
|
-
</View>
|
|
60
|
-
<Button id="viewProfileBtn"
|
|
61
|
-
title="L('view_profile')"
|
|
62
|
-
onClick="onViewProfile"
|
|
63
|
-
/>
|
|
64
|
-
</View>
|
|
65
|
-
</Alloy>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Styles (`styles/userCard.tss`)
|
|
69
|
-
```tss
|
|
70
|
-
"#cardContainer": { left: 8, right: 8, top: 8, height: Ti.UI.SIZE, borderRadius: 12, backgroundColor: '#fff' }
|
|
71
|
-
"#headerRow": { layout: 'horizontal', left: 12, right: 12, top: 12, height: Ti.UI.SIZE, width: Ti.UI.FILL }
|
|
72
|
-
"#userIcon": { width: 32, height: 32 }
|
|
73
|
-
"#name": { left: 12, font: { fontSize: 18, fontWeight: 'bold' } }
|
|
74
|
-
"#viewProfileBtn": { left: 12, right: 12, bottom: 12, height: 40, width: Ti.UI.FILL, borderRadius: 6, backgroundColor: '#2563eb', color: '#fff' }
|
|
75
|
-
```
|
|
41
|
+
## Architectural Maturity Tiers
|
|
76
42
|
|
|
77
|
-
|
|
78
|
-
```javascript
|
|
79
|
-
const { Navigation } = require('services/navigation')
|
|
43
|
+
Choose the appropriate tier based on project complexity:
|
|
80
44
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
45
|
+
### Tier 1: Basic (Rapid Prototyping)
|
|
46
|
+
- **Best for**: Simple utility apps or developers transitioning from Classic.
|
|
47
|
+
- **Structure**: Logic resides directly within `index.js`.
|
|
48
|
+
- **UI Access**: Direct usage of the `$` object throughout the file.
|
|
49
|
+
- **Pros**: Zero boilerplate, extremely fast start.
|
|
50
|
+
- **Cons**: Unmaintainable beyond 500 lines of code.
|
|
85
51
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
52
|
+
### Tier 2: Intermediate (Modular Alloy)
|
|
53
|
+
- **Best for**: Standard commercial applications.
|
|
54
|
+
- **Structure**: Business logic extracted to `app/lib/` using a flat technical-type organization.
|
|
55
|
+
- **Pattern**: Slim Controllers that `require()` services.
|
|
56
|
+
- **Memory**: Mandatory implementation of `$.cleanup = cleanup`.
|
|
89
57
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
58
|
+
### Tier 3: Advanced / Enterprise (Service-Oriented)
|
|
59
|
+
- **Best for**: High-complexity apps (IDEs like TiDesigner, multi-state platforms).
|
|
60
|
+
- **Architecture**: Dependency Injection via a `ServiceRegistry`.
|
|
61
|
+
- **ID Scoping**: Services do not receive the entire `$` object. They receive a "Scoped UI" object containing only relevant IDs.
|
|
62
|
+
- **Cognitive Load**: "Black Box" logic—encapsulated units that reduce mental fatigue.
|
|
63
|
+
- **Observability**: Structured logging with a mandatory `service` context.
|
|
93
64
|
|
|
94
|
-
|
|
95
|
-
```
|
|
65
|
+
Detailed examples and full implementation samples are available in: [Architectural Tiers Detail](references/architecture-tiers.md)
|
|
96
66
|
|
|
97
|
-
|
|
98
|
-
```javascript
|
|
99
|
-
exports.Navigation = {
|
|
100
|
-
open(route, params = {}) {
|
|
101
|
-
const controller = Alloy.createController(route, params)
|
|
102
|
-
const view = controller.getView()
|
|
67
|
+
## Organization policy (low freedom)
|
|
103
68
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
69
|
+
- Use technical-type organization in `lib` (for example: `api`, `services`, `actions`, `repositories`, `helpers`, `policies`, `providers`).
|
|
70
|
+
- Keep `lib` flat and predictable: `lib/<type>/<file>.js` only.
|
|
71
|
+
- Do not recommend deep nesting like `lib/services/auth/session/login.js`.
|
|
72
|
+
- Keep UI layers aligned by screen (`controllers/`, `views/`, `styles/`) and avoid unnecessary depth.
|
|
107
73
|
|
|
108
|
-
view.open()
|
|
109
|
-
return controller
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
74
|
|
|
114
75
|
## Code standards (low freedom)
|
|
115
76
|
|
|
@@ -166,41 +127,47 @@ For the complete reference with examples, see [Alloy builtins and globals](refer
|
|
|
166
127
|
|
|
167
128
|
| Question | Answer |
|
|
168
129
|
| ---------------------------------- | -------------------------------------------------------------- |
|
|
169
|
-
| How to create a new Alloy project? | `ti create -t app --alloy` (not `--classic` + `alloy new`)
|
|
130
|
+
| How to create a new Alloy project? | `ti create -t app --alloy` (not `--classic` + `alloy new`) |
|
|
170
131
|
| Fastest way to build? | `tn <recipe>` (using TiNy CLI wrapper) |
|
|
132
|
+
| Controller > 100 lines? | Extract to Tier 2 (Services) |
|
|
133
|
+
| More than 50 IDs in XML? | Use Tier 3 (ID Scoping) |
|
|
171
134
|
| Where does API call go? | `lib/api/` |
|
|
172
135
|
| Where does business logic go? | `lib/services/` |
|
|
173
|
-
| How deep should `lib` folders be? | One level: `lib/<type>/<file>.js`
|
|
136
|
+
| How deep should `lib` folders be? | One level: `lib/<type>/<file>.js` |
|
|
174
137
|
| Where do I store auth tokens? | Keychain (iOS) / KeyStore (Android) via service |
|
|
175
138
|
| Models or Collections? | Collections for API data, Models for SQLite persistence |
|
|
176
139
|
| Ti.App.fireEvent or EventBus? | Always EventBus (Backbone.Events) |
|
|
177
140
|
| Direct navigation or service? | Always Navigation service (auto cleanup) |
|
|
178
|
-
| Inline styles or TSS files? | Always TSS files (per-controller + `app.tss` for global)
|
|
179
|
-
| Controller 100+ lines? | Extract logic to services |
|
|
141
|
+
| Inline styles or TSS files? | Always TSS files (per-controller + `app.tss` for global) |
|
|
180
142
|
|
|
181
143
|
## Reference guides (progressive disclosure)
|
|
182
144
|
|
|
183
|
-
Architecture
|
|
184
|
-
- [
|
|
185
|
-
- [
|
|
186
|
-
- [
|
|
187
|
-
- [
|
|
188
|
-
- [
|
|
189
|
-
- [
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- [Code
|
|
194
|
-
- [
|
|
195
|
-
- [
|
|
196
|
-
- [
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
- [
|
|
201
|
-
- [
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
- [
|
|
205
|
-
|
|
206
|
-
|
|
145
|
+
### Architecture & Patterns
|
|
146
|
+
- [Architectural Tiers Detail](references/architecture-tiers.md)
|
|
147
|
+
- [Architectural Patterns](references/patterns.md) (Factory, Singleton, Repository)
|
|
148
|
+
- [Structure & Organization](references/alloy-structure.md)
|
|
149
|
+
- [Contracts & Communication](references/contracts.md)
|
|
150
|
+
- [State Management](references/state-management.md)
|
|
151
|
+
- [Anti-patterns to Avoid](references/anti-patterns.md)
|
|
152
|
+
|
|
153
|
+
### Implementation & API
|
|
154
|
+
- [Alloy Builtins & Globals](references/alloy-builtins.md)
|
|
155
|
+
- [Code Conventions](references/code-conventions.md)
|
|
156
|
+
- [Controller Patterns](references/controller-patterns.md)
|
|
157
|
+
- [Theming & Dark Mode](references/theming.md)
|
|
158
|
+
- [Migration Patterns](references/migration-patterns.md)
|
|
159
|
+
- [Examples Collection](references/examples.md)
|
|
160
|
+
|
|
161
|
+
### Quality & Performance
|
|
162
|
+
- [Performance Optimization](references/performance-optimization.md)
|
|
163
|
+
- [ListView & ScrollView Performance](references/performance-listview.md)
|
|
164
|
+
- [Error Handling & Logging](references/error-handling.md)
|
|
165
|
+
- [Unit & Integration Testing](references/testing-unit.md)
|
|
166
|
+
- [E2E Testing & CI/CD](references/testing-e2e-ci.md)
|
|
167
|
+
|
|
168
|
+
### Security
|
|
169
|
+
- [Security Fundamentals](references/security-fundamentals.md)
|
|
170
|
+
- [Device Security](references/security-device.md)
|
|
171
|
+
|
|
172
|
+
### Tools
|
|
173
|
+
- [CLI Expert & TiNy](references/cli-expert.md)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Titanium Architectural Maturity Tiers
|
|
2
|
+
|
|
3
|
+
To ensure scalability and maintainability, Titanium projects should follow one of these three tiers based on their complexity.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Tier 1 — Basic (Rapid Prototyping)
|
|
8
|
+
|
|
9
|
+
**Best for:** Utilities, internal tools, proof of concept, learning Alloy.
|
|
10
|
+
|
|
11
|
+
### Characteristics
|
|
12
|
+
|
|
13
|
+
* Logic directly in `index.js`
|
|
14
|
+
* Direct `$` access everywhere
|
|
15
|
+
* No separation of concerns
|
|
16
|
+
* No cleanup strategy
|
|
17
|
+
|
|
18
|
+
### When to upgrade?
|
|
19
|
+
|
|
20
|
+
* Controller > 100–150 lines
|
|
21
|
+
* Logic duplicated in multiple controllers
|
|
22
|
+
* UI starts feeling coupled
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Example (Tier 1)
|
|
27
|
+
|
|
28
|
+
### Controller (`controllers/index.js`)
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
function onButtonClick() {
|
|
32
|
+
$.label.text = "Clicked!"
|
|
33
|
+
Ti.API.info("Button was clicked")
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
$.index.open()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Simple. Fast. Dangerous beyond small apps.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
# Tier 2 — Intermediate (Modular Alloy)
|
|
44
|
+
|
|
45
|
+
**Best for:** Standard commercial applications.
|
|
46
|
+
|
|
47
|
+
### Characteristics
|
|
48
|
+
|
|
49
|
+
* Business logic extracted to `app/lib/`
|
|
50
|
+
* Slim controllers
|
|
51
|
+
* Flat organization (`lib/services`, `lib/api`)
|
|
52
|
+
* Mandatory `cleanup`
|
|
53
|
+
* Reusable UI components
|
|
54
|
+
|
|
55
|
+
### Why this tier exists
|
|
56
|
+
|
|
57
|
+
This tier separates UI from logic, but still allows services to reference global dependencies.
|
|
58
|
+
|
|
59
|
+
It’s modular — but not yet decoupled.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Example (Tier 2)
|
|
64
|
+
|
|
65
|
+
### View (`views/userCard.xml`)
|
|
66
|
+
|
|
67
|
+
```xml
|
|
68
|
+
<Alloy>
|
|
69
|
+
<View id="cardContainer">
|
|
70
|
+
<View id="headerRow">
|
|
71
|
+
<ImageView id="userIcon" image="/images/user.png" />
|
|
72
|
+
<Label id="name" />
|
|
73
|
+
</View>
|
|
74
|
+
|
|
75
|
+
<Button id="viewProfileBtn"
|
|
76
|
+
title="View Profile"
|
|
77
|
+
onClick="onViewProfile" />
|
|
78
|
+
</View>
|
|
79
|
+
</Alloy>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### Controller (`controllers/userCard.js`)
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const { Navigation } = require('services/navigation')
|
|
88
|
+
|
|
89
|
+
function init() {
|
|
90
|
+
const user = $.args.user
|
|
91
|
+
$.name.text = user.name
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function onViewProfile() {
|
|
95
|
+
Navigation.open('userProfile', { userId: $.args.user.id })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function cleanup() {
|
|
99
|
+
$.destroy()
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
$.cleanup = cleanup
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### Service (`lib/services/navigation.js`)
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
exports.Navigation = {
|
|
111
|
+
open(route, params = {}) {
|
|
112
|
+
const controller = Alloy.createController(route, params)
|
|
113
|
+
const view = controller.getView()
|
|
114
|
+
|
|
115
|
+
view.addEventListener('close', () => {
|
|
116
|
+
if (controller.cleanup) controller.cleanup()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
view.open()
|
|
120
|
+
return controller
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### What improves from Tier 1?
|
|
128
|
+
|
|
129
|
+
* Controllers stay under control
|
|
130
|
+
* Logic is reusable
|
|
131
|
+
* Memory is explicitly cleaned
|
|
132
|
+
* Code is easier to test
|
|
133
|
+
|
|
134
|
+
But services can still depend directly on other services or globals.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
# Tier 3 — Advanced / Enterprise (Service-Oriented)
|
|
139
|
+
|
|
140
|
+
**Best for:** Complex applications (IDEs, platforms, multi-state apps).
|
|
141
|
+
|
|
142
|
+
This is where architectural maturity changes fundamentally.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Core Concepts
|
|
147
|
+
|
|
148
|
+
### 1️⃣ Dependency Injection
|
|
149
|
+
|
|
150
|
+
Services receive what they need — they don’t fetch it.
|
|
151
|
+
|
|
152
|
+
### 2️⃣ Service Registry
|
|
153
|
+
|
|
154
|
+
Centralized dependency wiring.
|
|
155
|
+
|
|
156
|
+
### 3️⃣ ID Scoping
|
|
157
|
+
|
|
158
|
+
Services receive only the UI elements they own.
|
|
159
|
+
|
|
160
|
+
### 4️⃣ Encapsulation (Black Box Principle)
|
|
161
|
+
|
|
162
|
+
Once a service method works, treat it as trusted.
|
|
163
|
+
|
|
164
|
+
### 5️⃣ Observability
|
|
165
|
+
|
|
166
|
+
All logs are structured and include service context.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Example (Tier 3)
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Service (`lib/services/chatService.js`)
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
/**
|
|
178
|
+
* @param {Object} deps
|
|
179
|
+
* @param {Object} deps.ui - Scoped UI elements
|
|
180
|
+
* @param {Object} deps.logger
|
|
181
|
+
* @param {Object} deps.designService
|
|
182
|
+
*/
|
|
183
|
+
module.exports = function createChatService(deps) {
|
|
184
|
+
const { ui, logger, designService } = deps
|
|
185
|
+
|
|
186
|
+
function sendMessage(text) {
|
|
187
|
+
if (!text) return
|
|
188
|
+
|
|
189
|
+
ui.sendBtn.enabled = false // ID Scoping
|
|
190
|
+
designService.trackMessage(text) // Inter-service communication
|
|
191
|
+
|
|
192
|
+
logger.event('message:sent', {
|
|
193
|
+
service: 'ChatService',
|
|
194
|
+
length: text.length
|
|
195
|
+
})
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
sendMessage
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### Registry (`lib/services/indexServiceRegistry.js`)
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
const createChatService = require('services/chatService')
|
|
210
|
+
const createDesignService = require('services/designService')
|
|
211
|
+
|
|
212
|
+
module.exports = function createIndexServiceRegistry(deps) {
|
|
213
|
+
const { $, Ti, logger } = deps
|
|
214
|
+
|
|
215
|
+
// 1. Independent services
|
|
216
|
+
const designService = createDesignService({ Ti, logger })
|
|
217
|
+
|
|
218
|
+
// 2. Dependent services with scoped UI
|
|
219
|
+
const chatService = createChatService({
|
|
220
|
+
ui: {
|
|
221
|
+
sendBtn: $.sendBtn,
|
|
222
|
+
messageInput: $.messageInput
|
|
223
|
+
},
|
|
224
|
+
logger,
|
|
225
|
+
designService
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
return {
|
|
229
|
+
chatService,
|
|
230
|
+
designService
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Decision Matrix
|
|
238
|
+
|
|
239
|
+
| Signal | Move To |
|
|
240
|
+
| ----------------------------------- | ------- |
|
|
241
|
+
| Controller > 100 lines | Tier 2 |
|
|
242
|
+
| Controller > 300 lines | Tier 3 |
|
|
243
|
+
| More than 50 IDs in XML | Tier 3 |
|
|
244
|
+
| Services need to talk to each other | Tier 3 |
|
|
245
|
+
| Multiple application states | Tier 3 |
|
|
246
|
+
| Memory leaks appear | Tier 3 |
|
|
247
|
+
|
|
248
|
+
---
|