Skip to content

Commit

Permalink
Merge pull request #1083 from neon-bindings/create-namespaced-lib
Browse files Browse the repository at this point in the history
feature(create-neon): namespaced libraries
  • Loading branch information
dherman authored Nov 20, 2024
2 parents 323450a + ac53ea1 commit 7780a2f
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 37 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

{
"name": "{{options.name}}",
"name": "{{options.fullName}}",
"version": "{{options.version}}",
"main": "index.node",
"scripts": {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

{
"name": "{{options.name}}",
"name": "{{options.fullName}}",
"version": "{{options.version}}",
{{#eq options.library.module compare="esm"}}
"exports": {
Expand Down Expand Up @@ -28,6 +28,9 @@
{{#if options.library.cache.org}}
"org": "{{options.library.cache.org}}",
{{/if}}
{{#if options.library.cache.prefix}}
"prefix": "{{options.library.cache.prefix}}",
{{/if}}
{{/eq}}
"platforms": {},
"load": "./src/load.cts"
Expand Down
4 changes: 2 additions & 2 deletions pkgs/create-neon/data/versions.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"neon": "1",
"neonCLI": "0.1.73",
"neonLoad": "0.1.73",
"neonCLI": "0.1.82",
"neonLoad": "0.1.82",
"typescript": "5.3.3",
"typesNode": "20.11.16",
"tsconfigNode": {
Expand Down
4 changes: 2 additions & 2 deletions pkgs/create-neon/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-neon",
"version": "0.5.2",
"version": "0.6.0",
"description": "Create Neon projects with no build configuration.",
"type": "module",
"exports": "./dist/src/bin/create-neon.js",
Expand Down Expand Up @@ -48,7 +48,7 @@
"typescript": "^5.3.2"
},
"dependencies": {
"@neon-rs/manifest": "^0.1.0",
"@neon-rs/manifest": "^0.2.1",
"chalk": "^5.3.0",
"command-line-args": "^5.2.1",
"command-line-usage": "^7.0.1",
Expand Down
56 changes: 47 additions & 9 deletions pkgs/create-neon/src/bin/create-neon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,24 @@ try {
}

const [pkg] = opts._unknown;
const { org, basename } = /^((?<org>@[^/]+)\/)?(?<basename>.*)/.exec(pkg)
?.groups as {
org?: string;
basename: string;
};
const fullName = org ? pkg : basename;
const platforms = parsePlatforms(opts.platform);
const cache = parseCache(opts.lib, opts.bins, pkg);
const cache = parseCache(opts.lib, opts.bins, basename, org);
const ci = parseCI(opts.ci);

if (opts.yes) {
process.env["npm_configure_yes"] = "true";
}

createNeon({
name: pkg,
org,
basename,
fullName,
version: "0.1.0",
library: opts.lib
? {
Expand Down Expand Up @@ -112,21 +120,51 @@ function parseCI(ci: string): CI | undefined {
function parseCache(
lib: boolean,
bins: string,
pkg: string
pkg: string,
org: string | undefined
): Cache | undefined {
if (bins === "none") {
return lib ? new NPM(pkg) : undefined;
const defaultPrefix = org ? `${pkg}-` : "";
org ??= `@${pkg}`;
// CASE: npm create neon -- --app logos-r-us
// CASE: npm create neon -- --app @acme/logos-r-us
// - <no binaries cache>
if (bins === "none" && !lib) {
return undefined;
}
if (bins === "npm") {
return new NPM(pkg);
// CASE: npm create neon -- --lib logo-generator
// CASE: npm create neon -- --lib --bins npm logo-generator
// - lib: `logo-generator`
// - bin: `@logo-generator/darwin-arm64`
// CASE: npm create neon -- --lib @acme/logo-generator
// CASE: npm create neon -- --lib --bins npm @acme/logo-generator
// - lib: `@acme/logo-generator`
// - bin: `@acme/logo-generator-darwin-arm64`
if (bins === "none" || bins === "npm") {
return new NPM(org, defaultPrefix);
}
// CASE: npm create neon -- --lib --bins=npm:acme logo-generator
// lib: logo-generator
// bin: @acme/logo-generator-darwin-arm64
// CASE: npm create neon -- --lib --bins=npm:acme/libs-logo-generator- logo-generator
// lib: logo-generator
// bin: @acme/libs-logo-generator-darwin-arm64
// CASE: npm create neon -- --lib --bins=npm:acme-libs @acme/logo-generator
// lib: @acme-libs/logo-generator
// bin: @acme-libs/logo-generator-darwin-arm64
if (bins.startsWith("npm:")) {
return new NPM(pkg, bins.substring(4));
const split = bins.substring(4).split("/", 2);
const org = split[0].replace(/^@?/, "@"); // don't care if they include the @ or not
const prefix = split.length > 1 ? split[1] : defaultPrefix;
return new NPM(org, prefix);
}
throw new Error(
`Unrecognized binaries cache ${bins}, expected 'npm[:org]' or 'none'`
`Unrecognized binaries cache ${bins}, expected 'npm[:org[/prefix]]' or 'none'`
);
}
11 changes: 4 additions & 7 deletions pkgs/create-neon/src/cache/npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import { Cache } from "../cache.js";

export class NPM implements Cache {
readonly org: string;
readonly prefix: string;

readonly type: string = "npm";

constructor(pkg: string, org?: string) {
this.org = org || NPM.inferOrg(pkg);
}

static inferOrg(pkg: string): string {
const m = pkg.match(/^@([^/]+)\/(.*)/);
return `@${m?.[1] ?? pkg}`;
constructor(org: string, prefix: string) {
this.org = org;
this.prefix = prefix;
}
}
12 changes: 7 additions & 5 deletions pkgs/create-neon/src/create/creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ export type LibraryOptions = {
};

export type ProjectOptions = {
name: string;
org?: string | undefined;
basename: string;
fullName: string;
version: string;
library: LibraryOptions | null;
app: boolean | null;
Expand Down Expand Up @@ -64,12 +66,12 @@ export abstract class Creator {
async create(cx: Context): Promise<void> {
try {
this._temp = await mktemp();
this._tempPkg = path.join(this._temp, this._options.name);
this._tempPkg = path.join(this._temp, this._options.basename);

await fs.mkdir(this._tempPkg);
} catch (err: any) {
await die(
`Could not create \`${this._options.name}\`: ${err.message}`,
`Could not create \`${this._options.basename}\`: ${err.message}`,
this._temp
);
}
Expand Down Expand Up @@ -122,11 +124,11 @@ export abstract class Creator {
await this.createNeonBoilerplate(cx);

try {
await fs.rename(this._tempPkg, this._options.name);
await fs.rename(this._tempPkg, this._options.basename);
await fs.rmdir(this._temp);
} catch (err: any) {
await die(
`Could not create \`${this._options.name}\`: ${err.message}`,
`Could not create \`${this._options.basename}\`: ${err.message}`,
this._tempPkg
);
}
Expand Down
25 changes: 19 additions & 6 deletions pkgs/create-neon/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,23 @@ async function askProjectType(options: ProjectOptions) {

const org =
cache === "npm"
? (
await dialog.ask({
prompt: "cache org",
parse: (v: string): string => v,
default: options.org ?? `@${options.basename}`,
})
).replace(/^@?/, "@") // don't care if they include the @ or not
: null;

const prefix =
cache === "npm" && org === `@${options.basename}`
? ""
: cache === "npm"
? await dialog.ask({
prompt: "cache org",
prompt: "cache prefix",
parse: (v: string): string => v,
default: NPM.inferOrg(options.name),
default: `${options.basename}-`,
})
: null;

Expand All @@ -76,7 +89,7 @@ async function askProjectType(options: ProjectOptions) {
options.library = {
lang: Lang.TS,
module: ModuleType.ESM,
cache: cache === "npm" ? new NPM(options.name, org!) : undefined,
cache: cache === "npm" ? new NPM(org!, prefix!) : undefined,
ci: ci === "github" ? new GitHub() : undefined,
platforms: platforms.length === 1 ? platforms[0] : platforms,
};
Expand All @@ -88,9 +101,9 @@ async function askProjectType(options: ProjectOptions) {

export async function createNeon(options: ProjectOptions): Promise<void> {
try {
await assertCanMkdir(options.name);
await assertCanMkdir(options.basename);
} catch (err: any) {
await die(`Could not create \`${options.name}\`: ${err.message}`);
await die(`Could not create \`${options.basename}\`: ${err.message}`);
}

const cx = new Context(options);
Expand All @@ -113,6 +126,6 @@ export async function createNeon(options: ProjectOptions): Promise<void> {
await creator.create(cx);

console.log(
`✨ Created Neon project \`${options.name}\`. Happy 🦀 hacking! ✨`
`✨ Created Neon project \`${options.fullName}\`. Happy 🦀 hacking! ✨`
);
}
41 changes: 41 additions & 0 deletions pkgs/create-neon/test/create-neon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe("Command-line argument validation", () => {
});

const PROJECT = "create-neon-test-project";
const NAMESPACED_PROJECT = "@dherman/create-neon-test-project";

describe("Project creation", () => {
afterEach(async () => {
Expand Down Expand Up @@ -182,6 +183,46 @@ describe("Project creation", () => {

assert.strictEqual(json.neon.type, "library");
assert.strictEqual(json.neon.org, "@create-neon-test-project");
assert.notProperty(json.neon, "prefix");
assert.strictEqual(json.neon.platforms, "common");
assert.strictEqual(json.neon.load, "./src/load.cts");

TOML.parse(
await fs.readFile(path.join(PROJECT, "Cargo.toml"), { encoding: "utf8" })
);
});

it("asks for a prefix when Neon lib is namespaced", async () => {
try {
await expect(spawn(NODE, [CREATE_NEON, NAMESPACED_PROJECT]), {
"neon project type": "lib",
"neon target platforms": "",
"neon binary cache": "",
"neon cache org": "",
"neon cache prefix": "",
"neon ci provider": "",
"package name:": "",
"version:": "",
"description:": "",
"git repository:": "",
"keywords:": "",
"author:": "",
"license:": "",
"Is this OK?": "",
});
} catch (error: any) {
assert.fail("create-neon unexpectedly failed: " + error.message);
}

let json = JSON.parse(
await fs.readFile(path.join(PROJECT, "package.json"), {
encoding: "utf8",
})
);

assert.strictEqual(json.neon.type, "library");
assert.strictEqual(json.neon.org, "@dherman");
assert.strictEqual(json.neon.prefix, "create-neon-test-project-");
assert.strictEqual(json.neon.platforms, "common");
assert.strictEqual(json.neon.load, "./src/load.cts");

Expand Down

0 comments on commit 7780a2f

Please sign in to comment.