Merge pull request #64 from o-development/feat/auto-generator

Feat/auto generator
main
jaxoncreed 9 months ago committed by GitHub
commit 30b9a4b15d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 129
      package-lock.json
  2. 2
      packages/cli/.gitignore
  3. 11
      packages/cli/README.md
  4. 11
      packages/cli/example-init-placeholder/package.json
  5. 23
      packages/cli/package.json
  6. 93
      packages/cli/src/build.ts
  7. 118
      packages/cli/src/create.ts
  8. 81
      packages/cli/src/generateReadme.ts
  9. 29
      packages/cli/src/index.ts
  10. 47
      packages/cli/src/init.ts
  11. 15
      packages/cli/src/templates/readme/main.ejs
  12. 2
      packages/cli/src/templates/readme/projectIndex.ejs
  13. 27
      packages/cli/src/templates/readme/shape.ejs
  14. 26
      packages/cli/src/util/forAllShapes.ts
  15. 33
      packages/cli/src/util/modifyPackageJson.ts
  16. 19
      packages/cli/test/.shapes/foafProfile.shex
  17. 3
      packages/cli/test/placeholder.test.ts

129
package-lock.json generated

@ -8093,6 +8093,32 @@
"@ts-jison/lexer": "^0.4.1-alpha.1"
}
},
"node_modules/@ts-morph/common": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.25.0.tgz",
"integrity": "sha512-kMnZz+vGGHi4GoHnLmMhGNjm44kGtKUXGnOvrKmMwAuvNjM/PgKVGfUnL7IDvK7Jb2QQ82jq3Zmp04Gy+r3Dkg==",
"license": "MIT",
"dependencies": {
"minimatch": "^9.0.4",
"path-browserify": "^1.0.1",
"tinyglobby": "^0.2.9"
}
},
"node_modules/@ts-morph/common/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"devOptional": true,
@ -8453,7 +8479,9 @@
}
},
"node_modules/@types/jsonld": {
"version": "1.5.13",
"version": "1.5.15",
"resolved": "https://registry.npmjs.org/@types/jsonld/-/jsonld-1.5.15.tgz",
"integrity": "sha512-PlAFPZjL+AuGYmwlqwKEL0IMP8M8RexH0NIPGfCVWSQ041H2rR/8OlyZSD7KsCVoN8vCfWdtWDBxX8yBVP+xow==",
"license": "MIT"
},
"node_modules/@types/keygrip": {
@ -8569,6 +8597,17 @@
"version": "2.7.3",
"license": "MIT"
},
"node_modules/@types/prompts": {
"version": "2.4.9",
"resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz",
"integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"kleur": "^3.0.3"
}
},
"node_modules/@types/prop-types": {
"version": "15.7.11",
"dev": true,
@ -8713,6 +8752,8 @@
},
"node_modules/@types/shexj": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@types/shexj/-/shexj-2.1.4.tgz",
"integrity": "sha512-/dcF8vT/CHseZxNTcWR+otf6018PACgHiKFukPYsxQCRppGZq0UcALMedZUUnj7IM4WOesFoERwJBhEw44d/VQ==",
"dev": true,
"license": "MIT"
},
@ -11031,6 +11072,12 @@
"node": ">=4"
}
},
"node_modules/code-block-writer": {
"version": "13.0.3",
"resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz",
"integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==",
"license": "MIT"
},
"node_modules/codepage": {
"version": "1.15.0",
"dev": true,
@ -21261,6 +21308,12 @@
"tslib": "^2.0.3"
}
},
"node_modules/path-browserify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
"license": "MIT"
},
"node_modules/path-exists": {
"version": "4.0.0",
"license": "MIT",
@ -22759,6 +22812,8 @@
},
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
"integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
"license": "MIT",
"dependencies": {
"kleur": "^3.0.3",
@ -26605,6 +26660,45 @@
"dev": true,
"license": "MIT"
},
"node_modules/tinyglobby": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
"integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
"license": "MIT",
"dependencies": {
"fdir": "^6.4.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/tinyglobby/node_modules/fdir": {
"version": "6.4.2",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
"integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
"license": "MIT",
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/tmp": {
"version": "0.2.1",
"dev": true,
@ -26713,6 +26807,16 @@
"version": "0.1.13",
"license": "Apache-2.0"
},
"node_modules/ts-morph": {
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-24.0.0.tgz",
"integrity": "sha512-2OAOg/Ob5yx9Et7ZX4CvTCc0UFoZHwLEJ+dpDPSUi5TgwwlTlX47w+iFRrEwzUZwYACjq83cgjS/Da50Ga37uw==",
"license": "MIT",
"dependencies": {
"@ts-morph/common": "~0.25.0",
"code-block-writer": "^13.0.3"
}
},
"node_modules/ts-node": {
"version": "10.9.2",
"devOptional": true,
@ -28640,6 +28744,7 @@
"version": "0.0.1-alpha.28",
"license": "MIT",
"dependencies": {
"@ldo/ldo": "^0.0.1-alpha.28",
"@ldo/schema-converter-shex": "^0.0.1-alpha.24",
"@shexjs/parser": "^1.0.0-alpha.24",
"child-process-promise": "^2.2.1",
@ -28647,17 +28752,23 @@
"ejs": "^3.1.8",
"fs-extra": "^10.1.0",
"loading-cli": "^1.1.0",
"prettier": "^3.0.3"
"prettier": "^3.0.3",
"prompts": "^2.4.2",
"ts-morph": "^24.0.0",
"type-fest": "^2.19.0"
},
"bin": {
"ldo": "dist/index.js"
},
"devDependencies": {
"@ldo/cli": "^0.0.1-alpha.28",
"@types/child-process-promise": "^2.2.2",
"@types/ejs": "^3.1.1",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.0.3",
"@types/shexj": "2.1.4",
"@types/jsonld": "^1.5.15",
"@types/prompts": "^2.4.9",
"@types/shexj": "^2.1.4",
"copyfiles": "^2.4.1",
"jest": "^27.4.2",
"rimraf": "^3.0.2",
@ -28726,6 +28837,18 @@
}
}
},
"packages/cli/node_modules/type-fest": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
"license": "(MIT OR CC0-1.0)",
"engines": {
"node": ">=12.20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"packages/cli/node_modules/typescript": {
"version": "4.9.5",
"dev": true,

@ -0,0 +1,2 @@
example-create
example-init

@ -53,9 +53,20 @@ This will generate five files:
- `./ldo/foafProfile.schema.ts`
- `./ldo/foafProfile.context.ts`
## Creating a new project to distribure shapes
Sometimes, you might want to distribute shapes to others. The easiest way to do that is to deploy them to NPM. The LDO CLI has an easy-to-use command for generating a standalone project just for your shapes.
```bash
npx @ldo/cli create ./my-project
```
This script will generate a project with a place to put your shapes. Running `npm publish` will build the shapes and push to project to NPM for you.
## API Details
- [`init` command](https://ldo.js.org/api/cli/init/)
- [`build` command](https://ldo.js.org/api/cli/build/)
- [`create` command](https://ldo.js.org/api/cli/create/)
```
## Sponsorship

@ -0,0 +1,11 @@
{
"name": "example-init",
"version": "1.0.0",
"description": "",
"keywords": [
""
],
"author": "",
"license": "MIT",
"main": "./index.js"
}

@ -7,20 +7,16 @@
"ldo": "./dist/index.js"
},
"scripts": {
"start": "node dist/index.js build",
"start:init": "node dist/index.js init",
"dev": "npm run build && npm run start:init",
"build": "npm run clean && npm run build:ts && npm run copy-files",
"build": "npm run clean && npm run build:ts && npm run copy-files && npm run update-permission",
"build:ts": "tsc --project tsconfig.build.json",
"clean": "rimraf dist/",
"copy-files": "copyfiles -u 1 \"./src/**/*.ejs\" dist/",
"update-permission": "chmod +x ../../node_modules/.bin/ldo",
"watch": "tsc --watch",
"update-permission": "chmod +x ./dist/index.js",
"test": "jest --coverage",
"test:watch": "jest --watch",
"prepublishOnly": "npm run test && npm run build",
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern",
"build:ldo": "./dist/index.js build --input test/.shapes --output test/.ldo"
"test:init": "rm -rf ./example-init && cp -R ./example-init-placeholder ./example-init && cd ./example-init && ../dist/index.js init",
"test:create": "rm -rf ./example-create && ./dist/index.js create ./example-create"
},
"repository": {
"type": "git",
@ -33,17 +29,21 @@
},
"homepage": "https://github.com/o-development/ldobjects/tree/main/packages/cli#readme",
"devDependencies": {
"@ldo/cli": "^0.0.1-alpha.28",
"@types/child-process-promise": "^2.2.2",
"@types/ejs": "^3.1.1",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.0.3",
"@types/shexj": "2.1.4",
"@types/jsonld": "^1.5.15",
"@types/prompts": "^2.4.9",
"@types/shexj": "^2.1.4",
"copyfiles": "^2.4.1",
"jest": "^27.4.2",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.7"
},
"dependencies": {
"@ldo/ldo": "^0.0.1-alpha.28",
"@ldo/schema-converter-shex": "^0.0.1-alpha.24",
"@shexjs/parser": "^1.0.0-alpha.24",
"child-process-promise": "^2.2.1",
@ -51,7 +51,10 @@
"ejs": "^3.1.8",
"fs-extra": "^10.1.0",
"loading-cli": "^1.1.0",
"prettier": "^3.0.3"
"prettier": "^3.0.3",
"prompts": "^2.4.2",
"ts-morph": "^24.0.0",
"type-fest": "^2.19.0"
},
"files": [
"dist",

@ -6,6 +6,7 @@ import schemaConverterShex from "@ldo/schema-converter-shex";
import { renderFile } from "ejs";
import prettier from "prettier";
import loading from "loading-cli";
import { forAllShapes } from "./util/forAllShapes";
interface BuildOptions {
input: string;
@ -15,13 +16,6 @@ interface BuildOptions {
export async function build(options: BuildOptions) {
const load = loading("Peparing Environment");
load.start();
const shapeDir = await fs.promises.readdir(options.input, {
withFileTypes: true,
});
// Filter out non-shex documents
const shexFiles = shapeDir.filter(
(file) => file.isFile() && file.name.endsWith(".shex"),
);
// Prepare new folder by clearing/and/or creating it
if (fs.existsSync(options.output)) {
await fs.promises.rm(options.output, { recursive: true });
@ -29,51 +23,44 @@ export async function build(options: BuildOptions) {
await fs.promises.mkdir(options.output);
load.text = "Generating LDO Documents";
await Promise.all(
shexFiles.map(async (file) => {
const fileName = path.parse(file.name).name;
// Get the content of each document
const shexC = await fs.promises.readFile(
path.join(options.input, file.name),
"utf8",
);
// Convert to ShexJ
let schema: Schema;
try {
schema = parser.construct("https://ldo.js.org/").parse(shexC);
} catch (err) {
const errMessage =
err instanceof Error
? err.message
: typeof err === "string"
? err
: "Unknown Error";
console.error(`Error processing ${file.name}: ${errMessage}`);
return;
}
// Convert the content to types
const [typings, context] = await schemaConverterShex(schema);
await Promise.all(
["context", "schema", "shapeTypes", "typings"].map(
async (templateName) => {
const finalContent = await renderFile(
path.join(__dirname, "./templates", `${templateName}.ejs`),
{
typings: typings.typings,
fileName,
schema: JSON.stringify(schema, null, 2),
context: JSON.stringify(context, null, 2),
},
);
// Save conversion to document
await fs.promises.writeFile(
path.join(options.output, `${fileName}.${templateName}.ts`),
await prettier.format(finalContent, { parser: "typescript" }),
);
},
),
);
}),
);
await forAllShapes(options.input, async (fileName, shexC) => {
// Convert to ShexJ
let schema: Schema;
try {
schema = parser.construct("https://ldo.js.org/").parse(shexC);
} catch (err) {
const errMessage =
err instanceof Error
? err.message
: typeof err === "string"
? err
: "Unknown Error";
console.error(`Error processing ${fileName}: ${errMessage}`);
return;
}
// Convert the content to types
const [typings, context] = await schemaConverterShex(schema);
await Promise.all(
["context", "schema", "shapeTypes", "typings"].map(
async (templateName) => {
const finalContent = await renderFile(
path.join(__dirname, "./templates", `${templateName}.ejs`),
{
typings: typings.typings,
fileName,
schema: JSON.stringify(schema, null, 2),
context: JSON.stringify(context, null, 2),
},
);
// Save conversion to document
await fs.promises.writeFile(
path.join(options.output, `${fileName}.${templateName}.ts`),
await prettier.format(finalContent, { parser: "typescript" }),
);
},
),
);
});
load.stop();
}

@ -0,0 +1,118 @@
import { init } from "./init";
import { modifyPackageJson, savePackageJson } from "./util/modifyPackageJson";
import { generateReadme } from "./generateReadme";
import path from "path";
import prompts from "prompts";
import type { PackageJson } from "type-fest";
import loading from "loading-cli";
import { promises as fs } from "fs";
import { renderFile } from "ejs";
export async function create(directory: string) {
// Init the NPM Package
const responses = await prompts([
{
type: "text",
name: "name",
message: "Package name:",
initial: path.basename(directory),
},
{
type: "text",
name: "version",
message: "Version:",
initial: "1.0.0",
},
{
type: "text",
name: "description",
message: "Description:",
},
{
type: "list",
name: "keywords",
message: "Keywords (comma separated):",
separator: ",",
},
{
type: "text",
name: "author",
message: "Author:",
},
{
type: "text",
name: "license",
message: "License:",
initial: "MIT",
},
{
type: "text",
name: "repository",
message: "Git repository (optional):",
},
]);
const load = loading("Generating package.json");
const packageJson: PackageJson = {
name: responses.name,
version: responses.version,
description: responses.description,
keywords: responses.keywords,
author: responses.author,
license: responses.license,
main: "./index.js",
};
if (responses.repository) {
packageJson.repository = {
type: "git",
url: responses.repository,
};
packageJson.bugs = {
url: `${responses.repository.replace(/\.git$/, "")}/issues`,
};
packageJson.homepage = `${responses.repository.replace(
/\.git$/,
"",
)}#readme`;
}
await savePackageJson(directory, packageJson);
// Init LDO
load.text = "Initializing LDO";
await init(directory);
// Add prepublish script
await modifyPackageJson(directory, async (packageJson) => {
if (!packageJson.scripts) packageJson.scripts = {};
packageJson.scripts.prepublish =
"npm run build:ldo & npm run generate-readme";
packageJson.scripts[
"genenerate-readme"
] = `ldo generate-readme --project ./ --shapes ./.shapes --ldo ./.ldo`;
return packageJson;
});
// Create index.js
load.text = "Generating index.js";
const ldoDir = await fs.readdir(path.join(directory, "./.ldo"), {
withFileTypes: true,
});
const indexText = await renderFile(
path.join(__dirname, "./templates/readme/projectIndex.ejs"),
{ fileNames: ldoDir.map((file) => file.name) },
);
await fs.writeFile(path.join(directory, "index.js"), indexText);
// Generate ReadMe
load.text = "Generating README";
await generateReadme({
project: directory,
shapes: path.join(directory, ".shapes"),
ldo: path.join(directory, ".ldo"),
});
load.stop();
}

@ -0,0 +1,81 @@
import { getPackageJson } from "./util/modifyPackageJson";
import { forAllShapes } from "./util/forAllShapes";
import { promises as fs } from "fs";
import path from "path";
import { Project } from "ts-morph";
import { renderFile } from "ejs";
interface GenerateReadmeOptions {
project: string;
shapes: string;
ldo: string;
}
interface ReadmeEjsOptions {
projectName: string;
projectDescription: string;
shapes: {
name: string;
types: {
typeName: string;
shapeTypeName: string;
}[];
shex: string;
typescript: string;
}[];
}
export async function generateReadme(options: GenerateReadmeOptions) {
const packageJson = await getPackageJson(options.project);
const projectName = packageJson.name!;
const projectDescription = packageJson.description!;
const shapes: ReadmeEjsOptions["shapes"] = [];
await forAllShapes(options.shapes, async (fileName, shexC) => {
const typeFilePath = path.join(options.ldo, `${fileName}.typings.ts`);
const typesRaw = await fs.readFile(typeFilePath, "utf8");
const shape: ReadmeEjsOptions["shapes"][0] = {
name: fileName,
shex: shexC,
typescript: typesRaw,
types: [],
};
listInterfaces(typeFilePath).forEach((interfaceName) => {
shape.types.push({
typeName: interfaceName,
shapeTypeName: `${interfaceName}ShapeType`,
});
});
shapes.push(shape);
});
const readmeEjsOptions: ReadmeEjsOptions = {
projectName,
projectDescription,
shapes,
};
// Save Readme
const finalContent = await renderFile(
path.join(__dirname, "./templates/readme/", "main.ejs"),
readmeEjsOptions,
);
// Save readme to document
await fs.writeFile(path.join(options.project, "README.md"), finalContent);
}
/**
* Helper Function that lists all the interfaces in a typescript file
*/
function listInterfaces(filePath: string): string[] {
const project = new Project();
const sourceFile = project.addSourceFileAtPath(filePath);
// Get all interfaces in the file
const interfaces = sourceFile.getInterfaces().map((iface) => iface.getName());
return interfaces;
}

@ -3,6 +3,7 @@
import { program } from "commander";
import { build } from "./build";
import { init } from "./init";
import { create } from "./create";
program
.name("LDO-CLI")
@ -18,8 +19,34 @@ program
program
.command("init")
.option("-d --directory>", "A parent directory for ldo files")
.argument("[directory]", "A parent directory for ldo files")
.description("Initializes a project for LDO.")
.action(init);
program
.command("create")
.argument("<directory>", "The package's directory")
.description("Creates a standalone package for shapes to publish to NPM.")
.action(create);
program
.command("generate-readme")
.description("Create a ReadMe from the shapes and generated code.")
.requiredOption(
"-r, --readme <readmePath>",
"Provide the path to the readme",
"./.shapes",
)
.requiredOption(
"-s, --shapes <shapesPath>",
"Provide the path to the shapes folder",
"./.shapes",
)
.requiredOption(
"-s, --ldo <ldoPath>",
"Provide the path to the ldo folder",
"./.ldo",
)
.action(build);
program.parse();

@ -2,22 +2,15 @@ import { exec } from "child-process-promise";
import fs from "fs-extra";
import path from "path";
import { renderFile } from "ejs";
import { modifyPackageJson } from "./util/modifyPackageJson";
const DEFAULT_SHAPES_FOLDER = "./.shapes";
const DEFAULT_LDO_FOLDER = "./.ldo";
const POTENTIAL_PARENT_DIRECTORIES = ["src", "lib", "bin"];
export interface InitOptions {
directory?: string;
}
export async function init(initOptions: InitOptions) {
// Install dependencies
await exec("npm install @ldo/ldo --save");
await exec("npm install @ldo/cli @types/shexj @types/jsonld --save-dev");
export async function init(directory?: string) {
// Find folder to save to
let parentDirectory = initOptions.directory;
let parentDirectory = directory!;
if (!parentDirectory) {
parentDirectory = "./";
const allDirectories = (
@ -37,6 +30,12 @@ export async function init(initOptions: InitOptions) {
}
}
// Install dependencies
await exec(`cd ${parentDirectory} && npm install @ldo/ldo --save`);
await exec(
`cd ${parentDirectory} && npm install @ldo/cli @types/shexj @types/jsonld --save-dev`,
);
// Create "shapes" folder
const shapesFolderPath = path.join(parentDirectory, DEFAULT_SHAPES_FOLDER);
await fs.promises.mkdir(shapesFolderPath);
@ -57,22 +56,18 @@ export async function init(initOptions: InitOptions) {
);
// Add build script
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const packageJson: any = JSON.parse(
(await fs.promises.readFile("./package.json")).toString(),
);
if (!packageJson.scripts) {
packageJson.scripts = {};
}
const ldoFolder = path.join(parentDirectory, DEFAULT_LDO_FOLDER);
packageJson.scripts[
"build:ldo"
] = `ldo build --input ${shapesFolderPath} --output ${ldoFolder}`;
await fs.promises.writeFile(
"./package.json",
JSON.stringify(packageJson, null, 2),
);
await modifyPackageJson(parentDirectory, async (packageJson) => {
if (!packageJson.scripts) {
packageJson.scripts = {};
}
const ldoFolder = path.join(parentDirectory, DEFAULT_LDO_FOLDER);
packageJson.scripts["build:ldo"] = `ldo build --input ${path.relative(
parentDirectory,
shapesFolderPath,
)} --output ${path.relative(parentDirectory, ldoFolder)}`;
return packageJson;
});
// Build LDO
await exec("npm run build:ldo");
await exec(`cd ${parentDirectory} && npm run build:ldo`);
}

@ -0,0 +1,15 @@
# <%= projectName %>
<%- projectDescription %>
This project includes shapes and generated files for [LDO](https://ldo.js.org).
## Installation
```bash
npm i <%= projectName %>
```
<% shapes.forEach(function(shape) { %>
<%- include('shape', { shape: shape, projectName: projectName }) %>
<% }); %>

@ -0,0 +1,2 @@
<% fileNames.forEach((fileName) => { %>export * from "./.ldo/<%- fileName %>";
<% }); %>

@ -0,0 +1,27 @@
## <%= shape.name %>
### Usage with LDO
```typescript
import { createLdoDataset } from "@ldo/ldo";
import { <%= shape.types.map((type) => type.shapeTypeName).join(", ") %> } from "<%= projectName %>";
import type { <%= shape.types.map((type) => type.typeName).join(", ") %> } from "<%= projectName %>";
const ldoDataset = createLdoDataset();
<% shape.types.forEach(function(type, index) { %>
const example<%= index %>: <%= type.typeName %> = ldoDataset
.usingType(<%= type.shapeTypeName %>)
.fromSubject("http://example.com/example<%= index %>");
<% }); %>
```
### ShEx Typings
```shex
<%- shape.shex %>
```
### TypeScript Typings
```typescript
<%- shape.typescript %>
```

@ -0,0 +1,26 @@
import fs from "fs";
import path from "path";
export async function forAllShapes(
shapePath: string,
callback: (filename: string, shape: string) => Promise<void>,
): Promise<void> {
const shapeDir = await fs.promises.readdir(shapePath, {
withFileTypes: true,
});
// Filter out non-shex documents
const shexFiles = shapeDir.filter(
(file) => file.isFile() && file.name.endsWith(".shex"),
);
await Promise.all(
shexFiles.map(async (file) => {
const fileName = path.parse(file.name).name;
// Get the content of each document
const shexC = await fs.promises.readFile(
path.join(shapePath, file.name),
"utf8",
);
await callback(fileName, shexC);
}),
);
}

@ -0,0 +1,33 @@
import type { PackageJson } from "type-fest";
import fs from "fs-extra";
import path from "path";
export async function getPackageJson(
projectFolder: string,
): Promise<PackageJson> {
return JSON.parse(
(
await fs.promises.readFile(path.join(projectFolder, "./package.json"))
).toString(),
);
}
export async function savePackageJson(
projectFolder: string,
packageJson: PackageJson,
): Promise<void> {
await fs.promises.mkdir(projectFolder, { recursive: true });
await fs.promises.writeFile(
path.join(projectFolder, "./package.json"),
JSON.stringify(packageJson, null, 2),
);
}
export async function modifyPackageJson(
projectFolder: string,
modifyCallback: (packageJson: PackageJson) => Promise<PackageJson>,
): Promise<void> {
const packageJson: PackageJson = await getPackageJson(projectFolder);
const newPackageJson = await modifyCallback(packageJson);
await savePackageJson(projectFolder, newPackageJson);
}

@ -1,19 +0,0 @@
# This shape is provided by default as an example
# You can create your own shape to fit your needs using ShEx (https://shex.io)
# Also check out https://shaperepo.com for examples of more shapes.
PREFIX ex: <https://example.com/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
ex:FoafProfile EXTRA a {
a [ foaf:Person ]
// rdfs:comment "Defines the node as a Person (from foaf)" ;
foaf:name xsd:string ?
// rdfs:comment "Define a person's name." ;
foaf:img xsd:string ?
// rdfs:comment "Photo link but in string form"
foaf:knows @ex:FoafProfile *
// rdfs:comment "A list of WebIds for all the people this user knows." ;
}

@ -1,3 +0,0 @@
it("placeholder", () => {
expect(true).toBe(true);
});
Loading…
Cancel
Save