commit
30b9a4b15d
@ -0,0 +1,2 @@ |
||||
example-create |
||||
example-init |
@ -0,0 +1,11 @@ |
||||
{ |
||||
"name": "example-init", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"keywords": [ |
||||
"" |
||||
], |
||||
"author": "", |
||||
"license": "MIT", |
||||
"main": "./index.js" |
||||
} |
@ -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; |
||||
} |
@ -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…
Reference in new issue