Convert additional data-directory files to TypeScript (#56396)
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import yaml from 'js-yaml'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import dataSchemas from '#src/data-directory/lib/data-schemas/index.js'
|
||||
import dataSchemas from '#src/data-directory/lib/data-schemas/index.ts'
|
||||
import ajv from '#src/tests/lib/validate-json-schema.js'
|
||||
|
||||
// AJV already has a built-in way to extract out properties
|
||||
|
||||
4
src/data-directory/lib/data-directory.d.ts
vendored
4
src/data-directory/lib/data-directory.d.ts
vendored
@@ -1,4 +0,0 @@
|
||||
import { FeatureData } from '@/types.js'
|
||||
|
||||
declare function dataDirectory(dir: string, opts?: Object): FeatureData
|
||||
export default dataDirectory
|
||||
@@ -4,45 +4,65 @@ import path from 'path'
|
||||
import walk from 'walk-sync'
|
||||
import yaml from 'js-yaml'
|
||||
import { isRegExp, setWith } from 'lodash-es'
|
||||
import filenameToKey from './filename-to-key.js'
|
||||
import filenameToKey from './filename-to-key'
|
||||
import matter from 'gray-matter'
|
||||
|
||||
export default function dataDirectory(dir, opts = {}) {
|
||||
const defaultOpts = {
|
||||
preprocess: (content) => {
|
||||
interface DataDirectoryOptions {
|
||||
preprocess?: (content: string) => string
|
||||
ignorePatterns?: RegExp[]
|
||||
extensions?: string[]
|
||||
}
|
||||
|
||||
interface DataDirectoryResult {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export default function dataDirectory(
|
||||
dir: string,
|
||||
opts: DataDirectoryOptions = {},
|
||||
): DataDirectoryResult {
|
||||
const defaultOpts: Required<DataDirectoryOptions> = {
|
||||
preprocess: (content: string) => {
|
||||
return content
|
||||
},
|
||||
ignorePatterns: [/README\.md$/i],
|
||||
extensions: ['.json', '.md', '.markdown', '.yml'],
|
||||
}
|
||||
|
||||
opts = Object.assign({}, defaultOpts, opts)
|
||||
const mergedOpts = Object.assign({}, defaultOpts, opts)
|
||||
|
||||
// validate input
|
||||
assert(Array.isArray(opts.ignorePatterns))
|
||||
assert(opts.ignorePatterns.every(isRegExp))
|
||||
assert(Array.isArray(opts.extensions))
|
||||
assert(opts.extensions.length)
|
||||
assert(Array.isArray(mergedOpts.ignorePatterns))
|
||||
assert(mergedOpts.ignorePatterns.every(isRegExp))
|
||||
assert(Array.isArray(mergedOpts.extensions))
|
||||
assert(mergedOpts.extensions.length)
|
||||
|
||||
// start with an empty data object
|
||||
const data = {}
|
||||
const data: DataDirectoryResult = {}
|
||||
|
||||
// find YAML and Markdown files in the given directory, recursively
|
||||
const filenames = walk(dir, { includeBasePath: true }).filter((filename) => {
|
||||
const filenames = walk(dir, { includeBasePath: true }).filter((filename: string) => {
|
||||
// ignore files that match any of ignorePatterns regexes
|
||||
if (opts.ignorePatterns.some((pattern) => pattern.test(filename))) return false
|
||||
if (mergedOpts.ignorePatterns.some((pattern) => pattern.test(filename))) return false
|
||||
|
||||
// ignore files that don't have a whitelisted file extension
|
||||
return opts.extensions.includes(path.extname(filename).toLowerCase())
|
||||
return mergedOpts.extensions.includes(path.extname(filename).toLowerCase())
|
||||
})
|
||||
|
||||
const files = filenames.map((filename) => [filename, fs.readFileSync(filename, 'utf8')])
|
||||
const files: [string, string][] = filenames.map((filename: string) => [
|
||||
filename,
|
||||
fs.readFileSync(filename, 'utf8'),
|
||||
])
|
||||
|
||||
files.forEach(([filename, fileContent]) => {
|
||||
// derive `foo.bar.baz` object key from `foo/bar/baz.yml` filename
|
||||
const key = filenameToKey(path.relative(dir, filename))
|
||||
const extension = path.extname(filename).toLowerCase()
|
||||
|
||||
if (opts.preprocess) fileContent = opts.preprocess(fileContent)
|
||||
let processedContent = fileContent
|
||||
if (mergedOpts.preprocess) {
|
||||
processedContent = mergedOpts.preprocess(fileContent)
|
||||
}
|
||||
|
||||
// Add this file's data to the global data object.
|
||||
// Note we want to use `setWith` instead of `set` so we can customize the type during path creation.
|
||||
@@ -51,17 +71,17 @@ export default function dataDirectory(dir, opts = {}) {
|
||||
// See https://lodash.com/docs#set for an explanation.
|
||||
switch (extension) {
|
||||
case '.json':
|
||||
setWith(data, key, JSON.parse(fileContent), Object)
|
||||
setWith(data, key, JSON.parse(processedContent), Object)
|
||||
break
|
||||
case '.yml':
|
||||
setWith(data, key, yaml.load(fileContent, { filename }), Object)
|
||||
setWith(data, key, yaml.load(processedContent, { filename }), Object)
|
||||
break
|
||||
case '.md':
|
||||
case '.markdown':
|
||||
// Use `matter` to drop frontmatter, since localized reusable Markdown files
|
||||
// can potentially have frontmatter, but we want to prevent the frontmatter
|
||||
// from being rendered.
|
||||
setWith(data, key, matter(fileContent).content, Object)
|
||||
setWith(data, key, matter(processedContent).content, Object)
|
||||
break
|
||||
}
|
||||
})
|
||||
@@ -1,4 +1,8 @@
|
||||
export default {
|
||||
interface DataSchemas {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
const dataSchemas: DataSchemas = {
|
||||
'data/features': '#src/data-directory/lib/data-schemas/features.js',
|
||||
'data/variables': '#src/data-directory/lib/data-schemas/variables.js',
|
||||
'data/learning-tracks': '#src/data-directory/lib/data-schemas/learning-tracks.js',
|
||||
@@ -7,3 +11,5 @@ export default {
|
||||
'data/glossaries/candidates.yml': '#src/data-directory/lib/data-schemas/glossaries-candidates.js',
|
||||
'data/glossaries/external.yml': '#src/data-directory/lib/data-schemas/glossaries-external.js',
|
||||
}
|
||||
|
||||
export default dataSchemas
|
||||
@@ -1,5 +1,6 @@
|
||||
import path from 'path'
|
||||
import { escapeRegExp } from 'lodash-es'
|
||||
|
||||
/* eslint-disable prefer-regex-literals */
|
||||
|
||||
// slash at the beginning of a filename
|
||||
@@ -14,8 +15,8 @@ const windowsPathSeparator = new RegExp('/', 'g')
|
||||
const windowsDoubleSlashSeparator = new RegExp('\\\\', 'g')
|
||||
|
||||
// derive `foo.bar.baz` object key from `foo/bar/baz.yml` filename
|
||||
export default function filenameToKey(filename) {
|
||||
const extension = new RegExp(`${path.extname(filename)}$`)
|
||||
export default function filenameToKey(filename: string): string {
|
||||
const extension = new RegExp(`${escapeRegExp(path.extname(filename))}$`)
|
||||
const key = filename
|
||||
.replace(extension, '')
|
||||
.replace(leadingPathSeparator, '')
|
||||
@@ -7,7 +7,7 @@ import { beforeAll, describe, expect, test } from 'vitest'
|
||||
|
||||
import { getJsonValidator, validateJson } from '#src/tests/lib/validate-json-schema.js'
|
||||
import { formatAjvErrors } from '#src/tests/helpers/schemas.js'
|
||||
import dataSchemas from '#src/data-directory/lib/data-schemas/index.js'
|
||||
import dataSchemas from '#src/data-directory/lib/data-schemas/index.ts'
|
||||
|
||||
const schemaPaths = Object.keys(dataSchemas)
|
||||
const singleFilesSchemas = schemaPaths.filter((schemaPath) => extname(schemaPath))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import filenameToKey from '#src/data-directory/lib/filename-to-key.js'
|
||||
import filenameToKey from '#src/data-directory/lib/filename-to-key.ts'
|
||||
|
||||
describe('filename-to-key', () => {
|
||||
test('converts filenames to object keys', () => {
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path'
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import dataDirectory from '#src/data-directory/lib/data-directory.js'
|
||||
import dataDirectory from '#src/data-directory/lib/data-directory.ts'
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||
const fixturesDir = path.join(__dirname, 'fixtures')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import semver from 'semver'
|
||||
|
||||
import { supported } from '@/versions/lib/enterprise-server-releases.js'
|
||||
import getDataDirectory from '@/data-directory/lib/data-directory.js'
|
||||
import getDataDirectory from '@/data-directory/lib/data-directory'
|
||||
import { FeatureData, FrontmatterVersions } from '@/types.js'
|
||||
|
||||
// Return true if lowestSupportedVersion > semVerRange
|
||||
|
||||
Reference in New Issue
Block a user