@_linked/cli 1.11.1 → 1.13.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.
- package/CHANGELOG.md +84 -0
- package/README.md +48 -0
- package/defaults/app-react-native/README.md +56 -0
- package/defaults/app-react-native/apps/mobile/App.tsx +26 -0
- package/defaults/app-react-native/apps/mobile/__tests__/linkedDefaults.test.tsx +65 -0
- package/defaults/app-react-native/apps/mobile/__tests__/shapes.test.ts +27 -0
- package/defaults/app-react-native/apps/mobile/app.json +14 -0
- package/defaults/app-react-native/apps/mobile/gitignore.template +41 -0
- package/defaults/app-react-native/apps/mobile/index.ts +8 -0
- package/defaults/app-react-native/apps/mobile/metro.config.js +17 -0
- package/defaults/app-react-native/apps/mobile/package.json +41 -0
- package/defaults/app-react-native/apps/mobile/src/shell/linkedDefaults.tsx +10 -0
- package/defaults/app-react-native/apps/mobile/tsconfig.json +8 -0
- package/defaults/app-react-native/gitignore.template +6 -0
- package/defaults/app-react-native/package.json +14 -0
- package/defaults/app-react-native/packages/app-shapes/package.json +10 -0
- package/defaults/app-react-native/packages/app-shapes/src/index.ts +2 -0
- package/defaults/app-react-native/packages/app-shapes/src/package.ts +10 -0
- package/defaults/app-react-native/packages/app-shapes/src/shapes/Example.ts +17 -0
- package/defaults/app-react-native/packages/app-shapes/tsconfig.json +12 -0
- package/defaults/app-react-native/services/api/README.md +4 -0
- package/defaults/app-react-native/services/api/package.json +5 -0
- package/defaults/package/npmignore.template +6 -0
- package/defaults/package/src/backend.ts +5 -0
- package/defaults/package/src/data/example-ontology.json +10 -0
- package/defaults/package/src/data/example-ontology.json.d.ts +1 -0
- package/defaults/package/src/index.ts +8 -0
- package/defaults/package/src/ontologies/example-ontology.ts +42 -0
- package/defaults/package/src/package.ts +16 -0
- package/defaults/package/src/shapes/index.ts +5 -0
- package/defaults/package/src/types.ts +4 -0
- package/defaults/package/tsconfig.json +17 -0
- package/defaults/setup-publish/dual-branch/github/workflows/publish.yml +29 -15
- package/lib/esm/cli-methods.d.ts +39 -0
- package/lib/esm/cli-methods.d.ts.map +1 -1
- package/lib/esm/cli-methods.js +303 -60
- package/lib/esm/cli-methods.js.map +1 -1
- package/lib/esm/cli.d.ts.map +1 -1
- package/lib/esm/cli.js +11 -2
- package/lib/esm/cli.js.map +1 -1
- package/lib/esm/commands/setup-publish.js +23 -2
- package/lib/esm/commands/setup-publish.js.map +1 -1
- package/lib/esm/commands/start.d.ts +33 -0
- package/lib/esm/commands/start.d.ts.map +1 -1
- package/lib/esm/commands/start.js +90 -48
- package/lib/esm/commands/start.js.map +1 -1
- package/lib/esm/interfaces.d.ts +7 -0
- package/lib/esm/interfaces.d.ts.map +1 -1
- package/lib/esm/utils/esmSpecifiers.d.ts +3 -0
- package/lib/esm/utils/esmSpecifiers.d.ts.map +1 -0
- package/lib/esm/utils/esmSpecifiers.js +95 -0
- package/lib/esm/utils/esmSpecifiers.js.map +1 -0
- package/lib/esm/utils/packageSetup.d.ts +19 -0
- package/lib/esm/utils/packageSetup.d.ts.map +1 -0
- package/lib/esm/utils/packageSetup.js +23 -0
- package/lib/esm/utils/packageSetup.js.map +1 -0
- package/lib/esm/utils/shippedDotfiles.d.ts +2 -0
- package/lib/esm/utils/shippedDotfiles.d.ts.map +1 -0
- package/lib/esm/utils/shippedDotfiles.js +21 -0
- package/lib/esm/utils/shippedDotfiles.js.map +1 -0
- package/lib/esm/vite-config.d.ts +56 -0
- package/lib/esm/vite-config.d.ts.map +1 -1
- package/lib/esm/vite-config.js +185 -34
- package/lib/esm/vite-config.js.map +1 -1
- package/package.json +9 -1
- package/.changeset/README.md +0 -20
- package/.changeset/config.json +0 -14
- package/.github/workflows/changeset-check.yml +0 -44
- package/.github/workflows/ci.yml +0 -51
- package/.github/workflows/publish.yml +0 -77
- package/.prettierignore +0 -4
- package/.prettierrc.json +0 -24
- package/babel.config.cjs +0 -11
- package/docs/architecture/vite-runtime-config.md +0 -57
- package/jest.config.cjs +0 -33
- package/lib-template/cjs/package.json +0 -3
- package/lib-template/esm/package.json +0 -3
- package/test-results/.last-run.json +0 -6
- package/test-results/create-app-Person-fixture-add-/342/206/222-edit-/342/206/222-delete-round-trip/error-context.md +0 -16
- package/test-results/create-app-Person-fixture-add-/342/206/222-edit-/342/206/222-delete-round-trip/trace.zip +0 -0
- package/tests/e2e/create-app.spec.ts +0 -157
- package/tests/unit/safeYarn.test.ts +0 -55
- package/tsconfig-cjs.json +0 -10
- package/tsconfig-esm.json +0 -10
package/lib/esm/cli-methods.js
CHANGED
|
@@ -15,6 +15,9 @@ import fs from 'fs-extra';
|
|
|
15
15
|
import path, { dirname } from 'path';
|
|
16
16
|
import { createInterface } from 'readline';
|
|
17
17
|
import { debugInfo, execp, execPromise, getFileImports, getFiles, getLastCommitTime, getPackageJSON, isImportOutsideOfPackage, isImportWithMissingExtension, isInvalidLINCDImport, needsRebuilding, } from './utils.js';
|
|
18
|
+
import { renameShippedDotfiles } from './utils/shippedDotfiles.js';
|
|
19
|
+
import { planPackageSetup } from './utils/packageSetup.js';
|
|
20
|
+
import { rewriteExtensionlessImports } from './utils/esmSpecifiers.js';
|
|
18
21
|
import { spawn as spawnChild } from 'child_process';
|
|
19
22
|
import { findNearestPackageJson } from 'find-nearest-package-json';
|
|
20
23
|
import { statSync } from 'fs';
|
|
@@ -60,6 +63,14 @@ function promptUser(question) {
|
|
|
60
63
|
});
|
|
61
64
|
}
|
|
62
65
|
export const createApp = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, basePath = process.cwd(), options = {}) {
|
|
66
|
+
// Reject unknown templates before prompting or writing anything.
|
|
67
|
+
const template = options.template;
|
|
68
|
+
if (template !== undefined &&
|
|
69
|
+
template !== 'web' &&
|
|
70
|
+
template !== 'react-native') {
|
|
71
|
+
console.warn(chalk.red(`Unknown template "${template}". Use "web" or "react-native".`));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
63
74
|
// If no name provided, prompt for folder name first
|
|
64
75
|
if (!name) {
|
|
65
76
|
console.log(chalk.blue('\n📁 Folder name for your app:\n'));
|
|
@@ -102,6 +113,11 @@ export const createApp = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...ar
|
|
|
102
113
|
setVariable('app_prefix', appPrefix);
|
|
103
114
|
setVariable('app_domain', appDomain);
|
|
104
115
|
let targetFolder = path.join(basePath, hyphenName);
|
|
116
|
+
if (template === 'react-native') {
|
|
117
|
+
// Called through reactNativeInternals so tests can stub the scaffold step.
|
|
118
|
+
yield reactNativeInternals.scaffoldReactNativeApp(targetFolder, { appName, appPrefix, appDomain, hyphenName }, { skipInstall: options.skipInstall });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
105
121
|
if (!fs.existsSync(targetFolder)) {
|
|
106
122
|
fs.mkdirSync(targetFolder);
|
|
107
123
|
}
|
|
@@ -194,6 +210,155 @@ export const createApp = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...ar
|
|
|
194
210
|
const startCommand = pm === 'yarn' ? 'yarn start' : 'npm start';
|
|
195
211
|
log(`Your Linked app is ready at ${chalk.blueBright(targetFolder)}`, `\nStorage: linked.backend.storage.ts wires aliases to stores; linked.backend.datasets.json holds endpoints.`, `Defaults to Fuseki at ${chalk.cyan('http://localhost:3030')} (auto-creates the dataset on first boot).`, `Make sure Fuseki is running, e.g.:`, ` ${chalk.blueBright('docker run -d --rm -p 3030:3030 --name fuseki stain/jena-fuseki')}`, `Edit ${chalk.cyan('linked.backend.datasets.json')} to change endpoints or credentials.`, `Mirror file for the frontend: ${chalk.cyan('src/linked.frontend.storage.ts')} + ${chalk.cyan('src/linked.frontend.datasets.json')}.`, `\nTo start:`, ` ${chalk.blueBright(`cd ${hyphenName} && ${startCommand}`)}`);
|
|
196
212
|
});
|
|
213
|
+
/**
|
|
214
|
+
* iOS bundle identifier from the app domain and prefix:
|
|
215
|
+
* ('formaestudios.com', 'formae') -> 'com.formaestudios.formae'.
|
|
216
|
+
*/
|
|
217
|
+
export function reactNativeBundleId(appDomain, appPrefix) {
|
|
218
|
+
const host = appDomain
|
|
219
|
+
.trim()
|
|
220
|
+
.toLowerCase()
|
|
221
|
+
.replace(/^[a-z][a-z0-9+.-]*:\/\//, '')
|
|
222
|
+
.split(/[/?#]/)[0]
|
|
223
|
+
.replace(/:\d*$/, '');
|
|
224
|
+
const hostLabels = host.split('.').filter(Boolean);
|
|
225
|
+
// A bare host such as `localhost` gets a `com` top level: com.localhost.<prefix>.
|
|
226
|
+
if (hostLabels.length === 1)
|
|
227
|
+
hostLabels.push('com');
|
|
228
|
+
return [...hostLabels.reverse(), appPrefix.toLowerCase()]
|
|
229
|
+
.map((label) => label.replace(/_/g, '-').replace(/[^a-z0-9-]/g, ''))
|
|
230
|
+
.filter(Boolean)
|
|
231
|
+
.join('.');
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The prefix becomes a directory, an npm package name, a bundle-ID label and a
|
|
235
|
+
* literal inside a Jest regex; this form is valid in all four unescaped.
|
|
236
|
+
*/
|
|
237
|
+
export const RN_PREFIX_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
238
|
+
/** Throws when the prefix is invalid or the target folder is non-empty. */
|
|
239
|
+
function assertReactNativeScaffoldable(targetFolder, appPrefix) {
|
|
240
|
+
if (typeof appPrefix !== 'string' || !RN_PREFIX_PATTERN.test(appPrefix)) {
|
|
241
|
+
throw new Error(`Invalid app prefix "${appPrefix !== null && appPrefix !== void 0 ? appPrefix : ''}": it must match ${RN_PREFIX_PATTERN.source} ` +
|
|
242
|
+
'(start with a lowercase letter; only lowercase letters, digits and hyphens).');
|
|
243
|
+
}
|
|
244
|
+
if (fs.existsSync(targetFolder) && fs.readdirSync(targetFolder).length > 0) {
|
|
245
|
+
throw new Error(`Target folder ${targetFolder} already exists and is not empty. ` +
|
|
246
|
+
'Choose another name or remove the folder.');
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** Placeholder name of the shapes package in defaults/app-react-native. */
|
|
250
|
+
export const RN_SHAPES_TOKEN = 'app-shapes';
|
|
251
|
+
/**
|
|
252
|
+
* Replace every occurrence of `token` in the text files under `folder`
|
|
253
|
+
* (node_modules and files containing a NUL byte are skipped). A literal token
|
|
254
|
+
* replacement, not the ${...} variable substitution.
|
|
255
|
+
*/
|
|
256
|
+
function replaceTokenInTextFiles(folder, token, value) {
|
|
257
|
+
if (token === value)
|
|
258
|
+
return;
|
|
259
|
+
for (const entry of fs.readdirSync(folder, { withFileTypes: true })) {
|
|
260
|
+
const full = path.join(folder, entry.name);
|
|
261
|
+
if (entry.isDirectory()) {
|
|
262
|
+
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
263
|
+
replaceTokenInTextFiles(full, token, value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if (entry.isFile()) {
|
|
267
|
+
const buffer = fs.readFileSync(full);
|
|
268
|
+
if (buffer.includes(0))
|
|
269
|
+
continue;
|
|
270
|
+
const text = buffer.toString('utf8');
|
|
271
|
+
if (text.includes(token)) {
|
|
272
|
+
fs.writeFileSync(full, text.split(token).join(value));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const readJSON = (file) => JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
278
|
+
const writeJSON = (file, data) => fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n');
|
|
279
|
+
/**
|
|
280
|
+
* Scaffold the React Native monorepo from defaults/app-react-native.
|
|
281
|
+
* Identity is stamped into named fields only; the global ${...} substitution
|
|
282
|
+
* (replaceVariablesInFolder) is never used, so template literals in TypeScript
|
|
283
|
+
* sources stay intact.
|
|
284
|
+
*/
|
|
285
|
+
export function scaffoldReactNativeApp(targetFolder_1, id_1) {
|
|
286
|
+
return __awaiter(this, arguments, void 0, function* (targetFolder, id, options = {}) {
|
|
287
|
+
const { appName, appPrefix, appDomain, hyphenName } = id;
|
|
288
|
+
// Validate before writing anything.
|
|
289
|
+
assertReactNativeScaffoldable(targetFolder, appPrefix);
|
|
290
|
+
// lib/esm/ (built) is two levels below the package root; src/ (Jest) is one.
|
|
291
|
+
const templateDir = options.templateDir ||
|
|
292
|
+
[
|
|
293
|
+
path.join(getScriptDir(), '..', '..', 'defaults', 'app-react-native'),
|
|
294
|
+
path.join(getScriptDir(), '..', 'defaults', 'app-react-native'),
|
|
295
|
+
].find((dir) => fs.existsSync(dir));
|
|
296
|
+
if (!templateDir) {
|
|
297
|
+
throw new Error('React Native template not found (defaults/app-react-native)');
|
|
298
|
+
}
|
|
299
|
+
const shapesName = `${appPrefix}-shapes`;
|
|
300
|
+
log("Creating new Linked React Native app '" + appName + "'");
|
|
301
|
+
// 1. Copy the template.
|
|
302
|
+
fs.copySync(templateDir, targetFolder);
|
|
303
|
+
// 2. Restore dotfiles npm would strip from the CLI tarball.
|
|
304
|
+
renameShippedDotfiles(targetFolder);
|
|
305
|
+
// 3. Rename the shapes package directory.
|
|
306
|
+
const oldShapesDir = path.join(targetFolder, 'packages', RN_SHAPES_TOKEN);
|
|
307
|
+
const shapesDir = path.join(targetFolder, 'packages', shapesName);
|
|
308
|
+
if (fs.existsSync(oldShapesDir) && oldShapesDir !== shapesDir) {
|
|
309
|
+
fs.renameSync(oldShapesDir, shapesDir);
|
|
310
|
+
}
|
|
311
|
+
// 4a. Rename the shapes package token everywhere: workspaces, .gitignore
|
|
312
|
+
// negation, package names, dependency keys, Jest patterns, import specifiers,
|
|
313
|
+
// test expectations and docs. Only the literal `app-shapes` token is replaced.
|
|
314
|
+
replaceTokenInTextFiles(targetFolder, RN_SHAPES_TOKEN, shapesName);
|
|
315
|
+
// 4b. Stamp the identity fields that are not the shapes token.
|
|
316
|
+
const rootPkgPath = path.join(targetFolder, 'package.json');
|
|
317
|
+
if (fs.existsSync(rootPkgPath)) {
|
|
318
|
+
const rootPkg = readJSON(rootPkgPath);
|
|
319
|
+
rootPkg.name = `${hyphenName}-monorepo`;
|
|
320
|
+
writeJSON(rootPkgPath, rootPkg);
|
|
321
|
+
}
|
|
322
|
+
const mobileDir = path.join(targetFolder, 'apps', 'mobile');
|
|
323
|
+
const appJsonPath = path.join(mobileDir, 'app.json');
|
|
324
|
+
if (fs.existsSync(appJsonPath)) {
|
|
325
|
+
const appJson = readJSON(appJsonPath);
|
|
326
|
+
appJson.expo = appJson.expo || {};
|
|
327
|
+
appJson.expo.name = appName;
|
|
328
|
+
appJson.expo.slug = hyphenName;
|
|
329
|
+
appJson.expo.ios = appJson.expo.ios || {};
|
|
330
|
+
appJson.expo.ios.bundleIdentifier = reactNativeBundleId(appDomain, appPrefix);
|
|
331
|
+
writeJSON(appJsonPath, appJson);
|
|
332
|
+
}
|
|
333
|
+
// 5. Install with npm: the template is an npm workspaces monorepo.
|
|
334
|
+
if (!options.skipInstall) {
|
|
335
|
+
const spinner = ora({
|
|
336
|
+
text: 'Installing dependencies (npm)...',
|
|
337
|
+
spinner: 'dots',
|
|
338
|
+
}).start();
|
|
339
|
+
try {
|
|
340
|
+
yield execPromise('npm install', false, false, {
|
|
341
|
+
cwd: targetFolder,
|
|
342
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
343
|
+
});
|
|
344
|
+
spinner.succeed('Dependencies installed (npm)');
|
|
345
|
+
}
|
|
346
|
+
catch (err) {
|
|
347
|
+
spinner.fail('Could not install dependencies');
|
|
348
|
+
if (err === null || err === void 0 ? void 0 : err.stdout)
|
|
349
|
+
process.stdout.write(err.stdout);
|
|
350
|
+
if (err === null || err === void 0 ? void 0 : err.stderr)
|
|
351
|
+
process.stderr.write(err.stderr);
|
|
352
|
+
throw new Error(`npm install failed. The files are in ${targetFolder}; ` +
|
|
353
|
+
`run \`npm install\` there to retry.`);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
// 6. Next steps.
|
|
357
|
+
log(`Your Linked React Native app is ready at ${chalk.blueBright(targetFolder)}`, `\nNext steps:`, ` ${chalk.blueBright(`cd ${path.basename(targetFolder)}`)}`, ` ${chalk.blueBright('npm test -w apps/mobile')}`, ` ${chalk.blueBright('cd apps/mobile && npx expo run:ios')}`);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
// Indirection so tests can replace the scaffold step when exercising createApp.
|
|
361
|
+
export const reactNativeInternals = { scaffoldReactNativeApp };
|
|
197
362
|
/** Set or append a `KEY=value` line in a `.env`-style text blob. */
|
|
198
363
|
function setEnvVar(envText, key, value) {
|
|
199
364
|
const line = `${key}=${value}`;
|
|
@@ -961,6 +1126,42 @@ export const createOntology = (prefix_1, uriBase_1, ...args_1) => __awaiter(void
|
|
|
961
1126
|
log(`Added an import of this file from ${chalk.magenta(indexPath)}`);
|
|
962
1127
|
}
|
|
963
1128
|
});
|
|
1129
|
+
// The shapes barrel (src/shapes/index.ts) is imported by both the frontend index and
|
|
1130
|
+
// the backend entry, so every shape registers on both boot paths (and materializes into
|
|
1131
|
+
// app-data on boot). `create-shape` adds each new shape here — NOT to the main index.
|
|
1132
|
+
const SHAPES_BARREL_HEADER = `// Shape registry — every shape is imported here so its @linkedShape decorator runs and\n` +
|
|
1133
|
+
`// the shape registers on both boot paths (backend materialization + frontend). \`linked\n` +
|
|
1134
|
+
`// create-shape\` maintains this list.\n//SHAPES\n`;
|
|
1135
|
+
const ensureBackendImportsShapes = function (root = process.cwd()) {
|
|
1136
|
+
const backendPath = path.join(root, 'src', 'backend.ts');
|
|
1137
|
+
if (!fs.existsSync(backendPath))
|
|
1138
|
+
return;
|
|
1139
|
+
let contents = fs.readFileSync(backendPath, 'utf-8');
|
|
1140
|
+
if (contents.includes('./shapes/index'))
|
|
1141
|
+
return;
|
|
1142
|
+
fs.writeFileSync(backendPath, `import './shapes/index.js';\n` + contents);
|
|
1143
|
+
};
|
|
1144
|
+
// Register a shape in the shapes barrel (src/shapes/index.ts), creating it if needed, and
|
|
1145
|
+
// make sure both the main index and backend.ts import the barrel. Idempotent.
|
|
1146
|
+
export const addShapeToBarrel = function (shapeHyphenName, root = process.cwd()) {
|
|
1147
|
+
const shapesDir = path.join(root, 'src', 'shapes');
|
|
1148
|
+
fs.ensureDirSync(shapesDir);
|
|
1149
|
+
const barrelPath = path.join(shapesDir, 'index.ts');
|
|
1150
|
+
let contents = fs.existsSync(barrelPath)
|
|
1151
|
+
? fs.readFileSync(barrelPath, 'utf-8')
|
|
1152
|
+
: SHAPES_BARREL_HEADER;
|
|
1153
|
+
const line = `import './${shapeHyphenName}.js';`;
|
|
1154
|
+
if (!contents.split(/\n/g).some((l) => l.trim() === line.trim())) {
|
|
1155
|
+
contents = contents.includes('//SHAPES')
|
|
1156
|
+
? contents.replace('//SHAPES', `//SHAPES\n${line}`)
|
|
1157
|
+
: contents.replace(/\n*$/, '') + `\n${line}\n`;
|
|
1158
|
+
fs.writeFileSync(barrelPath, contents);
|
|
1159
|
+
}
|
|
1160
|
+
// Both boot paths must load the barrel (idempotent).
|
|
1161
|
+
addLineToIndex(`import './shapes/index.js';`, 'shapes', root);
|
|
1162
|
+
ensureBackendImportsShapes(root);
|
|
1163
|
+
return barrelPath;
|
|
1164
|
+
};
|
|
964
1165
|
// Exported for Shape-Builder reuse (plan-010 T1d.4): CodeShapeSyncService adds
|
|
965
1166
|
// the `import './shapes/<Shape>.js';` line to a generated app package's index.
|
|
966
1167
|
export const addLineToIndex = function (line, insertMatchString, root = process.cwd(), insertAtStart = false) {
|
|
@@ -1145,12 +1346,11 @@ export const createShape = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...
|
|
|
1145
1346
|
//replace variables in some of the copied files
|
|
1146
1347
|
yield replaceVariablesInFiles(targetFile);
|
|
1147
1348
|
log(`Created a new shape class template in ${chalk.magenta(targetFile.replace(basePath, ''))}`);
|
|
1148
|
-
//
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
}
|
|
1349
|
+
// Register the shape in the shapes barrel (src/shapes/index.ts) — NOT the main index —
|
|
1350
|
+
// and make sure the barrel is loaded on both boot paths. This is what makes the app
|
|
1351
|
+
// materialize its own shapes on boot (plan-027 / plan-028 handover).
|
|
1352
|
+
const barrelPath = addShapeToBarrel(hyphenName);
|
|
1353
|
+
log(`Registered the shape in ${chalk.magenta(barrelPath.replace(basePath, ''))}`);
|
|
1154
1354
|
});
|
|
1155
1355
|
export const createSetComponent = (name_1, ...args_1) => __awaiter(void 0, [name_1, ...args_1], void 0, function* (name, basePath = process.cwd()) {
|
|
1156
1356
|
let targetFolder = ensureFolderExists(basePath, 'src', 'components');
|
|
@@ -1866,6 +2066,7 @@ export const createPackage = (name_1, uriBase_1, ...args_1) => __awaiter(void 0,
|
|
|
1866
2066
|
let { hyphenName, camelCaseName, underscoreName } = setNameVariables(cleanPackageName);
|
|
1867
2067
|
log("Creating new LINCD package '" + name + "'");
|
|
1868
2068
|
fs.copySync(path.join(getScriptDir(), '..', '..', 'defaults', 'package'), targetFolder);
|
|
2069
|
+
renameShippedDotfiles(targetFolder);
|
|
1869
2070
|
//replace variables in some of the copied files
|
|
1870
2071
|
yield Promise.all([
|
|
1871
2072
|
'src/index.ts',
|
|
@@ -1896,12 +2097,25 @@ export const createPackage = (name_1, uriBase_1, ...args_1) => __awaiter(void 0,
|
|
|
1896
2097
|
console.log('yarn probably not working');
|
|
1897
2098
|
return '';
|
|
1898
2099
|
}));
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2100
|
+
const setup = planPackageSetup(version.toString(), path.join(getScriptDir(), 'launch.js'));
|
|
2101
|
+
if (setup.yarnrc) {
|
|
2102
|
+
fs.writeFileSync(path.join(targetFolder, '.yarnrc.yml'), setup.yarnrc);
|
|
2103
|
+
}
|
|
2104
|
+
const installed = yield execp(setup.installCommand, true, false, {
|
|
2105
|
+
cwd: targetFolder,
|
|
2106
|
+
})
|
|
2107
|
+
.then(() => true)
|
|
2108
|
+
.catch(() => {
|
|
2109
|
+
console.warn(`Could not install dependencies (${setup.installCommand})`);
|
|
2110
|
+
process.exitCode = 1;
|
|
2111
|
+
return false;
|
|
1904
2112
|
});
|
|
2113
|
+
if (installed) {
|
|
2114
|
+
yield execp(setup.buildCommand, true, false, { cwd: targetFolder }).catch(() => {
|
|
2115
|
+
console.warn('Dependencies installed, but the initial build failed');
|
|
2116
|
+
process.exitCode = 1;
|
|
2117
|
+
});
|
|
2118
|
+
}
|
|
1905
2119
|
log(`Prepared a new LINCD package in ${chalk.magenta(targetFolder)}`, `Run ${chalk.blueBright('yarn build')} from this directory to build once`, `Or ${chalk.blueBright('yarn dev')} to continuously rebuild on file changes`);
|
|
1906
2120
|
});
|
|
1907
2121
|
var getNextVersion = function (version) {
|
|
@@ -1967,6 +2181,7 @@ export const register = function (registryURL) {
|
|
|
1967
2181
|
}
|
|
1968
2182
|
};
|
|
1969
2183
|
export const buildPackage = (target_1, target2_1, ...args_1) => __awaiter(void 0, [target_1, target2_1, ...args_1], void 0, function* (target, target2, packagePath = process.cwd(), logResults = true) {
|
|
2184
|
+
var _a;
|
|
1970
2185
|
// Ensure packagePath is absolute and points to a directory containing package.json; if not, go up until we find one
|
|
1971
2186
|
// First, resolve to absolute path
|
|
1972
2187
|
let currentPath = path.isAbsolute(packagePath)
|
|
@@ -2047,23 +2262,89 @@ export const buildPackage = (target_1, target2_1, ...args_1) => __awaiter(void 0
|
|
|
2047
2262
|
});
|
|
2048
2263
|
});
|
|
2049
2264
|
};
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2265
|
+
if (((_a = pkgJson.linked) === null || _a === void 0 ? void 0 : _a.extensionlessImports) === true) {
|
|
2266
|
+
const skipped = "Skipping the import check: package.json sets 'linked.extensionlessImports'";
|
|
2267
|
+
logResults ? spinner.info(skipped) : console.log(skipped);
|
|
2268
|
+
}
|
|
2269
|
+
planBuildSteps(pkgJson, packagePath).forEach(buildStep);
|
|
2270
|
+
let success = yield buildProcess.catch((err) => {
|
|
2271
|
+
let msg = typeof err === 'string' || err instanceof Error
|
|
2272
|
+
? err.toString()
|
|
2273
|
+
: err.error && !err.error.toString().includes('Command failed:')
|
|
2274
|
+
? err.error
|
|
2275
|
+
: err.stdout + '\n' + err.stderr;
|
|
2276
|
+
if (logResults) {
|
|
2277
|
+
spinner.stopAndPersist({
|
|
2278
|
+
symbol: chalk.red('✖'),
|
|
2279
|
+
// text: 'Build failed',
|
|
2280
|
+
});
|
|
2281
|
+
}
|
|
2282
|
+
else {
|
|
2283
|
+
console.error(chalk.red(packagePath.split('/').pop(), ' - Build failed:'));
|
|
2284
|
+
console.error(err);
|
|
2285
|
+
return msg;
|
|
2286
|
+
}
|
|
2287
|
+
console.log(msg);
|
|
2053
2288
|
});
|
|
2054
|
-
|
|
2289
|
+
//will be undefined if there was an error
|
|
2290
|
+
if (typeof success !== 'undefined' && success !== false) {
|
|
2291
|
+
if (logResults) {
|
|
2292
|
+
spinner.stopAndPersist({
|
|
2293
|
+
symbol: chalk.greenBright('✔'),
|
|
2294
|
+
text: success === true
|
|
2295
|
+
? 'Build successful'
|
|
2296
|
+
: 'Build successful with warnings',
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
else {
|
|
2301
|
+
if (logResults) {
|
|
2302
|
+
spinner.stopAndPersist({
|
|
2303
|
+
symbol: chalk.red('✖'),
|
|
2304
|
+
text: 'Build failed',
|
|
2305
|
+
});
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
return success;
|
|
2309
|
+
});
|
|
2310
|
+
// The ordered `linked build` steps for a linkedPackage. A package whose source
|
|
2311
|
+
// uses extensionless relative imports (`"linked": {"extensionlessImports": true}`)
|
|
2312
|
+
// skips the import check and gets `.js` added to its emitted ESM specifiers.
|
|
2313
|
+
export const planBuildSteps = (pkgJson, packagePath) => {
|
|
2314
|
+
var _a;
|
|
2315
|
+
const extensionlessImports = ((_a = pkgJson.linked) === null || _a === void 0 ? void 0 : _a.extensionlessImports) === true;
|
|
2316
|
+
const steps = [];
|
|
2317
|
+
if (!extensionlessImports) {
|
|
2318
|
+
steps.push({
|
|
2319
|
+
name: 'Checking imports',
|
|
2320
|
+
apply: () => checkImports(packagePath + '/src'),
|
|
2321
|
+
});
|
|
2322
|
+
}
|
|
2323
|
+
steps.push({
|
|
2055
2324
|
name: 'Compiling ESM',
|
|
2056
2325
|
apply: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2057
2326
|
return compilePackageESM(packagePath);
|
|
2058
2327
|
}),
|
|
2059
2328
|
});
|
|
2060
|
-
|
|
2329
|
+
if (extensionlessImports) {
|
|
2330
|
+
steps.push({
|
|
2331
|
+
name: 'Rewriting ESM import specifiers',
|
|
2332
|
+
apply: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2333
|
+
const libEsm = path.join(packagePath, 'lib', 'esm');
|
|
2334
|
+
if (fs.existsSync(libEsm)) {
|
|
2335
|
+
yield rewriteExtensionlessImports(libEsm);
|
|
2336
|
+
}
|
|
2337
|
+
return true;
|
|
2338
|
+
}),
|
|
2339
|
+
});
|
|
2340
|
+
}
|
|
2341
|
+
steps.push({
|
|
2061
2342
|
name: 'Compiling CJS',
|
|
2062
2343
|
apply: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2063
2344
|
return compilePackageCJS(packagePath);
|
|
2064
2345
|
}),
|
|
2065
2346
|
});
|
|
2066
|
-
|
|
2347
|
+
steps.push({
|
|
2067
2348
|
name: 'Copying files to lib folder',
|
|
2068
2349
|
apply: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2069
2350
|
const files = yield glob(packagePath + '/src/**/*.{json,d.ts,css,scss}');
|
|
@@ -2086,7 +2367,7 @@ export const buildPackage = (target_1, target2_1, ...args_1) => __awaiter(void 0
|
|
|
2086
2367
|
});
|
|
2087
2368
|
}),
|
|
2088
2369
|
});
|
|
2089
|
-
|
|
2370
|
+
steps.push({
|
|
2090
2371
|
name: 'Dual package support',
|
|
2091
2372
|
apply: () => {
|
|
2092
2373
|
// Skip if no tsconfig files (e.g. pure-CSS packages).
|
|
@@ -2101,56 +2382,18 @@ export const buildPackage = (target_1, target2_1, ...args_1) => __awaiter(void 0
|
|
|
2101
2382
|
});
|
|
2102
2383
|
},
|
|
2103
2384
|
});
|
|
2104
|
-
|
|
2385
|
+
steps.push({
|
|
2105
2386
|
name: 'Removing old files from lib folder',
|
|
2106
2387
|
apply: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
2107
2388
|
return removeOldFiles(packagePath);
|
|
2108
2389
|
}),
|
|
2109
2390
|
});
|
|
2110
|
-
|
|
2391
|
+
steps.push({
|
|
2111
2392
|
name: 'Checking dependencies',
|
|
2112
2393
|
apply: () => depCheck(packagePath),
|
|
2113
2394
|
});
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
? err.toString()
|
|
2117
|
-
: err.error && !err.error.toString().includes('Command failed:')
|
|
2118
|
-
? err.error
|
|
2119
|
-
: err.stdout + '\n' + err.stderr;
|
|
2120
|
-
if (logResults) {
|
|
2121
|
-
spinner.stopAndPersist({
|
|
2122
|
-
symbol: chalk.red('✖'),
|
|
2123
|
-
// text: 'Build failed',
|
|
2124
|
-
});
|
|
2125
|
-
}
|
|
2126
|
-
else {
|
|
2127
|
-
console.error(chalk.red(packagePath.split('/').pop(), ' - Build failed:'));
|
|
2128
|
-
console.error(err);
|
|
2129
|
-
return msg;
|
|
2130
|
-
}
|
|
2131
|
-
console.log(msg);
|
|
2132
|
-
});
|
|
2133
|
-
//will be undefined if there was an error
|
|
2134
|
-
if (typeof success !== 'undefined' && success !== false) {
|
|
2135
|
-
if (logResults) {
|
|
2136
|
-
spinner.stopAndPersist({
|
|
2137
|
-
symbol: chalk.greenBright('✔'),
|
|
2138
|
-
text: success === true
|
|
2139
|
-
? 'Build successful'
|
|
2140
|
-
: 'Build successful with warnings',
|
|
2141
|
-
});
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
else {
|
|
2145
|
-
if (logResults) {
|
|
2146
|
-
spinner.stopAndPersist({
|
|
2147
|
-
symbol: chalk.red('✖'),
|
|
2148
|
-
text: 'Build failed',
|
|
2149
|
-
});
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
return success;
|
|
2153
|
-
});
|
|
2395
|
+
return steps;
|
|
2396
|
+
};
|
|
2154
2397
|
export const compilePackage = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (packagePath = process.cwd()) {
|
|
2155
2398
|
//echo 'compiling CJS' && tsc -p tsconfig-cjs.json && echo 'compiling ESM' && tsc -p tsconfig-esm.json
|
|
2156
2399
|
// let cjsConfig = fs.existsSync(path.join(packagePath,'tsconfig-cjs.json'));
|