parent
1db769103f
commit
e0520c0d08
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@ |
||||
{ |
||||
"extends": ["../../eslintrc"] |
||||
} |
@ -0,0 +1,26 @@ |
||||
# LDO-CLI |
||||
|
||||
A command line interface for Linked Data Objects. LDO-CLI builds `.shex` shapes into LDO types. |
||||
|
||||
## Setup |
||||
Install the CLI |
||||
|
||||
```bash |
||||
npm i ldo-cli --save-dev |
||||
``` |
||||
|
||||
Set up a shapes folder |
||||
```bash |
||||
mkdir shapes |
||||
``` |
||||
|
||||
Place ShexC shapes inside `.shex` files |
||||
|
||||
```bash |
||||
touch ./shapes/example.shex |
||||
``` |
||||
|
||||
Build the shpaes |
||||
```bash |
||||
ldo build --input ./shapes --output ./ldo |
||||
``` |
@ -0,0 +1,5 @@ |
||||
const sharedConfig = require('../../jest.config.js'); |
||||
module.exports = { |
||||
...sharedConfig, |
||||
'rootDir': './', |
||||
} |
@ -0,0 +1,54 @@ |
||||
{ |
||||
"name": "@ldo/cli", |
||||
"version": "0.0.0", |
||||
"description": "A Command Line Interface for Linked Data Objects", |
||||
"main": "./dist/index.js", |
||||
"bin": { |
||||
"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 && 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", |
||||
"test": "jest --coverage", |
||||
"test:watch": "jest --watch", |
||||
"prepublishOnly": "npm run test && npm run build", |
||||
"postinstall": "npm run build" |
||||
}, |
||||
"repository": { |
||||
"type": "git", |
||||
"url": "git+https://github.com/o-development/ldo-cli.git" |
||||
}, |
||||
"author": "Jackson Morgan", |
||||
"license": "MIT", |
||||
"bugs": { |
||||
"url": "https://github.com/o-development/ldo-cli/issues" |
||||
}, |
||||
"homepage": "https://github.com/o-development/ldo-cli#readme", |
||||
"devDependencies": { |
||||
"@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", |
||||
"copyfiles": "^2.4.1", |
||||
"jest": "^27.4.2", |
||||
"rimraf": "^3.0.2", |
||||
"ts-jest": "^27.0.7" |
||||
}, |
||||
"dependencies": { |
||||
"@shexjs/parser": "^1.0.0-alpha.24", |
||||
"child-process-promise": "^2.2.1", |
||||
"commander": "^9.3.0", |
||||
"ejs": "^3.1.8", |
||||
"fs-extra": "^10.1.0", |
||||
"loading-cli": "^1.1.0", |
||||
"shexj2typeandcontext": "^2.0.0" |
||||
} |
||||
} |
@ -0,0 +1,69 @@ |
||||
import fs from "fs-extra"; |
||||
import path from "path"; |
||||
import { Schema } from "shexj"; |
||||
import parser from "@shexjs/parser"; |
||||
import shexjToTypeAndContext from "shexj2typeandcontext"; |
||||
import { renderFile } from "ejs"; |
||||
import prettier from "prettier"; |
||||
import loading from "loading-cli"; |
||||
|
||||
interface BuildOptions { |
||||
input: string; |
||||
output: string; |
||||
} |
||||
|
||||
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 }); |
||||
} |
||||
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
|
||||
const schema: Schema = parser |
||||
.construct("https://ldo.js.org/") |
||||
.parse(shexC); |
||||
// Convert the content to types
|
||||
const [typings, context] = await shexjToTypeAndContext(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,25 @@ |
||||
#!/usr/bin/env node |
||||
|
||||
import { program } from "commander"; |
||||
import { build } from "./build"; |
||||
import { init } from "./init"; |
||||
|
||||
program |
||||
.name("LDO-CLI") |
||||
.description("CLI to some JavaScript string utilities") |
||||
.version("3.0.1"); |
||||
|
||||
program |
||||
.command("build") |
||||
.description("Build a shex folder into Shape Types") |
||||
.option("-i, --input <inputPath>", "Provide the input path", "./shapes") |
||||
.option("-o, --output <outputPath>", "Provide the output path", "./ldo") |
||||
.action(build); |
||||
|
||||
program |
||||
.command("init") |
||||
.option("-d --directory>", "A parent directory for ldo files") |
||||
.description("Initializes a project for ldo") |
||||
.action(init); |
||||
|
||||
program.parse(); |
@ -0,0 +1,78 @@ |
||||
import { exec } from "child-process-promise"; |
||||
import fs from "fs-extra"; |
||||
import path from "path"; |
||||
import { renderFile } from "ejs"; |
||||
|
||||
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 --save"); |
||||
await exec("npm install ldo-cli @types/shexj @types/jsonld --save-dev"); |
||||
|
||||
// Find folder to save to
|
||||
let parentDirectory = initOptions.directory; |
||||
if (!parentDirectory) { |
||||
parentDirectory = "./"; |
||||
const allDirectories = ( |
||||
await fs.promises.readdir("./", { |
||||
withFileTypes: true, |
||||
}) |
||||
).filter((file) => file.isDirectory()); |
||||
for (let i = 0; i < POTENTIAL_PARENT_DIRECTORIES.length; i++) { |
||||
if ( |
||||
allDirectories.some( |
||||
(dir) => dir.name === POTENTIAL_PARENT_DIRECTORIES[i] |
||||
) |
||||
) { |
||||
parentDirectory = POTENTIAL_PARENT_DIRECTORIES[i]; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Create "shapes" folder
|
||||
const shapesFolderPath = path.join(parentDirectory, DEFAULT_SHAPES_FOLDER); |
||||
await fs.promises.mkdir(shapesFolderPath); |
||||
const defaultShapePaths = await fs.promises.readdir( |
||||
path.join(__dirname, "./templates/defaultShapes") |
||||
); |
||||
await Promise.all( |
||||
defaultShapePaths.map(async (shapePath) => { |
||||
const shapeContent = await renderFile( |
||||
path.join(__dirname, "./templates/defaultShapes", shapePath), |
||||
{} |
||||
); |
||||
await fs.promises.writeFile( |
||||
path.join(shapesFolderPath, `${path.parse(shapePath).name}.shex`), |
||||
shapeContent |
||||
); |
||||
}) |
||||
); |
||||
|
||||
// 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) |
||||
); |
||||
|
||||
// Build LDO
|
||||
await exec("npm run build:ldo"); |
||||
} |
@ -0,0 +1,8 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* <%- fileName %>Context: JSONLD Context for <%- fileName %> |
||||
* ============================================================================= |
||||
*/ |
||||
export const <%- fileName %>Context: ContextDefinition = <%- context %>; |
@ -0,0 +1,19 @@ |
||||
# 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." ; |
||||
} |
@ -0,0 +1,8 @@ |
||||
import { Schema } from "shexj"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* <%- fileName %>Schema: ShexJ Schema for <%- fileName %> |
||||
* ============================================================================= |
||||
*/ |
||||
export const <%- fileName %>Schema: Schema = <%- schema %>; |
@ -0,0 +1,24 @@ |
||||
import { ShapeType } from "ldo"; |
||||
import { <%- fileName %>Schema } from "./<%- fileName %>.schema"; |
||||
import { <%- fileName %>Context } from "./<%- fileName %>.context"; |
||||
import { |
||||
<% typings.forEach((typing) => { -%> |
||||
<%- typing.dts.name %>, |
||||
<% }); -%>} from "./<%- fileName %>.typings"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* LDO ShapeTypes <%- fileName %> |
||||
* ============================================================================= |
||||
*/ |
||||
<% typings.forEach((typing) => { -%> |
||||
|
||||
/** |
||||
* <%- typing.dts.name %> ShapeType |
||||
*/ |
||||
export const <%- typing.dts.name %>ShapeType: ShapeType<<%- typing.dts.name %>> = { |
||||
schema: <%- fileName %>Schema, |
||||
shape: "<%- typing.dts.shapeId %>", |
||||
context: <%- fileName %>Context, |
||||
}; |
||||
<% }); -%> |
@ -0,0 +1,14 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for <%- fileName %> |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
<% typings.forEach((typing) => { -%> |
||||
/** |
||||
* <%- typing.dts.name %> Type |
||||
*/ |
||||
export <%- typing.typingString -%> |
||||
<% }); -%> |
@ -0,0 +1,3 @@ |
||||
it("placeholder", () => { |
||||
expect(true).toBe(true); |
||||
}); |
@ -0,0 +1,7 @@ |
||||
{ |
||||
"extends": "../../tsconfig.base.json", |
||||
"compilerOptions": { |
||||
"outDir": "./dist" |
||||
}, |
||||
"include": ["./src"] |
||||
} |
Loading…
Reference in new issue