squared 0.5.4 → 0.5.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +123 -63
- data/README.md +662 -1273
- data/lib/squared/common/base.rb +1 -1
- data/lib/squared/common/format.rb +5 -3
- data/lib/squared/common/prompt.rb +1 -1
- data/lib/squared/common/shell.rb +7 -2
- data/lib/squared/common/system.rb +1 -1
- data/lib/squared/config.rb +8 -8
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +26 -8
- data/lib/squared/workspace/project/base.rb +94 -19
- data/lib/squared/workspace/project/docker.rb +2 -2
- data/lib/squared/workspace/project/git.rb +140 -118
- data/lib/squared/workspace/project/node.rb +18 -19
- data/lib/squared/workspace/project/python.rb +36 -19
- data/lib/squared/workspace/project/ruby.rb +97 -53
- data/lib/squared/workspace/project/support/class.rb +46 -3
- data/lib/squared/workspace/repo.rb +36 -13
- data/squared.gemspec +2 -2
- metadata +5 -6
- data/README.ruby.md +0 -728
data/README.md
CHANGED
@@ -1,1360 +1,749 @@
|
|
1
|
-
# squared
|
1
|
+
# squared 0.5
|
2
2
|
|
3
|
-
|
3
|
+
* [source](https://github.com/anpham6/squared-ruby)
|
4
|
+
* [docs](https://squared.readthedocs.io)
|
4
5
|
|
5
|
-
|
6
|
+
## Version Compatibility
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
| Date | squared | Min | Max |
|
9
|
+
| :--------: | ------: | -----: | -----: |
|
10
|
+
| 2024-12-07 | 0.1.0 | 2.4.0 | 3.3.6 |
|
11
|
+
| 2025-01-07 | 0.2.0 | | 3.4.0 |
|
12
|
+
| 2025-02-07 | 0.3.0 | | 3.4.1 |
|
13
|
+
| 2025-03-06 | 0.4.0 | | 3.4.2 |
|
14
|
+
| 2025-06-16 | 0.5.0 | 2.5.0 | 3.4.3 |
|
15
|
+
| ---------- | ----- | ----- | ----- |
|
16
|
+
| 2025-08-23 | 0.5.5 | | 3.4.5 |
|
9
17
|
|
10
|
-
|
11
|
-
> Content in the README was migrated into `Read the Docs`. The file is no longer fully maintained.
|
12
|
-
|
13
|
-
### README
|
14
|
-
|
15
|
-
* [squared-express](https://github.com/anpham6/squared-express#readme)
|
16
|
-
* [E-mc](https://github.com/anpham6/e-mc#readme)
|
17
|
-
* [Pi-r](https://github.com/anpham6/pi-r#readme)
|
18
|
-
* [Pi-r2](https://github.com/anpham6/pi-r2#readme)
|
18
|
+
The range chart indicates the latest Ruby tested against at the time of release.
|
19
19
|
|
20
20
|
## Installation
|
21
21
|
|
22
|
-
* NodeJS 18
|
23
|
-
|
24
|
-
### NPX
|
25
|
-
|
26
22
|
```sh
|
27
|
-
|
28
|
-
> npm i sqd-cli sqd-serve
|
29
|
-
|
30
|
-
> npx sqd init
|
31
|
-
# OR
|
32
|
-
> npx sqd init --public --local-serve # Same as squared-express
|
33
|
-
|
34
|
-
> npx sqd serve --access-all
|
35
|
-
# OR
|
36
|
-
> node serve.cjs --access-all
|
23
|
+
gem install squared
|
37
24
|
```
|
38
25
|
|
39
|
-
|
40
|
-
> npm init
|
41
|
-
> npm i squared sqd-serve
|
42
|
-
|
43
|
-
> mkdir dist html
|
44
|
-
> cp -r ./node_modules/squared/dist/* ./dist
|
45
|
-
> cp ./node_modules/squared/html/* ./html # optional
|
46
|
-
> cp ./node_modules/sqd-serve/config/json/* . # yaml
|
26
|
+
### Optional
|
47
27
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
28
|
+
* [Repo](https://source.android.com/docs/setup/reference/repo)
|
29
|
+
* https://github.com/anpham6/squared-repo
|
30
|
+
* Python 3.6
|
31
|
+
* Not compatible with Windows
|
52
32
|
|
53
33
|
```sh
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
> npm run prod
|
59
|
-
|
60
|
-
> cd ..
|
61
|
-
|
62
|
-
> git clone https://github.com/anpham6/squared-express
|
63
|
-
> cd squared-express
|
64
|
-
|
65
|
-
> npm i
|
66
|
-
> npm run prod
|
67
|
-
> npm run deploy # deploy:yaml
|
68
|
-
|
69
|
-
> cd ../squared
|
70
|
-
|
71
|
-
> node serve.cjs --access-all # squared.{json,yml}
|
34
|
+
mkdir -p ~/.bin
|
35
|
+
PATH="${HOME}/.bin:${PATH}"
|
36
|
+
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
|
37
|
+
chmod a+rx ~/.bin/repo
|
72
38
|
```
|
73
39
|
|
74
|
-
|
40
|
+
## Example - Rakefile
|
75
41
|
|
76
|
-
*
|
77
|
-
* [Commands](https://source.android.com/docs/setup/reference/repo)
|
42
|
+
Projects from any accessible folder can be added relative to the parent directory (e.g. *REPO_ROOT*) or absolutely. The same Rakefile can also manage other similarly cloned `Repo` repositories remotely by setting the `REPO_ROOT` environment variable to the location. Missing projects will simply be excluded from the task runner.
|
78
43
|
|
79
|
-
|
44
|
+
```ruby
|
45
|
+
require "squared"
|
80
46
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
47
|
+
require "squared/workspace"
|
48
|
+
require "squared/workspace/repo" # Optional
|
49
|
+
require "squared/workspace/project/node" #
|
50
|
+
require "squared/workspace/project/python" #
|
51
|
+
require "squared/workspace/project/ruby" #
|
52
|
+
require "squared/workspace/project/docker" #
|
87
53
|
# OR
|
88
|
-
|
89
|
-
```
|
90
|
-
|
91
|
-
#### Usage
|
54
|
+
require "squared/app" # All workspace related modules
|
92
55
|
|
93
|
-
|
94
|
-
mkdir workspaces
|
95
|
-
cd workspaces
|
96
|
-
|
97
|
-
repo init -u https://github.com/anpham6/squared-repo -m latest.xml
|
98
|
-
repo sync -j4
|
56
|
+
# NODE_ENV = production
|
99
57
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
#### Ruby
|
105
|
-
|
106
|
-
Workspace management uses [Ruby](https://www.ruby-lang.org/en/documentation/installation) for syncing and building. It is not installed by default on most operating systems.
|
107
|
-
|
108
|
-
```sh
|
109
|
-
mkdir workspaces
|
110
|
-
cd workspaces # REPO_ROOT
|
111
|
-
|
112
|
-
wget https://unpkg.com/squared/Rakefile
|
113
|
-
|
114
|
-
rake -T # List tasks
|
115
|
-
|
116
|
-
# REPO_BUILD={dev,prod}
|
117
|
-
# PIPE_FAIL=1
|
118
|
-
rake repo:init # nightly
|
119
|
-
rake repo:init[latest] # squared
|
120
|
-
rake repo:init[0.11.x] # e-mc
|
121
|
-
# OR
|
122
|
-
REPO_ROOT=/tmp/123 NODE_INSTALL=pnpm repo:init
|
123
|
-
# OR - without Repo
|
124
|
-
rake clone:node # master
|
125
|
-
rake clone # node + docs
|
126
|
-
```
|
127
|
-
|
128
|
-
> [!TIP]
|
129
|
-
> Use the supplied Rakefile inside the **squared** project folder once the source has been downloaded.
|
130
|
-
|
131
|
-
#### Docker
|
132
|
-
|
133
|
-
```sh
|
134
|
-
# NODE_TAG=latest
|
135
|
-
# RUBY_VERSION=2.4.0-3.4.0
|
136
|
-
# MANIFEST=nightly,prod,latest,android
|
137
|
-
# BUILD={dev,prod}
|
138
|
-
# DEV={0,1,local}
|
139
|
-
# DOCS=any
|
140
|
-
# PIPE_FAIL={0,1}
|
141
|
-
# PORT=3000
|
142
|
-
docker build -t squared --build-arg MANIFEST=prod --build-arg NODE_ENV=production .
|
143
|
-
docker build -t node --build-arg NODE_TAG=22 --build-arg NODE_INSTALL=pnpm -f Dockerfile.slim .
|
144
|
-
NODE=22 docker buildx bake node
|
58
|
+
# REPO_ROOT = /workspaces |
|
59
|
+
# REPO_HOME = /workspaces/squared | Dir.pwd
|
60
|
+
# rake = /workspaces/squared/Rakefile | main?
|
145
61
|
# OR
|
146
|
-
|
147
|
-
|
148
|
-
#
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
menu: "" // Will copy to default location "res/menu"
|
235
|
-
/* integer + fraction + array + color + dimension + style + theme = Same as "string" */
|
236
|
-
},
|
237
|
-
enabledMultiline: false,
|
238
|
-
enabledSubstitute: true,
|
239
|
-
include: ["android.substitute"], // Automatically removed after finalize
|
240
|
-
exclude: ["squared.list", "squared.grid"], // Disabled only during parseDocument
|
241
|
-
excludeQuery: [{
|
242
|
-
selector: "main > article", // Hide elements
|
243
|
-
/* OR */
|
244
|
-
resource: squared.base.lib.constant.NODE_RESOURCE.BOX_STYLE, // Exclusions during processing
|
245
|
-
procedure: squared.base.lib.constant.NODE_PROCEDURE.OPTIMIZATION,
|
246
|
-
section: squared.base.lib.constant.APP_SECTION.DOM_TRAVERSE
|
247
|
-
}],
|
248
|
-
customizationsBaseAPI: -1,
|
249
|
-
observe(mutations, observer, settings) { // Uses MutationObserver
|
250
|
-
squared.reset(); // Required when calling "parseDocument" after a File action
|
251
|
-
squared.parseDocument(settings).then(() => {
|
252
|
-
squared.copyTo("/path/project", { modified: true }).then(response => console.log(response));
|
253
|
-
});
|
254
|
-
},
|
255
|
-
afterCascade(sessionId, node) {/* Restore previous state */},
|
256
|
-
beforeRender(layout: LayoutUI) {/* Edit initial values */},
|
257
|
-
afterFinalize(node: NodeUI) {/* Edit controller values */}
|
258
|
-
},
|
259
|
-
{ // Only "element" is required
|
260
|
-
element: "fragment-1",
|
261
|
-
projectId: "project-1", // Implicit once projectId is not "_"
|
262
|
-
resourceQualifier: "land",
|
263
|
-
pathname: "app/src/main/res/layout-hdpi", // Will not be overridden by resourceQualifier "land"
|
264
|
-
filename: "fragment.xml",
|
265
|
-
baseLayoutAsFragment: {
|
266
|
-
name: "androidx.navigation.fragment.NavHostFragment",
|
267
|
-
documentId: "main_content",
|
268
|
-
app: {
|
269
|
-
navGraph: "@navigation/product_list_graph",
|
270
|
-
defaultNavHost: "true"
|
271
|
-
}
|
272
|
-
},
|
273
|
-
beforeCascade(sessionId) {
|
274
|
-
document.getElementById("fragment-id").style.display = "block"; // Use inline styles
|
275
|
-
}
|
276
|
-
}
|
277
|
-
);
|
278
|
-
await squared.parseDocument({
|
279
|
-
element: "fragment-2",
|
280
|
-
projectId: "sqd2", // Explicit
|
281
|
-
resourceQualifier: "port", // Will not conflict with projectId "project-1"
|
282
|
-
enabledFragment: true,
|
283
|
-
fragmentableElements: [
|
284
|
-
{
|
285
|
-
selector: "main", // querySelector
|
286
|
-
name: "androidx.navigation.fragment.NavHostFragment",
|
287
|
-
filename: "navigation.xml",
|
288
|
-
documentId: "main_content"
|
289
|
-
},
|
290
|
-
"main > article" // Declarative double nested fragments are invalid (querySelectorAll)
|
291
|
-
],
|
292
|
-
options: {
|
293
|
-
"android.resource.fragment": {
|
294
|
-
dynamicNestedFragments: true // FragmentContainerView or FrameLayout as the container (name and tag are ignored)
|
295
|
-
}
|
296
|
-
}
|
297
|
-
});
|
298
|
-
// OR - Chromium
|
299
|
-
squared.prefetch("css").then(() => squared.parseDocument()); // Cross-origin support
|
300
|
-
Promise.all(
|
301
|
-
squared.prefetch("css", true), // All stylesheets
|
302
|
-
squared.prefetch("css", "./undetected.css", element.shadowRoot),
|
303
|
-
squared.prefetch("svg", "http://embedded.example.com/icon.svg", "../images/android.svg")
|
304
|
-
)
|
305
|
-
.then(() => squared.parseDocument());
|
306
|
-
|
307
|
-
// Modify attributes
|
308
|
-
|
309
|
-
const body = squared.findDocumentNode(document.body);
|
310
|
-
body.android("layout_width", "match_parent");
|
311
|
-
body.lockAttr("android", "layout_width");
|
312
|
-
|
313
|
-
await squared.close(/* projectId */); // Next call to parseDocument will reset project (optional)
|
314
|
-
|
315
|
-
squared.kill("30s").then(result => {/* killed when result > 0 */}); // Abort next request in 30 seconds
|
316
|
-
|
317
|
-
// File actions - implicitly calls "close"
|
318
|
-
|
319
|
-
await squared.save(/* "project-1" */, /* broadcastId | timeout */); // Uses defaults from settings
|
320
|
-
// OR
|
321
|
-
await squared.saveAs(/* archive filename */, { projectId: "project-1" });
|
322
|
-
await squared.saveAs(/* archive filename */, { timeout: 10 }); // Kills request if not complete in 10 seconds
|
323
|
-
await squared.saveAs(/* archive filename */, { throwErrors: true }).catch(err => console.log(err)); // Will cancel partial archive download
|
324
|
-
// OR
|
325
|
-
await squared.copyTo(/* directory */, {/* options */});
|
326
|
-
await squared.copyTo(/* directory */, { modified: true }); // Can be used with observe
|
327
|
-
// OR
|
328
|
-
await squared.appendTo(/* archive location */, {/* options */});
|
329
|
-
|
330
|
-
// Other features
|
331
|
-
|
332
|
-
squared.observe();
|
333
|
-
// OR
|
334
|
-
await squared.observeSrc(
|
335
|
-
"link[rel=stylesheet]", // HTMLElement
|
336
|
-
(ev, element) => {
|
337
|
-
squared.reset();
|
338
|
-
squared.parseDocument().then(() => squared.copyTo("/path/project"));
|
339
|
-
},
|
340
|
-
{ port: 8080, secure: false, action: "reload" /* "hot" */, expires: "1h" } // squared.json: "observe"
|
341
|
-
);
|
342
|
-
|
343
|
-
squared.reset(/* projectId */); // Start new "parseDocument" session (optional)
|
344
|
-
});
|
345
|
-
</script>
|
346
|
-
```
|
347
|
-
|
348
|
-
> [!CAUTION]
|
349
|
-
> Calling `saveAs` or `copyTo` methods before the images have completely loaded can cause them to be excluded from the generated layout. In these cases you should use the asynchronous `parseDocument` method to set a callback for your commands.
|
350
|
-
|
351
|
-
### Example: chrome
|
352
|
-
|
353
|
-
Used primarly for developing single page layouts but can also bundle assets using query selector syntax. It is adequate for most projects and gives you the ability to develop your application as a module in place.
|
354
|
-
|
355
|
-
* ES2020
|
356
|
-
|
357
|
-
```html
|
358
|
-
<script src="/dist/squared.min.js"></script>
|
359
|
-
<script src="/dist/squared.base.min.js"></script>
|
360
|
-
<script src="/dist/chrome.framework.min.js"></script>
|
361
|
-
<script>
|
362
|
-
document.addEventListener("DOMContentLoaded", async () => {
|
363
|
-
squared.setFramework(chrome, {/* settings */});
|
364
|
-
|
365
|
-
await squared.save(); // Uses defaults from settings
|
366
|
-
// OR
|
367
|
-
await squared.saveAs(/* archive filename */, {/* options */});
|
368
|
-
// OR
|
369
|
-
await squared.copyTo(/* directory */, {/* options */});
|
370
|
-
// OR
|
371
|
-
await squared.appendTo(/* archive location */, {/* options */});
|
372
|
-
|
373
|
-
// Observe
|
374
|
-
await squared.copyTo(/* directory */, { useOriginalHtmlPage: false, observe: /* Same as Android */ | true /* Auto-reload */}).then(() => squared.observe());
|
375
|
-
});
|
376
|
-
</script>
|
377
|
-
```
|
378
|
-
|
379
|
-
### Example: vdom
|
380
|
-
|
381
|
-
The most minimal framework possible (*55kb gzipped*) and can be useful when debugging through DevTools. The `lite` version is about half the bundle size and is recommended for most browser applications.
|
382
|
-
|
383
|
-
* ES2018
|
384
|
-
|
385
|
-
```html
|
386
|
-
<script src="/dist/squared.min.js"></script>
|
387
|
-
<script src="/dist/squared.base-dom.min.js"></script>
|
388
|
-
<script src="/dist/vdom.framework.min.js"></script>
|
389
|
-
<script>
|
390
|
-
document.addEventListener("DOMContentLoaded", async () => {
|
391
|
-
squared.setFramework(vdom, {/* settings */});
|
392
|
-
|
393
|
-
const element = squared.querySelector("body", true /* synchronous */);
|
394
|
-
// OR
|
395
|
-
const elements = await squared.querySelectorAll("*");
|
396
|
-
// OR
|
397
|
-
const element = squared.fromElement(document.body, true /* synchronous */);
|
398
|
-
// OR
|
399
|
-
const elements = await squared.getElementById("content-id").querySelectorAll("*");
|
400
|
-
});
|
401
|
-
</script>
|
402
|
-
```
|
403
|
-
|
404
|
-
There are **ES2018** minified versions (\*.min.js) and also **ES2018** non-minified versions.
|
405
|
-
|
406
|
-
## User Settings
|
407
|
-
|
408
|
-
These settings are available in the global variable `squared` to customize your desired output structure. Each framework shares a common set of settings and also a subset of their own settings.
|
409
|
-
|
410
|
-
### Example: android
|
411
|
-
|
412
|
-
- [Read the Docs](https://squared.readthedocs.io/en/latest/settings/android.html)
|
413
|
-
|
414
|
-
```javascript
|
415
|
-
squared.settings = {
|
416
|
-
targetAPI: 35,
|
417
|
-
supportRTL: true,
|
418
|
-
supportNegativeLeftTop: true,
|
419
|
-
preloadImages: true,
|
420
|
-
preloadFonts: true,
|
421
|
-
preloadLocalFonts: true, // Chromium
|
422
|
-
preloadCustomElements: true,
|
423
|
-
enabledSVG: true,
|
424
|
-
enabledMultiline: true,
|
425
|
-
enabledViewModel: true,
|
426
|
-
enabledIncludes: false,
|
427
|
-
enabledFragment: false,
|
428
|
-
enabledSubstitute: false,
|
429
|
-
enabledCompose: false,
|
430
|
-
dataBindableElements: [], // { selector, attr, expression, namespace?, twoWay? } (see Data Binding section)
|
431
|
-
includableElements: [], // { selectorStart, selectorEnd, pathname?, filename?, merge?, viewModel? }
|
432
|
-
substitutableElements: [], // { selector, tag, tagChild?, renderChildren?, autoLayout? }
|
433
|
-
fragmentableElements: [], // selector | ExtensionFragmentElement
|
434
|
-
composableElements: [], // selector or property (see Jetpack Compose section)
|
435
|
-
baseLayoutAsFragment: false | "fragment-name" | ["fragment-name", "fragment-tag"] | { selector, pathname?, filename?, name?, tag? }, // ExtensionFragmentElement
|
436
|
-
baseLayoutToolsIgnore: "", // Android Studio (e.g. "TooManyViews, HardcodedText")
|
437
|
-
fontMeasureAdjust: 0.75, // thicker < 0 | thinner > 0 (data-android-font-measure-adjust)
|
438
|
-
lineHeightAdjust: 1.1, // shorter < 1 | taller > 1 (data-android-line-height-adjust)
|
439
|
-
preferMaterialDesign: false | "MaterialComponents" | "Material3", // Default is "Material3"
|
440
|
-
createDownloadableFonts: true,
|
441
|
-
createElementMap: false,
|
442
|
-
pierceShadowRoot: true,
|
443
|
-
adaptStyleMap: true, // Use rendered values for output
|
444
|
-
lockElementSettings: true,
|
445
|
-
customizationsBaseAPI: 0, // 0 - All | -1 - None
|
446
|
-
customizationsBaseAPI: [0, 33, 34], // Multiple
|
447
|
-
removeDeprecatedAttributes: true, // Remove all
|
448
|
-
removeDeprecatedAttributes: ["enabled", "singleLine"], // Remove all except "enabled" + "singleLine"
|
449
|
-
removeUnusedResourceViewId: false,
|
450
|
-
idNamingStyle: "android",
|
451
|
-
idNamingStyle: "html", // Use element tagName
|
452
|
-
idNamingStyle: {
|
453
|
-
"__default__": "html", // Optional
|
454
|
-
"DIV": "comments", // HTML is uppercase (comments_1 then comments_2)
|
455
|
-
"svg": ["vector", 0], // SVG elements areis lowercase (vector_0 then vector_1)
|
456
|
-
"#text": "text", // Plain text
|
457
|
-
"::first-letter": "dropcap", // Pseudo element
|
458
|
-
"main > section": ["content", 1, 2], // content_1 then content_3
|
459
|
-
"form input[type=submit]": function(node) {
|
460
|
-
return "submit_" + node.id;
|
461
|
-
}
|
462
|
-
},
|
463
|
-
customizationsOverwritePrivilege: true,
|
464
|
-
outputMainFileName: "activity_main.xml",
|
465
|
-
outputFragmentFileName: "fragment_main.xml",
|
466
|
-
/* Project - parseDocument (first only) */
|
467
|
-
resourceQualifier: "", // "land" -> "res/layout-land" | "port" -> "res/layout-port" (appended to every "res" folder)
|
468
|
-
resourceSystemColors: {
|
469
|
-
"system_accent1_100": "white", // Will be converted to ARGB
|
470
|
-
"system_accent1_200": ['#ff0000', 0.75], // opacity
|
471
|
-
"system_accent1_300": squared.lib.color.parseColor("#000", 1)
|
472
|
-
},
|
473
|
-
manifestPackage: "", // OR: RequestData<{ namespace: "android.application.id" }>
|
474
|
-
manifestLabelAppName: "android",
|
475
|
-
manifestThemeName: "AppTheme",
|
476
|
-
manifestParentThemeName: "Theme.AppCompat.Light.NoActionBar",
|
477
|
-
manifestActivityName: ".MainActivity",
|
478
|
-
outputDocumentEditing: true,
|
479
|
-
outputDocumentCSS: [], // CSS properties to be processed at server (e.g. "boxShadow")
|
480
|
-
outputDirectory: "app/src/main",
|
481
|
-
createManifest: false, // Update AndroidManifest.xml
|
482
|
-
createBuildDependencies: false | "ktx" | "baseline-profile" | ["ktx", "baseline-profile"], // Update build.gradle
|
483
|
-
|
484
|
-
// Not customizable with parseDocument
|
485
|
-
builtInExtensions: [
|
486
|
-
"squared.accessibility",
|
487
|
-
"android.delegate.background",
|
488
|
-
"android.delegate.negative-x",
|
489
|
-
"android.delegate.positive-x",
|
490
|
-
"android.delegate.max-width-height",
|
491
|
-
"android.delegate.percent",
|
492
|
-
"android.delegate.content",
|
493
|
-
"android.delegate.scrollbar",
|
494
|
-
"android.delegate.radiogroup",
|
495
|
-
"android.delegate.multiline",
|
496
|
-
"squared.relative",
|
497
|
-
"squared.css-grid",
|
498
|
-
"squared.flexbox",
|
499
|
-
"squared.table",
|
500
|
-
"squared.column",
|
501
|
-
"squared.list",
|
502
|
-
"squared.grid",
|
503
|
-
"squared.sprite",
|
504
|
-
"squared.whitespace",
|
505
|
-
"android.resource.background",
|
506
|
-
"android.resource.svg",
|
507
|
-
"android.resource.strings",
|
508
|
-
"android.resource.fonts",
|
509
|
-
"android.resource.dimens",
|
510
|
-
"android.resource.styles",
|
511
|
-
"android.resource.data",
|
512
|
-
|
513
|
-
/* EXCLUDED (breaks layout) */
|
514
|
-
"android.resource.includes", // enabledIncludes
|
515
|
-
"android.substitute", // enabledSubstitute
|
516
|
-
"android.resource.fragment", // enabledFragment
|
517
|
-
"jetpack.compose.view" // enabledCompose
|
518
|
-
],
|
519
|
-
compressImages: false, // TinyPNG API Key <https://tinypng.com/developers>
|
520
|
-
compressImages: "****************", // API key
|
521
|
-
compressImages: [{ plugin: "imagemin-pngquant", format: "png", options: { quality: [0.6, 0.8] } }], // v5.5
|
522
|
-
convertImages: "", // png | jpeg | webp | gif | bmp
|
523
|
-
showAttributes: true,
|
524
|
-
showAttributes: {
|
525
|
-
"hyphenationFrequency": "full", // Replace all ("android" is the default namespace)
|
526
|
-
"android:fontFeatureSettings": null, // Delete all
|
527
|
-
"app:menu": [
|
528
|
-
"@menu/menu_1", "@menu/menu_2", // Replace with "@menu/menu_2" when value is "@menu/menu_1"
|
529
|
-
"@menu/menu_3", null // Delete attribute when value is "@menu/menu_3"
|
530
|
-
],
|
531
|
-
/* OR */
|
532
|
-
"app:menu": {
|
533
|
-
"@menu/menu_1": "@menu/menu_2",
|
534
|
-
"@menu/menu_3": null
|
535
|
-
}
|
536
|
-
},
|
537
|
-
showComments: false | ["boxShadow"] | { self: ["boxShadow"], nextSibling: ["marginBottom"], previousSibling: ["marginTop"], parent: ["position", "top", "left"] }, // TODO in layout.xml
|
538
|
-
showComments: { include: { tagName: true | ["button"], attributes: true | ["style"], dataset: false, bounds: true }, self: ["boxShadow", ".className"] },
|
539
|
-
showErrorMessages: false,
|
540
|
-
convertPixels: "dp", // "sp" | "pt" | "in" | "mm"
|
541
|
-
convertLineHeight: "sp", // "dp" | "pt" | "in" | "mm"
|
542
|
-
convertEntities: ["numeric"],
|
543
|
-
convertEntities: ["codepoints", {/* JSON (last) */}], // https://html.spec.whatwg.org/entities.json
|
544
|
-
insertSpaces: 4,
|
545
|
-
outputDocumentHandler: "android",
|
546
|
-
outputEmptyCopyDirectory: false, // Sub directories within target directory (OR: RequestData<{ emptyDir: false }>)
|
547
|
-
outputSummaryModal: false | "path/summary.css" | ".status-4 { color: purple; }",
|
548
|
-
outputTasks: {
|
549
|
-
"**/drawable/*.xml": { handler: "gulp", task: "minify" }
|
550
|
-
},
|
551
|
-
outputWatch: {
|
552
|
-
"**/drawable/*.png": true,
|
553
|
-
"**/drawable/*.jpg": { interval: 1000, expires: "2h" }
|
554
|
-
},
|
555
|
-
outputArchiveName: "android-xml",
|
556
|
-
outputArchiveFormat: "zip", // tar | 7z | gz
|
557
|
-
outputArchiveCache: false // Downloadable URL in ResponseData<downloadUrl>
|
558
|
-
};
|
559
|
-
|
560
|
-
// Optional
|
561
|
-
squared.settings = {
|
562
|
-
resolutionDPI: 160, // 320dpi = 2560x1600
|
563
|
-
resolutionScreenWidth: 1280,
|
564
|
-
resolutionScreenHeight: 800,
|
565
|
-
framesPerSecond: 60,
|
566
|
-
useShapeGeometryBox: true, // Bounding box uses native SVG method getBbox
|
567
|
-
formatUUID: "8-4-4-4-12", // UUID: 8-4-[12345]3-[89ab]3-12
|
568
|
-
formatDictionary: "0123456789abcdef",
|
569
|
-
outputConfigName: "sqd.config",
|
570
|
-
observePort: 8080,
|
571
|
-
observeSecurePort: 8443,
|
572
|
-
observeExpires: "1h", // Server defaults will be used
|
573
|
-
broadcastPort: 3080,
|
574
|
-
broadcastSecurePort: 3443
|
575
|
-
};
|
576
|
-
```
|
577
|
-
|
578
|
-
### Example: chrome
|
579
|
-
|
580
|
-
- [Read the Docs](https://squared.readthedocs.io/en/latest/settings/chrome.html)
|
581
|
-
|
582
|
-
```javascript
|
583
|
-
squared.settings = {
|
584
|
-
preloadImages: false,
|
585
|
-
preloadFonts: false,
|
586
|
-
preloadLocalFonts: false,
|
587
|
-
preloadCustomElements: false,
|
588
|
-
excludePlainText: true,
|
589
|
-
createElementMap: true,
|
590
|
-
pierceShadowRoot: true,
|
591
|
-
adaptStyleMap: false,
|
592
|
-
builtInExtensions: [],
|
593
|
-
showErrorMessages: false,
|
594
|
-
webSocketPort: 80,
|
595
|
-
webSocketSecurePort: 443,
|
596
|
-
outputDocumentHandler: "chrome",
|
597
|
-
outputEmptyCopyDirectory: false,
|
598
|
-
outputSummaryModal: false,
|
599
|
-
outputTasks: {
|
600
|
-
"*.js": [{ handler: "gulp", task: "minify" }, { handler: "gulp", task: "beautify" }]
|
601
|
-
},
|
602
|
-
outputWatch: { "*": true },
|
603
|
-
outputArchiveName: "chrome-data",
|
604
|
-
outputArchiveFormat: "zip",
|
605
|
-
outputArchiveCache: false
|
606
|
-
};
|
607
|
-
|
608
|
-
// Optional (Same as Android)
|
609
|
-
|
610
|
-
```
|
611
|
-
|
612
|
-
### Example: vdom
|
613
|
-
|
614
|
-
- [Read the Docs](https://squared.readthedocs.io/en/latest/settings/vdom.html)
|
615
|
-
|
616
|
-
```javascript
|
617
|
-
squared.settings = {
|
618
|
-
createElementMap: true,
|
619
|
-
pierceShadowRoot: false,
|
620
|
-
adaptStyleMap: false,
|
621
|
-
builtInExtensions: [],
|
622
|
-
showErrorMessages: false
|
623
|
-
};
|
624
|
-
```
|
625
|
-
|
626
|
-
## Local Storage
|
627
|
-
|
628
|
-
Custom named user settings per framework can be saved to local storage as JSON and reused across all pages in the same domain. Extensions are configured using the same procedure.
|
629
|
-
|
630
|
-
```javascript
|
631
|
-
// Save
|
632
|
-
squared.setFramework(android, { compressImages: true }, "android-example");
|
633
|
-
|
634
|
-
// Load
|
635
|
-
squared.setFramework(android, "android-example");
|
636
|
-
```
|
637
|
-
|
638
|
-
```javascript
|
639
|
-
// Save
|
640
|
-
await squared.copyTo("/path/project", {/* options will be saved */}, "copy-example", true); // Will overwrite and not merge with previously saved settings
|
641
|
-
|
642
|
-
// Load
|
643
|
-
await squared.copyTo("/path/project", {/* takes precedence */}, "http://localhost:3000/copy-to/base-config.json"); // Object.assign({ base-config.json }, options)
|
644
|
-
await squared.copyTo("/path/project", {/* takes precedence */}, "copy-example"); // Object.assign({ copy-example }, options)
|
645
|
-
|
646
|
-
await squared.copyTo("/path/project", "http://localhost:3000/copy-to/base-config.json"); // options = { base-config.json }
|
647
|
-
await squared.copyTo("/path/project", "copy-example"); // options = { copy_example }
|
648
|
-
```
|
649
|
-
|
650
|
-
## Public Properties and Methods
|
651
|
-
|
652
|
-
- [Read the Docs](https://squared.readthedocs.io/en/latest/methods/squared.html)
|
653
|
-
|
654
|
-
```javascript
|
655
|
-
.settings // See user preferences section
|
656
|
-
|
657
|
-
setFramework(app: {}, options?: PlainObject, setting?: string, cache?: boolean) // Install application interpreter
|
658
|
-
setFramework(app: {}, loadName: string, cache?: boolean) // Load settings from local storage
|
659
|
-
|
660
|
-
// http - hostname(:port)? | https - hostname:443
|
661
|
-
setHostname(value: string /* http(s)://hostname(:port) */) // Use another cors-enabled server for processing files (--cors <origin>)
|
662
|
-
|
663
|
-
setEndpoint(name: string, value: string) // Set alternate pathname for API v1 functions (ASSETS_COPY | ASSETS_ARCHIVE | LOADER_DATA | THREADS_KILL | WEBSOCKET_OBSERVE)
|
664
|
-
setLocalAddress(...values: (string | URL | Location)[]) // Additional hostnames which are interpreted as localhost (e.g. http://127.0.0.1)
|
665
|
-
|
666
|
-
prefetch(type: "css" | "javascript" | "image" | "svg", all?: boolean, ...targets: unknown[]) // Cross-origin support for CSS
|
667
|
-
|
668
|
-
parseDocument(...elements: (HTMLElement | string | ElementSettings)[]) // See installation section (Promise)
|
669
|
-
parseDocumentSync(...elements: (HTMLElement | string | ElementSettings)[]) // Skips preloadImages and preloadFonts (synchronous)
|
670
|
-
|
671
|
-
latest(count?: number) // Most recent parseDocument session ids (1 newest / -1 oldest: string, other: string[])
|
672
|
-
|
673
|
-
auth(token: string) // Set JWT authorization token for all requests
|
674
|
-
|
675
|
-
save(projectId?: string) // Save current session to a new archive using default settings
|
676
|
-
save(projectId?: string, broadcastId?: string)
|
677
|
-
save(projectId?: string, timeout?: number)
|
678
|
-
|
679
|
-
close(projectId?: string) // Close current session
|
680
|
-
reset(projectId?: string) // Clear cache and reopen new session
|
681
|
-
clear() // Clear all data stored in memory
|
682
|
-
|
683
|
-
toString() // Current framework loaded
|
684
|
-
toString(projectId: string) // await squared.close(projectId) (required)
|
685
|
-
|
686
|
-
add(...names: (string | Extension | ExtensionRequestObject)[]) // See extension configuration section
|
687
|
-
remove(...names: (string | Extension)[]) // Remove extensions by namespace or control
|
688
|
-
get(...names: string[]) // Retrieve extensions by namespace
|
689
|
-
attr(name: string | Extension, attrName: string, value?: unknown) // Set or get extension options attribute value
|
690
|
-
apply(name: string | Extension, options: PlainObject, setting?: string) // See extension configuration section
|
691
|
-
|
692
|
-
extend(functionMap: {}, framework?: /* 0 - ALL | 1 - vdom | 2 - android | 4 - chrome */) // Add extension functions and properties to Node prototype
|
693
|
-
|
694
|
-
observe(value?: boolean | MutationObserverInit) // Start after DOM and third-party libraries initialization
|
695
|
-
broadcast(callback: BroadcastMessageCallback, options: FileBroadcastOptions | string) // Redirect stdout messages to DevTools console
|
696
|
-
|
697
|
-
// Promise (Recommended "cache": createElementMap - true)
|
698
|
-
|
699
|
-
getElementById(value: string, sync?: boolean, cache?: boolean) // sync - false | cache - true (default)
|
700
|
-
querySelector(value: string, sync?: boolean, cache?: boolean)
|
701
|
-
querySelectorAll(value: string, sync?: boolean, cache?: boolean)
|
702
|
-
|
703
|
-
fromElement(element: HTMLElement | string, sync?: boolean, cache?: boolean) // sync - false | cache - false (default)
|
704
|
-
fromNode(node: Node, sync?: boolean, cache?: boolean)
|
705
|
-
findDocumentNode(element: HTMLElement | string /* querySelector | elementId | controlId */, all?: boolean) // Use before saving to modify internal Node attributes
|
706
|
-
|
707
|
-
observeSrc(element: HTMLElement | string /* querySelector */, callback: WebSocketMessageChange, options?: FileObserveOptions) // Can be used to watch any element with externally hosted files (src/href)
|
708
|
-
observeSrc(element: HTMLElement | string, options: FileObserveOptions) // Uses location.reload (reload - true)
|
709
|
-
```
|
710
|
-
|
711
|
-
Packaging methods will return a Promise and requires a squared-express installation. These features are not supported when the framework is VDOM.
|
712
|
-
|
713
|
-
```javascript
|
714
|
-
saveAs(filename: string, options?: {}, setting?: string, overwrite?: boolean) // Save current session as a new archive
|
715
|
-
saveFiles(filename: string, options: {}, setting?: string, overwrite?: boolean) // Create new archive from FileAsset[]
|
716
|
-
|
717
|
-
// Required (local archives): --disk-read | --unc-read | --access-all (command-line)
|
718
|
-
|
719
|
-
appendTo(pathname: string, options?: {}, setting?: string, overwrite?: boolean) // Create new archive from a preexisting archive and current session
|
720
|
-
appendFiles(pathname: string, options: {}, setting?: string, overwrite?: boolean) // Create new archive from a preexisting archive and FileAsset[]
|
721
|
-
|
722
|
-
// Required (all): --disk-write | --unc-write | --access-all (command-line)
|
723
|
-
|
724
|
-
copyTo(pathname: string | string[], options?: {}, setting?: string, overwrite?: boolean) // Copy current session to local
|
725
|
-
copyFiles(pathname: string | string[], options: {}, setting?: string, overwrite?: boolean) // Copy FileAsset[] to local
|
726
|
-
|
727
|
-
kill(pid: number, timeout?: number) // Use -1 or options.pid (set by system) + seconds
|
728
|
-
kill(timeout: string)
|
729
|
-
kill() // Terminate previous request
|
730
|
-
kill(0) // By username (auth required)
|
731
|
-
kill(-1, 10) // Terminate previous request in 10 seconds
|
732
|
-
kill(NaN, 10) // Terminate in 10 seconds (next request) ("timeout" is required)
|
733
|
-
kill("10s") // Only "s" + "ms" (next request)
|
734
|
-
```
|
735
|
-
|
736
|
-
## Extending Node object
|
737
|
-
|
738
|
-
You can add functions and initial variables to the Node object including overwriting preexisting class definitions per framework. Accessor properties are also supported using the *get/set* object syntax.
|
739
|
-
|
740
|
-
```javascript
|
741
|
-
squared.extend({
|
742
|
-
_id: 1,
|
743
|
-
altId: {
|
744
|
-
get() {
|
745
|
-
return this._id;
|
746
|
-
},
|
747
|
-
set(value) {
|
748
|
-
this._id += value;
|
749
|
-
}
|
750
|
-
},
|
751
|
-
customId: {
|
752
|
-
value: 2,
|
753
|
-
configurable: false,
|
754
|
-
enumerable: false
|
755
|
-
},
|
756
|
-
addEvent(eventName, callback) {
|
757
|
-
this.element.addEventListener(eventName, callback);
|
62
|
+
# REPO_ROOT = /workspaces | Dir.pwd
|
63
|
+
# rake = /workspaces/Rakefile |
|
64
|
+
# REPO_HOME = /workspaces/squared | main: "squared"
|
65
|
+
|
66
|
+
# pathname = /workspaces/pathname
|
67
|
+
# optparse = /workspaces/optparse
|
68
|
+
# log = /workspaces/logger
|
69
|
+
# emc = /workspaces/e-mc
|
70
|
+
# pir = /workspaces/pi-r
|
71
|
+
# pir2 = /workspaces/pi-r2
|
72
|
+
# squared = /workspaces/squared
|
73
|
+
# cli = /workspaces/squared/publish/sqd-cli
|
74
|
+
# sqd-serve = /workspaces/squared/publish/sqd-serve
|
75
|
+
# sqd = /workspaces/squared/sqd
|
76
|
+
|
77
|
+
Workspace::Application
|
78
|
+
.new(Dir.pwd, main: "squared") # Dir.pwd? (main? is implicitly basename)
|
79
|
+
.banner("group", "project", styles: ["yellow", "black"], border: "bold") # name | project | path | ref | group? | parent? | version?
|
80
|
+
.repo("https://github.com/anpham6/squared-repo", "nightly", script: ["build:dev", "build:prod"], ref: :node) # Repo (optional)
|
81
|
+
.run("rake install", ref: :ruby)
|
82
|
+
.depend(false, group: "default")
|
83
|
+
.clean("rake clean", group: "default")
|
84
|
+
.clean(["build/"], group: "app")
|
85
|
+
.log({ file: "tmp/%Y-%m-%d.log", level: "debug" }, group: "app")
|
86
|
+
.add("pathname", run: "rake compile", copy: "rake install", test: "rake test", group: "default", env: { # Ruby (with C extensions)
|
87
|
+
"CFLAGS" => "-fPIC -O1"
|
88
|
+
})
|
89
|
+
.add("optparse", doc: "rake rdoc", gemspec: "optparse.gemspec", group: "default") # Uses bundler/gem_tasks (without C extensions)
|
90
|
+
.add("logger", copy: { from: "lib", glob: "**/*.rb", into: "~/.rvm/gems/ruby-3.4.0/gems/logger-1.6.1" }, clean: ["tmp/"]) # autodetect: true | "rvm" | "rbenv" | "asdf" | "bundler"
|
91
|
+
.add("e-mc", "emc", copy: { from: "publish", scope: "@e-mc", also: [:pir, "squared-express/"] }, ref: :node) # Node
|
92
|
+
.add("pi-r", "pir", copy: { from: "publish", scope: "@pi-r" }, clean: ["publish/**/*.js", "tmp/"]) # Trailing slash required for directories
|
93
|
+
.add("pi-r2", "pir2", copy: { from: :npm, also: %i[squared express], files: ["LICENSE", ["README.md.ruby", "README.md"]] }) # Uses dist files from NPM package spec
|
94
|
+
.add("squared", init: 'pnpm', script: ["build:stage1", "build:stage2"], group: "app") do # Use pnpm/yarn/berry for depend + Copy target (main)
|
95
|
+
# Repo (global)
|
96
|
+
as(:run, "build:dev", "dev") # npm run build:dev -> npm run dev
|
97
|
+
as(:run, { "build:dev": "dev", "build:prod": "prod" })
|
98
|
+
|
99
|
+
add("publish/sqd-cli", "cli", exclude: [:git]) # rake cli:build
|
100
|
+
add("publish/sqd-serve") # rake sqd-serve:build
|
101
|
+
add("publish/sqd-admin", group: "sqd", exclude: [:base])
|
102
|
+
# OR
|
103
|
+
with(exclude: [:base]) { add("publish/*", "packages") } # rake packages:sqd-serve:build
|
104
|
+
# OR
|
105
|
+
add(["publish/sqd-cli", "publish/sqd-serve"], true, exclude: [:base]) # rake squared:sqd-serve:build
|
106
|
+
|
107
|
+
# Git
|
108
|
+
revbuild(include: %w[src/ framework/ types/]) # Synchronous is recommended
|
109
|
+
end
|
110
|
+
.add("squared/sqd", exclude: :git, pass: [:node, "checkout", "bump"]) do # Skip initialize(:node) + squared:checkout:* + squared:bump:*
|
111
|
+
variable_set :script, "build:sqd" # Override detection
|
112
|
+
variable_set :depend, false
|
113
|
+
variable_set :clean, ["build/sqd/"]
|
114
|
+
end
|
115
|
+
.with(:docker, only: ["build", "compose"]) do
|
116
|
+
.add("squared", "docker", file: "Dockerfile", context: ".", tag: "latest", registry: "localhost:5000", username: "squared",
|
117
|
+
args: "--ssh=default",
|
118
|
+
secrets: ["id=github,env=GITHUB_TOKEN"],
|
119
|
+
mounts: ["src=.,dst=/project,ro,bind-propagation=rshared"]) do # Docker
|
120
|
+
series(:clean) do # run | depend | doc | lint | test | copy | clean
|
121
|
+
File.read(basepath("docker-bake.hcl"))
|
122
|
+
.scan(/\btags\s+=\s+\["([^"]+)"\]/)
|
123
|
+
.each { |val| image(:rm, tag: val.first) }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
.pass("pull", group: "default") { test? || doc? } # rake pathname:pull | rake optparse:pull
|
128
|
+
.style("banner", 255.255) # 256 colors (fg | fg.bg | -0.bg)
|
129
|
+
.build(default: "build", parallel: ["pull", "fetch", "rebase", "archive", "clean", /^outdated:/], pass: ["publish"]) do |workspace|
|
130
|
+
workspace
|
131
|
+
.enable_aixterm
|
132
|
+
.style({
|
133
|
+
banner: ["bright_cyan", "bold", "bright_black!"],
|
134
|
+
border: "bright_white"
|
135
|
+
})
|
136
|
+
end
|
137
|
+
|
138
|
+
# default = /workspaces/ruby/*
|
139
|
+
# pathname = /workspaces/ruby/pathname
|
140
|
+
# optparse = /workspaces/ruby/optparse
|
141
|
+
# logger = /workspaces/ruby/logger
|
142
|
+
# android = /workspaces/android-docs
|
143
|
+
# chrome = /workspaces/chrome-docs
|
144
|
+
|
145
|
+
Workspace::Application
|
146
|
+
.new(ENV["SQUARED_HOME"], prefix: "rb", common: false) # Local styles
|
147
|
+
.group("ruby", "default", run: "rake build", copy: "rake install", clean: "rake clean", ref: :ruby, override: {
|
148
|
+
pathname: {
|
149
|
+
run: "rake compile" # rake rb:pathname:build
|
758
150
|
}
|
759
|
-
})
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
node.each((child, index) => child.element.title = data[index]);
|
818
|
-
}
|
151
|
+
})
|
152
|
+
.with(:python, editable: false) do # ref=Symbol | group=String
|
153
|
+
banner([:name, ": ", :version], "path") # chrome-docs: 0.1.0 | /workspaces/chrome-docs
|
154
|
+
doc("make html") # rake rb:doc:python
|
155
|
+
run(false) # rake rb:build:python (disabled)
|
156
|
+
exclude(%i[base git]) # Project::Git.ref (superclass)
|
157
|
+
add("android-docs", "android") # rake rb:android:doc
|
158
|
+
add("chrome-docs", "chrome") # rake rb:chrome:doc
|
159
|
+
end
|
160
|
+
.style("inline", "bold")
|
161
|
+
.build
|
162
|
+
```
|
163
|
+
|
164
|
+
**NOTE**: The use of "**ref**" (class name) is only necessary when initializing an empty directory (e.g. *rake repo:init*).
|
165
|
+
|
166
|
+
### Archive
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
# HEADERS={"Authorization":"Bearer RANDOM-TOKEN"} | hash/json
|
170
|
+
# ZIP_DEPTH=0 | default=1
|
171
|
+
# TAR_DEPTH=0 | TAR_DEPTH_SQUARED
|
172
|
+
# UNPACK_FORCE=1 | Remove target directory
|
173
|
+
|
174
|
+
Workspace::Application
|
175
|
+
.new(main: "squared")
|
176
|
+
.with(:python) do
|
177
|
+
add("android-docs", "android", archive: "https://github.com/anpham6/android-docs/archive/refs/tags/v0.3.0.zip")
|
178
|
+
add("chrome-docs", "chrome", archive: {
|
179
|
+
uri: "https://github.com/anpham6/chrome-docs/archive/refs/tags/v0.5.0.tar.gz", # URI.open (required)
|
180
|
+
digest: "e3d55d2004d4770dd663254c9272dc3baad0d57a5bd14ca767de6546cdf14680", # SHA1 | SHA256 | SHA384 | SHA512 | MD5
|
181
|
+
digest: "rmd160:47b7790a511eed675fec1a3e742845fef058799b", # RMD160
|
182
|
+
ext: "tar.gz", # zip | tar | tar.gz | tgz | tar.xz | txz | 7z
|
183
|
+
depth: 1, # nested directories (e.g. --strip-components)
|
184
|
+
headers: { # URI.open
|
185
|
+
"Authorization" => "Bearer RANDOM-TOKEN"
|
186
|
+
}
|
187
|
+
})
|
188
|
+
end
|
189
|
+
.add("squared", release: "https://github.com/anpham6/squared/archive/refs/tags/??") # squared:unpack:zip[v5.4.0,/tmp/squared]
|
190
|
+
end
|
191
|
+
```
|
192
|
+
|
193
|
+
### Clone
|
194
|
+
|
195
|
+
The task is only active when the project directory is empty or does not exist.
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
Workspace::Application
|
199
|
+
.new(main: "squared")
|
200
|
+
.git(
|
201
|
+
"emc": "https://github.com/anpham6/e-mc", # rake emc:clone
|
202
|
+
"pir": { # rake pir:clone
|
203
|
+
uri: "https://github.com/anpham6/pi-r", #
|
204
|
+
options: { #
|
205
|
+
"origin": "github", # --origin=github
|
206
|
+
"recurse-submodules": false, # --no-recurse-submodules
|
207
|
+
"shallow-exclude": ["v0.0.1", "v0.0.2"] # --shallow-exclude=v0.0.1 --shallow-exclude=v0.0.2
|
208
|
+
}
|
819
209
|
}
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
squared.add([sample, {/* config */}]);
|
827
|
-
|
828
|
-
// Configure an extension
|
829
|
-
squared.attr("widget.example.com", "attributeName", ["width", "height"]); // typeof is enforced and will only set existing attributes
|
830
|
-
|
831
|
-
// Add project data
|
832
|
-
const ext = squared.get("widget.example.com");
|
833
|
-
|
834
|
-
ext.project.set(element, await fetch(url?id=1)); // Map interface with optional "projectId" argument
|
835
|
-
ext.project.set(element, await fetch(url?id=2), "project-1");
|
836
|
-
|
837
|
-
const data = ext.project.get(element, "project-2"); // Returns data from default project (id=1)
|
838
|
-
```
|
839
|
-
|
840
|
-
Some extensions have a few settings which can be configured. The default settings usually achieve the best overall rendering accuracy without noticeably affecting performance.
|
841
|
-
|
842
|
-
## ANDROID
|
843
|
-
|
844
|
-
### Public Methods
|
845
|
-
|
846
|
-
- [Read the Docs](https://squared.readthedocs.io/en/latest/methods/android.html)
|
847
|
-
|
848
|
-
```javascript
|
849
|
-
android.setViewModel(data: {}, sessionId?: string) // Object data for layout bindings
|
850
|
-
android.setViewModelByProject(data: {}, projectId?: string)
|
851
|
-
android.removeObserver(element: HTMLElement) // Disconnect an observed element from "parseDocument"
|
852
|
-
android.addXmlNs(name: string, uri: string) // Add global namespaces for third-party controls
|
853
|
-
android.addDependency(group: string, name: string, version?: string, type?: number) // Add application dependency implementation (build.gradle)
|
854
|
-
android.addDependencyByProject(projectId: string, group: string, name: string, version?: string, type?: number) // DEPENDENCY_TYPE: 0 - implementation 1 - api 2 - compileOnly 3 - compileOnlyApi 4 - runtimeOnly 5 - testImplementation 8 - androidTestImplementation
|
855
|
-
android.customize(build: number, tagNameOrWidget: string, options: {}) // Global attributes applied to specific views
|
856
|
-
android.loadCustomizations(name: string) // Load customizations from Local Storage
|
857
|
-
android.saveCustomizations(name: string) // Save "customize" data into Local Storage (includes xmlns)
|
858
|
-
android.resetCustomizations() // All session customizations are deleted
|
859
|
-
android.addFontProvider(authority: string, package: string, certs: string[], webFonts: string | {}) // Add additional Web fonts (Google Fonts already included)
|
860
|
-
android.setResolutionByDeviceName(value: string) // Settings prefixed with "resolution" (e.g. Pixel C)
|
861
|
-
android.getLocalSettings() // Modify controller styles and parsing rules
|
862
|
-
```
|
863
|
-
|
864
|
-
```javascript
|
865
|
-
// NOTE: squared.settings.targetAPI is always parsed (Except: customizationsBaseAPI = -1)
|
866
|
-
|
867
|
-
android.customize(android.lib.constant.BUILD_VERSION.ALL /* 0 */, "Button", {
|
868
|
-
android: {
|
869
|
-
minWidth: "35px",
|
870
|
-
minHeight: "25px"
|
210
|
+
)
|
211
|
+
.git("squared", "/path/to/squared", options: { local: true }) # Relative paths resolve from workspace root
|
212
|
+
.git(
|
213
|
+
{
|
214
|
+
emc: { uri: "e-mc", options: { "depth": 2 } }, # https://github.com/anpham6/e-mc
|
215
|
+
pir: "pi-r" # Maps task alias to repository folder
|
871
216
|
},
|
872
|
-
"
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
android.customize(android.lib.constant.BUILD_VERSION.KITKAT /* 19 */, "svg", {
|
878
|
-
android: {
|
879
|
-
"[src]": "app:srcCompat" // Change namespace to "app"
|
217
|
+
base: "https://github.com/anpham6", # Required
|
218
|
+
repo: ["squared", "android-docs", "chrome-docs"], # https://github.com/anpham6/squared
|
219
|
+
options: { # Only "repo"
|
220
|
+
"depth": 1,
|
221
|
+
"quiet": true
|
880
222
|
}
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
223
|
+
)
|
224
|
+
.with(:node) do # rake clone:node
|
225
|
+
add("e-mc", "emc") # https://github.com/anpham6/e-mc
|
226
|
+
add("pi-r", "pir") # https://github.com/anpham6/pi-r
|
227
|
+
add("squared") # https://github.com/anpham6/squared
|
228
|
+
end
|
229
|
+
.with(:python) do # rake clone:python
|
230
|
+
add("android-docs")
|
231
|
+
add("chrome-docs") do
|
232
|
+
revbuild(include: "source/", exclude: ["source/conf.py"]) # Limit files being watched
|
233
|
+
end
|
234
|
+
end
|
235
|
+
.git("https://github.com/anpham6", ["emc", "pir"]) # Targets any defined project
|
236
|
+
.git("https://github.com/anpham6", cache: true) # Uses already defined root projects + revbuild
|
237
|
+
.revbuild # Enables task revbuild (squared.revb)
|
238
|
+
.revbuild(file: "../build.json") # $ROOT/build.json
|
239
|
+
.build(parallel: ["clone"]) # rake clone + rake clone:sync
|
240
|
+
```
|
241
|
+
|
242
|
+
### Build
|
243
|
+
|
244
|
+
#### Chain
|
245
|
+
|
246
|
+
There has to be at least one project which uses the ``step`` attribute. Other placement attributes are ignored.
|
247
|
+
|
248
|
+
**NOTE**: Projects can only reference non-global namespaced tasks. (e.g. with ":")
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
Workspace::Application
|
252
|
+
.new
|
253
|
+
.with(:node) do
|
254
|
+
add("e-mc", "emc") do
|
255
|
+
chain "all", "clean", step: 1 # Required
|
256
|
+
chain "all", "build", step: 2
|
257
|
+
end
|
258
|
+
add("pi-r", "pir") do
|
259
|
+
chain "all", "build", after: "emc:build" # step: 3
|
260
|
+
end
|
261
|
+
add("pi-r2", "pir2") do
|
262
|
+
chain "all", "build", before: "squared" # step: 3
|
263
|
+
end
|
264
|
+
add("squared-express", "express") do
|
265
|
+
chain "all", "clean", with: "emc" # step: 1
|
266
|
+
chain "all", "build", with: "pir" # step: 3
|
267
|
+
end
|
268
|
+
add("squared") do
|
269
|
+
revbuild(include: %w[src/ framework/ types/]) # Git revision build command (optional)
|
270
|
+
chain "all", "revbuild", after: "express:build" # step: 4
|
271
|
+
chain "publish", "bump:patch", "publish:latest", step: 0, sync: true # rake publish
|
272
|
+
end
|
273
|
+
end
|
274
|
+
.with(:python) do
|
275
|
+
doc("make html")
|
276
|
+
add("android-docs") do
|
277
|
+
chain "all", "doc", with: "squared", after: "squared" # step: 4
|
278
|
+
end
|
279
|
+
add("chrome-docs") do
|
280
|
+
chain "all", "doc", with: "squared", before: "squared:revbuild" # Same
|
281
|
+
end
|
282
|
+
end
|
283
|
+
.chain("all", "status", with: "squared", after: "android-docs") # Global tasks (e.g. without ":")
|
284
|
+
.build
|
887
285
|
```
|
888
286
|
|
889
|
-
```
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
287
|
+
```sh
|
288
|
+
rake all # all[1-3-4]
|
289
|
+
rake all:print
|
290
|
+
```
|
291
|
+
|
292
|
+
Threaded is the default when there are two or more tasks. Using ``with`` and either **before** or **after** will create a synchronous group.
|
293
|
+
|
294
|
+
* Step 1: emc:clean + express:clean (thread)
|
295
|
+
* Step 2: emc:build (sync)
|
296
|
+
* Step 3: pir:build + express:build + pir2:build (thread)
|
297
|
+
* Step 4: chrome-docs:doc + squared:revbuild + android-docs:doc + status (sync)
|
298
|
+
|
299
|
+
#### Graph
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
Workspace::Application
|
303
|
+
.new(main: "squared")
|
304
|
+
.graph(["depend"], ref: :git) # Optional
|
305
|
+
.with(:python) do
|
306
|
+
doc(windows? ? ".\make.bat html" : "make html") # rake android-docs:doc | rake doc:python
|
307
|
+
add("android-docs", "android", venv: "/home/user/.venv") # rake android-docs:depend
|
308
|
+
add("chrome-docs", "chrome", graph: "android", venv: %w[.venv --clear]) do # /workspaces/chrome-docs/.venv
|
309
|
+
variable_set :dependindex, 1 # Use Poetry for dependencies (optional)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
.with(:node) do
|
313
|
+
graph(["build", "copy"], on: { # Overrides "git"
|
314
|
+
first: proc { puts "1" },
|
315
|
+
last: proc { puts "2" }
|
316
|
+
})
|
317
|
+
script("build:dev") # npm run build:dev
|
318
|
+
# OR
|
319
|
+
run([nil, "build:dev", { "PATH" => "~/.bin" }, "--workspace", "--silent"]) # PATH="~/.bin" npm run build:dev --workspace -- --silent
|
320
|
+
# OR
|
321
|
+
run({ # Same
|
322
|
+
script: "build:dev", #
|
323
|
+
env: { "PATH" => "~/.bin" }, #
|
324
|
+
opts: "--workspace", #
|
325
|
+
args: "--silent" #
|
326
|
+
})
|
327
|
+
|
328
|
+
add("e-mc", "emc") do
|
329
|
+
first("build", "emc:clean", "emc:depend") # rake emc:clean && rake emc:depend && rake emc:build && echo "123"
|
330
|
+
last("build", out: "123") { |out: nil| puts out } #
|
331
|
+
error("build") { |err: nil| log.debug err } #
|
332
|
+
end
|
333
|
+
add("pi-r", "pir", graph: "emc", first: {
|
334
|
+
build: proc { puts self.name } # puts "pir"
|
335
|
+
})
|
336
|
+
add("squared-express", "express", graph: "pir")
|
337
|
+
add("squared", graph: ["chrome", "express"]) do
|
338
|
+
first("git:ls-files") { puts "1" } # skipped
|
339
|
+
first("git:ls-files", override: true) { puts "2" } # puts "2"
|
340
|
+
last("git:ls-files") { puts workspace.root } # puts "/workspaces"
|
341
|
+
end
|
342
|
+
end
|
343
|
+
.with(:ruby) do
|
344
|
+
run("gem build") # gem build
|
345
|
+
# OR
|
346
|
+
run("gem build", on: { first: -> { p "2" }, last: -> { p "4" } }) do # run | depend | graph | clean | doc | lint | test
|
347
|
+
p "1"
|
348
|
+
end
|
349
|
+
# OR
|
350
|
+
run(on: { first: -> { p "pass" }, last: -> { p "pass" } }) do
|
351
|
+
p "1"
|
352
|
+
end
|
353
|
+
# OR
|
354
|
+
run(["gem build", "--force", { "RUBY_VERSION" => "3.4.0" }]) # RUBY_VERSION="3.4.0" gem build --force
|
355
|
+
# OR
|
356
|
+
run({ #
|
357
|
+
command: "gem build", # RUBY_VERSION="3.4.0" gem build --silent --force
|
358
|
+
opts: "--force", # composable
|
359
|
+
env: { "PATH" => "~/.bin" }, #
|
360
|
+
args: { silent: true } #
|
361
|
+
})
|
362
|
+
# OR
|
363
|
+
run(["gem pristine", ["gem build", "gem cleanup"], nil, "--debug"]) # gem pristine --debug && gem build --debug && gem cleanup --debug
|
364
|
+
#
|
365
|
+
# All commands are either Array or Hash
|
366
|
+
#
|
367
|
+
run([ # PATH="~/.bin" GEM_HOME="~/.gems/ruby-3.4.0" (merged)
|
368
|
+
["gem pristine", "--all", { "PATH" => "~/.bin" }, "--silent"], # gem pristine --silent --all
|
369
|
+
["gem build", { strict: true }, { "GEM_HOME" => "~/.gems/ruby-3.4.0" }] # gem build --strict
|
370
|
+
]) #
|
371
|
+
# OR
|
372
|
+
run([ # Same
|
373
|
+
{ #
|
374
|
+
env: { "PATH" => "~/.bin" }, #
|
375
|
+
command: "gem pristine", #
|
376
|
+
opts: "--all", args: "--silent" #
|
377
|
+
}, #
|
378
|
+
{ #
|
379
|
+
env: { "GEM_HOME" => "~/.gems/ruby-3.4.0" }, #
|
380
|
+
command: "gem build", #
|
381
|
+
opts: { strict: true } #
|
382
|
+
} #
|
383
|
+
])
|
384
|
+
|
385
|
+
add("pathname", test: ["rake test", { jobs: ENV["RAKE_JOBS"] }]) # rake test --jobs 4
|
386
|
+
add("fileutils", graph: "pathname")
|
387
|
+
add("optparse", run: "gem build", env: { "PATH" => "~/.bin" }, opts: "-v") # PATH="~/.bin" gem build -v
|
388
|
+
add("rake", graph: ["fileutils", "optparse"])
|
389
|
+
banner(command: false) # Always hide banner
|
390
|
+
end
|
391
|
+
.build
|
898
392
|
```
|
899
393
|
|
900
|
-
|
901
|
-
|
902
|
-
|
394
|
+
```sh
|
395
|
+
rake pir:graph # emc + pir
|
396
|
+
rake express:graph # emc + pir + express
|
397
|
+
rake chrome:graph # android + chrome
|
398
|
+
rake graph:python # same
|
399
|
+
rake squared:graph # android + chrome + emc + pir + express + squared
|
400
|
+
rake graph:node # same
|
401
|
+
rake rake:graph # pathname + fileutils + optparse + rake
|
402
|
+
rake graph:ruby # same
|
403
|
+
rake graph # graph:node + graph:ruby
|
903
404
|
|
904
|
-
|
905
|
-
squared
|
906
|
-
const resourceId = node.localSettings.resourceId;
|
907
|
-
android.base.Resource.addString(resourceId, value, /* name */);
|
908
|
-
android.base.Resource.addArray(resourceId, name, items);
|
909
|
-
android.base.Resource.addColor(resourceId, color);
|
910
|
-
android.base.Resource.addDimen(resourceId, name, value);
|
911
|
-
android.base.Resource.addTheme(resourceId, theme);
|
912
|
-
squared.save();
|
913
|
-
});
|
405
|
+
rake squared:graph:run[express,pir] # emc + pir + express + squared
|
406
|
+
rake squared:graph:run[node,-emc] # pir + express + squared
|
914
407
|
```
|
915
408
|
|
916
|
-
###
|
917
|
-
|
918
|
-
View model data can be applied to most HTML elements using the dataset attribute. Different view models can be used for every `parseDocument` session.
|
919
|
-
|
920
|
-
Leaving the `sessionId` empty uses the default view model which is searched last for all projects when attempting a bind.
|
921
|
-
|
922
|
-
```javascript
|
923
|
-
// NOTE: latest(undefined = 1): string (1: most recent sessionId | -1: first sessionId)
|
924
|
-
|
925
|
-
squared.parseDocument("id-1", "id-2", "id-3").then(nodes => {
|
926
|
-
const sessions = squared.latest(2); // ["00001", "00002", "00003"] => ["00002", "00003"]
|
927
|
-
android.setViewModel(
|
928
|
-
{
|
929
|
-
import: ["java.util.Map", "java.util.List"],
|
930
|
-
variable: [
|
931
|
-
{ name: "user", type: "com.example.User" },
|
932
|
-
{ name: "list", type: "List<String>" },
|
933
|
-
{ name: "map", type: "Map<String, String>" },
|
934
|
-
{ name: "index", type: "int" },
|
935
|
-
{ name: "key", type: "String" }
|
936
|
-
]
|
937
|
-
},
|
938
|
-
sessions[0] // nodes[1].sessionId
|
939
|
-
);
|
940
|
-
android.setViewModel(
|
941
|
-
{
|
942
|
-
import: ["java.util.Map"],
|
943
|
-
variable: [
|
944
|
-
{ name: "map", type: "Map<String, String>" }
|
945
|
-
]
|
946
|
-
},
|
947
|
-
sessions[1] // nodes[2].sessionId
|
948
|
-
);
|
949
|
-
});
|
950
|
-
|
951
|
-
squared.parseDocument({
|
952
|
-
element: "main",
|
953
|
-
enabledViewModel: true,
|
954
|
-
dataBindableElements: [
|
955
|
-
{
|
956
|
-
selector: "#first_name",
|
957
|
-
namespace: "android", // "android" is default
|
958
|
-
attr: "text",
|
959
|
-
expression: "user.firstName"
|
960
|
-
},
|
961
|
-
{
|
962
|
-
selector: "#last_name",
|
963
|
-
attr: "text",
|
964
|
-
expression: "user.lastName"
|
965
|
-
},
|
966
|
-
{
|
967
|
-
selector: "#remember_me",
|
968
|
-
attr: "checked",
|
969
|
-
expression: "user.rememberMe",
|
970
|
-
twoWay: true
|
971
|
-
}
|
972
|
-
],
|
973
|
-
data: {
|
974
|
-
viewModel: {
|
975
|
-
import: ["java.util.Map"],
|
976
|
-
variable: [
|
977
|
-
{ name: "map", type: "Map<String, String>" }
|
978
|
-
]
|
979
|
-
}
|
980
|
-
}
|
981
|
-
});
|
982
|
-
|
983
|
-
squared.save();
|
984
|
-
```
|
409
|
+
### Tasks
|
985
410
|
|
986
|
-
|
411
|
+
```ruby
|
412
|
+
Workspace::Series.batch(:ruby, :node, {
|
413
|
+
stage: %i[graph test],
|
414
|
+
reset: %i[stash pull]
|
415
|
+
})
|
987
416
|
|
988
|
-
|
989
|
-
data-viewmodel-{namespace}-{attribute} -> data-viewmodel-android-text
|
417
|
+
Workspace::Series.rename("depend", "install")
|
990
418
|
```
|
991
419
|
|
992
|
-
|
420
|
+
## Usage
|
993
421
|
|
994
|
-
```
|
995
|
-
|
996
|
-
|
997
|
-
<input id="first_name" type="text" data-viewmodel-android-text="user.firstName" />
|
998
|
-
<input id="last_name" type="text" data-viewmodel-android-text="user.lastName" />
|
999
|
-
<input id="remember_me" type="checkbox" data-viewmodel-android-checked="=user.rememberMe" /> <!-- "=" for two-way binding -->
|
1000
|
-
</div>
|
1001
|
-
```
|
422
|
+
```sh
|
423
|
+
rake -T # List tasks
|
424
|
+
rake # rake status (usually "build")
|
1002
425
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
<variable name="list" type="List<String>" />
|
1010
|
-
<variable name="map" type="Map<String, String>" />
|
1011
|
-
<variable name="index" type="int" />
|
1012
|
-
<variable name="key" type="String" />
|
1013
|
-
</data>
|
1014
|
-
<LinearLayout android:id="@+id/main">
|
1015
|
-
<TextView android:text="Name:" />
|
1016
|
-
<EditText
|
1017
|
-
android:id="@+id/first_name"
|
1018
|
-
android:inputType="text"
|
1019
|
-
android:text="@{user.firstName}" />
|
1020
|
-
<EditText
|
1021
|
-
android:id="@+id/last_name"
|
1022
|
-
android:inputType="text"
|
1023
|
-
android:text="@{user.lastName}" />
|
1024
|
-
<CheckBox
|
1025
|
-
android:id="@+id/remember_me"
|
1026
|
-
android:checked="@={user.rememberMe}" />
|
1027
|
-
</LinearLayout>
|
1028
|
-
</layout>
|
1029
|
-
```
|
426
|
+
# GIT_OPTIONS=rebase
|
427
|
+
rake pull # All except "default" + "app"
|
428
|
+
rake pull:ruby # pathname + optparse + logger
|
429
|
+
rake pull:default # pathname + optparse
|
430
|
+
rake pull:app # squared
|
431
|
+
rake pull:node # emc + pir + squared
|
1030
432
|
|
1031
|
-
|
433
|
+
rake build # All except "android"
|
434
|
+
rake doc # optparse + android
|
435
|
+
rake depend # All except "default"
|
1032
436
|
|
1033
|
-
|
437
|
+
rake build:ruby # rake compile + rake install + rake install
|
1034
438
|
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
<div id="item4" data-android-include-end="true">Item 4</div>
|
1041
|
-
<div id="item5" data-android-include="filename2" data-android-include-end="true" data-android-include-viewmodel="exampleData">Item 5</div> <!-- viewModel -->
|
1042
|
-
</div>
|
1043
|
-
```
|
439
|
+
rake clean # All except "default" + "app"
|
440
|
+
rake clean:ruby # rake clean + rake clean + ["tmp/"]
|
441
|
+
rake clean:default # rake clean + rake clean + skip
|
442
|
+
rake clean:app # none + skip + ["build/"]
|
443
|
+
rake clean:node # none + ["publish/**/*.js", "tmp/"] + ["build/"]
|
1044
444
|
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
squared.parseDocument({
|
1049
|
-
element: document.body,
|
1050
|
-
projectId: "project-1", // Affects all layouts in same project
|
1051
|
-
enabledIncludes: true,
|
1052
|
-
includableElements: [
|
1053
|
-
{
|
1054
|
-
selectorStart: "#item2",
|
1055
|
-
selectorEnd: "#item4",
|
1056
|
-
pathname: "app/src/main/res/layout-land",
|
1057
|
-
filename: "filename1.xml",
|
1058
|
-
merge: true // Multiple elements will auto-merge
|
1059
|
-
},
|
1060
|
-
{
|
1061
|
-
selectorStart: "#item5",
|
1062
|
-
selectorEnd: "#item5",
|
1063
|
-
filename: "filename2",
|
1064
|
-
viewModel: "exampleData" // One element only (merge=false)
|
1065
|
-
}
|
1066
|
-
]
|
1067
|
-
});
|
1068
|
-
```
|
1069
|
-
> [!NOTE]
|
1070
|
-
> By sessionId has precedence when associating a view model.
|
1071
|
-
|
1072
|
-
```xml
|
1073
|
-
<LinearLayout>
|
1074
|
-
<TextView>Item 1</TextView>
|
1075
|
-
<include layout="@layout/filename1" />
|
1076
|
-
<include layout="@layout/filename2" app:exampleData="@{exampleData}" />
|
1077
|
-
</LinearLayout>
|
1078
|
-
<!-- res/layout/activity_main.xml -->
|
1079
|
-
|
1080
|
-
<merge>
|
1081
|
-
<TextView>Item 2</TextView>
|
1082
|
-
<TextView>Item 3</TextView>
|
1083
|
-
<TextView>Item 4</TextView>
|
1084
|
-
</merge>
|
1085
|
-
<!-- res/layout-land/filename1.xml -->
|
1086
|
-
|
1087
|
-
<layout>
|
1088
|
-
<data>
|
1089
|
-
<variable name="exampleData" type="com.example.ExampleData" />
|
1090
|
-
</data>
|
1091
|
-
<TextView>Item 5</TextView>
|
1092
|
-
</layout>
|
1093
|
-
<!-- res/layout/filename2.xml -->
|
445
|
+
rake squared:run[#] # List scripts (node)
|
446
|
+
rake squared:rake[#] # List tasks (ruby)
|
1094
447
|
```
|
1095
448
|
|
1096
|
-
|
449
|
+
```sh
|
450
|
+
rake build:app # squared + cli + sqd-serve
|
451
|
+
rake squared:build:workspace # cli + sqd-serve
|
452
|
+
rake pull:sqd # sqd-admin
|
453
|
+
rake squared:pull:workspace # sqd-serve + sqd-admin
|
454
|
+
rake squared:outdated:workspace # cli + sqd-serve + sqd-admin
|
455
|
+
```
|
456
|
+
|
457
|
+
## Methods
|
458
|
+
|
459
|
+
Task:
|
460
|
+
|
461
|
+
* run
|
462
|
+
* script
|
463
|
+
* depend
|
464
|
+
* archive
|
465
|
+
* graph
|
466
|
+
* doc
|
467
|
+
* lint
|
468
|
+
* test
|
469
|
+
* clean
|
470
|
+
|
471
|
+
Non-task:
|
472
|
+
|
473
|
+
* log
|
474
|
+
* exclude
|
475
|
+
|
476
|
+
## Styles
|
477
|
+
|
478
|
+
* banner
|
479
|
+
* border
|
480
|
+
* header
|
481
|
+
* active
|
482
|
+
* inline
|
483
|
+
* subject
|
484
|
+
* border
|
485
|
+
* warn
|
486
|
+
* caution
|
487
|
+
* current
|
488
|
+
* latest
|
489
|
+
* extra
|
490
|
+
* major
|
491
|
+
* red
|
492
|
+
* yellow
|
493
|
+
* green
|
494
|
+
|
495
|
+
## Git
|
496
|
+
|
497
|
+
Most project classes will inherit from `Git` which enables these tasks:
|
498
|
+
|
499
|
+
| Task | Git | Command |
|
500
|
+
| :--------- | :--------------- | :-------------------------------------------- |
|
501
|
+
| branch | branch | create set delete move copy list edit current |
|
502
|
+
| checkout | checkout | commit branch track detach path |
|
503
|
+
| commit | commit | add all amend amend-orig fixup |
|
504
|
+
| diff | diff | head cached branch files between contain |
|
505
|
+
| fetch | fetch | origin remote all |
|
506
|
+
| files | ls-files | cached modified deleted others |
|
507
|
+
| git | | add blame clean mv rm revert status |
|
508
|
+
| merge | merge | commit no-commit send |
|
509
|
+
| pull | pull | origin remote all |
|
510
|
+
| rebase | rebase | branch onto send |
|
511
|
+
| refs | ls-remote --refs | heads tags remote |
|
512
|
+
| reset | reset | commit index patch mode |
|
513
|
+
| restore | restore | staged worktree |
|
514
|
+
| rev | rev | commit output |
|
515
|
+
| show | show | format oneline |
|
516
|
+
| stash | stash | push pop apply branch drop clear list all |
|
517
|
+
| submodule | submodule | status update branch url sync |
|
518
|
+
| switch | switch | branch create detach |
|
519
|
+
| tag | tag | add sign delete list |
|
520
|
+
|
521
|
+
You can disable all of them at once using the `exclude` property.
|
522
|
+
|
523
|
+
```ruby
|
524
|
+
Workspace::Application.exclude('autostash', 'rebase')
|
525
|
+
|
526
|
+
Workspace::Application
|
527
|
+
.new
|
528
|
+
.add("squared", exclude: :git)
|
529
|
+
```
|
530
|
+
|
531
|
+
You can disable one or more of them using the `pass` property as a *string*.
|
532
|
+
|
533
|
+
```ruby
|
534
|
+
Workspace::Application
|
535
|
+
.new
|
536
|
+
.add("squared", pass: ["pull"], ref: :node)
|
537
|
+
.pass("pull", ref: :node) { read_packagemanager(:private) }
|
538
|
+
```
|
539
|
+
|
540
|
+
### Commit Hash
|
541
|
+
|
542
|
+
Commands which use commit hashes are parsed using a ":" prefix as to not be confused for an option.
|
1097
543
|
|
1098
|
-
|
1099
|
-
|
544
|
+
```sh
|
545
|
+
rake squared:log:view[:af012345] # git log af012345
|
546
|
+
rake squared:log:view[H1,HEAD^5,all,lib,./H12345] # git log --all @~1 @^5 -- 'lib' 'H12345'
|
547
|
+
```
|
1100
548
|
|
1101
|
-
|
549
|
+
## Environment
|
1102
550
|
|
1103
|
-
|
551
|
+
### Path
|
1104
552
|
|
1105
|
-
|
1106
|
-
<div>
|
1107
|
-
<span>Item 1</span>
|
1108
|
-
<span data-android-target="location">Item 2</span>
|
1109
|
-
<span data-android-target="location" data-android-target-index="1">Item 3</span>
|
1110
|
-
<div>
|
1111
|
-
<ul id="location">
|
1112
|
-
<li>Item 4</li>
|
1113
|
-
<li>Item 5</li>
|
1114
|
-
<!-- span -->
|
1115
|
-
</ul>
|
1116
|
-
```
|
553
|
+
All project binary programs can have their executable path set to a non-global alias.
|
1117
554
|
|
1118
|
-
```
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1122
|
-
|
1123
|
-
|
1124
|
-
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
555
|
+
```ruby
|
556
|
+
Common::PATH.update({
|
557
|
+
GIT: "/usr/bin/git", # PATH_GIT=/usr/bin/git
|
558
|
+
TAR: "/opt/archivers/tar", # PATH_TAR=/opt/archivers/tar
|
559
|
+
UNZIP: "/opt/archivers/unzip",
|
560
|
+
GEM: "~/.rvm/gems/ruby-3.4.0/bin/gem",
|
561
|
+
BUNDLE: "~/.rvm/gems/ruby-3.4.0/bin/bundle",
|
562
|
+
RAKE: "~/.rvm/gems/ruby-3.4.0/bin/rake",
|
563
|
+
NPM: "/opt/node/v22.0.0/bin/npm",
|
564
|
+
PYTHON: "#{ENV["PYTHONPATH"]}/bin/python"
|
565
|
+
})
|
1128
566
|
```
|
1129
567
|
|
1130
|
-
|
1131
|
-
|
1132
|
-
### Custom Attributes
|
568
|
+
### Build
|
1133
569
|
|
1134
|
-
|
1135
|
-
|
1136
|
-
|
1137
|
-
|
570
|
+
```ruby
|
571
|
+
Workspace::Application
|
572
|
+
.new
|
573
|
+
.add("squared", run: "gcc a.c -o a.o", opts: { __debug__: { g: true, O2: true, c: nil }, c: true, j: 4 }) # gcc a.c -o a.o -c -j4
|
1138
574
|
```
|
1139
575
|
|
1140
|
-
```
|
1141
|
-
|
1142
|
-
|
1143
|
-
data-android-attr-app="layout_scrollFlags::scroll|exitUntilCollapsed">
|
1144
|
-
</div>
|
1145
|
-
```
|
576
|
+
```sh
|
577
|
+
BUILD_TYPE # global
|
578
|
+
${PROG}_COLOR=0 # --no-color (e.g. GIT_COLOR)
|
1146
579
|
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
|
1152
|
-
|
1153
|
-
```
|
580
|
+
# :env :run :args :opts :type
|
581
|
+
# LD_LIBRARY_PATH="path/to/lib" CFLAGS="-Wall" gcc a.c -o a.o -g -O2
|
582
|
+
BUILD_${NAME} # gcc a.c -o a.o
|
583
|
+
BUILD_${NAME}_OPTS # -g
|
584
|
+
BUILD_${NAME}_ENV # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
|
585
|
+
BUILD_${NAME}_TYPE # debug
|
1154
586
|
|
1155
|
-
|
1156
|
-
|
1157
|
-
|
1158
|
-
|
1159
|
-
|
1160
|
-
|
587
|
+
# :env :script :opts :args
|
588
|
+
# NODE_ENV="production" NO_COLOR="1" npm run build:dev --loglevel=error --workspaces=false -- --quiet
|
589
|
+
BUILD_${NAME} # build:dev
|
590
|
+
BUILD_${NAME}_OPTS # --loglevel=error --workspaces=false
|
591
|
+
BUILD_${NAME}_ENV # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
|
592
|
+
BUILD_${NAME}_DEV # pattern,0,1 (:dev)
|
593
|
+
BUILD_${NAME}_PROD # pattern,0,1 (:prod)
|
594
|
+
${REF}_${NAME}_OPTS # --quiet (e.g. NODE_SQUARED_OPTS)
|
1161
595
|
|
1162
|
-
|
596
|
+
BUILD_${NAME}=0 # skip project
|
597
|
+
BUILD_${NAME}_VERSION=0.1.0 # publish + detection
|
1163
598
|
|
1164
|
-
|
599
|
+
BANNER=0 # hide banner
|
600
|
+
BANNER_${NAME}=0 #
|
1165
601
|
|
1166
|
-
|
1167
|
-
|
602
|
+
REVBUILD_FORCE=1 # Rebuild all targets
|
603
|
+
REVBUILD_FORCE_${NAME}=1 # Rebuild project
|
1168
604
|
|
1169
|
-
|
1170
|
-
|
1171
|
-
Animatable animatable = (Animatable) imageView1.getDrawable();
|
1172
|
-
animatable.start();
|
1173
|
-
}
|
605
|
+
PREREQS_${NAME}=build,copy # Class method name to invoke
|
606
|
+
PREREQS_${REF}=depend # e.g. Node
|
1174
607
|
```
|
1175
608
|
|
1176
|
-
###
|
1177
|
-
|
1178
|
-
Most mobile applications do not have a deeply nested hierarchy and are generally better to implement using declarative programming.
|
609
|
+
### Graph
|
1179
610
|
|
1180
|
-
```
|
1181
|
-
|
1182
|
-
|
1183
|
-
android: {
|
1184
|
-
layout_height: "match_parent"
|
1185
|
-
},
|
1186
|
-
tools: {
|
1187
|
-
composableName: "com.example.compose.Preview"
|
1188
|
-
}
|
1189
|
-
}];
|
1190
|
-
squared.settings.createBuildDependencies = true; // Optional
|
611
|
+
```sh
|
612
|
+
GRAPH_${NAME} # depend,build => squared:depend + squared:build
|
613
|
+
GRAPH_${NAME}_PASS # -emc,pir,express => pir + express
|
1191
614
|
```
|
1192
615
|
|
1193
|
-
|
616
|
+
### Logger
|
1194
617
|
|
1195
|
-
|
1196
|
-
// android.substitute is only used here to demonstrate using extensions
|
1197
|
-
|
1198
|
-
squared.add(["android.substitute", {
|
1199
|
-
element: {
|
1200
|
-
content: { android: { layout_width: "match_parent" } }
|
1201
|
-
}
|
1202
|
-
}]);
|
1203
|
-
|
1204
|
-
const items = squared.attr("android.substitute", "viewAttributes");
|
1205
|
-
items.push("hint", "buttonTint");
|
1206
|
-
/* OR */
|
1207
|
-
squared.attr("android.substitute", "viewAttributes", items.concat(["hint", "buttonTint"])); // Attributes to preserve (default is "android.view.View")
|
1208
|
-
squared.attr("android.substitute", "attributeMapping", { "android:src": "app:srcCompat", "icon": "navigationIcon" /* android */});
|
1209
|
-
|
1210
|
-
squared.parseDocument({
|
1211
|
-
element: document.body,
|
1212
|
-
substitutableElements: [{
|
1213
|
-
selector: "#content",
|
1214
|
-
tag: "androidx.compose.ui.platform.ComposeView",
|
1215
|
-
renderChildren: false
|
1216
|
-
}],
|
1217
|
-
|
1218
|
-
// Some extensions have convenience properties
|
1219
|
-
enabledSubstitute: true,
|
1220
|
-
/* OR */
|
1221
|
-
include: ["android.substitute"]
|
1222
|
-
});
|
1223
|
-
```
|
618
|
+
These global options also can target the project suffix `${NAME}`. (e.g. LOG_FILE_EMC)
|
1224
619
|
|
1225
|
-
```
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
1229
|
-
|
1230
|
-
|
1231
|
-
|
1232
|
-
<!-- Interior elements are not rendered -->
|
1233
|
-
</main>
|
1234
|
-
<footer style="height: 80px"></footer>
|
1235
|
-
</body>
|
620
|
+
```sh
|
621
|
+
LOG_FILE # %Y-%m-%d.log
|
622
|
+
# OR
|
623
|
+
LOG_AUTO # year,y,month,m,day,d,1
|
624
|
+
# Optional
|
625
|
+
LOG_DIR # exist?
|
626
|
+
LOG_LEVEL # See gem "logger"
|
1236
627
|
```
|
1237
628
|
|
1238
|
-
|
629
|
+
### Git
|
1239
630
|
|
1240
|
-
|
1241
|
-
<div id="fragment"
|
1242
|
-
data-use="android.substitute"
|
1243
|
-
data-android-substitute-tag="androidx.fragment.app.FragmentContainerView"
|
1244
|
-
data-android-substitute-render-children="false"
|
1245
|
-
data-android-attr="name::com.github.fragment;tag::example">
|
1246
|
-
<!-- Interior elements are not rendered -->
|
1247
|
-
</div>
|
1248
|
-
```
|
631
|
+
* Version: [2.50](https://github.com/git/git/blob/v2.50.0/Documentation/RelNotes/2.50.0.adoc)
|
1249
632
|
|
1250
|
-
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
|
1271
|
-
|
633
|
+
```sh
|
634
|
+
GIT_OPTIONS=q,strategy=ort # all
|
635
|
+
GIT_OPTIONS_${NAME}=v,ff # project only
|
636
|
+
GIT_AUTOSTASH=1 # rebase (all)
|
637
|
+
GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
|
638
|
+
```
|
639
|
+
|
640
|
+
| Command | Flag | ENV |
|
641
|
+
| :--------- | :---------------- | :-------------------------------------------------------------------- |
|
642
|
+
| branch | create | TRACK=0,1,s F|FORCE |
|
643
|
+
| branch | move copy | F|FORCE |
|
644
|
+
| branch | set delete | COUNT=n |
|
645
|
+
| branch | global | SYNC |
|
646
|
+
| checkout | branch | DETACH TRACK=s COUNT=n |
|
647
|
+
| checkout | detach | REFLOG=1 |
|
648
|
+
| checkout | track | COUNT=n |
|
649
|
+
| checkout | global path | HEAD=s PATHSPEC=s |
|
650
|
+
| checkout | * | F|FORCE MERGE |
|
651
|
+
| clone | * | DEPTH=n ORIGIN=s BRANCH=s REVISION=s LOCAL=0,1 |
|
652
|
+
| commit | * | UPSTREAM=s DRY_RUN EDIT=0 M|MESSAGE=s |
|
653
|
+
| diff | -between -contain | MERGE_BASE |
|
654
|
+
| diff | head branch | INDEX=n |
|
655
|
+
| diff | * | PATHSPEC=s |
|
656
|
+
| fetch | -remote | ALL |
|
657
|
+
| fetch | remote | REFSPEC=s |
|
658
|
+
| fetch | * | F|FORCE RECURSE_SUBMODULES=0,1,s |
|
659
|
+
| git | rm | PATHSPEC=s |
|
660
|
+
| log | * | PATHSPEC=s |
|
661
|
+
| pull | remote | REFSPEC=s |
|
662
|
+
| pull | -remote | REBASE=0,1 ALL |
|
663
|
+
| pull | all | FF_ONLY=0 |
|
664
|
+
| pull | * | AUTOSTASH F|FORCE RECURSE_SUBMODULES=0,1,s |
|
665
|
+
| rebase | branch | HEAD=s |
|
666
|
+
| rebase | onto | INTERACTIVE I HEAD=s |
|
667
|
+
| reset | mode (mixed) | N REFRESH=0 |
|
668
|
+
| reset | index | PATHSPEC=s |
|
669
|
+
| reset | commit | COUNT=n REFLOG=1 |
|
670
|
+
| reset | -commit | HEAD=s |
|
671
|
+
| restore | * | PATHSPEC=s |
|
672
|
+
| revbuild | global | UNTRACKED_FILES=s IGNORE_SUBMODULES=s IGNORED=s (status) |
|
673
|
+
| stash | push | PATHSPEC=s |
|
674
|
+
| stash | global | ALL=0,1 KEEP_INDEX=0,1 INCLUDE_UNTRACKED=0,1 STAGED=0,1 M|MESSAGE=s |
|
675
|
+
| status | global | BRANCH LONG IGNORE_SUBMODULES=s,0-3 PATHSPEC=s |
|
676
|
+
| submodule | -branch -url | R|RECURSIVE |
|
677
|
+
| switch | detach | REFLOG=1 |
|
678
|
+
| switch | -detach | HEAD=s |
|
679
|
+
| switch | * | F|FORCE |
|
680
|
+
| tag | add | SIGN FORCE HEAD=s M|MESSAGE=s |
|
681
|
+
| tag | sign | F|FORCE HEAD=s M|MESSAGE=s |
|
682
|
+
| tag | delete | COUNT=n |
|
683
|
+
| rev | commit branch | HEAD=s |
|
684
|
+
|
685
|
+
### Docker
|
686
|
+
|
687
|
+
* Version: [28.3](https://docs.docker.com/engine/release-notes/28)
|
1272
688
|
|
1273
|
-
```
|
1274
|
-
|
1275
|
-
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
data-android-substitute-auto-layout="true">
|
1281
|
-
<li>TAB 1</li>
|
1282
|
-
<li>TAB 2</li>
|
1283
|
-
<li>TAB 3</li>
|
1284
|
-
</ul>
|
1285
|
-
```
|
689
|
+
```sh
|
690
|
+
DOCKER_OPTIONS=q,no-cache # all
|
691
|
+
DOCKER_OPTIONS_${NAME}=v,no-cache=false # project only (override)
|
692
|
+
DOCKER_TAG=latest # all
|
693
|
+
DOCKER_TAG_${NAME}=v0.1.0 # project only (override)
|
694
|
+
DOCKER_ALL=1 # list every image/container
|
695
|
+
DOCKER_Y=1 # confirm all
|
1286
696
|
|
1287
|
-
|
1288
|
-
|
1289
|
-
android:id="@+id/navigation"
|
1290
|
-
android:layout_height="match_parent"
|
1291
|
-
android:layout_width="wrap_content">
|
1292
|
-
<com.google.android.material.tabs.TabItem
|
1293
|
-
android:layout_height="match_parent"
|
1294
|
-
android:layout_width="wrap_content"
|
1295
|
-
android:text="@string/tab_1" />
|
1296
|
-
<com.google.android.material.tabs.TabItem
|
1297
|
-
android:layout_height="match_parent"
|
1298
|
-
android:layout_width="wrap_content"
|
1299
|
-
android:text="@string/tab_2" />
|
1300
|
-
<com.google.android.material.tabs.TabItem
|
1301
|
-
android:layout_height="match_parent"
|
1302
|
-
android:layout_width="wrap_content"
|
1303
|
-
android:text="@string/tab_3" />
|
1304
|
-
</com.google.android.material.tabs.TabLayout>
|
697
|
+
BUILD_SQUARED_OPTS="NODE_TAG=24 RUBY_VERSION=3.4.0" DOCKER_SQUARED_OPTS="--no-cache --label=v1" rake squared:build
|
698
|
+
docker build --no-cache --label=v1 --build-arg='NODE_TAG=24' --build-arg='RUBY_VERSION=3.4.0' .
|
1305
699
|
```
|
1306
700
|
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
701
|
+
| Command | Flag | ENV |
|
702
|
+
| :--------- | :---------------- | :---------------------------------------------- |
|
703
|
+
| buildx | build | TAG=s |
|
704
|
+
| buildx | bake | SERVICE=s |
|
705
|
+
| compose | build | TARGET=s |
|
706
|
+
| container | commit | REGISTRY=s PLATFORM=s DISABLE_CONTENT_TRUST=0,1 |
|
707
|
+
| image | rm | Y=0,1 |
|
708
|
+
| image | push | TAG=s REGISTRY=s |
|
1310
709
|
|
1311
|
-
|
710
|
+
### asdf
|
1312
711
|
|
1313
|
-
|
1314
|
-
<!-- build.gradle -->
|
1315
|
-
dependencies {
|
1316
|
-
implementation 'androidx.appcompat:appcompat:1.6.0' <!-- createBuildDependencies = true -->
|
1317
|
-
<!-- OR -->
|
1318
|
-
implementation 'com.android.support:appcompat-v7:28.0.0'
|
1319
|
-
}
|
712
|
+
* Version: [15](https://asdf-vm.com/guide/getting-started-legacy.html) | [16+](https://asdf-vm.com/guide/getting-started.html)
|
1320
713
|
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
</manifest>
|
1327
|
-
```
|
714
|
+
| Command | Options | Arguments |
|
715
|
+
| :--------- | :---------------- | :---------------|
|
716
|
+
| set | u|home p|parent | version |
|
717
|
+
| exec | | command,args* |
|
718
|
+
| current | | |
|
1328
719
|
|
1329
|
-
```
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
"com.google.android.gms",
|
1335
|
-
["MIIEqDCCA5CgAwIBAgIJANWFuGx9007...", "MIIEQzCCAyugAwIBAgIJAMLgh0Zk..."],
|
1336
|
-
"https://www.googleapis.com/webfonts/v1/webfonts?key=1234567890" // JSON object is synchronous
|
1337
|
-
);
|
1338
|
-
/* OR */
|
1339
|
-
squared.attr("android.resource.fonts", "installGoogleFonts", false); // Use browser and local fonts only
|
720
|
+
```ruby
|
721
|
+
Workspace::Application
|
722
|
+
.new
|
723
|
+
.add("squared", asdf: "ruby", ref: :node) # Any command is supported (default: nodejs)
|
724
|
+
.add("squared-ruby", "squared") # Uses default command "ruby"
|
1340
725
|
```
|
1341
726
|
|
1342
|
-
###
|
1343
|
-
|
1344
|
-
Most attributes can be excluded from the generated XML using the dataset feature in HTML. One or more can be applied to any tag using the OR "**|**" operator. These may cause warnings when you compile your project and should only be used when an extension has their custom attributes overwritten.
|
727
|
+
### Repo
|
1345
728
|
|
1346
|
-
|
729
|
+
These global options also can target the application main suffix `${NAME}`. (e.g. REPO_ROOT_SQUARED)
|
1347
730
|
|
1348
|
-
```
|
1349
|
-
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
731
|
+
```sh
|
732
|
+
REPO_ROOT # parent dir
|
733
|
+
REPO_HOME # project dir (main)
|
734
|
+
REPO_BUILD # run,script
|
735
|
+
REPO_GROUP # string
|
736
|
+
REPO_REF # e.g. ruby,node
|
737
|
+
REPO_DEV # pattern,0,1
|
738
|
+
REPO_PROD # pattern,0,1
|
739
|
+
REPO_WARN # 0,1
|
740
|
+
REPO_SYNC # 0,1
|
741
|
+
REPO_URL # manifest repository
|
742
|
+
REPO_MANIFEST # e.g. latest,nightly,prod
|
743
|
+
REPO_GROUPS # e.g. base,prod,docs
|
744
|
+
REPO_STAGE # 0,1,2,3
|
745
|
+
REPO_SUBMODULLES # 0,1
|
746
|
+
REPO_TIMEOUT # confirm dialog (seconds)
|
1358
747
|
```
|
1359
748
|
|
1360
749
|
## LICENSE
|