@pi-r/android 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,18 +4,18 @@ const htmlparser2 = require("htmlparser2");
4
4
  const domhandler = require("domhandler");
5
5
  const domutils = require("domutils");
6
6
  const domserializer = require("dom-serializer");
7
- const util_1 = require("@e-mc/document/util");
8
7
  const types_1 = require("@e-mc/types");
8
+ const util_1 = require("@e-mc/document/util");
9
9
  const Parser = htmlparser2.Parser;
10
10
  const DomHandler = domhandler.DomHandler;
11
11
  const MANIFEST_ATTR = ['package', 'android:sharedUserId', 'android:sharedUserLabel', 'android:sharedUserMaxSdkVersion', 'android:versionCode', 'android:versionName', 'android:installLocation'];
12
- module.exports = function finalize(instance) {
12
+ function finalize(instance) {
13
13
  const config = instance.config;
14
14
  const manifest = config.manifest;
15
15
  if (!manifest) {
16
16
  return;
17
17
  }
18
- let { localUri, source, existing } = instance.findTemplate(path.join(this.baseDirectory, config.mainParentDir, config.mainSrcDir), "AndroidManifest.xml", { detect: this.incremental !== 'staging' });
18
+ let { localUri, source, existing } = instance.findTemplate(path.join(this.baseDirectory, config.mainParentDir, config.mainSrcDir), "AndroidManifest.xml", { detect: instance.detect(this) });
19
19
  if (localUri && source && instance.canWrite(localUri, { ownPermissionOnly: true })) {
20
20
  const { supportsRtl, label, theme, activity, metaData = [], activityName, fontProvider } = manifest.application || {};
21
21
  const profileable = config.profileable;
@@ -28,7 +28,7 @@ module.exports = function finalize(instance) {
28
28
  case 'label':
29
29
  return '@string/' + (label || 'app_name');
30
30
  case 'theme':
31
- return '@style/' + (theme || 'Theme.Android2');
31
+ return '@style/' + (theme || 'Theme.Android4');
32
32
  case 'activityName':
33
33
  return activityName || '';
34
34
  case 'profileable':
@@ -65,7 +65,7 @@ module.exports = function finalize(instance) {
65
65
  if (activityName) {
66
66
  for (const item of activities) {
67
67
  const intentFilter = domutils.findAll(elem => elem.tagName === 'intent-filter', [item]);
68
- if (intentFilter.length) {
68
+ if (intentFilter.length > 0) {
69
69
  const action = domutils.findOne(elem => elem.tagName === 'action' && elem.attribs['android:name'] === 'android.intent.action.MAIN', intentFilter);
70
70
  if (action) {
71
71
  const attribs = item.attribs;
@@ -131,14 +131,14 @@ module.exports = function finalize(instance) {
131
131
  metaData.push({ name: 'preloaded_fonts', resource: '@array/' + fontProvider });
132
132
  }
133
133
  const keys = Object.keys(manifest).map(attr => MANIFEST_ATTR.includes(attr) ? attr : attr !== 'package' && MANIFEST_ATTR.includes('android:' + attr) ? attr : '').filter(item => item);
134
- if (keys.length || (0, types_1.isArray)(metaData)) {
134
+ if (keys.length > 0 || (0, types_1.isArray)(metaData)) {
135
135
  new Parser(new DomHandler((err, dom) => {
136
136
  if (err) {
137
137
  instance.writeFail(['Unable to parse XML document', "AndroidManifest.xml"], err, 0);
138
138
  return;
139
139
  }
140
140
  let target = null;
141
- if (keys.length && (target = domutils.findOne(elem => elem.tagName === 'manifest', dom, true))) {
141
+ if (keys.length > 0 && (target = domutils.findOne(elem => elem.tagName === 'manifest', dom, true))) {
142
142
  for (let key of keys) {
143
143
  if (!key.startsWith('android:') && key !== 'package') {
144
144
  key = 'android:' + key;
@@ -182,4 +182,5 @@ module.exports = function finalize(instance) {
182
182
  }
183
183
  }
184
184
  }
185
- };
185
+ }
186
+ module.exports = finalize;
@@ -1,14 +1,20 @@
1
1
  "use strict";
2
2
  const path = require("path");
3
- const util_1 = require("@e-mc/document/util");
4
- const types_1 = require("@e-mc/types");
3
+ const fs = require("fs");
5
4
  const Document = require("@e-mc/document");
5
+ const types_1 = require("@e-mc/types");
6
+ const util_1 = require("@e-mc/document/util");
6
7
  const REGEXP_SEMVER = /^((\s*,\s*)?[([\]]((\s*,\s*)?\d+\.\d+(\s*,\s*)?)+[)\][])+$/;
8
+ const REGEXP_DEPENDENCIES = /dependencies\s+\{((?:{[^{]*{|{[^}]*}|}[^}]*}|\\}*?|[^{}+])+)\}/;
9
+ const REGEXP_DEPENDENCY = /([ \t]*)([A-Za-z_$][\w$]*)(?:\s*\(?\s*(?:module\(?\s*)?["']([^"']+)["']\s*\)?|\s+((?:\s*(?:group|name|version)\s*:\s*(?:"[^"]+"|'[^']+')\s*,?){3}))?/gd;
10
+ const REGEXP_DEPENDENCY_KOTLIN = /([ \t]*)([A-Za-z_$][\w$]*)\((?:\s*(?:(?:module\(\s*)?"([^"]+)"|((?:\s*(?:group|name|version)\s*=\s*"[^"]+"\s*,?){3}))\s*\))?/gd;
11
+ const REGEXP_VERSIONS = /([^\s]+)\s*=\s*(?:"([^":]+)"|'([^':]+)'|(\{(?:\s*(?:require|strictly|prefer|reject(?:All)?)\s*=\s*(?:"[^":]+"|'[^':]+')\s*,?)+\s*\}))/g;
12
+ const REGEXP_VERSIONS_LIB = /([^\s]+)\s*=\s*(?:\{\s*(group|name|module|version(?:\.ref)?)\s*=\s*(?:"([^"]+)"|'([^']+)'|(\{[^}]+\}))\s*,\s*(group|name|module|version(?:\.ref)?)\s*=\s*(?:"([^"]+)"|'([^']+)'|(\{[^}]+\}))(?:\s*,\s*(group|name|module|version(?:\.ref)?)\s*=\s*(?:"([^"]+)"|'([^']+)')|(\{[^}]+\}))?\s*\}|(?:"([^:]+:[^"]+)"|'([^:]+:[^']+)'))/gd;
7
13
  function isUpgrade(version, pending) {
8
- if (REGEXP_SEMVER.test(pending)) {
14
+ if (isSemVer(pending)) {
9
15
  return true;
10
16
  }
11
- if (!REGEXP_SEMVER.test(version)) {
17
+ if (!isSemVer(version)) {
12
18
  const previous = version.split(/[.-]/);
13
19
  const current = pending.split(/[.-]/);
14
20
  for (let i = 0; i < previous.length; ++i) {
@@ -27,15 +33,72 @@ function isUpgrade(version, pending) {
27
33
  }
28
34
  return false;
29
35
  }
30
- module.exports = function finalize(instance) {
31
- const { profileable, dependencies, dataBinding, versionName, versionCode, namespace, applicationId, mainParentDir } = instance.config;
32
- if (!profileable && !dependencies && !dataBinding && !versionName && !versionCode && !namespace && !applicationId) {
36
+ function writeMethod(kotlin, named, item, args = '', prefix = 'implementation') {
37
+ if (/^(?:implementation|api|compileOnly(?:Api)?|runtimeOnly|(?:test|androidTest)(?:Implementation|RuntimeOnly|CompileOnly))$/.test(prefix)) {
38
+ switch (parseInt(item[3])) {
39
+ case 0:
40
+ prefix = 'implementation';
41
+ break;
42
+ case 1:
43
+ prefix = 'api';
44
+ break;
45
+ case 2:
46
+ prefix = 'compileOnly';
47
+ break;
48
+ case 3:
49
+ prefix = 'compileOnlyApi';
50
+ break;
51
+ case 4:
52
+ prefix = 'runtimeOnly';
53
+ break;
54
+ case 5:
55
+ prefix = 'testImplementation';
56
+ break;
57
+ case 6:
58
+ prefix = 'testCompileOnly';
59
+ break;
60
+ case 7:
61
+ prefix = 'testRuntimeOnly';
62
+ break;
63
+ case 8:
64
+ prefix = 'androidTestImplementation';
65
+ break;
66
+ case 9:
67
+ prefix = 'androidTestCompileOnly';
68
+ break;
69
+ case 10:
70
+ prefix = 'androidTestRuntimeOnly';
71
+ break;
72
+ }
73
+ }
74
+ const [group, name, version] = item;
75
+ let dependency;
76
+ if (!name && !version) {
77
+ dependency = kotlin ? `(${group})` : ' ' + group;
78
+ }
79
+ else if (args || named) {
80
+ dependency = kotlin ? `(group = "${group}", name = "${name}"${version ? `, version = "${version}"` : ''})` : ` group: '${group}', name: '${name}'${version ? `, version: '${version}'` : ''})` + (args.endsWith(',') ? ',' : '');
81
+ }
82
+ else {
83
+ dependency = item.slice(0, 3).join(':');
84
+ if (dependency.endsWith(':')) {
85
+ dependency = dependency.substring(0, dependency.length - 1);
86
+ }
87
+ dependency = kotlin ? `("${dependency}")` : ` '${dependency}'`;
88
+ }
89
+ return prefix + dependency;
90
+ }
91
+ const isLatest = (value) => value === '' || value.startsWith('latest.');
92
+ const isSemVer = (value) => isLatest(value) || REGEXP_SEMVER.test(value);
93
+ const toCamelCase = (value) => value.replace(/-([a-z])/gi, (...capture) => capture[1].toUpperCase());
94
+ function finalize(instance) {
95
+ const { profileable, dependencies, dataBinding, jvmToolchain, versionName, versionCode, namespace, applicationId, mainParentDir } = instance.config;
96
+ if (!profileable && !dependencies && !dataBinding && !jvmToolchain && !versionName && !versionCode && !namespace && !applicationId) {
33
97
  return;
34
98
  }
35
- const options = { detect: this.incremental !== 'staging', languageOf: 'gradle' };
36
- let { localUri, source, existing, kotlin } = instance.findTemplate(path.join(this.baseDirectory, mainParentDir), "build.gradle", options);
99
+ let { localUri, source, existing, kotlin = false, language } = instance.findTemplate(path.join(this.baseDirectory, mainParentDir), "build.gradle", { detect: instance.detect(this), languageOf: 'gradle' });
37
100
  if (localUri && source && instance.canWrite(localUri, { ownPermissionOnly: true })) {
38
- const { javaVersion, dependencyScopes } = instance.config;
101
+ const javaVersion = instance.config.javaVersion;
39
102
  let jvmTarget, modified;
40
103
  const upgrade = javaVersion > 0;
41
104
  const setModified = (output) => {
@@ -45,10 +108,13 @@ module.exports = function finalize(instance) {
45
108
  }
46
109
  };
47
110
  if (dependencies) {
48
- let data;
111
+ const { dependencyScopes, versionCatalog } = instance.config;
112
+ let mavenData;
49
113
  const hasScope = (value) => (0, types_1.isArray)(dependencyScopes) && dependencyScopes.includes(value) || dependencyScopes === value;
50
114
  const snapshot = dependencyScopes === 1 || hasScope('snapshot');
51
- const getData = () => data ||= instance.findData('google-maven' + (snapshot ? '-snapshot' : '') + '.json', 'json');
115
+ const constraints = hasScope('constraints');
116
+ const checkVersion = (item, version, value) => !value && version.startsWith('{') && version.endsWith('}') ? false : snapshot || constraints && !item[2] || (version.length > 0 && !version.startsWith('$') || !kotlin && !!value?.includes("'")) && isUpgrade(version, item[2]);
117
+ const getData = () => mavenData ||= instance.findData('google-maven' + (snapshot ? '-snapshot' : '') + '.json', 'json');
52
118
  const items = dependencies.map(item => {
53
119
  let [groupId, artifactId, version, type] = item.split(':');
54
120
  if (!version || version === 'maven') {
@@ -61,13 +127,13 @@ module.exports = function finalize(instance) {
61
127
  version = '';
62
128
  }
63
129
  }
64
- return [groupId, artifactId, version || (snapshot ? 'latest.integration' : 'latest.release'), type];
130
+ return [groupId, artifactId, version || (snapshot ? 'latest.integration' : constraints ? '' : 'latest.release'), type];
65
131
  });
66
- if (dependencyScopes && (data = getData())) {
132
+ if (dependencyScopes && (mavenData = getData())) {
67
133
  const supplement = [];
68
134
  for (const item of items) {
69
135
  const [gId, id] = item;
70
- const target = data[gId]?.find(group => id === group.artifactId);
136
+ const target = mavenData[gId]?.find(group => id === group.artifactId);
71
137
  if (!target) {
72
138
  continue;
73
139
  }
@@ -95,8 +161,8 @@ module.exports = function finalize(instance) {
95
161
  if (current) {
96
162
  const t = parseInt(current[3]);
97
163
  if (t !== type) {
98
- const rangeVer = REGEXP_SEMVER.test(version);
99
- if (!REGEXP_SEMVER.test(current[2])) {
164
+ const rangeVer = isSemVer(version);
165
+ if (!isSemVer(current[2])) {
100
166
  if (rangeVer || type < t) {
101
167
  current[2] = version;
102
168
  found = true;
@@ -154,106 +220,201 @@ module.exports = function finalize(instance) {
154
220
  if (!kotlin && items.some(seg => seg[1].endsWith('-ktx'))) {
155
221
  setModified(Document.updateGradle(source, ['plugins'], "id 'kotlin-android'", { multiple: true }));
156
222
  }
157
- const match = /dependencies\s+\{((?:{[^{]*{|{[^}]*}|}[^}]*}|\\}*?|[^{}+])+)\}/.exec(source);
223
+ const match = REGEXP_DEPENDENCIES.exec(source);
158
224
  if (match) {
159
- const pattern = kotlin ? /([ \t]*)(implementation|api|compileOnly(?:Api)?|runtimeOnly|(?:test|androidTest)(?:Implementation|RuntimeOnly|CompileOnly))\((?:\s*(?:"([^"]+)"|((?:\s*(?:group|name|version)\s*=\s*"[^"]+"\s*,?){3}))\s*\))?/g : /([ \t]*)(implementation|api|compileOnly(?:Api)?|runtimeOnly|(?:test|androidTest)(?:Implementation|RuntimeOnly|CompileOnly))(?:\s*\(?\s*["']([^"']+)["']\s*\)?|\s+((?:\s*(?:group|name|version)\s*:\s*["'][^"']+["']\s*,?){3}))?/g;
160
- let content = match[1], named = false, indent, method;
161
- const writeMethod = (item, args, prefix = 'implementation') => {
162
- switch (parseInt(item[3])) {
163
- case 0:
164
- prefix = 'implementation';
165
- break;
166
- case 1:
167
- prefix = 'api';
168
- break;
169
- case 2:
170
- prefix = 'compileOnly';
171
- break;
172
- case 3:
173
- prefix = 'compileOnlyApi';
174
- break;
175
- case 4:
176
- prefix = 'runtimeOnly';
177
- break;
178
- case 5:
179
- prefix = 'testImplementation';
180
- break;
181
- case 6:
182
- prefix = 'testCompileOnly';
183
- break;
184
- case 7:
185
- prefix = 'testRuntimeOnly';
186
- break;
187
- case 8:
188
- prefix = 'androidTestImplementation';
189
- break;
190
- case 9:
191
- prefix = 'androidTestCompileOnly';
192
- break;
193
- case 10:
194
- prefix = 'androidTestRuntimeOnly';
195
- break;
196
- }
197
- let dependency;
198
- if (args || named) {
199
- const [group, name, version] = item;
200
- dependency = kotlin ? `(group = "${group}", name = "${name}", version = "${version}")` : ` group: '${group}', name: '${name}', version: '${version}'` + (args?.endsWith(',') ? ',' : '');
201
- }
202
- else {
203
- dependency = item.slice(0, 3).join(':');
204
- dependency = kotlin ? `("${dependency}")` : ` '${dependency}'`;
205
- }
206
- return prefix + dependency;
207
- };
208
- while (method = pattern.exec(match[1])) {
209
- let group, name, version;
210
- if (method[3]) {
211
- [group, name, version] = method[3].trim().split(/\s*:\s*/);
212
- }
213
- else if (method[4]) {
214
- const params = /(group|name|version)\s*[=:]\s*["']([^"']+)["']/g;
215
- let param;
216
- while (param = params.exec(method[4])) {
217
- const value = param[2].trim();
218
- switch (param[1]) {
219
- case 'group':
220
- group = value;
221
- break;
222
- case 'name':
223
- name = value;
224
- break;
225
- case 'version':
226
- version = value;
227
- break;
225
+ const newLine = source.includes('\r\n') ? '\r\n' : '\n';
226
+ const gradleDir = path.join(this.baseDirectory, 'gradle');
227
+ const template = instance.findTemplate(gradleDir, "libs.versions.toml", { detect: true, subDir: kotlin ? 'kotlin' : undefined, throwsDoesNotExist: false });
228
+ let content = match[1], named = false, versioning, indent;
229
+ if (template.localUri && template.source) {
230
+ versioning = kotlin && versionCatalog !== false || versionCatalog;
231
+ if (versioning || template.existing) {
232
+ const libraries = {};
233
+ const versions = {};
234
+ let config = template.source, catalog;
235
+ while (catalog = REGEXP_VERSIONS.exec(config)) {
236
+ versions[catalog[1]] = (catalog[2] || catalog[3] || catalog[4]).trim();
237
+ }
238
+ while (catalog = REGEXP_VERSIONS_LIB.exec(config)) {
239
+ const lib = {};
240
+ const inline = catalog[14] || catalog[15];
241
+ if (inline) {
242
+ [lib.group, lib.name] = inline.trim().split(':');
243
+ }
244
+ else {
245
+ let i = 0;
246
+ for (const attr of ['group', 'name', 'module', 'version.ref', 'version']) {
247
+ const index = catalog.findIndex(seg => seg === attr);
248
+ if (index !== -1) {
249
+ lib[attr] = (catalog[i = index + 1] || catalog[i = index + 2] || catalog[i = index + 3]).trim();
250
+ if (attr === 'version') {
251
+ lib.version_indices = catalog.indices[i];
252
+ }
253
+ }
254
+ }
255
+ }
256
+ let { group, name } = lib;
257
+ if (lib.module) {
258
+ [group, name] = lib.module.split(':');
259
+ }
260
+ if (group && name) {
261
+ const index = items.findIndex(seg => seg[0] === group && seg[1] === name);
262
+ if (index !== -1) {
263
+ const item = items[index];
264
+ items.splice(index, 1);
265
+ const ref = lib['version.ref'];
266
+ const version = ref ? versions[ref] : lib.version;
267
+ if (version && checkVersion(item, version)) {
268
+ if (ref) {
269
+ const target = new RegExp(`\\s${(0, types_1.escapePattern)(ref)}\\s*=\\s*(?:"([^":]+)"|'([^':]+)')`, 'd').exec(config);
270
+ if (target) {
271
+ const [start, end] = target.indices[1] || target.indices[2];
272
+ config = (0, util_1.spliceString)(config, start, end, versions[ref] = item[2], REGEXP_VERSIONS_LIB);
273
+ }
274
+ }
275
+ else if (lib.version_indices) {
276
+ const [start, end] = lib.version_indices;
277
+ config = (0, util_1.spliceString)(config, start, end, lib.version = item[2], REGEXP_VERSIONS_LIB);
278
+ }
279
+ }
280
+ }
281
+ libraries[catalog[1]] = lib;
228
282
  }
229
283
  }
230
- named = true;
231
- }
232
- if (group && name) {
233
- let found = 0, index = -1;
234
- if (version && (index = items.findIndex(seg => seg[0] === group && seg[1] === name)) !== -1) {
235
- found = (!version.startsWith('$') || !kotlin && method[0].includes("'")) && isUpgrade(version, items[index][2]) ? 2 : 1;
284
+ if (versioning && items.length > 0) {
285
+ let output = '[libraries]' + newLine, outputVer = '';
286
+ for (let i = 0, length = items.length; i < length; ++i) {
287
+ const item = items[i];
288
+ const [group, name, version] = item;
289
+ let key = group.replaceAll('.', '-');
290
+ if (libraries[key]) {
291
+ key += '-' + name.replaceAll('.', '-');
292
+ }
293
+ let versionRef;
294
+ found: {
295
+ for (const ref in versions) {
296
+ if (versions[ref] === version) {
297
+ for (const lib in libraries) {
298
+ if (libraries[lib]['version.ref'] === ref && (libraries[lib].group === group || libraries[lib].module?.startsWith(group + ':'))) {
299
+ versionRef = ref;
300
+ break found;
301
+ }
302
+ }
303
+ }
304
+ }
305
+ }
306
+ if (!versionRef) {
307
+ if (versions[versionRef = toCamelCase(name)]) {
308
+ const prefix = group.split('.').filter(seg => seg !== name).pop();
309
+ if (prefix) {
310
+ versionRef = toCamelCase(prefix + '-' + name);
311
+ }
312
+ else {
313
+ const baseRef = versionRef;
314
+ let j = 1;
315
+ do {
316
+ versionRef = baseRef + j++;
317
+ } while (versions[versionRef]);
318
+ }
319
+ }
320
+ versions[versionRef] = version;
321
+ outputVer += versionRef + ` = "${version}"` + newLine;
322
+ }
323
+ output += key + ` = { group = "${group}", name = "${name}", version.ref = "${versionRef}" }` + newLine;
324
+ item[0] = 'libs.' + key.replaceAll('-', '.');
325
+ item[1] = '';
326
+ item[2] = '';
327
+ libraries[key] = { group, name, "version.ref": versionRef };
328
+ }
329
+ let section = /\[libraries\]\s*/.exec(config);
330
+ const writeOutput = (value) => (0, util_1.spliceString)(config, section.index, section.index + section[0].length, value);
331
+ if (section) {
332
+ config = writeOutput(output);
333
+ }
334
+ else {
335
+ config += output;
336
+ }
337
+ if (outputVer) {
338
+ outputVer = '[versions]' + newLine + outputVer;
339
+ if (section = /\[versions\]\s*/.exec(config)) {
340
+ config = writeOutput(outputVer);
341
+ }
342
+ else {
343
+ config = outputVer + newLine + config;
344
+ }
345
+ }
346
+ REGEXP_VERSIONS.lastIndex = 0;
236
347
  }
237
- if (found) {
238
- if (found === 2) {
239
- content = content.replace(method[0].trim(), writeMethod(items[index], method[4], method[2]));
240
- modified = true;
348
+ if (instance.canWrite(template.localUri, { ownPermissionOnly: true }) && Document.createDir(gradleDir)) {
349
+ try {
350
+ if (instance.writeFile(template.localUri, config, { encoding: 'utf-8', ownPermissionOnly: true, throwsPermission: true })) {
351
+ this.add(template.localUri);
352
+ }
353
+ }
354
+ catch (err) {
355
+ this.writeFail(["Unable to write file", path.basename(template.localUri)], err, 8192);
241
356
  }
242
- items.splice(index, 1);
243
357
  }
244
- }
245
- if (method[1]) {
246
- indent = method[1];
358
+ REGEXP_VERSIONS_LIB.lastIndex = 0;
247
359
  }
248
360
  }
249
- if (items.length) {
250
- const newline = process.platform === 'win32' ? '\r\n' : '\n';
361
+ if (items.length > 0) {
362
+ if (!versioning) {
363
+ const pattern = kotlin ? REGEXP_DEPENDENCY_KOTLIN : REGEXP_DEPENDENCY;
364
+ pattern.lastIndex = 0;
365
+ let method;
366
+ while (method = pattern.exec(content)) {
367
+ let group, name, version;
368
+ if (method[1]) {
369
+ indent ||= method[1];
370
+ }
371
+ if (method[3]) {
372
+ [group, name, version] = method[3].trim().split(/\s*:\s*/);
373
+ }
374
+ else if (method[4]) {
375
+ const params = /(group|name|version)\s*[=:]\s*(?:"([^"]+)"|'([^']+)')/g;
376
+ let param;
377
+ while (param = params.exec(method[4])) {
378
+ const value = (param[2] || param[3]).trim();
379
+ switch (param[1]) {
380
+ case 'group':
381
+ group = value;
382
+ break;
383
+ case 'name':
384
+ name = value;
385
+ break;
386
+ case 'version':
387
+ version = value;
388
+ break;
389
+ }
390
+ }
391
+ named = true;
392
+ }
393
+ if (group && name) {
394
+ const index = items.findIndex(seg => seg[0] === group && seg[1] === name);
395
+ if (index !== -1) {
396
+ const item = items[index];
397
+ items.splice(index, 1);
398
+ if (!version) {
399
+ if (constraints) {
400
+ continue;
401
+ }
402
+ version = '';
403
+ }
404
+ if (checkVersion(item, version, method[0])) {
405
+ content = (0, util_1.spliceString)(content, method.index, method.index + method[0].length, method[1] + writeMethod(kotlin, named, item, method[4], method[2]) + newLine, pattern);
406
+ modified = true;
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
251
412
  indent ||= (0, util_1.getIndent)(source);
252
- content = items.reduce((a, b) => a + indent + writeMethod(b) + newline, content);
413
+ content = items.reduce((a, b) => a + indent + writeMethod(kotlin, named, b) + newLine, content);
253
414
  modified = true;
254
415
  }
255
416
  if (modified || !existing) {
256
- setModified(source.substring(0, match.index) + `dependencies {${content}}` + source.substring(match.index + match[0].length));
417
+ setModified((0, util_1.spliceString)(source, match.index, match.index + match[0].length, `dependencies {${content}}`));
257
418
  }
258
419
  }
259
420
  if (items.some(seg => seg[0] === 'androidx.compose.ui')) {
@@ -263,9 +424,12 @@ module.exports = function finalize(instance) {
263
424
  output = Document.updateGradle(output, ['android', 'buildFeatures'], 'compose = true');
264
425
  }
265
426
  else {
266
- output = Document.updateGradle(output, ['plugins'], "id 'org.jetbrains.kotlin.android'", { upgrade: true, multiple: true, addendum: `version '${instance.findVersion('org.jetbrains.kotlin:kotlin-stdlib', "1.9.24")}'` });
427
+ const stdLib = instance.findVersion('org.jetbrains.kotlin:kotlin-stdlib', "2.0.20");
428
+ output = Document.updateGradle(output, ['plugins'], "id 'org.jetbrains.kotlin.android'", { upgrade: true, multiple: true, addendum: `version '${stdLib}'` });
267
429
  output = Document.updateGradle(output, ['android', 'buildFeatures'], "compose true");
268
- output = Document.updateGradle(output, ['android', 'composeOptions'], `kotlinCompilerExtensionVersion '${instance.findVersion('kotlinCompilerExtensionVersion', "1.5.14")}'`, true);
430
+ if (stdLib.startsWith('1.')) {
431
+ output = Document.updateGradle(output, ['android', 'composeOptions'], `kotlinCompilerExtensionVersion '${instance.findVersion('kotlinCompilerExtensionVersion', "1.5.14")}'`, true);
432
+ }
269
433
  if (upgrade) {
270
434
  output = Document.updateGradle(output, ['android', 'kotlinOptions'], `jvmTarget = '${javaVersion}'`, true);
271
435
  }
@@ -291,6 +455,16 @@ module.exports = function finalize(instance) {
291
455
  }
292
456
  setModified(output);
293
457
  }
458
+ if (jvmToolchain) {
459
+ let output = source;
460
+ if (language === 'java') {
461
+ output = Document.updateGradle(output, ['java', 'toolchain'], kotlin ? `languageVersion.set(JavaLanguageVersion.of(${jvmToolchain}))` : `languageVersion = JavaLanguageVersion.of(${jvmToolchain})`, true);
462
+ }
463
+ else {
464
+ output = Document.updateGradle(output, ['kotlin'], kotlin ? `jvmToolchain(${jvmToolchain})` : 'jvmToolchain ' + jvmToolchain, true);
465
+ }
466
+ setModified(output);
467
+ }
294
468
  if (!existing) {
295
469
  const targetAPI = instance.targetAPI;
296
470
  let output = source;
@@ -372,16 +546,55 @@ module.exports = function finalize(instance) {
372
546
  }
373
547
  }
374
548
  if (!existing) {
375
- ({ localUri, source, existing, kotlin } = instance.findTemplate(this.baseDirectory, "build.gradle", { ...options, subDir: 'static' }));
376
- if (localUri && source && instance.canWrite(localUri, { ownPermissionOnly: true })) {
549
+ const template = instance.findTemplate(this.baseDirectory, "build.gradle", { detect: instance.detect(this), languageOf: 'gradle', subDir: 'static' });
550
+ if (template.localUri && template.source && instance.canWrite(template.localUri, { ownPermissionOnly: true })) {
377
551
  try {
378
- if (instance.writeFile(localUri, source, { encoding: 'utf-8', ownPermissionOnly: true, throwsPermission: true })) {
379
- this.add(localUri);
552
+ if (instance.writeFile(template.localUri, template.source, { encoding: 'utf-8', ownPermissionOnly: true, throwsPermission: true })) {
553
+ this.add(template.localUri);
380
554
  }
381
555
  }
382
556
  catch (err) {
383
- this.writeFail(["Unable to write file", path.basename(localUri)], err, 8192);
557
+ this.writeFail(["Unable to write file", path.basename(template.localUri)], err, 8192);
558
+ }
559
+ }
560
+ try {
561
+ const projectDir = instance.resolveDir('project');
562
+ if (projectDir) {
563
+ (function recurse(subDir, targetDir) {
564
+ fs.readdirSync(subDir, { withFileTypes: true }).forEach(item => {
565
+ const srcName = path.join(subDir, item.name);
566
+ if (item.isDirectory()) {
567
+ switch (/^\$\{([^}]+)\}$/.exec(item.name)?.[1]) {
568
+ case 'app':
569
+ if (instance.config.mainParentDir) {
570
+ recurse.call(this, srcName, path.join(targetDir, instance.config.mainParentDir));
571
+ }
572
+ break;
573
+ case 'src':
574
+ if (instance.config.mainSrcDir) {
575
+ recurse.call(this, srcName, path.join(targetDir, instance.config.mainSrcDir));
576
+ }
577
+ break;
578
+ default:
579
+ recurse.call(this, srcName, path.join(targetDir, item.name));
580
+ break;
581
+ }
582
+ }
583
+ else if (item.isFile()) {
584
+ const destDir = path.join(this.baseDirectory, targetDir);
585
+ const destName = path.join(destDir, item.name);
586
+ if (!Document.isPath(destName) && instance.canWrite(destName, { ownPermissionOnly: true }) && Document.createDir(destDir)) {
587
+ fs.copyFileSync(srcName, destName);
588
+ this.add(destName);
589
+ }
590
+ }
591
+ });
592
+ }).call(this, projectDir, './');
384
593
  }
385
594
  }
595
+ catch (err) {
596
+ this.writeFail("Path not found", err, 32);
597
+ }
386
598
  }
387
- };
599
+ }
600
+ module.exports = finalize;
@@ -2,12 +2,12 @@
2
2
  const path = require("path");
3
3
  const util_1 = require("@e-mc/document/util");
4
4
  const parse_1 = require("@e-mc/document/parse");
5
- module.exports = function finalize(instance) {
5
+ function finalize(instance) {
6
6
  const { dependencies, projectName, mainParentDir } = instance.config;
7
7
  if (!dependencies && !projectName) {
8
8
  return;
9
9
  }
10
- let { localUri, source, existing, kotlin } = instance.findTemplate(this.baseDirectory, "settings.gradle", { detect: this.incremental !== 'staging', languageOf: 'gradle' });
10
+ let { localUri, source, existing, kotlin } = instance.findTemplate(this.baseDirectory, "settings.gradle", { detect: instance.detect(this), languageOf: 'gradle' });
11
11
  if (localUri && source && instance.canWrite(localUri, { ownPermissionOnly: true })) {
12
12
  const targetName = projectName?.replace(/"/g, '\\"');
13
13
  let modified;
@@ -75,4 +75,5 @@ module.exports = function finalize(instance) {
75
75
  }
76
76
  }
77
77
  }
78
- };
78
+ }
79
+ module.exports = finalize;