@_linked/cli 1.44.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +36 -2
  3. package/defaults/package/src/index.ts +0 -5
  4. package/defaults/package-ontology/src/index.ts +8 -0
  5. package/defaults/shape.ts +13 -10
  6. package/lib/esm/cli-methods.d.ts +10 -1
  7. package/lib/esm/cli-methods.d.ts.map +1 -1
  8. package/lib/esm/cli-methods.js +252 -97
  9. package/lib/esm/cli-methods.js.map +1 -1
  10. package/lib/esm/cli.js +60 -17
  11. package/lib/esm/cli.js.map +1 -1
  12. package/lib/esm/commands/localize.d.ts.map +1 -1
  13. package/lib/esm/commands/localize.js +2 -1
  14. package/lib/esm/commands/localize.js.map +1 -1
  15. package/lib/esm/localize/localize.d.ts.map +1 -1
  16. package/lib/esm/localize/localize.js +25 -3
  17. package/lib/esm/localize/localize.js.map +1 -1
  18. package/lib/esm/utils/createPackageLocation.d.ts +20 -5
  19. package/lib/esm/utils/createPackageLocation.d.ts.map +1 -1
  20. package/lib/esm/utils/createPackageLocation.js +9 -14
  21. package/lib/esm/utils/createPackageLocation.js.map +1 -1
  22. package/lib/esm/utils/packageBaseUri.d.ts +27 -0
  23. package/lib/esm/utils/packageBaseUri.d.ts.map +1 -0
  24. package/lib/esm/utils/packageBaseUri.js +91 -0
  25. package/lib/esm/utils/packageBaseUri.js.map +1 -0
  26. package/lib/esm/utils/packageKind.d.ts +49 -0
  27. package/lib/esm/utils/packageKind.d.ts.map +1 -0
  28. package/lib/esm/utils/packageKind.js +94 -0
  29. package/lib/esm/utils/packageKind.js.map +1 -0
  30. package/lib/esm/utils/relinkHooks.d.ts +19 -0
  31. package/lib/esm/utils/relinkHooks.d.ts.map +1 -0
  32. package/lib/esm/utils/relinkHooks.js +74 -0
  33. package/lib/esm/utils/relinkHooks.js.map +1 -0
  34. package/package.json +2 -2
  35. /package/defaults/{package → package-ontology}/src/data/example-ontology.json +0 -0
  36. /package/defaults/{package → package-ontology}/src/data/example-ontology.json.d.ts +0 -0
  37. /package/defaults/{package → package-ontology}/src/ontologies/example-ontology.register.ts +0 -0
  38. /package/defaults/{package → package-ontology}/src/ontologies/example-ontology.ts +0 -0
@@ -33,10 +33,38 @@ import ora from 'ora';
33
33
  import stagedGitFiles from 'staged-git-files';
34
34
  import { packagePublishesCjs } from './package-manifest.js';
35
35
  import { asNamespace, defaultOntologyNamespace } from './utils/ontologyNamespace.js';
36
+ import { decidePackageKind, ontologySlugFor, packageNameFor, scaffoldKinds, PACKAGE_TEMPLATE_DIRS, SHARED_TEMPLATE_FILES, } from './utils/packageKind.js';
37
+ import { resolvePackageBaseUri, withBaseUri } from './utils/packageBaseUri.js';
36
38
  let dirname__ = typeof __dirname !== 'undefined'
37
39
  ? __dirname
38
40
  : //@ts-ignore
39
41
  dirname(import.meta.url).replace('file:/', '');
