refactor: creators
This commit is contained in:
parent
73eb334e05
commit
f702e8b7f0
8
build/concurrent.js
Normal file
8
build/concurrent.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = async function concurrent(inputs, task, jobs = require('os').cpus().length) {
|
||||
const workers = new Array(jobs).fill(Promise.resolve(0));
|
||||
inputs.forEach((input, i) => {
|
||||
// then= :)
|
||||
workers[i % jobs] = workers[i % jobs].then(async (code) => await task(input) || code);
|
||||
});
|
||||
return (await Promise.all(workers)).find((code) => code !== 0) || 0;
|
||||
};
|
167
build/publish.js
167
build/publish.js
|
@ -1,43 +1,150 @@
|
|||
const {Buffer} = require('buffer');
|
||||
const {exec} = require('child_process');
|
||||
const {createHash} = require('crypto');
|
||||
const {createReadStream} = require('fs');
|
||||
const {cp, mkdir, writeFile} = require('fs/promises');
|
||||
const {join} = require('path');
|
||||
|
||||
const {processCode, spawnWith} = require('@flecks/core/src/server');
|
||||
const {
|
||||
processCode,
|
||||
spawnWith,
|
||||
} = require('@flecks/core/src/server');
|
||||
const Arborist = require('@npmcli/arborist');
|
||||
const {glob} = require('glob');
|
||||
|
||||
const concurrent = require('./concurrent');
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
const args = ['npm', 'publish', '--provenance'];
|
||||
const args = ['npm', 'publish', ...process.argv.slice(2)];
|
||||
const bumpedVersions = {};
|
||||
const creators = ['create-app', 'create-fleck'];
|
||||
const localVersions = {};
|
||||
const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish');
|
||||
const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||
|
||||
(async () => {
|
||||
const paths = (await Promise.all(workspaces.map((path) => glob(join(FLECKS_CORE_ROOT, path)))))
|
||||
.flat();
|
||||
const cpus = new Array(require('os').cpus().length).fill(Promise.resolve(0));
|
||||
paths.forEach((cwd, i) => {
|
||||
// then= :)
|
||||
cpus[i % cpus.length] = cpus[i % cpus.length]
|
||||
.then(async (code) => {
|
||||
const {name, version} = require(join(cwd, 'package.json'));
|
||||
const [localVersion, remoteVersion] = await Promise.all([
|
||||
version,
|
||||
new Promise((resolve, reject) => {
|
||||
exec(`npm view ${name} version`, (error, stdout) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
return;
|
||||
}
|
||||
resolve(stdout.trim());
|
||||
});
|
||||
}),
|
||||
]);
|
||||
if (localVersion === remoteVersion) {
|
||||
return code;
|
||||
}
|
||||
const publishCode = await processCode(spawnWith(args, {cwd: join(cwd, 'dist', 'fleck')}));
|
||||
return publishCode || code;
|
||||
});
|
||||
const run = (cmd) => (
|
||||
new Promise((resolve) => {
|
||||
exec(cmd, (error, stdout) => {
|
||||
if (error) {
|
||||
resolve(undefined)
|
||||
return;
|
||||
}
|
||||
resolve(stdout.trim());
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// Get integrity sums for creator dependencies.
|
||||
const packPkg = async (pkg) => {
|
||||
await processCode(spawnWith(
|
||||
['npm', 'pack', '--pack-destination', packCache],
|
||||
{cwd: join(FLECKS_CORE_ROOT, 'packages', pkg, 'dist', 'fleck'), stdio: 'ignore'},
|
||||
));
|
||||
};
|
||||
|
||||
const bumpDependencies = (dependencies) => (
|
||||
Object.fromEntries(
|
||||
Object.entries(dependencies)
|
||||
.map(([pkg, version]) => ([pkg, localVersions[pkg] || version])),
|
||||
)
|
||||
);
|
||||
|
||||
const integrityForPkg = async (pkg) => {
|
||||
const pack = join(packCache, `flecks-${pkg.split('/')[1]}-${localVersions[pkg]}.tgz`);
|
||||
const buffers = [];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for await (const data of createReadStream(pack).pipe(createHash('sha512'))) {
|
||||
buffers.push(data);
|
||||
}
|
||||
return `sha512-${Buffer.concat(buffers).toString('base64')}`;
|
||||
};
|
||||
|
||||
const shrinkwrap = async (path) => {
|
||||
const arb = new Arborist({
|
||||
path,
|
||||
registry: await run('npm config get registry'),
|
||||
});
|
||||
process.exitCode = (await Promise.all(cpus)).find((code) => code !== 0) || 0;
|
||||
const {meta} = await arb.buildIdealTree({saveType: 'prod'});
|
||||
const shrinkwrap = await meta.commit();
|
||||
shrinkwrap.packages = Object.fromEntries(
|
||||
await Promise.all(
|
||||
Object.entries(shrinkwrap.packages)
|
||||
.map(async ([pkg, config]) => {
|
||||
if (pkg.match(/node_modules\/@flecks\/[^/]+$/)) {
|
||||
if (config.dependencies) {
|
||||
config.dependencies = bumpDependencies(config.dependencies);
|
||||
}
|
||||
if (config.devDependencies) {
|
||||
config.devDependencies = bumpDependencies(config.devDependencies);
|
||||
}
|
||||
const subpkg = pkg.split('/').slice(1).join('/');
|
||||
config.version = localVersions[subpkg];
|
||||
config.integrity = await integrityForPkg(subpkg);
|
||||
}
|
||||
return [pkg, config];
|
||||
}),
|
||||
),
|
||||
);
|
||||
return shrinkwrap;
|
||||
};
|
||||
|
||||
const shrinkwrapsAndPublish = async (creator) => {
|
||||
const dist = join(FLECKS_CORE_ROOT, 'packages', creator, 'dist', 'fleck');
|
||||
const fakePackage = join(packCache, creator);
|
||||
await mkdir(fakePackage, {recursive: true});
|
||||
// Get a shrinkwrap from template package.json and insert it as a package-lock.json.
|
||||
await cp(join(dist, 'template', 'package.json.noconflict'), join(fakePackage, 'package.json'));
|
||||
await writeFile(
|
||||
join(dist, 'template', 'package-lock.json.noconflict'),
|
||||
JSON.stringify(await shrinkwrap(fakePackage), null, 2),
|
||||
);
|
||||
// Get a shrinkwrap from the built creator and insert it as shrinkwrap.
|
||||
await writeFile(
|
||||
join(dist, 'npm-shrinkwrap.json'),
|
||||
JSON.stringify(await shrinkwrap(dist), null, 2),
|
||||
);
|
||||
// Publish.
|
||||
await processCode(spawnWith(args, {cwd: dist}));
|
||||
};
|
||||
|
||||
(async () => {
|
||||
await concurrent(
|
||||
(await Promise.all(workspaces.map((path) => glob(join(FLECKS_CORE_ROOT, path))))).flat(),
|
||||
async (cwd) => {
|
||||
const {name, version} = require(join(cwd, 'package.json'));
|
||||
const [localVersion, remoteVersion] = await Promise.all([
|
||||
version,
|
||||
run(`npm view ${name} version`),
|
||||
]);
|
||||
localVersions[name] = version;
|
||||
if (localVersion === remoteVersion) {
|
||||
return undefined;
|
||||
}
|
||||
bumpedVersions[name] = version;
|
||||
// Skip creators for now.
|
||||
if (creators.some((creator) => name.endsWith(creator))) {
|
||||
return undefined;
|
||||
}
|
||||
return processCode(spawnWith(args, {cwd: join(cwd, 'dist', 'fleck')}));
|
||||
},
|
||||
);
|
||||
// No creators? Bail.
|
||||
if (!bumpedVersions['@flecks/create-app'] && !bumpedVersions['@flecks/create-app']) {
|
||||
return;
|
||||
}
|
||||
// Pack dependencies.
|
||||
await mkdir(packCache, {recursive: true});
|
||||
const dependencies = ['build', 'core', 'fleck', 'server'];
|
||||
await Promise.all(dependencies.map(packPkg));
|
||||
if (bumpedVersions['@flecks/create-fleck']) {
|
||||
await shrinkwrapsAndPublish('create-fleck');
|
||||
}
|
||||
if (bumpedVersions['@flecks/create-app']) {
|
||||
// Needs packed create-fleck for package lock.
|
||||
await packPkg('create-fleck');
|
||||
await shrinkwrapsAndPublish('create-app');
|
||||
}
|
||||
})();
|
||||
|
|
|
@ -3,21 +3,18 @@ const {join} = require('path');
|
|||
const {processCode, spawnWith} = require('@flecks/core/src/server');
|
||||
const {glob} = require('glob');
|
||||
|
||||
const concurrent = require('./concurrent');
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
const args = ['npm', 'run', ...process.argv.slice(2)];
|
||||
const args = process.argv.slice(2);
|
||||
const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||
|
||||
(async () => {
|
||||
const paths = (await Promise.all(workspaces.map((path) => glob(join(FLECKS_CORE_ROOT, path)))))
|
||||
.flat();
|
||||
const cpus = new Array(require('os').cpus().length).fill(Promise.resolve(0));
|
||||
paths.forEach((cwd, i) => {
|
||||
// then= :)
|
||||
cpus[i % cpus.length] = cpus[i % cpus.length]
|
||||
.then(async (code) => (await processCode(spawnWith(args, {cwd}))) || code);
|
||||
});
|
||||
process.exitCode = (await Promise.all(cpus)).find((code) => code !== 0) || 0;
|
||||
process.exitCode = await concurrent(
|
||||
(await Promise.all(workspaces.map((path) => glob(join(FLECKS_CORE_ROOT, path))))).flat(),
|
||||
(cwd) => processCode(spawnWith(args, {cwd})),
|
||||
);
|
||||
})();
|
||||
|
|
3686
package-lock.json
generated
3686
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
|
@ -7,17 +7,20 @@
|
|||
"url": "git+https://github.com/cha0s/flecks.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build/tasks build",
|
||||
"build": "node build/tasks npm run build",
|
||||
"ci": "act -j verify",
|
||||
"dox:bump": "npm run dox:gh-pages && cd dox && git add . && git commit -m $(git -C .. rev-parse HEAD) && git push origin gh-pages",
|
||||
"dox:gh-pages": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus build --out-dir ../dox-tmp && cd .. && rm -rf dox/* && mv dox-tmp/* dox && rmdir dox-tmp",
|
||||
"dox:serve": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus build --no-minify --out-dir ../dox-tmp && node_modules/.bin/docusaurus serve --dir ../dox-tmp",
|
||||
"dox": "flecks dox docusaurus && cd website && DOCUSAURUS_GENERATED_FILES_DIR_NAME=node_modules/.cache/docusaurus node_modules/.bin/docusaurus",
|
||||
"lint": "node build/tasks lint",
|
||||
"publish": "node build/publish",
|
||||
"test": "node build/tasks -- test -t 300000"
|
||||
"lint": "node build/tasks npm run lint",
|
||||
"publish": "node build/publish --provenance",
|
||||
"test": "node build/tasks npm run -- test -t 300000"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
]
|
||||
],
|
||||
"devDependencies": {
|
||||
"@npmcli/arborist": "^7.3.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,21 +19,20 @@ const {
|
|||
isStringLiteral,
|
||||
stringLiteral,
|
||||
} = require('@babel/types');
|
||||
const addPathsToYml = require('@flecks/core/build/add-paths-to-yml');
|
||||
const D = require('@flecks/core/build/debug');
|
||||
const {
|
||||
add,
|
||||
binaryPath,
|
||||
loadYml,
|
||||
lockFile,
|
||||
spawnWith,
|
||||
} = require('@flecks/core/src/server');
|
||||
const chokidar = require('chokidar');
|
||||
const {glob} = require('glob');
|
||||
const {load: loadYml} = require('js-yaml');
|
||||
const {paperwork} = require('precinct');
|
||||
const {rimraf} = require('rimraf');
|
||||
|
||||
const addPathsToYml = require('./add-paths-to-yml');
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
@ -236,6 +235,7 @@ exports.commands = (program, flecks) => {
|
|||
...(target ? {FLECKS_CORE_BUILD_LIST: target} : {}),
|
||||
...(hot ? {FLECKS_ENV__flecks_server__hot: 'true'} : {}),
|
||||
},
|
||||
// @todo This kills the pnpm. Let's use a real IPC channel.
|
||||
useFork: true,
|
||||
...rest,
|
||||
};
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
const {readFile} = require('fs/promises');
|
||||
const {join} = require('path');
|
||||
|
||||
const {loadYml} = require('@flecks/core/src/server');
|
||||
|
||||
const D = require('@flecks/core/build/debug');
|
||||
|
||||
const debug = D('@flecks/build/build/load-config');
|
||||
|
||||
module.exports = async function loadConfig(root) {
|
||||
try {
|
||||
const {load} = require('js-yaml');
|
||||
const filename = join(root, 'build', 'flecks.yml');
|
||||
const buffer = await readFile(filename, 'utf8');
|
||||
debug('parsing configuration from YML...');
|
||||
return ['YML', load(buffer, {filename})];
|
||||
return ['YML', loadYml(buffer, {filename})];
|
||||
}
|
||||
catch (error) {
|
||||
if ('ENOENT' !== error.code) {
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
"glob": "^10.3.10",
|
||||
"globals": "^13.23.0",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"js-yaml": "4.1.0",
|
||||
"mocha": "^10.2.0",
|
||||
"precinct": "^11.0.5",
|
||||
"rimraf": "^5.0.5",
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
/* eslint-disable global-require */
|
||||
|
||||
const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
||||
|
||||
module.exports = {
|
||||
dumpYml,
|
||||
loadYml,
|
||||
rimraf: require('rimraf').rimraf,
|
||||
webpack: require('webpack'),
|
||||
...require('../build/webpack'),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import addPathsToYml from '@flecks/build/build/add-paths-to-yml';
|
||||
import addPathsToYml from '@flecks/core/build/add-paths-to-yml';
|
||||
import {loadYml} from '@flecks/core/server';
|
||||
import {expect} from 'chai';
|
||||
import {readFile, writeFile} from 'fs/promises';
|
||||
import {load as loadYml} from 'js-yaml';
|
||||
|
||||
it('can add paths to YML', async () => {
|
||||
await writeFile(
|
||||
|
|
|
@ -9,7 +9,7 @@ const {
|
|||
|
||||
module.exports = async (paths, root) => {
|
||||
const ymlPath = join(root || FLECKS_CORE_ROOT, 'build', 'flecks.yml');
|
||||
let yml = loadYml(await readFile(ymlPath));
|
||||
let yml = loadYml(await readFile(ymlPath)) || {};
|
||||
yml = Object.fromEntries(Object.entries(yml).concat(paths.map((path) => [path, {}])));
|
||||
await writeFile(ymlPath, dumpYml(yml, {sortKeys: true}));
|
||||
};
|
16
packages/core/build/move.js
Normal file
16
packages/core/build/move.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const {basename, dirname, join} = require('path');
|
||||
|
||||
const {JsonStream} = require('./stream');
|
||||
const FileTree = require('./tree');
|
||||
|
||||
exports.move = async (name, source) => {
|
||||
const fileTree = await FileTree.loadFrom(source);
|
||||
// Renamed to avoid conflicts.
|
||||
fileTree.glob('**/*.noconflict')
|
||||
.forEach((path) => {
|
||||
fileTree.move(path, join(dirname(path), basename(path, '.noconflict')));
|
||||
});
|
||||
// Add project name to `package.json`.
|
||||
fileTree.pipe('package.json', new JsonStream((json) => ({name, ...json})));
|
||||
return fileTree;
|
||||
};
|
|
@ -1,57 +1,70 @@
|
|||
// eslint-disable-next-line max-classes-per-file
|
||||
const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
||||
const JsonParse = require('jsonparse');
|
||||
const {Transform} = require('stream');
|
||||
|
||||
exports.JsonStream = class JsonStream extends Transform {
|
||||
|
||||
constructor() {
|
||||
constructor(decorator) {
|
||||
super();
|
||||
const self = this;
|
||||
this.done = undefined;
|
||||
this.parser = new JsonParse();
|
||||
const self = this;
|
||||
this.parser.onValue = function onValue(O) {
|
||||
if (0 === this.stack.length) {
|
||||
self.push(JSON.stringify(O));
|
||||
self.done();
|
||||
self.transformed = JSON.stringify(decorator(O));
|
||||
}
|
||||
};
|
||||
this.transformed = undefined;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
_flush(done) {
|
||||
this.push(this.transformed);
|
||||
done();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
_transform(chunk, encoding, done) {
|
||||
this.done = done;
|
||||
this.parser.write(chunk);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.JsonStream.PrettyPrint = class extends Transform {
|
||||
|
||||
constructor(indent = 2) {
|
||||
super();
|
||||
this.indent = indent;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
async _transform(chunk, encoding, done) {
|
||||
this.push(JSON.stringify(JSON.parse(chunk), null, this.indent));
|
||||
done();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.transform = (fn, opts = {}) => {
|
||||
class EasyTransform extends Transform {
|
||||
|
||||
constructor() {
|
||||
super(opts);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle, class-methods-use-this
|
||||
_transform(chunk, encoding, done) {
|
||||
fn(chunk, encoding, done, this);
|
||||
}
|
||||
exports.JsonStream.PrettyPrint = class extends exports.JsonStream {
|
||||
|
||||
constructor(decorator, indent = 2) {
|
||||
super(decorator);
|
||||
const self = this;
|
||||
this.parser.onValue = function onValue(O) {
|
||||
if (0 === this.stack.length) {
|
||||
self.transformed = JSON.stringify(O, null, indent);
|
||||
}
|
||||
};
|
||||
}
|
||||
return new EasyTransform();
|
||||
|
||||
};
|
||||
|
||||
exports.YamlStream = class YamlStream extends Transform {
|
||||
|
||||
constructor(decorator, options = {dump: {}, load: {}}) {
|
||||
super();
|
||||
this.buffers = [];
|
||||
this.decorator = decorator;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
_flush(done) {
|
||||
const yml = loadYml(Buffer.concat(this.buffers).toString(), this.options.load);
|
||||
this.push(dumpYml(this.decorator(yml), this.options.dump));
|
||||
done();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
_transform(chunk, encoding, done) {
|
||||
this.buffers.push(chunk);
|
||||
done();
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const {createReadStream, createWriteStream} = require('fs');
|
||||
const {mkdir, stat} = require('fs/promises');
|
||||
|
||||
const {glob, JsonStream} = require('@flecks/core/server');
|
||||
const {glob} = require('glob');
|
||||
const minimatch = require('minimatch');
|
||||
const {dirname, join} = require('path');
|
||||
|
||||
const {JsonStream} = require('./stream');
|
||||
|
||||
module.exports = class FileTree {
|
||||
|
||||
constructor(files = {}) {
|
||||
|
@ -19,6 +21,12 @@ module.exports = class FileTree {
|
|||
this.files[path] = stream;
|
||||
}
|
||||
|
||||
delete(path) {
|
||||
if (this.files[path]) {
|
||||
delete this.files[path];
|
||||
}
|
||||
}
|
||||
|
||||
glob(glob) {
|
||||
return Object.keys(this.files).filter((path) => minimatch(path, glob, {dot: true}));
|
||||
}
|
||||
|
@ -41,6 +49,13 @@ module.exports = class FileTree {
|
|||
);
|
||||
}
|
||||
|
||||
move(from, to) {
|
||||
if (this.files[from]) {
|
||||
this.files[to] = this.files[from];
|
||||
this.delete(from);
|
||||
}
|
||||
}
|
||||
|
||||
pipe(path, stream) {
|
||||
this.files[path] = this.files[path] ? this.files[path].pipe(stream) : undefined;
|
||||
}
|
|
@ -26,8 +26,10 @@
|
|||
"dependencies": {
|
||||
"debug": "4.3.1",
|
||||
"glob": "^10.3.10",
|
||||
"js-yaml": "4.1.0",
|
||||
"jsonparse": "^1.3.1",
|
||||
"lodash.get": "^4.4.2",
|
||||
"minimatch": "^5.0.1",
|
||||
"set-value": "^4.1.0",
|
||||
"source-map-support": "0.5.19",
|
||||
"supports-color": "9.2.1"
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
/* eslint-disable global-require */
|
||||
|
||||
const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
||||
|
||||
module.exports = {
|
||||
dumpYml,
|
||||
glob: require('glob').glob,
|
||||
loadYml,
|
||||
...require('../../build/stream'),
|
||||
...require('./package-manager'),
|
||||
...require('./process'),
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const {stat} = require('fs/promises');
|
||||
const {join} = require('path');
|
||||
|
||||
const {move} = require('@flecks/core/build/move');
|
||||
const {
|
||||
build,
|
||||
install,
|
||||
transform,
|
||||
} = require('@flecks/core/server');
|
||||
YamlStream,
|
||||
} = require('@flecks/core/src/server');
|
||||
const {program} = require('commander');
|
||||
const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
||||
const validate = require('validate-npm-package-name');
|
||||
|
||||
// const build = require('./build');
|
||||
const {move, testDestination} = require('./move');
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
@ -32,22 +30,23 @@ const {
|
|||
}
|
||||
const destination = join(FLECKS_CORE_ROOT, app);
|
||||
const name = app.startsWith('@') ? app : `@${app}/monorepo`;
|
||||
if (!await testDestination(destination)) {
|
||||
try {
|
||||
await stat(destination);
|
||||
const error = new Error(
|
||||
`@flecks/create-app: destination '${destination} already exists: aborting`,
|
||||
);
|
||||
error.code = 129;
|
||||
throw error;
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
catch (error) {}
|
||||
const fileTree = await move(name, join(__dirname, '..', 'template'));
|
||||
fileTree.pipe(
|
||||
'build/flecks.yml',
|
||||
transform((chunk, encoding, done, stream) => {
|
||||
const yml = loadYml(chunk);
|
||||
yml['@flecks/core'].id = app;
|
||||
stream.push(dumpYml(yml, {forceQuotes: true, sortKeys: true}));
|
||||
done();
|
||||
}),
|
||||
new YamlStream(
|
||||
(yml) => ({...yml, '@flecks/core': {id: app}}),
|
||||
{dump: {forceQuotes: true, sortKeys: true}},
|
||||
),
|
||||
);
|
||||
// Write the tree.
|
||||
await fileTree.writeTo(destination);
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
const {stat} = require('fs/promises');
|
||||
const {basename, dirname, join} = require('path');
|
||||
|
||||
const {transform} = require('@flecks/core/server');
|
||||
|
||||
const FileTree = require('./tree');
|
||||
|
||||
exports.testDestination = async (destination) => {
|
||||
try {
|
||||
await stat(destination);
|
||||
return false;
|
||||
}
|
||||
catch (error) {
|
||||
if ('ENOENT' !== error.code) {
|
||||
throw error;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
exports.move = async (name, source) => {
|
||||
const fileTree = await FileTree.loadFrom(source);
|
||||
// Renamed to avoid conflicts.
|
||||
const {files} = fileTree;
|
||||
fileTree.glob('**/*.noconflict')
|
||||
.forEach((path) => {
|
||||
files[join(dirname(path), basename(path, '.noconflict'))] = files[path];
|
||||
delete files[path];
|
||||
});
|
||||
// Add project name to `package.json`.
|
||||
fileTree.pipe(
|
||||
'package.json',
|
||||
transform((chunk, encoding, done, stream) => {
|
||||
stream.push(JSON.stringify({name, ...JSON.parse(chunk)}));
|
||||
done();
|
||||
}),
|
||||
);
|
||||
return fileTree;
|
||||
};
|
|
@ -22,14 +22,13 @@
|
|||
"create-app": "./build/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"npm-shrinkwrap.json",
|
||||
"server.js",
|
||||
"template"
|
||||
],
|
||||
"dependencies": {
|
||||
"@flecks/core": "^4.0.2",
|
||||
"commander": "11.1.0",
|
||||
"js-yaml": "4.1.0",
|
||||
"minimatch": "^5.0.1",
|
||||
"validate-npm-package-name": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
export {default as validate} from 'validate-npm-package-name';
|
||||
/* eslint-disable global-require */
|
||||
|
||||
module.exports = {
|
||||
validate: require('validate-npm-package-name'),
|
||||
};
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
'@flecks/build': {}
|
||||
'@flecks/core': {}
|
||||
'@flecks/server': {}
|
||||
|
|
|
@ -11,12 +11,11 @@
|
|||
"start": "DEBUG=@flecks/*,-*:silly npm run dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@flecks/core": "^3.0.0",
|
||||
"@flecks/server": "^3.0.0"
|
||||
"@flecks/server": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flecks/build": "^3.0.0",
|
||||
"@flecks/create-fleck": "^3.0.0",
|
||||
"@flecks/build": "^4.0.0",
|
||||
"@flecks/create-fleck": "^4.0.0",
|
||||
"patch-package": "^8.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,115 +1,97 @@
|
|||
#!/usr/bin/env node
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
const {stat} = require('fs/promises');
|
||||
const {join} = require('path');
|
||||
const {
|
||||
basename,
|
||||
dirname,
|
||||
join,
|
||||
relative,
|
||||
sep,
|
||||
} = require('path');
|
||||
|
||||
const addPathsToYml = require('@flecks/build/build/add-paths-to-yml');
|
||||
const addPathsToYml = require('@flecks/core/build/add-paths-to-yml');
|
||||
const {program} = require('commander');
|
||||
const {move} = require('@flecks/core/build/move');
|
||||
const {
|
||||
build,
|
||||
install,
|
||||
transform,
|
||||
} = require('@flecks/core/server');
|
||||
const {move, testDestination} = require('@flecks/create-app/build/move');
|
||||
const {validate} = require('@flecks/create-app/src/server');
|
||||
JsonStream,
|
||||
} = require('@flecks/core/src/server');
|
||||
|
||||
const {
|
||||
FLECKS_CORE_ROOT = process.cwd(),
|
||||
} = process.env;
|
||||
|
||||
const checkIsMonorepo = async () => {
|
||||
try {
|
||||
await stat(join(FLECKS_CORE_ROOT, 'packages'));
|
||||
return true;
|
||||
}
|
||||
catch (error) {
|
||||
if ('ENOENT' !== error.code) {
|
||||
throw error;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const monorepoScope = async () => {
|
||||
try {
|
||||
const {name} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||
const [scope] = name.split('/');
|
||||
return scope;
|
||||
}
|
||||
catch (error) {
|
||||
if ('MODULE_NOT_FOUND' !== error.code) {
|
||||
throw error;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
const target = async (fleck) => {
|
||||
const {errors} = validate(fleck);
|
||||
if (errors) {
|
||||
throw new Error(`@flecks/create-fleck: invalid fleck name: ${errors.join(', ')}`);
|
||||
}
|
||||
const parts = fleck.split('/');
|
||||
let pkg;
|
||||
let scope;
|
||||
if (1 === parts.length) {
|
||||
pkg = fleck;
|
||||
if (await checkIsMonorepo()) {
|
||||
scope = await monorepoScope();
|
||||
}
|
||||
return [scope, pkg];
|
||||
}
|
||||
return parts;
|
||||
};
|
||||
const {
|
||||
npm_config_local_prefix,
|
||||
npm_config_scope,
|
||||
npm_package_json,
|
||||
} = process.env;
|
||||
|
||||
(async () => {
|
||||
program.argument('<fleck>', 'name of the fleck to create');
|
||||
program.argument('[path]', "the path of the fleck (e.g.: 'packages/foobar')");
|
||||
program.option('--no-add', 'do not add an entry to `build/flecks.yml`');
|
||||
program.option('--no-alias', 'do not alias the fleck in `build/flecks.yml`');
|
||||
program.addOption(
|
||||
program.createOption('-pm,--package-manager <binary>', 'package manager binary')
|
||||
.choices(['npm', 'bun', 'pnpm', 'yarn']),
|
||||
);
|
||||
program.action(async (fleck, {alias, add, packageManager}) => {
|
||||
program.option('--no-inherit-version', 'do not inherit root package version');
|
||||
program.option('--alias', 'alias the fleck in `build/flecks.yml`');
|
||||
program.option('--dry-run', 'just say what would be done without actually doing it');
|
||||
program.action(async (
|
||||
path,
|
||||
{
|
||||
alias,
|
||||
add,
|
||||
inheritVersion,
|
||||
packageManager,
|
||||
},
|
||||
) => {
|
||||
try {
|
||||
const isMonorepo = await checkIsMonorepo();
|
||||
const [scope, pkg] = await target(fleck);
|
||||
const name = [scope, pkg].filter((e) => !!e).join('/');
|
||||
const destination = join(
|
||||
join(...[FLECKS_CORE_ROOT].concat(isMonorepo ? ['packages'] : [])),
|
||||
pkg,
|
||||
);
|
||||
if (!await testDestination(destination)) {
|
||||
const error = new Error(
|
||||
`@flecks/create-fleck: destination '${destination} already exists: aborting`,
|
||||
);
|
||||
error.code = 129;
|
||||
throw error;
|
||||
if (!npm_config_local_prefix && !path) {
|
||||
throw new Error('name required');
|
||||
}
|
||||
const root = npm_config_local_prefix || FLECKS_CORE_ROOT;
|
||||
let rootJson;
|
||||
try {
|
||||
rootJson = require(join(root, 'package.json'));
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
catch (error) {}
|
||||
let scope;
|
||||
if (npm_config_scope) {
|
||||
scope = npm_config_scope;
|
||||
}
|
||||
else if (rootJson?.name) {
|
||||
const inferredScope = rootJson.name.split('/')[0] || '';
|
||||
if (inferredScope.startsWith('@')) {
|
||||
scope = inferredScope;
|
||||
}
|
||||
}
|
||||
const local = basename(path || root);
|
||||
const name = scope ? `${scope}/${local}` : local;
|
||||
const fileTree = await move(name, join(__dirname, '..', 'template'));
|
||||
if (isMonorepo) {
|
||||
const {version} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||
if (inheritVersion && rootJson?.version) {
|
||||
// Inherit version from monorepo root.
|
||||
fileTree.pipe(
|
||||
'package.json',
|
||||
transform((chunk, encoding, done, stream) => {
|
||||
stream.push(JSON.stringify({...JSON.parse(chunk), version}));
|
||||
done();
|
||||
}),
|
||||
);
|
||||
const {version} = rootJson;
|
||||
fileTree.pipe('package.json', new JsonStream((json) => ({...json, version})));
|
||||
}
|
||||
// Write the tree.
|
||||
const destination = path ? join(root, path) : dirname(npm_package_json);
|
||||
await fileTree.writeTo(destination);
|
||||
// Install and build.
|
||||
await install({cwd: destination, packageManager});
|
||||
await build({cwd: destination, packageManager});
|
||||
if (isMonorepo && add) {
|
||||
await addPathsToYml([[name].concat(alias ? `./packages/${pkg}` : []).join(':')]);
|
||||
if (add) {
|
||||
const maybeAliasedPath = [name]
|
||||
.concat(alias ? `.${sep}${relative(root, destination)}` : [])
|
||||
.join(':');
|
||||
try {
|
||||
await addPathsToYml([maybeAliasedPath], root);
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
catch (error) {}
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Creation failed:', error);
|
||||
console.error('creation failed:', error);
|
||||
}
|
||||
});
|
||||
await program.parseAsync(process.argv);
|
||||
|
|
|
@ -22,15 +22,15 @@
|
|||
"create-fleck": "./build/cli.js"
|
||||
},
|
||||
"files": [
|
||||
"npm-shrinkwrap.json",
|
||||
"template"
|
||||
],
|
||||
"dependencies": {
|
||||
"@flecks/build": "^4.0.2",
|
||||
"@flecks/core": "^4.0.2",
|
||||
"@flecks/create-app": "^4.0.2",
|
||||
"commander": "11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flecks/build": "^4.0.2",
|
||||
"@flecks/fleck": "^4.0.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
"index.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@flecks/core": "^3.0.0"
|
||||
"@flecks/core": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@flecks/build": "^3.0.0",
|
||||
"@flecks/fleck": "^3.0.0"
|
||||
"@flecks/build": "^4.0.0",
|
||||
"@flecks/fleck": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const {dumpYml} = require('@flecks/build/src/server');
|
||||
const {dumpYml} = require('@flecks/core/src/server');
|
||||
|
||||
const {generateComposeConfig, generateDockerFile} = require('./generate');
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const {banner} = require('@flecks/build/src/server');
|
||||
|
||||
exports.dependencies = ['@flecks/build'];
|
||||
|
||||
exports.hooks = {
|
||||
'@flecks/build.config.alter': ({server}, env, argv, flecks) => {
|
||||
if (server) {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import {Buffer} from 'buffer';
|
||||
import {Transform} from 'stream';
|
||||
|
||||
const {
|
||||
|
@ -14,26 +15,42 @@ class InlineConfig extends Transform {
|
|||
|
||||
constructor(flecks, req) {
|
||||
super();
|
||||
this.buffers = [];
|
||||
this.flecks = flecks;
|
||||
this.req = req;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
async _transform(chunk, encoding, done) {
|
||||
const string = chunk.toString('utf8');
|
||||
async _flush(done) {
|
||||
const string = Buffer.concat(this.buffers).toString();
|
||||
const {appMountId} = this.flecks.get('@flecks/web');
|
||||
const rendered = string.replaceAll(
|
||||
'<body>',
|
||||
[
|
||||
const hideAttributes = 'production' === NODE_ENV ? 'data-flecks="ignore"' : '';
|
||||
this.push(
|
||||
string.replaceAll(
|
||||
'<body>',
|
||||
`<div id="${appMountId}-container">`,
|
||||
`<script${'production' === NODE_ENV ? 'data-flecks="ignore"' : ''}>window.document.querySelector('#${appMountId}-container').style.display = 'none'</script>`,
|
||||
`<script data-flecks="ignore">${await configSource(this.flecks, this.req)}</script>`,
|
||||
`<div id="${appMountId}"></div>`,
|
||||
'</div>',
|
||||
].join(''),
|
||||
/* eslint-disable indent */
|
||||
[
|
||||
'<body>',
|
||||
`<div id="${appMountId}-container">`,
|
||||
`<script${hideAttributes}>`,
|
||||
`window.document.querySelector('#${appMountId}-container').style.display = 'none'`,
|
||||
'</script>',
|
||||
'<script data-flecks="ignore">',
|
||||
await configSource(this.flecks, this.req),
|
||||
'</script>',
|
||||
`<div id="${appMountId}"></div>`,
|
||||
'</div>',
|
||||
].join(''),
|
||||
/* eslint-enable indent */
|
||||
),
|
||||
);
|
||||
this.push(rendered);
|
||||
this.buffers = [];
|
||||
done();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
_transform(chunk, encoding, done) {
|
||||
this.buffers.push(chunk);
|
||||
done();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user