-
-
Notifications
You must be signed in to change notification settings - Fork 5k
refactor(model): add Code model for include_code tag #5633
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 7 commits
798afce
caf9d9c
ae5fae7
c03d4ce
98cf8c5
b1d66ef
0f5713d
d1bbd80
80ec349
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import warehouse from 'warehouse'; | ||
import type Hexo from '../hexo'; | ||
import { CodeSchema } from '../types'; | ||
import { join } from 'path'; | ||
|
||
export = (ctx: Hexo) => { | ||
const Code = new warehouse.Schema<CodeSchema>({ | ||
_id: { type: String, required: true }, | ||
path: { type: String, required: true }, | ||
slug: { type: String, required: true }, | ||
modified: { type: Boolean, default: true }, | ||
content: { type: String, default: '' } | ||
}); | ||
|
||
Code.virtual('source').get(function() { | ||
return join(ctx.base_dir, this._id); | ||
}); | ||
|
||
return Code; | ||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,27 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type Hexo from '../../hexo'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import Promise from 'bluebird'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { exists } from 'hexo-fs'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { CodeSchema } from '../../types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import type Document from 'warehouse/dist/document'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
interface CodeData { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modified: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function codeGenerator(this: Hexo): Promise<any[]> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return Promise.filter(this.model('Code').toArray(), (code: Document<CodeSchema>) => exists(code.source).tap(exist => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!exist) return code.remove(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
})).map((code: Document<CodeSchema>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+13
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation checks file existence for every code file on each generation. Consider implementing a more efficient approach that only checks existence when files are modified or caches the results.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { path } = code; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const data: CodeData = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
modified: code.modified, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
data: code.content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { path, data }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+12
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The returned object structure is inconsistent with other generators. Consider adding a comment explaining why this generator returns a different structure or align it with the BaseGeneratorReturn interface.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export = codeGenerator; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { Pattern } from 'hexo-util'; | ||
import { relative } from 'path'; | ||
import type Hexo from '../../hexo'; | ||
import type { _File } from '../../box'; | ||
|
||
export = (ctx: Hexo) => { | ||
let codeDir = ctx.config.code_dir; | ||
if (!codeDir.endsWith('/')) codeDir += '/'; | ||
return { | ||
pattern: new Pattern(path => { | ||
return path.startsWith(codeDir); | ||
}), | ||
process: function codeProcessor(file: _File) { | ||
const id = relative(ctx.base_dir, file.source).replace(/\\/g, '/'); | ||
const slug = relative(ctx.config.source_dir, id).replace(/\\/g, '/'); | ||
const Code = ctx.model('Code'); | ||
const doc = Code.findById(id); | ||
|
||
if (file.type === 'delete') { | ||
if (doc) { | ||
return doc.remove(); | ||
} | ||
|
||
return; | ||
} | ||
|
||
if (file.type === 'skip' && doc) { | ||
return; | ||
} | ||
|
||
return file.read().then(content => { | ||
return Code.save({ | ||
_id: id, | ||
path: file.path, | ||
slug, | ||
modified: file.type !== 'skip', | ||
content | ||
}); | ||
}); | ||
} | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { join } from 'path'; | ||
import { mkdirs, rmdir, unlink, writeFile } from 'hexo-fs'; | ||
import Hexo from '../../../lib/hexo'; | ||
import codeGenerator from '../../../lib/plugins/generator/code'; | ||
import defaults from '../../../lib/hexo/default_config'; | ||
import chai from 'chai'; | ||
const should = chai.should(); | ||
type CodeParams = Parameters<typeof codeGenerator> | ||
type CodeReturn = ReturnType<typeof codeGenerator> | ||
|
||
describe('code', () => { | ||
const hexo = new Hexo(join(__dirname, 'code_test'), {silent: true}); | ||
const generator: (...args: CodeParams) => CodeReturn = codeGenerator.bind(hexo); | ||
const Code = hexo.model('Code'); | ||
const codeDir = defaults.code_dir; | ||
|
||
before(async () => { | ||
await mkdirs(hexo.base_dir); | ||
await hexo.init(); | ||
}); | ||
|
||
after(() => rmdir(hexo.base_dir)); | ||
|
||
it('renderable', async () => { | ||
const path = 'test.j2'; | ||
const source = join(hexo.base_dir, defaults.source_dir, defaults.code_dir, path); | ||
const content = '{{ 1 }}'; | ||
|
||
await Promise.all([ | ||
Code.insert({ | ||
_id: `${defaults.source_dir}/${codeDir}/${path}`, | ||
slug: `${codeDir}/${path}`, | ||
path: `${codeDir}/${path}`, | ||
content | ||
}), | ||
writeFile(source, content) | ||
]); | ||
const data = await generator(); | ||
data[0].path.should.eql(`${codeDir}/${path}`); | ||
data[0].data.modified.should.be.true; | ||
|
||
const result = await data[0].data.data; | ||
result.should.eql(content); | ||
|
||
await Promise.all([ | ||
Code.removeById(`${defaults.source_dir}/${codeDir}/${path}`), | ||
unlink(source) | ||
]); | ||
}); | ||
|
||
it('not renderable', async () => { | ||
const path = 'test.txt'; | ||
const source = join(hexo.base_dir, defaults.source_dir, defaults.code_dir, path); | ||
const content = 'test content'; | ||
|
||
await Promise.all([ | ||
Code.insert({ | ||
_id: `${defaults.source_dir}/${codeDir}/${path}`, | ||
slug: `${codeDir}/${path}`, | ||
path: `${codeDir}/${path}`, | ||
content | ||
}), | ||
writeFile(source, content) | ||
]); | ||
const data = await generator(); | ||
data[0].path.should.eql(`${codeDir}/${path}`); | ||
data[0].data.modified.should.be.true; | ||
|
||
const result = await data[0].data.data; | ||
result.should.eql(content); | ||
|
||
await Promise.all([ | ||
Code.removeById(`${defaults.source_dir}/${codeDir}/${path}`), | ||
unlink(source) | ||
]); | ||
}); | ||
|
||
it('remove codes which does not exist', async () => { | ||
const path = 'test.js'; | ||
|
||
await Code.insert({ | ||
_id: `${defaults.source_dir}/${codeDir}/${path}`, | ||
slug: `${codeDir}/${path}`, | ||
path: `${codeDir}/${path}` | ||
}); | ||
await generator(); | ||
should.not.exist(Code.findById(`${defaults.source_dir}/${codeDir}/${path}`)); | ||
}); | ||
|
||
it('don\'t remove extension name', async () => { | ||
const path = 'test.min.js'; | ||
const source = join(hexo.base_dir, defaults.source_dir, defaults.code_dir, path); | ||
|
||
await Promise.all([ | ||
Code.insert({ | ||
_id: `${defaults.source_dir}/${codeDir}/${path}`, | ||
slug: `${codeDir}/${path}`, | ||
path: `${codeDir}/${path}` | ||
}), | ||
writeFile(source, '') | ||
]); | ||
const data = await generator(); | ||
data[0].path.should.eql(`${codeDir}/${path}`); | ||
|
||
await Promise.all([ | ||
Code.removeById(`${defaults.source_dir}/${codeDir}/${path}`), | ||
unlink(source) | ||
]); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { join } from 'path'; | ||
import Hexo from '../../../lib/hexo'; | ||
|
||
describe('Code', () => { | ||
const hexo = new Hexo(); | ||
const Code = hexo.model('Code'); | ||
|
||
it('_id - required', async () => { | ||
try { | ||
await Code.insert({}); | ||
} catch (err) { | ||
err.message.should.eql('ID is not defined'); | ||
} | ||
}); | ||
|
||
it('path - required', async () => { | ||
try { | ||
await Code.insert({ | ||
_id: 'foo' | ||
}); | ||
} catch (err) { | ||
err.message.should.eql('`path` is required!'); | ||
} | ||
}); | ||
|
||
it('slug - required', async () => { | ||
try { | ||
await Code.insert({ | ||
_id: 'foo', | ||
path: 'bar' | ||
}); | ||
} catch (err) { | ||
err.message.should.eql('`slug` is required!'); | ||
} | ||
}); | ||
|
||
it('default values', async () => { | ||
const data = await Code.insert({ | ||
_id: 'foo', | ||
path: 'bar', | ||
slug: 'baz' | ||
}); | ||
data.modified.should.be.true; | ||
data.content.should.eql(''); | ||
|
||
Code.removeById(data._id); | ||
}); | ||
|
||
it('source - virtual', async () => { | ||
const data = await Code.insert({ | ||
_id: 'foo', | ||
path: 'bar', | ||
slug: 'baz' | ||
}); | ||
data.source.should.eql(join(hexo.base_dir, data._id)); | ||
|
||
Code.removeById(data._id); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the same value is already set in
path
, I don't thinkslug
is necessary. Though the difference may be slight, reducing the elements inSchema<CodeSchema>
should have a positive effect on performance.However, if we remove the
slug
, it could potentially be a breaking change since there may be users referencing it in custom scripts or etc..., so it might require an announcement.