42
+ /**
43
+ * A folder under this package's `defaults/`. The built module sits in `lib/esm/`
44
+ * and the source in `src/`, so the templates are two or one level up.
45
+ */
46
+ function defaultsDir(...parts) {
47
+ var _a;
48
+ const candidates = [
49
+ path.join(dirname__, '..', '..', 'defaults'),
50
+ path.join(dirname__, '..', 'defaults'),
51
+ ];
52
+ const root = (_a = candidates.find((dir) => fs.existsSync(dir))) !== null && _a !== void 0 ? _a : candidates[0];
53
+ return path.join(root, ...parts);
54
+ }
55
+ /**
56
+ * The commands that write a file importing `../package.js` need a `src/package.ts`
57
+ * to import. A new app root has none (it is a linkedApp, not a linkedPackage), so
58
+ * there the import would be broken: refuse instead. Only the file decides: a
59
+ * linkedApp that keeps its shapes at its root with its own `src/package.ts`, as
60
+ * create-now does, is served as before.
61
+ */
62
+ function assertInsidePackage(sourceFolder, command) {
63
+ if (fs.existsSync(path.join(sourceFolder, 'package.ts')))
64
+ return;
65
+ throw new CreatePackageError(`${command}: no src/package.ts here, so there is no package to add to. An app root is ` +
66
+ `not a package; run this inside a package (packages/<name>).`);
67
+ }
40
68
  /**
41
69
  * Dynamically import the app's backend storage configuration. Tries the
42
70
  * canonical `linked.backend.storage.{ts,js}` at app root first, then the
@@ -376,8 +404,12 @@ function setEnvVar(envText, key, value) {
376
404
  * - `.env.example` (committed defaults for this app) + `.env` (local): APP_NAME
377
405
  * drives the display name; APP_PREFIX names data files.
378
406
  * - `package.json`: `name` (hyphenated id) + `displayName` (human name).
379
- * - `src/package.ts`: the runtime `linkedPackage` id — shape URIs derive from it.
380
407
  * - pm2 process names + the VS Code launch name (cosmetic, but should match).
408
+ *
409
+ * Nothing under `src/` is touched: the app is a linkedApp, not a linked package,
410
+ * so its root registers no package and has no package id to stamp. Its shapes
411
+ * live in its packages (`packages/<name>-assets`), each with its own
412
+ * `src/package.ts`.
381
413
  */
