pkg-json / package-json

Spec for package.json
269 stars 3 forks source link

Format #1

Open jamiebuilds opened 6 years ago

jamiebuilds commented 6 years ago

How should we document everything?

orta commented 6 years ago

There’s JSON schema? I assume Microsoft is already trying to do this for a ‘package.json’ - so could build on that?

http://json-schema.org

montogeek commented 6 years ago

He means spec format, I vote for Markdown.

fathyb commented 6 years ago

WebIDL is overkill for plain JSON values, Bikeshed looks great though!

mohsen1 commented 6 years ago

Do any of the options have a way of generating JSON Schema?

devongovett commented 6 years ago

Markdown is probably the easiest and is likely sufficient for what we're doing here. I don't have experience with the others though so not sure.

j-f1 commented 6 years ago

Once the spec has been parsed, it should be fairly easy to generate various outputs from it, as I attempt to do in this Observable notebook.

PEG.js grammar
The only modification needed to the spec text ([permalink](https://raw.githubusercontent.com/pkg-json/package.json/4da82ebf1a503f6b0ea00d39f4217bc4990cf48e/SPEC.md)) was to wrap the last line of the spec in a “Rules” block. (i.e. prepend #### Rules\n\n*  to the last line) To hack on or improve the parser, I’d suggest visiting [the online playground](https://pegjs.org/online) for PEG.js. ```js { function slugify(str) { return str.toLowerCase().replace(/[^a-z]+/g, '-').replace(/^-|-$/g, '') } } Spec = title: H1 intro: Line '\n\n' toc: (TOC '\n')+ '\n' sections: Section+ {return { title, intro, toc: toc.map(([line]) => line), sections, }} TOC = indent: ' '* [*-] ' [' label: $ [^\]]+ '](#' slug: $ [^)]+ ')' { if (slugify(label) !== slug) { expected('slug to match label') } return { indent: indent.length, label, id: slug } } Section = title: H2 keys: Key+ {return { title, keys }} Key = name: ( heading: H3 { let name = heading.match(/^`(.+)`$/) return name ? name[1] : expected('code literal inside heading') } ) meta: ( required: '**(Required)**' {return { required: true }} / default_: '**(Default)**' Line {return { required: false, default: default_ }} ) [\n ]* desc: Line '\n\n' '```json\n' sample: $[^`]+ '```\n\n' (h4: H4 { h4 === 'Rules' || expected('rules section header')}) rules: List tips: ( '\n' (h4: H4 { h4 === 'Tips' || expected('tips section header')}) tips: List '\n' {return tips} )? { return { name, meta, desc, sample: sample.trimRight(), rules, tips: tips || [] } } List 'list' = ('* ' content: Line '\n' {return content})+ Line 'line of text' = $[^\n]+ H1 'h1' = '# ' content: Line '\n\n' {return content} H2 'h2' = '#' content: H1 {return content} H3 'h3' = '#' content: H2 {return content} H4 'h4' = '#' content: H3 {return content} ```
Current AST ```json { "title": "package.json", "intro": "`package.json` is a module metadata format commonly used to describe packages in the JavaScript ecosystem. It is consumed by tools such as package managers, bundlers, compilers, app frameworks, testing tools, and more. This document describes the fields that can be included in a `package.json` file, including what they are for, how they should work, what tools they are useful for, and tracks conforming implementations.", "toc": [ { "indent": 0, "label": "Essentials", "id": "essentials" }, { "indent": 1, "label": "`name`", "id": "name" }, { "indent": 1, "label": "`version`", "id": "version" } ], "sections": [ { "title": "Essentials", "keys": [ { "name": "name", "meta": { "required": true }, "desc": "The name of the package.", "sample": "{\n \"name\": \"my-package\"\n}", "rules": [ "Must be less than or equal to 214 characters (including the `@scope/` for scoped packages).", "Must not start with a dot (`.`) or an underscore (`_`).", "Must not have an uppercase letter in the name.", "Must use only URL-safe characters." ], "tips": [ "Don't use the same name as a core Node.js module", "Don't put js or node in the name.", "Keep names short and descriptive. You want people to understand what it is from the name, but it will also be used in require() calls.", "Make sure that there isn't something in the [registry](https://npmjs.com) with the same name." ] }, { "name": "version", "meta": { "required": true }, "desc": "The current version of the package.", "sample": "{\n \"version\": \"1.0.0\"\n}", "rules": [ "The version number must be valid [semver](https://semver.org). See the [npm docs](https://docs.npmjs.com/misc/semver) for more info." ], "tips": [] } ] } ] } ```
jamiebuilds commented 6 years ago

I'm good with Markdown.

But I think we should break things down a bit better. It would be nice to have shared definitions of stuff like:

That way we can reference the same types over and over without having to repeat ourselves and potentially have inconsistencies.

Stuff like Bikeshed and Ecmarkup are good for this sort of thing because they generate links between everything and make it easy to reference stuff. Ecmarkup is markdown based too

j-f1 commented 6 years ago

It’s fairly simple to link type names to their definition; for example, this Observable notebook will convert inline code blocks written with the ``SemanticVersion`` syntax to a link to the “SemanticVersion” header.

devongovett commented 6 years ago

Yeah definitely want definitions like that. We could do links like [SemanticVersion](#SemanticVersion) to go to that section. Github already generates ids for all headings so we wouldn't need to generate anything in order to read the spec.

j-f1 commented 6 years ago

@devongovett Check out the notebook — that’s exactly what it does 😉

jamiebuilds commented 6 years ago

An observable notebook is not a good format for a spec and we definitely should not use a custom tool for doing this.

j-f1 commented 6 years ago

SchemaStore has a schema for package.json we could perhaps work off of.