lecodes-cli 2.2.8 → 2.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "lecodes-cli",
55
- version: "2.2.8",
55
+ version: "2.2.9",
56
56
  dependencies: {
57
57
  "@letary/chisel": "^0.14.0",
58
58
  jimp: "^1.6.1",
@@ -76,7 +76,7 @@ var init_package = __esm(() => {
76
76
  },
77
77
  peerDependencies: {
78
78
  "lecodes-design": "^0.11.0",
79
- "lecodes-headless": "^2.2.8",
79
+ "lecodes-headless": "^2.2.9",
80
80
  "lecodes-3d-editor": "^0.9.0",
81
81
  "lecodes-assets": "^0.2.1",
82
82
  "heic-decode": "^2.1.0",
@@ -146,7 +146,7 @@ var init_package = __esm(() => {
146
146
  });
147
147
 
148
148
  // ../../sdk/src/version.ts
149
- var SDK_VERSION = "2.2.8", sdkMajor = (version) => {
149
+ var SDK_VERSION = "2.2.9", sdkMajor = (version) => {
150
150
  const m = version?.match(/^(\d+)\.\d+\.\d+/);
151
151
  return m ? Number(m[1]) : null;
152
152
  }, bundleSdkVersion = (head) => head.slice(0, 2000).match(/^\/\/ sdk: (\d+\.\d+\.\d+\S*)/m)?.[1] ?? null, bundleRunsOn = (bundleVersion, hostVersion) => sdkMajor(bundleVersion) !== null && sdkMajor(bundleVersion) === sdkMajor(hostVersion);
@@ -217959,6 +217959,82 @@ var readManifest2 = (dir, id) => {
217959
217959
  };
217960
217960
  var readManifestIfAny = (dir, id) => existsSync14(join17(dir, MANIFEST_FILE)) ? readManifest2(dir, id) : null;
217961
217961
 
217962
+ // src/plugin/emitPackage.ts
217963
+ class PackageError extends Error {
217964
+ }
217965
+ var swiftPackageName = (url) => (url.replace(/\/+$/, "").split("/").pop() ?? url).replace(/\.git$/, "");
217966
+ var iosModule = (id, manifest) => manifest.ios?.module ?? `LeCodes${pascal(id)}`;
217967
+ var PACKAGE_FILE = "Package.swift";
217968
+ var DEFAULT_SDK_PATH = "../lecodes";
217969
+ var emitPackageSwift = (plugins, sdkPath = DEFAULT_SDK_PATH) => {
217970
+ const ios = plugins.filter((p) => p.manifest.ios !== null);
217971
+ const packages = new Map;
217972
+ for (const p of ios) {
217973
+ for (const pkg of p.manifest.ios.packages ?? []) {
217974
+ const prior = packages.get(pkg.url);
217975
+ if (prior && (prior.exact !== pkg.exact || prior.from !== pkg.from)) {
217976
+ throw new PackageError(`"${p.id}" pins ${pkg.url} at ${pkg.exact ?? `from ${pkg.from}`} but "${prior.by}" pins ${prior.exact ?? `from ${prior.from}`} — one package resolves once`);
217977
+ }
217978
+ if (!prior)
217979
+ packages.set(pkg.url, { ...pkg, by: p.id });
217980
+ }
217981
+ }
217982
+ const moduleOf = (p) => iosModule(p.id, p.manifest);
217983
+ const products = ios.map((p) => ` .library(name: "${moduleOf(p)}", targets: ["${moduleOf(p)}"]),`);
217984
+ const dependencies = [
217985
+ ` .package(name: "lecodes", path: sdk),`,
217986
+ ...[...packages.values()].map((pkg) => ` .package(url: "${pkg.url}", ${pkg.exact ? `exact: "${pkg.exact}"` : `from: "${pkg.from}"`}),`)
217987
+ ];
217988
+ const targets = ios.map((p) => {
217989
+ const deps = [
217990
+ `.product(name: "LeCodes", package: "lecodes")`,
217991
+ ...(p.manifest.ios.packages ?? []).flatMap((pkg) => pkg.products.map((name) => `.product(name: "${name}", package: "${swiftPackageName(pkg.url)}")`))
217992
+ ];
217993
+ return [
217994
+ ` // ${p.id}`,
217995
+ ` .target(`,
217996
+ ` name: "${moduleOf(p)}",`,
217997
+ ` dependencies: [${deps.join(", ")}],`,
217998
+ ` path: "plugins/${p.id}/ios"`,
217999
+ ` ),`
218000
+ ].join(`
218001
+ `);
218002
+ });
218003
+ return `// swift-tools-version:5.9
218004
+ // GENERATED by \`lecodes plugin gen\` from the plugins' manifests (lecodes-plugin.json) — do not edit.
218005
+ //
218006
+ // The plugins with an iOS half as ONE SwiftPM package: a target per plugin (its sources in
218007
+ // plugins/<id>/ios, the packages its manifest names) and a product per plugin. Each plugin is its
218008
+ // own module: an Xcode project links a plugin as a product instead of compiling its folder, and two
218009
+ // plugins may name a type alike.
218010
+ //
218011
+ // The SDK is the LeCodes package on disk: LECODES_IOS_SDK_PATH, else the path below (the repo's
218012
+ // package.json \`lecodes.iosSdkPath\`, or the sibling ../lecodes). A shell made by \`lecodes app sync\`
218013
+ // does not use this package: it vendors the sources into targets of its own, pinned by
218014
+ // plugins.lock.json.
218015
+ import PackageDescription
218016
+
218017
+ let sdk = Context.environment["LECODES_IOS_SDK_PATH"] ?? ${JSON.stringify(sdkPath)}
218018
+
218019
+ let package = Package(
218020
+ name: "lecodes-plugins",
218021
+ platforms: [.iOS(.v15)],
218022
+ products: [
218023
+ ${products.join(`
218024
+ `)}
218025
+ ],
218026
+ dependencies: [
218027
+ ${dependencies.join(`
218028
+ `)}
218029
+ ],
218030
+ targets: [
218031
+ ${targets.join(`
218032
+ `)}
218033
+ ]
218034
+ )
218035
+ `;
218036
+ };
218037
+
217962
218038
  // src/commands/app/shared.ts
217963
218039
  var FIRST_PARTY_PLUGINS = {
217964
218040
  camera: "letary/lecodes-plugins",
@@ -218006,7 +218082,6 @@ var desktopDefaultViewport = (root) => {
218006
218082
  height: cfg.desktop.window?.height ?? DESKTOP_DEFAULT_WINDOW.height
218007
218083
  };
218008
218084
  };
218009
- var swiftPackageName = (url) => (url.replace(/\/+$/, "").split("/").pop() ?? url).replace(/\.git$/, "");
218010
218085
  var isLocalPluginSpec = (spec) => spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/") || spec.startsWith("file:");
218011
218086
  var resolveUpdateUrl = (update, root, sdkVersion) => {
218012
218087
  if (update === false)
@@ -231179,7 +231254,7 @@ var loadTypescript = (dir) => {
231179
231254
  var generatePlugin = (ts, plugin2) => {
231180
231255
  const file = join46(plugin2.dir, CONTRACT_FILE);
231181
231256
  const contract = readContract(ts, file, readFileSync33(file, "utf8"));
231182
- readManifestIfAny(plugin2.dir, plugin2.id);
231257
+ const manifest = readManifestIfAny(plugin2.dir, plugin2.id);
231183
231258
  const handWritten = existsSync41(join46(plugin2.dir, "sdk", `${plugin2.id}.ts`));
231184
231259
  const single = contract.channels.length === 1;
231185
231260
  const files = contract.channels.map((channel) => ({
@@ -231203,7 +231278,7 @@ var generatePlugin = (ts, plugin2) => {
231203
231278
  ${foreign.map((f5) => ` ${f5}`).join(`
231204
231279
  `)}`);
231205
231280
  }
231206
- return { contract, files };
231281
+ return { contract, manifest, files };
231207
231282
  };
231208
231283
  var hostImports = (web) => {
231209
231284
  const found = [];
@@ -231243,32 +231318,53 @@ var kotlinPackage = (android) => {
231243
231318
  }
231244
231319
  return { dir, name: relative8(root, dir).split(/[\\/]/).join(".") };
231245
231320
  };
231321
+ var repoSdkPath = (root) => {
231322
+ const file = join46(root, "package.json");
231323
+ if (!existsSync41(file))
231324
+ return DEFAULT_SDK_PATH;
231325
+ try {
231326
+ const pkg = JSON.parse(readFileSync33(file, "utf8"));
231327
+ const path2 = pkg.lecodes?.iosSdkPath;
231328
+ if (path2 !== undefined && typeof path2 !== "string")
231329
+ throw new PackageError(`package.json lecodes.iosSdkPath: a path, as a string`);
231330
+ return path2 ?? DEFAULT_SDK_PATH;
231331
+ } catch (e2) {
231332
+ if (e2 instanceof PackageError)
231333
+ throw e2;
231334
+ throw new PackageError(`package.json does not parse: ${e2 instanceof Error ? e2.message : String(e2)}`);
231335
+ }
231336
+ };
231246
231337
  var generate = (path2, opts = {}) => {
231247
231338
  const plugins = findPlugins(path2);
231248
231339
  if (plugins.length === 0)
231249
231340
  throw new CliError(`No plugin under ${resolve23(path2)}: a plugin is a directory with a ${CONTRACT_FILE} (one, or plugins/<id>/ of a repo).`);
231250
231341
  const ts = loadTypescript(plugins[0].dir);
231251
231342
  const root = resolve23(path2);
231252
- const report = { plugins: [], failures: [] };
231343
+ const report = { plugins: [], repo: { written: [], stale: [], fresh: [] }, failures: [] };
231344
+ const place = (f5, entry) => {
231345
+ const name = shown(root, f5.file) || basename23(f5.file);
231346
+ const current = existsSync41(f5.file) ? readFileSync33(f5.file, "utf8") : null;
231347
+ if (current === f5.text) {
231348
+ entry.fresh.push(name);
231349
+ return;
231350
+ }
231351
+ if (opts.check) {
231352
+ entry.stale.push(name);
231353
+ return;
231354
+ }
231355
+ mkdirSync26(join46(f5.file, ".."), { recursive: true });
231356
+ writeFileSync28(f5.file, f5.text);
231357
+ entry.written.push(name);
231358
+ };
231359
+ const manifests = [];
231253
231360
  for (const plugin2 of plugins) {
231254
231361
  try {
231255
- const { contract, files } = generatePlugin(ts, plugin2);
231362
+ const { contract, manifest, files } = generatePlugin(ts, plugin2);
231363
+ if (manifest)
231364
+ manifests.push({ id: plugin2.id, manifest });
231256
231365
  const entry = { id: plugin2.id, contract, written: [], stale: [], fresh: [] };
231257
- for (const f5 of files) {
231258
- const name = shown(root, f5.file) || basename23(f5.file);
231259
- const current = existsSync41(f5.file) ? readFileSync33(f5.file, "utf8") : null;
231260
- if (current === f5.text) {
231261
- entry.fresh.push(name);
231262
- continue;
231263
- }
231264
- if (opts.check) {
231265
- entry.stale.push(name);
231266
- continue;
231267
- }
231268
- mkdirSync26(join46(f5.file, ".."), { recursive: true });
231269
- writeFileSync28(f5.file, f5.text);
231270
- entry.written.push(name);
231271
- }
231366
+ for (const f5 of files)
231367
+ place(f5, entry);
231272
231368
  report.plugins.push(entry);
231273
231369
  } catch (e2) {
231274
231370
  if (e2 instanceof ContractError)
@@ -231284,6 +231380,17 @@ ${e2.problems.map((p2) => ` ${p2}`).join(`
231284
231380
  throw e2;
231285
231381
  }
231286
231382
  }
231383
+ const isRepo = !existsSync41(join46(root, CONTRACT_FILE));
231384
+ if (isRepo && report.failures.length === 0 && manifests.some((m) => m.manifest.ios)) {
231385
+ try {
231386
+ place({ file: join46(root, PACKAGE_FILE), text: emitPackageSwift(manifests, repoSdkPath(root)) }, report.repo);
231387
+ } catch (e2) {
231388
+ if (e2 instanceof PackageError)
231389
+ report.failures.push(`${PACKAGE_FILE}: ${e2.message}`);
231390
+ else
231391
+ throw e2;
231392
+ }
231393
+ }
231287
231394
  return report;
231288
231395
  };
231289
231396
 
@@ -231294,7 +231401,7 @@ var gen = defineCommand({
231294
231401
  usage: "[path]",
231295
231402
  description: `The path is one plugin (a directory with a contract.d.ts) or a repo that keeps its plugins in plugins/<id>/; the current directory when omitted.
231296
231403
 
231297
- Writes sdk/<id>.gen.ts — the wrapper an app calls: the wire call by call, the class with the wire's methods as its own, and the public export when the plugin has no hand-written sdk/<id>.ts. Where the plugin has an ios/ folder, writes ios/<Name>.gen.swift — the contract's types, the protocol the plugin implements and the glue that reads a call off the wire. Where it has an android/ folder, writes the same as <Name>.gen.kt into the folder of the plugin's Kotlin package (android/ is laid out as a Gradle module: the package is the folder the path under android/src/main/java narrows down to). Where it has a web/ folder, writes web/<id>.gen.ts — the same for the web half, in a file that imports nothing; a web half that imports a LeCodes package is refused, because it would run on that host only. A contract the generator does not understand is an error with its line, and every problem of a file is reported at once.
231404
+ Writes sdk/<id>.gen.ts — the wrapper an app calls: the wire call by call, the class with the wire's methods as its own, and the public export when the plugin has no hand-written sdk/<id>.ts. Where the plugin has an ios/ folder, writes ios/<Name>.gen.swift — the contract's types, the protocol the plugin implements and the glue that reads a call off the wire. Where it has an android/ folder, writes the same as <Name>.gen.kt into the folder of the plugin's Kotlin package (android/ is laid out as a Gradle module: the package is the folder the path under android/src/main/java narrows down to). Where it has a web/ folder, writes web/<id>.gen.ts — the same for the web half, in a file that imports nothing; a web half that imports a LeCodes package is refused, because it would run on that host only. A repo of plugins also gets its Package.swift from the manifests: the iOS halves as one SwiftPM package, a target and a product per plugin, the SDK as a package on disk (LECODES_IOS_SDK_PATH, else the repo's package.json lecodes.iosSdkPath, else ../lecodes) — what an Xcode project links the halves as (a shell vendors the sources instead). A contract the generator does not understand is an error with its line, and every problem of a file is reported at once.
231298
231405
 
231299
231406
  Generated files are committed. Reading a contract needs TypeScript in the plugin's repo.`,
231300
231407
  flags: {
@@ -231313,9 +231420,18 @@ Generated files are committed. Reading a contract needs TypeScript in the plugin
231313
231420
  for (const f5 of p2.fresh)
231314
231421
  log(c.dim(` fresh ${f5}`));
231315
231422
  }
231423
+ if (report.repo.written.length + report.repo.stale.length + report.repo.fresh.length > 0) {
231424
+ info(`${c.bold("the repo")} ${c.dim("Package.swift from the manifests")}`);
231425
+ for (const f5 of report.repo.written)
231426
+ log(c.green(` written ${f5}`));
231427
+ for (const f5 of report.repo.stale)
231428
+ log(c.red(` stale ${f5}`));
231429
+ for (const f5 of report.repo.fresh)
231430
+ log(c.dim(` fresh ${f5}`));
231431
+ }
231316
231432
  for (const failure2 of report.failures)
231317
231433
  log(c.red(failure2));
231318
- const stale = report.plugins.reduce((n2, p2) => n2 + p2.stale.length, 0);
231434
+ const stale = report.plugins.reduce((n2, p2) => n2 + p2.stale.length, 0) + report.repo.stale.length;
231319
231435
  if (report.failures.length)
231320
231436
  throw new CliError(`${report.failures.length} contract${report.failures.length === 1 ? "" : "s"} did not generate.`);
231321
231437
  if (stale)
package/package.json CHANGED
@@ -1,22 +1,22 @@
1
1
  {
2
2
  "name": "lecodes-cli",
3
- "version": "2.2.8",
3
+ "version": "2.2.9",
4
4
  "dependencies": {
5
5
  "@letary/chisel": "^0.14.0",
6
6
  "jimp": "^1.6.1",
7
- "lecodes-sdk": "2.2.8"
7
+ "lecodes-sdk": "2.2.9"
8
8
  },
9
9
  "devDependencies": {
10
10
  "lecodes-design": "https://storage.yandexcloud.net/le-codes/releases/packages/lecodes-design/lecodes-design-0.11.0.tgz",
11
- "lecodes-headless": "2.2.8",
11
+ "lecodes-headless": "2.2.9",
12
12
  "qrcode-terminal": "^0.12.0",
13
13
  "lecodes-3d-editor": "https://storage.yandexcloud.net/le-codes/releases/packages/lecodes-3d-editor/lecodes-3d-editor-0.9.0.tgz",
14
14
  "lecodes-assets": "0.2.1",
15
15
  "lecodes-creator-nav": "0.19.0",
16
- "lecodes-gl-lite": "2.2.8",
17
- "lecodes-web-frame": "2.2.8",
18
- "lecodes-web-player": "2.2.8",
19
- "lecodes-web-shared": "2.2.8",
16
+ "lecodes-gl-lite": "2.2.9",
17
+ "lecodes-web-frame": "2.2.9",
18
+ "lecodes-web-player": "2.2.9",
19
+ "lecodes-web-shared": "2.2.9",
20
20
  "lecodes-web-lite": "2.0.2",
21
21
  "heic-decode": "^2.1.0",
22
22
  "marcidb-embedded": "^0.15.0",
@@ -24,7 +24,7 @@
24
24
  },
25
25
  "peerDependencies": {
26
26
  "lecodes-design": "^0.11.0",
27
- "lecodes-headless": "^2.2.8",
27
+ "lecodes-headless": "^2.2.9",
28
28
  "lecodes-3d-editor": "^0.9.0",
29
29
  "lecodes-assets": "^0.2.1",
30
30
  "heic-decode": "^2.1.0",