382
414
  /**
383
415
  * Scaffolded apps are npm apps, so the new app must not also look like a yarn
@@ -396,7 +428,7 @@ export function stripYarnProjectFiles(targetFolder) {
396
428
  fs.removeSync(path.join(targetFolder, yarnLeftover));
397
429
  }
398
430
  }
399
- function applyAppIdentity(targetFolder, ids) {
431
+ export function applyAppIdentity(targetFolder, ids) {
400
432
  const { appName, appPrefix, hyphenName } = ids;
401
433
  // 1. .env.example (+ seed .env from it so the first `npm start` is correct).
402
434
  const envExample = path.join(targetFolder, '.env.example');
@@ -417,13 +449,7 @@ function applyAppIdentity(targetFolder, ids) {
417
449
  pkg.displayName = appName;
418
450
  fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
419
451
  }
420
- // 3. src/package.ts — the runtime linkedPackage id.
421
- const packageTs = path.join(targetFolder, 'src', 'package.ts');
422
- if (fs.existsSync(packageTs)) {
423
- const src = fs.readFileSync(packageTs, 'utf8');
424
- fs.writeFileSync(packageTs, src.replace(/linkedPackage\(\s*['"][^'"]*['"]\s*\)/, `linkedPackage('${hyphenName}')`));
425
- }
426
- // 4. pm2 process names + VS Code launch name (template hardcodes 'app').
452
+ // 3. pm2 process names + VS Code launch name (template hardcodes 'app').
427
453
  const renames = [
428
454
  ['pm2.config.js', /name:\s*'app'/, `name: '${hyphenName}'`],
429
455
  ['pm2-staging.config.js', /name:\s*'app-staging'/, `name: '${hyphenName}-staging'`],
@@ -1043,6 +1069,7 @@ export const createOntology = (prefix_1, uriBase_1, ...args_1) => __awaiter(void
1043
1069
  return;
1044
1070
  }
1045
1071
  let sourceFolder = getSourceFolder(basePath);
1072
+ assertInsidePackage(sourceFolder, 'create-ontology');
1046
1073
  let targetFolder = ensureFolderExists(sourceFolder, 'ontologies');
1047
1074
  if (!uriBase) {
1048
1075
  uriBase = defaultOntologyNamespace(prefix);
@@ -1053,16 +1080,16 @@ export const createOntology = (prefix_1, uriBase_1, ...args_1) => __awaiter(void
1053
1080
  log("Creating files for ontology '" + prefix + "'");
1054
1081
  let targetFile = path.join(targetFolder, hyphenName + '.ts');
1055
1082
  let targetRegisterFile = path.join(targetFolder, hyphenName + '.register.ts');
1056
- fs.copySync(path.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'ontologies', 'example-ontology.ts'), targetFile);
1083
+ fs.copySync(defaultsDir('package-ontology', 'src', 'ontologies', 'example-ontology.ts'), targetFile);
1057
1084
  // The registration sibling. It has to be a separate module: registration needs the
1058
1085
  // ontology module's whole export namespace, and a module cannot import itself once a
1059
1086
  // bundler is involved -- Rollup elides the self-reference and the app dies at boot.
1060
- fs.copySync(path.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'ontologies', 'example-ontology.register.ts'), targetRegisterFile);
1087
+ fs.copySync(defaultsDir('package-ontology', 'src', 'ontologies', 'example-ontology.register.ts'), targetRegisterFile);
1061
1088
  //copy data files
1062
1089
  let targetDataFile = path.join(targetFolder, '..', 'data', hyphenName + '.json');
1063
1090
  let targetDataFile2 = path.join(targetFolder, '..', 'data', hyphenName + '.json.d.ts');
1064
- fs.copySync(path.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'data', 'example-ontology.json'), targetDataFile);
1065
- fs.copySync(path.join(dirname__, '..', '..', 'defaults', 'package', 'src', 'data', 'example-ontology.json.d.ts'), targetDataFile2);
1091
+ fs.copySync(defaultsDir('package-ontology', 'src', 'data', 'example-ontology.json'), targetDataFile);
1092
+ fs.copySync(defaultsDir('package-ontology', 'src', 'data', 'example-ontology.json.d.ts'), targetDataFile2);
1066
1093
  yield replaceVariablesInFiles(targetFile, targetRegisterFile, targetDataFile, targetDataFile2);
1067
1094
  log(`Prepared a new ontology data files in ${chalk.magenta(targetDataFile.replace(basePath, ''))}`, `And an ontology accessor file in ${chalk.magenta(targetFile.replace(basePath, ''))}`);
1068
1095
  //if this is not a lincd app (but a lincd package instead)
@@ -1261,12 +1288,13 @@ export const getScriptDir = () => {
1261
1288
  };
1262
1289
  export const createShape = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, basePath = process.cwd()) {
1263
1290
  let sourceFolder = getSourceFolder(basePath);
1291
+ assertInsidePackage(sourceFolder, 'create-shape');
1264
1292
  let targetFolder = ensureFolderExists(sourceFolder, 'shapes');
1265
1293
  let { hyphenName, camelCaseName, underscoreName } = setNameVariables(name);
1266
1294
  //copy default shape file
1267
1295
  // log("Creating files for shape '" + name + "'");
1268
1296
  let targetFile = path.join(targetFolder, hyphenName + '.ts');
1269
- fs.copySync(path.join(getScriptDir(), '..', '..', 'defaults', 'shape.ts'), targetFile);
1297
+ fs.copySync(defaultsDir('shape.ts'), targetFile);
1270
1298
  //replace variables in some of the copied files
1271
1299
  yield replaceVariablesInFiles(targetFile);
1272
1300
  log(`Created a new shape class template in ${chalk.magenta(targetFile.replace(basePath, ''))}`);
@@ -1279,14 +1307,15 @@ export const createShape = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...
1279
1307
  log(`Registered the shape in ${chalk.magenta(barrelPath.replace(basePath, ''))}`);
1280
1308
  });
1281
1309
  export const createSetComponent = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, basePath = process.cwd()) {
1310
+ assertInsidePackage(path.join(basePath, 'src'), 'create-set-component');
1282
1311
  let targetFolder = ensureFolderExists(basePath, 'src', 'components');
1283
1312
  let { hyphenName, camelCaseName, underscoreName } = setNameVariables(name);
1284
1313
  //copy default shape file
1285
1314
  log("Creating files for set component '" + name + "'");
1286
1315
  let targetFile = path.join(targetFolder, hyphenName + '.tsx');
1287
- fs.copySync(path.join(getScriptDir(), '..', '..', 'defaults', 'set-component.tsx'), targetFile);
1316
+ fs.copySync(defaultsDir('set-component.tsx'), targetFile);
1288
1317
  let targetFile2 = path.join(targetFolder, hyphenName + '.scss');
1289
- fs.copySync(path.join(getScriptDir(), '..', '..', 'defaults', 'component.scss'), targetFile2);
1318
+ fs.copySync(defaultsDir('component.scss'), targetFile2);
1290
1319
  //replace variables in some of the copied files
1291
1320
  yield replaceVariablesInFiles(targetFile, targetFile2);
1292
1321
  let indexPath = addLineToIndex(`import './components/${hyphenName}.js';`, 'components');
@@ -1294,14 +1323,15 @@ export const createSetComponent = (name_1, ...args_1) => __awaiter(void 0, [name
1294
1323
  });
1295
1324
  export const createComponent = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, basePath = process.cwd()) {
1296
1325
  let sourceFolder = getSourceFolder(basePath);
1326
+ assertInsidePackage(sourceFolder, 'create-component');
1297
1327
  let targetFolder = ensureFolderExists(sourceFolder, 'components');
1298
1328
  let { hyphenName, camelCaseName, underscoreName } = setNameVariables(name);
1299
1329
  //copy default shape file
1300
1330
  log("Creating files for component '" + name + "'");
1301
1331
  let targetFile = path.join(targetFolder, hyphenName + '.tsx');
1302
- fs.copySync(path.join(getScriptDir(), '..', 'defaults', 'component.tsx'), targetFile);
1332
+ fs.copySync(defaultsDir('component.tsx'), targetFile);
1303
1333
  let targetFile2 = path.join(targetFolder, hyphenName + '.scss');
1304
- fs.copySync(path.join(getScriptDir(), '..', 'defaults', 'component.scss'), targetFile2);
1334
+ fs.copySync(defaultsDir('component.scss'), targetFile2);
1305
1335
  //replace variables in some of the copied files
1306
1336
  yield replaceVariablesInFiles(targetFile, targetFile2);
1307
1337
  log(`Created a new component template in ${chalk.magenta(targetFile.replace(basePath, ''))}`, `Created component stylesheet template in ${chalk.magenta(targetFile2.replace(basePath, ''))}`);
@@ -1839,95 +1869,216 @@ export const createPackage = (name_1, uriBase_1, ...args_1) => __awaiter(void 0,
1839
1869
  console.warn('Please provide a name as the first argument');
1840
1870
  return;
1841
1871
  }
1842
- const appRoot = findLinkedAppRoot(basePath);
1843
- const decided = decideCreatePackageTarget({
1844
- appRoot,
1845
- options,
1846
- isTTY: !!(process.stdin.isTTY && process.stdout.isTTY),
1872
+ const isTTY = !!(process.stdin.isTTY && process.stdout.isTTY);
1873
+ // What, then where. Both are settled before anything is written, so a
1874
+ // refusal leaves nothing behind and `both` asks each question once.
1875
+ const kindDecided = decidePackageKind({
1876
+ kind: options.kind,
1877
+ remote: options.remote,
1878
+ isTTY,
1847
1879
  });
1880
+ if (kindDecided.kind === 'refuse')
1881
+ throw new CreatePackageError(kindDecided.message);
1882
+ const packageKind = kindDecided.kind === 'ask' ? yield askPackageKind(name) : kindDecided.packageKind;
1883
+ const appRoot = findLinkedAppRoot(basePath);
1884
+ const decided = decideCreatePackageTarget({ appRoot, options, isTTY });
1848
1885
  if (decided.kind === 'refuse')
1849
1886
  throw new CreatePackageError(decided.message);
1887
+ // The root its IRIs are minted under: a malformed one is refused here, before
1888
+ // anything is written or asked.
1889
+ let root;
1890
+ try {
1891
+ root = resolvePackageBaseUri({ flag: options.baseUri, appRoot });
1892
+ }
1893
+ catch (e) {
1894
+ throw new CreatePackageError(e.message);
1895
+ }
1850
1896
  const decision = decided.kind === 'ask' ? yield askPackageLocation(name) : decided;
1851
- //let's remove scope for variable names
1852
- const cleanPackageName = bareName(name);
1853
- let targetFolder;
1854
- if (decision.kind === 'outside') {
1855
- //if ran with npx, basePath will be the root directory of the repository, even if we're executing from a sub folder (the root directory is where node_modules lives and package.json with workspaces)
1856
- //so we manually find a packages folder, if it exists we go into that.
1857
- if (fs.existsSync(path.join(basePath, 'packages'))) {
1858
- basePath = path.join(basePath, 'packages');
1897
+ const packages = scaffoldKinds(packageKind).map((kind) => ({
1898
+ kind,
1899
+ name: packageNameFor(name, kind),
1900
+ }));
1901
+ // Nothing is written until every target is free.
1902
+ const targets = yield Promise.all(packages.map((_a) => __awaiter(void 0, [_a], void 0, function* ({ name: packageName }) {
1903
+ const targetFolder = yield packageTargetFolder(packageName, basePath, appRoot, decision);
1904
+ if (fs.existsSync(targetFolder)) {
1905
+ throw new CreatePackageError(`${targetFolder} already exists. Refusing to write a new package over it.`);
1906
+ }
1907
+ return targetFolder;
1908
+ })));
1909
+ // linked.cm is the normal root for an open-source package, so its absence is
1910
+ // information, not a warning.
1911
+ log(root
1912
+ ? `Base URI ${root.baseUri} (from ${root.source}): shapes mint ${root.baseUri}shape/<package>/<Name>`
1913
+ : `Shapes and terms in ${packages.map((p) => p.name).join(' and ')} mint under https://linked.cm/. ` +
1914
+ `They resolve once the package is published (npx linked publish, coming soon).`);
1915
+ for (const [i, { kind, name: packageName }] of packages.entries()) {
1916
+ const targetFolder = targets[i];
1917
+ yield scaffoldPackage(packageName, kind, targetFolder, uriBase, root === null || root === void 0 ? void 0 : root.baseUri);
1918
+ if (kind === 'assets' && packageKind === 'both') {
1919
+ // The pair is one unit: the asset package's shapes use the ontology
1920
+ // created with it. `ontology` comes first in `scaffoldKinds`, so its
1921
+ // package.json is already written.
1922
+ const ontIndex = packages.findIndex((p) => p.kind === 'ontology');
1923
+ dependOnOntologyPackage(targetFolder, packages[ontIndex].name, targets[ontIndex], decision.kind === 'resolved' && decision.location === 'packages');
1924
+ }
1925
+ const skipped = () => log(`Prepared a new linked package in ${chalk.magenta(targetFolder)} (install skipped)`);
1926
+ if (decision.kind === 'outside') {
1927
+ if (options.skipInstall)
1928
+ skipped();
1929
+ else
1930
+ yield installStandalonePackage(targetFolder);
1931
+ }
1932
+ else if (decision.location === 'packages') {
1933
+ // The app's package.json is wired either way: that is files, not install.
1934
+ yield installWorkspacePackage(packageName, targetFolder, appRoot, options.skipInstall);
1935
+ }
1936
+ else if (options.skipInstall) {
1937
+ skipped();
1859
1938
  }
1860
- //for lincd.org currently packages are stored in the modules folder
1861
- else if (fs.existsSync(path.join(basePath, 'modules'))) {
1862
- basePath = path.join(basePath, 'modules');
1939
+ else {
1940
+ yield installOwnRepoPackage(packageName, targetFolder, appRoot, decision);
1863
1941
  }
1864
- targetFolder = path.join(basePath, cleanPackageName);
1865
1942
  }
1866
- else if (decision.location === 'packages') {
1867
- targetFolder = path.join(appRoot, 'packages', cleanPackageName);
1943
+ });
1944
+ /**
1945
+ * Declare the ontology package as a regular dependency of the asset package,
1946
+ * at `^` its version — the same entry Create Now's project scaffold writes.
1947
+ *
1948
+ * Only where npm workspaces link the two (`--location packages`). Anywhere
1949
+ * else the `-ont` package is not published yet, so `npm install` in the asset
1950
+ * package would fail with E404: the entry is left out and one line says how to
1951
+ * add it once the ontology package is published.
1952
+ */
1953
+ function dependOnOntologyPackage(assetsFolder, ontName, ontFolder, linkedByWorkspace) {
1954
+ if (!linkedByWorkspace) {
1955
+ log(`The asset package does not depend on ${ontName} yet: once ${ontName} is published, ` +
1956
+ `run npm install ${ontName} in ${assetsFolder}`);
1957
+ return;
1868
1958
  }
1869
- else {
1959
+ const { version } = fs.readJsonSync(path.join(ontFolder, 'package.json'));
1960
+ const pkgPath = path.join(assetsFolder, 'package.json');
1961
+ const pkg = fs.readJsonSync(pkgPath);
1962
+ pkg.dependencies = Object.assign(Object.assign({}, pkg.dependencies), { [ontName]: `^${version}` });
1963
+ fs.writeJsonSync(pkgPath, pkg, { spaces: 2 });
1964
+ }
1965
+ /** Where a package goes, given where create-package was told to put it. */
1966
+ function packageTargetFolder(name, basePath, appRoot, decision) {
1967
+ return __awaiter(this, void 0, void 0, function* () {
1968
+ //let's remove scope for folder names
1969
+ const cleanPackageName = bareName(name);
1970
+ if (decision.kind === 'outside') {
1971
+ //if ran with npx, basePath will be the root directory of the repository, even if we're executing from a sub folder (the root directory is where node_modules lives and package.json with workspaces)
1972
+ //so we manually find a packages folder, if it exists we go into that.
1973
+ if (fs.existsSync(path.join(basePath, 'packages'))) {
1974
+ basePath = path.join(basePath, 'packages');
1975
+ }
1976
+ //for lincd.org currently packages are stored in the modules folder
1977
+ else if (fs.existsSync(path.join(basePath, 'modules'))) {
1978
+ basePath = path.join(basePath, 'modules');
1979
+ }
1980
+ return path.join(basePath, cleanPackageName);
1981
+ }
1982
+ if (decision.kind === 'resolved' && decision.location === 'packages') {
1983
+ return path.join(appRoot, 'packages', cleanPackageName);
1984
+ }
1870
1985
  // localize's own naming, so `linked localize` and this command can never
1871
1986
  // disagree about where a package lives.
1872
1987
  const { checkoutNameFor, DEFAULT_DIR } = yield import('./localize/index.js');
1873
- targetFolder = path.join(appRoot, DEFAULT_DIR, checkoutNameFor(name));
1874
- }
1875
- if (fs.existsSync(targetFolder)) {
1876
- throw new CreatePackageError(`${targetFolder} already exists. Refusing to write a new package over it.`);
1877
- }
1878
- if (!uriBase) {
1879
- uriBase = defaultOntologyNamespace(name);
1880
- }
1881
- setVariable('uri_base', asNamespace(uriBase));
1882
- //save the full scoped package name under ${package_name}
1883
- setVariable('package_name', name);
1884
- //extra variable for clarity (will be same as 'name')
1885
- setVariable('output_file_name', name);
1886
- const { hyphenName } = setNameVariables(cleanPackageName);
1887
- log("Creating new linked package '" + name + "'");
1888
- fs.mkdirSync(targetFolder, { recursive: true });
1889
- fs.copySync(path.join(getScriptDir(), '..', '..', 'defaults', 'package'), targetFolder);
1890
- renameShippedDotfiles(targetFolder);
1891
- //replace variables in some of the copied files
1892
- yield Promise.all([
1893
- 'src/index.ts',
1894
- 'package.json',
1895
- 'src/package.ts',
1896
- 'src/ontologies/example-ontology.ts',
1897
- 'src/ontologies/example-ontology.register.ts',
1898
- 'src/data/example-ontology.json',
1899
- ]
1900
- .map((f) => path.join(targetFolder, f))
1901
- .map((file) => {
1902
- return replaceVariablesInFile(file);
1903
- }));
1904
- //rename these to a file name similar to the pkg name
1905
- [
1906
- 'src/ontologies/example-ontology.ts',
1907
- // The register sibling is what index.ts imports; without it here the scaffold keeps a
1908
- // literal `example-ontology.register.ts` full of unsubstituted `${...}` placeholders and
1909
- // nothing ever calls linkedOntology().
1910
- 'src/ontologies/example-ontology.register.ts',
1911
- 'src/data/example-ontology.json',
1912
- 'src/data/example-ontology.json.d.ts',
1913
- ].forEach((f) => {
1914
- let parts = f.split('/');
1915
- let newParts = [...parts];
1916
- let [name, ...extensions] = newParts.pop().split('.');
1917
- let newName = hyphenName + '.' + extensions.join('.');
1918
- console.log('rename ', path.join(targetFolder, f), path.join(targetFolder, ...newParts, newName));
1919
- fs.renameSync(path.join(targetFolder, f), path.join(targetFolder, ...newParts, newName));
1988
+ return path.join(appRoot, DEFAULT_DIR, checkoutNameFor(name));
1920
1989
  });
1921
- if (decision.kind === 'outside') {
1922
- yield installStandalonePackage(targetFolder);
1923
- }
1924
- else if (decision.location === 'packages') {
1925
- yield installWorkspacePackage(name, targetFolder, appRoot);
1926
- }
1927
- else {
1928
- yield installOwnRepoPackage(name, targetFolder, appRoot, decision);
1929
- }
1930
- });
1990
+ }
1991
+ /**
1992
+ * Write one package of a kind. Every kind gets the shared files of
1993
+ * `defaults/package` (manifest, tsconfigs, dotfiles, `src/package.ts`); an asset
1994
+ * package gets the rest of that folder, an ontology package gets
1995
+ * `defaults/package-ontology` instead, with the example ontology named after
1996
+ * its ontology slug.
1997
+ */
1998
+ function scaffoldPackage(name, kind, targetFolder, uriBase, baseUri) {
1999
+ return __awaiter(this, void 0, void 0, function* () {
2000
+ // An ontology package `foo-ont` holds the ontology `foo`: that slug names its
2001
+ // files and its prefix, and its terms mint `{root}ont/foo/{Term}`.
2002
+ const ontologySlug = kind === 'ontology' ? ontologySlugFor(name) : undefined;
2003
+ if (!uriBase) {
2004
+ uriBase = baseUri
2005
+ ? `${baseUri}ont/${ontologySlug !== null && ontologySlug !== void 0 ? ontologySlug : bareName(name)}/`
2006
+ : defaultOntologyNamespace(ontologySlug !== null && ontologySlug !== void 0 ? ontologySlug : name);
2007
+ }
2008
+ setVariable('uri_base', asNamespace(uriBase));
2009
+ //save the full scoped package name under ${package_name}
2010
+ setVariable('package_name', name);
2011
+ //extra variable for clarity (will be same as 'name')
2012
+ setVariable('output_file_name', name);
2013
+ const { hyphenName } = setNameVariables(ontologySlug !== null && ontologySlug !== void 0 ? ontologySlug : bareName(name));
2014
+ log(`Creating new linked ${kind} package '${name}'`);
2015
+ fs.mkdirSync(targetFolder, { recursive: true });
2016
+ const [shared, ...variants] = PACKAGE_TEMPLATE_DIRS[kind];
2017
+ if (variants.length === 0) {
2018
+ fs.copySync(defaultsDir(shared), targetFolder);
2019
+ }
2020
+ else {
2021
+ for (const file of SHARED_TEMPLATE_FILES) {
2022
+ fs.copySync(defaultsDir(shared, file), path.join(targetFolder, file));
2023
+ }
2024
+ for (const variant of variants) {
2025
+ fs.copySync(defaultsDir(variant), targetFolder);
2026
+ }
2027
+ }
2028
+ renameShippedDotfiles(targetFolder);
2029
+ //replace variables in some of the copied files
2030
+ yield Promise.all(['src/index.ts', 'package.json', 'src/package.ts']
2031
+ .concat(kind === 'ontology'
2032
+ ? [
2033
+ 'src/ontologies/example-ontology.ts',
2034
+ 'src/ontologies/example-ontology.register.ts',
2035
+ 'src/data/example-ontology.json',
2036
+ ]
2037
+ : [])
2038
+ .map((f) => path.join(targetFolder, f))
2039
+ .map((file) => replaceVariablesInFile(file)));
2040
+ if (baseUri) {
2041
+ const packageTs = path.join(targetFolder, 'src', 'package.ts');
2042
+ fs.writeFileSync(packageTs, withBaseUri(fs.readFileSync(packageTs, 'utf8'), baseUri));
2043
+ }
2044
+ if (kind !== 'ontology')
2045
+ return;
2046
+ //rename these to a file name similar to the ontology slug
2047
+ [
2048
+ 'src/ontologies/example-ontology.ts',
2049
+ // The register sibling is what index.ts imports; without it here the scaffold keeps a
2050
+ // literal `example-ontology.register.ts` full of unsubstituted `${...}` placeholders and
2051
+ // nothing ever calls linkedOntology().
2052
+ 'src/ontologies/example-ontology.register.ts',
2053
+ 'src/data/example-ontology.json',
2054
+ 'src/data/example-ontology.json.d.ts',
2055
+ ].forEach((f) => {
2056
+ let parts = f.split('/');
2057
+ let newParts = [...parts];
2058
+ let [, ...extensions] = newParts.pop().split('.');
2059
+ let newName = hyphenName + '.' + extensions.join('.');
2060
+ fs.renameSync(path.join(targetFolder, f), path.join(targetFolder, ...newParts, newName));
2061
+ });
2062
+ });
2063
+ }
2064
+ /**
2065
+ * Ask what kind of package to make — only ever on a terminal, and only when
2066
+ * `--kind` did not say.
2067
+ */
2068
+ function askPackageKind(name) {
2069
+ return __awaiter(this, void 0, void 0, function* () {
2070
+ console.log(`\nWhat kind of package is ${chalk.magenta(name)}?\n` +
2071
+ ` 1) ontology one ontology, no shapes or components (${packageNameFor(name, 'ontology')})\n` +
2072
+ ` 2) assets shapes, components and a backend (${packageNameFor(name, 'assets')})\n` +
2073
+ ` 3) both the two packages above\n`);
2074
+ const kinds = ['ontology', 'assets', 'both'];
2075
+ let answer = '';
2076
+ while (!['1', '2', '3'].includes(answer)) {
2077
+ answer = yield promptUser('Choose 1, 2 or 3: ');
2078
+ }
2079
+ return kinds[Number(answer) - 1];
2080
+ });
2081
+ }
1931
2082
  /**
1932
2083
  * Ask where a new package goes — only ever on a terminal, and only when no
1933
2084
  * flag said so already.
@@ -2004,8 +2155,8 @@ function installStandalonePackage(targetFolder) {
2004
2155
  * workspace member by name, and `build-all` builds what the app depends on —
2005
2156
  * and the install runs at the app root, where the workspace is.
2006
2157
  */
2007
- function installWorkspacePackage(name, targetFolder, appRoot) {
2008
- return __awaiter(this, void 0, void 0, function* () {
2158
+ function installWorkspacePackage(name_1, targetFolder_1, appRoot_1) {
2159
+ return __awaiter(this, arguments, void 0, function* (name, targetFolder, appRoot, skipInstall = false) {
2009
2160
  const appPkgPath = path.join(appRoot, 'package.json');
2010
2161
  const appPkg = fs.readJsonSync(appPkgPath);
2011
2162
  const workspaces = ensureWorkspaceGlob(appPkg);
@@ -2016,6 +2167,10 @@ function installWorkspacePackage(name, targetFolder, appRoot) {
2016
2167
  fs.writeJsonSync(appPkgPath, appPkg, { spaces: 2 });
2017
2168
  log(`Added ${name}@^${version} to ${path.relative(process.cwd(), appPkgPath) || 'package.json'}` +
2018
2169
  (workspaces.changed ? ' and packages/* to its workspaces' : ''));
2170
+ if (skipInstall) {
2171
+ log(`Prepared a new linked package in ${chalk.magenta(targetFolder)} (install skipped)`);
2172
+ return;
2173
+ }
2019
2174
  const setup = yield packageSetupFor(appRoot);
2020
2175
  yield installThenBuild(setup, appRoot, targetFolder, `The app's package.json already declares ${name}; run the install again at the app root once it is fixed.`);
2021
2176
  log(`Prepared a new linked package in ${chalk.magenta(targetFolder)}, part of this app's repository`, `Run ${chalk.blueBright(runScriptCommand(setup.packageManager, 'start'))} in it to continuously rebuild on file changes`);